@vosjs/render-core 0.10.0 → 0.11.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/stepBound.ts","../../src/record/pageSound.ts","../../src/record/takeClock.ts","../../src/record/pageErrors.ts","../../src/record/surfaceFit.ts","../../src/record/waits.ts","../../src/record/ready.ts","../../src/record/gestures.ts","../../src/record/paste.ts","../../src/record/settle.ts","../../src/record/peers.ts","../../src/record/actions.ts","../../src/record/scriptFiles.ts","../../src/record/pasteStep.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\n/** Which button a press is, and which press of a multi-click. */\nexport interface RecorderButtonOpts {\n button?: 'left' | 'right' | 'middle'\n clickCount?: number\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' | 'load'; 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' | 'load'\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 // A click's `button` and `count` (a double click is two presses, the\n // second with clickCount 2).\n down(opts?: RecorderButtonOpts): Promise<void>\n up(opts?: RecorderButtonOpts): 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 /** A drag's modifiers, held from the press to the release. */\n down(key: string): Promise<void>\n up(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 /**\n * A `paste` step's clipboard access, when the driver grants it; absent,\n * the paste is dispatched in the page and the recorder says so.\n */\n grantPermissions?(\n permissions: string[],\n opts?: { origin?: string },\n ): Promise<unknown>\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/**\n * Where the sound a page played during the take is kept: the CLI writes\n * `page-sound/<name>` in the take directory and answers that take-relative\n * key, which the plan's audio clips name. A host that hands in none (the\n * fleet) still records `meta.media`; the plan then places nothing.\n */\nexport interface SoundSink {\n save(\n name: string,\n bytes: Uint8Array,\n contentType?: string,\n ): Promise<string> | string\n}\n\n/**\n * Where the files a script names beside itself come from: a drag's path\n * file, a paste's file, by a plain name. The CLI reads the actions file's\n * directory. A host that hands in none (a hosted recorder carries the\n * script alone) cannot run such a step, and the recorder refuses it before\n * capturing anything.\n */\nexport interface ScriptFiles {\n read(name: string): Promise<Uint8Array>\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 paste: 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 case 'paste':\n return step.ms ?? SETTLE_MS.paste\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]\nexport type Notice = NonNullable<RecordingMeta['notices']>[number]\n/** A notice as one scan reports it. */\nexport type ScannedNotice = Omit<Notice, 'step' | 'seen'>\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 INFORMATION the scan reports beside the exposures (never a failure):\n * the signed-in account's own display name, wherever the frame shows it,\n * and a list of the account's recent items. Runs inside EXPOSURE_PROBE,\n * after `seen` and before any selector is made: it sets `acct`, which\n * `quiet` then keeps out of every selector. Never `$` + `{` in here: it is\n * spliced into a template.\n *\n * The name is read conservatively, from where apps say whose account it\n * is: a line that greets or names the account (\"Signed in as …\",\n * \"Welcome back, …\"), the label of an account menu (\"Account menu for …\"),\n * or the words on the account menu's own trigger (the button that opens\n * a menu and holds the avatar), which are SURE; or a name-like label on an avatar (an image's alt, a\n * button holding the picture), which MAY be the name.\n */\nexport const NOTICE_SRC = String.raw`const notices = () => {\n // A label made only of these words is the control's, never a person's:\n // \"Account menu\", \"Open user menu\", \"Profile settings\".\n const UI_WORDS = new Set(['account', 'accounts', 'profile', 'profiles', 'menu', 'user', 'users', 'settings', 'setting', 'avatar', 'open', 'close', 'toggle', 'show', 'hide', 'the', 'my', 'your', 'me', 'you', 'home', 'guest', 'admin', 'team', 'workspace', 'dashboard', 'sign', 'signed', 'in', 'out', 'log', 'logged', 'logout', 'login', 'help', 'search', 'notification', 'notifications', 'more', 'options', 'option', 'button', 'dropdown', 'picture', 'image', 'photo', 'main', 'navigation', 'nav', 'preferences', 'switch', 'manage'])\n const nameLike = (v) => {\n if (!v) return null\n const t = v.replace(/\\s+/g, ' ').trim().replace(/[!.,:]+$/, '')\n if (t.length < 2 || t.length > 40 || /[@\\d<>/|]/.test(t)) return null\n if (!/^\\p{Lu}[\\p{L}'’.-]*(?: \\p{L}[\\p{L}'’.-]*){0,3}$/u.test(t)) return null\n if (t.toLowerCase().split(' ').every((w) => UI_WORDS.has(w))) return null\n return t\n }\n const GREETING = /^(?:signed in as|logged in as|welcome back,?|welcome,|hi,|hello,|hey,)\\s+(.+)$/i\n const LABELS = [\n /^(?:account|user|profile)(?: menu)?(?: for|:|,| -)\\s*(.+)$/i,\n /^open (?:the )?(?:user|account|profile) menu(?: for|,|:)?\\s*(.+)$/i,\n /^(.+?)[’']s? (?:account|profile|avatar)$/i,\n ]\n const avatarish = (el) => el.tagName === 'IMG' || !!el.querySelector('img, svg') || /avatar/i.test(String(el.className || '') + ' ' + (el.getAttribute('data-testid') || ''))\n let sure = false\n const texts = document.createTreeWalker(document.body || document.documentElement, NodeFilter.SHOW_TEXT)\n for (let n; !acct && (n = texts.nextNode()); ) {\n const el = n.parentElement\n if (!el || /^(SCRIPT|STYLE|NOSCRIPT|TEMPLATE)$/.test(el.tagName)) continue\n const line = (el.textContent || '').replace(/\\s+/g, ' ').trim()\n if (line.length > 80) continue\n const m = GREETING.exec(line)\n const who = m && nameLike(m[1])\n if (who && seen(el)) { acct = who; sure = true }\n }\n let maybe = null\n if (!acct) {\n for (const el of document.querySelectorAll('[aria-label], img[alt], [title]')) {\n const label = el.getAttribute('aria-label') || el.getAttribute('alt') || el.getAttribute('title') || ''\n const box = el.closest('button, a, [role=\"button\"], [aria-haspopup]') || el\n if (!seen(el) && !seen(box)) continue\n let hit = null\n for (const rx of LABELS) { const m = rx.exec(label.trim()); if (m && (hit = nameLike(m[1]))) break }\n if (hit) { acct = hit; sure = true; break }\n if (!maybe && (avatarish(el) || avatarish(box)) && box !== el.ownerDocument.body) maybe = nameLike(label)\n }\n }\n // The account menu's TRIGGER, whose own words are the name: a control\n // that opens a menu and holds the avatar, or one labelled as the\n // account's. The name-like line among its words (an address there is\n // an exposure already, and never a name).\n if (!acct) {\n const TRIGGER_LABEL = /\b(account|user|profile|avatar)\b/i\n for (const el of document.querySelectorAll('button, a, [role=\"button\"], [aria-haspopup]')) {\n const label = (el.getAttribute('aria-label') || '') + ' ' + (el.getAttribute('title') || '')\n const trigger = (el.hasAttribute('aria-haspopup') && avatarish(el)) || TRIGGER_LABEL.test(label)\n if (!trigger || !seen(el)) continue\n const words = document.createTreeWalker(el, NodeFilter.SHOW_TEXT)\n for (let n; !acct && (n = words.nextNode()); ) {\n const who = nameLike(n.nodeValue)\n if (who && n.parentElement && seen(n.parentElement)) { acct = who; sure = true }\n }\n if (acct) break\n }\n }\n if (!acct && maybe) acct = maybe\n const found = []\n if (acct) {\n const places = [], at = new Set()\n const walk = document.createTreeWalker(document.body || document.documentElement, NodeFilter.SHOW_TEXT)\n for (let n; (n = walk.nextNode()) && places.length < 20; ) {\n const el = n.parentElement\n if (!el || /^(SCRIPT|STYLE|NOSCRIPT|TEMPLATE)$/.test(el.tagName)) continue\n if (!(n.nodeValue || '').includes(acct)) continue\n const r = seen(el)\n if (!r) continue\n const selector = name(el)\n if (at.has(selector)) continue\n at.add(selector)\n places.push({ selector, rect: { x: Math.round(r.left), y: Math.round(r.top), w: Math.round(r.width), h: Math.round(r.height) } })\n }\n if (places.length) found.push({ kind: 'account-name', sure, places })\n }\n const RECENT = /^(recents?|recently (?:viewed|opened|visited|edited)|history|recent (?:files|projects|documents|items|pages|boards|chats|conversations|searches))$/i\n const ITEMS = 'a[href], [role=\"link\"], [role=\"menuitem\"], [role=\"treeitem\"], [role=\"option\"]'\n const listed = new Set()\n for (const el of document.querySelectorAll('h1, h2, h3, h4, h5, h6, [role=\"heading\"], summary, div, span, p, li, label, strong, button, a')) {\n if (el.children.length > 2) continue\n const word = (el.textContent || '').replace(/\\s+/g, ' ').trim()\n if (word.length > 40 || !RECENT.test(word)) continue\n // A nav link that happens to say History is a page, not a list.\n if (/^(A|BUTTON)$/.test(el.tagName) && !el.hasAttribute('aria-expanded')) continue\n if (!seen(el)) continue\n for (const c of [el.nextElementSibling, el.parentElement && el.parentElement.nextElementSibling, el.parentElement]) {\n if (!c || c === document.body) continue\n const items = [...c.querySelectorAll(ITEMS)].filter((x) => x !== el && !x.contains(el) && seen(x))\n if (items.length < 3) continue\n const r = seen(c)\n if (!r) continue\n const selector = name(c)\n if (!listed.has(selector)) {\n listed.add(selector)\n found.push({ kind: 'personal-list', heading: word, selector, items: items.length, rect: { x: Math.round(r.left), y: Math.round(r.top), w: Math.round(r.width), h: Math.round(r.height) } })\n }\n break\n }\n if (listed.size >= 5) break\n }\n return found\n }\n // Read before any selector is made, so none of them quotes the name.\n const noticeList = notices()`\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 // The signed-in account's own name, once the notices have read it: a\n // selector never quotes it either.\n let acct = null\n const quiet = (v) => !!v && v.length <= 80 && !kindsIn(v).length && !(acct && v.toLowerCase().includes(acct.toLowerCase()))\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 ${NOTICE_SRC}\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, notices: noticeList }\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/**\n * Accumulates the notices across a take: the account's name is ONE notice,\n * its places gathered from every scan; a recent-items list is one notice\n * per list. Each keeps the first step it was seen at.\n */\nexport class NoticeLog {\n private byKey = new Map<string, Notice>()\n\n add(step: number, notices: ScannedNotice[] | undefined | null): void {\n for (const n of notices ?? []) {\n const key =\n n.kind === 'account-name' ? n.kind : `${n.kind}|${n.selector ?? ''}`\n const had = this.byKey.get(key)\n if (!had) {\n this.byKey.set(key, { step, ...n, seen: 1 })\n continue\n }\n had.seen += 1\n if (n.kind !== 'account-name') continue\n if (n.sure) had.sure = true\n const places = had.places ?? []\n for (const p of n.places ?? [])\n if (\n places.length < 20 &&\n !places.some((q) => q.selector === p.selector)\n )\n places.push(p)\n had.places = places\n }\n }\n\n notices(): Notice[] {\n return [...this.byKey.values()]\n }\n}\n\n/**\n * One notice, in words. The account's name is never printed: the line says\n * where it showed, so each place can be masked.\n */\nexport function noticeLine(n: Notice): string {\n const when = n.step < 0 ? 'as the page opened' : `from step #${n.step}`\n if (n.kind === 'account-name') {\n const places = n.places ?? []\n return `${n.sure ? '' : 'what may be '}the account's name (${places.length} ${places.length === 1 ? 'place' : 'places'}, ${when}): ${places.map((p) => p.selector).join('; ')}`\n }\n const mask = JSON.stringify({ selector: n.selector, as: 'blur' })\n return `a \"${n.heading}\" list of the account's own items (${n.items} items, ${when}) in ${n.selector}; to hide it, add to \"mask\": ${mask}`\n}\n\n/**\n * What to do about the notices, in one line: the swap hint is about the\n * account's name, so it is said only when the name was noticed.\n */\nexport function noticeAdvice(notices: readonly Pick<Notice, 'kind'>[]): string {\n const name = notices.some((n) => n.kind === 'account-name')\n return `These are the signed-in account's own: fine for a demo account, worth a mask on a real one.${name ? ' The name reads better swapped than blurred: { \"selector\": \"…\", \"as\": \"text\", \"text\": \"Jane Doe\" }.' : ''}`\n}\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 *\n * `teardown`: the same steps, run AFTER the take, off camera too: what the\n * take created in the product (an API key, a project, an invite) removed\n * again, so a rehearsal or a re-record leaves the account as it found it.\n * They run once the screencast has stopped, on the take's own page and\n * context (a session's cookies apply), and also when the take stops early\n * or throws once its first step has run. A teardown that fails never fails\n * the take: the footage is fine, and what is left behind is reported.\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/** Which list a step belongs to, as its messages and log lines name it. */\nexport type StepPhase = 'setup' | 'teardown'\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/**\n * Structural validation, mirrored on `validateActions` for `steps`. The\n * same verbs and rules hold for `teardown`; `phase` names the list.\n */\nexport function validateSetup(\n value: unknown,\n phase: StepPhase = 'setup',\n): string[] {\n const errors: string[] = []\n if (!Array.isArray(value)) return [`${phase} must be an array of steps`]\n value.forEach((raw, i) => {\n const at = `${phase}[${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/**\n * Every name a script reads from its env, its setup's and its teardown's,\n * each once: what a host must supply before the take begins.\n */\nexport function scriptEnvNames(script: {\n setup?: SetupStep[]\n teardown?: SetupStep[]\n}): string[] {\n return [\n ...new Set([\n ...setupEnvNames(script.setup),\n ...setupEnvNames(script.teardown),\n ]),\n ]\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 phase: StepPhase = 'setup',\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 `${phase}: 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\n/**\n * The first `{ env }` a teardown reads that `env` does not hold, in words,\n * or null. Asked BEFORE the take: a take that creates something its\n * teardown cannot then remove is the one case teardown exists for.\n */\nexport function teardownEnvProblem(\n steps: SetupStep[] | undefined,\n env: Record<string, string | undefined>,\n): string | null {\n for (const [i, s] of (steps ?? []).entries()) {\n if (s.do !== 'type' || typeof s.text !== 'object') continue\n const v = env[s.text.env]\n if (v === undefined || v === '')\n return `teardown[${i}] reads the environment variable ${s.text.env}, which is not set, so the take could leave behind what its teardown removes. Export it in the shell that runs vos record; it is never written to a file. Nothing was recorded.`\n }\n return null\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 /**\n * The step that failed: for a setup, a selector that never appeared (the\n * take does not start); for a teardown, the step it stopped at. `error`\n * is the driver's reason, one line, never a typed value.\n */\n failed?: { step: number; do: string; selector?: string; error?: string }\n}\n\n/** How long a whole teardown may take before it is stopped and reported. */\nexport const TEARDOWN_BOUND_MS = 60_000\n\n/**\n * What a teardown did, on the take's result: how many of its steps ran,\n * and where it stopped. Never a typed value.\n */\nexport interface TeardownReport {\n ran: number\n of: number\n failed?: { step: number; do: string; selector?: string; error: string }\n}\n\n/** The teardown in one line, for the end of a take or a rehearsal. */\nexport function teardownLine(report: TeardownReport): string {\n const f = report.failed\n if (!f) return `teardown: ${report.ran} step(s) ran`\n const reason = f.error.replace(/[.\\s]+$/, '')\n return `TEARDOWN FAILED at teardown[${f.step}] (${f.do}${f.selector ? ` ${f.selector}` : ''}): ${reason}. What the take created may still be in the product; remove it by hand.`\n}\n\n/**\n * Run the setup (or the teardown) on a page, with plain Playwright actions:\n * no humanized pointer, no cursor events, no frames. A selector that never\n * appears fails the steps there, because a take that begins at a\n * half-finished sign-in is the wall by another name. With `boundMs`, the\n * steps together run no longer than that: the step running when it passes\n * fails, and the call it left pending is abandoned.\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 /** How a `goto` opens its page and waits for it (the take's ready mode); absent, network idle. */\n goto?: (url: string) => Promise<unknown>\n /** Which list these are, for the log and the messages (default `setup`). */\n phase?: StepPhase\n /** The longest the steps may take together, in ms. */\n boundMs?: number\n now?: () => number\n },\n): Promise<SetupResult> {\n const env = opts.env ?? {}\n const phase = opts.phase ?? 'setup'\n const now = opts.now ?? Date.now\n const deadline = opts.boundMs === undefined ? undefined : now() + opts.boundMs\n const lines: string[] = []\n // The value a `type` step is filling, so a reason that quotes it is not used.\n let typed = ''\n const runStep = async (step: SetupStep, i: number): Promise<string> => {\n const settle = 'ms' in step && typeof step.ms === 'number' ? step.ms : 150\n switch (step.do) {\n case 'wait':\n await opts.sleep(step.ms)\n return `${phase} #${i} wait ${step.ms}ms`\n case 'goto':\n await (\n opts.goto\n ? opts.goto(step.url)\n : page.goto(step.url, {\n waitUntil: 'networkidle',\n timeout: 45000,\n })\n ).catch(() => null)\n return `${phase} #${i} goto ${step.url}`\n case 'press':\n await page.keyboard.press(step.key)\n await opts.sleep(settle)\n return `${phase} #${i} press ${step.key}`\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 return `${phase} #${i} click ${step.selector}`\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, phase)\n typed = value\n await loc.fill(value)\n await opts.sleep(settle)\n // The log names the field, never what went into it.\n return `${phase} #${i} type ${secret ? `\\${${(step.text as { env: string }).env}}` : `${value.length} chars`} into ${step.selector}`\n }\n }\n }\n for (const [i, step] of steps.entries()) {\n typed = ''\n try {\n lines.push(\n await withinDeadline(\n runStep(step, i),\n deadline,\n now,\n `the ${phase} ran past its ${sayBound(opts.boundMs ?? 0)} bound`,\n ),\n )\n } catch (e) {\n // A missing variable is a usage error before a take; a teardown's is\n // the step it stopped at.\n if (e instanceof SetupEnvError && phase === 'setup') 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 error: reasonWords(e, typed),\n },\n }\n }\n }\n return { ran: steps.length, lines }\n}\n\n/** A bound in the words a log reads: whole seconds, or ms under one. */\nfunction sayBound(ms: number): string {\n return ms >= 1000 ? `${Math.round(ms / 1000)} s` : `${ms} ms`\n}\n\n/** `p`, or a rejection once `deadline` passes; the abandoned call is never awaited. */\nfunction withinDeadline<T>(\n p: Promise<T>,\n deadline: number | undefined,\n now: () => number,\n message: string,\n): Promise<T> {\n if (deadline === undefined) return p\n const left = deadline - now()\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(\n () => {\n p.catch(() => {})\n reject(new Error(message))\n },\n Math.max(0, left),\n )\n p.then(\n (v) => {\n clearTimeout(timer)\n resolve(v)\n },\n (e: unknown) => {\n clearTimeout(timer)\n reject(e)\n },\n )\n })\n}\n\n/** A terminal colour sequence, as a driver's error may carry one. */\nconst ANSI_COLOUR = new RegExp(`${String.fromCharCode(27)}\\\\[[0-9;]*m`, 'g')\n\n/**\n * A driver's error as one line a log may carry: its first line, without\n * terminal colour, and never a value a `type` step was filling.\n */\nfunction reasonWords(e: unknown, typed: string): string {\n const raw = e instanceof Error ? e.message : String(e)\n const line = (raw.replace(ANSI_COLOUR, '').split('\\n')[0] ?? '').trim()\n if (typed && line.includes(typed)) return 'the field could not be filled'\n return line || 'the step failed'\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 * A step never runs past its own bound, however the page behaves. A page\n * that stops answering (a busy loop, a renderer stuck after a reload the\n * page made itself) leaves every driver call pending for good, and a poll\n * that reads it waits on the read, not on its clock: an `expect` that said\n * \"for 5 s\" ran for fifteen minutes. So the page the recorder drives is\n * BOUNDED: while a step runs, every call into it is raced against the\n * step's deadline, and once the deadline has passed a pending call answers\n * `undefined` (what an absent element answers) instead of waiting. The\n * step then ends as a skip with the real time it took; the call it left\n * pending is abandoned, never awaited.\n *\n * Between steps the same race holds with a looser bound, so the take's\n * own finish (its last reads, the page's title) cannot hang either.\n */\n\n/** A gesture's bound past what it planned to take. */\nexport const STEP_MARGIN_MS = 30_000\n/** A check's (`expect`, `await`) bound past its own timeout. */\nexport const WAIT_MARGIN_MS = 5000\n/** One call's bound while no step runs (a navigation has its own 45 s timeout). */\nexport const IDLE_CALL_MS = 60_000\n\n/** The bound of one step, in ms: its own timeout for a check, its plan plus a margin for a gesture. */\nexport function stepBoundMs(\n step: {\n do: string\n timeout?: number\n until?: unknown\n reload?: boolean\n },\n plannedMs: number,\n defaults: { expectS: number; awaitS: number; downloadS: number },\n): number {\n if (step.do === 'expect')\n return (step.timeout ?? defaults.expectS) * 1000 + WAIT_MARGIN_MS\n if (step.do === 'await')\n return (step.timeout ?? defaults.awaitS) * 1000 + STEP_MARGIN_MS\n if (step.do === 'download') return defaults.downloadS * 1000 + STEP_MARGIN_MS\n return plannedMs + STEP_MARGIN_MS\n}\n\nexport class StepBound {\n private deadline: number | null = null\n private started = 0\n private hung = false\n\n constructor(\n private readonly now: () => number = Date.now,\n private readonly idleMs = IDLE_CALL_MS,\n ) {}\n\n /** A step begins: calls into the page answer within `boundMs` from now. */\n start(boundMs: number): void {\n this.started = this.now()\n this.deadline = this.started + boundMs\n this.hung = false\n }\n\n /** The step ends: whether it ran into its bound, and how long it really took. */\n end(): { hung: boolean; ms: number; boundMs: number } {\n const out = {\n hung: this.hung,\n ms: this.now() - this.started,\n boundMs: (this.deadline ?? this.started) - this.started,\n }\n this.deadline = null\n this.hung = false\n return out\n }\n\n /** The pending call, or `undefined` once the bound has passed. */\n race<T>(p: Promise<T>): Promise<T> {\n const left =\n this.deadline === null ? this.idleMs : this.deadline - this.now()\n if (left <= 0) {\n this.hung = true\n p.catch(() => {})\n return Promise.resolve(undefined as T)\n }\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.hung = true\n resolve(undefined as T)\n }, left)\n p.then(\n (v) => {\n clearTimeout(timer)\n resolve(v)\n },\n (e: unknown) => {\n clearTimeout(timer)\n reject(e)\n },\n )\n })\n }\n}\n\n/**\n * `target` with every method that answers a promise raced through the\n * guard, and every object it hands back (`page.mouse`, `locator()`,\n * `.first()`) guarded the same way. A call is made on the real object, so\n * nothing private to the driver is touched through the proxy.\n */\nexport function bounded<T extends object>(target: T, bound: StepBound): T {\n const cache = new WeakMap<object, object>()\n const wrap = <O extends object>(obj: O): O => {\n const had = cache.get(obj)\n if (had) return had as O\n const proxy = new Proxy(obj, {\n get(t, prop) {\n const value: unknown = Reflect.get(t, prop, t)\n if (typeof value === 'function')\n return (...args: unknown[]) => {\n const out: unknown = (value as (...a: unknown[]) => unknown).apply(\n t,\n args,\n )\n if (out && typeof (out as Promise<unknown>).then === 'function')\n return bound.race(out as Promise<unknown>)\n if (out && typeof out === 'object' && out !== t) return wrap(out)\n return out\n }\n if (value && typeof value === 'object') return wrap(value)\n return value\n },\n })\n cache.set(obj, proxy)\n return proxy\n }\n return wrap(target)\n}\n","/**\n * The sound a page plays during a take. The recorder captures frames, and\n * a product's sound (a voice preview, a video playing in the page) would\n * be lost with nothing to say it was there. Most of it is a media element,\n * so the recorder watches every `<video>` and `<audio>` the page plays, in\n * the page and in its same-origin frames, and keeps WHEN each was heard\n * and WHAT media time it played, so a clip of the same file can be placed\n * exactly under the footage (`meta.media`, then the plan's audio clips).\n *\n * Two pieces run IN the page, both plain JavaScript strings (a function\n * serialized out of a bundle picks up the bundler's helpers and dies in the\n * page): an init script that notes every play, pause, seek, end and volume\n * change into a log on the top window, and a drain that hands the log over\n * with the page's clock. The rest is here, in the recorder's clock: the\n * page's instants become wall instants, and the take clock turns those\n * into footage stretches, split wherever an `await` took the camera away.\n */\nimport type { RecordingPageMedia } from '@vosjs/studio-core'\nimport type { TakeClock } from './takeClock'\n\n/** The most elements a take follows, and the most notes the page keeps between drains. */\nconst MAX_ELEMENTS = 50\nconst MAX_NOTES = 2000\n/** A heard stretch shorter than this places nothing. */\nconst MIN_HEARD_S = 0.05\n\n/**\n * The init script: runs at document start in every frame. A frame that\n * cannot reach the top window (another origin) notes nothing. A media\n * element out of the document (`new Audio(url).play()`) is reached by\n * the play it is started with.\n */\nexport const MEDIA_WATCH_SCRIPT = `(() => {\n let host\n try { host = window.top; void host.document.title } catch { return }\n if (window.__vosMediaWatch) return\n window.__vosMediaWatch = true\n if (!host.__vosMedia) {\n const M = { log: [], seq: 0, els: new Set(), doc: Math.random().toString(36).slice(2) }\n M.fields = (el, kind) => ({\n id: el.__vosMediaId,\n tag: el.tagName === 'VIDEO' ? 'video' : 'audio',\n src: el.currentSrc || el.src || '',\n kind,\n wall: Date.now(),\n t: el.currentTime,\n rate: el.playbackRate || 1,\n paused: el.paused || el.ended,\n audible: !el.muted && el.volume > 0,\n volume: el.volume,\n duration: isFinite(el.duration) ? el.duration : null,\n ab: typeof el.webkitAudioDecodedByteCount === 'number' ? el.webkitAudioDecodedByteCount : null,\n })\n host.__vosMedia = M\n }\n const M = host.__vosMedia\n const EVENTS = ['playing', 'pause', 'ended', 'seeking', 'seeked', 'volumechange', 'ratechange', 'emptied']\n const note = (e) => {\n const el = e.target\n if (!el || typeof el.currentTime !== 'number' || !/^(VIDEO|AUDIO)$/.test(el.tagName || '')) return\n if (e.__vosNoted) return\n e.__vosNoted = true\n if (!el.__vosMediaId) {\n if (M.els.size >= ${MAX_ELEMENTS}) return\n el.__vosMediaId = ++M.seq\n M.els.add(el)\n }\n if (M.log.length < ${MAX_NOTES}) M.log.push(M.fields(el, e.type))\n }\n for (const type of EVENTS) document.addEventListener(type, note, true)\n const proto = window.HTMLMediaElement && window.HTMLMediaElement.prototype\n if (proto && proto.play) {\n const play = proto.play\n proto.play = function () {\n if (!this.__vosListening && !this.isConnected) {\n this.__vosListening = true\n for (const type of EVENTS) this.addEventListener(type, note)\n }\n return play.apply(this, arguments)\n }\n }\n})()`\n\n/**\n * The drain: the notes since the last drain, a `tick` for every element\n * followed (what it is doing now, which catches a note that never came),\n * the page's clock, and which document the log belongs to (a navigation\n * starts a new one).\n */\nexport const MEDIA_DRAIN_PROBE = `(() => {\n const M = window.__vosMedia\n if (!M) return { now: Date.now(), doc: null, notes: [] }\n const notes = M.log.splice(0)\n M.els.forEach((el) => notes.push(M.fields(el, 'tick')))\n return { now: Date.now(), doc: M.doc, notes }\n})()`\n\n/** One note from the page. */\nexport interface MediaNote {\n id: number\n tag: 'video' | 'audio'\n src: string\n kind: string\n wall: number\n t: number\n rate: number\n paused: boolean\n audible: boolean\n volume: number\n duration: number | null\n ab: number | null\n}\n\nexport interface MediaDrain {\n now: number\n doc: string | null\n notes: MediaNote[]\n}\n\ninterface Stretch {\n fromWall: number\n toWall: number\n t0: number\n rate: number\n}\n\ninterface Followed {\n tag: 'video' | 'audio'\n src: string\n step?: number\n duration?: number\n volume?: number\n played: boolean\n audioBytes: number | null\n open: { wall: number; t: number; rate: number } | null\n stretches: Stretch[]\n}\n\n/** A page sound with its full source, for the fetch; `meta` is what the take keeps. */\nexport interface HeardSound {\n meta: RecordingPageMedia\n /** the address as the page played it, query and all: fetched, never stored */\n src: string\n}\n\n/** What `meta.media[].src` keeps of an address: origin and path; a `blob:` or `data:` by its scheme. */\nexport function soundSrcForMeta(src: string): string {\n if (/^blob:/i.test(src)) return 'blob:'\n if (/^data:/i.test(src)) return src.slice(0, src.search(/[;,]/) + 1 || 5)\n try {\n const u = new URL(src)\n return `${u.origin}${u.pathname}`\n } catch {\n return ''\n }\n}\n\n/**\n * Accumulates the page's notes across a take, in the recorder's clock.\n * `add` takes each drain with the recorder's own `Date.now()` at the\n * moment it came back; `heard` closes what is still playing at the end\n * and maps every stretch to footage time.\n */\nexport class PageSoundLog {\n private byKey = new Map<string, Followed>()\n private openKeyOf = new Map<number, string>()\n private doc: string | null = null\n private lastWall = 0\n\n add(drain: MediaDrain | null, nodeNow: number, step?: number): void {\n if (!drain) return\n const skew = nodeNow - drain.now\n // A new document: what the old one was playing stopped with it, no\n // later than the last time it was seen.\n if (drain.doc !== this.doc) {\n if (this.doc !== null) this.closeAll(this.lastWall)\n this.openKeyOf.clear()\n this.doc = drain.doc\n }\n const notes = [...drain.notes].sort((a, b) => a.wall - b.wall)\n for (const n of notes) this.note(n, n.wall + skew, step)\n this.lastWall = nodeNow\n }\n\n private note(n: MediaNote, wall: number, step?: number): void {\n const key = `${this.doc}|${n.id}|${n.src}`\n const prevKey = this.openKeyOf.get(n.id)\n // The element moved on to another source: what it played before ended.\n if (prevKey && prevKey !== key) {\n const prev = this.byKey.get(prevKey)\n if (prev) this.close(prev, wall)\n }\n let f = this.byKey.get(key)\n if (!f) {\n if (!n.src) return\n f = {\n tag: n.tag,\n src: n.src,\n played: false,\n audioBytes: null,\n open: null,\n stretches: [],\n }\n this.byKey.set(key, f)\n }\n this.openKeyOf.set(n.id, key)\n if (n.duration !== null) f.duration = n.duration\n if (n.ab !== null) f.audioBytes = Math.max(f.audioBytes ?? 0, n.ab)\n if (!n.paused) f.played = true\n const stops = ['pause', 'ended', 'seeking', 'emptied'].includes(n.kind)\n const heard = !n.paused && n.audible && !stops\n // A resync point: the stretch so far ends here, and a new one starts\n // from the media time the page reports now.\n const resync = ['playing', 'seeked', 'ratechange'].includes(n.kind)\n if (f.open && (!heard || resync))\n this.close(\n f,\n wall,\n n.kind === 'ended' ? (n.duration ?? undefined) : undefined,\n )\n if (!f.open && heard) {\n f.open = { wall, t: n.t, rate: n.rate > 0 ? n.rate : 1 }\n f.volume = n.volume\n if (f.step === undefined && step !== undefined && step >= 0) f.step = step\n }\n }\n\n private close(f: Followed, wall: number, endT?: number): void {\n if (!f.open) return\n const { wall: from, t, rate } = f.open\n f.open = null\n if (wall <= from) return\n // The media time at the end is where the stretch was heading; an end\n // the page reported (`ended`) is the file's length.\n const to = endT ?? t + ((wall - from) / 1000) * rate\n f.stretches.push({\n fromWall: from,\n toWall: from + ((to - t) / rate) * 1000,\n t0: t,\n rate,\n })\n }\n\n private closeAll(wall: number): void {\n for (const f of this.byKey.values()) this.close(f, wall)\n }\n\n /**\n * Every element the page played, each heard stretch as footage seconds\n * `at` with media seconds `from`..`to`, none past `endMs` of footage.\n * A video whose decoder never decoded a byte of sound played none.\n */\n heard(clock: TakeClock, endWall: number, endMs: number): HeardSound[] {\n this.closeAll(endWall)\n const out: HeardSound[] = []\n for (const f of this.byKey.values()) {\n if (!f.played) continue\n const silentVideo = f.tag === 'video' && f.audioBytes === 0\n const intervals: RecordingPageMedia['intervals'] = []\n if (!silentVideo)\n for (const s of f.stretches)\n for (const c of clock.onCamera(s.fromWall, s.toWall)) {\n const at = c.atMs / 1000\n let from = s.t0 + ((c.wallMs - s.fromWall) / 1000) * s.rate\n let to = from + (c.ms / 1000) * s.rate\n if (f.duration !== undefined) to = Math.min(to, f.duration)\n const room = (endMs - c.atMs) / 1000\n if (room <= 0) continue\n to = Math.min(to, from + room * s.rate)\n from = Math.max(0, from)\n if (to - from < MIN_HEARD_S) continue\n intervals.push({\n at: +at.toFixed(3),\n from: +from.toFixed(3),\n to: +to.toFixed(3),\n })\n }\n out.push({\n src: f.src,\n meta: {\n ...(f.step !== undefined ? { step: f.step } : {}),\n src: soundSrcForMeta(f.src),\n tag: f.tag,\n ...(f.duration !== undefined\n ? { duration: +f.duration.toFixed(3) }\n : {}),\n ...(intervals.length && f.volume !== undefined\n ? { volume: +f.volume.toFixed(3) }\n : {}),\n intervals,\n ...(intervals.length ? {} : { muted: true }),\n },\n })\n }\n return out\n }\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 * The parts of a wall-clock stretch the camera saw: each sub-stretch\n * outside every off-camera wait, as its wall start (`wallMs`), its\n * footage start (`atMs`) and its length. A stretch an `await` cut in two\n * comes back as two; one wholly off camera as none.\n */\n onCamera(\n fromWall: number,\n toWall: number,\n ): { wallMs: number; atMs: number; ms: number }[] {\n const out: { wallMs: number; atMs: number; ms: number }[] = []\n let cur = Math.max(fromWall, this.t0)\n for (const p of this.pauses) {\n const pTo = p.to ?? Infinity\n if (pTo <= cur) continue\n if (p.from >= toWall) break\n if (p.from > cur)\n out.push({\n wallMs: cur,\n atMs: this.footageMs(cur),\n ms: p.from - cur,\n })\n cur = Math.max(cur, pTo)\n if (cur >= toWall) return out\n }\n if (toWall > cur)\n out.push({ wallMs: cur, atMs: this.footageMs(cur), ms: toWall - cur })\n return out\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","/**\n * The recorded surface is the viewport, exactly.\n *\n * The screencast reads the window's content surface, not the page's\n * emulated viewport. Playwright sizes a headless window TO the viewport,\n * assuming a headless window has no frame, and headless Chrome (the\n * `channel: 'chrome'` builds) gives it one: the page lays out at 1280x720\n * while the surface under it is 1280x633, and every frame of the take loses\n * the bottom 87 px (measured, Chrome 155 on macOS; a viewport of any size\n * loses the same strip, and a window made LARGER than the viewport hands\n * back more than the page). Two cases are exact already, and a fit there\n * measures and does nothing: Playwright's bundled headless shell, and a\n * page a persistent context opens with `newPage()` (a `--session` take),\n * while the first page of that same context and every page of a\n * `newContext()` (the default take, `--storage-state`) are short.\n *\n * So before the camera rolls: one screenshot says what the surface really\n * is, the window's bounds take the difference, and a second screenshot\n * says whether it landed. A driver that cannot (no Browser domain, a\n * window it may not move) is left as it was, and the meta's\n * `captureWidth`/`captureHeight` still say what was recorded.\n */\nimport { base64Bytes, jpegDims } from './recorder'\nimport type { RecorderCdp } from './driver'\n\nexport interface SurfaceSize {\n width: number\n height: number\n}\n\nexport interface SurfaceFit {\n before: SurfaceSize\n after: SurfaceSize\n}\n\n/** The surface the compositor hands back, in CSS px. */\nasync function surfaceSize(\n cdp: RecorderCdp,\n dpr: number,\n): Promise<SurfaceSize | null> {\n const shot = (await cdp.send('Page.captureScreenshot', {\n format: 'jpeg',\n quality: 1,\n })) as { data?: string }\n const dims = shot.data ? jpegDims(base64Bytes(shot.data)) : null\n if (!dims) return null\n return { width: Math.round(dims.w / dpr), height: Math.round(dims.h / dpr) }\n}\n\n/**\n * Make the surface the viewport. Returns what it measured, or null when\n * nothing could be measured; never throws, because a take made as before\n * is better than no take.\n */\nexport async function fitSurfaceToViewport(\n cdp: RecorderCdp,\n width: number,\n height: number,\n): Promise<SurfaceFit | null> {\n try {\n const ratio = (await cdp.send('Runtime.evaluate', {\n expression: 'devicePixelRatio',\n returnByValue: true,\n })) as { result?: { value?: unknown } }\n const value = ratio.result?.value\n const dpr = typeof value === 'number' && value > 0 ? value : 1\n const before = await surfaceSize(cdp, dpr)\n if (!before) return null\n let after = before\n // Twice at most: a window manager may round the first move.\n for (let tries = 0; tries < 2; tries++) {\n if (after.width === width && after.height === height) break\n const win = (await cdp.send('Browser.getWindowForTarget')) as {\n windowId: number\n bounds: { width?: number; height?: number }\n }\n const { width: ww, height: wh } = win.bounds\n if (ww === undefined || wh === undefined) break\n await cdp.send('Browser.setWindowBounds', {\n windowId: win.windowId,\n bounds: {\n width: ww + (width - after.width),\n height: wh + (height - after.height),\n },\n })\n after = (await surfaceSize(cdp, dpr)) ?? after\n }\n return { before, after }\n } catch {\n return null\n }\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 * A JavaScript expression evaluated in the page (awaited when it answers\n * a promise): the condition holds when its value is truthy, or, with\n * `equals`, when its value equals that one. For an app that keeps its\n * state in script rather than in the DOM (a canvas, a document model).\n */\n js?: string\n /** with `js`: the value the expression must equal (compared as JSON) */\n equals?: unknown\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 * with `js`: what the expression answered the last time it was read, as\n * JSON when it has a JSON form (absent for `undefined`), and in words\n * either way (`said`), or the error it threw (`threw`).\n */\n value?: unknown\n said?: string\n threw?: string\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/** The longest a js value is said in a line, in characters. */\nexport const JS_SAID_MAX = 120\n/** The most a js value kept on the step holds, in characters of JSON. */\nexport const JS_VALUE_MAX = 2048\n\n/**\n * The page script that evaluates a step's expression and answers what it\n * found, as a string (the one evaluate shape every driver shares). The\n * expression is the script author's own, run on their own page: it is\n * wrapped, never parsed, and a newline closes it before the paren so a\n * trailing line comment cannot swallow the wrapper.\n */\nexport function jsConditionScript(expr: string): string {\n return `(async () => {\n let v;\n try { v = await (${expr}\n ); } catch (e) { return JSON.stringify({ threw: String(e && e.message ? e.message : e) }) }\n const out = { truthy: !!v };\n try { const j = JSON.stringify(v); if (j !== undefined) out.json = j } catch (e) {}\n try { out.said = typeof v === 'string' ? JSON.stringify(v) : String(v) } catch (e) { out.said = typeof v }\n if (out.json !== undefined && typeof v !== 'string') out.said = out.json\n return JSON.stringify(out);\n})()`\n}\n\n/** Two JSON values alike: the same keys and values whatever the key order. */\nexport function sameJson(a: unknown, b: unknown): boolean {\n if (a === b) return true\n if (typeof a !== typeof b || a === null || b === null) return false\n if (typeof a !== 'object') return false\n if (Array.isArray(a) !== Array.isArray(b)) return false\n if (Array.isArray(a)) {\n const bb = b as unknown[]\n return a.length === bb.length && a.every((v, i) => sameJson(v, bb[i]))\n }\n const ao = a as Record<string, unknown>\n const bo = b as Record<string, unknown>\n const keys = Object.keys(ao)\n if (keys.length !== Object.keys(bo).length) return false\n return keys.every(\n (k) =>\n Object.prototype.hasOwnProperty.call(bo, k) && sameJson(ao[k], bo[k]),\n )\n}\n\n/** What a js expression answered, read once: the condition and the value. */\nasync function readJs(\n page: RecorderPage,\n c: { js: string; equals?: unknown },\n): Promise<ConditionState> {\n let raw: string\n try {\n raw = await page.evaluate<string>(jsConditionScript(c.js))\n } catch (e) {\n // An expression that does not parse never will: said, not retried as\n // \"not yet\". Anything else (a navigation under the read) is.\n const why = e instanceof Error ? e.message : String(e)\n if (\n /SyntaxError/.test(why) ||\n (e instanceof Error && e.name === 'SyntaxError')\n )\n return { holds: false, threw: `it does not parse: ${why.split('\\n')[0]}` }\n throw e\n }\n let got: { truthy?: boolean; json?: string; said?: string; threw?: string }\n try {\n got = JSON.parse(raw) as typeof got\n } catch {\n return { holds: false }\n }\n if (got.threw !== undefined) return { holds: false, threw: got.threw }\n let value: unknown\n let hasValue = false\n if (got.json !== undefined) {\n try {\n value = JSON.parse(got.json)\n hasValue = true\n } catch {\n // not JSON after all: said in words only\n }\n }\n const holds =\n c.equals !== undefined\n ? hasValue && sameJson(value, c.equals)\n : got.truthy === true\n return {\n holds,\n ...(hasValue ? { value } : {}),\n said: clip(got.said ?? 'undefined', JS_SAID_MAX),\n }\n}\n\nconst clip = (s: string, max: number): string =>\n s.length > max ? `${s.slice(0, max - 1)}…` : s\n\n/**\n * A js value as a step keeps it (`meta.steps[].value`): the value itself\n * while its JSON fits, else its JSON cut short as a string.\n */\nexport function keptValue(value: unknown): unknown {\n const json = JSON.stringify(value)\n if (json === undefined) return undefined\n return json.length <= JS_VALUE_MAX ? value : clip(json, JS_VALUE_MAX)\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.js !== undefined) return await readJs(page, { ...c, js: c.js })\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.js !== undefined)\n return c.equals !== undefined\n ? `${sayJs(c.js)} to equal ${clip(JSON.stringify(c.equals) ?? 'undefined', JS_SAID_MAX)}`\n : `${sayJs(c.js)} to hold`\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.js !== undefined) {\n if (last.threw !== undefined)\n return `${sayJs(c.js)} threw for ${t} (${clip(last.threw, JS_SAID_MAX)})`\n const was = last.said ?? 'never answered'\n return c.equals !== undefined\n ? `${sayJs(c.js)} was ${was}, not ${clip(JSON.stringify(c.equals) ?? 'undefined', JS_SAID_MAX)}, for ${t}`\n : `${sayJs(c.js)} was ${was} for ${t}`\n }\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/** An expression as a line names it: in backticks, cut short. */\nexport function sayJs(expr: string): string {\n return `js \\`${clip(expr.replace(/\\s+/g, ' ').trim(), 80)}\\``\n}\n\n/** A kept value as a line says it: its JSON, cut short. */\nexport function sayValue(value: unknown): string {\n return clip(JSON.stringify(value) ?? 'undefined', JS_SAID_MAX)\n}\n","/**\n * When a page counts as ready for the take to begin. The default is the\n * DOM: after `load`, the page must make no DOM change for a beat (counted\n * from outside, the way an `await` reload's settle is), at most a few\n * seconds. Network idle is the opt-in: plenty of real apps hold a socket\n * open or keep an analytics beacon going and never go network-idle, so a\n * take that waited for it started after its whole timeout, every time.\n */\nimport type { RecorderPage, RecorderResponse } from './driver'\nimport { realSleep } from './driver'\nimport { DOM_QUIET_MS, domSettled } from './waits'\n\n/** How a page counts as ready: its DOM settled (default), or its network went idle. */\nexport type ReadyMode = 'networkidle' | 'dom'\nexport const READY_MODES: readonly ReadyMode[] = ['dom', 'networkidle']\nexport const DEFAULT_READY: ReadyMode = 'dom'\n\n/** The longest a navigation waits for `load` or network idle. */\nexport const NAV_TIMEOUT_MS = 45_000\n/** The longest the settle waits on a page that never stops changing. */\nexport const READY_SETTLE_CAP_MS = 8000\n/** After network idle, the beat a hydration takes (what the recorder always gave it). */\nexport const NETWORKIDLE_HYDRATION_MS = 800\n\n/** How the first load settled: the done event's `ready`. */\nexport interface ReadyReport {\n mode: ReadyMode\n /** ms from the navigation's start until the page counted as ready */\n ms: number\n /**\n * The wait gave up instead of the page settling: the DOM never stopped\n * changing within the cap (dom), or network idle never came within\n * the navigation timeout (networkidle). Recorded anyway either way.\n */\n capped: boolean\n}\n\n/** Why a ready mode is not one, or null. */\nexport function readyProblem(v: unknown): string | null {\n if (v === undefined) return null\n return typeof v === 'string' && (READY_MODES as string[]).includes(v)\n ? null\n : `ready must be ${READY_MODES.map((m) => `\"${m}\"`).join(' or ')}`\n}\n\nexport interface ReadyOpts {\n sleep: (ms: number) => Promise<void>\n now?: () => number\n /** the settle's cap (default `READY_SETTLE_CAP_MS`) */\n capMs?: number\n /** the navigation's own timeout (default `NAV_TIMEOUT_MS`) */\n timeoutMs?: number\n}\n\n/**\n * Wait for a page that is navigating (or has just navigated) to be ready:\n * `navigate` starts the navigation with the `waitUntil` the mode asks for;\n * in `dom` mode the DOM settle follows `load`. A navigation that times\n * out is not fatal: the take goes on from whatever the page shows, and the\n * report says it was capped.\n */\nexport async function untilReady(\n page: RecorderPage,\n mode: ReadyMode,\n navigate: (opts: {\n waitUntil: 'networkidle' | 'load'\n timeout: number\n }) => Promise<RecorderResponse | null>,\n opts: ReadyOpts,\n): Promise<{ response: RecorderResponse | null; ready: ReadyReport }> {\n const now = opts.now ?? Date.now\n const start = now()\n const timeout = opts.timeoutMs ?? NAV_TIMEOUT_MS\n if (mode === 'networkidle') {\n let idle = true\n const response = await navigate({\n waitUntil: 'networkidle',\n timeout,\n }).catch(() => {\n idle = false\n return null\n })\n await opts.sleep(NETWORKIDLE_HYDRATION_MS)\n return {\n response,\n ready: { mode, ms: Math.round(now() - start), capped: !idle },\n }\n }\n const response = await navigate({ waitUntil: 'load', timeout }).catch(\n () => null,\n )\n const settled = await domSettled(page, {\n sleep: opts.sleep,\n now,\n quietMs: DOM_QUIET_MS,\n capMs: opts.capMs ?? READY_SETTLE_CAP_MS,\n })\n return {\n response,\n ready: { mode, ms: Math.round(now() - start), capped: !settled.settled },\n }\n}\n\n/**\n * An `await`'s reload between polls, under the take's ready mode: the\n * reload waits for `load` (dom) or network idle (networkidle), at most\n * the await's own timeout, and then the DOM settles either way, because\n * network quiet is not a drawn page (a list rendered from its data lands\n * after it). A page that never goes network-idle no longer costs a whole\n * navigation timeout per poll.\n */\nexport async function reloadUntilReady(\n page: RecorderPage,\n mode: ReadyMode,\n timeoutMs: number,\n opts: { sleep?: (ms: number) => Promise<void> } = {},\n): Promise<void> {\n const nav = {\n waitUntil:\n mode === 'networkidle' ? ('networkidle' as const) : ('load' as const),\n timeout: Math.min(NAV_TIMEOUT_MS, timeoutMs),\n }\n await (page.reload ? page.reload(nav) : page.goto(page.url(), nav)).catch(\n () => null,\n )\n await domSettled(page, { sleep: opts.sleep ?? realSleep })\n}\n\n/** The ready report in words, for the take's log. */\nexport function readyLine(r: ReadyReport): string {\n const s = (r.ms / 1000).toFixed(1)\n if (r.mode === 'networkidle')\n return r.capped\n ? `(networkidle timeout after ${s} s, continuing)`\n : `(network idle after ${s} s)`\n return r.capped\n ? `(the page was still changing after ${s} s, starting anyway)`\n : `(the page settled after ${s} s)`\n}\n","/**\n * The canvas gestures, the pure parts: key chords and sequences, the\n * modifiers a drag holds, a drawn path and its timing, a click's count and\n * button, and the overrun report. What a whiteboard, a design tool or a\n * timeline is recorded with, said as data so a script can carry it and\n * both hosts validate it in the same words.\n *\n * None of it reaches the cursor track as key identity: a key is a typing\n * ping (when and where), a modifier is nothing at all, and a path is its\n * points.\n */\n\n/** The modifiers a chord or a drag may hold. `Mod` is Meta on macOS, Control elsewhere. */\nexport const MODIFIERS = [\n 'Shift',\n 'Control',\n 'Alt',\n 'Meta',\n 'Mod',\n 'ControlOrMeta',\n] as const\nexport type Modifier = (typeof MODIFIERS)[number]\n\n/** The modifiers a drag names (the platform-neutral one is `Mod`). */\nexport const DRAG_MODIFIERS = [\n 'Alt',\n 'Shift',\n 'Meta',\n 'Control',\n 'Mod',\n] as const\nexport type DragModifier = (typeof DRAG_MODIFIERS)[number]\n\n/** Named keys a chord may end on, besides a single character. */\nconst NAMED_KEYS = new Set([\n 'Escape',\n 'Enter',\n 'Tab',\n 'Backspace',\n 'Delete',\n 'Insert',\n 'ArrowUp',\n 'ArrowDown',\n 'ArrowLeft',\n 'ArrowRight',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n 'Space',\n 'CapsLock',\n 'ContextMenu',\n 'Backquote',\n 'Minus',\n 'Equal',\n 'BracketLeft',\n 'BracketRight',\n 'Backslash',\n 'Semicolon',\n 'Quote',\n 'Comma',\n 'Period',\n 'Slash',\n 'NumpadAdd',\n 'NumpadSubtract',\n 'NumpadMultiply',\n 'NumpadDivide',\n 'NumpadDecimal',\n 'NumpadEnter',\n])\n\nconst isModifier = (s: string): s is Modifier =>\n (MODIFIERS as readonly string[]).includes(s)\n\n/** A key name the browser's keyboard answers: a character, a code, a named key. */\nexport function isKeyName(k: string): boolean {\n if ([...k].length === 1) return k.trim().length === 1 || k === ' '\n if (NAMED_KEYS.has(k)) return true\n return (\n /^Key[A-Z]$/.test(k) ||\n /^Digit[0-9]$/.test(k) ||\n /^Numpad[0-9]$/.test(k) ||\n /^F([1-9]|1[0-9]|2[0-4])$/.test(k)\n )\n}\n\n/**\n * A chord split into its modifiers and its key: `Shift+D` is\n * `{ mods: ['Shift'], key: 'D' }`, a bare `r` has no modifiers, and `+`\n * names the plus key when it ends the chord (`Shift++`).\n */\nexport function splitChord(chord: string): { mods: string[]; key: string } {\n if (chord === '+') return { mods: [], key: '+' }\n const plusKey = chord.endsWith('++')\n const parts = (plusKey ? chord.slice(0, -2) : chord).split('+')\n if (plusKey) return { mods: parts, key: '+' }\n const key = parts.pop() ?? ''\n return { mods: parts, key }\n}\n\n/** Why a chord is not one the recorder can press, or null. */\nexport function chordProblem(chord: unknown): string | null {\n if (typeof chord !== 'string' || !chord)\n return 'must be a key name or a chord like \"Shift+D\"'\n const { mods, key } = splitChord(chord)\n for (const m of mods) {\n if (!isModifier(m))\n return `\"${chord}\": \"${m}\" is not a modifier (one of ${MODIFIERS.join(', ')})`\n }\n if (new Set(mods).size !== mods.length)\n return `\"${chord}\" names a modifier twice`\n if (!key) return `\"${chord}\" ends without a key`\n // A modifier alone is a key: Shift pressed and released.\n if (isModifier(key)) {\n if (mods.length) return `\"${chord}\" ends on a modifier, not a key`\n return null\n }\n if (!isKeyName(key))\n return `\"${chord}\": \"${key}\" is not a key (a single character, a named key like Escape or ArrowLeft, F1 to F24, or a code like KeyA or Digit1)`\n return null\n}\n\n/**\n * A chord as the browser's keyboard takes it: `Mod` becomes\n * `ControlOrMeta`, which the browser resolves to Meta on macOS and to\n * Control elsewhere, where the browser runs.\n */\nexport function resolveChord(chord: string): string {\n const { mods, key } = splitChord(chord)\n const k = key === 'Mod' ? 'ControlOrMeta' : key\n return [...mods.map((m) => (m === 'Mod' ? 'ControlOrMeta' : m)), k].join('+')\n}\n\n/** A `press` step's keys as a list: one chord or a sequence. */\nexport function pressSequence(step: {\n key?: string\n keys?: string | string[]\n}): string[] {\n if (step.keys !== undefined)\n return typeof step.keys === 'string' ? [step.keys] : step.keys\n return step.key ? [step.key] : []\n}\n\n/** The pause between two keys of a sequence, a person's hand: ms. */\nexport const KEY_SEQUENCE_GAP_MS = 150\n/**\n * What one key costs beyond the script's gaps: the browser's round trip for\n * the press (a keydown and a keyup the page answers). Part of the plan, so a\n * sequence on an idle page is never \"slower than scripted\".\n */\nexport const KEY_ROUNDTRIP_MS = 50\n\n/** A key sequence's plan, ms: its gaps, and each key's round trip. */\nexport const keySequencePlanMs = (keys: number): number =>\n Math.max(0, keys - 1) * KEY_SEQUENCE_GAP_MS + keys * KEY_ROUNDTRIP_MS\n\n/** The hold after a drag's release, ms: the recorder's, part of the gesture. */\nexport const DRAG_HOLD_MS = 400\n/** The most keys one press step may name. */\nexport const MAX_KEYS = 50\n\n/** A drag modifier as the keyboard holds it. */\nexport function resolveModifier(m: DragModifier): string {\n return m === 'Mod' ? 'ControlOrMeta' : m\n}\n\n/**\n * The modifier bits of a raw pointer event (the pen path): Alt 1, Control\n * 2, Meta 4, Shift 8, with `Mod` read for the platform the browser runs on.\n */\nexport function modifierBits(\n mods: readonly DragModifier[],\n platform: 'mac' | 'linux' | 'windows' | undefined,\n): number {\n let bits = 0\n for (const m of mods) {\n const k = m === 'Mod' ? (platform === 'mac' ? 'Meta' : 'Control') : m\n bits |= k === 'Alt' ? 1 : k === 'Control' ? 2 : k === 'Meta' ? 4 : 8\n }\n return bits\n}\n\n/** A click's button, and the pointer button number the cursor track records. */\nexport const CLICK_BUTTONS = ['left', 'right', 'middle'] as const\nexport type ClickButton = (typeof CLICK_BUTTONS)[number]\nexport const buttonNumber = (b: ClickButton | undefined): 0 | 1 | 2 =>\n b === 'right' ? 2 : b === 'middle' ? 1 : 0\n\n/**\n * The pause between the presses of a double or triple click, well inside\n * every platform's double-click interval (500 ms on macOS and Windows by\n * default), so the page reads one gesture.\n */\nexport const MULTI_CLICK_GAP_MS = 90\n\n/**\n * One point of a drawn path: viewport CSS px, with an optional time in ms\n * (from the path's start) and an optional pressure in [0, 1]. Written as a\n * tuple `[x, y]`, `[x, y, t]`, `[x, y, t, pressure]`, or an object.\n */\nexport type PathPoint =\n | [number, number]\n | [number, number, number]\n | [number, number, number, number]\n | { x: number; y: number; t?: number; pressure?: number }\n\n/** A path point as the recorder replays it. */\nexport interface PathSample {\n x: number\n y: number\n /** ms from the path's first point */\n at: number\n pressure?: number\n}\n\n/** The most points one path may hold. */\nexport const MAX_PATH_POINTS = 20_000\n/** An untimed path's travel when the step names no ms. */\nexport const PATH_DEFAULT_MS = 700\n\nconst finite = (v: unknown): v is number =>\n typeof v === 'number' && Number.isFinite(v)\n\nfunction readPoint(\n raw: unknown,\n): { x: number; y: number; t?: number; pressure?: number } | string {\n if (Array.isArray(raw)) {\n if (raw.length < 2 || raw.length > 4)\n return 'must be [x, y], [x, y, tMs] or [x, y, tMs, pressure]'\n const [x, y, t, pressure] = raw as unknown[]\n if (!finite(x) || !finite(y)) return 'x and y must be numbers (CSS px)'\n if (t !== undefined && !finite(t)) return 'its time must be a number of ms'\n if (pressure !== undefined && !finite(pressure))\n return 'its pressure must be a number from 0 to 1'\n return {\n x,\n y,\n ...(t !== undefined ? { t } : {}),\n ...(pressure !== undefined ? { pressure } : {}),\n }\n }\n if (typeof raw === 'object' && raw !== null) {\n const o = raw as Record<string, unknown>\n const extra = Object.keys(o).filter(\n (k) => !['x', 'y', 't', 'pressure'].includes(k),\n )\n if (extra.length)\n return `takes x, y, t and pressure, not ${extra.join(', ')}`\n if (!finite(o.x) || !finite(o.y)) return 'x and y must be numbers (CSS px)'\n if (o.t !== undefined && !finite(o.t)) return 'its t must be a number of ms'\n if (o.pressure !== undefined && !finite(o.pressure))\n return 'its pressure must be a number from 0 to 1'\n return {\n x: o.x,\n y: o.y,\n ...(o.t !== undefined ? { t: o.t as number } : {}),\n ...(o.pressure !== undefined ? { pressure: o.pressure as number } : {}),\n }\n }\n return 'must be [x, y] or { x, y }'\n}\n\n/**\n * A path's points read and checked, or the problems in words. The same\n * reader takes an inline `path` and the contents of a path file (an array\n * of points, or `{ \"points\": [...] }`).\n */\nexport function readPath(\n raw: unknown,\n): { points: PathSample[]; timed: boolean } | { problems: string[] } {\n const list =\n typeof raw === 'object' &&\n raw !== null &&\n !Array.isArray(raw) &&\n Array.isArray((raw as { points?: unknown }).points)\n ? (raw as { points: unknown[] }).points\n : raw\n if (!Array.isArray(list))\n return { problems: ['must be an array of points, or { \"points\": [...] }'] }\n if (list.length < 2) return { problems: ['needs at least two points'] }\n if (list.length > MAX_PATH_POINTS)\n return { problems: [`holds more than ${MAX_PATH_POINTS} points`] }\n const problems: string[] = []\n const read: { x: number; y: number; t?: number; pressure?: number }[] = []\n list.forEach((p, i) => {\n const r = readPoint(p)\n if (typeof r === 'string') problems.push(`point ${i} ${r}`)\n else {\n if (r.x < 0 || r.y < 0)\n problems.push(`point ${i} is off the viewport (x and y are ≥ 0)`)\n if (r.pressure !== undefined && (r.pressure < 0 || r.pressure > 1))\n problems.push(`point ${i} pressure must be from 0 to 1`)\n read.push(r)\n }\n })\n if (problems.length) return { problems: problems.slice(0, 5) }\n const timedCount = read.filter((p) => p.t !== undefined).length\n if (timedCount !== 0 && timedCount !== read.length)\n return {\n problems: [\n 'every point carries a time or none does: a path is replayed by its own timing, or evenly over ms',\n ],\n }\n const timed = timedCount > 0\n if (timed) {\n for (let i = 1; i < read.length; i++)\n if ((read[i].t as number) < (read[i - 1].t as number))\n return {\n problems: [`point ${i}'s time runs backwards (times never decrease)`],\n }\n }\n const t0 = timed ? (read[0].t as number) : 0\n return {\n timed,\n points: read.map((p) => ({\n x: p.x,\n y: p.y,\n at: timed ? (p.t as number) - t0 : 0,\n ...(p.pressure !== undefined ? { pressure: p.pressure } : {}),\n })),\n }\n}\n\n/**\n * The path's schedule: a timed path keeps its own times (from its first\n * point), an untimed one spreads its points evenly over `ms` (default\n * 700). The last point is at the path's whole duration.\n */\nexport function schedulePath(\n path: { points: PathSample[]; timed: boolean },\n ms: number | undefined,\n): PathSample[] {\n if (path.timed) return path.points\n const dur = ms ?? PATH_DEFAULT_MS\n const n = path.points.length\n return path.points.map((p, i) => ({\n ...p,\n at: n > 1 ? Math.round((dur * i) / (n - 1)) : 0,\n }))\n}\n\n/** How long a scheduled path takes, ms. */\nexport const pathDurationMs = (s: readonly PathSample[]): number =>\n s.length ? s[s.length - 1].at : 0\n\n/**\n * A paced gesture that ran past its script: the wall time it took against\n * the time the script planned for it (a drag's travel, a path's timing,\n * typing's characters × delay, a key sequence's gaps). Reported when the\n * gesture took more than a fifth longer, the sign of a page that could not\n * keep up with what it was sent.\n */\nexport interface StepOverrun {\n step: number\n id?: string\n do: string\n plannedMs: number\n tookMs: number\n overrunMs: number\n}\n\n/** The share past the plan that counts as an overrun. */\nexport const OVERRUN_SHARE = 0.2\n/** A plan shorter than this is not measured: its noise is the round trip. */\nexport const OVERRUN_MIN_PLANNED_MS = 100\n/**\n * The least a gesture must run over to count, ms: below it the difference\n * is one slow sample or round trip on a busy machine, never a page that\n * fell behind, however short the gesture.\n */\nexport const OVERRUN_MIN_MS = 100\n\n/** The overrun, ms, or null when the gesture kept to its plan. */\nexport function overrunOf(plannedMs: number, tookMs: number): number | null {\n if (!(plannedMs >= OVERRUN_MIN_PLANNED_MS)) return null\n if (tookMs <= plannedMs * (1 + OVERRUN_SHARE)) return null\n if (tookMs - plannedMs < OVERRUN_MIN_MS) return null\n return Math.round(tookMs - plannedMs)\n}\n\n/** The overruns in one line for the log and the done event, or null when none. */\nexport function overrunLine(overruns: readonly StepOverrun[]): string | null {\n if (!overruns.length) return null\n const planned = overruns.reduce((a, o) => a + o.plannedMs, 0)\n const took = overruns.reduce((a, o) => a + o.tookMs, 0)\n const ratio = planned > 0 ? took / planned : 0\n const n = overruns.length\n const which = overruns\n .map((o) => `#${o.step}${o.id ? ` (${o.id})` : ''} ${o.do}`)\n .join(', ')\n return `${n} step${n === 1 ? '' : 's'} ran ${ratio.toFixed(1)}× slower than scripted (${which}): the page could not keep up; add settle or raise ms`\n}\n","/**\n * The `paste` step, the pure parts: what a file is pasted as, and the two\n * page scripts that put an item where a person's ⌘V finds it.\n *\n * The first rung is the browser's own clipboard: the item is written with\n * `navigator.clipboard.write` (the context is granted clipboard access\n * first), and the recorder then presses the platform's paste chord, so the\n * page receives a TRUSTED keydown and a trusted `paste` event carrying the\n * item, and a page that reads `navigator.clipboard.read()` itself sees it\n * there too. A headless browser keeps its own clipboard, so nothing on the\n * machine's clipboard is touched.\n *\n * When the browser refuses the write (no clipboard access on this driver,\n * a type it will not hold), the second rung dispatches the paste in the\n * page: a `paste` event with a `DataTransfer` holding the item on the\n * focused element, and `navigator.clipboard.read`/`readText` answering the\n * item for the rest of the take. Those events are untrusted, which the\n * recorder says.\n *\n * Both scripts are strings, the one evaluate shape every driver shares,\n * and neither carries anything the cursor track keeps: a paste is a typing\n * ping, never its contents.\n */\n\n/** How long after a dispatched paste is first read its item stays on the async reads, ms. */\nexport const PASTE_READ_WINDOW_MS = 300\n/** How long a dispatched paste's item stays on the async reads when nothing reads it, ms. */\nexport const PASTE_UNREAD_MS = 3000\n\n/** The most bytes a pasted file may hold. */\nexport const PASTE_MAX_BYTES = 10 * 1024 * 1024\n\n/** The file types a paste takes, by extension. */\nexport const PASTE_TYPES: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.webp': 'image/webp',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.txt': 'text/plain',\n '.md': 'text/plain',\n '.html': 'text/html',\n '.htm': 'text/html',\n '.json': 'text/plain',\n '.csv': 'text/plain',\n}\n\n/** A pasted file's type from its name, or null when a paste does not take it. */\nexport function pasteTypeOf(name: string): string | null {\n const dot = name.lastIndexOf('.')\n if (dot < 0) return null\n return PASTE_TYPES[name.slice(dot).toLowerCase()] ?? null\n}\n\n/** What a paste puts on the clipboard: words, or a file's bytes (base64) with its type and name. */\nexport interface PasteItem {\n text?: string\n b64?: string\n type?: string\n name?: string\n}\n\n/**\n * The page script that builds the item's blobs: an image other than PNG\n * is redrawn as PNG for the clipboard (the one image type every browser\n * holds) and an SVG rides as its markup too, so an app that reads text\n * finds it. Shared by both rungs.\n */\nconst BUILD = (item: PasteItem) => `\n const item = ${JSON.stringify(item)};\n const bytes = item.b64 ? Uint8Array.from(atob(item.b64), (c) => c.charCodeAt(0)) : null;\n const asText = bytes ? new TextDecoder().decode(bytes) : null;\n async function blobs() {\n if (item.text !== undefined) return { 'text/plain': new Blob([item.text], { type: 'text/plain' }) };\n const type = item.type;\n if (type === 'text/plain') return { 'text/plain': new Blob([asText], { type }) };\n if (type === 'text/html') return { 'text/html': new Blob([asText], { type }), 'text/plain': new Blob([asText], { type: 'text/plain' }) };\n if (type === 'image/svg+xml') return { 'image/svg+xml': new Blob([bytes], { type }), 'text/plain': new Blob([asText], { type: 'text/plain' }) };\n if (type === 'image/png') return { 'image/png': new Blob([bytes], { type }) };\n const bmp = await createImageBitmap(new Blob([bytes], { type }));\n const c = document.createElement('canvas');\n c.width = bmp.width; c.height = bmp.height;\n c.getContext('2d').drawImage(bmp, 0, 0);\n const png = await new Promise((r) => c.toBlob(r, 'image/png'));\n return { 'image/png': png };\n }\n`\n\n/**\n * Rung one: write the item to the browser's clipboard. Answers 'ok', or\n * 'refused: <why>'. An SVG the clipboard will not hold as an image is\n * written as its markup alone.\n */\nexport function stageClipboardScript(item: PasteItem): string {\n return `(async () => {\n ${BUILD(item)}\n try {\n if (!navigator.clipboard || typeof ClipboardItem === 'undefined') return 'refused: this page has no clipboard';\n const b = await blobs();\n try {\n await navigator.clipboard.write([new ClipboardItem(b)]);\n } catch (e) {\n if (!b['text/plain'] || Object.keys(b).length === 1) throw e;\n await navigator.clipboard.write([new ClipboardItem({ 'text/plain': b['text/plain'] })]);\n }\n return 'ok';\n } catch (e) {\n return 'refused: ' + (e && e.message ? e.message : String(e));\n }\n})()`\n}\n\n/**\n * Rung two: the paste dispatched in the page, on the focused element (or\n * the body), with the item in its `clipboardData`; and the async clipboard\n * reads answer the item from here on. A plain field the page did not take\n * the paste for gets the words inserted, as the browser's own paste does.\n * Answers 'ok', or 'failed: <why>'.\n */\nexport function syntheticPasteScript(\n item: PasteItem,\n opts: { original?: boolean } = {},\n): string {\n return `(async () => {\n ${BUILD(item)}\n try {\n // With original, an image file is handed over as its own bytes and type\n // (an SVG also as its markup), never redrawn.\n const b = ${opts.original ? `item.type === 'image/svg+xml' ? { 'image/svg+xml': new Blob([bytes], { type: item.type }), 'text/plain': new Blob([asText], { type: 'text/plain' }) } : { [item.type]: new Blob([bytes], { type: item.type }) }` : 'await blobs()'};\n const dt = new DataTransfer();\n let file = null;\n for (const [type, blob] of Object.entries(b)) {\n if (type.startsWith('image/')) {\n file = new File([blob], item.name || 'image.png', { type: blob.type || type });\n dt.items.add(file);\n } else dt.setData(type, await blob.text());\n }\n try {\n // The async reads answer the item for THIS paste only: shortly after\n // the first read (an app may read text and items in turn), or after a\n // few seconds when nothing reads, the browser's own reads come back,\n // so a later paste through the clipboard is the clipboard's.\n const staged = [new ClipboardItem(b)];\n const clip = navigator.clipboard;\n const own = { read: Object.prototype.hasOwnProperty.call(clip, 'read'), readText: Object.prototype.hasOwnProperty.call(clip, 'readText') };\n const was = { read: clip.read, readText: clip.readText };\n let restored = false;\n const restore = () => {\n if (restored) return;\n restored = true;\n for (const k of ['read', 'readText']) {\n if (own[k]) clip[k] = was[k];\n else delete clip[k];\n }\n };\n let soon = null;\n const readOnce = () => { if (!soon) soon = setTimeout(restore, ${PASTE_READ_WINDOW_MS}) };\n clip.read = async () => { readOnce(); return staged };\n clip.readText = async () => { readOnce(); return b['text/plain'] ? b['text/plain'].text() : '' };\n setTimeout(restore, ${PASTE_UNREAD_MS});\n } catch {}\n const target = document.activeElement || document.body;\n const ev = new ClipboardEvent('paste', { clipboardData: dt, bubbles: true, cancelable: true, composed: true });\n const taken = !target.dispatchEvent(ev);\n const words = dt.getData('text/plain');\n if (!taken && words && (target.isContentEditable || /^(INPUT|TEXTAREA)$/.test(target.tagName)))\n document.execCommand('insertText', false, words);\n return 'ok';\n } catch (e) {\n return 'failed: ' + (e && e.message ? e.message : String(e));\n }\n})()`\n}\n","/**\n * A gesture that waits on the app (`settle`): after the gesture, the\n * recorder waits until the page has made no DOM change and painted no new\n * frame for a beat, at most a few seconds. A heavy canvas falls behind\n * under load, and a script paced by the wall clock then outruns it: the\n * next stroke is drawn before the app has processed the last one.\n *\n * The DOM half is the recorder's one DOM-settle reader (`domSettled`, the\n * same an `await`'s reload lets the page finish with). The paint half is\n * the screencast: it emits a frame only when the compositor painted\n * something new, a canvas redrawn by `requestAnimationFrame` included, and\n * it is read from here rather than by an animation frame in the page,\n * which a background tab never fires. The two are one count: the page's\n * DOM changes plus the frames captured so far. A rehearsal captures no\n * frames, so there it waits on the DOM alone.\n */\nimport type { RecorderPage } from './driver'\nimport { domSettled } from './waits'\n\n/** The quiet a settle waits for: no DOM change and no new frame, ms. */\nexport const APP_QUIET_MS = 300\n/** The longest a settle waits on a page that never stops changing, ms. */\nexport const APP_SETTLE_CAP_MS = 4000\n\n/** The verbs a settle follows: the ones that send the page input. */\nexport const SETTLE_VERBS = new Set([\n 'hover',\n 'click',\n 'type',\n 'press',\n 'scroll',\n 'move',\n 'drag',\n 'paste',\n])\n\n/**\n * How long ago the page last changed its DOM, in ms by the page's own clock,\n * or -1 when this is the first look at this document (the reader is\n * installed now and knows no history). A string, the one evaluate shape\n * every driver shares.\n */\nexport const CHANGE_AGE_PROBE = `(() => {\n const w = window;\n if (!w.__vosChangeAt) {\n w.__vosChangeAt = { at: Date.now() };\n new MutationObserver(() => { w.__vosChangeAt.at = Date.now() })\n .observe(document, { subtree: true, childList: true, attributes: true, characterData: true });\n return -1;\n }\n return Date.now() - w.__vosChangeAt.at;\n})()`\n\n/** Whether a step waits on the app after its gesture: its own `settle`, else the script's. */\nexport function settleOn(\n step: { do: string; settle?: boolean },\n scriptDefault: boolean | undefined,\n): boolean {\n if (!SETTLE_VERBS.has(step.do)) return false\n return step.settle ?? scriptDefault ?? false\n}\n\n/**\n * Wait for the app: no DOM change and no new captured frame for `quietMs`,\n * at most `capMs`. `frames` reads how many frames the capture has kept.\n */\nexport async function appSettled(\n page: Pick<RecorderPage, 'evaluate'>,\n frames: () => number,\n opts: {\n sleep: (ms: number) => Promise<void>\n now?: () => number\n quietMs?: number\n capMs?: number\n /** ms since the last captured frame, or null when none was captured */\n sinceFrame?: () => number | null\n },\n): Promise<{ settled: boolean; ms: number }> {\n const quiet = opts.quietMs ?? APP_QUIET_MS\n // Already still: the page's last DOM change and the last frame are both\n // older than the quiet window, so there is nothing to wait for. The\n // window is counted from the last change, never from the settle's start.\n const age = await page.evaluate<number>(CHANGE_AGE_PROBE).catch(() => -1)\n const frameAge = opts.sinceFrame?.() ?? null\n if (\n typeof age === 'number' &&\n age >= quiet &&\n (frameAge === null || frameAge >= quiet)\n )\n return { settled: true, ms: 0 }\n // The DOM reader polls the page's change count; this hands it the count\n // with the frames added, so a paint is a change like a mutation is.\n const counted = {\n evaluate: async (script: string) => {\n const n = await page.evaluate<number>(script).catch(() => 0)\n return (typeof n === 'number' && n > 0 ? n : 0) + frames()\n },\n } as unknown as RecorderPage\n return domSettled(counted, {\n sleep: opts.sleep,\n ...(opts.now ? { now: opts.now } : {}),\n quietMs: quiet,\n capMs: opts.capMs ?? APP_SETTLE_CAP_MS,\n tickMs: 50,\n })\n}\n","/**\n * `peers`: other people on the same page, off camera. A collaboration\n * product shows best with a second person on the canvas: their cursor, the\n * shape they drew, the comment they left, arriving in the filmed page the\n * way the app syncs them. A peer is a second browser context (its own\n * cookies, so its own user, from its own storage state or none) on the\n * same URL, driven by its own step list, interleaved with the take's.\n *\n * What a peer is, and is not:\n *\n * - NOT FILMED. Only the take's own page is captured. A peer's page is\n * never screencast, scanned, masked or listened to; what it does reaches\n * the footage only through the app (its sync, its presence, its remote\n * cursors), which is what a viewer would see.\n * - NOT ON THE CURSOR TRACK. A peer's pointer moves its own page; the take's\n * CursorTrack is synthesized from the take's own steps alone, so a zoom,\n * a click ring or a dwell is never planned on a peer's gesture.\n * - ORDERED BY THE TAKE'S STEPS. A peer step may name a take step by id:\n * `with` starts it as that step starts (the two run together), `after` as\n * that step ends. A step naming neither follows the peer's previous step\n * at once; a peer's first step with neither starts as the camera rolls.\n * The take never waits on a peer: it waits on what the peer's work\n * SHOWS, with an `expect` or an `await` on its own page, so the footage\n * holds exactly the moment the sync landed. When the take's steps end,\n * a peer step still waiting on a trigger never runs (said), and one\n * already running finishes, bounded, before the trailing hold.\n * - PACED, NOT INSTANT. A peer's pointer glides on the same clock as the\n * take's (an app that draws remote cursors shows it travelling) and its\n * typing is paced per key, so what it does reads as a person.\n * - BOUNDED. Every peer step runs inside its own bound, as a take step\n * does; a selector that never appears or a check that never holds is a\n * skip with its reason, listed with the take's (`--strict` fails on it).\n *\n * A peer takes the take's gestures and checks (`wait`, `move`, `hover`,\n * `click`, `type`, `press`, `scroll`, `drag` with an inline `path`, and\n * `expect`), never a `paste`, a `download`, an `await` (a peer that must\n * wait for a result is the take's `await`), a guard, a `read`, a `caption`\n * or `settle`, which all belong to the filmed page.\n */\nimport type { ActionStep } from './actions'\nimport type { RecorderClock, RecorderPage } from './driver'\nimport {\n DRAG_HOLD_MS,\n KEY_SEQUENCE_GAP_MS,\n MULTI_CLICK_GAP_MS,\n pressSequence,\n readPath,\n resolveChord,\n resolveModifier,\n schedulePath,\n} from './gestures'\nimport type { ClickButton, DragModifier } from './gestures'\nimport {\n PRESS_HOLD_MS,\n PRESS_LEAD_MS,\n SETTLE_MS,\n askedMs,\n clockMotion,\n clockTyping,\n pointerTravelMs,\n} from './pace'\nimport { StepBound, bounded, stepBoundMs } from './stepBound'\nimport { conditionMiss, pollCondition, sayCondition } from './waits'\nimport type { ConditionState, WaitCondition } from './waits'\nimport { urlSchemeProblem } from './setup'\nimport type { PeerStepSpan } from '@vosjs/studio-core'\n\n/** One other person on the page: their own context, their own steps. */\nexport interface Peer {\n /** How the peer is named in lines and in `meta.peers`: a short word. */\n id: string\n /** The page the peer opens; absent, the take's own `url`. */\n url?: string\n /** The peer's viewport in CSS px; absent, the take's. */\n viewport?: { width: number; height: number }\n /**\n * A Playwright storage state the peer's context is made from: the second\n * person's own sign-in. The host resolves the name (the CLI: a path from\n * the actions file's directory) and never sends the file anywhere.\n * Absent, the peer is signed out.\n */\n storageState?: string\n steps: PeerStep[]\n}\n\n/** A peer's step: one of the take's gestures or checks, and when it starts. */\nexport type PeerStep = ActionStep & {\n /**\n * Start as the take's step with this id starts: the two run together.\n * (`with`, never `at`: a `type` step's `at` is where its caret goes.)\n */\n with?: string\n /** Start as the take's step with this id ends. */\n after?: string\n}\n\n/** The verbs a peer takes: the gestures and the on-page check. */\nexport const PEER_VERBS = [\n 'wait',\n 'move',\n 'hover',\n 'click',\n 'type',\n 'press',\n 'scroll',\n 'drag',\n 'expect',\n] as const\n\n/** The most peers a take may have: each is a whole browser context. */\nexport const MAX_PEERS = 4\n/** The most steps one peer may take. */\nexport const MAX_PEER_STEPS = 200\n\n/** Fields a take step carries that a peer's never does, and why. */\nconst TAKE_ONLY: Record<string, string> = {\n guard: 'a guard is pressed only on the filmed page, under --confirm',\n read: 'read keeps words from the filmed page',\n caption: 'a caption is a beat of the film, which is the take’s',\n settle: 'settle reads the filmed page’s frames',\n zoom: 'a zoom mark picks a moment on the cursor track, and a peer is never on it',\n}\n\nconst PEER_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/\n\n/**\n * Structural validation of `peers`, given the take's own steps (a trigger\n * names one of their ids). `validate` is the take's step validator, run on\n * each peer's list so a peer step is checked in exactly the take's words.\n */\nexport function validatePeers(\n value: unknown,\n takeSteps: unknown,\n validate: (steps: unknown[]) => string[],\n): string[] {\n if (!Array.isArray(value))\n return [\n 'peers must be an array of { id, url?, viewport?, storageState?, steps }',\n ]\n const errors: string[] = []\n if (value.length > MAX_PEERS)\n errors.push(\n `peers names ${value.length} peers; a take holds at most ${MAX_PEERS} (each is a whole browser)`,\n )\n const takeIds = new Set(\n (Array.isArray(takeSteps) ? takeSteps : [])\n .map((s) => (s as { id?: unknown } | null)?.id)\n .filter((id): id is string => typeof id === 'string'),\n )\n const seen = new Set<string>()\n value.forEach((raw, i) => {\n const at = `peers[${i}]`\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n errors.push(`${at}: must be an object`)\n return\n }\n const p = raw as Record<string, unknown>\n if (typeof p.id !== 'string' || !PEER_ID.test(p.id))\n errors.push(\n `${at}: id must be a short word (letters, digits, - and _, at most 32), which lines and meta.peers name the peer by`,\n )\n else if (seen.has(p.id)) errors.push(`${at}: duplicate peer id \"${p.id}\"`)\n else seen.add(p.id)\n if (p.url !== undefined) {\n if (typeof p.url !== 'string') errors.push(`${at}: url must be a string`)\n else {\n const problem = urlSchemeProblem(p.url)\n if (problem) errors.push(`${at}: url ${problem}`)\n }\n }\n if (p.viewport !== undefined) {\n const v = p.viewport as Record<string, unknown> | null\n if (\n typeof v !== 'object' ||\n v === null ||\n typeof v.width !== 'number' ||\n typeof v.height !== 'number'\n )\n errors.push(`${at}: viewport must be { width, height }`)\n }\n if (\n p.storageState !== undefined &&\n (typeof p.storageState !== 'string' || !p.storageState.trim())\n )\n errors.push(\n `${at}: storageState must name a Playwright storage state file (the second person's sign-in)`,\n )\n for (const k of Object.keys(p))\n if (!['id', 'url', 'viewport', 'storageState', 'steps'].includes(k))\n errors.push(\n `${at}: a peer takes id, url, viewport, storageState and steps, not ${k}`,\n )\n if (!Array.isArray(p.steps) || p.steps.length === 0) {\n errors.push(`${at}: steps must be a non-empty array`)\n return\n }\n if (p.steps.length > MAX_PEER_STEPS)\n errors.push(\n `${at}: steps holds ${p.steps.length} steps; a peer takes at most ${MAX_PEER_STEPS}`,\n )\n const steps = p.steps as unknown[]\n steps.forEach((rawStep, j) => {\n const sat = `${at}.steps[${j}]`\n if (typeof rawStep !== 'object' || rawStep === null) return\n const s = rawStep as Record<string, unknown>\n if (\n typeof s.do === 'string' &&\n !(PEER_VERBS as readonly string[]).includes(s.do)\n )\n errors.push(\n `${sat}: a peer step is one of ${PEER_VERBS.join(', ')}; ${/^[aeiou]/.test(s.do) ? 'an' : 'a'} ${s.do} belongs to the filmed page${s.do === 'await' ? ' (wait for what the peer did with the take’s own await or expect)' : ''}`,\n )\n for (const [k, why] of Object.entries(TAKE_ONLY))\n if (s[k] !== undefined)\n errors.push(`${sat}: no ${k} on a peer step: ${why}`)\n if (s.do === 'drag' && typeof s.path === 'string')\n errors.push(\n `${sat}: a peer draws its path inline (an array of points), never from a file`,\n )\n if (s.with !== undefined && s.after !== undefined)\n errors.push(\n `${sat}: with or after, not both (with starts as the take's step starts, after once it ends)`,\n )\n for (const k of ['with', 'after'] as const) {\n const v = s[k]\n if (v === undefined) continue\n if (typeof v !== 'string' || !v.trim())\n errors.push(`${sat}: ${k} must name a take step by its id`)\n else if (!takeIds.has(v))\n errors.push(\n `${sat}: ${k} \"${v}\" names no take step (the take's steps with ids: ${takeIds.size ? [...takeIds].join(', ') : 'none'}); give the take step an id`,\n )\n }\n })\n for (const e of validate(steps))\n errors.push(e.replace(/^steps\\[/, `${at}.steps[`))\n })\n return errors\n}\n\n/** What a hosted recorder says of a script with peers, or null. */\nexport function peersHostedRefusal(peers: unknown): string | null {\n if (!Array.isArray(peers) || !peers.length) return null\n return 'the script has peers (more browsers on the page, off camera), and a hosted take runs one browser: record it on this machine'\n}\n\n/**\n * The take's step boundaries, as promises a peer step waits on. The take\n * calls `begin` as the camera rolls, `start`/`end` around each step and\n * `close` once its steps are over; a trigger still pending then resolves\n * false and its step never runs.\n */\nexport class StepSignals {\n private readonly started = new Map<string, Deferred>()\n private readonly ended = new Map<string, Deferred>()\n private readonly began = deferred()\n private closed = false\n\n constructor(ids: Iterable<string>) {\n for (const id of ids) {\n this.started.set(id, deferred())\n this.ended.set(id, deferred())\n }\n }\n\n begin(): void {\n this.began.resolve(true)\n }\n\n start(id: string | undefined): void {\n if (id) this.started.get(id)?.resolve(true)\n }\n\n end(id: string | undefined): void {\n if (id) this.ended.get(id)?.resolve(true)\n }\n\n close(): void {\n this.closed = true\n this.began.resolve(false)\n for (const d of [...this.started.values(), ...this.ended.values()])\n d.resolve(false)\n }\n\n get isClosed(): boolean {\n return this.closed\n }\n\n /** When a step with this trigger may start: true, or false for never. */\n when(trigger: { with?: string; after?: string }): {\n ready: Promise<boolean>\n already: boolean\n } {\n const d = trigger.with\n ? this.started.get(trigger.with)\n : trigger.after\n ? this.ended.get(trigger.after)\n : this.began\n if (!d) return { ready: Promise.resolve(false), already: false }\n return { ready: d.promise, already: d.settled }\n }\n}\n\ninterface Deferred {\n promise: Promise<boolean>\n resolve: (v: boolean) => void\n settled: boolean\n}\n\nfunction deferred(): Deferred {\n let resolve: (v: boolean) => void = () => {}\n const d: Deferred = {\n promise: new Promise<boolean>((r) => {\n resolve = r\n }),\n resolve: (v) => {\n if (d.settled) return\n d.settled = true\n resolve(v)\n },\n settled: false,\n }\n return d\n}\n\n/** One peer step as it ran, in the take's footage seconds. */\nexport type { PeerStepSpan } from '@vosjs/studio-core'\n\n/** The most a peer step's kept value holds, in characters of JSON (as a take step's). */\nexport const PEER_VALUE_MAX = 2048\n\n/**\n * What a peer's check last answered, kept on its step the way the take's\n * own steps keep theirs (`meta.steps[].value`): the value itself while its\n * JSON fits, else that JSON cut short as a string; absent when the read\n * answered nothing JSON can hold, or no value at all (a check that only\n * holds or not).\n */\nexport function peerValue(last: ConditionState): unknown {\n if (!('value' in last)) return undefined\n const value = (last as { value?: unknown }).value\n const json = JSON.stringify(value)\n if (json === undefined) return undefined\n return json.length <= PEER_VALUE_MAX\n ? value\n : `${json.slice(0, PEER_VALUE_MAX - 1)}…`\n}\n\n/** What a peer did: its steps as they ran, and the ones that never did. */\nexport interface PeerRun {\n id: string\n steps: PeerStepSpan[]\n /** Steps whose trigger never fired before the take's steps were over. */\n notRun: number[]\n}\n\n/** A selector's centre, or a viewport point. */\ntype Spot = { x: number; y: number }\n\nconst EXPECT_TIMEOUT_S = 5\nconst EXPECT_EVERY_MS = 150\n\n/**\n * Drive one peer's steps on its page, each when its trigger fires. Never\n * throws for a page's reasons: a miss is a skip on the run.\n */\nexport async function runPeer(\n peer: Peer,\n rawPage: RecorderPage,\n signals: StepSignals,\n opts: {\n clock: RecorderClock\n /** The take's footage clock, ms: what a span is placed by. */\n footageMs: () => number\n log: (msg: string) => void\n /** A rehearsal: no travel, every pause cut short. */\n dry?: boolean\n },\n): Promise<PeerRun> {\n const bound = new StepBound()\n const page = bounded(rawPage, bound)\n const { clock, log } = opts\n const run: PeerRun = { id: peer.id, steps: [], notRun: [] }\n const cur = { x: 24, y: 24 }\n const moveTo = async (tx: number, ty: number) => {\n const from = { ...cur }\n const dist = Math.hypot(tx - from.x, ty - from.y)\n await clockMotion(\n opts.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 },\n clock,\n )\n }\n const spotOf = async (s: {\n selector?: string\n x?: number\n y?: number\n }): Promise<Spot | null> => {\n if (s.selector === undefined) return { x: s.x ?? cur.x, y: s.y ?? cur.y }\n const loc = page.locator(s.selector).first()\n try {\n await loc.waitFor({ state: 'visible', timeout: 8000 })\n await loc.scrollIntoViewIfNeeded()\n const bb = await loc.boundingBox()\n return bb ? { x: bb.x + bb.width / 2, y: bb.y + bb.height / 2 } : null\n } catch {\n return null\n }\n }\n const press = async (how: {\n count?: number\n button?: ClickButton\n modifiers?: DragModifier[]\n }) => {\n const held: string[] = []\n try {\n for (const m of how.modifiers ?? []) {\n const key = resolveModifier(m)\n await page.keyboard.down(key)\n held.push(key)\n }\n await clock.sleep(PRESS_LEAD_MS)\n const count = how.count ?? 1\n for (let n = 1; n <= count; n++) {\n if (n > 1) await clock.sleep(MULTI_CLICK_GAP_MS)\n const o = {\n ...(how.button && how.button !== 'left'\n ? { button: how.button }\n : {}),\n ...(n > 1 ? { clickCount: n } : {}),\n }\n const has = Object.keys(o).length > 0\n await (has ? page.mouse.down(o) : page.mouse.down())\n await clock.sleep(PRESS_HOLD_MS)\n await (has ? page.mouse.up(o) : page.mouse.up())\n }\n } finally {\n for (const key of held.reverse())\n await page.keyboard.up(key).catch(() => undefined)\n }\n }\n\n for (const [i, step] of peer.steps.entries()) {\n const tag = `peer ${peer.id} #${i}${step.id ? ` ${step.id}` : ''}`\n const trigger = signals.when(step)\n const go = await trigger.ready\n if (!go) {\n run.notRun = peer.steps.slice(i).map((_, k) => i + k)\n log(\n ` (${tag} ${step.do}: not run: ${step.with ? `the take's step ${step.with} never started` : step.after ? `the take's step ${step.after} never ended` : 'the take ended first'})`,\n )\n break\n }\n const late =\n (step.with !== undefined || step.after !== undefined) && trigger.already\n const tStart = opts.footageMs()\n let selector: string | undefined\n let reason: string | null = null\n let value: unknown\n bound.start(\n stepBoundMs(\n step as Parameters<typeof stepBoundMs>[0],\n askedMs(step as Parameters<typeof askedMs>[0]),\n { expectS: EXPECT_TIMEOUT_S, awaitS: 0, downloadS: 0 },\n ),\n )\n try {\n switch (step.do) {\n case 'wait':\n await clock.sleep(step.ms)\n break\n case 'move':\n await moveTo(step.x, step.y)\n break\n case 'hover': {\n selector = step.selector\n const spot = await spotOf(step)\n if (!spot) reason = `'${step.selector}' never appeared`\n else {\n await moveTo(spot.x, spot.y)\n await clock.sleep(step.ms ?? 700)\n }\n break\n }\n case 'click': {\n selector = step.selector\n const spot = await spotOf(step)\n if (!spot) {\n reason = `'${step.selector}' never appeared`\n break\n }\n await moveTo(spot.x, spot.y)\n await press(step)\n await clock.sleep(step.ms ?? SETTLE_MS.click)\n break\n }\n case 'type': {\n selector = step.selector\n if (step.focus !== false) {\n const spot = await spotOf(step)\n if (!spot) {\n reason = `'${step.selector}' never appeared`\n break\n }\n await moveTo(spot.x, spot.y)\n await press({})\n }\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 await clockTyping(\n [...step.text],\n opts.dry ? 0 : (step.delayMs ?? 40),\n (ch) => page.keyboard.type(ch),\n clock,\n )\n await clock.sleep(step.ms ?? SETTLE_MS.type)\n break\n }\n case 'press': {\n selector = step.selector\n if (step.selector !== undefined) {\n const spot = await spotOf(step)\n if (!spot) {\n reason = `'${step.selector}' never appeared`\n break\n }\n }\n const keys = pressSequence(step)\n for (const [k, key] of keys.entries()) {\n if (k > 0) await clock.sleep(KEY_SEQUENCE_GAP_MS)\n await page.keyboard.press(resolveChord(key))\n }\n await clock.sleep(step.ms ?? SETTLE_MS.press)\n break\n }\n case 'scroll':\n await page.mouse.wheel(0, step.dy)\n await clock.sleep(step.ms ?? 200)\n break\n case 'drag': {\n selector = step.selector\n const read = step.path !== undefined ? readPath(step.path) : null\n if (read && 'problems' in read) {\n reason = `its path ${read.problems.join('; ')}`\n break\n }\n const held: string[] = []\n try {\n if (read) {\n const sched = schedulePath(read, step.ms)\n await moveTo(sched[0].x, sched[0].y)\n for (const m of step.modifiers ?? []) {\n const key = resolveModifier(m)\n await page.keyboard.down(key)\n held.push(key)\n }\n await page.mouse.down()\n const t0 = clock.now()\n for (const p of sched.slice(1)) {\n const wait = t0 + (opts.dry ? 0 : p.at) - clock.now()\n if (wait > 0) await clock.sleep(wait)\n cur.x = p.x\n cur.y = p.y\n await page.mouse.move(p.x, p.y)\n }\n } else {\n const start = await spotOf(step)\n if (!start) {\n reason = `'${step.selector}' never appeared`\n break\n }\n await moveTo(start.x, start.y)\n for (const m of step.modifiers ?? []) {\n const key = resolveModifier(m)\n await page.keyboard.down(key)\n held.push(key)\n }\n await page.mouse.down()\n const from = { ...cur }\n const tx = step.tx as number\n const ty = step.ty as number\n await clockMotion(\n opts.dry ? 0 : (step.ms ?? 700),\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 },\n clock,\n )\n }\n await page.mouse.up()\n } finally {\n for (const key of held.reverse())\n await page.keyboard.up(key).catch(() => undefined)\n }\n await clock.sleep(DRAG_HOLD_MS)\n break\n }\n case 'expect': {\n const cond: WaitCondition = step\n selector = step.selector ?? step.gone\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: clock.sleep,\n })\n value = peerValue(res.last)\n if (!res.ok) reason = conditionMiss(cond, res.last, timeoutMs)\n else log(` ${tag} expect ${sayCondition(cond)}: holds`)\n break\n }\n default:\n reason = `a peer does not ${step.do}`\n }\n } catch (e) {\n reason = e instanceof Error ? e.message.split('\\n')[0] : String(e)\n }\n const hang = bound.end()\n if (hang.hung)\n reason = `the page stopped answering: this ${step.do} ran past its bound`\n if (reason) log(` (${tag} ${step.do}: ${reason})`)\n else if (step.do !== 'expect')\n log(` ${tag} ${step.do}${selector ? ` ${selector}` : ''}`)\n run.steps.push({\n step: i,\n ...(step.id ? { id: step.id } : {}),\n do: step.do,\n ...(step.with ? { with: step.with } : {}),\n ...(step.after ? { after: step.after } : {}),\n ...(selector ? { selector } : {}),\n tStart: +(tStart / 1000).toFixed(3),\n tEnd: +(opts.footageMs() / 1000).toFixed(3),\n ...(reason ? { skipped: true, reason } : {}),\n ...(late ? { late: true } : {}),\n ...(value !== undefined ? { value } : {}),\n })\n }\n return run\n}\n","import type { MaskRule } from './exposure'\nimport type { SetupStep } from './setup'\nimport { urlSchemeProblem, validateSetup } from './setup'\nimport { readyProblem } from './ready'\nimport type { ReadyMode } from './ready'\nimport type { ClickButton, DragModifier, PathPoint } from './gestures'\nimport {\n CLICK_BUTTONS,\n DRAG_MODIFIERS,\n MAX_KEYS,\n chordProblem,\n readPath,\n} from './gestures'\nimport { pasteTypeOf } from './paste'\nimport { SETTLE_VERBS } from './settle'\nimport { peersHostedRefusal, validatePeers } from './peers'\nimport type { Peer } from './peers'\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 /**\n * Run AFTER the take, off camera, with the same verbs as `setup`: what\n * the take created in the product (an API key, a project, an invite)\n * removed again. They run once the screencast has stopped, on the take's\n * own page, after a rehearsal too, and when the take stops early or\n * throws after its first step. A failing teardown never fails the take;\n * it stops at the step that failed and is reported.\n */\n teardown?: SetupStep[]\n /**\n * When the first page counts as ready for step 1: `dom` (default),\n * once its DOM has made no change for a beat after `load`, at most 8 s;\n * `networkidle`, once the network has gone quiet, at most 45 s, which a\n * page holding a socket open never does. `--ready` overrides.\n */\n ready?: ReadyMode\n /**\n * Every gesture waits on the app after it (`settle` on a step overrides):\n * a canvas that falls behind under load finishes the last stroke before\n * the next one starts.\n */\n settle?: boolean\n steps: ActionStep[]\n /**\n * Other people on the page, OFF CAMERA: each a browser context of its\n * own (its own storage state, so its own user) on the same `url`, driven\n * by its own steps, each started `with` a take step or `after` one (by\n * id). Only the take's page is filmed, and only its own steps make the\n * cursor track; a peer's work reaches the footage through the app's own\n * sync. A hosted take refuses peers.\n */\n peers?: Peer[]\n}\n\nexport type ActionStep = (\n | { do: 'wait'; ms: number }\n /**\n * Rest the pointer on `selector`'s centre, or on the viewport point\n * (`x`, `y`) when no selector names the spot (a place on a canvas).\n */\n | { do: 'hover'; selector?: string; x?: number; y?: number; ms?: number }\n /**\n * Press `selector`'s centre, or the viewport point (`x`, `y`). `ms` is\n * the settle after the press (default 150). `count` 2 or 3 is a real\n * double or triple click; `button` presses the right or middle one;\n * `modifiers` are held for the press (a Shift-click) and released after.\n */\n | {\n do: 'click'\n selector?: string\n x?: number\n y?: number\n ms?: number\n count?: 1 | 2 | 3\n button?: ClickButton\n modifiers?: DragModifier[]\n }\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 * A key, a chord or a sequence, each recorded as a typing ping where the\n * pointer is (or on `selector` when given, with no click), never as the\n * key itself. `key` names one control key (Escape closes what a click\n * opened, Enter submits what was typed); `keys` names a chord\n * (`\"Shift+D\"`, `\"Mod+Z\"`, with `Mod` Meta on macOS and Control\n * elsewhere), a plain key (`\"r\"`, a tool's shortcut) or a sequence\n * (`[\"v\", \"Escape\"]`). Words are typed with `type`.\n */\n | {\n do: 'press'\n key?: PressKey\n keys?: string | string[]\n selector?: string\n ms?: number\n }\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 * `path` draws instead: viewport points (inline, or a file beside the\n * actions file), the press at the first and the release at the last,\n * replayed by the points' own times or evenly over ms. `modifiers` are\n * held for the whole drag.\n */\n | {\n do: 'drag'\n selector?: string\n x?: number\n y?: number\n tx?: number\n ty?: number\n path?: PathPoint[] | string\n modifiers?: DragModifier[]\n ms?: number\n }\n /**\n * Put words or a file (an image, an SVG) on the clipboard and paste it\n * the way a person's ⌘V does, into `selector` (clicked first) or where\n * the focus is. A file is read beside the actions file, by a plain name.\n */\n | {\n do: 'paste'\n selector?: string\n text?: string\n file?: string\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`, `gone` no longer visible, or `js`, an\n * expression evaluated in the page that holds when its value is truthy\n * (with `equals`, when its value equals that one): the state a canvas\n * app keeps in script, never in the DOM. Exactly one of the four. Waits\n * up to `timeout` seconds (default 5); a condition that never holds is a\n * skip with its reason, which names the value a `js` last answered.\n */\n | {\n do: 'expect'\n selector?: string\n text?: string\n gone?: string\n enabled?: boolean\n js?: string\n equals?: unknown\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 * The cut's camera on this step: `true` marks the step as its beat's\n * payoff, the moment worth the zoom (`vos plan --zooms per-beat` keeps\n * the proposal on it, and only it); `false` means never zoom here (the\n * planner's proposal on it is rejected). The planner still decides the\n * level and the focus; a mark never invents a zoom. On a gesture only\n * (ZOOM_MARK_VERBS).\n */\n zoom?: boolean\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 * After the gesture, wait until the page has made no DOM change and\n * painted no new frame for a beat (at most a few seconds): an app that\n * falls behind catches up before the next step. The script's top-level\n * `settle` is the default.\n */\n settle?: boolean\n}\n\n/** What an `await` waits for: exactly one of the four (`equals` rides with `js`). */\nexport interface AwaitUntil {\n selector?: string\n text?: string\n gone?: string\n js?: string\n equals?: unknown\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 `zoom` mark may sit on: the gestures a camera can be about. */\nexport const ZOOM_MARK_VERBS: readonly string[] = [\n 'click',\n 'drag',\n 'type',\n 'paste',\n 'press',\n 'hover',\n]\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 'paste',\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.teardown !== undefined)\n errors.push(...validateSetup(obj.teardown, 'teardown'))\n const ready = readyProblem(obj.ready)\n if (ready) errors.push(ready)\n if (obj.settle !== undefined && typeof obj.settle !== 'boolean')\n errors.push('settle must be true or false')\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 if (obj.peers !== undefined)\n errors.push(\n ...validatePeers(obj.peers, obj.steps, (steps) =>\n validateActions({ steps }),\n ),\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 if (s.do === 'type' && typeof s.selector !== 'string')\n errors.push(`${at}: type needs a selector`)\n if (s.do === 'hover' || s.do === 'click') {\n const point = s.x !== undefined || s.y !== undefined\n if (point && s.selector !== undefined)\n errors.push(\n `${at}: ${s.do} takes a selector or x and y (a viewport point), not both`,\n )\n else if (point) {\n if (!isCoord(s.x) || !isCoord(s.y))\n errors.push(\n `${at}: ${s.do} x and y must both be numbers of CSS px, 0 or more`,\n )\n } else if (typeof s.selector !== 'string')\n errors.push(\n `${at}: ${s.do} needs a selector, or x and y (a viewport point)`,\n )\n }\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 (s.key !== undefined && s.keys !== undefined)\n errors.push(\n `${at}: press takes key or keys, not both (keys says everything key does)`,\n )\n else if (s.keys !== undefined) {\n const list: unknown[] = Array.isArray(s.keys) ? s.keys : [s.keys]\n if (!list.length)\n errors.push(`${at}: press keys must name at least one key`)\n else if (list.length > MAX_KEYS)\n errors.push(`${at}: press keys names more than ${MAX_KEYS} keys`)\n list.forEach((k, j) => {\n const problem = chordProblem(k)\n if (problem)\n errors.push(\n `${at}: press keys${Array.isArray(s.keys) ? `[${j}]` : ''} ${problem}`,\n )\n })\n } else 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(', ')}, or keys (a chord like \"Shift+D\", a plain key like \"r\", or a sequence); 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 === 'click') {\n errors.push(...modifiersProblem(at, 'click', s.modifiers))\n if (\n s.count !== undefined &&\n s.count !== 1 &&\n s.count !== 2 &&\n s.count !== 3\n )\n errors.push(\n `${at}: click count must be 1, 2 (a double click) or 3 (a triple click)`,\n )\n if (\n s.button !== undefined &&\n !(CLICK_BUTTONS as readonly unknown[]).includes(s.button)\n )\n errors.push(`${at}: click button must be \"left\", \"right\" or \"middle\"`)\n }\n if (s.settle !== undefined) {\n if (typeof s.settle !== 'boolean')\n errors.push(`${at}: settle must be true or false`)\n else if (!SETTLE_VERBS.has(s.do))\n errors.push(\n `${at}: settle follows a gesture (hover, click, type, press, scroll, move, drag, paste); a ${s.do} sends the page nothing to catch up on`,\n )\n }\n if (s.do === 'paste') {\n const given = (['text', 'file'] as const).filter(\n (k) => s[k] !== undefined,\n )\n if (given.length !== 1)\n errors.push(\n `${at}: paste needs exactly one of text (words) or file (an image, an SVG or a text file beside the actions file)`,\n )\n if (s.text !== undefined && typeof s.text !== 'string')\n errors.push(`${at}: paste text must be a string`)\n if (s.file !== undefined) {\n const problem =\n typeof s.file === 'string'\n ? (fileNameProblem(s.file) ??\n (pasteTypeOf(s.file)\n ? null\n : `\"${s.file}\" is not a type a paste takes (.png, .jpg, .webp, .gif, .svg, .txt, .md, .html, .json, .csv)`))\n : 'is not a string'\n if (problem) errors.push(`${at}: paste file ${problem}`)\n }\n if (s.selector !== undefined && !isFilled(s.selector))\n errors.push(`${at}: paste selector must be a non-empty 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.zoom !== undefined) {\n if (typeof s.zoom !== 'boolean')\n errors.push(`${at}: zoom must be true or false`)\n else if (!ZOOM_MARK_VERBS.includes(s.do))\n errors.push(\n `${at}: zoom marks a gesture (${ZOOM_MARK_VERBS.join(', ')}); a ${s.do} shows nothing to zoom on`,\n )\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', 'js'] 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, gone or js${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 errors.push(...equalsProblem(`${at}: expect`, s))\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\" }, { \"gone\" } or { \"js\" }`,\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' || k === 'js',\n )\n const unknown = keys.filter((k) => !known.includes(k) && k !== 'equals')\n if (unknown.length)\n errors.push(\n `${at}: await until takes selector, text, gone or js (with equals), not ${unknown.join(', ')}`,\n )\n if (known.length !== 1)\n errors.push(\n `${at}: await until needs exactly one of selector, text, gone or js${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 errors.push(...equalsProblem(`${at}: await until`, until))\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 (s.path !== undefined) {\n const clash = (['selector', 'x', 'y', 'tx', 'ty'] as const).filter(\n (k) => s[k] !== undefined,\n )\n if (clash.length)\n errors.push(\n `${at}: a drag with a path starts at its first point and ends at its last, so it takes no ${clash.join(', ')}`,\n )\n if (typeof s.path === 'string') {\n const problem = fileNameProblem(s.path)\n if (problem)\n errors.push(\n `${at}: drag path ${problem} (a file beside the actions file)`,\n )\n } else {\n const read = readPath(s.path)\n if ('problems' in read)\n for (const p of read.problems) errors.push(`${at}: drag path ${p}`)\n }\n } else {\n if (typeof s.tx !== 'number' || typeof s.ty !== 'number') {\n errors.push(`${at}: drag needs tx and ty (CSS px), or a path`)\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 errors.push(...modifiersProblem(at, 'drag', s.modifiers))\n }\n })\n return errors\n}\n\nconst isCoord = (v: unknown): boolean =>\n typeof v === 'number' && Number.isFinite(v) && v >= 0\n\n/** The modifiers a click or a drag holds, checked in the same words for both. */\nfunction modifiersProblem(at: string, verb: string, v: unknown): string[] {\n if (v === undefined) return []\n if (\n !Array.isArray(v) ||\n v.some((m) => !(DRAG_MODIFIERS as readonly unknown[]).includes(m))\n )\n return [\n `${at}: ${verb} modifiers must be a list of ${DRAG_MODIFIERS.map((m) => `\"${m}\"`).join(', ')} (Mod is Meta on macOS, Control elsewhere)`,\n ]\n if (new Set(v).size !== v.length)\n return [`${at}: ${verb} modifiers names a modifier twice`]\n return []\n}\n\n/**\n * `equals` sits beside a `js` only, and holds a value JSON can say: what\n * the expression's own value is compared against.\n */\nfunction equalsProblem(at: string, s: Record<string, unknown>): string[] {\n if (s.equals === undefined) return []\n if (s.js === undefined)\n return [\n `${at} equals is the value a js expression must answer, so it needs js`,\n ]\n if (!isJsonValue(s.equals, 0))\n return [\n `${at} equals must be a JSON value (a number, a string, true, false, null, a list or an object of them)`,\n ]\n return []\n}\n\nfunction isJsonValue(v: unknown, depth: number): boolean {\n if (depth > 32) return false\n if (v === null || typeof v === 'string' || typeof v === 'boolean') return true\n if (typeof v === 'number') return Number.isFinite(v)\n if (Array.isArray(v)) return v.every((x) => isJsonValue(x, depth + 1))\n if (typeof v === 'object')\n return Object.values(v as Record<string, unknown>).every((x) =>\n isJsonValue(x, depth + 1),\n )\n return false\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, a download has no\n * take directory to land in there, and a `js` check is code a stranger's\n * script would run in the fleet's browser.\n */\nexport function hostedRefusals(\n actions: Pick<ActionsFile, 'steps' | 'peers'>,\n): string[] {\n const out: string[] = []\n const peers = peersHostedRefusal(actions.peers)\n if (peers) out.push(peers)\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 if (s.do === 'paste')\n out.push(\n `steps[${i}] is a paste, and a hosted browser has no clipboard to paste from: record it on this machine`,\n )\n if (\n (s.do === 'expect' && s.js !== undefined) ||\n (s.do === 'await' && s.until.js !== undefined)\n )\n out.push(\n `steps[${i}] ${s.do === 'expect' ? 'checks' : 'waits on'} a js expression, which runs as code in the page, and a hosted browser runs no script it was handed: record it on this machine, or check what the page shows (selector, text or gone)`,\n )\n if (s.do === 'drag' && typeof s.path === 'string')\n out.push(\n `steps[${i}] draws a path from the file \"${s.path}\", and a hosted take carries the script alone: write the points inline as path`,\n )\n })\n return out\n}\n\n/**\n * The files a script names beside itself, in order: a drag's path file\n * and a paste's file. A host reads them before anything is captured.\n */\nexport function scriptFiles(\n actions: Pick<ActionsFile, 'steps'>,\n): { step: number; name: string; as: 'path' | 'paste' }[] {\n const out: { step: number; name: string; as: 'path' | 'paste' }[] = []\n actions.steps.forEach((s, i) => {\n if (s.do === 'drag' && typeof s.path === 'string')\n out.push({ step: i, name: s.path, as: 'path' })\n if (s.do === 'paste' && typeof s.file === 'string')\n out.push({ step: i, name: s.file, as: 'paste' })\n })\n return out\n}\n","/**\n * The files a script names beside itself, read before the take: a drag's\n * path file (points as JSON) and a paste's file (its bytes). The host\n * hands in where they come from (`ScriptFiles`); the names are plain file\n * names, checked by `validateActions`, so a script can only name what sits\n * next to it.\n */\nimport type { ActionsFile } from './actions'\nimport { fileNameProblem, scriptFiles } from './actions'\nimport type { ScriptFiles } from './driver'\nimport { readPath } from './gestures'\nimport type { PathPoint, PathSample } from './gestures'\nimport { PASTE_MAX_BYTES, pasteTypeOf } from './paste'\n\nexport interface LoadedFiles {\n /** a drag's path, read from its file, by step index */\n paths: Map<number, { points: PathSample[]; timed: boolean }>\n /** a paste's file, by step index */\n pastes: Map<number, { bytes: Uint8Array; type: string; name: string }>\n}\n\n/**\n * Read every file the script names. Answers the files, or the problem in\n * words (the step, the file, what is wrong) for the caller to refuse the\n * take with.\n */\nexport async function loadScriptFiles(\n actions: Pick<ActionsFile, 'steps'>,\n source: ScriptFiles | undefined,\n): Promise<LoadedFiles | { problem: string }> {\n const loaded: LoadedFiles = { paths: new Map(), pastes: new Map() }\n const named = scriptFiles(actions)\n if (!named.length) return loaded\n if (!source) {\n const f = named[0]\n return {\n problem: `steps[${f.step}] names the file \"${f.name}\", and this recorder has no actions directory to read it from${f.as === 'path' ? ': write the points inline as path' : ''}. Nothing was recorded.`,\n }\n }\n for (const f of named) {\n const at = `steps[${f.step}]`\n const bad = fileNameProblem(f.name)\n if (bad) return { problem: `${at}: ${bad}. Nothing was recorded.` }\n let bytes: Uint8Array\n try {\n bytes = await source.read(f.name)\n } catch (e) {\n const why = e instanceof Error ? e.message : String(e)\n return {\n problem:\n f.as === 'paste'\n ? `${at} pastes the file \"${f.name}\", which could not be read beside the actions file (${why}): a file paste needs its file beside the script, so put ${f.name} next to it (a take fetched with its media brings its pasted files home beside its script; one pushed before they travelled with it does not). Nothing was recorded.`\n : `${at} names \"${f.name}\", which could not be read beside the actions file (${why}). Nothing was recorded.`,\n }\n }\n if (f.as === 'path') {\n let raw: unknown\n try {\n raw = JSON.parse(new TextDecoder().decode(bytes))\n } catch {\n return {\n problem: `${at}: the path file \"${f.name}\" is not JSON (an array of [x, y] or [x, y, tMs] points). Nothing was recorded.`,\n }\n }\n const path = readPath(raw)\n if ('problems' in path)\n return {\n problem: `${at}: the path file \"${f.name}\" ${path.problems.join('; ')}. Nothing was recorded.`,\n }\n loaded.paths.set(f.step, path)\n } else {\n if (bytes.length > PASTE_MAX_BYTES)\n return {\n problem: `${at}: \"${f.name}\" is larger than ${PASTE_MAX_BYTES / 1024 / 1024} MB, more than a paste carries. Nothing was recorded.`,\n }\n loaded.pastes.set(f.step, {\n bytes,\n type: pasteTypeOf(f.name) ?? 'application/octet-stream',\n name: f.name,\n })\n }\n }\n return loaded\n}\n\n/** A read path as inline points: its own times when it had them, its pressure when it carried one. */\nexport function inlinePoints(path: {\n points: PathSample[]\n timed: boolean\n}): PathPoint[] {\n return path.points.map((p): PathPoint => {\n if (path.timed)\n return p.pressure !== undefined\n ? [p.x, p.y, p.at, p.pressure]\n : [p.x, p.y, p.at]\n return p.pressure !== undefined\n ? { x: p.x, y: p.y, pressure: p.pressure }\n : [p.x, p.y]\n })\n}\n\n/**\n * The script as it ran, self-contained: every path a file held is written\n * inline, so the script a take keeps (and the one a push embeds, a fetch\n * writes back and a hosted recorder runs) re-records the same strokes with\n * the file gone. A paste's file stays a name: it is bytes, kept beside the\n * script by the host.\n */\nexport function inlineScript<T extends Pick<ActionsFile, 'steps'>>(\n actions: T,\n files: LoadedFiles,\n): T {\n if (!files.paths.size) return actions\n return {\n ...actions,\n steps: actions.steps.map((s, i) => {\n const read = files.paths.get(i)\n if (s.do !== 'drag' || typeof s.path !== 'string' || !read) return s\n return { ...s, path: inlinePoints(read) }\n }),\n }\n}\n","/**\n * The `paste` step run against a page: the clipboard first (a trusted\n * paste through the platform's chord), the page's own paste event when the\n * browser's clipboard refuses the item. paste.ts holds the page scripts and\n * says why there are two rungs.\n */\nimport type { RecorderContext, RecorderPage } from './driver'\nimport type { LoadedFiles } from './scriptFiles'\nimport type { PasteItem } from './paste'\nimport { stageClipboardScript, syntheticPasteScript } from './paste'\n\n/** Bytes to base64 without Node's Buffer, so the fleet's isolate runs it too. */\nfunction toBase64(bytes: Uint8Array): string {\n let bin = ''\n for (let i = 0; i < bytes.length; i += 0x8000)\n bin += String.fromCharCode(...bytes.subarray(i, i + 0x8000))\n return btoa(bin)\n}\n\n/** What a paste step puts on the clipboard: its words, or its file as read before the take. */\nexport function pasteItemOf(\n step: { text?: string; file?: string },\n stepIdx: number,\n files: LoadedFiles,\n): PasteItem | null {\n if (step.text !== undefined) return { text: step.text }\n const f = files.pastes.get(stepIdx)\n if (!f) return null\n return { b64: toBase64(f.bytes), type: f.type, name: f.name }\n}\n\nexport type PasteOutcome =\n | { via: 'clipboard' }\n | { via: 'file' }\n | { via: 'page'; why: string }\n | { failed: string }\n\n/**\n * Paste `item` where the focus is. `press` presses the paste chord and is\n * the recorder's, so the keystroke is timed and pinged like any other.\n */\nexport async function runPaste(\n page: RecorderPage,\n context: RecorderContext,\n item: PasteItem,\n press: (chord: string) => Promise<void>,\n): Promise<PasteOutcome> {\n // An image FILE is dispatched in the page with its own bytes: the\n // browser's clipboard re-encodes a picture and drops what the file\n // carries (a screenshot's density, so a 2x capture lands at twice its\n // size). Words keep the trusted path.\n if (item.b64 !== undefined && item.type?.startsWith('image/')) {\n const done = await page\n .evaluate<string>(syntheticPasteScript(item, { original: true }))\n .catch((e: unknown) => `failed: ${e instanceof Error ? e.message : e}`)\n return done === 'ok'\n ? { via: 'file' }\n : { failed: `the page's paste failed (${done.replace(/^failed: /, '')})` }\n }\n let origin: string | undefined\n try {\n origin = new URL(page.url()).origin\n } catch {\n origin = undefined\n }\n if (context.grantPermissions && origin && origin !== 'null')\n await context\n .grantPermissions(['clipboard-read', 'clipboard-write'], { origin })\n .catch(() => undefined)\n const staged = await page\n .evaluate<string>(stageClipboardScript(item))\n .catch((e: unknown) => `refused: ${e instanceof Error ? e.message : e}`)\n if (staged === 'ok') {\n await press('ControlOrMeta+v')\n return { via: 'clipboard' }\n }\n const why = staged.replace(/^refused: /, '')\n const done = await page\n .evaluate<string>(syntheticPasteScript(item))\n .catch((e: unknown) => `failed: ${e instanceof Error ? e.message : e}`)\n if (done === 'ok') return { via: 'page', why }\n return {\n failed: `this browser has no clipboard to paste from (${why}), and the page's own paste failed too (${done.replace(/^failed: /, '')})`,\n }\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 SoundSink,\n RecorderBrowser,\n RecorderClock,\n RecorderContext,\n RecorderPage,\n ScriptFiles,\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, wallVerdict } from './wall'\nimport {\n EXPOSURE_PROBE,\n ExposureLog,\n NoticeLog,\n maskInitScript,\n} from './exposure'\nimport type { ScannedNotice } from './exposure'\nimport {\n SetupEnvError,\n SetupError,\n TEARDOWN_BOUND_MS,\n runSetup,\n teardownEnvProblem,\n teardownLine,\n} from './setup'\nimport type { TeardownReport } from './setup'\nimport { StepBound, bounded, stepBoundMs } from './stepBound'\nimport {\n MEDIA_DRAIN_PROBE,\n MEDIA_WATCH_SCRIPT,\n PageSoundLog,\n} from './pageSound'\nimport type { MediaDrain } from './pageSound'\nimport { TakeClock } from './takeClock'\nimport { PageErrorLog } from './pageErrors'\nimport { fitSurfaceToViewport } from './surfaceFit'\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 { DEFAULT_READY, readyLine, reloadUntilReady, untilReady } from './ready'\nimport type { ReadyReport } from './ready'\nimport {\n DRAG_HOLD_MS,\n KEY_SEQUENCE_GAP_MS,\n MULTI_CLICK_GAP_MS,\n keySequencePlanMs,\n buttonNumber,\n modifierBits,\n overrunLine,\n overrunOf,\n pathDurationMs,\n pressSequence,\n resolveChord,\n resolveModifier,\n readPath,\n schedulePath,\n} from './gestures'\nimport type {\n ClickButton,\n DragModifier,\n PathSample,\n StepOverrun,\n} from './gestures'\nimport { inlineScript, loadScriptFiles } from './scriptFiles'\nimport { StepSignals, runPeer } from './peers'\nimport type { Peer, PeerRun } from './peers'\nimport type { LoadedFiles } from './scriptFiles'\nimport { pasteItemOf, runPaste } from './pasteStep'\nimport { CHANGE_AGE_PROBE, appSettled, settleOn } from './settle'\nimport {\n conditionMiss,\n keptValue,\n pollCondition,\n sayCondition,\n sayDuration,\n} from './waits'\nimport type { ConditionState, 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 /** A PEER's step (`peers[].id`): `step` is then an index into that peer's steps. */\n peer?: 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 /** `ready: \"networkidle\"` was asked for and the first load never reached it (recording proceeded anyway). */\n navTimeout: boolean\n /** How the first load settled before step 1. */\n ready: ReadyReport\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 /**\n * INFORMATION, never a failure and never in `exposures`: the signed-in\n * account's own name and its recent-items lists (also `meta.notices`).\n */\n notices: NonNullable<RecordingMeta['notices']>\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 /** The sound the page played, each heard stretch in footage seconds (also `meta.media`). */\n media: NonNullable<RecordingMeta['media']>\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 /**\n * Paced gestures that ran more than a fifth past their script (a drag's\n * travel, a path's timing, typing, a key sequence): the page could not\n * keep up with what it was sent. Also on `meta.steps[].overrunMs`.\n */\n overruns: StepOverrun[]\n /** The actions as recorded, `url` resolved: what a take directory writes back. */\n actions: ActionsFile\n /** What each peer did, off camera (also `meta.peers`); [] with none. */\n peers: PeerRun[]\n /**\n * What the script's `teardown` did after the take, off camera; null when\n * it has none. A failure here is reported and never fails the take.\n */\n teardown: TeardownReport | null\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 and a teardown's `{ env }` texts resolve\n * from: the shell's for the CLI, the job's own map on the fleet. Absent\n * means no env at all, so a setup that reads one fails in words, and a\n * teardown that reads one refuses the take before it begins.\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 /**\n * Where the sound the page played is kept, fetched with the page's own\n * cookies at the end of the take. A host that hands in none still\n * records `meta.media`, with no file; a rehearsal fetches nothing.\n */\n sounds?: SoundSink\n /**\n * The files the script names beside itself (a drag's path file, a\n * paste's file). A host that hands in none cannot run such a step: the\n * script is refused before anything is captured.\n */\n files?: ScriptFiles\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 /**\n * A step the page stopped answering in (it ran into its bound) stops the\n * take there, as an `await` that timed out does (`--strict`). Without\n * it the step is a skip and the take goes on.\n */\n stopOnHang?: boolean\n /** How often a long `await` reports it is still waiting (default 30 s). */\n awaitHeartbeatMs?: number\n /**\n * Where a peer's `storageState` is read from: the CLI resolves the name\n * from the actions file's directory to a path the browser opens, and\n * throws in words when there is none. A host that hands in none cannot\n * sign a peer in, and such a script is refused before anything is\n * captured.\n */\n peerStorageState?: (name: string) => Promise<string> | string\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 // Set once the take's first step is about to run: a take that throws\n // after that still runs its teardown, since undoing what it created\n // matters most exactly then. Best effort, and the throw propagates.\n const late: { teardown?: () => Promise<unknown> } = {}\n try {\n return await recordTakeSteps(browser, url, actions, sink, log, opts, late)\n } catch (e) {\n const teardown = late.teardown\n late.teardown = undefined\n if (teardown) await teardown().catch(() => {})\n throw e\n }\n}\n\nasync function recordTakeSteps(\n browser: RecorderBrowser,\n url: string,\n actions: ActionsFile,\n sink: FrameSink,\n log: (msg: string) => void,\n opts: RecordOpts,\n late: { teardown?: () => Promise<unknown> },\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 // A teardown that reads a variable this env does not hold is refused\n // before anything runs, in a rehearsal too (it clicks for real): the take\n // would create what its teardown then cannot remove.\n const teardownEnv = teardownEnvProblem(actions.teardown, opts.env ?? {})\n if (teardownEnv) throw new SetupEnvError(teardownEnv)\n // The files a script names (a path to draw, a file to paste) are read\n // and checked before a browser context exists, in a rehearsal too: a\n // missing or malformed one refuses the take in words.\n const read = await loadScriptFiles(actions, opts.files)\n if ('problem' in read) throw new RecordRefusedError(read.problem)\n const files: LoadedFiles = read\n // A peer's sign-in is resolved before a browser context exists too: a\n // storage state that is not there refuses the take in words.\n const peers: Peer[] = actions.peers ?? []\n const peerStates = new Map<string, string>()\n for (const p of peers) {\n if (p.storageState === undefined) continue\n if (!opts.peerStorageState)\n throw new RecordRefusedError(\n `peer ${p.id} signs in from the storage state \"${p.storageState}\", and this recorder has nowhere to read one from. Nothing was recorded.`,\n )\n try {\n peerStates.set(p.id, await opts.peerStorageState(p.storageState))\n } catch (e) {\n throw new RecordRefusedError(\n `peer ${p.id}'s storage state \"${p.storageState}\" could not be read (${e instanceof Error ? e.message : String(e)}). Nothing was recorded.`,\n )\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 // Every media element the page plays is noted from document start, in\n // every frame (pageSound.ts), so the sound it made can be placed later.\n await context.addInitScript(MEDIA_WATCH_SCRIPT)\n const soundLog = new PageSoundLog()\n const exposureLog = new ExposureLog(masks)\n const noticeLog = new NoticeLog()\n const rawPage = await context.newPage()\n // Every call into the page is bounded (stepBound.ts): a page that stops\n // answering ends the step it hung, never the take's clock.\n const pageBound = new StepBound()\n const page = bounded(rawPage, pageBound)\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 noticeLog.add(step, (scan as { notices?: ScannedNotice[] } | null)?.notices)\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 // The teardown's page errors are not the take's.\n let tearingDown = false\n page.on('console', (m) => {\n if (m.type() !== 'error' || tearingDown) return\n const line = pageErrors.add(m.text())\n if (line) log(line)\n })\n\n // When the first page counts as ready: its DOM settled (default), or\n // its network went idle (`ready: \"networkidle\"`). Polled on the wall's\n // clock in a rehearsal too: how long a page takes is what it is for.\n const readyMode = actions.ready ?? DEFAULT_READY\n const open = (target: string) =>\n untilReady(page, readyMode, (o) => page.goto(target, o), {\n sleep: realSleep,\n })\n log(`goto ${url}`)\n const opened = await open(url)\n let response = opened.response\n const ready: ReadyReport = opened.ready\n log(` ${readyLine(ready)}`)\n // A warning only when network idle was asked for and never came.\n const navTimeout = ready.mode === 'networkidle' && ready.capped\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 goto: (target) => open(target),\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 open(url)).response\n }\n\n // The teardown: off camera, after the take, on this page and context. Run\n // once, bounded as a whole, and never thrown: a step that fails stops it\n // there and is reported, and the take stands.\n const teardownSteps = actions.teardown ?? []\n let teardown: TeardownReport | null = null\n let teardownRan = false\n const runTeardown = async (): Promise<TeardownReport | null> => {\n if (!teardownSteps.length || teardownRan) return teardown\n teardownRan = true\n tearingDown = true\n log(`teardown: ${teardownSteps.length} step(s), off camera`)\n try {\n const result = await runSetup(page, teardownSteps, {\n phase: 'teardown',\n sleep: realSleep,\n env: opts.env ?? {},\n goto: (target) => open(target),\n boundMs: TEARDOWN_BOUND_MS,\n })\n for (const line of result.lines) log(` ${line}`)\n teardown = {\n ran: result.ran,\n of: teardownSteps.length,\n ...(result.failed\n ? {\n failed: {\n step: result.failed.step,\n do: result.failed.do,\n ...(result.failed.selector !== undefined\n ? { selector: result.failed.selector }\n : {}),\n error: result.failed.error ?? 'the step failed',\n },\n }\n : {}),\n }\n } catch (e) {\n teardown = {\n ran: 0,\n of: teardownSteps.length,\n failed: {\n step: 0,\n do: teardownSteps[0].do,\n error: e instanceof Error ? e.message : String(e),\n },\n }\n }\n if (teardown.failed) log(` ${teardownLine(teardown)}`)\n return teardown\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 // What the page played while it was being prepared is not the take's.\n await page.evaluate(MEDIA_DRAIN_PROBE).catch(() => null)\n // A script that settles gets the page's change clock started now, so the\n // first settle knows how long the page has been still.\n if (actions.steps.some((s) => settleOn(s, actions.settle)))\n await page.evaluate(CHANGE_AGE_PROBE).catch(() => undefined)\n\n // The peers open now, before the camera rolls: each its own context and\n // page on the same address, never filmed, scanned or listened to. A peer\n // that lands on a sign-in has no one signed in to act as, so the take is\n // refused before a frame is captured.\n const peerPages: {\n peer: Peer\n context: RecorderContext\n page: RecorderPage\n }[] = []\n const closePeers = async () => {\n const bound = new StepBound()\n bound.start(CLOSE_BOUND_MS)\n await Promise.all(\n peerPages.map((p) => bound.race(p.context.close().catch(() => {}))),\n )\n bound.end()\n }\n for (const peer of peers) {\n const peerUrl = peer.url ?? url\n const pctx = await browser.newContext({\n viewport: peer.viewport ?? { width: vw, height: vh },\n deviceScaleFactor: 1,\n ...(peerStates.has(peer.id)\n ? { storageState: peerStates.get(peer.id) }\n : {}),\n })\n if (opts.headers && Object.keys(opts.headers).length)\n await applyHeaders(pctx, opts.headers, peerUrl, log)\n const ppage = await pctx.newPage()\n peerPages.push({ peer, context: pctx, page: ppage })\n const peerErrors = new PageErrorLog(opts.verbose === true)\n ppage.on('console', (m) => {\n if (m.type() !== 'error') return\n const line = peerErrors.add(m.text())\n if (line) log(` peer ${peer.id}: ${line.trim()}`)\n })\n log(`peer ${peer.id}: goto ${peerUrl} (off camera)`)\n const popened = await untilReady(\n ppage,\n readyMode,\n (o) => ppage.goto(peerUrl, o),\n { sleep: realSleep },\n )\n const seen = (await ppage.evaluate(WALL_PROBE).catch(() => null)) as Pick<\n Arrival,\n 'passwordFields' | 'newPasswordField' | 'oneTimeCodeField'\n > | null\n const peerWall = wallVerdict({\n askedUrl: peerUrl,\n landedUrl: ppage.url(),\n ...(popened.response ? { status: popened.response.status() } : {}),\n passwordFields: seen?.passwordFields ?? 0,\n newPasswordField: seen?.newPasswordField ?? false,\n oneTimeCodeField: seen?.oneTimeCodeField ?? false,\n })\n if (peerWall?.level === 'hard') {\n await closePeers()\n await context.close().catch(() => {})\n throw new RecordRefusedError(\n `peer ${peer.id} landed on ${peerWall.landed}, not ${peerWall.asked} (${peerWall.kind}): a peer acts as someone signed in, so give it a storageState of the second person's sign-in (beside actions.json). Nothing was recorded.`,\n )\n }\n log(` peer ${peer.id}: ${readyLine(popened.ready)}`)\n }\n\n const cdp = await context.newCDPSession(rawPage)\n // The surface the screencast reads is the viewport, or the take is short\n // (surfaceFit.ts). Before the camera rolls; a rehearsal captures nothing.\n if (!dry) await fitSurfaceToViewport(cdp, vw, vh)\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 // The page's media notes since the last look, in the recorder's clock.\n const drainSound = async (step?: number) => {\n const drain = (await page\n .evaluate(MEDIA_DRAIN_PROBE)\n .catch(() => null)) as MediaDrain | null\n soundLog.add(drain, Date.now(), step)\n }\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 /**\n * Travel to the rect's centre and press. A double or triple click is that\n * many presses well inside the platform's double-click interval, each\n * carrying its click count, so the page reads one gesture; every press is\n * a down and an up on the cursor track, with its button.\n */\n /**\n * Travel to an element's centre (a rect) or to a viewport point, and\n * press. A double or triple click is that many presses well inside the\n * platform's double-click interval, each carrying its click count, so the\n * page reads one gesture; every press is a down and an up on the cursor\n * track, with its button, and with the element's rect when there is one.\n * `modifiers` go down after the travel and come up after the last\n * release, whatever happens in between.\n */\n const clickAt = async (\n at: Rect | { x: number; y: number },\n how: {\n count?: number\n button?: ClickButton\n modifiers?: readonly DragModifier[]\n } = {},\n ) => {\n const rect = 'w' in at ? at : undefined\n await moveTo(\n rect ? rect.x + rect.w / 2 : at.x,\n rect ? rect.y + rect.h / 2 : at.y,\n )\n const held: string[] = []\n try {\n for (const m of how.modifiers ?? []) {\n const key = resolveModifier(m)\n await page.keyboard.down(key)\n held.push(key)\n }\n await sleep(PRESS_LEAD_MS)\n const count = how.count ?? 1\n const button = buttonNumber(how.button)\n for (let n = 1; n <= count; n++) {\n if (n > 1) await sleep(MULTI_CLICK_GAP_MS)\n const press = {\n ...(how.button && how.button !== 'left'\n ? { button: how.button }\n : {}),\n ...(n > 1 ? { clickCount: n } : {}),\n }\n const hasOpts = Object.keys(press).length > 0\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'down',\n button,\n ...(rect ? { rect } : {}),\n })\n await (hasOpts ? page.mouse.down(press) : page.mouse.down())\n await sleep(n < count ? PRESS_HOLD_MS / 2 : PRESS_HOLD_MS)\n await (hasOpts ? page.mouse.up(press) : page.mouse.up())\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'up',\n button,\n ...(rect ? { rect } : {}),\n })\n }\n } finally {\n for (const key of held.reverse())\n await page.keyboard.up(key).catch(() => undefined)\n }\n }\n\n /** A key's typing ping: where the key is about, never which key. */\n const keyPing = (rect: Rect | null) =>\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\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 const overruns: StepOverrun[] = []\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 // The peers' lanes start now and wait on the take's step boundaries; the\n // camera rolls with the first step.\n const signals = new StepSignals(\n actions.steps.map((s) => s.id).filter((id): id is string => !!id),\n )\n const lanes = peerPages.map(({ peer, page: ppage }) =>\n runPeer(peer, ppage, signals, {\n clock: { now: () => Date.now(), sleep },\n footageMs: () => now(),\n log,\n dry,\n }).catch((e: unknown): PeerRun => {\n log(\n ` (peer ${peer.id}: stopped: ${e instanceof Error ? e.message : String(e)})`,\n )\n return { id: peer.id, steps: [], notRun: [] }\n }),\n )\n signals.begin()\n // From the first step on, a take that throws still runs its teardown,\n // with the camera stopped first so none of it is captured.\n late.teardown = async () => {\n if (!dry) await cdp.send('Page.stopScreencast').catch(() => {})\n pageBound.end()\n // No result carries it on this path, so the log says how it went.\n const report = await runTeardown()\n if (report && !report.failed) log(` ${teardownLine(report)}`)\n }\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 paced gesture's plan against its wall time (the overrun report):\n // set by the cases whose tempo the script sets.\n const paced: { v: { plannedMs: number; tookMs: number } | null } = {\n v: null,\n }\n const timed = async <T>(plannedMs: number, fn: () => Promise<T>) => {\n const t = Date.now()\n const out = await fn()\n paced.v = { plannedMs, tookMs: Date.now() - t }\n return out\n }\n // A step's own ask when the script's numbers do not say it (a path\n // read from a file, a key sequence): what the pace report compares.\n let askedOverride: number | null = null\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 if (typeof step.zoom === 'boolean') extra.zoom = step.zoom\n // What a `js` check last answered, kept on the step: the app's own\n // state at that moment, which the frames cannot say.\n const keepValue = (last: ConditionState) => {\n if (!('value' in last)) return\n const kept = keptValue(last.value)\n if (kept !== undefined) extra.value = kept\n }\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 (\n sel: string | undefined,\n point?: { x: number; y: number } | null,\n ): 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 else if (point) await gesture(() => moveTo(point.x, point.y))\n log(\n `${tag}: guarded (${step.guard}), ${rect || point ? '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 const boundMs = stepBoundMs(\n step as Parameters<typeof stepBoundMs>[0],\n askedMs(step as Parameters<typeof askedMs>[0]),\n {\n expectS: EXPECT_TIMEOUT_S,\n awaitS: AWAIT_TIMEOUT_S,\n downloadS: DOWNLOAD_TIMEOUT_S,\n },\n )\n opts.onEvent?.({\n event: 'step',\n phase: 'start',\n i: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n do: step.do,\n })\n signals.start(step.id)\n const stepWall = Date.now()\n pageBound.start(boundMs)\n switch (step.do) {\n case 'wait':\n await sleep(clampWait(step.ms, now(), maxSeconds))\n break\n case 'move':\n // The pointer's travel is the recorder's, a gesture.\n await gesture(() => moveTo(step.x, step.y))\n break\n case 'hover': {\n // An element's centre, or a viewport point (a spot on a canvas).\n if (step.selector === undefined) {\n const px = step.x ?? cur.x\n const py = step.y ?? cur.y\n await gesture(() => moveTo(px, py))\n log(`hover ${Math.round(px)},${Math.round(py)}`)\n await sleep(step.ms ?? 700)\n break\n }\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 how = {\n count: step.count,\n button: step.button,\n modifiers: step.modifiers,\n }\n const said = `${step.count === 3 ? 'triple-click' : step.count === 2 ? 'double-click' : 'click'}${step.button && step.button !== 'left' ? ` (${step.button})` : ''}${step.modifiers?.length ? ` holding ${step.modifiers.join('+')}` : ''}`\n // A viewport point: a spot on a canvas no selector names.\n if (step.selector === undefined) {\n const point = { x: step.x ?? cur.x, y: step.y ?? cur.y }\n if (await rehearseGuard(undefined, point)) break\n await gesture(() => clickAt(point, how))\n log(`${said} at ${Math.round(point.x)},${Math.round(point.y)}`)\n const sinceChange = await gesture(() => waitSettled())\n await sleep(holdLeftMs(settleMs(step), sinceChange))\n break\n }\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, how))\n log(`${said} ${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 const chars = [...step.text]\n await timed(Math.max(0, chars.length - 1) * delay, () =>\n clockTyping(\n chars,\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 )\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 // A chord, a plain key or a sequence: each key is its own ping, a\n // person's hand apart. The ping is when and where, never which key.\n const seq = pressSequence(step)\n const chords = step.keys !== undefined ? seq.map(resolveChord) : seq\n const plan = keySequencePlanMs(chords.length)\n if (chords.length > 1) askedOverride = plan + settleMs(step)\n await timed(plan, async () => {\n for (const [i, chord] of chords.entries()) {\n if (i > 0) await sleep(KEY_SEQUENCE_GAP_MS)\n keyPing(rect)\n await page.keyboard.press(chord)\n }\n })\n log(`press ${seq.join(', ')}`)\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 // A drawn path starts at its first point; a straight drag at the\n // selector's centre, else (x, y).\n let path: PathSample[] | null = null\n if (typeof step.path === 'string') {\n const read = files.paths.get(stepIdx)\n if (read) path = schedulePath(read, step.ms)\n } else if (step.path !== undefined) {\n const read = readPath(step.path)\n if (!('problems' in read)) path = schedulePath(read, step.ms)\n }\n let start: { x: number; y: number } | null = null\n let rect: Rect | undefined\n if (path) {\n start = { x: path[0].x, y: path[0].y }\n } else 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 const from0 = start\n await gesture(() => moveTo(from0.x, from0.y))\n // The modifiers go down after the travel and before the press, and\n // come up after the release, so the page sees them for the whole\n // drag and the pointer's approach is a plain move.\n const mods = step.modifiers ?? []\n const held: string[] = []\n try {\n for (const m of mods) {\n const key = resolveModifier(m)\n await page.keyboard.down(key)\n held.push(key)\n }\n await gesture(() => sleep(PRESS_LEAD_MS))\n // A path that carries pressure is drawn with a PEN through the\n // browser's own input (the mouse has no pressure); a driver that\n // will not take one draws it with the mouse and says so.\n const bits = modifierBits(mods, opts.platform)\n const penAt = (\n type: 'mousePressed' | 'mouseMoved' | 'mouseReleased',\n p: { x: number; y: number; pressure?: number },\n ) =>\n cdp.send('Input.dispatchMouseEvent', {\n type,\n x: p.x,\n y: p.y,\n button: 'left',\n buttons: type === 'mouseReleased' ? 0 : 1,\n ...(type === 'mouseMoved' ? {} : { clickCount: 1 }),\n pointerType: 'pen',\n force: type === 'mouseReleased' ? 0 : (p.pressure ?? 0.5),\n modifiers: bits,\n })\n let pen = path?.some((p) => p.pressure !== undefined) ?? false\n if (pen && path) {\n try {\n await penAt('mousePressed', path[0])\n } catch {\n pen = false\n log(\n ` (${tag} drag: this browser takes no pen input; the path is drawn with the mouse and its pressure dropped)`,\n )\n }\n }\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'down',\n button: 0,\n rect,\n })\n if (!pen) await page.mouse.down()\n await gesture(() => sleep(PRESS_HOLD_MS))\n if (path) {\n // Every point is sent, in order, at its time: a drawing's shape\n // is its points, so a page that answers slowly makes the stroke\n // late (an overrun, reported), never a different stroke.\n const pts = path\n const total = pathDurationMs(pts)\n askedOverride = total\n await timed(total, async () => {\n const from = Date.now()\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i]\n if (!dry) {\n const wait = from + p.at - Date.now()\n if (wait > 0) await realSleep(wait)\n }\n if (pen) await penAt('mouseMoved', p)\n else await page.mouse.move(p.x, p.y)\n cur.x = p.x\n cur.y = p.y\n emit({ x: Math.round(p.x), y: Math.round(p.y), type: 'move' })\n }\n })\n } else {\n // The drag is the ask: `ms` of travel by the clock, however\n // slowly the page answers each move (a slider re-rendering per\n // sample).\n const dur = step.ms ?? 700\n const from = { ...cur }\n const tx = step.tx ?? from.x\n const ty = step.ty ?? from.y\n await timed(dur, () =>\n clockMotion(\n dur,\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({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'move',\n })\n },\n clock,\n ),\n )\n }\n await gesture(() => sleep(settleMs({ do: 'drag' })))\n if (pen) await penAt('mouseReleased', { x: cur.x, y: cur.y })\n else 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 } finally {\n for (const key of held.reverse())\n await page.keyboard.up(key).catch(() => undefined)\n }\n const holding = mods.length ? ` holding ${mods.join('+')}` : ''\n log(\n path\n ? `drag a path of ${path.length} points from ${Math.round(start.x)},${Math.round(start.y)}${holding}`\n : `drag ${step.selector ?? `${start.x},${start.y}`} → ${step.tx},${step.ty}${holding}`,\n )\n // The drag's own hold after the release: the recorder's, a gesture.\n await gesture(() => sleep(DRAG_HOLD_MS))\n break\n }\n case 'paste': {\n // Words or a file on the clipboard, pasted as a person's ⌘V does:\n // into the selector (clicked first, as a person puts the caret\n // there) or where the focus already is. The keystroke is a typing\n // ping; what was pasted never reaches the cursor track.\n const item = pasteItemOf(step, stepIdx, files)\n if (!item) {\n skip(step.file ?? '', `\"${step.file}\" was not read`)\n break\n }\n let rect: Rect | null = null\n if (step.selector) {\n rect = await boxOf(step.selector)\n stepRect = rect\n if (!rect) {\n skip(step.selector)\n break\n }\n const at = rect\n await gesture(() => clickAt(at))\n }\n const ping = { done: false }\n const outcome = await runPaste(page, context, item, async (chord) => {\n keyPing(rect)\n ping.done = true\n await page.keyboard.press(chord)\n })\n if ('failed' in outcome) {\n skip(step.selector ?? step.file ?? 'paste', outcome.failed)\n log(` (${tag} paste: ${outcome.failed})`)\n break\n }\n if (!ping.done) keyPing(rect)\n const what =\n step.text !== undefined\n ? `${[...step.text].length} chars`\n : `the file ${step.file}`\n const into = step.selector ? ` into ${step.selector}` : ''\n log(\n outcome.via === 'file'\n ? `paste ${what}${into}, dispatched in the page with the file's own bytes (the browser's clipboard re-encodes an image and drops what it carries, its density among it); its events are untrusted`\n : outcome.via === 'page'\n ? `paste ${what}${into}, dispatched in the page (the browser's clipboard refused it: ${outcome.why}); its events are untrusted`\n : `paste ${what}${into}`,\n )\n const sinceChange = await gesture(() => waitSettled())\n await sleep(holdLeftMs(settleMs(step), sinceChange))\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 keepValue(res.last)\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 ? () => reloadUntilReady(page, readyMode, timeoutMs)\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 keepValue(out.last)\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 gesture that waits on the app: no DOM change and no new frame for a\n // beat before the next step, so a canvas that fell behind catches up.\n if (\n settleOn(step, actions.settle) &&\n skipped.length === skippedBefore &&\n !stopped\n ) {\n const res = await gesture(() =>\n appSettled(page, () => frames.length, {\n sleep: realSleep,\n sinceFrame: () =>\n frames.length ? now() - frames[frames.length - 1].tMs : null,\n }),\n )\n extra.settleMs = res.ms\n if (!res.settled)\n log(\n ` (${tag} settle: the page was still changing after ${sayDuration(res.ms)}; going on)`,\n )\n }\n // A paced gesture that ran past its script: the page could not keep up.\n if (paced.v && !dry) {\n const over = overrunOf(paced.v.plannedMs, paced.v.tookMs)\n if (over !== null) {\n overruns.push({\n step: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n do: step.do,\n plannedMs: Math.round(paced.v.plannedMs),\n tookMs: Math.round(paced.v.tookMs),\n overrunMs: over,\n })\n extra.overrunMs = over\n }\n }\n const hang = pageBound.end()\n if (hang.hung) {\n const reason = hangReason(step.do, hang.ms, hang.boundMs)\n // One skip per step: a miss the step said already gives way to why.\n const said = skipped.length > skippedBefore ? skipped.at(-1) : undefined\n if (said) {\n said.reason = reason\n extra.reason = reason\n } else skip((step as { selector?: string }).selector ?? '', reason)\n log(` (${tag} ${step.do}: ${reason})`)\n // --strict: a page that stopped answering stops the take here.\n if (opts.stopOnHang && !stopped)\n stopped = {\n step: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n reason: `${tag} ${step.do}: ${reason}, so the take stopped there`,\n }\n }\n // The step's own reads after it (its words, the scans) get a beat each.\n pageBound.start(POST_STEP_READ_MS)\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: askedOverride ?? 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 await drainSound(stepIdx)\n pageBound.end()\n const stepSpan = stepSpans[stepSpans.length - 1]\n signals.end(step.id)\n opts.onEvent?.({\n event: 'step',\n phase: 'end',\n i: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n do: step.do,\n ms: Date.now() - stepWall,\n ...(stepSpan?.skipped ? { skipped: true } : {}),\n ...(hang.hung ? { hung: true } : {}),\n })\n // An await that timed out with onTimeout \"fail\": the take ends here.\n if (stopped) break\n }\n // The take's steps are over: a peer step still waiting never runs, one\n // already running finishes (bounded) while the camera still rolls.\n signals.close()\n const peerRuns = await Promise.all(lanes)\n for (const pr of peerRuns)\n for (const ps of pr.steps)\n if (ps.skipped)\n skipped.push({\n step: ps.step,\n ...(ps.id ? { id: ps.id } : {}),\n do: ps.do,\n selector: ps.selector ?? '',\n ...(ps.reason ? { reason: ps.reason } : {}),\n peer: pr.id,\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 // The take's own finish reads the page too, and is bounded like a step.\n pageBound.start(POST_STEP_READ_MS * 2)\n await drainSound()\n const endWall = Date.now()\n const durationMs = capped ? Math.min(now(), maxSeconds * 1000) : now()\n const heard = soundLog.heard(takeClock, endWall, durationMs)\n await cdp.send('Page.stopScreencast').catch(() => {})\n // Off camera now: the fetch takes what it takes.\n const media = await keepPageSound(\n heard,\n dry ? undefined : opts.sounds,\n fetchSource,\n log,\n )\n await sleep(200)\n const pageTitle = (await page.title().catch(() => '')) ?? ''\n for (const line of pageErrors.repeats()) log(line)\n pageBound.end()\n // The camera has stopped and the take's reads are done: what the take\n // created is undone now, before the context (and its cookies) closes.\n late.teardown = undefined\n await runTeardown()\n // A context whose page stopped answering may not close either: the take\n // is done whether it does or not.\n pageBound.start(CLOSE_BOUND_MS)\n await pageBound.race(context.close().catch(() => {}))\n pageBound.end()\n await closePeers()\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 ...(noticeLog.notices().length ? { notices: noticeLog.notices() } : {}),\n ...(masks.length ? { masks: exposureLog.masks(masks) } : {}),\n ...(skips.length ? { skips } : {}),\n ...(outputs.length ? { outputs } : {}),\n ...(media.length ? { media } : {}),\n ...(peerRuns.length\n ? {\n peers: peerRuns.map((pr) => ({\n id: pr.id,\n steps: pr.steps,\n ...(pr.notRun.length ? { notRun: pr.notRun } : {}),\n })),\n }\n : {}),\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 // A rehearsal captures no frames: it has no dead time to warn about.\n if (!dry && deadWarns(dead)) log(` WARNING: ${deadLine(dead)}`)\n\n const pace = paceReport(paces)\n if (!dry) log(` ${paceLine(pace)}`)\n const overrun = overrunLine(overruns)\n if (overrun) log(` WARNING: ${overrun}`)\n return {\n events,\n frames,\n meta,\n pace,\n skipped,\n navTimeout,\n ready,\n wall,\n exposures: exposureLog.exposures(),\n notices: noticeLog.notices(),\n masks: exposureLog.masks(masks),\n freezes,\n freezePct,\n dead,\n capped,\n disabled,\n confirmed,\n skips,\n outputs,\n media,\n stopped,\n pageErrors: pageErrors.entries(),\n overruns,\n // Self-contained: a path a file held is inline, so the take re-records\n // from its own script with the file gone.\n actions: { ...inlineScript(actions, files), url },\n peers: peerRuns,\n teardown,\n }\n}\n\n/**\n * Fetch each sound the page was heard playing, once per address, and keep\n * it through the host's sink: the take-relative key lands on its\n * `meta.media` entry. A source that cannot be fetched (a `blob:` of a page\n * that has gone, an address that answers 403) is said, and the entry keeps\n * the reason instead of a file. Nothing is fetched without a sink.\n */\nasync function keepPageSound(\n heard: ReturnType<PageSoundLog['heard']>,\n sink: SoundSink | undefined,\n fetchSource: (\n src: string,\n ) => Promise<{ bytes: Uint8Array; suggested: string; contentType?: string }>,\n log: (msg: string) => void,\n): Promise<NonNullable<RecordingMeta['media']>> {\n const kept = new Map<string, { file?: string; fetchError?: string }>()\n const used = new Set<string>()\n for (const h of heard) {\n if (!h.meta.intervals.length) continue\n const stretches = h.meta.intervals.length\n log(\n ` page sound: ${h.meta.src || 'a media element'} heard ${stretches === 1 ? 'once' : `${stretches} times`}`,\n )\n if (!sink || kept.has(h.src)) continue\n try {\n const got = await fetchSource(h.src)\n const name = outputName(\n undefined,\n got.suggested,\n `sound-${kept.size + 1}${extForType(got.contentType)}`,\n used,\n )\n used.add(name)\n kept.set(h.src, {\n file: await sink.save(name, got.bytes, got.contentType),\n })\n } catch (e) {\n const why = e instanceof Error ? e.message : String(e)\n kept.set(h.src, { fetchError: why })\n log(` (page sound not kept: ${why})`)\n }\n }\n return heard.map((h) => ({ ...h.meta, ...(kept.get(h.src) ?? {}) }))\n}\n\n/** How long a step's own reads after it (its words, the scans) may take on a page that has stopped answering. */\nconst POST_STEP_READ_MS = 5000\n/** How long the take waits for its browser context to close. */\nconst CLOSE_BOUND_MS = 10_000\n\n/** Why a step ended at its bound, with the real time it took. */\nexport function hangReason(verb: string, ms: number, boundMs: number): string {\n return `the page stopped answering: this ${verb} ran ${sayDuration(ms)}, past its bound of ${sayDuration(boundMs)}`\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 // A frame is drawn at its own size, never stretched to the take's: a\n // frame of another size means the surface moved mid-take, and a\n // picture scaled to fit would be a distorted take nobody was told of.\n if (bmp.width !== W || bmp.height !== H) {\n const size = bmp.width + 'x' + bmp.height\n bmp.close()\n throw new Error('frame ' + frames[fi].file + ' is ' + size + ', the take is ' + W + 'x' + H + ' (meta.captureWidth/captureHeight): frames are never resized, so the recorded surface changed size mid-take. Re-record it')\n }\n c2.drawImage(bmp, 0, 0)\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 EXPORT_RESOLUTION_OPTIONS,\n planAutoSpeed,\n planAutoZoom,\n projectFromArtifact,\n ratedSegments,\n recommendedExportResolution,\n withBackdrop,\n} from '@vosjs/studio-core'\nimport type {\n AudioClip,\n Backdrop,\n ProjectDoc,\n RecordingArtifact,\n RecordingPageMedia,\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 withFittingExport(withPageSound(doc, artifact.meta.media))\n}\n\n/**\n * The export a FRESH document opens on, sized to what the footage holds:\n * the ingest's default resolution, or the largest the recording supports\n * without upscaling when that is less (a 1280×720 take exports 720p, not a\n * 1080p that `vos validate` then warns upscales). Never raised. In place,\n * and returned.\n */\nexport function withFittingExport(doc: ProjectDoc): ProjectDoc {\n if (!doc.export) return doc\n const fits = recommendedExportResolution(doc)\n const order = EXPORT_RESOLUTION_OPTIONS as readonly string[]\n if (order.indexOf(fits) < order.indexOf(doc.export.resolution))\n doc.export = { ...doc.export, resolution: fits }\n return doc\n}\n\n/**\n * OUTPUT seconds of a moment of the PRIMARY footage through a rated piece\n * list; a moment in cut footage snaps to the next kept piece, and a piece\n * of another media only adds its length.\n */\nfunction sourceToOutput(\n pieces: readonly { in: number; out: number; rate?: number; media?: string }[],\n s: number,\n): number {\n let acc = 0\n for (const p of pieces) {\n const rate = p.rate && p.rate > 0 ? p.rate : 1\n if (p.media) {\n acc += Math.max(0, p.out - p.in) / rate\n continue\n }\n if (s < p.in) return acc\n if (s <= p.out) return acc + (s - p.in) / rate\n acc += Math.max(0, p.out - p.in) / rate\n }\n return acc\n}\n\n/**\n * The sound the page played (`meta.media`) as the document's audio: one\n * clip per heard stretch, keyed to the fetched file, placed at the OUTPUT\n * time of the footage moment it was heard (through the segments, the speed\n * spans and the freezes), stamped `source: 'page'`. A re-plan replaces only\n * those clips, so a clip someone added stays. An auto speed span over a\n * heard stretch is dropped first, or the footage would race ahead of what\n * the page was saying. A stretch with no fetched file (a hosted take, a\n * fetch that failed) places nothing. In place, and returned.\n */\nexport function withPageSound(\n doc: ProjectDoc,\n media: readonly RecordingPageMedia[] | undefined,\n): ProjectDoc {\n const kept = (doc.audio ?? []).filter((a) => a.source !== 'page')\n const heard = (media ?? []).filter((m) => m.file && m.intervals.length)\n if (!heard.length) {\n doc.audio = kept\n return doc\n }\n const spans = heard.flatMap((m) =>\n m.intervals.map((iv) => ({ in: iv.at, out: iv.at + (iv.to - iv.from) })),\n )\n doc.speed = (doc.speed ?? []).filter(\n (sp) =>\n sp.source !== 'auto' ||\n !!sp.media ||\n !spans.some((h) => sp.in < h.out && h.in < sp.out),\n )\n const pieces = ratedSegments(doc)\n const clips: AudioClip[] = []\n heard.forEach((m, i) => {\n const file = m.file as string\n const name = file.split('/').pop() || file\n const length = Math.max(m.duration ?? 0, ...m.intervals.map((iv) => iv.to))\n m.intervals.forEach((iv, j) => {\n clips.push({\n id: `page-${i + 1}-${j + 1}`,\n key: file,\n name,\n start: +sourceToOutput(pieces, iv.at).toFixed(3),\n in: iv.from,\n out: iv.to,\n duration: +length.toFixed(3),\n gain: m.volume ?? 1,\n fadeIn: 0,\n fadeOut: 0,\n source: 'page',\n })\n })\n })\n doc.audio = [...kept, ...clips]\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","response","EXPECT_TIMEOUT_S","VERBS","done","EXPECT_EVERY_MS","type","EXPECT_TIMEOUT_S","read"]}
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/stepBound.ts","../../src/record/pageSound.ts","../../src/record/takeClock.ts","../../src/record/pageErrors.ts","../../src/record/surfaceFit.ts","../../src/record/waits.ts","../../src/record/ready.ts","../../src/record/gestures.ts","../../src/record/paste.ts","../../src/record/settle.ts","../../src/record/peers.ts","../../src/record/actions.ts","../../src/record/scriptFiles.ts","../../src/record/pasteStep.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\n/** Which button a press is, and which press of a multi-click. */\nexport interface RecorderButtonOpts {\n button?: 'left' | 'right' | 'middle'\n clickCount?: number\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' | 'load'; 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' | 'load'\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 // A click's `button` and `count` (a double click is two presses, the\n // second with clickCount 2).\n down(opts?: RecorderButtonOpts): Promise<void>\n up(opts?: RecorderButtonOpts): 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 /** A drag's modifiers, held from the press to the release. */\n down(key: string): Promise<void>\n up(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 /**\n * A `paste` step's clipboard access, when the driver grants it; absent,\n * the paste is dispatched in the page and the recorder says so.\n */\n grantPermissions?(\n permissions: string[],\n opts?: { origin?: string },\n ): Promise<unknown>\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/**\n * Where the sound a page played during the take is kept: the CLI writes\n * `page-sound/<name>` in the take directory and answers that take-relative\n * key, which the plan's audio clips name. A host that hands in none (the\n * fleet) still records `meta.media`; the plan then places nothing.\n */\nexport interface SoundSink {\n save(\n name: string,\n bytes: Uint8Array,\n contentType?: string,\n ): Promise<string> | string\n}\n\n/**\n * Where the files a script names beside itself come from: a drag's path\n * file, a paste's file, by a plain name. The CLI reads the actions file's\n * directory. A host that hands in none (a hosted recorder carries the\n * script alone) cannot run such a step, and the recorder refuses it before\n * capturing anything.\n */\nexport interface ScriptFiles {\n read(name: string): Promise<Uint8Array>\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 paste: 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 case 'paste':\n return step.ms ?? SETTLE_MS.paste\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]\nexport type Notice = NonNullable<RecordingMeta['notices']>[number]\n/** A notice as one scan reports it. */\nexport type ScannedNotice = Omit<Notice, 'step' | 'seen'>\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 INFORMATION the scan reports beside the exposures (never a failure):\n * the signed-in account's own display name, wherever the frame shows it,\n * and a list of the account's recent items. Runs inside EXPOSURE_PROBE,\n * after `seen` and before any selector is made: it sets `acct`, which\n * `quiet` then keeps out of every selector. Never `$` + `{` in here: it is\n * spliced into a template.\n *\n * The name is read conservatively, from where apps say whose account it\n * is: a line that greets or names the account (\"Signed in as …\",\n * \"Welcome back, …\"), the label of an account menu (\"Account menu for …\"),\n * or the words on the account menu's own trigger (the button that opens\n * a menu and holds the avatar), which are SURE; or a name-like label on an avatar (an image's alt, a\n * button holding the picture), which MAY be the name.\n */\nexport const NOTICE_SRC = String.raw`const notices = () => {\n // A label made only of these words is the control's, never a person's:\n // \"Account menu\", \"Open user menu\", \"Profile settings\".\n const UI_WORDS = new Set(['account', 'accounts', 'profile', 'profiles', 'menu', 'user', 'users', 'settings', 'setting', 'avatar', 'open', 'close', 'toggle', 'show', 'hide', 'the', 'my', 'your', 'me', 'you', 'home', 'guest', 'admin', 'team', 'workspace', 'dashboard', 'sign', 'signed', 'in', 'out', 'log', 'logged', 'logout', 'login', 'help', 'search', 'notification', 'notifications', 'more', 'options', 'option', 'button', 'dropdown', 'picture', 'image', 'photo', 'main', 'navigation', 'nav', 'preferences', 'switch', 'manage'])\n const nameLike = (v) => {\n if (!v) return null\n const t = v.replace(/\\s+/g, ' ').trim().replace(/[!.,:]+$/, '')\n if (t.length < 2 || t.length > 40 || /[@\\d<>/|]/.test(t)) return null\n if (!/^\\p{Lu}[\\p{L}'’.-]*(?: \\p{L}[\\p{L}'’.-]*){0,3}$/u.test(t)) return null\n if (t.toLowerCase().split(' ').every((w) => UI_WORDS.has(w))) return null\n return t\n }\n const GREETING = /^(?:signed in as|logged in as|welcome back,?|welcome,|hi,|hello,|hey,)\\s+(.+)$/i\n const LABELS = [\n /^(?:account|user|profile)(?: menu)?(?: for|:|,| -)\\s*(.+)$/i,\n /^open (?:the )?(?:user|account|profile) menu(?: for|,|:)?\\s*(.+)$/i,\n /^(.+?)[’']s? (?:account|profile|avatar)$/i,\n ]\n const avatarish = (el) => el.tagName === 'IMG' || !!el.querySelector('img, svg') || /avatar/i.test(String(el.className || '') + ' ' + (el.getAttribute('data-testid') || ''))\n let sure = false\n const texts = document.createTreeWalker(document.body || document.documentElement, NodeFilter.SHOW_TEXT)\n for (let n; !acct && (n = texts.nextNode()); ) {\n const el = n.parentElement\n if (!el || /^(SCRIPT|STYLE|NOSCRIPT|TEMPLATE)$/.test(el.tagName)) continue\n const line = (el.textContent || '').replace(/\\s+/g, ' ').trim()\n if (line.length > 80) continue\n const m = GREETING.exec(line)\n const who = m && nameLike(m[1])\n if (who && seen(el)) { acct = who; sure = true }\n }\n let maybe = null\n if (!acct) {\n for (const el of document.querySelectorAll('[aria-label], img[alt], [title]')) {\n const label = el.getAttribute('aria-label') || el.getAttribute('alt') || el.getAttribute('title') || ''\n const box = el.closest('button, a, [role=\"button\"], [aria-haspopup]') || el\n if (!seen(el) && !seen(box)) continue\n let hit = null\n for (const rx of LABELS) { const m = rx.exec(label.trim()); if (m && (hit = nameLike(m[1]))) break }\n if (hit) { acct = hit; sure = true; break }\n if (!maybe && (avatarish(el) || avatarish(box)) && box !== el.ownerDocument.body) maybe = nameLike(label)\n }\n }\n // The account menu's TRIGGER, whose own words are the name: a control\n // that opens a menu and holds the avatar, or one labelled as the\n // account's. The name-like line among its words (an address there is\n // an exposure already, and never a name).\n if (!acct) {\n const TRIGGER_LABEL = /\b(account|user|profile|avatar)\b/i\n for (const el of document.querySelectorAll('button, a, [role=\"button\"], [aria-haspopup]')) {\n const label = (el.getAttribute('aria-label') || '') + ' ' + (el.getAttribute('title') || '')\n const trigger = (el.hasAttribute('aria-haspopup') && avatarish(el)) || TRIGGER_LABEL.test(label)\n if (!trigger || !seen(el)) continue\n const words = document.createTreeWalker(el, NodeFilter.SHOW_TEXT)\n for (let n; !acct && (n = words.nextNode()); ) {\n const who = nameLike(n.nodeValue)\n if (who && n.parentElement && seen(n.parentElement)) { acct = who; sure = true }\n }\n if (acct) break\n }\n }\n if (!acct && maybe) acct = maybe\n const found = []\n if (acct) {\n const places = [], at = new Set()\n const walk = document.createTreeWalker(document.body || document.documentElement, NodeFilter.SHOW_TEXT)\n for (let n; (n = walk.nextNode()) && places.length < 20; ) {\n const el = n.parentElement\n if (!el || /^(SCRIPT|STYLE|NOSCRIPT|TEMPLATE)$/.test(el.tagName)) continue\n if (!(n.nodeValue || '').includes(acct)) continue\n const r = seen(el)\n if (!r) continue\n const selector = name(el)\n if (at.has(selector)) continue\n at.add(selector)\n places.push({ selector, rect: { x: Math.round(r.left), y: Math.round(r.top), w: Math.round(r.width), h: Math.round(r.height) } })\n }\n if (places.length) found.push({ kind: 'account-name', sure, places })\n }\n const RECENT = /^(recents?|recently (?:viewed|opened|visited|edited)|history|recent (?:files|projects|documents|items|pages|boards|chats|conversations|searches))$/i\n const ITEMS = 'a[href], [role=\"link\"], [role=\"menuitem\"], [role=\"treeitem\"], [role=\"option\"]'\n const listed = new Set()\n for (const el of document.querySelectorAll('h1, h2, h3, h4, h5, h6, [role=\"heading\"], summary, div, span, p, li, label, strong, button, a')) {\n if (el.children.length > 2) continue\n const word = (el.textContent || '').replace(/\\s+/g, ' ').trim()\n if (word.length > 40 || !RECENT.test(word)) continue\n // A nav link that happens to say History is a page, not a list.\n if (/^(A|BUTTON)$/.test(el.tagName) && !el.hasAttribute('aria-expanded')) continue\n if (!seen(el)) continue\n for (const c of [el.nextElementSibling, el.parentElement && el.parentElement.nextElementSibling, el.parentElement]) {\n if (!c || c === document.body) continue\n const items = [...c.querySelectorAll(ITEMS)].filter((x) => x !== el && !x.contains(el) && seen(x))\n if (items.length < 3) continue\n const r = seen(c)\n if (!r) continue\n const selector = name(c)\n if (!listed.has(selector)) {\n listed.add(selector)\n found.push({ kind: 'personal-list', heading: word, selector, items: items.length, rect: { x: Math.round(r.left), y: Math.round(r.top), w: Math.round(r.width), h: Math.round(r.height) } })\n }\n break\n }\n if (listed.size >= 5) break\n }\n return found\n }\n // Read before any selector is made, so none of them quotes the name.\n const noticeList = notices()`\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 // The signed-in account's own name, once the notices have read it: a\n // selector never quotes it either.\n let acct = null\n const quiet = (v) => !!v && v.length <= 80 && !kindsIn(v).length && !(acct && v.toLowerCase().includes(acct.toLowerCase()))\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 ${NOTICE_SRC}\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, notices: noticeList }\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/**\n * Accumulates the notices across a take: the account's name is ONE notice,\n * its places gathered from every scan; a recent-items list is one notice\n * per list. Each keeps the first step it was seen at.\n */\nexport class NoticeLog {\n private byKey = new Map<string, Notice>()\n\n add(step: number, notices: ScannedNotice[] | undefined | null): void {\n for (const n of notices ?? []) {\n const key =\n n.kind === 'account-name' ? n.kind : `${n.kind}|${n.selector ?? ''}`\n const had = this.byKey.get(key)\n if (!had) {\n this.byKey.set(key, { step, ...n, seen: 1 })\n continue\n }\n had.seen += 1\n if (n.kind !== 'account-name') continue\n if (n.sure) had.sure = true\n const places = had.places ?? []\n for (const p of n.places ?? [])\n if (\n places.length < 20 &&\n !places.some((q) => q.selector === p.selector)\n )\n places.push(p)\n had.places = places\n }\n }\n\n notices(): Notice[] {\n return [...this.byKey.values()]\n }\n}\n\n/**\n * One notice, in words. The account's name is never printed: the line says\n * where it showed, so each place can be masked.\n */\nexport function noticeLine(n: Notice): string {\n const when = n.step < 0 ? 'as the page opened' : `from step #${n.step}`\n if (n.kind === 'account-name') {\n const places = n.places ?? []\n return `${n.sure ? '' : 'what may be '}the account's name (${places.length} ${places.length === 1 ? 'place' : 'places'}, ${when}): ${places.map((p) => p.selector).join('; ')}`\n }\n const mask = JSON.stringify({ selector: n.selector, as: 'blur' })\n return `a \"${n.heading}\" list of the account's own items (${n.items} items, ${when}) in ${n.selector}; to hide it, add to \"mask\": ${mask}`\n}\n\n/**\n * What to do about the notices, in one line: the swap hint is about the\n * account's name, so it is said only when the name was noticed.\n */\nexport function noticeAdvice(notices: readonly Pick<Notice, 'kind'>[]): string {\n const name = notices.some((n) => n.kind === 'account-name')\n return `These are the signed-in account's own: fine for a demo account, worth a mask on a real one.${name ? ' The name reads better swapped than blurred: { \"selector\": \"…\", \"as\": \"text\", \"text\": \"Jane Doe\" }.' : ''}`\n}\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 *\n * `teardown`: the same steps, run AFTER the take, off camera too: what the\n * take created in the product (an API key, a project, an invite) removed\n * again, so a rehearsal or a re-record leaves the account as it found it.\n * They run once the screencast has stopped, on the take's own page and\n * context (a session's cookies apply), and also when the take stops early\n * or throws once its first step has run. A teardown that fails never fails\n * the take: the footage is fine, and what is left behind is reported.\n *\n * `if`: a guard, `{ \"do\": \"if\", \"selector\": \"…\" }`. When its selector is on\n * the page the steps after it run as usual; when it is not, they are skipped\n * and the list ends there, which is not a failure. A teardown that undoes\n * what the take may already have removed on camera starts its undoing with\n * one (`if` the new key's row is still listed), so a good take reports\n * nothing to undo instead of a failure; a setup that signs in guards its\n * sign-in the same way (`if` the email field shows), so a session that is\n * already signed in passes. A failure AFTER a guard is still a failure.\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 | { do: 'if'; selector: string; ms?: number }\n) & { id?: string }\n\nconst VERBS = new Set(['wait', 'click', 'type', 'press', 'goto', 'if'])\n\n/** How long an `if` looks for its selector, when it names no `ms`. */\nexport const IF_LOOK_MS = 3000\n\n/** Which list a step belongs to, as its messages and log lines name it. */\nexport type StepPhase = 'setup' | 'teardown'\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/**\n * Structural validation, mirrored on `validateActions` for `steps`. The\n * same verbs and rules hold for `teardown`; `phase` names the list.\n */\nexport function validateSetup(\n value: unknown,\n phase: StepPhase = 'setup',\n): string[] {\n const errors: string[] = []\n if (!Array.isArray(value)) return [`${phase} must be an array of steps`]\n value.forEach((raw, i) => {\n const at = `${phase}[${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 (\n (s.do === 'click' || s.do === 'type' || s.do === 'if') &&\n typeof s.selector !== 'string'\n )\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/**\n * Every name a script reads from its env, its setup's and its teardown's,\n * each once: what a host must supply before the take begins.\n */\nexport function scriptEnvNames(script: {\n setup?: SetupStep[]\n teardown?: SetupStep[]\n}): string[] {\n return [\n ...new Set([\n ...setupEnvNames(script.setup),\n ...setupEnvNames(script.teardown),\n ]),\n ]\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 phase: StepPhase = 'setup',\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 `${phase}: 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\n/**\n * The first `{ env }` a teardown reads that `env` does not hold, in words,\n * or null. Asked BEFORE the take: a take that creates something its\n * teardown cannot then remove is the one case teardown exists for.\n */\nexport function teardownEnvProblem(\n steps: SetupStep[] | undefined,\n env: Record<string, string | undefined>,\n): string | null {\n for (const [i, s] of (steps ?? []).entries()) {\n if (s.do !== 'type' || typeof s.text !== 'object') continue\n const v = env[s.text.env]\n if (v === undefined || v === '')\n return `teardown[${i}] reads the environment variable ${s.text.env}, which is not set, so the take could leave behind what its teardown removes. Export it in the shell that runs vos record; it is never written to a file. Nothing was recorded.`\n }\n return null\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 /**\n * The step that failed: for a setup, a selector that never appeared (the\n * take does not start); for a teardown, the step it stopped at. `error`\n * is the driver's reason, one line, never a typed value.\n */\n failed?: { step: number; do: string; selector?: string; error?: string }\n /**\n * An `if` whose selector was not on the page: the list ended there, and\n * `rest` steps after it were skipped. Not a failure.\n */\n skipped?: { step: number; selector: string; rest: number }\n}\n\n/** How long a whole teardown may take before it is stopped and reported. */\nexport const TEARDOWN_BOUND_MS = 60_000\n\n/**\n * What a teardown did, on the take's result: how many of its steps ran,\n * and where it stopped. Never a typed value.\n */\nexport interface TeardownReport {\n ran: number\n of: number\n failed?: { step: number; do: string; selector?: string; error: string }\n /** An `if` whose selector was gone: nothing left to undo, never a failure. */\n skipped?: { step: number; selector: string; rest: number }\n}\n\n/** The teardown in one line, for the end of a take or a rehearsal. */\nexport function teardownLine(report: TeardownReport): string {\n const f = report.failed\n const k = report.skipped\n if (!f && k)\n return `teardown: nothing to undo, ${k.selector} is not on the page (teardown[${k.step}] if); ${report.ran} step(s) ran, ${k.rest} skipped`\n if (!f) return `teardown: ${report.ran} step(s) ran`\n const reason = f.error.replace(/[.\\s]+$/, '')\n return `TEARDOWN FAILED at teardown[${f.step}] (${f.do}${f.selector ? ` ${f.selector}` : ''}): ${reason}. What the take created may still be in the product; remove it by hand.`\n}\n\n/**\n * Run the setup (or the teardown) on a page, with plain Playwright actions:\n * no humanized pointer, no cursor events, no frames. A selector that never\n * appears fails the steps there, because a take that begins at a\n * half-finished sign-in is the wall by another name. With `boundMs`, the\n * steps together run no longer than that: the step running when it passes\n * fails, and the call it left pending is abandoned.\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 /** How a `goto` opens its page and waits for it (the take's ready mode); absent, network idle. */\n goto?: (url: string) => Promise<unknown>\n /** Which list these are, for the log and the messages (default `setup`). */\n phase?: StepPhase\n /** The longest the steps may take together, in ms. */\n boundMs?: number\n now?: () => number\n },\n): Promise<SetupResult> {\n const env = opts.env ?? {}\n const phase = opts.phase ?? 'setup'\n const now = opts.now ?? Date.now\n const deadline = opts.boundMs === undefined ? undefined : now() + opts.boundMs\n const lines: string[] = []\n // The value a `type` step is filling, so a reason that quotes it is not used.\n let typed = ''\n // Set by an `if` whose selector is not on the page: the list ends there.\n let gone: { step: number; selector: string } | null = null\n const runStep = async (step: SetupStep, i: number): Promise<string> => {\n const settle = 'ms' in step && typeof step.ms === 'number' ? step.ms : 150\n switch (step.do) {\n case 'wait':\n await opts.sleep(step.ms)\n return `${phase} #${i} wait ${step.ms}ms`\n case 'goto':\n await (\n opts.goto\n ? opts.goto(step.url)\n : page.goto(step.url, {\n waitUntil: 'networkidle',\n timeout: 45000,\n })\n ).catch(() => null)\n return `${phase} #${i} goto ${step.url}`\n case 'press':\n await page.keyboard.press(step.key)\n await opts.sleep(settle)\n return `${phase} #${i} press ${step.key}`\n case 'if': {\n const present = await page\n .locator(step.selector)\n .first()\n .waitFor({ state: 'visible', timeout: step.ms ?? IF_LOOK_MS })\n .then(() => true)\n .catch(() => false)\n if (present) return `${phase} #${i} if ${step.selector}: on the page`\n gone = { step: i, selector: step.selector }\n return `${phase} #${i} if ${step.selector}: not on the page, the ${steps.length - i - 1} step(s) after it skipped`\n }\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 return `${phase} #${i} click ${step.selector}`\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, phase)\n typed = value\n await loc.fill(value)\n await opts.sleep(settle)\n // The log names the field, never what went into it.\n return `${phase} #${i} type ${secret ? `\\${${(step.text as { env: string }).env}}` : `${value.length} chars`} into ${step.selector}`\n }\n }\n }\n for (const [i, step] of steps.entries()) {\n typed = ''\n try {\n lines.push(\n await withinDeadline(\n runStep(step, i),\n deadline,\n now,\n `the ${phase} ran past its ${sayBound(opts.boundMs ?? 0)} bound`,\n ),\n )\n } catch (e) {\n // A missing variable is a usage error before a take; a teardown's is\n // the step it stopped at.\n if (e instanceof SetupEnvError && phase === 'setup') 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 error: reasonWords(e, typed),\n },\n }\n }\n // Set inside runStep, which the compiler cannot see from here.\n const ended = gone as { step: number; selector: string } | null\n if (ended)\n return {\n ran: i + 1,\n lines,\n skipped: { ...ended, rest: steps.length - i - 1 },\n }\n }\n return { ran: steps.length, lines }\n}\n\n/** A bound in the words a log reads: whole seconds, or ms under one. */\nfunction sayBound(ms: number): string {\n return ms >= 1000 ? `${Math.round(ms / 1000)} s` : `${ms} ms`\n}\n\n/** `p`, or a rejection once `deadline` passes; the abandoned call is never awaited. */\nfunction withinDeadline<T>(\n p: Promise<T>,\n deadline: number | undefined,\n now: () => number,\n message: string,\n): Promise<T> {\n if (deadline === undefined) return p\n const left = deadline - now()\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(\n () => {\n p.catch(() => {})\n reject(new Error(message))\n },\n Math.max(0, left),\n )\n p.then(\n (v) => {\n clearTimeout(timer)\n resolve(v)\n },\n (e: unknown) => {\n clearTimeout(timer)\n reject(e)\n },\n )\n })\n}\n\n/** A terminal colour sequence, as a driver's error may carry one. */\nconst ANSI_COLOUR = new RegExp(`${String.fromCharCode(27)}\\\\[[0-9;]*m`, 'g')\n\n/**\n * A driver's error as one line a log may carry: its first line, without\n * terminal colour, and never a value a `type` step was filling.\n */\nfunction reasonWords(e: unknown, typed: string): string {\n const raw = e instanceof Error ? e.message : String(e)\n const line = (raw.replace(ANSI_COLOUR, '').split('\\n')[0] ?? '').trim()\n if (typed && line.includes(typed)) return 'the field could not be filled'\n return line || 'the step failed'\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 * A step never runs past its own bound, however the page behaves. A page\n * that stops answering (a busy loop, a renderer stuck after a reload the\n * page made itself) leaves every driver call pending for good, and a poll\n * that reads it waits on the read, not on its clock: an `expect` that said\n * \"for 5 s\" ran for fifteen minutes. So the page the recorder drives is\n * BOUNDED: while a step runs, every call into it is raced against the\n * step's deadline, and once the deadline has passed a pending call answers\n * `undefined` (what an absent element answers) instead of waiting. The\n * step then ends as a skip with the real time it took; the call it left\n * pending is abandoned, never awaited.\n *\n * Between steps the same race holds with a looser bound, so the take's\n * own finish (its last reads, the page's title) cannot hang either.\n */\n\n/** A gesture's bound past what it planned to take. */\nexport const STEP_MARGIN_MS = 30_000\n/** A check's (`expect`, `await`) bound past its own timeout. */\nexport const WAIT_MARGIN_MS = 5000\n/** One call's bound while no step runs (a navigation has its own 45 s timeout). */\nexport const IDLE_CALL_MS = 60_000\n\n/** The bound of one step, in ms: its own timeout for a check, its plan plus a margin for a gesture. */\nexport function stepBoundMs(\n step: {\n do: string\n timeout?: number\n until?: unknown\n reload?: boolean\n },\n plannedMs: number,\n defaults: { expectS: number; awaitS: number; downloadS: number },\n): number {\n if (step.do === 'expect')\n return (step.timeout ?? defaults.expectS) * 1000 + WAIT_MARGIN_MS\n if (step.do === 'await')\n return (step.timeout ?? defaults.awaitS) * 1000 + STEP_MARGIN_MS\n if (step.do === 'download') return defaults.downloadS * 1000 + STEP_MARGIN_MS\n return plannedMs + STEP_MARGIN_MS\n}\n\nexport class StepBound {\n private deadline: number | null = null\n private started = 0\n private hung = false\n\n constructor(\n private readonly now: () => number = Date.now,\n private readonly idleMs = IDLE_CALL_MS,\n ) {}\n\n /** A step begins: calls into the page answer within `boundMs` from now. */\n start(boundMs: number): void {\n this.started = this.now()\n this.deadline = this.started + boundMs\n this.hung = false\n }\n\n /** The step ends: whether it ran into its bound, and how long it really took. */\n end(): { hung: boolean; ms: number; boundMs: number } {\n const out = {\n hung: this.hung,\n ms: this.now() - this.started,\n boundMs: (this.deadline ?? this.started) - this.started,\n }\n this.deadline = null\n this.hung = false\n return out\n }\n\n /** The pending call, or `undefined` once the bound has passed. */\n race<T>(p: Promise<T>): Promise<T> {\n const left =\n this.deadline === null ? this.idleMs : this.deadline - this.now()\n if (left <= 0) {\n this.hung = true\n p.catch(() => {})\n return Promise.resolve(undefined as T)\n }\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.hung = true\n resolve(undefined as T)\n }, left)\n p.then(\n (v) => {\n clearTimeout(timer)\n resolve(v)\n },\n (e: unknown) => {\n clearTimeout(timer)\n reject(e)\n },\n )\n })\n }\n}\n\n/**\n * `target` with every method that answers a promise raced through the\n * guard, and every object it hands back (`page.mouse`, `locator()`,\n * `.first()`) guarded the same way. A call is made on the real object, so\n * nothing private to the driver is touched through the proxy.\n */\nexport function bounded<T extends object>(target: T, bound: StepBound): T {\n const cache = new WeakMap<object, object>()\n const wrap = <O extends object>(obj: O): O => {\n const had = cache.get(obj)\n if (had) return had as O\n const proxy = new Proxy(obj, {\n get(t, prop) {\n const value: unknown = Reflect.get(t, prop, t)\n if (typeof value === 'function')\n return (...args: unknown[]) => {\n const out: unknown = (value as (...a: unknown[]) => unknown).apply(\n t,\n args,\n )\n if (out && typeof (out as Promise<unknown>).then === 'function')\n return bound.race(out as Promise<unknown>)\n if (out && typeof out === 'object' && out !== t) return wrap(out)\n return out\n }\n if (value && typeof value === 'object') return wrap(value)\n return value\n },\n })\n cache.set(obj, proxy)\n return proxy\n }\n return wrap(target)\n}\n","/**\n * The sound a page plays during a take. The recorder captures frames, and\n * a product's sound (a voice preview, a video playing in the page) would\n * be lost with nothing to say it was there. Most of it is a media element,\n * so the recorder watches every `<video>` and `<audio>` the page plays, in\n * the page and in its same-origin frames, and keeps WHEN each was heard\n * and WHAT media time it played, so a clip of the same file can be placed\n * exactly under the footage (`meta.media`, then the plan's audio clips).\n *\n * Two pieces run IN the page, both plain JavaScript strings (a function\n * serialized out of a bundle picks up the bundler's helpers and dies in the\n * page): an init script that notes every play, pause, seek, end and volume\n * change into a log on the top window, and a drain that hands the log over\n * with the page's clock. The rest is here, in the recorder's clock: the\n * page's instants become wall instants, and the take clock turns those\n * into footage stretches, split wherever an `await` took the camera away.\n */\nimport type { RecordingPageMedia } from '@vosjs/studio-core'\nimport type { TakeClock } from './takeClock'\n\n/** The most elements a take follows, and the most notes the page keeps between drains. */\nconst MAX_ELEMENTS = 50\nconst MAX_NOTES = 2000\n/** A heard stretch shorter than this places nothing. */\nconst MIN_HEARD_S = 0.05\n\n/**\n * The init script: runs at document start in every frame. A frame that\n * cannot reach the top window (another origin) notes nothing. A media\n * element out of the document (`new Audio(url).play()`) is reached by\n * the play it is started with.\n */\nexport const MEDIA_WATCH_SCRIPT = `(() => {\n let host\n try { host = window.top; void host.document.title } catch { return }\n if (window.__vosMediaWatch) return\n window.__vosMediaWatch = true\n if (!host.__vosMedia) {\n const M = { log: [], seq: 0, els: new Set(), doc: Math.random().toString(36).slice(2) }\n M.fields = (el, kind) => ({\n id: el.__vosMediaId,\n tag: el.tagName === 'VIDEO' ? 'video' : 'audio',\n src: el.currentSrc || el.src || '',\n kind,\n wall: Date.now(),\n t: el.currentTime,\n rate: el.playbackRate || 1,\n paused: el.paused || el.ended,\n audible: !el.muted && el.volume > 0,\n volume: el.volume,\n duration: isFinite(el.duration) ? el.duration : null,\n ab: typeof el.webkitAudioDecodedByteCount === 'number' ? el.webkitAudioDecodedByteCount : null,\n })\n host.__vosMedia = M\n }\n const M = host.__vosMedia\n const EVENTS = ['playing', 'pause', 'ended', 'seeking', 'seeked', 'volumechange', 'ratechange', 'emptied']\n const note = (e) => {\n const el = e.target\n if (!el || typeof el.currentTime !== 'number' || !/^(VIDEO|AUDIO)$/.test(el.tagName || '')) return\n if (e.__vosNoted) return\n e.__vosNoted = true\n if (!el.__vosMediaId) {\n if (M.els.size >= ${MAX_ELEMENTS}) return\n el.__vosMediaId = ++M.seq\n M.els.add(el)\n }\n if (M.log.length < ${MAX_NOTES}) M.log.push(M.fields(el, e.type))\n }\n for (const type of EVENTS) document.addEventListener(type, note, true)\n const proto = window.HTMLMediaElement && window.HTMLMediaElement.prototype\n if (proto && proto.play) {\n const play = proto.play\n proto.play = function () {\n if (!this.__vosListening && !this.isConnected) {\n this.__vosListening = true\n for (const type of EVENTS) this.addEventListener(type, note)\n }\n return play.apply(this, arguments)\n }\n }\n})()`\n\n/**\n * The drain: the notes since the last drain, a `tick` for every element\n * followed (what it is doing now, which catches a note that never came),\n * the page's clock, and which document the log belongs to (a navigation\n * starts a new one).\n */\nexport const MEDIA_DRAIN_PROBE = `(() => {\n const M = window.__vosMedia\n if (!M) return { now: Date.now(), doc: null, notes: [] }\n const notes = M.log.splice(0)\n M.els.forEach((el) => notes.push(M.fields(el, 'tick')))\n return { now: Date.now(), doc: M.doc, notes }\n})()`\n\n/** One note from the page. */\nexport interface MediaNote {\n id: number\n tag: 'video' | 'audio'\n src: string\n kind: string\n wall: number\n t: number\n rate: number\n paused: boolean\n audible: boolean\n volume: number\n duration: number | null\n ab: number | null\n}\n\nexport interface MediaDrain {\n now: number\n doc: string | null\n notes: MediaNote[]\n}\n\ninterface Stretch {\n fromWall: number\n toWall: number\n t0: number\n rate: number\n}\n\ninterface Followed {\n tag: 'video' | 'audio'\n src: string\n step?: number\n duration?: number\n volume?: number\n played: boolean\n audioBytes: number | null\n open: { wall: number; t: number; rate: number } | null\n stretches: Stretch[]\n}\n\n/** A page sound with its full source, for the fetch; `meta` is what the take keeps. */\nexport interface HeardSound {\n meta: RecordingPageMedia\n /** the address as the page played it, query and all: fetched, never stored */\n src: string\n}\n\n/** What `meta.media[].src` keeps of an address: origin and path; a `blob:` or `data:` by its scheme. */\nexport function soundSrcForMeta(src: string): string {\n if (/^blob:/i.test(src)) return 'blob:'\n if (/^data:/i.test(src)) return src.slice(0, src.search(/[;,]/) + 1 || 5)\n try {\n const u = new URL(src)\n return `${u.origin}${u.pathname}`\n } catch {\n return ''\n }\n}\n\n/**\n * Accumulates the page's notes across a take, in the recorder's clock.\n * `add` takes each drain with the recorder's own `Date.now()` at the\n * moment it came back; `heard` closes what is still playing at the end\n * and maps every stretch to footage time.\n */\nexport class PageSoundLog {\n private byKey = new Map<string, Followed>()\n private openKeyOf = new Map<number, string>()\n private doc: string | null = null\n private lastWall = 0\n\n add(drain: MediaDrain | null, nodeNow: number, step?: number): void {\n if (!drain) return\n const skew = nodeNow - drain.now\n // A new document: what the old one was playing stopped with it, no\n // later than the last time it was seen.\n if (drain.doc !== this.doc) {\n if (this.doc !== null) this.closeAll(this.lastWall)\n this.openKeyOf.clear()\n this.doc = drain.doc\n }\n const notes = [...drain.notes].sort((a, b) => a.wall - b.wall)\n for (const n of notes) this.note(n, n.wall + skew, step)\n this.lastWall = nodeNow\n }\n\n private note(n: MediaNote, wall: number, step?: number): void {\n const key = `${this.doc}|${n.id}|${n.src}`\n const prevKey = this.openKeyOf.get(n.id)\n // The element moved on to another source: what it played before ended.\n if (prevKey && prevKey !== key) {\n const prev = this.byKey.get(prevKey)\n if (prev) this.close(prev, wall)\n }\n let f = this.byKey.get(key)\n if (!f) {\n if (!n.src) return\n f = {\n tag: n.tag,\n src: n.src,\n played: false,\n audioBytes: null,\n open: null,\n stretches: [],\n }\n this.byKey.set(key, f)\n }\n this.openKeyOf.set(n.id, key)\n if (n.duration !== null) f.duration = n.duration\n if (n.ab !== null) f.audioBytes = Math.max(f.audioBytes ?? 0, n.ab)\n if (!n.paused) f.played = true\n const stops = ['pause', 'ended', 'seeking', 'emptied'].includes(n.kind)\n const heard = !n.paused && n.audible && !stops\n // A resync point: the stretch so far ends here, and a new one starts\n // from the media time the page reports now.\n const resync = ['playing', 'seeked', 'ratechange'].includes(n.kind)\n if (f.open && (!heard || resync))\n this.close(\n f,\n wall,\n n.kind === 'ended' ? (n.duration ?? undefined) : undefined,\n )\n if (!f.open && heard) {\n f.open = { wall, t: n.t, rate: n.rate > 0 ? n.rate : 1 }\n f.volume = n.volume\n if (f.step === undefined && step !== undefined && step >= 0) f.step = step\n }\n }\n\n private close(f: Followed, wall: number, endT?: number): void {\n if (!f.open) return\n const { wall: from, t, rate } = f.open\n f.open = null\n if (wall <= from) return\n // The media time at the end is where the stretch was heading; an end\n // the page reported (`ended`) is the file's length.\n const to = endT ?? t + ((wall - from) / 1000) * rate\n f.stretches.push({\n fromWall: from,\n toWall: from + ((to - t) / rate) * 1000,\n t0: t,\n rate,\n })\n }\n\n private closeAll(wall: number): void {\n for (const f of this.byKey.values()) this.close(f, wall)\n }\n\n /**\n * Every element the page played, each heard stretch as footage seconds\n * `at` with media seconds `from`..`to`, none past `endMs` of footage.\n * A video whose decoder never decoded a byte of sound played none.\n */\n heard(clock: TakeClock, endWall: number, endMs: number): HeardSound[] {\n this.closeAll(endWall)\n const out: HeardSound[] = []\n for (const f of this.byKey.values()) {\n if (!f.played) continue\n const silentVideo = f.tag === 'video' && f.audioBytes === 0\n const intervals: RecordingPageMedia['intervals'] = []\n if (!silentVideo)\n for (const s of f.stretches)\n for (const c of clock.onCamera(s.fromWall, s.toWall)) {\n const at = c.atMs / 1000\n let from = s.t0 + ((c.wallMs - s.fromWall) / 1000) * s.rate\n let to = from + (c.ms / 1000) * s.rate\n if (f.duration !== undefined) to = Math.min(to, f.duration)\n const room = (endMs - c.atMs) / 1000\n if (room <= 0) continue\n to = Math.min(to, from + room * s.rate)\n from = Math.max(0, from)\n if (to - from < MIN_HEARD_S) continue\n intervals.push({\n at: +at.toFixed(3),\n from: +from.toFixed(3),\n to: +to.toFixed(3),\n })\n }\n out.push({\n src: f.src,\n meta: {\n ...(f.step !== undefined ? { step: f.step } : {}),\n src: soundSrcForMeta(f.src),\n tag: f.tag,\n ...(f.duration !== undefined\n ? { duration: +f.duration.toFixed(3) }\n : {}),\n ...(intervals.length && f.volume !== undefined\n ? { volume: +f.volume.toFixed(3) }\n : {}),\n intervals,\n ...(intervals.length ? {} : { muted: true }),\n },\n })\n }\n return out\n }\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 * The parts of a wall-clock stretch the camera saw: each sub-stretch\n * outside every off-camera wait, as its wall start (`wallMs`), its\n * footage start (`atMs`) and its length. A stretch an `await` cut in two\n * comes back as two; one wholly off camera as none.\n */\n onCamera(\n fromWall: number,\n toWall: number,\n ): { wallMs: number; atMs: number; ms: number }[] {\n const out: { wallMs: number; atMs: number; ms: number }[] = []\n let cur = Math.max(fromWall, this.t0)\n for (const p of this.pauses) {\n const pTo = p.to ?? Infinity\n if (pTo <= cur) continue\n if (p.from >= toWall) break\n if (p.from > cur)\n out.push({\n wallMs: cur,\n atMs: this.footageMs(cur),\n ms: p.from - cur,\n })\n cur = Math.max(cur, pTo)\n if (cur >= toWall) return out\n }\n if (toWall > cur)\n out.push({ wallMs: cur, atMs: this.footageMs(cur), ms: toWall - cur })\n return out\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","/**\n * The recorded surface is the viewport, exactly.\n *\n * The screencast reads the window's content surface, not the page's\n * emulated viewport. Playwright sizes a headless window TO the viewport,\n * assuming a headless window has no frame, and headless Chrome (the\n * `channel: 'chrome'` builds) gives it one: the page lays out at 1280x720\n * while the surface under it is 1280x633, and every frame of the take loses\n * the bottom 87 px (measured, Chrome 155 on macOS; a viewport of any size\n * loses the same strip, and a window made LARGER than the viewport hands\n * back more than the page). Two cases are exact already, and a fit there\n * measures and does nothing: Playwright's bundled headless shell, and a\n * page a persistent context opens with `newPage()` (a `--session` take),\n * while the first page of that same context and every page of a\n * `newContext()` (the default take, `--storage-state`) are short.\n *\n * So before the camera rolls: one screenshot says what the surface really\n * is, the window's bounds take the difference, and a second screenshot\n * says whether it landed. A driver that cannot (no Browser domain, a\n * window it may not move) is left as it was, and the meta's\n * `captureWidth`/`captureHeight` still say what was recorded.\n */\nimport { base64Bytes, jpegDims } from './recorder'\nimport type { RecorderCdp } from './driver'\n\nexport interface SurfaceSize {\n width: number\n height: number\n}\n\nexport interface SurfaceFit {\n before: SurfaceSize\n after: SurfaceSize\n}\n\n/** The surface the compositor hands back, in CSS px. */\nasync function surfaceSize(\n cdp: RecorderCdp,\n dpr: number,\n): Promise<SurfaceSize | null> {\n const shot = (await cdp.send('Page.captureScreenshot', {\n format: 'jpeg',\n quality: 1,\n })) as { data?: string }\n const dims = shot.data ? jpegDims(base64Bytes(shot.data)) : null\n if (!dims) return null\n return { width: Math.round(dims.w / dpr), height: Math.round(dims.h / dpr) }\n}\n\n/**\n * Make the surface the viewport. Returns what it measured, or null when\n * nothing could be measured; never throws, because a take made as before\n * is better than no take.\n */\nexport async function fitSurfaceToViewport(\n cdp: RecorderCdp,\n width: number,\n height: number,\n): Promise<SurfaceFit | null> {\n try {\n const ratio = (await cdp.send('Runtime.evaluate', {\n expression: 'devicePixelRatio',\n returnByValue: true,\n })) as { result?: { value?: unknown } }\n const value = ratio.result?.value\n const dpr = typeof value === 'number' && value > 0 ? value : 1\n const before = await surfaceSize(cdp, dpr)\n if (!before) return null\n let after = before\n // Twice at most: a window manager may round the first move.\n for (let tries = 0; tries < 2; tries++) {\n if (after.width === width && after.height === height) break\n const win = (await cdp.send('Browser.getWindowForTarget')) as {\n windowId: number\n bounds: { width?: number; height?: number }\n }\n const { width: ww, height: wh } = win.bounds\n if (ww === undefined || wh === undefined) break\n await cdp.send('Browser.setWindowBounds', {\n windowId: win.windowId,\n bounds: {\n width: ww + (width - after.width),\n height: wh + (height - after.height),\n },\n })\n after = (await surfaceSize(cdp, dpr)) ?? after\n }\n return { before, after }\n } catch {\n return null\n }\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 * A JavaScript expression evaluated in the page (awaited when it answers\n * a promise): the condition holds when its value is truthy, or, with\n * `equals`, when its value equals that one. For an app that keeps its\n * state in script rather than in the DOM (a canvas, a document model).\n */\n js?: string\n /** with `js`: the value the expression must equal (compared as JSON) */\n equals?: unknown\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 * with `js`: what the expression answered the last time it was read, as\n * JSON when it has a JSON form (absent for `undefined`), and in words\n * either way (`said`), or the error it threw (`threw`).\n */\n value?: unknown\n said?: string\n threw?: string\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/** The longest a js value is said in a line, in characters. */\nexport const JS_SAID_MAX = 120\n/** The most a js value kept on the step holds, in characters of JSON. */\nexport const JS_VALUE_MAX = 2048\n\n/**\n * The page script that evaluates a step's expression and answers what it\n * found, as a string (the one evaluate shape every driver shares). The\n * expression is the script author's own, run on their own page: it is\n * wrapped, never parsed, and a newline closes it before the paren so a\n * trailing line comment cannot swallow the wrapper.\n */\nexport function jsConditionScript(expr: string): string {\n return `(async () => {\n let v;\n try { v = await (${expr}\n ); } catch (e) { return JSON.stringify({ threw: String(e && e.message ? e.message : e) }) }\n const out = { truthy: !!v };\n try { const j = JSON.stringify(v); if (j !== undefined) out.json = j } catch (e) {}\n try { out.said = typeof v === 'string' ? JSON.stringify(v) : String(v) } catch (e) { out.said = typeof v }\n if (out.json !== undefined && typeof v !== 'string') out.said = out.json\n return JSON.stringify(out);\n})()`\n}\n\n/** Two JSON values alike: the same keys and values whatever the key order. */\nexport function sameJson(a: unknown, b: unknown): boolean {\n if (a === b) return true\n if (typeof a !== typeof b || a === null || b === null) return false\n if (typeof a !== 'object') return false\n if (Array.isArray(a) !== Array.isArray(b)) return false\n if (Array.isArray(a)) {\n const bb = b as unknown[]\n return a.length === bb.length && a.every((v, i) => sameJson(v, bb[i]))\n }\n const ao = a as Record<string, unknown>\n const bo = b as Record<string, unknown>\n const keys = Object.keys(ao)\n if (keys.length !== Object.keys(bo).length) return false\n return keys.every(\n (k) =>\n Object.prototype.hasOwnProperty.call(bo, k) && sameJson(ao[k], bo[k]),\n )\n}\n\n/** What a js expression answered, read once: the condition and the value. */\nasync function readJs(\n page: RecorderPage,\n c: { js: string; equals?: unknown },\n): Promise<ConditionState> {\n let raw: string\n try {\n raw = await page.evaluate<string>(jsConditionScript(c.js))\n } catch (e) {\n // An expression that does not parse never will: said, not retried as\n // \"not yet\". Anything else (a navigation under the read) is.\n const why = e instanceof Error ? e.message : String(e)\n if (\n /SyntaxError/.test(why) ||\n (e instanceof Error && e.name === 'SyntaxError')\n )\n return { holds: false, threw: `it does not parse: ${why.split('\\n')[0]}` }\n throw e\n }\n let got: { truthy?: boolean; json?: string; said?: string; threw?: string }\n try {\n got = JSON.parse(raw) as typeof got\n } catch {\n return { holds: false }\n }\n if (got.threw !== undefined) return { holds: false, threw: got.threw }\n let value: unknown\n let hasValue = false\n if (got.json !== undefined) {\n try {\n value = JSON.parse(got.json)\n hasValue = true\n } catch {\n // not JSON after all: said in words only\n }\n }\n const holds =\n c.equals !== undefined\n ? hasValue && sameJson(value, c.equals)\n : got.truthy === true\n return {\n holds,\n ...(hasValue ? { value } : {}),\n said: clip(got.said ?? 'undefined', JS_SAID_MAX),\n }\n}\n\nconst clip = (s: string, max: number): string =>\n s.length > max ? `${s.slice(0, max - 1)}…` : s\n\n/**\n * A js value as a step keeps it (`meta.steps[].value`): the value itself\n * while its JSON fits, else its JSON cut short as a string.\n */\nexport function keptValue(value: unknown): unknown {\n const json = JSON.stringify(value)\n if (json === undefined) return undefined\n return json.length <= JS_VALUE_MAX ? value : clip(json, JS_VALUE_MAX)\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.js !== undefined) return await readJs(page, { ...c, js: c.js })\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.js !== undefined)\n return c.equals !== undefined\n ? `${sayJs(c.js)} to equal ${clip(JSON.stringify(c.equals) ?? 'undefined', JS_SAID_MAX)}`\n : `${sayJs(c.js)} to hold`\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.js !== undefined) {\n if (last.threw !== undefined)\n return `${sayJs(c.js)} threw for ${t} (${clip(last.threw, JS_SAID_MAX)})`\n const was = last.said ?? 'never answered'\n return c.equals !== undefined\n ? `${sayJs(c.js)} was ${was}, not ${clip(JSON.stringify(c.equals) ?? 'undefined', JS_SAID_MAX)}, for ${t}`\n : `${sayJs(c.js)} was ${was} for ${t}`\n }\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/** An expression as a line names it: in backticks, cut short. */\nexport function sayJs(expr: string): string {\n return `js \\`${clip(expr.replace(/\\s+/g, ' ').trim(), 80)}\\``\n}\n\n/** A kept value as a line says it: its JSON, cut short. */\nexport function sayValue(value: unknown): string {\n return clip(JSON.stringify(value) ?? 'undefined', JS_SAID_MAX)\n}\n","/**\n * When a page counts as ready for the take to begin. The default is the\n * DOM: after `load`, the page must make no DOM change for a beat (counted\n * from outside, the way an `await` reload's settle is), at most a few\n * seconds. Network idle is the opt-in: plenty of real apps hold a socket\n * open or keep an analytics beacon going and never go network-idle, so a\n * take that waited for it started after its whole timeout, every time.\n */\nimport type { RecorderPage, RecorderResponse } from './driver'\nimport { realSleep } from './driver'\nimport { DOM_QUIET_MS, domSettled } from './waits'\n\n/** How a page counts as ready: its DOM settled (default), or its network went idle. */\nexport type ReadyMode = 'networkidle' | 'dom'\nexport const READY_MODES: readonly ReadyMode[] = ['dom', 'networkidle']\nexport const DEFAULT_READY: ReadyMode = 'dom'\n\n/** The longest a navigation waits for `load` or network idle. */\nexport const NAV_TIMEOUT_MS = 45_000\n/** The longest the settle waits on a page that never stops changing. */\nexport const READY_SETTLE_CAP_MS = 8000\n/** After network idle, the beat a hydration takes (what the recorder always gave it). */\nexport const NETWORKIDLE_HYDRATION_MS = 800\n\n/** How the first load settled: the done event's `ready`. */\nexport interface ReadyReport {\n mode: ReadyMode\n /** ms from the navigation's start until the page counted as ready */\n ms: number\n /**\n * The wait gave up instead of the page settling: the DOM never stopped\n * changing within the cap (dom), or network idle never came within\n * the navigation timeout (networkidle). Recorded anyway either way.\n */\n capped: boolean\n}\n\n/** Why a ready mode is not one, or null. */\nexport function readyProblem(v: unknown): string | null {\n if (v === undefined) return null\n return typeof v === 'string' && (READY_MODES as string[]).includes(v)\n ? null\n : `ready must be ${READY_MODES.map((m) => `\"${m}\"`).join(' or ')}`\n}\n\nexport interface ReadyOpts {\n sleep: (ms: number) => Promise<void>\n now?: () => number\n /** the settle's cap (default `READY_SETTLE_CAP_MS`) */\n capMs?: number\n /** the navigation's own timeout (default `NAV_TIMEOUT_MS`) */\n timeoutMs?: number\n}\n\n/**\n * Wait for a page that is navigating (or has just navigated) to be ready:\n * `navigate` starts the navigation with the `waitUntil` the mode asks for;\n * in `dom` mode the DOM settle follows `load`. A navigation that times\n * out is not fatal: the take goes on from whatever the page shows, and the\n * report says it was capped.\n */\nexport async function untilReady(\n page: RecorderPage,\n mode: ReadyMode,\n navigate: (opts: {\n waitUntil: 'networkidle' | 'load'\n timeout: number\n }) => Promise<RecorderResponse | null>,\n opts: ReadyOpts,\n): Promise<{ response: RecorderResponse | null; ready: ReadyReport }> {\n const now = opts.now ?? Date.now\n const start = now()\n const timeout = opts.timeoutMs ?? NAV_TIMEOUT_MS\n if (mode === 'networkidle') {\n let idle = true\n const response = await navigate({\n waitUntil: 'networkidle',\n timeout,\n }).catch(() => {\n idle = false\n return null\n })\n await opts.sleep(NETWORKIDLE_HYDRATION_MS)\n return {\n response,\n ready: { mode, ms: Math.round(now() - start), capped: !idle },\n }\n }\n const response = await navigate({ waitUntil: 'load', timeout }).catch(\n () => null,\n )\n const settled = await domSettled(page, {\n sleep: opts.sleep,\n now,\n quietMs: DOM_QUIET_MS,\n capMs: opts.capMs ?? READY_SETTLE_CAP_MS,\n })\n return {\n response,\n ready: { mode, ms: Math.round(now() - start), capped: !settled.settled },\n }\n}\n\n/**\n * An `await`'s reload between polls, under the take's ready mode: the\n * reload waits for `load` (dom) or network idle (networkidle), at most\n * the await's own timeout, and then the DOM settles either way, because\n * network quiet is not a drawn page (a list rendered from its data lands\n * after it). A page that never goes network-idle no longer costs a whole\n * navigation timeout per poll.\n */\nexport async function reloadUntilReady(\n page: RecorderPage,\n mode: ReadyMode,\n timeoutMs: number,\n opts: { sleep?: (ms: number) => Promise<void> } = {},\n): Promise<void> {\n const nav = {\n waitUntil:\n mode === 'networkidle' ? ('networkidle' as const) : ('load' as const),\n timeout: Math.min(NAV_TIMEOUT_MS, timeoutMs),\n }\n await (page.reload ? page.reload(nav) : page.goto(page.url(), nav)).catch(\n () => null,\n )\n await domSettled(page, { sleep: opts.sleep ?? realSleep })\n}\n\n/** The ready report in words, for the take's log. */\nexport function readyLine(r: ReadyReport): string {\n const s = (r.ms / 1000).toFixed(1)\n if (r.mode === 'networkidle')\n return r.capped\n ? `(networkidle timeout after ${s} s, continuing)`\n : `(network idle after ${s} s)`\n return r.capped\n ? `(the page was still changing after ${s} s, starting anyway)`\n : `(the page settled after ${s} s)`\n}\n","/**\n * The canvas gestures, the pure parts: key chords and sequences, the\n * modifiers a drag holds, a drawn path and its timing, a click's count and\n * button, and the overrun report. What a whiteboard, a design tool or a\n * timeline is recorded with, said as data so a script can carry it and\n * both hosts validate it in the same words.\n *\n * None of it reaches the cursor track as key identity: a key is a typing\n * ping (when and where), a modifier is nothing at all, and a path is its\n * points.\n */\n\n/** The modifiers a chord or a drag may hold. `Mod` is Meta on macOS, Control elsewhere. */\nexport const MODIFIERS = [\n 'Shift',\n 'Control',\n 'Alt',\n 'Meta',\n 'Mod',\n 'ControlOrMeta',\n] as const\nexport type Modifier = (typeof MODIFIERS)[number]\n\n/** The modifiers a drag names (the platform-neutral one is `Mod`). */\nexport const DRAG_MODIFIERS = [\n 'Alt',\n 'Shift',\n 'Meta',\n 'Control',\n 'Mod',\n] as const\nexport type DragModifier = (typeof DRAG_MODIFIERS)[number]\n\n/** Named keys a chord may end on, besides a single character. */\nconst NAMED_KEYS = new Set([\n 'Escape',\n 'Enter',\n 'Tab',\n 'Backspace',\n 'Delete',\n 'Insert',\n 'ArrowUp',\n 'ArrowDown',\n 'ArrowLeft',\n 'ArrowRight',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n 'Space',\n 'CapsLock',\n 'ContextMenu',\n 'Backquote',\n 'Minus',\n 'Equal',\n 'BracketLeft',\n 'BracketRight',\n 'Backslash',\n 'Semicolon',\n 'Quote',\n 'Comma',\n 'Period',\n 'Slash',\n 'NumpadAdd',\n 'NumpadSubtract',\n 'NumpadMultiply',\n 'NumpadDivide',\n 'NumpadDecimal',\n 'NumpadEnter',\n])\n\nconst isModifier = (s: string): s is Modifier =>\n (MODIFIERS as readonly string[]).includes(s)\n\n/** A key name the browser's keyboard answers: a character, a code, a named key. */\nexport function isKeyName(k: string): boolean {\n if ([...k].length === 1) return k.trim().length === 1 || k === ' '\n if (NAMED_KEYS.has(k)) return true\n return (\n /^Key[A-Z]$/.test(k) ||\n /^Digit[0-9]$/.test(k) ||\n /^Numpad[0-9]$/.test(k) ||\n /^F([1-9]|1[0-9]|2[0-4])$/.test(k)\n )\n}\n\n/**\n * A chord split into its modifiers and its key: `Shift+D` is\n * `{ mods: ['Shift'], key: 'D' }`, a bare `r` has no modifiers, and `+`\n * names the plus key when it ends the chord (`Shift++`).\n */\nexport function splitChord(chord: string): { mods: string[]; key: string } {\n if (chord === '+') return { mods: [], key: '+' }\n const plusKey = chord.endsWith('++')\n const parts = (plusKey ? chord.slice(0, -2) : chord).split('+')\n if (plusKey) return { mods: parts, key: '+' }\n const key = parts.pop() ?? ''\n return { mods: parts, key }\n}\n\n/** Why a chord is not one the recorder can press, or null. */\nexport function chordProblem(chord: unknown): string | null {\n if (typeof chord !== 'string' || !chord)\n return 'must be a key name or a chord like \"Shift+D\"'\n const { mods, key } = splitChord(chord)\n for (const m of mods) {\n if (!isModifier(m))\n return `\"${chord}\": \"${m}\" is not a modifier (one of ${MODIFIERS.join(', ')})`\n }\n if (new Set(mods).size !== mods.length)\n return `\"${chord}\" names a modifier twice`\n if (!key) return `\"${chord}\" ends without a key`\n // A modifier alone is a key: Shift pressed and released.\n if (isModifier(key)) {\n if (mods.length) return `\"${chord}\" ends on a modifier, not a key`\n return null\n }\n if (!isKeyName(key))\n return `\"${chord}\": \"${key}\" is not a key (a single character, a named key like Escape or ArrowLeft, F1 to F24, or a code like KeyA or Digit1)`\n return null\n}\n\n/**\n * A chord as the browser's keyboard takes it: `Mod` becomes\n * `ControlOrMeta`, which the browser resolves to Meta on macOS and to\n * Control elsewhere, where the browser runs.\n */\nexport function resolveChord(chord: string): string {\n const { mods, key } = splitChord(chord)\n const k = key === 'Mod' ? 'ControlOrMeta' : key\n return [...mods.map((m) => (m === 'Mod' ? 'ControlOrMeta' : m)), k].join('+')\n}\n\n/** A `press` step's keys as a list: one chord or a sequence. */\nexport function pressSequence(step: {\n key?: string\n keys?: string | string[]\n}): string[] {\n if (step.keys !== undefined)\n return typeof step.keys === 'string' ? [step.keys] : step.keys\n return step.key ? [step.key] : []\n}\n\n/** The pause between two keys of a sequence, a person's hand: ms. */\nexport const KEY_SEQUENCE_GAP_MS = 150\n/**\n * What one key costs beyond the script's gaps: the browser's round trip for\n * the press (a keydown and a keyup the page answers). Part of the plan, so a\n * sequence on an idle page is never \"slower than scripted\".\n */\nexport const KEY_ROUNDTRIP_MS = 50\n\n/** A key sequence's plan, ms: its gaps, and each key's round trip. */\nexport const keySequencePlanMs = (keys: number): number =>\n Math.max(0, keys - 1) * KEY_SEQUENCE_GAP_MS + keys * KEY_ROUNDTRIP_MS\n\n/** The hold after a drag's release, ms: the recorder's, part of the gesture. */\nexport const DRAG_HOLD_MS = 400\n/** The most keys one press step may name. */\nexport const MAX_KEYS = 50\n\n/** A drag modifier as the keyboard holds it. */\nexport function resolveModifier(m: DragModifier): string {\n return m === 'Mod' ? 'ControlOrMeta' : m\n}\n\n/**\n * The modifier bits of a raw pointer event (the pen path): Alt 1, Control\n * 2, Meta 4, Shift 8, with `Mod` read for the platform the browser runs on.\n */\nexport function modifierBits(\n mods: readonly DragModifier[],\n platform: 'mac' | 'linux' | 'windows' | undefined,\n): number {\n let bits = 0\n for (const m of mods) {\n const k = m === 'Mod' ? (platform === 'mac' ? 'Meta' : 'Control') : m\n bits |= k === 'Alt' ? 1 : k === 'Control' ? 2 : k === 'Meta' ? 4 : 8\n }\n return bits\n}\n\n/** A click's button, and the pointer button number the cursor track records. */\nexport const CLICK_BUTTONS = ['left', 'right', 'middle'] as const\nexport type ClickButton = (typeof CLICK_BUTTONS)[number]\nexport const buttonNumber = (b: ClickButton | undefined): 0 | 1 | 2 =>\n b === 'right' ? 2 : b === 'middle' ? 1 : 0\n\n/**\n * The pause between the presses of a double or triple click, well inside\n * every platform's double-click interval (500 ms on macOS and Windows by\n * default), so the page reads one gesture.\n */\nexport const MULTI_CLICK_GAP_MS = 90\n\n/**\n * One point of a drawn path: viewport CSS px, with an optional time in ms\n * (from the path's start) and an optional pressure in [0, 1]. Written as a\n * tuple `[x, y]`, `[x, y, t]`, `[x, y, t, pressure]`, or an object.\n */\nexport type PathPoint =\n | [number, number]\n | [number, number, number]\n | [number, number, number, number]\n | { x: number; y: number; t?: number; pressure?: number }\n\n/** A path point as the recorder replays it. */\nexport interface PathSample {\n x: number\n y: number\n /** ms from the path's first point */\n at: number\n pressure?: number\n}\n\n/** The most points one path may hold. */\nexport const MAX_PATH_POINTS = 20_000\n/** An untimed path's travel when the step names no ms. */\nexport const PATH_DEFAULT_MS = 700\n\nconst finite = (v: unknown): v is number =>\n typeof v === 'number' && Number.isFinite(v)\n\nfunction readPoint(\n raw: unknown,\n): { x: number; y: number; t?: number; pressure?: number } | string {\n if (Array.isArray(raw)) {\n if (raw.length < 2 || raw.length > 4)\n return 'must be [x, y], [x, y, tMs] or [x, y, tMs, pressure]'\n const [x, y, t, pressure] = raw as unknown[]\n if (!finite(x) || !finite(y)) return 'x and y must be numbers (CSS px)'\n if (t !== undefined && !finite(t)) return 'its time must be a number of ms'\n if (pressure !== undefined && !finite(pressure))\n return 'its pressure must be a number from 0 to 1'\n return {\n x,\n y,\n ...(t !== undefined ? { t } : {}),\n ...(pressure !== undefined ? { pressure } : {}),\n }\n }\n if (typeof raw === 'object' && raw !== null) {\n const o = raw as Record<string, unknown>\n const extra = Object.keys(o).filter(\n (k) => !['x', 'y', 't', 'pressure'].includes(k),\n )\n if (extra.length)\n return `takes x, y, t and pressure, not ${extra.join(', ')}`\n if (!finite(o.x) || !finite(o.y)) return 'x and y must be numbers (CSS px)'\n if (o.t !== undefined && !finite(o.t)) return 'its t must be a number of ms'\n if (o.pressure !== undefined && !finite(o.pressure))\n return 'its pressure must be a number from 0 to 1'\n return {\n x: o.x,\n y: o.y,\n ...(o.t !== undefined ? { t: o.t as number } : {}),\n ...(o.pressure !== undefined ? { pressure: o.pressure as number } : {}),\n }\n }\n return 'must be [x, y] or { x, y }'\n}\n\n/**\n * A path's points read and checked, or the problems in words. The same\n * reader takes an inline `path` and the contents of a path file (an array\n * of points, or `{ \"points\": [...] }`).\n */\nexport function readPath(\n raw: unknown,\n): { points: PathSample[]; timed: boolean } | { problems: string[] } {\n const list =\n typeof raw === 'object' &&\n raw !== null &&\n !Array.isArray(raw) &&\n Array.isArray((raw as { points?: unknown }).points)\n ? (raw as { points: unknown[] }).points\n : raw\n if (!Array.isArray(list))\n return { problems: ['must be an array of points, or { \"points\": [...] }'] }\n if (list.length < 2) return { problems: ['needs at least two points'] }\n if (list.length > MAX_PATH_POINTS)\n return { problems: [`holds more than ${MAX_PATH_POINTS} points`] }\n const problems: string[] = []\n const read: { x: number; y: number; t?: number; pressure?: number }[] = []\n list.forEach((p, i) => {\n const r = readPoint(p)\n if (typeof r === 'string') problems.push(`point ${i} ${r}`)\n else {\n if (r.x < 0 || r.y < 0)\n problems.push(`point ${i} is off the viewport (x and y are ≥ 0)`)\n if (r.pressure !== undefined && (r.pressure < 0 || r.pressure > 1))\n problems.push(`point ${i} pressure must be from 0 to 1`)\n read.push(r)\n }\n })\n if (problems.length) return { problems: problems.slice(0, 5) }\n const timedCount = read.filter((p) => p.t !== undefined).length\n if (timedCount !== 0 && timedCount !== read.length)\n return {\n problems: [\n 'every point carries a time or none does: a path is replayed by its own timing, or evenly over ms',\n ],\n }\n const timed = timedCount > 0\n if (timed) {\n for (let i = 1; i < read.length; i++)\n if ((read[i].t as number) < (read[i - 1].t as number))\n return {\n problems: [`point ${i}'s time runs backwards (times never decrease)`],\n }\n }\n const t0 = timed ? (read[0].t as number) : 0\n return {\n timed,\n points: read.map((p) => ({\n x: p.x,\n y: p.y,\n at: timed ? (p.t as number) - t0 : 0,\n ...(p.pressure !== undefined ? { pressure: p.pressure } : {}),\n })),\n }\n}\n\n/**\n * The path's schedule: a timed path keeps its own times (from its first\n * point), an untimed one spreads its points evenly over `ms` (default\n * 700). The last point is at the path's whole duration.\n */\nexport function schedulePath(\n path: { points: PathSample[]; timed: boolean },\n ms: number | undefined,\n): PathSample[] {\n if (path.timed) return path.points\n const dur = ms ?? PATH_DEFAULT_MS\n const n = path.points.length\n return path.points.map((p, i) => ({\n ...p,\n at: n > 1 ? Math.round((dur * i) / (n - 1)) : 0,\n }))\n}\n\n/** How long a scheduled path takes, ms. */\nexport const pathDurationMs = (s: readonly PathSample[]): number =>\n s.length ? s[s.length - 1].at : 0\n\n/**\n * A paced gesture that ran past its script: the wall time it took against\n * the time the script planned for it (a drag's travel, a path's timing,\n * typing's characters × delay, a key sequence's gaps). Reported when the\n * gesture took more than a fifth longer, the sign of a page that could not\n * keep up with what it was sent.\n */\nexport interface StepOverrun {\n step: number\n id?: string\n do: string\n plannedMs: number\n tookMs: number\n overrunMs: number\n}\n\n/** The share past the plan that counts as an overrun. */\nexport const OVERRUN_SHARE = 0.2\n/** A plan shorter than this is not measured: its noise is the round trip. */\nexport const OVERRUN_MIN_PLANNED_MS = 100\n/**\n * The least a gesture must run over to count, ms: below it the difference\n * is one slow sample or round trip on a busy machine, never a page that\n * fell behind, however short the gesture.\n */\nexport const OVERRUN_MIN_MS = 100\n\n/** The overrun, ms, or null when the gesture kept to its plan. */\nexport function overrunOf(plannedMs: number, tookMs: number): number | null {\n if (!(plannedMs >= OVERRUN_MIN_PLANNED_MS)) return null\n if (tookMs <= plannedMs * (1 + OVERRUN_SHARE)) return null\n if (tookMs - plannedMs < OVERRUN_MIN_MS) return null\n return Math.round(tookMs - plannedMs)\n}\n\n/** The overruns in one line for the log and the done event, or null when none. */\nexport function overrunLine(overruns: readonly StepOverrun[]): string | null {\n if (!overruns.length) return null\n const planned = overruns.reduce((a, o) => a + o.plannedMs, 0)\n const took = overruns.reduce((a, o) => a + o.tookMs, 0)\n const ratio = planned > 0 ? took / planned : 0\n const n = overruns.length\n const which = overruns\n .map((o) => `#${o.step}${o.id ? ` (${o.id})` : ''} ${o.do}`)\n .join(', ')\n return `${n} step${n === 1 ? '' : 's'} ran ${ratio.toFixed(1)}× slower than scripted (${which}): the page could not keep up; add settle or raise ms`\n}\n","/**\n * The `paste` step, the pure parts: what a file is pasted as, and the two\n * page scripts that put an item where a person's ⌘V finds it.\n *\n * The first rung is the browser's own clipboard: the item is written with\n * `navigator.clipboard.write` (the context is granted clipboard access\n * first), and the recorder then presses the platform's paste chord, so the\n * page receives a TRUSTED keydown and a trusted `paste` event carrying the\n * item, and a page that reads `navigator.clipboard.read()` itself sees it\n * there too. A headless browser keeps its own clipboard, so nothing on the\n * machine's clipboard is touched.\n *\n * When the browser refuses the write (no clipboard access on this driver,\n * a type it will not hold), the second rung dispatches the paste in the\n * page: a `paste` event with a `DataTransfer` holding the item on the\n * focused element, and `navigator.clipboard.read`/`readText` answering the\n * item for the rest of the take. Those events are untrusted, which the\n * recorder says.\n *\n * Both scripts are strings, the one evaluate shape every driver shares,\n * and neither carries anything the cursor track keeps: a paste is a typing\n * ping, never its contents.\n */\n\n/** How long after a dispatched paste is first read its item stays on the async reads, ms. */\nexport const PASTE_READ_WINDOW_MS = 300\n/** How long a dispatched paste's item stays on the async reads when nothing reads it, ms. */\nexport const PASTE_UNREAD_MS = 3000\n\n/** The most bytes a pasted file may hold. */\nexport const PASTE_MAX_BYTES = 10 * 1024 * 1024\n\n/** The file types a paste takes, by extension. */\nexport const PASTE_TYPES: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.webp': 'image/webp',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.txt': 'text/plain',\n '.md': 'text/plain',\n '.html': 'text/html',\n '.htm': 'text/html',\n '.json': 'text/plain',\n '.csv': 'text/plain',\n}\n\n/** A pasted file's type from its name, or null when a paste does not take it. */\nexport function pasteTypeOf(name: string): string | null {\n const dot = name.lastIndexOf('.')\n if (dot < 0) return null\n return PASTE_TYPES[name.slice(dot).toLowerCase()] ?? null\n}\n\n/** What a paste puts on the clipboard: words, or a file's bytes (base64) with its type and name. */\nexport interface PasteItem {\n text?: string\n b64?: string\n type?: string\n name?: string\n}\n\n/**\n * The page script that builds the item's blobs: an image other than PNG\n * is redrawn as PNG for the clipboard (the one image type every browser\n * holds) and an SVG rides as its markup too, so an app that reads text\n * finds it. Shared by both rungs.\n */\nconst BUILD = (item: PasteItem) => `\n const item = ${JSON.stringify(item)};\n const bytes = item.b64 ? Uint8Array.from(atob(item.b64), (c) => c.charCodeAt(0)) : null;\n const asText = bytes ? new TextDecoder().decode(bytes) : null;\n async function blobs() {\n if (item.text !== undefined) return { 'text/plain': new Blob([item.text], { type: 'text/plain' }) };\n const type = item.type;\n if (type === 'text/plain') return { 'text/plain': new Blob([asText], { type }) };\n if (type === 'text/html') return { 'text/html': new Blob([asText], { type }), 'text/plain': new Blob([asText], { type: 'text/plain' }) };\n if (type === 'image/svg+xml') return { 'image/svg+xml': new Blob([bytes], { type }), 'text/plain': new Blob([asText], { type: 'text/plain' }) };\n if (type === 'image/png') return { 'image/png': new Blob([bytes], { type }) };\n const bmp = await createImageBitmap(new Blob([bytes], { type }));\n const c = document.createElement('canvas');\n c.width = bmp.width; c.height = bmp.height;\n c.getContext('2d').drawImage(bmp, 0, 0);\n const png = await new Promise((r) => c.toBlob(r, 'image/png'));\n return { 'image/png': png };\n }\n`\n\n/**\n * Rung one: write the item to the browser's clipboard. Answers 'ok', or\n * 'refused: <why>'. An SVG the clipboard will not hold as an image is\n * written as its markup alone.\n */\nexport function stageClipboardScript(item: PasteItem): string {\n return `(async () => {\n ${BUILD(item)}\n try {\n if (!navigator.clipboard || typeof ClipboardItem === 'undefined') return 'refused: this page has no clipboard';\n const b = await blobs();\n try {\n await navigator.clipboard.write([new ClipboardItem(b)]);\n } catch (e) {\n if (!b['text/plain'] || Object.keys(b).length === 1) throw e;\n await navigator.clipboard.write([new ClipboardItem({ 'text/plain': b['text/plain'] })]);\n }\n return 'ok';\n } catch (e) {\n return 'refused: ' + (e && e.message ? e.message : String(e));\n }\n})()`\n}\n\n/**\n * Rung two: the paste dispatched in the page, on the focused element (or\n * the body), with the item in its `clipboardData`; and the async clipboard\n * reads answer the item from here on. A plain field the page did not take\n * the paste for gets the words inserted, as the browser's own paste does.\n * Answers 'ok', or 'failed: <why>'.\n */\nexport function syntheticPasteScript(\n item: PasteItem,\n opts: { original?: boolean } = {},\n): string {\n return `(async () => {\n ${BUILD(item)}\n try {\n // With original, an image file is handed over as its own bytes and type\n // (an SVG also as its markup), never redrawn.\n const b = ${opts.original ? `item.type === 'image/svg+xml' ? { 'image/svg+xml': new Blob([bytes], { type: item.type }), 'text/plain': new Blob([asText], { type: 'text/plain' }) } : { [item.type]: new Blob([bytes], { type: item.type }) }` : 'await blobs()'};\n const dt = new DataTransfer();\n let file = null;\n for (const [type, blob] of Object.entries(b)) {\n if (type.startsWith('image/')) {\n file = new File([blob], item.name || 'image.png', { type: blob.type || type });\n dt.items.add(file);\n } else dt.setData(type, await blob.text());\n }\n try {\n // The async reads answer the item for THIS paste only: shortly after\n // the first read (an app may read text and items in turn), or after a\n // few seconds when nothing reads, the browser's own reads come back,\n // so a later paste through the clipboard is the clipboard's.\n const staged = [new ClipboardItem(b)];\n const clip = navigator.clipboard;\n const own = { read: Object.prototype.hasOwnProperty.call(clip, 'read'), readText: Object.prototype.hasOwnProperty.call(clip, 'readText') };\n const was = { read: clip.read, readText: clip.readText };\n let restored = false;\n const restore = () => {\n if (restored) return;\n restored = true;\n for (const k of ['read', 'readText']) {\n if (own[k]) clip[k] = was[k];\n else delete clip[k];\n }\n };\n let soon = null;\n const readOnce = () => { if (!soon) soon = setTimeout(restore, ${PASTE_READ_WINDOW_MS}) };\n clip.read = async () => { readOnce(); return staged };\n clip.readText = async () => { readOnce(); return b['text/plain'] ? b['text/plain'].text() : '' };\n setTimeout(restore, ${PASTE_UNREAD_MS});\n } catch {}\n const target = document.activeElement || document.body;\n const ev = new ClipboardEvent('paste', { clipboardData: dt, bubbles: true, cancelable: true, composed: true });\n const taken = !target.dispatchEvent(ev);\n const words = dt.getData('text/plain');\n if (!taken && words && (target.isContentEditable || /^(INPUT|TEXTAREA)$/.test(target.tagName)))\n document.execCommand('insertText', false, words);\n return 'ok';\n } catch (e) {\n return 'failed: ' + (e && e.message ? e.message : String(e));\n }\n})()`\n}\n","/**\n * A gesture that waits on the app (`settle`): after the gesture, the\n * recorder waits until the page has made no DOM change and painted no new\n * frame for a beat, at most a few seconds. A heavy canvas falls behind\n * under load, and a script paced by the wall clock then outruns it: the\n * next stroke is drawn before the app has processed the last one.\n *\n * The DOM half is the recorder's one DOM-settle reader (`domSettled`, the\n * same an `await`'s reload lets the page finish with). The paint half is\n * the screencast: it emits a frame only when the compositor painted\n * something new, a canvas redrawn by `requestAnimationFrame` included, and\n * it is read from here rather than by an animation frame in the page,\n * which a background tab never fires. The two are one count: the page's\n * DOM changes plus the frames captured so far. A rehearsal captures no\n * frames, so there it waits on the DOM alone.\n */\nimport type { RecorderPage } from './driver'\nimport { domSettled } from './waits'\n\n/** The quiet a settle waits for: no DOM change and no new frame, ms. */\nexport const APP_QUIET_MS = 300\n/** The longest a settle waits on a page that never stops changing, ms. */\nexport const APP_SETTLE_CAP_MS = 4000\n\n/** The verbs a settle follows: the ones that send the page input. */\nexport const SETTLE_VERBS = new Set([\n 'hover',\n 'click',\n 'type',\n 'press',\n 'scroll',\n 'move',\n 'drag',\n 'paste',\n])\n\n/**\n * How long ago the page last changed its DOM, in ms by the page's own clock,\n * or -1 when this is the first look at this document (the reader is\n * installed now and knows no history). A string, the one evaluate shape\n * every driver shares.\n */\nexport const CHANGE_AGE_PROBE = `(() => {\n const w = window;\n if (!w.__vosChangeAt) {\n w.__vosChangeAt = { at: Date.now() };\n new MutationObserver(() => { w.__vosChangeAt.at = Date.now() })\n .observe(document, { subtree: true, childList: true, attributes: true, characterData: true });\n return -1;\n }\n return Date.now() - w.__vosChangeAt.at;\n})()`\n\n/** Whether a step waits on the app after its gesture: its own `settle`, else the script's. */\nexport function settleOn(\n step: { do: string; settle?: boolean },\n scriptDefault: boolean | undefined,\n): boolean {\n if (!SETTLE_VERBS.has(step.do)) return false\n return step.settle ?? scriptDefault ?? false\n}\n\n/**\n * Wait for the app: no DOM change and no new captured frame for `quietMs`,\n * at most `capMs`. `frames` reads how many frames the capture has kept.\n */\nexport async function appSettled(\n page: Pick<RecorderPage, 'evaluate'>,\n frames: () => number,\n opts: {\n sleep: (ms: number) => Promise<void>\n now?: () => number\n quietMs?: number\n capMs?: number\n /** ms since the last captured frame, or null when none was captured */\n sinceFrame?: () => number | null\n },\n): Promise<{ settled: boolean; ms: number }> {\n const quiet = opts.quietMs ?? APP_QUIET_MS\n // Already still: the page's last DOM change and the last frame are both\n // older than the quiet window, so there is nothing to wait for. The\n // window is counted from the last change, never from the settle's start.\n const age = await page.evaluate<number>(CHANGE_AGE_PROBE).catch(() => -1)\n const frameAge = opts.sinceFrame?.() ?? null\n if (\n typeof age === 'number' &&\n age >= quiet &&\n (frameAge === null || frameAge >= quiet)\n )\n return { settled: true, ms: 0 }\n // The DOM reader polls the page's change count; this hands it the count\n // with the frames added, so a paint is a change like a mutation is.\n const counted = {\n evaluate: async (script: string) => {\n const n = await page.evaluate<number>(script).catch(() => 0)\n return (typeof n === 'number' && n > 0 ? n : 0) + frames()\n },\n } as unknown as RecorderPage\n return domSettled(counted, {\n sleep: opts.sleep,\n ...(opts.now ? { now: opts.now } : {}),\n quietMs: quiet,\n capMs: opts.capMs ?? APP_SETTLE_CAP_MS,\n tickMs: 50,\n })\n}\n","/**\n * `peers`: other people on the same page, off camera. A collaboration\n * product shows best with a second person on the canvas: their cursor, the\n * shape they drew, the comment they left, arriving in the filmed page the\n * way the app syncs them. A peer is a second browser context (its own\n * cookies, so its own user, from its own storage state or none) on the\n * same URL, driven by its own step list, interleaved with the take's.\n *\n * What a peer is, and is not:\n *\n * - NOT FILMED. Only the take's own page is captured. A peer's page is\n * never screencast, scanned, masked or listened to; what it does reaches\n * the footage only through the app (its sync, its presence, its remote\n * cursors), which is what a viewer would see.\n * - NOT ON THE CURSOR TRACK. A peer's pointer moves its own page; the take's\n * CursorTrack is synthesized from the take's own steps alone, so a zoom,\n * a click ring or a dwell is never planned on a peer's gesture.\n * - ORDERED BY THE TAKE'S STEPS. A peer step may name a take step by id:\n * `with` starts it as that step starts (the two run together), `after` as\n * that step ends. A step naming neither follows the peer's previous step\n * at once; a peer's first step with neither starts as the camera rolls.\n * The take never waits on a peer: it waits on what the peer's work\n * SHOWS, with an `expect` or an `await` on its own page, so the footage\n * holds exactly the moment the sync landed. When the take's steps end,\n * a peer step still waiting on a trigger never runs (said), and one\n * already running finishes, bounded, before the trailing hold.\n * - PACED, NOT INSTANT. A peer's pointer glides on the same clock as the\n * take's (an app that draws remote cursors shows it travelling) and its\n * typing is paced per key, so what it does reads as a person.\n * - BOUNDED. Every peer step runs inside its own bound, as a take step\n * does; a selector that never appears or a check that never holds is a\n * skip with its reason, listed with the take's (`--strict` fails on it).\n *\n * A peer takes the take's gestures and checks (`wait`, `move`, `hover`,\n * `click`, `type`, `press`, `scroll`, `drag` with an inline `path`, and\n * `expect`), never a `paste`, a `download`, an `await` (a peer that must\n * wait for a result is the take's `await`), a guard, a `read`, a `caption`\n * or `settle`, which all belong to the filmed page.\n */\nimport type { ActionStep } from './actions'\nimport type { RecorderClock, RecorderPage } from './driver'\nimport {\n DRAG_HOLD_MS,\n KEY_SEQUENCE_GAP_MS,\n MULTI_CLICK_GAP_MS,\n pressSequence,\n readPath,\n resolveChord,\n resolveModifier,\n schedulePath,\n} from './gestures'\nimport type { ClickButton, DragModifier } from './gestures'\nimport {\n PRESS_HOLD_MS,\n PRESS_LEAD_MS,\n SETTLE_MS,\n askedMs,\n clockMotion,\n clockTyping,\n pointerTravelMs,\n} from './pace'\nimport { StepBound, bounded, stepBoundMs } from './stepBound'\nimport { conditionMiss, pollCondition, sayCondition } from './waits'\nimport type { ConditionState, WaitCondition } from './waits'\nimport { urlSchemeProblem } from './setup'\nimport type { PeerStepSpan } from '@vosjs/studio-core'\n\n/** One other person on the page: their own context, their own steps. */\nexport interface Peer {\n /** How the peer is named in lines and in `meta.peers`: a short word. */\n id: string\n /** The page the peer opens; absent, the take's own `url`. */\n url?: string\n /** The peer's viewport in CSS px; absent, the take's. */\n viewport?: { width: number; height: number }\n /**\n * A Playwright storage state the peer's context is made from: the second\n * person's own sign-in. The host resolves the name (the CLI: a path from\n * the actions file's directory) and never sends the file anywhere.\n * Absent, the peer is signed out.\n */\n storageState?: string\n steps: PeerStep[]\n}\n\n/** A peer's step: one of the take's gestures or checks, and when it starts. */\nexport type PeerStep = ActionStep & {\n /**\n * Start as the take's step with this id starts: the two run together.\n * (`with`, never `at`: a `type` step's `at` is where its caret goes.)\n */\n with?: string\n /** Start as the take's step with this id ends. */\n after?: string\n}\n\n/** The verbs a peer takes: the gestures and the on-page check. */\nexport const PEER_VERBS = [\n 'wait',\n 'move',\n 'hover',\n 'click',\n 'type',\n 'press',\n 'scroll',\n 'drag',\n 'expect',\n] as const\n\n/** The most peers a take may have: each is a whole browser context. */\nexport const MAX_PEERS = 4\n/** The most steps one peer may take. */\nexport const MAX_PEER_STEPS = 200\n\n/** Fields a take step carries that a peer's never does, and why. */\nconst TAKE_ONLY: Record<string, string> = {\n guard: 'a guard is pressed only on the filmed page, under --confirm',\n read: 'read keeps words from the filmed page',\n caption: 'a caption is a beat of the film, which is the take’s',\n settle: 'settle reads the filmed page’s frames',\n zoom: 'a zoom mark picks a moment on the cursor track, and a peer is never on it',\n}\n\nconst PEER_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/\n\n/**\n * Structural validation of `peers`, given the take's own steps (a trigger\n * names one of their ids). `validate` is the take's step validator, run on\n * each peer's list so a peer step is checked in exactly the take's words.\n */\nexport function validatePeers(\n value: unknown,\n takeSteps: unknown,\n validate: (steps: unknown[]) => string[],\n): string[] {\n if (!Array.isArray(value))\n return [\n 'peers must be an array of { id, url?, viewport?, storageState?, steps }',\n ]\n const errors: string[] = []\n if (value.length > MAX_PEERS)\n errors.push(\n `peers names ${value.length} peers; a take holds at most ${MAX_PEERS} (each is a whole browser)`,\n )\n const takeIds = new Set(\n (Array.isArray(takeSteps) ? takeSteps : [])\n .map((s) => (s as { id?: unknown } | null)?.id)\n .filter((id): id is string => typeof id === 'string'),\n )\n const seen = new Set<string>()\n value.forEach((raw, i) => {\n const at = `peers[${i}]`\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n errors.push(`${at}: must be an object`)\n return\n }\n const p = raw as Record<string, unknown>\n if (typeof p.id !== 'string' || !PEER_ID.test(p.id))\n errors.push(\n `${at}: id must be a short word (letters, digits, - and _, at most 32), which lines and meta.peers name the peer by`,\n )\n else if (seen.has(p.id)) errors.push(`${at}: duplicate peer id \"${p.id}\"`)\n else seen.add(p.id)\n if (p.url !== undefined) {\n if (typeof p.url !== 'string') errors.push(`${at}: url must be a string`)\n else {\n const problem = urlSchemeProblem(p.url)\n if (problem) errors.push(`${at}: url ${problem}`)\n }\n }\n if (p.viewport !== undefined) {\n const v = p.viewport as Record<string, unknown> | null\n if (\n typeof v !== 'object' ||\n v === null ||\n typeof v.width !== 'number' ||\n typeof v.height !== 'number'\n )\n errors.push(`${at}: viewport must be { width, height }`)\n }\n if (\n p.storageState !== undefined &&\n (typeof p.storageState !== 'string' || !p.storageState.trim())\n )\n errors.push(\n `${at}: storageState must name a Playwright storage state file (the second person's sign-in)`,\n )\n for (const k of Object.keys(p))\n if (!['id', 'url', 'viewport', 'storageState', 'steps'].includes(k))\n errors.push(\n `${at}: a peer takes id, url, viewport, storageState and steps, not ${k}`,\n )\n if (!Array.isArray(p.steps) || p.steps.length === 0) {\n errors.push(`${at}: steps must be a non-empty array`)\n return\n }\n if (p.steps.length > MAX_PEER_STEPS)\n errors.push(\n `${at}: steps holds ${p.steps.length} steps; a peer takes at most ${MAX_PEER_STEPS}`,\n )\n const steps = p.steps as unknown[]\n steps.forEach((rawStep, j) => {\n const sat = `${at}.steps[${j}]`\n if (typeof rawStep !== 'object' || rawStep === null) return\n const s = rawStep as Record<string, unknown>\n if (\n typeof s.do === 'string' &&\n !(PEER_VERBS as readonly string[]).includes(s.do)\n )\n errors.push(\n `${sat}: a peer step is one of ${PEER_VERBS.join(', ')}; ${/^[aeiou]/.test(s.do) ? 'an' : 'a'} ${s.do} belongs to the filmed page${s.do === 'await' ? ' (wait for what the peer did with the take’s own await or expect)' : ''}`,\n )\n for (const [k, why] of Object.entries(TAKE_ONLY))\n if (s[k] !== undefined)\n errors.push(`${sat}: no ${k} on a peer step: ${why}`)\n if (s.do === 'drag' && typeof s.path === 'string')\n errors.push(\n `${sat}: a peer draws its path inline (an array of points), never from a file`,\n )\n if (s.with !== undefined && s.after !== undefined)\n errors.push(\n `${sat}: with or after, not both (with starts as the take's step starts, after once it ends)`,\n )\n for (const k of ['with', 'after'] as const) {\n const v = s[k]\n if (v === undefined) continue\n if (typeof v !== 'string' || !v.trim())\n errors.push(`${sat}: ${k} must name a take step by its id`)\n else if (!takeIds.has(v))\n errors.push(\n `${sat}: ${k} \"${v}\" names no take step (the take's steps with ids: ${takeIds.size ? [...takeIds].join(', ') : 'none'}); give the take step an id`,\n )\n }\n })\n for (const e of validate(steps))\n errors.push(e.replace(/^steps\\[/, `${at}.steps[`))\n })\n return errors\n}\n\n/** What a hosted recorder says of a script with peers, or null. */\nexport function peersHostedRefusal(peers: unknown): string | null {\n if (!Array.isArray(peers) || !peers.length) return null\n return 'the script has peers (more browsers on the page, off camera), and a hosted take runs one browser: record it on this machine'\n}\n\n/**\n * The take's step boundaries, as promises a peer step waits on. The take\n * calls `begin` as the camera rolls, `start`/`end` around each step and\n * `close` once its steps are over; a trigger still pending then resolves\n * false and its step never runs.\n */\nexport class StepSignals {\n private readonly started = new Map<string, Deferred>()\n private readonly ended = new Map<string, Deferred>()\n private readonly began = deferred()\n private closed = false\n\n constructor(ids: Iterable<string>) {\n for (const id of ids) {\n this.started.set(id, deferred())\n this.ended.set(id, deferred())\n }\n }\n\n begin(): void {\n this.began.resolve(true)\n }\n\n start(id: string | undefined): void {\n if (id) this.started.get(id)?.resolve(true)\n }\n\n end(id: string | undefined): void {\n if (id) this.ended.get(id)?.resolve(true)\n }\n\n close(): void {\n this.closed = true\n this.began.resolve(false)\n for (const d of [...this.started.values(), ...this.ended.values()])\n d.resolve(false)\n }\n\n get isClosed(): boolean {\n return this.closed\n }\n\n /** When a step with this trigger may start: true, or false for never. */\n when(trigger: { with?: string; after?: string }): {\n ready: Promise<boolean>\n already: boolean\n } {\n const d = trigger.with\n ? this.started.get(trigger.with)\n : trigger.after\n ? this.ended.get(trigger.after)\n : this.began\n if (!d) return { ready: Promise.resolve(false), already: false }\n return { ready: d.promise, already: d.settled }\n }\n}\n\ninterface Deferred {\n promise: Promise<boolean>\n resolve: (v: boolean) => void\n settled: boolean\n}\n\nfunction deferred(): Deferred {\n let resolve: (v: boolean) => void = () => {}\n const d: Deferred = {\n promise: new Promise<boolean>((r) => {\n resolve = r\n }),\n resolve: (v) => {\n if (d.settled) return\n d.settled = true\n resolve(v)\n },\n settled: false,\n }\n return d\n}\n\n/** One peer step as it ran, in the take's footage seconds. */\nexport type { PeerStepSpan } from '@vosjs/studio-core'\n\n/** The most a peer step's kept value holds, in characters of JSON (as a take step's). */\nexport const PEER_VALUE_MAX = 2048\n\n/**\n * What a peer's check last answered, kept on its step the way the take's\n * own steps keep theirs (`meta.steps[].value`): the value itself while its\n * JSON fits, else that JSON cut short as a string; absent when the read\n * answered nothing JSON can hold, or no value at all (a check that only\n * holds or not).\n */\nexport function peerValue(last: ConditionState): unknown {\n if (!('value' in last)) return undefined\n const value = (last as { value?: unknown }).value\n const json = JSON.stringify(value)\n if (json === undefined) return undefined\n return json.length <= PEER_VALUE_MAX\n ? value\n : `${json.slice(0, PEER_VALUE_MAX - 1)}…`\n}\n\n/** What a peer did: its steps as they ran, and the ones that never did. */\nexport interface PeerRun {\n id: string\n steps: PeerStepSpan[]\n /** Steps whose trigger never fired before the take's steps were over. */\n notRun: number[]\n}\n\n/** A selector's centre, or a viewport point. */\ntype Spot = { x: number; y: number }\n\nconst EXPECT_TIMEOUT_S = 5\nconst EXPECT_EVERY_MS = 150\n\n/**\n * Drive one peer's steps on its page, each when its trigger fires. Never\n * throws for a page's reasons: a miss is a skip on the run.\n */\nexport async function runPeer(\n peer: Peer,\n rawPage: RecorderPage,\n signals: StepSignals,\n opts: {\n clock: RecorderClock\n /** The take's footage clock, ms: what a span is placed by. */\n footageMs: () => number\n log: (msg: string) => void\n /** A rehearsal: no travel, every pause cut short. */\n dry?: boolean\n },\n): Promise<PeerRun> {\n const bound = new StepBound()\n const page = bounded(rawPage, bound)\n const { clock, log } = opts\n const run: PeerRun = { id: peer.id, steps: [], notRun: [] }\n const cur = { x: 24, y: 24 }\n const moveTo = async (tx: number, ty: number) => {\n const from = { ...cur }\n const dist = Math.hypot(tx - from.x, ty - from.y)\n await clockMotion(\n opts.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 },\n clock,\n )\n }\n const spotOf = async (s: {\n selector?: string\n x?: number\n y?: number\n }): Promise<Spot | null> => {\n if (s.selector === undefined) return { x: s.x ?? cur.x, y: s.y ?? cur.y }\n const loc = page.locator(s.selector).first()\n try {\n await loc.waitFor({ state: 'visible', timeout: 8000 })\n await loc.scrollIntoViewIfNeeded()\n const bb = await loc.boundingBox()\n return bb ? { x: bb.x + bb.width / 2, y: bb.y + bb.height / 2 } : null\n } catch {\n return null\n }\n }\n const press = async (how: {\n count?: number\n button?: ClickButton\n modifiers?: DragModifier[]\n }) => {\n const held: string[] = []\n try {\n for (const m of how.modifiers ?? []) {\n const key = resolveModifier(m)\n await page.keyboard.down(key)\n held.push(key)\n }\n await clock.sleep(PRESS_LEAD_MS)\n const count = how.count ?? 1\n for (let n = 1; n <= count; n++) {\n if (n > 1) await clock.sleep(MULTI_CLICK_GAP_MS)\n const o = {\n ...(how.button && how.button !== 'left'\n ? { button: how.button }\n : {}),\n ...(n > 1 ? { clickCount: n } : {}),\n }\n const has = Object.keys(o).length > 0\n await (has ? page.mouse.down(o) : page.mouse.down())\n await clock.sleep(PRESS_HOLD_MS)\n await (has ? page.mouse.up(o) : page.mouse.up())\n }\n } finally {\n for (const key of held.reverse())\n await page.keyboard.up(key).catch(() => undefined)\n }\n }\n\n for (const [i, step] of peer.steps.entries()) {\n const tag = `peer ${peer.id} #${i}${step.id ? ` ${step.id}` : ''}`\n const trigger = signals.when(step)\n const go = await trigger.ready\n if (!go) {\n run.notRun = peer.steps.slice(i).map((_, k) => i + k)\n log(\n ` (${tag} ${step.do}: not run: ${step.with ? `the take's step ${step.with} never started` : step.after ? `the take's step ${step.after} never ended` : 'the take ended first'})`,\n )\n break\n }\n const late =\n (step.with !== undefined || step.after !== undefined) && trigger.already\n const tStart = opts.footageMs()\n let selector: string | undefined\n let reason: string | null = null\n let value: unknown\n bound.start(\n stepBoundMs(\n step as Parameters<typeof stepBoundMs>[0],\n askedMs(step as Parameters<typeof askedMs>[0]),\n { expectS: EXPECT_TIMEOUT_S, awaitS: 0, downloadS: 0 },\n ),\n )\n try {\n switch (step.do) {\n case 'wait':\n await clock.sleep(step.ms)\n break\n case 'move':\n await moveTo(step.x, step.y)\n break\n case 'hover': {\n selector = step.selector\n const spot = await spotOf(step)\n if (!spot) reason = `'${step.selector}' never appeared`\n else {\n await moveTo(spot.x, spot.y)\n await clock.sleep(step.ms ?? 700)\n }\n break\n }\n case 'click': {\n selector = step.selector\n const spot = await spotOf(step)\n if (!spot) {\n reason = `'${step.selector}' never appeared`\n break\n }\n await moveTo(spot.x, spot.y)\n await press(step)\n await clock.sleep(step.ms ?? SETTLE_MS.click)\n break\n }\n case 'type': {\n selector = step.selector\n if (step.focus !== false) {\n const spot = await spotOf(step)\n if (!spot) {\n reason = `'${step.selector}' never appeared`\n break\n }\n await moveTo(spot.x, spot.y)\n await press({})\n }\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 await clockTyping(\n [...step.text],\n opts.dry ? 0 : (step.delayMs ?? 40),\n (ch) => page.keyboard.type(ch),\n clock,\n )\n await clock.sleep(step.ms ?? SETTLE_MS.type)\n break\n }\n case 'press': {\n selector = step.selector\n if (step.selector !== undefined) {\n const spot = await spotOf(step)\n if (!spot) {\n reason = `'${step.selector}' never appeared`\n break\n }\n }\n const keys = pressSequence(step)\n for (const [k, key] of keys.entries()) {\n if (k > 0) await clock.sleep(KEY_SEQUENCE_GAP_MS)\n await page.keyboard.press(resolveChord(key))\n }\n await clock.sleep(step.ms ?? SETTLE_MS.press)\n break\n }\n case 'scroll':\n await page.mouse.wheel(0, step.dy)\n await clock.sleep(step.ms ?? 200)\n break\n case 'drag': {\n selector = step.selector\n const read = step.path !== undefined ? readPath(step.path) : null\n if (read && 'problems' in read) {\n reason = `its path ${read.problems.join('; ')}`\n break\n }\n const held: string[] = []\n try {\n if (read) {\n const sched = schedulePath(read, step.ms)\n await moveTo(sched[0].x, sched[0].y)\n for (const m of step.modifiers ?? []) {\n const key = resolveModifier(m)\n await page.keyboard.down(key)\n held.push(key)\n }\n await page.mouse.down()\n const t0 = clock.now()\n for (const p of sched.slice(1)) {\n const wait = t0 + (opts.dry ? 0 : p.at) - clock.now()\n if (wait > 0) await clock.sleep(wait)\n cur.x = p.x\n cur.y = p.y\n await page.mouse.move(p.x, p.y)\n }\n } else {\n const start = await spotOf(step)\n if (!start) {\n reason = `'${step.selector}' never appeared`\n break\n }\n await moveTo(start.x, start.y)\n for (const m of step.modifiers ?? []) {\n const key = resolveModifier(m)\n await page.keyboard.down(key)\n held.push(key)\n }\n await page.mouse.down()\n const from = { ...cur }\n const tx = step.tx as number\n const ty = step.ty as number\n await clockMotion(\n opts.dry ? 0 : (step.ms ?? 700),\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 },\n clock,\n )\n }\n await page.mouse.up()\n } finally {\n for (const key of held.reverse())\n await page.keyboard.up(key).catch(() => undefined)\n }\n await clock.sleep(DRAG_HOLD_MS)\n break\n }\n case 'expect': {\n const cond: WaitCondition = step\n selector = step.selector ?? step.gone\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: clock.sleep,\n })\n value = peerValue(res.last)\n if (!res.ok) reason = conditionMiss(cond, res.last, timeoutMs)\n else log(` ${tag} expect ${sayCondition(cond)}: holds`)\n break\n }\n default:\n reason = `a peer does not ${step.do}`\n }\n } catch (e) {\n reason = e instanceof Error ? e.message.split('\\n')[0] : String(e)\n }\n const hang = bound.end()\n if (hang.hung)\n reason = `the page stopped answering: this ${step.do} ran past its bound`\n if (reason) log(` (${tag} ${step.do}: ${reason})`)\n else if (step.do !== 'expect')\n log(` ${tag} ${step.do}${selector ? ` ${selector}` : ''}`)\n run.steps.push({\n step: i,\n ...(step.id ? { id: step.id } : {}),\n do: step.do,\n ...(step.with ? { with: step.with } : {}),\n ...(step.after ? { after: step.after } : {}),\n ...(selector ? { selector } : {}),\n tStart: +(tStart / 1000).toFixed(3),\n tEnd: +(opts.footageMs() / 1000).toFixed(3),\n ...(reason ? { skipped: true, reason } : {}),\n ...(late ? { late: true } : {}),\n ...(value !== undefined ? { value } : {}),\n })\n }\n return run\n}\n","import type { MaskRule } from './exposure'\nimport type { SetupStep } from './setup'\nimport { urlSchemeProblem, validateSetup } from './setup'\nimport { readyProblem } from './ready'\nimport type { ReadyMode } from './ready'\nimport type { ClickButton, DragModifier, PathPoint } from './gestures'\nimport {\n CLICK_BUTTONS,\n DRAG_MODIFIERS,\n MAX_KEYS,\n chordProblem,\n readPath,\n} from './gestures'\nimport { pasteTypeOf } from './paste'\nimport { SETTLE_VERBS } from './settle'\nimport { peersHostedRefusal, validatePeers } from './peers'\nimport type { Peer } from './peers'\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 /**\n * Run AFTER the take, off camera, with the same verbs as `setup`: what\n * the take created in the product (an API key, a project, an invite)\n * removed again. They run once the screencast has stopped, on the take's\n * own page, after a rehearsal too, and when the take stops early or\n * throws after its first step. A failing teardown never fails the take;\n * it stops at the step that failed and is reported.\n */\n teardown?: SetupStep[]\n /**\n * When the first page counts as ready for step 1: `dom` (default),\n * once its DOM has made no change for a beat after `load`, at most 8 s;\n * `networkidle`, once the network has gone quiet, at most 45 s, which a\n * page holding a socket open never does. `--ready` overrides.\n */\n ready?: ReadyMode\n /**\n * Every gesture waits on the app after it (`settle` on a step overrides):\n * a canvas that falls behind under load finishes the last stroke before\n * the next one starts.\n */\n settle?: boolean\n steps: ActionStep[]\n /**\n * Other people on the page, OFF CAMERA: each a browser context of its\n * own (its own storage state, so its own user) on the same `url`, driven\n * by its own steps, each started `with` a take step or `after` one (by\n * id). Only the take's page is filmed, and only its own steps make the\n * cursor track; a peer's work reaches the footage through the app's own\n * sync. A hosted take refuses peers.\n */\n peers?: Peer[]\n}\n\nexport type ActionStep = (\n | { do: 'wait'; ms: number }\n /**\n * Rest the pointer on `selector`'s centre, or on the viewport point\n * (`x`, `y`) when no selector names the spot (a place on a canvas).\n */\n | { do: 'hover'; selector?: string; x?: number; y?: number; ms?: number }\n /**\n * Press `selector`'s centre, or the viewport point (`x`, `y`). `ms` is\n * the settle after the press (default 150). `count` 2 or 3 is a real\n * double or triple click; `button` presses the right or middle one;\n * `modifiers` are held for the press (a Shift-click) and released after.\n */\n | {\n do: 'click'\n selector?: string\n x?: number\n y?: number\n ms?: number\n count?: 1 | 2 | 3\n button?: ClickButton\n modifiers?: DragModifier[]\n }\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 * A key, a chord or a sequence, each recorded as a typing ping where the\n * pointer is (or on `selector` when given, with no click), never as the\n * key itself. `key` names one control key (Escape closes what a click\n * opened, Enter submits what was typed); `keys` names a chord\n * (`\"Shift+D\"`, `\"Mod+Z\"`, with `Mod` Meta on macOS and Control\n * elsewhere), a plain key (`\"r\"`, a tool's shortcut) or a sequence\n * (`[\"v\", \"Escape\"]`). Words are typed with `type`.\n */\n | {\n do: 'press'\n key?: PressKey\n keys?: string | string[]\n selector?: string\n ms?: number\n }\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 * `path` draws instead: viewport points (inline, or a file beside the\n * actions file), the press at the first and the release at the last,\n * replayed by the points' own times or evenly over ms. `modifiers` are\n * held for the whole drag.\n */\n | {\n do: 'drag'\n selector?: string\n x?: number\n y?: number\n tx?: number\n ty?: number\n path?: PathPoint[] | string\n modifiers?: DragModifier[]\n ms?: number\n }\n /**\n * Put words or a file (an image, an SVG) on the clipboard and paste it\n * the way a person's ⌘V does, into `selector` (clicked first) or where\n * the focus is. A file is read beside the actions file, by a plain name.\n */\n | {\n do: 'paste'\n selector?: string\n text?: string\n file?: string\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`, `gone` no longer visible, or `js`, an\n * expression evaluated in the page that holds when its value is truthy\n * (with `equals`, when its value equals that one): the state a canvas\n * app keeps in script, never in the DOM. Exactly one of the four. Waits\n * up to `timeout` seconds (default 5); a condition that never holds is a\n * skip with its reason, which names the value a `js` last answered.\n */\n | {\n do: 'expect'\n selector?: string\n text?: string\n gone?: string\n enabled?: boolean\n js?: string\n equals?: unknown\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 * The cut's camera on this step: `true` marks the step as its beat's\n * payoff, the moment worth the zoom (`vos plan --zooms per-beat` keeps\n * the proposal on it, and only it); `false` means never zoom here (the\n * planner's proposal on it is rejected). The planner still decides the\n * level and the focus; a mark never invents a zoom. On a gesture only\n * (ZOOM_MARK_VERBS).\n */\n zoom?: boolean\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 * After the gesture, wait until the page has made no DOM change and\n * painted no new frame for a beat (at most a few seconds): an app that\n * falls behind catches up before the next step. The script's top-level\n * `settle` is the default.\n */\n settle?: boolean\n}\n\n/** What an `await` waits for: exactly one of the four (`equals` rides with `js`). */\nexport interface AwaitUntil {\n selector?: string\n text?: string\n gone?: string\n js?: string\n equals?: unknown\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 `zoom` mark may sit on: the gestures a camera can be about. */\nexport const ZOOM_MARK_VERBS: readonly string[] = [\n 'click',\n 'drag',\n 'type',\n 'paste',\n 'press',\n 'hover',\n]\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 'paste',\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.teardown !== undefined)\n errors.push(...validateSetup(obj.teardown, 'teardown'))\n const ready = readyProblem(obj.ready)\n if (ready) errors.push(ready)\n if (obj.settle !== undefined && typeof obj.settle !== 'boolean')\n errors.push('settle must be true or false')\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 if (obj.peers !== undefined)\n errors.push(\n ...validatePeers(obj.peers, obj.steps, (steps) =>\n validateActions({ steps }),\n ),\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 if (s.do === 'type' && typeof s.selector !== 'string')\n errors.push(`${at}: type needs a selector`)\n if (s.do === 'hover' || s.do === 'click') {\n const point = s.x !== undefined || s.y !== undefined\n if (point && s.selector !== undefined)\n errors.push(\n `${at}: ${s.do} takes a selector or x and y (a viewport point), not both`,\n )\n else if (point) {\n if (!isCoord(s.x) || !isCoord(s.y))\n errors.push(\n `${at}: ${s.do} x and y must both be numbers of CSS px, 0 or more`,\n )\n } else if (typeof s.selector !== 'string')\n errors.push(\n `${at}: ${s.do} needs a selector, or x and y (a viewport point)`,\n )\n }\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 (s.key !== undefined && s.keys !== undefined)\n errors.push(\n `${at}: press takes key or keys, not both (keys says everything key does)`,\n )\n else if (s.keys !== undefined) {\n const list: unknown[] = Array.isArray(s.keys) ? s.keys : [s.keys]\n if (!list.length)\n errors.push(`${at}: press keys must name at least one key`)\n else if (list.length > MAX_KEYS)\n errors.push(`${at}: press keys names more than ${MAX_KEYS} keys`)\n list.forEach((k, j) => {\n const problem = chordProblem(k)\n if (problem)\n errors.push(\n `${at}: press keys${Array.isArray(s.keys) ? `[${j}]` : ''} ${problem}`,\n )\n })\n } else 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(', ')}, or keys (a chord like \"Shift+D\", a plain key like \"r\", or a sequence); 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 === 'click') {\n errors.push(...modifiersProblem(at, 'click', s.modifiers))\n if (\n s.count !== undefined &&\n s.count !== 1 &&\n s.count !== 2 &&\n s.count !== 3\n )\n errors.push(\n `${at}: click count must be 1, 2 (a double click) or 3 (a triple click)`,\n )\n if (\n s.button !== undefined &&\n !(CLICK_BUTTONS as readonly unknown[]).includes(s.button)\n )\n errors.push(`${at}: click button must be \"left\", \"right\" or \"middle\"`)\n }\n if (s.settle !== undefined) {\n if (typeof s.settle !== 'boolean')\n errors.push(`${at}: settle must be true or false`)\n else if (!SETTLE_VERBS.has(s.do))\n errors.push(\n `${at}: settle follows a gesture (hover, click, type, press, scroll, move, drag, paste); a ${s.do} sends the page nothing to catch up on`,\n )\n }\n if (s.do === 'paste') {\n const given = (['text', 'file'] as const).filter(\n (k) => s[k] !== undefined,\n )\n if (given.length !== 1)\n errors.push(\n `${at}: paste needs exactly one of text (words) or file (an image, an SVG or a text file beside the actions file)`,\n )\n if (s.text !== undefined && typeof s.text !== 'string')\n errors.push(`${at}: paste text must be a string`)\n if (s.file !== undefined) {\n const problem =\n typeof s.file === 'string'\n ? (fileNameProblem(s.file) ??\n (pasteTypeOf(s.file)\n ? null\n : `\"${s.file}\" is not a type a paste takes (.png, .jpg, .webp, .gif, .svg, .txt, .md, .html, .json, .csv)`))\n : 'is not a string'\n if (problem) errors.push(`${at}: paste file ${problem}`)\n }\n if (s.selector !== undefined && !isFilled(s.selector))\n errors.push(`${at}: paste selector must be a non-empty 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.zoom !== undefined) {\n if (typeof s.zoom !== 'boolean')\n errors.push(`${at}: zoom must be true or false`)\n else if (!ZOOM_MARK_VERBS.includes(s.do))\n errors.push(\n `${at}: zoom marks a gesture (${ZOOM_MARK_VERBS.join(', ')}); a ${s.do} shows nothing to zoom on`,\n )\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', 'js'] 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, gone or js${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 errors.push(...equalsProblem(`${at}: expect`, s))\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\" }, { \"gone\" } or { \"js\" }`,\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' || k === 'js',\n )\n const unknown = keys.filter((k) => !known.includes(k) && k !== 'equals')\n if (unknown.length)\n errors.push(\n `${at}: await until takes selector, text, gone or js (with equals), not ${unknown.join(', ')}`,\n )\n if (known.length !== 1)\n errors.push(\n `${at}: await until needs exactly one of selector, text, gone or js${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 errors.push(...equalsProblem(`${at}: await until`, until))\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 (s.path !== undefined) {\n const clash = (['selector', 'x', 'y', 'tx', 'ty'] as const).filter(\n (k) => s[k] !== undefined,\n )\n if (clash.length)\n errors.push(\n `${at}: a drag with a path starts at its first point and ends at its last, so it takes no ${clash.join(', ')}`,\n )\n if (typeof s.path === 'string') {\n const problem = fileNameProblem(s.path)\n if (problem)\n errors.push(\n `${at}: drag path ${problem} (a file beside the actions file)`,\n )\n } else {\n const read = readPath(s.path)\n if ('problems' in read)\n for (const p of read.problems) errors.push(`${at}: drag path ${p}`)\n }\n } else {\n if (typeof s.tx !== 'number' || typeof s.ty !== 'number') {\n errors.push(`${at}: drag needs tx and ty (CSS px), or a path`)\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 errors.push(...modifiersProblem(at, 'drag', s.modifiers))\n }\n })\n return errors\n}\n\nconst isCoord = (v: unknown): boolean =>\n typeof v === 'number' && Number.isFinite(v) && v >= 0\n\n/** The modifiers a click or a drag holds, checked in the same words for both. */\nfunction modifiersProblem(at: string, verb: string, v: unknown): string[] {\n if (v === undefined) return []\n if (\n !Array.isArray(v) ||\n v.some((m) => !(DRAG_MODIFIERS as readonly unknown[]).includes(m))\n )\n return [\n `${at}: ${verb} modifiers must be a list of ${DRAG_MODIFIERS.map((m) => `\"${m}\"`).join(', ')} (Mod is Meta on macOS, Control elsewhere)`,\n ]\n if (new Set(v).size !== v.length)\n return [`${at}: ${verb} modifiers names a modifier twice`]\n return []\n}\n\n/**\n * `equals` sits beside a `js` only, and holds a value JSON can say: what\n * the expression's own value is compared against.\n */\nfunction equalsProblem(at: string, s: Record<string, unknown>): string[] {\n if (s.equals === undefined) return []\n if (s.js === undefined)\n return [\n `${at} equals is the value a js expression must answer, so it needs js`,\n ]\n if (!isJsonValue(s.equals, 0))\n return [\n `${at} equals must be a JSON value (a number, a string, true, false, null, a list or an object of them)`,\n ]\n return []\n}\n\nfunction isJsonValue(v: unknown, depth: number): boolean {\n if (depth > 32) return false\n if (v === null || typeof v === 'string' || typeof v === 'boolean') return true\n if (typeof v === 'number') return Number.isFinite(v)\n if (Array.isArray(v)) return v.every((x) => isJsonValue(x, depth + 1))\n if (typeof v === 'object')\n return Object.values(v as Record<string, unknown>).every((x) =>\n isJsonValue(x, depth + 1),\n )\n return false\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, a download has no\n * take directory to land in there, and a `js` check is code a stranger's\n * script would run in the fleet's browser.\n */\nexport function hostedRefusals(\n actions: Pick<ActionsFile, 'steps' | 'peers'>,\n): string[] {\n const out: string[] = []\n const peers = peersHostedRefusal(actions.peers)\n if (peers) out.push(peers)\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 if (s.do === 'paste')\n out.push(\n `steps[${i}] is a paste, and a hosted browser has no clipboard to paste from: record it on this machine`,\n )\n if (\n (s.do === 'expect' && s.js !== undefined) ||\n (s.do === 'await' && s.until.js !== undefined)\n )\n out.push(\n `steps[${i}] ${s.do === 'expect' ? 'checks' : 'waits on'} a js expression, which runs as code in the page, and a hosted browser runs no script it was handed: record it on this machine, or check what the page shows (selector, text or gone)`,\n )\n if (s.do === 'drag' && typeof s.path === 'string')\n out.push(\n `steps[${i}] draws a path from the file \"${s.path}\", and a hosted take carries the script alone: write the points inline as path`,\n )\n })\n return out\n}\n\n/**\n * The files a script names beside itself, in order: a drag's path file\n * and a paste's file. A host reads them before anything is captured.\n */\nexport function scriptFiles(\n actions: Pick<ActionsFile, 'steps'>,\n): { step: number; name: string; as: 'path' | 'paste' }[] {\n const out: { step: number; name: string; as: 'path' | 'paste' }[] = []\n actions.steps.forEach((s, i) => {\n if (s.do === 'drag' && typeof s.path === 'string')\n out.push({ step: i, name: s.path, as: 'path' })\n if (s.do === 'paste' && typeof s.file === 'string')\n out.push({ step: i, name: s.file, as: 'paste' })\n })\n return out\n}\n","/**\n * The files a script names beside itself, read before the take: a drag's\n * path file (points as JSON) and a paste's file (its bytes). The host\n * hands in where they come from (`ScriptFiles`); the names are plain file\n * names, checked by `validateActions`, so a script can only name what sits\n * next to it.\n */\nimport type { ActionsFile } from './actions'\nimport { fileNameProblem, scriptFiles } from './actions'\nimport type { ScriptFiles } from './driver'\nimport { readPath } from './gestures'\nimport type { PathPoint, PathSample } from './gestures'\nimport { PASTE_MAX_BYTES, pasteTypeOf } from './paste'\n\nexport interface LoadedFiles {\n /** a drag's path, read from its file, by step index */\n paths: Map<number, { points: PathSample[]; timed: boolean }>\n /** a paste's file, by step index */\n pastes: Map<number, { bytes: Uint8Array; type: string; name: string }>\n}\n\n/**\n * Read every file the script names. Answers the files, or the problem in\n * words (the step, the file, what is wrong) for the caller to refuse the\n * take with.\n */\nexport async function loadScriptFiles(\n actions: Pick<ActionsFile, 'steps'>,\n source: ScriptFiles | undefined,\n): Promise<LoadedFiles | { problem: string }> {\n const loaded: LoadedFiles = { paths: new Map(), pastes: new Map() }\n const named = scriptFiles(actions)\n if (!named.length) return loaded\n if (!source) {\n const f = named[0]\n return {\n problem: `steps[${f.step}] names the file \"${f.name}\", and this recorder has no actions directory to read it from${f.as === 'path' ? ': write the points inline as path' : ''}. Nothing was recorded.`,\n }\n }\n for (const f of named) {\n const at = `steps[${f.step}]`\n const bad = fileNameProblem(f.name)\n if (bad) return { problem: `${at}: ${bad}. Nothing was recorded.` }\n let bytes: Uint8Array\n try {\n bytes = await source.read(f.name)\n } catch (e) {\n const why = e instanceof Error ? e.message : String(e)\n return {\n problem:\n f.as === 'paste'\n ? `${at} pastes the file \"${f.name}\", which could not be read beside the actions file (${why}): a file paste needs its file beside the script, so put ${f.name} next to it (a take fetched with its media brings its pasted files home beside its script; one pushed before they travelled with it does not). Nothing was recorded.`\n : `${at} names \"${f.name}\", which could not be read beside the actions file (${why}). Nothing was recorded.`,\n }\n }\n if (f.as === 'path') {\n let raw: unknown\n try {\n raw = JSON.parse(new TextDecoder().decode(bytes))\n } catch {\n return {\n problem: `${at}: the path file \"${f.name}\" is not JSON (an array of [x, y] or [x, y, tMs] points). Nothing was recorded.`,\n }\n }\n const path = readPath(raw)\n if ('problems' in path)\n return {\n problem: `${at}: the path file \"${f.name}\" ${path.problems.join('; ')}. Nothing was recorded.`,\n }\n loaded.paths.set(f.step, path)\n } else {\n if (bytes.length > PASTE_MAX_BYTES)\n return {\n problem: `${at}: \"${f.name}\" is larger than ${PASTE_MAX_BYTES / 1024 / 1024} MB, more than a paste carries. Nothing was recorded.`,\n }\n loaded.pastes.set(f.step, {\n bytes,\n type: pasteTypeOf(f.name) ?? 'application/octet-stream',\n name: f.name,\n })\n }\n }\n return loaded\n}\n\n/** A read path as inline points: its own times when it had them, its pressure when it carried one. */\nexport function inlinePoints(path: {\n points: PathSample[]\n timed: boolean\n}): PathPoint[] {\n return path.points.map((p): PathPoint => {\n if (path.timed)\n return p.pressure !== undefined\n ? [p.x, p.y, p.at, p.pressure]\n : [p.x, p.y, p.at]\n return p.pressure !== undefined\n ? { x: p.x, y: p.y, pressure: p.pressure }\n : [p.x, p.y]\n })\n}\n\n/**\n * The script as it ran, self-contained: every path a file held is written\n * inline, so the script a take keeps (and the one a push embeds, a fetch\n * writes back and a hosted recorder runs) re-records the same strokes with\n * the file gone. A paste's file stays a name: it is bytes, kept beside the\n * script by the host.\n */\nexport function inlineScript<T extends Pick<ActionsFile, 'steps'>>(\n actions: T,\n files: LoadedFiles,\n): T {\n if (!files.paths.size) return actions\n return {\n ...actions,\n steps: actions.steps.map((s, i) => {\n const read = files.paths.get(i)\n if (s.do !== 'drag' || typeof s.path !== 'string' || !read) return s\n return { ...s, path: inlinePoints(read) }\n }),\n }\n}\n","/**\n * The `paste` step run against a page: the clipboard first (a trusted\n * paste through the platform's chord), the page's own paste event when the\n * browser's clipboard refuses the item. paste.ts holds the page scripts and\n * says why there are two rungs.\n */\nimport type { RecorderContext, RecorderPage } from './driver'\nimport type { LoadedFiles } from './scriptFiles'\nimport type { PasteItem } from './paste'\nimport { stageClipboardScript, syntheticPasteScript } from './paste'\n\n/** Bytes to base64 without Node's Buffer, so the fleet's isolate runs it too. */\nfunction toBase64(bytes: Uint8Array): string {\n let bin = ''\n for (let i = 0; i < bytes.length; i += 0x8000)\n bin += String.fromCharCode(...bytes.subarray(i, i + 0x8000))\n return btoa(bin)\n}\n\n/** What a paste step puts on the clipboard: its words, or its file as read before the take. */\nexport function pasteItemOf(\n step: { text?: string; file?: string },\n stepIdx: number,\n files: LoadedFiles,\n): PasteItem | null {\n if (step.text !== undefined) return { text: step.text }\n const f = files.pastes.get(stepIdx)\n if (!f) return null\n return { b64: toBase64(f.bytes), type: f.type, name: f.name }\n}\n\nexport type PasteOutcome =\n | { via: 'clipboard' }\n | { via: 'file' }\n | { via: 'page'; why: string }\n | { failed: string }\n\n/**\n * Paste `item` where the focus is. `press` presses the paste chord and is\n * the recorder's, so the keystroke is timed and pinged like any other.\n */\nexport async function runPaste(\n page: RecorderPage,\n context: RecorderContext,\n item: PasteItem,\n press: (chord: string) => Promise<void>,\n): Promise<PasteOutcome> {\n // An image FILE is dispatched in the page with its own bytes: the\n // browser's clipboard re-encodes a picture and drops what the file\n // carries (a screenshot's density, so a 2x capture lands at twice its\n // size). Words keep the trusted path.\n if (item.b64 !== undefined && item.type?.startsWith('image/')) {\n const done = await page\n .evaluate<string>(syntheticPasteScript(item, { original: true }))\n .catch((e: unknown) => `failed: ${e instanceof Error ? e.message : e}`)\n return done === 'ok'\n ? { via: 'file' }\n : { failed: `the page's paste failed (${done.replace(/^failed: /, '')})` }\n }\n let origin: string | undefined\n try {\n origin = new URL(page.url()).origin\n } catch {\n origin = undefined\n }\n if (context.grantPermissions && origin && origin !== 'null')\n await context\n .grantPermissions(['clipboard-read', 'clipboard-write'], { origin })\n .catch(() => undefined)\n const staged = await page\n .evaluate<string>(stageClipboardScript(item))\n .catch((e: unknown) => `refused: ${e instanceof Error ? e.message : e}`)\n if (staged === 'ok') {\n await press('ControlOrMeta+v')\n return { via: 'clipboard' }\n }\n const why = staged.replace(/^refused: /, '')\n const done = await page\n .evaluate<string>(syntheticPasteScript(item))\n .catch((e: unknown) => `failed: ${e instanceof Error ? e.message : e}`)\n if (done === 'ok') return { via: 'page', why }\n return {\n failed: `this browser has no clipboard to paste from (${why}), and the page's own paste failed too (${done.replace(/^failed: /, '')})`,\n }\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 SoundSink,\n RecorderBrowser,\n RecorderClock,\n RecorderContext,\n RecorderPage,\n ScriptFiles,\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, wallVerdict } from './wall'\nimport {\n EXPOSURE_PROBE,\n ExposureLog,\n NoticeLog,\n maskInitScript,\n} from './exposure'\nimport type { ScannedNotice } from './exposure'\nimport {\n SetupEnvError,\n SetupError,\n TEARDOWN_BOUND_MS,\n runSetup,\n teardownEnvProblem,\n teardownLine,\n} from './setup'\nimport type { TeardownReport } from './setup'\nimport { StepBound, bounded, stepBoundMs } from './stepBound'\nimport {\n MEDIA_DRAIN_PROBE,\n MEDIA_WATCH_SCRIPT,\n PageSoundLog,\n} from './pageSound'\nimport type { MediaDrain } from './pageSound'\nimport { TakeClock } from './takeClock'\nimport { PageErrorLog } from './pageErrors'\nimport { fitSurfaceToViewport } from './surfaceFit'\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 { DEFAULT_READY, readyLine, reloadUntilReady, untilReady } from './ready'\nimport type { ReadyReport } from './ready'\nimport {\n DRAG_HOLD_MS,\n KEY_SEQUENCE_GAP_MS,\n MULTI_CLICK_GAP_MS,\n keySequencePlanMs,\n buttonNumber,\n modifierBits,\n overrunLine,\n overrunOf,\n pathDurationMs,\n pressSequence,\n resolveChord,\n resolveModifier,\n readPath,\n schedulePath,\n} from './gestures'\nimport type {\n ClickButton,\n DragModifier,\n PathSample,\n StepOverrun,\n} from './gestures'\nimport { inlineScript, loadScriptFiles } from './scriptFiles'\nimport { StepSignals, runPeer } from './peers'\nimport type { Peer, PeerRun } from './peers'\nimport type { LoadedFiles } from './scriptFiles'\nimport { pasteItemOf, runPaste } from './pasteStep'\nimport { CHANGE_AGE_PROBE, appSettled, settleOn } from './settle'\nimport {\n conditionMiss,\n keptValue,\n pollCondition,\n sayCondition,\n sayDuration,\n} from './waits'\nimport type { ConditionState, 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 /** A PEER's step (`peers[].id`): `step` is then an index into that peer's steps. */\n peer?: 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 /** `ready: \"networkidle\"` was asked for and the first load never reached it (recording proceeded anyway). */\n navTimeout: boolean\n /** How the first load settled before step 1. */\n ready: ReadyReport\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 /**\n * INFORMATION, never a failure and never in `exposures`: the signed-in\n * account's own name and its recent-items lists (also `meta.notices`).\n */\n notices: NonNullable<RecordingMeta['notices']>\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 /** The sound the page played, each heard stretch in footage seconds (also `meta.media`). */\n media: NonNullable<RecordingMeta['media']>\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 /**\n * Paced gestures that ran more than a fifth past their script (a drag's\n * travel, a path's timing, typing, a key sequence): the page could not\n * keep up with what it was sent. Also on `meta.steps[].overrunMs`.\n */\n overruns: StepOverrun[]\n /** The actions as recorded, `url` resolved: what a take directory writes back. */\n actions: ActionsFile\n /** What each peer did, off camera (also `meta.peers`); [] with none. */\n peers: PeerRun[]\n /**\n * What the script's `teardown` did after the take, off camera; null when\n * it has none. A failure here is reported and never fails the take.\n */\n teardown: TeardownReport | null\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 and a teardown's `{ env }` texts resolve\n * from: the shell's for the CLI, the job's own map on the fleet. Absent\n * means no env at all, so a setup that reads one fails in words, and a\n * teardown that reads one refuses the take before it begins.\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 /**\n * Where the sound the page played is kept, fetched with the page's own\n * cookies at the end of the take. A host that hands in none still\n * records `meta.media`, with no file; a rehearsal fetches nothing.\n */\n sounds?: SoundSink\n /**\n * The files the script names beside itself (a drag's path file, a\n * paste's file). A host that hands in none cannot run such a step: the\n * script is refused before anything is captured.\n */\n files?: ScriptFiles\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 /**\n * A step the page stopped answering in (it ran into its bound) stops the\n * take there, as an `await` that timed out does (`--strict`). Without\n * it the step is a skip and the take goes on.\n */\n stopOnHang?: boolean\n /** How often a long `await` reports it is still waiting (default 30 s). */\n awaitHeartbeatMs?: number\n /**\n * Where a peer's `storageState` is read from: the CLI resolves the name\n * from the actions file's directory to a path the browser opens, and\n * throws in words when there is none. A host that hands in none cannot\n * sign a peer in, and such a script is refused before anything is\n * captured.\n */\n peerStorageState?: (name: string) => Promise<string> | string\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 // Set once the take's first step is about to run: a take that throws\n // after that still runs its teardown, since undoing what it created\n // matters most exactly then. Best effort, and the throw propagates.\n const late: { teardown?: () => Promise<unknown> } = {}\n try {\n return await recordTakeSteps(browser, url, actions, sink, log, opts, late)\n } catch (e) {\n const teardown = late.teardown\n late.teardown = undefined\n if (teardown) await teardown().catch(() => {})\n throw e\n }\n}\n\nasync function recordTakeSteps(\n browser: RecorderBrowser,\n url: string,\n actions: ActionsFile,\n sink: FrameSink,\n log: (msg: string) => void,\n opts: RecordOpts,\n late: { teardown?: () => Promise<unknown> },\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 // A teardown that reads a variable this env does not hold is refused\n // before anything runs, in a rehearsal too (it clicks for real): the take\n // would create what its teardown then cannot remove.\n const teardownEnv = teardownEnvProblem(actions.teardown, opts.env ?? {})\n if (teardownEnv) throw new SetupEnvError(teardownEnv)\n // The files a script names (a path to draw, a file to paste) are read\n // and checked before a browser context exists, in a rehearsal too: a\n // missing or malformed one refuses the take in words.\n const read = await loadScriptFiles(actions, opts.files)\n if ('problem' in read) throw new RecordRefusedError(read.problem)\n const files: LoadedFiles = read\n // A peer's sign-in is resolved before a browser context exists too: a\n // storage state that is not there refuses the take in words.\n const peers: Peer[] = actions.peers ?? []\n const peerStates = new Map<string, string>()\n for (const p of peers) {\n if (p.storageState === undefined) continue\n if (!opts.peerStorageState)\n throw new RecordRefusedError(\n `peer ${p.id} signs in from the storage state \"${p.storageState}\", and this recorder has nowhere to read one from. Nothing was recorded.`,\n )\n try {\n peerStates.set(p.id, await opts.peerStorageState(p.storageState))\n } catch (e) {\n throw new RecordRefusedError(\n `peer ${p.id}'s storage state \"${p.storageState}\" could not be read (${e instanceof Error ? e.message : String(e)}). Nothing was recorded.`,\n )\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 // Every media element the page plays is noted from document start, in\n // every frame (pageSound.ts), so the sound it made can be placed later.\n await context.addInitScript(MEDIA_WATCH_SCRIPT)\n const soundLog = new PageSoundLog()\n const exposureLog = new ExposureLog(masks)\n const noticeLog = new NoticeLog()\n const rawPage = await context.newPage()\n // Every call into the page is bounded (stepBound.ts): a page that stops\n // answering ends the step it hung, never the take's clock.\n const pageBound = new StepBound()\n const page = bounded(rawPage, pageBound)\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 noticeLog.add(step, (scan as { notices?: ScannedNotice[] } | null)?.notices)\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 // The teardown's page errors are not the take's.\n let tearingDown = false\n page.on('console', (m) => {\n if (m.type() !== 'error' || tearingDown) return\n const line = pageErrors.add(m.text())\n if (line) log(line)\n })\n\n // When the first page counts as ready: its DOM settled (default), or\n // its network went idle (`ready: \"networkidle\"`). Polled on the wall's\n // clock in a rehearsal too: how long a page takes is what it is for.\n const readyMode = actions.ready ?? DEFAULT_READY\n const open = (target: string) =>\n untilReady(page, readyMode, (o) => page.goto(target, o), {\n sleep: realSleep,\n })\n log(`goto ${url}`)\n const opened = await open(url)\n let response = opened.response\n const ready: ReadyReport = opened.ready\n log(` ${readyLine(ready)}`)\n // A warning only when network idle was asked for and never came.\n const navTimeout = ready.mode === 'networkidle' && ready.capped\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 goto: (target) => open(target),\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 open(url)).response\n }\n\n // The teardown: off camera, after the take, on this page and context. Run\n // once, bounded as a whole, and never thrown: a step that fails stops it\n // there and is reported, and the take stands.\n const teardownSteps = actions.teardown ?? []\n let teardown: TeardownReport | null = null\n let teardownRan = false\n const runTeardown = async (): Promise<TeardownReport | null> => {\n if (!teardownSteps.length || teardownRan) return teardown\n teardownRan = true\n tearingDown = true\n log(`teardown: ${teardownSteps.length} step(s), off camera`)\n try {\n const result = await runSetup(page, teardownSteps, {\n phase: 'teardown',\n sleep: realSleep,\n env: opts.env ?? {},\n goto: (target) => open(target),\n boundMs: TEARDOWN_BOUND_MS,\n })\n for (const line of result.lines) log(` ${line}`)\n teardown = {\n ran: result.ran,\n of: teardownSteps.length,\n ...(result.failed\n ? {\n failed: {\n step: result.failed.step,\n do: result.failed.do,\n ...(result.failed.selector !== undefined\n ? { selector: result.failed.selector }\n : {}),\n error: result.failed.error ?? 'the step failed',\n },\n }\n : {}),\n ...(result.skipped ? { skipped: result.skipped } : {}),\n }\n } catch (e) {\n teardown = {\n ran: 0,\n of: teardownSteps.length,\n failed: {\n step: 0,\n do: teardownSteps[0].do,\n error: e instanceof Error ? e.message : String(e),\n },\n }\n }\n if (teardown.failed) log(` ${teardownLine(teardown)}`)\n return teardown\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 // What the page played while it was being prepared is not the take's.\n await page.evaluate(MEDIA_DRAIN_PROBE).catch(() => null)\n // A script that settles gets the page's change clock started now, so the\n // first settle knows how long the page has been still.\n if (actions.steps.some((s) => settleOn(s, actions.settle)))\n await page.evaluate(CHANGE_AGE_PROBE).catch(() => undefined)\n\n // The peers open now, before the camera rolls: each its own context and\n // page on the same address, never filmed, scanned or listened to. A peer\n // that lands on a sign-in has no one signed in to act as, so the take is\n // refused before a frame is captured.\n const peerPages: {\n peer: Peer\n context: RecorderContext\n page: RecorderPage\n }[] = []\n const closePeers = async () => {\n const bound = new StepBound()\n bound.start(CLOSE_BOUND_MS)\n await Promise.all(\n peerPages.map((p) => bound.race(p.context.close().catch(() => {}))),\n )\n bound.end()\n }\n for (const peer of peers) {\n const peerUrl = peer.url ?? url\n const pctx = await browser.newContext({\n viewport: peer.viewport ?? { width: vw, height: vh },\n deviceScaleFactor: 1,\n ...(peerStates.has(peer.id)\n ? { storageState: peerStates.get(peer.id) }\n : {}),\n })\n if (opts.headers && Object.keys(opts.headers).length)\n await applyHeaders(pctx, opts.headers, peerUrl, log)\n const ppage = await pctx.newPage()\n peerPages.push({ peer, context: pctx, page: ppage })\n const peerErrors = new PageErrorLog(opts.verbose === true)\n ppage.on('console', (m) => {\n if (m.type() !== 'error') return\n const line = peerErrors.add(m.text())\n if (line) log(` peer ${peer.id}: ${line.trim()}`)\n })\n log(`peer ${peer.id}: goto ${peerUrl} (off camera)`)\n const popened = await untilReady(\n ppage,\n readyMode,\n (o) => ppage.goto(peerUrl, o),\n { sleep: realSleep },\n )\n const seen = (await ppage.evaluate(WALL_PROBE).catch(() => null)) as Pick<\n Arrival,\n 'passwordFields' | 'newPasswordField' | 'oneTimeCodeField'\n > | null\n const peerWall = wallVerdict({\n askedUrl: peerUrl,\n landedUrl: ppage.url(),\n ...(popened.response ? { status: popened.response.status() } : {}),\n passwordFields: seen?.passwordFields ?? 0,\n newPasswordField: seen?.newPasswordField ?? false,\n oneTimeCodeField: seen?.oneTimeCodeField ?? false,\n })\n if (peerWall?.level === 'hard') {\n await closePeers()\n await context.close().catch(() => {})\n throw new RecordRefusedError(\n `peer ${peer.id} landed on ${peerWall.landed}, not ${peerWall.asked} (${peerWall.kind}): a peer acts as someone signed in, so give it a storageState of the second person's sign-in (beside actions.json). Nothing was recorded.`,\n )\n }\n log(` peer ${peer.id}: ${readyLine(popened.ready)}`)\n }\n\n const cdp = await context.newCDPSession(rawPage)\n // The surface the screencast reads is the viewport, or the take is short\n // (surfaceFit.ts). Before the camera rolls; a rehearsal captures nothing.\n if (!dry) await fitSurfaceToViewport(cdp, vw, vh)\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 // The page's media notes since the last look, in the recorder's clock.\n const drainSound = async (step?: number) => {\n const drain = (await page\n .evaluate(MEDIA_DRAIN_PROBE)\n .catch(() => null)) as MediaDrain | null\n soundLog.add(drain, Date.now(), step)\n }\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 /**\n * Travel to the rect's centre and press. A double or triple click is that\n * many presses well inside the platform's double-click interval, each\n * carrying its click count, so the page reads one gesture; every press is\n * a down and an up on the cursor track, with its button.\n */\n /**\n * Travel to an element's centre (a rect) or to a viewport point, and\n * press. A double or triple click is that many presses well inside the\n * platform's double-click interval, each carrying its click count, so the\n * page reads one gesture; every press is a down and an up on the cursor\n * track, with its button, and with the element's rect when there is one.\n * `modifiers` go down after the travel and come up after the last\n * release, whatever happens in between.\n */\n const clickAt = async (\n at: Rect | { x: number; y: number },\n how: {\n count?: number\n button?: ClickButton\n modifiers?: readonly DragModifier[]\n } = {},\n ) => {\n const rect = 'w' in at ? at : undefined\n await moveTo(\n rect ? rect.x + rect.w / 2 : at.x,\n rect ? rect.y + rect.h / 2 : at.y,\n )\n const held: string[] = []\n try {\n for (const m of how.modifiers ?? []) {\n const key = resolveModifier(m)\n await page.keyboard.down(key)\n held.push(key)\n }\n await sleep(PRESS_LEAD_MS)\n const count = how.count ?? 1\n const button = buttonNumber(how.button)\n for (let n = 1; n <= count; n++) {\n if (n > 1) await sleep(MULTI_CLICK_GAP_MS)\n const press = {\n ...(how.button && how.button !== 'left'\n ? { button: how.button }\n : {}),\n ...(n > 1 ? { clickCount: n } : {}),\n }\n const hasOpts = Object.keys(press).length > 0\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'down',\n button,\n ...(rect ? { rect } : {}),\n })\n await (hasOpts ? page.mouse.down(press) : page.mouse.down())\n await sleep(n < count ? PRESS_HOLD_MS / 2 : PRESS_HOLD_MS)\n await (hasOpts ? page.mouse.up(press) : page.mouse.up())\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'up',\n button,\n ...(rect ? { rect } : {}),\n })\n }\n } finally {\n for (const key of held.reverse())\n await page.keyboard.up(key).catch(() => undefined)\n }\n }\n\n /** A key's typing ping: where the key is about, never which key. */\n const keyPing = (rect: Rect | null) =>\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\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 const overruns: StepOverrun[] = []\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 // The peers' lanes start now and wait on the take's step boundaries; the\n // camera rolls with the first step.\n const signals = new StepSignals(\n actions.steps.map((s) => s.id).filter((id): id is string => !!id),\n )\n const lanes = peerPages.map(({ peer, page: ppage }) =>\n runPeer(peer, ppage, signals, {\n clock: { now: () => Date.now(), sleep },\n footageMs: () => now(),\n log,\n dry,\n }).catch((e: unknown): PeerRun => {\n log(\n ` (peer ${peer.id}: stopped: ${e instanceof Error ? e.message : String(e)})`,\n )\n return { id: peer.id, steps: [], notRun: [] }\n }),\n )\n signals.begin()\n // From the first step on, a take that throws still runs its teardown,\n // with the camera stopped first so none of it is captured.\n late.teardown = async () => {\n if (!dry) await cdp.send('Page.stopScreencast').catch(() => {})\n pageBound.end()\n // No result carries it on this path, so the log says how it went.\n const report = await runTeardown()\n if (report && !report.failed) log(` ${teardownLine(report)}`)\n }\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 paced gesture's plan against its wall time (the overrun report):\n // set by the cases whose tempo the script sets.\n const paced: { v: { plannedMs: number; tookMs: number } | null } = {\n v: null,\n }\n const timed = async <T>(plannedMs: number, fn: () => Promise<T>) => {\n const t = Date.now()\n const out = await fn()\n paced.v = { plannedMs, tookMs: Date.now() - t }\n return out\n }\n // A step's own ask when the script's numbers do not say it (a path\n // read from a file, a key sequence): what the pace report compares.\n let askedOverride: number | null = null\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 if (typeof step.zoom === 'boolean') extra.zoom = step.zoom\n // What a `js` check last answered, kept on the step: the app's own\n // state at that moment, which the frames cannot say.\n const keepValue = (last: ConditionState) => {\n if (!('value' in last)) return\n const kept = keptValue(last.value)\n if (kept !== undefined) extra.value = kept\n }\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 (\n sel: string | undefined,\n point?: { x: number; y: number } | null,\n ): 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 else if (point) await gesture(() => moveTo(point.x, point.y))\n log(\n `${tag}: guarded (${step.guard}), ${rect || point ? '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 const boundMs = stepBoundMs(\n step as Parameters<typeof stepBoundMs>[0],\n askedMs(step as Parameters<typeof askedMs>[0]),\n {\n expectS: EXPECT_TIMEOUT_S,\n awaitS: AWAIT_TIMEOUT_S,\n downloadS: DOWNLOAD_TIMEOUT_S,\n },\n )\n opts.onEvent?.({\n event: 'step',\n phase: 'start',\n i: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n do: step.do,\n })\n signals.start(step.id)\n const stepWall = Date.now()\n pageBound.start(boundMs)\n switch (step.do) {\n case 'wait':\n await sleep(clampWait(step.ms, now(), maxSeconds))\n break\n case 'move':\n // The pointer's travel is the recorder's, a gesture.\n await gesture(() => moveTo(step.x, step.y))\n break\n case 'hover': {\n // An element's centre, or a viewport point (a spot on a canvas).\n if (step.selector === undefined) {\n const px = step.x ?? cur.x\n const py = step.y ?? cur.y\n await gesture(() => moveTo(px, py))\n log(`hover ${Math.round(px)},${Math.round(py)}`)\n await sleep(step.ms ?? 700)\n break\n }\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 how = {\n count: step.count,\n button: step.button,\n modifiers: step.modifiers,\n }\n const said = `${step.count === 3 ? 'triple-click' : step.count === 2 ? 'double-click' : 'click'}${step.button && step.button !== 'left' ? ` (${step.button})` : ''}${step.modifiers?.length ? ` holding ${step.modifiers.join('+')}` : ''}`\n // A viewport point: a spot on a canvas no selector names.\n if (step.selector === undefined) {\n const point = { x: step.x ?? cur.x, y: step.y ?? cur.y }\n if (await rehearseGuard(undefined, point)) break\n await gesture(() => clickAt(point, how))\n log(`${said} at ${Math.round(point.x)},${Math.round(point.y)}`)\n const sinceChange = await gesture(() => waitSettled())\n await sleep(holdLeftMs(settleMs(step), sinceChange))\n break\n }\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, how))\n log(`${said} ${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 const chars = [...step.text]\n await timed(Math.max(0, chars.length - 1) * delay, () =>\n clockTyping(\n chars,\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 )\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 // A chord, a plain key or a sequence: each key is its own ping, a\n // person's hand apart. The ping is when and where, never which key.\n const seq = pressSequence(step)\n const chords = step.keys !== undefined ? seq.map(resolveChord) : seq\n const plan = keySequencePlanMs(chords.length)\n if (chords.length > 1) askedOverride = plan + settleMs(step)\n await timed(plan, async () => {\n for (const [i, chord] of chords.entries()) {\n if (i > 0) await sleep(KEY_SEQUENCE_GAP_MS)\n keyPing(rect)\n await page.keyboard.press(chord)\n }\n })\n log(`press ${seq.join(', ')}`)\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 // A drawn path starts at its first point; a straight drag at the\n // selector's centre, else (x, y).\n let path: PathSample[] | null = null\n if (typeof step.path === 'string') {\n const read = files.paths.get(stepIdx)\n if (read) path = schedulePath(read, step.ms)\n } else if (step.path !== undefined) {\n const read = readPath(step.path)\n if (!('problems' in read)) path = schedulePath(read, step.ms)\n }\n let start: { x: number; y: number } | null = null\n let rect: Rect | undefined\n if (path) {\n start = { x: path[0].x, y: path[0].y }\n } else 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 const from0 = start\n await gesture(() => moveTo(from0.x, from0.y))\n // The modifiers go down after the travel and before the press, and\n // come up after the release, so the page sees them for the whole\n // drag and the pointer's approach is a plain move.\n const mods = step.modifiers ?? []\n const held: string[] = []\n try {\n for (const m of mods) {\n const key = resolveModifier(m)\n await page.keyboard.down(key)\n held.push(key)\n }\n await gesture(() => sleep(PRESS_LEAD_MS))\n // A path that carries pressure is drawn with a PEN through the\n // browser's own input (the mouse has no pressure); a driver that\n // will not take one draws it with the mouse and says so.\n const bits = modifierBits(mods, opts.platform)\n const penAt = (\n type: 'mousePressed' | 'mouseMoved' | 'mouseReleased',\n p: { x: number; y: number; pressure?: number },\n ) =>\n cdp.send('Input.dispatchMouseEvent', {\n type,\n x: p.x,\n y: p.y,\n button: 'left',\n buttons: type === 'mouseReleased' ? 0 : 1,\n ...(type === 'mouseMoved' ? {} : { clickCount: 1 }),\n pointerType: 'pen',\n force: type === 'mouseReleased' ? 0 : (p.pressure ?? 0.5),\n modifiers: bits,\n })\n let pen = path?.some((p) => p.pressure !== undefined) ?? false\n if (pen && path) {\n try {\n await penAt('mousePressed', path[0])\n } catch {\n pen = false\n log(\n ` (${tag} drag: this browser takes no pen input; the path is drawn with the mouse and its pressure dropped)`,\n )\n }\n }\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'down',\n button: 0,\n rect,\n })\n if (!pen) await page.mouse.down()\n await gesture(() => sleep(PRESS_HOLD_MS))\n if (path) {\n // Every point is sent, in order, at its time: a drawing's shape\n // is its points, so a page that answers slowly makes the stroke\n // late (an overrun, reported), never a different stroke.\n const pts = path\n const total = pathDurationMs(pts)\n askedOverride = total\n await timed(total, async () => {\n const from = Date.now()\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i]\n if (!dry) {\n const wait = from + p.at - Date.now()\n if (wait > 0) await realSleep(wait)\n }\n if (pen) await penAt('mouseMoved', p)\n else await page.mouse.move(p.x, p.y)\n cur.x = p.x\n cur.y = p.y\n emit({ x: Math.round(p.x), y: Math.round(p.y), type: 'move' })\n }\n })\n } else {\n // The drag is the ask: `ms` of travel by the clock, however\n // slowly the page answers each move (a slider re-rendering per\n // sample).\n const dur = step.ms ?? 700\n const from = { ...cur }\n const tx = step.tx ?? from.x\n const ty = step.ty ?? from.y\n await timed(dur, () =>\n clockMotion(\n dur,\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({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'move',\n })\n },\n clock,\n ),\n )\n }\n await gesture(() => sleep(settleMs({ do: 'drag' })))\n if (pen) await penAt('mouseReleased', { x: cur.x, y: cur.y })\n else 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 } finally {\n for (const key of held.reverse())\n await page.keyboard.up(key).catch(() => undefined)\n }\n const holding = mods.length ? ` holding ${mods.join('+')}` : ''\n log(\n path\n ? `drag a path of ${path.length} points from ${Math.round(start.x)},${Math.round(start.y)}${holding}`\n : `drag ${step.selector ?? `${start.x},${start.y}`} → ${step.tx},${step.ty}${holding}`,\n )\n // The drag's own hold after the release: the recorder's, a gesture.\n await gesture(() => sleep(DRAG_HOLD_MS))\n break\n }\n case 'paste': {\n // Words or a file on the clipboard, pasted as a person's ⌘V does:\n // into the selector (clicked first, as a person puts the caret\n // there) or where the focus already is. The keystroke is a typing\n // ping; what was pasted never reaches the cursor track.\n const item = pasteItemOf(step, stepIdx, files)\n if (!item) {\n skip(step.file ?? '', `\"${step.file}\" was not read`)\n break\n }\n let rect: Rect | null = null\n if (step.selector) {\n rect = await boxOf(step.selector)\n stepRect = rect\n if (!rect) {\n skip(step.selector)\n break\n }\n const at = rect\n await gesture(() => clickAt(at))\n }\n const ping = { done: false }\n const outcome = await runPaste(page, context, item, async (chord) => {\n keyPing(rect)\n ping.done = true\n await page.keyboard.press(chord)\n })\n if ('failed' in outcome) {\n skip(step.selector ?? step.file ?? 'paste', outcome.failed)\n log(` (${tag} paste: ${outcome.failed})`)\n break\n }\n if (!ping.done) keyPing(rect)\n const what =\n step.text !== undefined\n ? `${[...step.text].length} chars`\n : `the file ${step.file}`\n const into = step.selector ? ` into ${step.selector}` : ''\n log(\n outcome.via === 'file'\n ? `paste ${what}${into}, dispatched in the page with the file's own bytes (the browser's clipboard re-encodes an image and drops what it carries, its density among it); its events are untrusted`\n : outcome.via === 'page'\n ? `paste ${what}${into}, dispatched in the page (the browser's clipboard refused it: ${outcome.why}); its events are untrusted`\n : `paste ${what}${into}`,\n )\n const sinceChange = await gesture(() => waitSettled())\n await sleep(holdLeftMs(settleMs(step), sinceChange))\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 keepValue(res.last)\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 ? () => reloadUntilReady(page, readyMode, timeoutMs)\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 keepValue(out.last)\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 gesture that waits on the app: no DOM change and no new frame for a\n // beat before the next step, so a canvas that fell behind catches up.\n if (\n settleOn(step, actions.settle) &&\n skipped.length === skippedBefore &&\n !stopped\n ) {\n const res = await gesture(() =>\n appSettled(page, () => frames.length, {\n sleep: realSleep,\n sinceFrame: () =>\n frames.length ? now() - frames[frames.length - 1].tMs : null,\n }),\n )\n extra.settleMs = res.ms\n if (!res.settled)\n log(\n ` (${tag} settle: the page was still changing after ${sayDuration(res.ms)}; going on)`,\n )\n }\n // A paced gesture that ran past its script: the page could not keep up.\n if (paced.v && !dry) {\n const over = overrunOf(paced.v.plannedMs, paced.v.tookMs)\n if (over !== null) {\n overruns.push({\n step: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n do: step.do,\n plannedMs: Math.round(paced.v.plannedMs),\n tookMs: Math.round(paced.v.tookMs),\n overrunMs: over,\n })\n extra.overrunMs = over\n }\n }\n const hang = pageBound.end()\n if (hang.hung) {\n const reason = hangReason(step.do, hang.ms, hang.boundMs)\n // One skip per step: a miss the step said already gives way to why.\n const said = skipped.length > skippedBefore ? skipped.at(-1) : undefined\n if (said) {\n said.reason = reason\n extra.reason = reason\n } else skip((step as { selector?: string }).selector ?? '', reason)\n log(` (${tag} ${step.do}: ${reason})`)\n // --strict: a page that stopped answering stops the take here.\n if (opts.stopOnHang && !stopped)\n stopped = {\n step: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n reason: `${tag} ${step.do}: ${reason}, so the take stopped there`,\n }\n }\n // The step's own reads after it (its words, the scans) get a beat each.\n pageBound.start(POST_STEP_READ_MS)\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: askedOverride ?? 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 await drainSound(stepIdx)\n pageBound.end()\n const stepSpan = stepSpans[stepSpans.length - 1]\n signals.end(step.id)\n opts.onEvent?.({\n event: 'step',\n phase: 'end',\n i: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n do: step.do,\n ms: Date.now() - stepWall,\n ...(stepSpan?.skipped ? { skipped: true } : {}),\n ...(hang.hung ? { hung: true } : {}),\n })\n // An await that timed out with onTimeout \"fail\": the take ends here.\n if (stopped) break\n }\n // The take's steps are over: a peer step still waiting never runs, one\n // already running finishes (bounded) while the camera still rolls.\n signals.close()\n const peerRuns = await Promise.all(lanes)\n for (const pr of peerRuns)\n for (const ps of pr.steps)\n if (ps.skipped)\n skipped.push({\n step: ps.step,\n ...(ps.id ? { id: ps.id } : {}),\n do: ps.do,\n selector: ps.selector ?? '',\n ...(ps.reason ? { reason: ps.reason } : {}),\n peer: pr.id,\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 // The take's own finish reads the page too, and is bounded like a step.\n pageBound.start(POST_STEP_READ_MS * 2)\n await drainSound()\n const endWall = Date.now()\n const durationMs = capped ? Math.min(now(), maxSeconds * 1000) : now()\n const heard = soundLog.heard(takeClock, endWall, durationMs)\n await cdp.send('Page.stopScreencast').catch(() => {})\n // Off camera now: the fetch takes what it takes.\n const media = await keepPageSound(\n heard,\n dry ? undefined : opts.sounds,\n fetchSource,\n log,\n )\n await sleep(200)\n const pageTitle = (await page.title().catch(() => '')) ?? ''\n for (const line of pageErrors.repeats()) log(line)\n pageBound.end()\n // The camera has stopped and the take's reads are done: what the take\n // created is undone now, before the context (and its cookies) closes.\n late.teardown = undefined\n await runTeardown()\n // A context whose page stopped answering may not close either: the take\n // is done whether it does or not.\n pageBound.start(CLOSE_BOUND_MS)\n await pageBound.race(context.close().catch(() => {}))\n pageBound.end()\n await closePeers()\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 ...(noticeLog.notices().length ? { notices: noticeLog.notices() } : {}),\n ...(masks.length ? { masks: exposureLog.masks(masks) } : {}),\n ...(skips.length ? { skips } : {}),\n ...(outputs.length ? { outputs } : {}),\n ...(media.length ? { media } : {}),\n ...(peerRuns.length\n ? {\n peers: peerRuns.map((pr) => ({\n id: pr.id,\n steps: pr.steps,\n ...(pr.notRun.length ? { notRun: pr.notRun } : {}),\n })),\n }\n : {}),\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 // A rehearsal captures no frames: it has no dead time to warn about.\n if (!dry && deadWarns(dead)) log(` WARNING: ${deadLine(dead)}`)\n\n const pace = paceReport(paces)\n if (!dry) log(` ${paceLine(pace)}`)\n const overrun = overrunLine(overruns)\n if (overrun) log(` WARNING: ${overrun}`)\n return {\n events,\n frames,\n meta,\n pace,\n skipped,\n navTimeout,\n ready,\n wall,\n exposures: exposureLog.exposures(),\n notices: noticeLog.notices(),\n masks: exposureLog.masks(masks),\n freezes,\n freezePct,\n dead,\n capped,\n disabled,\n confirmed,\n skips,\n outputs,\n media,\n stopped,\n pageErrors: pageErrors.entries(),\n overruns,\n // Self-contained: a path a file held is inline, so the take re-records\n // from its own script with the file gone.\n actions: { ...inlineScript(actions, files), url },\n peers: peerRuns,\n teardown,\n }\n}\n\n/**\n * Fetch each sound the page was heard playing, once per address, and keep\n * it through the host's sink: the take-relative key lands on its\n * `meta.media` entry. A source that cannot be fetched (a `blob:` of a page\n * that has gone, an address that answers 403) is said, and the entry keeps\n * the reason instead of a file. Nothing is fetched without a sink.\n */\nasync function keepPageSound(\n heard: ReturnType<PageSoundLog['heard']>,\n sink: SoundSink | undefined,\n fetchSource: (\n src: string,\n ) => Promise<{ bytes: Uint8Array; suggested: string; contentType?: string }>,\n log: (msg: string) => void,\n): Promise<NonNullable<RecordingMeta['media']>> {\n const kept = new Map<string, { file?: string; fetchError?: string }>()\n const used = new Set<string>()\n for (const h of heard) {\n if (!h.meta.intervals.length) continue\n const stretches = h.meta.intervals.length\n log(\n ` page sound: ${h.meta.src || 'a media element'} heard ${stretches === 1 ? 'once' : `${stretches} times`}`,\n )\n if (!sink || kept.has(h.src)) continue\n try {\n const got = await fetchSource(h.src)\n const name = outputName(\n undefined,\n got.suggested,\n `sound-${kept.size + 1}${extForType(got.contentType)}`,\n used,\n )\n used.add(name)\n kept.set(h.src, {\n file: await sink.save(name, got.bytes, got.contentType),\n })\n } catch (e) {\n const why = e instanceof Error ? e.message : String(e)\n kept.set(h.src, { fetchError: why })\n log(` (page sound not kept: ${why})`)\n }\n }\n return heard.map((h) => ({ ...h.meta, ...(kept.get(h.src) ?? {}) }))\n}\n\n/** How long a step's own reads after it (its words, the scans) may take on a page that has stopped answering. */\nconst POST_STEP_READ_MS = 5000\n/** How long the take waits for its browser context to close. */\nconst CLOSE_BOUND_MS = 10_000\n\n/** Why a step ended at its bound, with the real time it took. */\nexport function hangReason(verb: string, ms: number, boundMs: number): string {\n return `the page stopped answering: this ${verb} ran ${sayDuration(ms)}, past its bound of ${sayDuration(boundMs)}`\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 // A frame is drawn at its own size, never stretched to the take's: a\n // frame of another size means the surface moved mid-take, and a\n // picture scaled to fit would be a distorted take nobody was told of.\n if (bmp.width !== W || bmp.height !== H) {\n const size = bmp.width + 'x' + bmp.height\n bmp.close()\n throw new Error('frame ' + frames[fi].file + ' is ' + size + ', the take is ' + W + 'x' + H + ' (meta.captureWidth/captureHeight): frames are never resized, so the recorded surface changed size mid-take. Re-record it')\n }\n c2.drawImage(bmp, 0, 0)\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 EXPORT_RESOLUTION_OPTIONS,\n planAutoSpeed,\n planAutoZoom,\n projectFromArtifact,\n ratedSegments,\n recommendedExportResolution,\n withBackdrop,\n} from '@vosjs/studio-core'\nimport type {\n AudioClip,\n Backdrop,\n ProjectDoc,\n RecordingArtifact,\n RecordingPageMedia,\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 withFittingExport(withPageSound(doc, artifact.meta.media))\n}\n\n/**\n * The export a FRESH document opens on, sized to what the footage holds:\n * the ingest's default resolution, or the largest the recording supports\n * without upscaling when that is less (a 1280×720 take exports 720p, not a\n * 1080p that `vos validate` then warns upscales). Never raised. In place,\n * and returned.\n */\nexport function withFittingExport(doc: ProjectDoc): ProjectDoc {\n if (!doc.export) return doc\n const fits = recommendedExportResolution(doc)\n const order = EXPORT_RESOLUTION_OPTIONS as readonly string[]\n if (order.indexOf(fits) < order.indexOf(doc.export.resolution))\n doc.export = { ...doc.export, resolution: fits }\n return doc\n}\n\n/**\n * OUTPUT seconds of a moment of the PRIMARY footage through a rated piece\n * list; a moment in cut footage snaps to the next kept piece, and a piece\n * of another media only adds its length.\n */\nfunction sourceToOutput(\n pieces: readonly { in: number; out: number; rate?: number; media?: string }[],\n s: number,\n): number {\n let acc = 0\n for (const p of pieces) {\n const rate = p.rate && p.rate > 0 ? p.rate : 1\n if (p.media) {\n acc += Math.max(0, p.out - p.in) / rate\n continue\n }\n if (s < p.in) return acc\n if (s <= p.out) return acc + (s - p.in) / rate\n acc += Math.max(0, p.out - p.in) / rate\n }\n return acc\n}\n\n/**\n * The sound the page played (`meta.media`) as the document's audio: one\n * clip per heard stretch, keyed to the fetched file, placed at the OUTPUT\n * time of the footage moment it was heard (through the segments, the speed\n * spans and the freezes), stamped `source: 'page'`. A re-plan replaces only\n * those clips, so a clip someone added stays. An auto speed span over a\n * heard stretch is dropped first, or the footage would race ahead of what\n * the page was saying. A stretch with no fetched file (a hosted take, a\n * fetch that failed) places nothing. In place, and returned.\n */\nexport function withPageSound(\n doc: ProjectDoc,\n media: readonly RecordingPageMedia[] | undefined,\n): ProjectDoc {\n const kept = (doc.audio ?? []).filter((a) => a.source !== 'page')\n const heard = (media ?? []).filter((m) => m.file && m.intervals.length)\n if (!heard.length) {\n doc.audio = kept\n return doc\n }\n const spans = heard.flatMap((m) =>\n m.intervals.map((iv) => ({ in: iv.at, out: iv.at + (iv.to - iv.from) })),\n )\n doc.speed = (doc.speed ?? []).filter(\n (sp) =>\n sp.source !== 'auto' ||\n !!sp.media ||\n !spans.some((h) => sp.in < h.out && h.in < sp.out),\n )\n const pieces = ratedSegments(doc)\n const clips: AudioClip[] = []\n heard.forEach((m, i) => {\n const file = m.file as string\n const name = file.split('/').pop() || file\n const length = Math.max(m.duration ?? 0, ...m.intervals.map((iv) => iv.to))\n m.intervals.forEach((iv, j) => {\n clips.push({\n id: `page-${i + 1}-${j + 1}`,\n key: file,\n name,\n start: +sourceToOutput(pieces, iv.at).toFixed(3),\n in: iv.from,\n out: iv.to,\n duration: +length.toFixed(3),\n gain: m.volume ?? 1,\n fadeIn: 0,\n fadeOut: 0,\n source: 'page',\n })\n })\n })\n doc.audio = [...kept, ...clips]\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","response","EXPECT_TIMEOUT_S","VERBS","done","EXPECT_EVERY_MS","type","EXPECT_TIMEOUT_S","read"]}