effect-browser 0.3.0-beta.15 → 0.3.0-beta.19
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.
- package/README.md +18 -6
- package/dist/{Browser-BBSySyjT.mjs → Browser-H63wiekr.mjs} +5 -5
- package/dist/Browser-H63wiekr.mjs.map +1 -0
- package/dist/Browser.d.mts +2 -2
- package/dist/Browser.mjs +1 -1
- package/dist/{BrowserEvent-BRu2juEz.d.mts → BrowserEvent-dq6FRT8w.d.mts} +9 -9
- package/dist/BrowserEvent.d.mts +1 -1
- package/dist/BrowserEvent.mjs +7 -12
- package/dist/BrowserEvent.mjs.map +1 -1
- package/dist/Cdp.mjs +2 -2
- package/dist/{Change-iMlcuzVD.d.mts → Change-DqING3tr.d.mts} +2 -2
- package/dist/Change.d.mts +1 -1
- package/dist/Chromium.mjs +2 -2
- package/dist/Expect.d.mts +1 -1
- package/dist/Expect.mjs +2 -2
- package/dist/Moment.d.mts +1 -1
- package/dist/Moment.mjs +3 -3
- package/dist/Moment.mjs.map +1 -1
- package/dist/Motion-DND6I-64.d.mts +40 -0
- package/dist/Motion.d.mts +2 -40
- package/dist/Motion.mjs +1 -2
- package/dist/Motion.mjs.map +1 -1
- package/dist/{Page-B5cjaUp5.mjs → Page-CfB6Zn1p.mjs} +7 -15
- package/dist/Page-CfB6Zn1p.mjs.map +1 -0
- package/dist/{Page-DL9eylp3.d.mts → Page-ku6j5t-v.d.mts} +23 -25
- package/dist/Page.d.mts +1 -1
- package/dist/Page.mjs +1 -1
- package/dist/{Plan-CXA2BW-G.mjs → Plan-C-d5QYS8.mjs} +6 -9
- package/dist/Plan-C-d5QYS8.mjs.map +1 -0
- package/dist/{Plan-6As6vcwT.d.mts → Plan-DJ4hEEna.d.mts} +3 -3
- package/dist/Plan.d.mts +1 -1
- package/dist/Plan.mjs +1 -1
- package/dist/Policy.d.mts +1 -1
- package/dist/Policy.mjs +1 -1
- package/dist/Presentation.d.mts +2 -2
- package/dist/Presentation.mjs +3 -2
- package/dist/Presentation.mjs.map +1 -1
- package/dist/Stage.d.mts +1 -1
- package/dist/Stage.mjs +8 -7
- package/dist/Stage.mjs.map +1 -1
- package/dist/{Supervisor-DaGlQVjv.mjs → Supervisor-2mPjIYYs.mjs} +44 -19
- package/dist/Supervisor-2mPjIYYs.mjs.map +1 -0
- package/dist/{Supervisor-5tZ47hR5.d.mts → Supervisor-mVPeEUp8.d.mts} +12 -5
- package/dist/Supervisor.d.mts +1 -1
- package/dist/Supervisor.mjs +1 -1
- package/dist/{context-BAjRj7Xo.mjs → context-w3NJPRLo.mjs} +81 -9
- package/dist/context-w3NJPRLo.mjs.map +1 -0
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +4 -4
- package/dist/match.inpage-xOe9LNO0.mjs.map +1 -1
- package/dist/{page-B92QnRfT.mjs → page-BKwfF6z-.mjs} +213 -218
- package/dist/page-BKwfF6z-.mjs.map +1 -0
- package/package.json +1 -1
- package/src/Browser.ts +1 -1
- package/src/BrowserEvent.ts +7 -12
- package/src/Moment.ts +3 -6
- package/src/Motion.ts +1 -2
- package/src/Page.ts +18 -20
- package/src/Plan.ts +1 -2
- package/src/Presentation.ts +2 -1
- package/src/Stage.ts +10 -17
- package/src/Supervisor.ts +9 -9
- package/src/internal/input/actions.ts +53 -97
- package/src/internal/input/dispatch.ts +25 -11
- package/src/internal/input/edit.inpage.ts +26 -11
- package/src/internal/input/evidence.inpage.ts +1 -21
- package/src/internal/input/guard.inpage.ts +9 -29
- package/src/internal/input/guard.ts +15 -10
- package/src/internal/input/perform.ts +14 -10
- package/src/internal/input/pointer.ts +3 -6
- package/src/internal/input/replies.ts +19 -8
- package/src/internal/input/settle.ts +3 -2
- package/src/internal/input/targets.inpage.ts +6 -13
- package/src/internal/input/targets.ts +13 -32
- package/src/internal/page/bridge.ts +2 -2
- package/src/internal/page/context.ts +15 -3
- package/src/internal/page/navigation.ts +3 -12
- package/src/internal/pictures/capture.ts +11 -4
- package/src/internal/pictures/clock.ts +8 -3
- package/src/internal/pictures/motion.ts +65 -0
- package/src/internal/pictures/pictures.ts +22 -17
- package/src/internal/pictures/utilsBundle.d.ts +9 -0
- package/src/internal/reading/controls.inpage.ts +8 -1
- package/src/internal/reading/match.inpage.ts +2 -1
- package/src/internal/reading/outline.inpage.ts +7 -4
- package/src/internal/reading/reading.ts +10 -25
- package/src/internal/reading/ready.ts +66 -14
- package/src/internal/supervisor/lifecycle.ts +56 -13
- package/src/internal/timeline/events.ts +5 -8
- package/src/internal/timeline/window.ts +3 -8
- package/dist/Browser-BBSySyjT.mjs.map +0 -1
- package/dist/Page-B5cjaUp5.mjs.map +0 -1
- package/dist/Plan-CXA2BW-G.mjs.map +0 -1
- package/dist/Supervisor-DaGlQVjv.mjs.map +0 -1
- package/dist/context-BAjRj7Xo.mjs.map +0 -1
- package/dist/page-B92QnRfT.mjs.map +0 -1
package/dist/Moment.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Moment.mjs","names":[],"sources":["../src/Moment.ts"],"sourcesContent":["/**\n * What a page showed, and what changed on it, over a window of time.\n *\n * A page's timeline has three tracks on its browser's host clock: its events, what visibly changed\n * on it (`Change`), and its screencast frames. A `Window` holds the three from `since` to `until`,\n * and says why a part it could not read is missing rather than fail. `Page.window` takes one, which\n * can end in the past, at a frame a delayed consumer airs late, so that a line written now tells\n * what its viewers will see. Its `account` says what was so at its end: how long the page had been\n * still, which of its changes were still under way, and which had settled.\n *\n * A `Moment` is a window that ends at a picture of the page now: `capture` takes the picture, then\n * the window up to it, and on request the page's outline. `toPrompt` turns a moment into one user\n * message for any `effect/ai` call: a structured answer from `LanguageModel.generateObject`, a\n * caption from `generateText`, or one turn of a `Chat` that follows moment after moment. It leads\n * with what changed, news and what settled before what was still changing, as its account tells\n * them apart, and names an action as what a change followed; as a step where changes followed it\n * but none names it, or where its effect is drawn rather than written, as on a canvas, which only\n * the screenshots show; and claims nothing of what changed where the record did not see, or of a\n * part it could not read, which it names with why.\n *\n * Frames come from a running screencast, as far back as the browser's `frameHistory` keeps them.\n * A moment's picture is the newest frame if it was painted after the page's latest input and\n * completed action, at most 250 ms ago, else a new screenshot timed by its capture.\n *\n * @since 0.3.0\n */\nimport { Duration, Effect, Option, Result, Schema } from \"effect\";\nimport { Prompt } from \"effect/ai\";\n\nimport { BrowserError, InvalidRequest } from \"./BrowserError.ts\";\nimport { type Action, BrowserEvent } from \"./BrowserEvent.ts\";\nimport { type Change, Changes } from \"./Change.ts\";\nimport { Frame } from \"./Frame.ts\";\nimport { undispatched } from \"./internal/page/context.ts\";\nimport { describe, named, quoted, where } from \"./internal/timeline/words.ts\";\nimport type * as Page from \"./Page.ts\";\nimport { Snapshot, type SnapshotOptions } from \"./Snapshot.ts\";\n\n/** A page's events, changes and frames over one window of its browser's host clock. */\nexport class Window extends Schema.Class<Window>(\"effect-browser/Window\")({\n page: Schema.String,\n /** Where the window starts, in host monotonic milliseconds on the owning browser’s clock. */\n since: Schema.Finite,\n /** Where it ends, never after it was taken. */\n until: Schema.Finite,\n /** The page's events after `since`, up to `until`, oldest first, without the input presentation track. */\n events: Schema.Array(BrowserEvent),\n /**\n * What visibly changed after `since`, up to `until`; absent where `missing` says why. A page's\n * first window starts its record, so the record sees none of it.\n */\n changes: Schema.optional(Changes),\n /** Screencast frames painted from `since` to `until`, oldest first, as far back as kept. */\n frames: Schema.Array(Frame),\n /**\n * Why each part that could not be read is missing: the read of its changes, by whatever\n * operation failed there, or a moment's picture (`frame`) or outline (`snapshot`).\n */\n missing: Schema.Array(BrowserError),\n}) {}\n\n/**\n * A window that ends at a picture of the page, its last frame, unless `missing` says why it has\n * none. Its frames are a few, spread over the window, so that it still begins where it starts.\n */\nexport class Moment extends Window.extend<Moment>(\"effect-browser/Moment\")({\n /** The page's outline at the end of the window, when the capture asked for it. */\n snapshot: Schema.optional(Snapshot),\n}) {}\n\nexport interface CaptureOptions {\n /**\n * Where the window starts, as for `Page.window`: a previous window or moment, so that consecutive\n * ones neither repeat nor miss an event or a change, or a `Duration` back from the picture.\n * Defaults to 5 seconds.\n */\n readonly since?: Page.WindowOptions[\"since\"] | undefined;\n /** Frames to keep, at least 1, spread over the window and ending with the picture. Defaults to 2. */\n readonly frames?: number | undefined;\n /**\n * Whether to take the page's outline at the end, or its options; `true` means 4,000 characters.\n * Defaults to `false`: the frames and the timeline carry most moments, while an outline costs a\n * round trip to the page and can double a moment's tokens.\n */\n readonly snapshot?: SnapshotOptions | boolean | undefined;\n /** Show what fields hold in the moment's changes; a secret field still reads `••••`. */\n readonly unmask?: boolean | undefined;\n}\n\n/** Pick `count` frames spread evenly over `frames`, always including the last. */\nconst spread = (frames: ReadonlyArray<Frame>, count: number): ReadonlyArray<Frame> => {\n if (frames.length <= count) return frames;\n if (count <= 1) return frames.slice(-1);\n const step = (frames.length - 1) / (count - 1);\n\n return Array.from({ length: count }, (_, index) => frames[Math.round(index * step)]).filter(\n (frame): frame is Frame => frame !== undefined,\n );\n};\n\n// An action ends after its navigation settles, which can follow the last paint. A fresh picture\n// keeps that completed action inside the moment without moving events between adjacent windows.\nconst pictureOf = Effect.fnUntraced(function* (page: Page.Page) {\n const frame = yield* page.frame({ after: \"input\" });\n const events = yield* page.recentEvents;\n\n return events.some((event) => event._tag === \"Action\" && event.at > frame.hostTime)\n ? yield* page.frame({ maxAge: 0 })\n : frame;\n});\n\nexport const capture = Effect.fn(\"Moment.capture\")(function* (\n page: Page.Page,\n options: CaptureOptions = {},\n) {\n const count = options.frames ?? 2;\n\n if (!Number.isSafeInteger(count) || count < 1)\n return yield* undispatched(\n \"moment\",\n new InvalidRequest({ detail: \"frames must be a positive safe integer\" }),\n );\n const outline = options.snapshot ?? false;\n\n // The picture comes first, at no call with a running screencast, and the window ends at its\n // paint, so its changes hold nothing it does not show; without one, the window ends now. The\n // outline is taken alongside. What cannot be read is missing from the moment, not its end.\n const { pictured, outlined } = yield* Effect.all(\n {\n pictured: Effect.result(pictureOf(page)).pipe(\n Effect.flatMap((picture) =>\n Effect.map(\n page.window({\n since: options.since ?? Duration.seconds(5),\n until: Result.getOrUndefined(picture),\n unmask: options.unmask,\n }),\n (window) => ({ window, picture }),\n ),\n ),\n ),\n outlined: Effect.result(\n outline === false\n ? Effect.void\n : page.snapshot({ maxChars: 4000, ...(outline === true ? {} : outline) }),\n ),\n },\n { concurrency: 2 },\n );\n\n const { window, picture } = pictured;\n const shown = Result.getOrUndefined(picture);\n\n return new Moment({\n ...window,\n frames: spread(\n shown === undefined\n ? window.frames\n : [...window.frames.filter((frame) => frame !== shown), shown],\n count,\n ),\n snapshot: Result.getOrUndefined(outlined) ?? undefined,\n missing: [\n ...window.missing,\n ...Option.toArray(Result.getFailure(picture)),\n ...Option.toArray(Result.getFailure(outlined)),\n ],\n });\n});\n\n/** A window's record of changes, if it saw any of the window: a page's first has none. */\nconst recordOf = ({ changes }: Window) =>\n changes !== undefined && changes.from < changes.until ? changes : undefined;\n\n/** What a window says of its page at its end: what was still in flux, and what had settled. */\nexport interface Account {\n /**\n * How long, in milliseconds, the page had been still at the end: since the last change in view\n * its record shows, or the last paint its screencast frames show, or else since the window, or\n * its record, began. Undefined where neither could tell, with no record of the window and no\n * painted frame: a screenshot shows the page, not when it last changed. Frames show paint only\n * while a capture runs, and the record does not see a canvas, so a canvas that keeps drawing\n * with no capture running reads as still.\n */\n readonly stillFor: number | undefined;\n /**\n * The changes still under way at the end: what kept changing, more than once in the window or\n * already before it, and changed again within twice its own pace before the end.\n */\n readonly changing: ReadonlyArray<Change>;\n /** Every other change, which shows what it settled at. */\n readonly settled: ReadonlyArray<Change>;\n}\n\n/** Whether a change was still under way at `until`, by its own pace. */\nconst underWay = (change: Change, until: number) => {\n const pace =\n change.count > 1\n ? (change.at - change.startedAt) / (change.count - 1)\n : change.earlier === undefined\n ? undefined\n : change.startedAt - change.earlier;\n\n return pace !== undefined && until - change.at < 2 * pace;\n};\n\n/**\n * An account of the window's page at its end: how long it had been still, and which of its\n * changes were still under way and which had settled. A window whose record saw none of it has\n * neither.\n */\nexport const account = (window: Window): Account => {\n const record = recordOf(window);\n const changes = record?.changes ?? [];\n\n const stirred = [\n ...changes.flatMap((change) => (change.kind === \"title\" ? [] : [change.at])),\n ...window.frames.flatMap((frame) =>\n frame.timing._tag === \"BrowserPaint\" ? [frame.hostTime] : [],\n ),\n ];\n\n return {\n stillFor:\n record === undefined && stirred.length === 0\n ? undefined\n : window.until - Math.max(window.since, record?.from ?? window.since, ...stirred),\n changing: changes.filter((change) => underWay(change, window.until)),\n settled: changes.filter((change) => !underWay(change, window.until)),\n };\n};\n\nconst seconds = (moment: Moment, at: number) => `${((at - moment.until) / 1000).toFixed(1)}s`;\n\nconst pointOf = (x: number | undefined, y: number | undefined) =>\n x === undefined || y === undefined ? undefined : `(${Math.round(x)}, ${Math.round(y)})`;\n\n/**\n * What an action acted on. Without a subject the action failed before finding it, and a ref it was\n * given is left out: refs are reused, so the page's outline may give it to something else by now.\n */\nconst acted = (event: Action): string => {\n const point = pointOf(event.x, event.y);\n\n if (event.subject === undefined)\n return event.target === undefined || /^e\\d+$|\"e\\d+\"/.test(event.target)\n ? (point ?? \"\")\n : event.target;\n // A drag's point is where it ended.\n if (event.to !== undefined)\n return `${named(event.subject, undefined)} to ${named(event.to, point)}`;\n\n return named(event.subject, point);\n};\n\n/**\n * An action as a step: `click button \"Pay\"`. A failed one says only that: its error is advice for\n * the caller that acted, which may name a ref, not a fact about the page.\n */\nconst step = (event: Action): string => {\n const target = acted(event);\n const text = event.text === undefined ? \"\" : JSON.stringify(event.text);\n\n const what =\n event.name === \"type\" && target !== \"\"\n ? `${text} into ${target}`\n : event.name === \"select\" && target !== \"\"\n ? `${text} in ${target}`\n : `${target} ${text}`;\n\n return `${event.name} ${what}${event.ok ? \"\" : \" (failed)\"}`.replace(/\\s+/g, \" \").trim();\n};\n\n/** What is drawn rather than written, whose changes only the screenshots show. */\nconst drawn = new Set([\"canvas\", \"iframe\", \"video\", \"embed\", \"object\", \"svg\"]);\n\nconst onDrawn = (event: Action) =>\n event.ok && event.subject !== undefined && drawn.has(event.subject.role ?? event.subject.tag);\n\ninterface Line {\n readonly at: number;\n readonly rank: number;\n readonly text: string;\n}\n\n/** At most this many lines of what happened; the least notable are counted, not listed. */\nconst maxLines = 24;\n\n/**\n * The changes as lines, news first, and the actions they name; cells of one column that changed\n * together as one line. What kept changing says whether it still was at the moment, by its account.\n */\nconst changed = (moment: Moment, record: Changes) => {\n const actions = moment.events.filter((event): event is Action => event._tag === \"Action\");\n const named = new Set<Action>();\n const changing = new Set(account(moment).changing);\n\n const state = (change: Change) =>\n changing.has(change)\n ? \", still changing at the moment\"\n : change.count > 1 || change.earlier !== undefined\n ? `, settled since ${seconds(moment, change.at)}`\n : \"\";\n\n // The action whose input a change followed: one that ran while the input arrived, give or take\n // the clock's mapping, so input the library did not send names no action.\n const cause = (change: Change) => {\n const input = change.cause;\n\n const action =\n input === undefined\n ? undefined\n : actions.findLast((event) => event.startedAt <= input + 100 && event.at >= input - 100);\n\n if (action === undefined) return \"\";\n named.add(action);\n\n return `, after ${step(action)}`;\n };\n\n const columns = Map.groupBy(\n record.changes.filter(\n (change) => change.kind === \"text\" && change.subject.context.column !== undefined,\n ),\n ({ subject: { context } }) => JSON.stringify([context.heading, context.column]),\n );\n\n const lines: Array<Line> = [];\n const collapsed = new Set<Change>();\n\n for (const [first, ...cells] of columns.values())\n if (first !== undefined && cells.length >= 2) {\n const still = [first, ...cells].filter((cell) => changing.has(cell)).length;\n\n for (const cell of [first, ...cells]) collapsed.add(cell);\n lines.push({\n at: first.startedAt,\n rank: still > 0 ? 3 : 2,\n text: `${cells.length + 1} cells in column ${quoted(first.subject.context.column)}${where({ heading: first.subject.context.heading })} changed, such as ${describe(first, true)}${still > 0 ? `, ${still} still changing at the moment` : \"\"}`,\n });\n }\n for (const change of record.changes)\n if (!collapsed.has(change))\n lines.push({\n at: change.startedAt,\n rank: changing.has(change) ? 3 : 2,\n text: describe(change) + cause(change) + state(change),\n });\n\n return { lines, named };\n};\n\n/** What a part a moment could not read was, by the operation that failed: a window's one read is its changes. */\nconst parts = new Map([\n [\"frame\", \"A picture of the moment\"],\n [\"snapshot\", \"The page's outline\"],\n]);\n\n/** The moment's changes and events as lines, most notable first when its changes are recorded. */\nconst happened = (moment: Moment): ReadonlyArray<string> => {\n const record = recordOf(moment);\n\n const { lines, named } =\n record === undefined\n ? { lines: new Array<Line>(), named: new Set<Action>() }\n : changed(moment, record);\n\n // Whether anything but a field's own edit changed after an action began.\n const followed = (event: Action) =>\n record?.changes.some((change) => change.kind !== \"value\" && change.at > event.startedAt) ===\n true;\n\n // With a record, an action is told as a step where changes followed it and none names it, so a\n // click whose effect a busy page leaves uncredited is not lost; where its effect is drawn; or\n // where it started before the record began, as on the document a click opened. An attempt that\n // nothing followed, a failed one, a hover and a scroll are left out.\n const told = (event: Action) =>\n !(event.ok && [\"navigate\", \"back\", \"reload\"].includes(event.name)) &&\n (record === undefined ||\n event.startedAt <= record.from ||\n (event.ok &&\n event.name !== \"scroll\" &&\n (onDrawn(event) || (event.name !== \"hover\" && !named.has(event) && followed(event)))));\n\n for (const event of moment.events)\n if (event._tag === \"Action\" && event.page === moment.page && told(event))\n lines.push({ at: event.at, rank: 4, text: step(event) });\n else if (event._tag === \"Navigated\")\n lines.push({\n at: event.at,\n rank: 0,\n text: `${event.sameDocument ? \"moved within the page\" : \"navigated\"} to ${event.url}`,\n });\n else if (event._tag === \"PageOpened\")\n lines.push({ at: event.at, rank: 0, text: `a tab opened at ${event.url}` });\n else if (event._tag === \"PageClosed\")\n lines.push({\n at: event.at,\n rank: 0,\n text: `the tab ${event.cause === \"crashed\" ? \"crashed\" : \"closed\"}`,\n });\n else if (event._tag === \"DialogShown\")\n lines.push({\n at: event.at,\n rank: 1,\n text: `a dialog (${event.kind}) said ${JSON.stringify(event.message)}`,\n });\n\n const ordered = lines.toSorted((left, right) =>\n record === undefined ? left.at - right.at : left.rank - right.rank || left.at - right.at,\n );\n\n const kept = ordered.slice(0, maxLines);\n const drawing = moment.events.some((event) => event._tag === \"Action\" && onDrawn(event));\n const begins = record === undefined ? moment.since : Math.max(moment.since, record.from);\n const unread = moment.missing.some((error) => !parts.has(error.operation));\n\n return [\n ...kept.map((line) => `${seconds(moment, line.at)} ${line.text}`),\n ...(ordered.length > maxLines ? [`…and ${ordered.length - maxLines} less notable`] : []),\n ...(record === undefined\n ? unread\n ? []\n : [\"What changed on the page was not recorded.\"]\n : record.changes.length > 0\n ? []\n : [\n `No text in view changed${begins > moment.since ? ` after ${seconds(moment, begins)}` : \"\"}${drawing ? \"; what is drawn, such as a canvas, shows only in the screenshots\" : \"\"}.`,\n ]),\n ...(record !== undefined && record.dropped > 0\n ? [\n `The page changed too much to tell it all: at least ${record.dropped} changes are not told.`,\n ]\n : []),\n ...(begins > moment.since\n ? [`Changes before ${seconds(moment, begins)} are not all known.`]\n : []),\n ...moment.missing.map(\n (error) =>\n `${parts.get(error.operation) ?? \"What changed on the page\"} could not be read: ${error.reason.message}.`,\n ),\n ];\n};\n\n/**\n * The moment as one user message: the page's outline when the moment has one, what changed, most\n * notable first, what kept changing told as still changing at the moment or settled since when, by\n * its account, with the actions that the changes followed, that changes followed though none\n * names them, or that drew what only the screenshots show, what could not be read and why, and its\n * frames captioned with their times, the last one \"the moment\" where it is the picture at its end.\n * Give a model its task with `Prompt.setSystem`, and add what the caller knows about the page as\n * more text.\n */\nexport const toPrompt = (moment: Moment): Prompt.Prompt => {\n const count = moment.frames.length;\n const last = count - 1;\n const pictured = moment.frames.at(-1)?.hostTime === moment.until;\n\n const following =\n count === 1 ? \"One screenshot follows\" : `${count} screenshots follow, oldest first`;\n\n return Prompt.fromMessages([\n Prompt.makeMessage(\"user\", {\n content: [\n Prompt.makePart(\"text\", {\n text: [\n \"One moment of a browser session. Rely only on what this material shows, and prefer concrete details: numbers, names, colours, positions and motion.\",\n \"\",\n ...(moment.snapshot === undefined ? [] : [moment.snapshot.rendered, \"\"]),\n `${recordOf(moment) === undefined ? \"What happened\" : \"What changed, most notable first\"} (seconds before the moment, over ${((moment.until - moment.since) / 1000).toFixed(1)}s):`,\n ...happened(moment),\n ...(count === 0\n ? []\n : [\n \"\",\n `${following}${pictured ? (count === 1 ? \": the moment itself.\" : \"; the last one is the moment itself.\") : \".\"}`,\n ]),\n ].join(\"\\n\"),\n }),\n ...moment.frames.flatMap((frame, index) => [\n Prompt.makePart(\"text\", {\n text:\n index === last && pictured ? \"The moment:\" : `${seconds(moment, frame.hostTime)}:`,\n }),\n Prompt.makePart(\"file\", { mediaType: \"image/jpeg\", data: frame.data }),\n ]),\n ],\n }),\n ]);\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Moment.mjs","names":[],"sources":["../src/Moment.ts"],"sourcesContent":["/**\n * What a page showed, and what changed on it, over a window of time.\n *\n * A page's timeline has three tracks on its browser's host clock: its events, what visibly changed\n * on it (`Change`), and its screencast frames. A `Window` holds the three from `since` to `until`,\n * and says why a part it could not read is missing rather than fail. `Page.window` takes one, which\n * can end in the past, at a frame a delayed consumer airs late, so that a line written now tells\n * what its viewers will see. Its `account` says what was so at its end: how long the page had been\n * still, which of its changes were still under way, and which had settled.\n *\n * A `Moment` is a window that ends at a picture of the page now: `capture` takes the picture, then\n * the window up to it, and on request the page's outline. `toPrompt` turns a moment into one user\n * message for any `effect/ai` call: a structured answer from `LanguageModel.generateObject`, a\n * caption from `generateText`, or one turn of a `Chat` that follows moment after moment. It leads\n * with what changed, news and what settled before what was still changing, as its account tells\n * them apart, and names an action as what a change followed; as a step where changes followed it\n * but none names it, or where its effect is drawn rather than written, as on a canvas, which only\n * the screenshots show; and claims nothing of what changed where the record did not see, or of a\n * part it could not read, which it names with why.\n *\n * Frames come from a running screencast, as far back as the browser's `frameHistory` keeps them.\n * A moment's picture is the newest frame if it was painted after the page's latest input and\n * completed action, at most 250 ms ago, else a new screenshot timed by its capture.\n *\n * @since 0.3.0\n */\nimport { Duration, Effect, Option, Result, Schema } from \"effect\";\nimport { Prompt } from \"effect/ai\";\n\nimport { BrowserError } from \"./BrowserError.ts\";\nimport { type Action, BrowserEvent } from \"./BrowserEvent.ts\";\nimport { type Change, Changes } from \"./Change.ts\";\nimport { Frame } from \"./Frame.ts\";\nimport { refuse } from \"./internal/page/context.ts\";\nimport { describe, named, quoted, where } from \"./internal/timeline/words.ts\";\nimport type * as Page from \"./Page.ts\";\nimport { Snapshot, type SnapshotOptions } from \"./Snapshot.ts\";\n\n/** A page's events, changes and frames over one window of its browser's host clock. */\nexport class Window extends Schema.Class<Window>(\"effect-browser/Window\")({\n page: Schema.String,\n /** Where the window starts, in host monotonic milliseconds on the owning browser’s clock. */\n since: Schema.Finite,\n /** Where it ends, never after it was taken. */\n until: Schema.Finite,\n /** The page's events after `since`, up to `until`, oldest first, without the input presentation track. */\n events: Schema.Array(BrowserEvent),\n /**\n * What visibly changed after `since`, up to `until`; absent where `missing` says why. A page's\n * first window starts its record, so the record sees none of it.\n */\n changes: Schema.optional(Changes),\n /** Screencast frames painted from `since` to `until`, oldest first, as far back as kept. */\n frames: Schema.Array(Frame),\n /**\n * Why each part that could not be read is missing: the read of its changes, by whatever\n * operation failed there, or a moment's picture (`frame`) or outline (`snapshot`).\n */\n missing: Schema.Array(BrowserError),\n}) {}\n\n/**\n * A window that ends at a picture of the page, its last frame, unless `missing` says why it has\n * none. Its frames are a few, spread over the window, so that it still begins where it starts.\n */\nexport class Moment extends Window.extend<Moment>(\"effect-browser/Moment\")({\n /** The page's outline at the end of the window, when the capture asked for it. */\n snapshot: Schema.optional(Snapshot),\n}) {}\n\nexport interface CaptureOptions {\n /**\n * Where the window starts, as for `Page.window`: a previous window or moment, so that consecutive\n * ones neither repeat nor miss an event or a change, or a `Duration` back from the picture.\n * Defaults to 5 seconds.\n */\n readonly since?: Page.WindowOptions[\"since\"] | undefined;\n /** Frames to keep, at least 1, spread over the window and ending with the picture. Defaults to 2. */\n readonly frames?: number | undefined;\n /**\n * Whether to take the page's outline at the end, or its options; `true` means 4,000 characters.\n * Defaults to `false`: the frames and the timeline carry most moments, while an outline costs a\n * round trip to the page and can double a moment's tokens.\n */\n readonly snapshot?: SnapshotOptions | boolean | undefined;\n /** Show what fields hold in the moment's changes; a secret field still reads `••••`. */\n readonly unmask?: boolean | undefined;\n}\n\n/** Pick `count` frames spread evenly over `frames`, always including the last. */\nconst spread = (frames: ReadonlyArray<Frame>, count: number): ReadonlyArray<Frame> => {\n if (frames.length <= count) return frames;\n if (count <= 1) return frames.slice(-1);\n const step = (frames.length - 1) / (count - 1);\n\n return Array.from({ length: count }, (_, index) => frames[Math.round(index * step)]).filter(\n (frame): frame is Frame => frame !== undefined,\n );\n};\n\n// An action ends after its navigation settles, which can follow the last paint. A fresh picture\n// keeps that completed action inside the moment without moving events between adjacent windows.\nconst pictureOf = Effect.fnUntraced(function* (page: Page.Page) {\n const frame = yield* page.frame({ after: \"input\" });\n const events = yield* page.recentEvents;\n\n return events.some((event) => event._tag === \"Action\" && event.at > frame.hostTime)\n ? yield* page.frame({ maxAge: 0 })\n : frame;\n});\n\nexport const capture = Effect.fn(\"Moment.capture\")(function* (\n page: Page.Page,\n options: CaptureOptions = {},\n) {\n const count = options.frames ?? 2;\n\n if (!Number.isSafeInteger(count) || count < 1)\n return yield* refuse(\"moment\", \"frames must be a positive safe integer\");\n const outline = options.snapshot ?? false;\n\n // The picture comes first, at no call with a running screencast, and the window ends at its\n // paint, so its changes hold nothing it does not show; without one, the window ends now. The\n // outline is taken alongside. What cannot be read is missing from the moment, not its end.\n const { pictured, outlined } = yield* Effect.all(\n {\n pictured: Effect.result(pictureOf(page)).pipe(\n Effect.flatMap((picture) =>\n Effect.map(\n page.window({\n since: options.since ?? Duration.seconds(5),\n until: Result.getOrUndefined(picture),\n unmask: options.unmask,\n }),\n (window) => ({ window, picture }),\n ),\n ),\n ),\n outlined: Effect.result(\n outline === false\n ? Effect.void\n : page.snapshot({ maxChars: 4000, ...(outline === true ? {} : outline) }),\n ),\n },\n { concurrency: 2 },\n );\n\n const { window, picture } = pictured;\n const shown = Result.getOrUndefined(picture);\n\n return new Moment({\n ...window,\n frames: spread(\n shown === undefined\n ? window.frames\n : [...window.frames.filter((frame) => frame !== shown), shown],\n count,\n ),\n snapshot: Result.getOrUndefined(outlined) ?? undefined,\n missing: [\n ...window.missing,\n ...Option.toArray(Result.getFailure(picture)),\n ...Option.toArray(Result.getFailure(outlined)),\n ],\n });\n});\n\n/** A window's record of changes, if it saw any of the window: a page's first has none. */\nconst recordOf = ({ changes }: Window) =>\n changes !== undefined && changes.from < changes.until ? changes : undefined;\n\n/** What a window says of its page at its end: what was still in flux, and what had settled. */\nexport interface Account {\n /**\n * How long, in milliseconds, the page had been still at the end: since the last change in view\n * its record shows, or the last paint its screencast frames show, or else since the window, or\n * its record, began. Undefined where neither could tell, with no record of the window and no\n * painted frame: a screenshot shows the page, not when it last changed. Frames show paint only\n * while a capture runs, and the record does not see a canvas, so a canvas that keeps drawing\n * with no capture running reads as still.\n */\n readonly stillFor: number | undefined;\n /**\n * The changes still under way at the end: what kept changing, more than once in the window or\n * already before it, and changed again within twice its own pace before the end.\n */\n readonly changing: ReadonlyArray<Change>;\n /** Every other change, which shows what it settled at. */\n readonly settled: ReadonlyArray<Change>;\n}\n\n/** Whether a change was still under way at `until`, by its own pace. */\nconst underWay = (change: Change, until: number) => {\n const pace =\n change.count > 1\n ? (change.at - change.startedAt) / (change.count - 1)\n : change.earlier === undefined\n ? undefined\n : change.startedAt - change.earlier;\n\n return pace !== undefined && until - change.at < 2 * pace;\n};\n\n/**\n * An account of the window's page at its end: how long it had been still, and which of its\n * changes were still under way and which had settled. A window whose record saw none of it has\n * neither.\n */\nexport const account = (window: Window): Account => {\n const record = recordOf(window);\n const changes = record?.changes ?? [];\n\n const stirred = [\n ...changes.flatMap((change) => (change.kind === \"title\" ? [] : [change.at])),\n ...window.frames.flatMap((frame) =>\n frame.timing._tag === \"BrowserPaint\" ? [frame.hostTime] : [],\n ),\n ];\n\n return {\n stillFor:\n record === undefined && stirred.length === 0\n ? undefined\n : window.until - Math.max(window.since, record?.from ?? window.since, ...stirred),\n changing: changes.filter((change) => underWay(change, window.until)),\n settled: changes.filter((change) => !underWay(change, window.until)),\n };\n};\n\nconst seconds = (moment: Moment, at: number) => `${((at - moment.until) / 1000).toFixed(1)}s`;\n\nconst pointOf = (x: number | undefined, y: number | undefined) =>\n x === undefined || y === undefined ? undefined : `(${Math.round(x)}, ${Math.round(y)})`;\n\n/**\n * What an action acted on. Without a subject the action failed before finding it, and a ref it was\n * given is left out: refs are reused, so the page's outline may give it to something else by now.\n */\nconst acted = (event: Action): string => {\n const point = pointOf(event.x, event.y);\n\n if (event.subject === undefined)\n return event.target === undefined || /^e\\d+$|\"e\\d+\"/.test(event.target)\n ? (point ?? \"\")\n : event.target;\n // A drag's point is where it ended.\n if (event.to !== undefined)\n return `${named(event.subject, undefined)} to ${named(event.to, point)}`;\n\n return named(event.subject, point);\n};\n\n/**\n * An action as a step: `click button \"Pay\"`. A failed one says only that: its error is advice for\n * the caller that acted, which may name a ref, not a fact about the page.\n */\nconst step = (event: Action): string => {\n const target = acted(event);\n const text = event.text === undefined ? \"\" : JSON.stringify(event.text);\n\n const what =\n event.name === \"type\" && target !== \"\"\n ? `${text} into ${target}`\n : event.name === \"select\" && target !== \"\"\n ? `${text} in ${target}`\n : `${target} ${text}`;\n\n return `${event.name} ${what}${event.ok ? \"\" : \" (failed)\"}`.replace(/\\s+/g, \" \").trim();\n};\n\n/** What is drawn rather than written, whose changes only the screenshots show. */\nconst drawn = new Set([\"canvas\", \"iframe\", \"video\", \"embed\", \"object\", \"svg\"]);\n\nconst onDrawn = (event: Action) =>\n event.ok && event.subject !== undefined && drawn.has(event.subject.role ?? event.subject.tag);\n\ninterface Line {\n readonly at: number;\n readonly rank: number;\n readonly text: string;\n}\n\n/** At most this many lines of what happened; the least notable are counted, not listed. */\nconst maxLines = 24;\n\n/**\n * The changes as lines, news first, and the actions they name; cells of one column that changed\n * together as one line. What kept changing says whether it still was at the moment, by its account.\n */\nconst changed = (moment: Moment, record: Changes) => {\n const actions = moment.events.filter((event): event is Action => event._tag === \"Action\");\n const named = new Set<Action>();\n const changing = new Set(account(moment).changing);\n\n const state = (change: Change) =>\n changing.has(change)\n ? \", still changing at the moment\"\n : change.count > 1 || change.earlier !== undefined\n ? `, settled since ${seconds(moment, change.at)}`\n : \"\";\n\n // The action whose input a change followed: one that ran while the input arrived, give or take\n // the clock's mapping, so input the library did not send names no action.\n const cause = (change: Change) => {\n const input = change.cause;\n\n const action =\n input === undefined\n ? undefined\n : actions.findLast((event) => event.startedAt <= input + 100 && event.at >= input - 100);\n\n if (action === undefined) return \"\";\n named.add(action);\n\n return `, after ${step(action)}`;\n };\n\n const columns = Map.groupBy(\n record.changes.filter(\n (change) => change.kind === \"text\" && change.subject.context.column !== undefined,\n ),\n ({ subject: { context } }) => JSON.stringify([context.heading, context.column]),\n );\n\n const lines: Array<Line> = [];\n const collapsed = new Set<Change>();\n\n for (const [first, ...cells] of columns.values())\n if (first !== undefined && cells.length >= 2) {\n const still = [first, ...cells].filter((cell) => changing.has(cell)).length;\n\n for (const cell of [first, ...cells]) collapsed.add(cell);\n lines.push({\n at: first.startedAt,\n rank: still > 0 ? 3 : 2,\n text: `${cells.length + 1} cells in column ${quoted(first.subject.context.column)}${where({ heading: first.subject.context.heading })} changed, such as ${describe(first, true)}${still > 0 ? `, ${still} still changing at the moment` : \"\"}`,\n });\n }\n for (const change of record.changes)\n if (!collapsed.has(change))\n lines.push({\n at: change.startedAt,\n rank: changing.has(change) ? 3 : 2,\n text: describe(change) + cause(change) + state(change),\n });\n\n return { lines, named };\n};\n\n/** What a part a moment could not read was, by the operation that failed: a window's one read is its changes. */\nconst parts = new Map([\n [\"frame\", \"A picture of the moment\"],\n [\"snapshot\", \"The page's outline\"],\n]);\n\n/** The moment's changes and events as lines, most notable first when its changes are recorded. */\nconst happened = (moment: Moment): ReadonlyArray<string> => {\n const record = recordOf(moment);\n\n const { lines, named } =\n record === undefined\n ? { lines: new Array<Line>(), named: new Set<Action>() }\n : changed(moment, record);\n\n // Whether anything but a field's own edit changed after an action began.\n const followed = (event: Action) =>\n record?.changes.some((change) => change.kind !== \"value\" && change.at > event.startedAt) ===\n true;\n\n // With a record, an action is told as a step where changes followed it and none names it, so a\n // click whose effect a busy page leaves uncredited is not lost; where its effect is drawn; or\n // where it started before the record began, as on the document a click opened. An attempt that\n // nothing followed, a failed one, a hover and a scroll are left out.\n const told = (event: Action) =>\n !(event.ok && [\"navigate\", \"back\", \"reload\"].includes(event.name)) &&\n (record === undefined ||\n event.startedAt <= record.from ||\n (event.ok &&\n event.name !== \"scroll\" &&\n (onDrawn(event) || (event.name !== \"hover\" && !named.has(event) && followed(event)))));\n\n for (const event of moment.events)\n if (event._tag === \"Action\" && event.page === moment.page && told(event))\n lines.push({ at: event.at, rank: 4, text: step(event) });\n else if (event._tag === \"Navigated\")\n lines.push({\n at: event.at,\n rank: 0,\n text: `${event.sameDocument ? \"moved within the page\" : \"navigated\"} to ${event.url}`,\n });\n else if (event._tag === \"PageOpened\")\n lines.push({ at: event.at, rank: 0, text: `a tab opened at ${event.url}` });\n else if (event._tag === \"PageClosed\")\n lines.push({\n at: event.at,\n rank: 0,\n text: `the tab ${event.cause === \"crashed\" ? \"crashed\" : \"closed\"}`,\n });\n else if (event._tag === \"DialogShown\")\n lines.push({\n at: event.at,\n rank: 1,\n text: `a dialog (${event.kind}) said ${JSON.stringify(event.message)}`,\n });\n\n const ordered = lines.toSorted((left, right) =>\n record === undefined ? left.at - right.at : left.rank - right.rank || left.at - right.at,\n );\n\n const kept = ordered.slice(0, maxLines);\n const drawing = moment.events.some((event) => event._tag === \"Action\" && onDrawn(event));\n const begins = record === undefined ? moment.since : Math.max(moment.since, record.from);\n const unread = moment.missing.some((error) => !parts.has(error.operation));\n\n return [\n ...kept.map((line) => `${seconds(moment, line.at)} ${line.text}`),\n ...(ordered.length > maxLines ? [`…and ${ordered.length - maxLines} less notable`] : []),\n ...(record === undefined\n ? unread\n ? []\n : [\"What changed on the page was not recorded.\"]\n : record.changes.length > 0\n ? []\n : [\n `No text in view changed${begins > moment.since ? ` after ${seconds(moment, begins)}` : \"\"}${drawing ? \"; what is drawn, such as a canvas, shows only in the screenshots\" : \"\"}.`,\n ]),\n ...(record !== undefined && record.dropped > 0\n ? [\n `The page changed too much to tell it all: at least ${record.dropped} changes are not told.`,\n ]\n : []),\n ...(begins > moment.since\n ? [`Changes before ${seconds(moment, begins)} are not all known.`]\n : []),\n ...moment.missing.map(\n (error) =>\n `${parts.get(error.operation) ?? \"What changed on the page\"} could not be read: ${error.reason.message}.`,\n ),\n ];\n};\n\n/**\n * The moment as one user message: the page's outline when the moment has one, what changed, most\n * notable first, what kept changing told as still changing at the moment or settled since when, by\n * its account, with the actions that the changes followed, that changes followed though none\n * names them, or that drew what only the screenshots show, what could not be read and why, and its\n * frames captioned with their times, the last one \"the moment\" where it is the picture at its end.\n * Give a model its task with `Prompt.setSystem`, and add what the caller knows about the page as\n * more text.\n */\nexport const toPrompt = (moment: Moment): Prompt.Prompt => {\n const count = moment.frames.length;\n const last = count - 1;\n const pictured = moment.frames.at(-1)?.hostTime === moment.until;\n\n const following =\n count === 1 ? \"One screenshot follows\" : `${count} screenshots follow, oldest first`;\n\n return Prompt.fromMessages([\n Prompt.makeMessage(\"user\", {\n content: [\n Prompt.makePart(\"text\", {\n text: [\n \"One moment of a browser session. Rely only on what this material shows, and prefer concrete details: numbers, names, colours, positions and motion.\",\n \"\",\n ...(moment.snapshot === undefined ? [] : [moment.snapshot.rendered, \"\"]),\n `${recordOf(moment) === undefined ? \"What happened\" : \"What changed, most notable first\"} (seconds before the moment, over ${((moment.until - moment.since) / 1000).toFixed(1)}s):`,\n ...happened(moment),\n ...(count === 0\n ? []\n : [\n \"\",\n `${following}${pictured ? (count === 1 ? \": the moment itself.\" : \"; the last one is the moment itself.\") : \".\"}`,\n ]),\n ].join(\"\\n\"),\n }),\n ...moment.frames.flatMap((frame, index) => [\n Prompt.makePart(\"text\", {\n text:\n index === last && pictured ? \"The moment:\" : `${seconds(moment, frame.hostTime)}:`,\n }),\n Prompt.makePart(\"file\", { mediaType: \"image/jpeg\", data: frame.data }),\n ]),\n ],\n }),\n ]);\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
declare namespace Motion_d_exports {
|
|
3
|
+
export { Plan, Point, Sample, Service, lognormal, maximumDurationMillis, maximumSamples };
|
|
4
|
+
}
|
|
5
|
+
declare const maximumSamples = 2048;
|
|
6
|
+
declare const maximumDurationMillis = 5000;
|
|
7
|
+
declare const Point: Schema.Struct<{
|
|
8
|
+
readonly x: Schema.Finite;
|
|
9
|
+
readonly y: Schema.Finite;
|
|
10
|
+
}>;
|
|
11
|
+
type Point = typeof Point.Type;
|
|
12
|
+
declare const Sample: Schema.Struct<{
|
|
13
|
+
readonly x: Schema.Finite;
|
|
14
|
+
readonly y: Schema.Finite;
|
|
15
|
+
readonly afterMillis: Schema.Finite;
|
|
16
|
+
}>;
|
|
17
|
+
type Sample = typeof Sample.Type;
|
|
18
|
+
/** A complete glide: 1 to 2,048 samples whose offsets never decrease. */
|
|
19
|
+
declare const Plan: Schema.$Array<Schema.Struct<{
|
|
20
|
+
readonly x: Schema.Finite;
|
|
21
|
+
readonly y: Schema.Finite;
|
|
22
|
+
readonly afterMillis: Schema.Finite;
|
|
23
|
+
}>>;
|
|
24
|
+
type Plan = typeof Plan.Type;
|
|
25
|
+
interface Service {
|
|
26
|
+
/**
|
|
27
|
+
* Offsets start when the performer publishes the plan, before its first input. The browser
|
|
28
|
+
* decodes the result as a `Plan` whose last sample must be exactly `to`. Glide time has a budget
|
|
29
|
+
* of its own, outside the browser's `actionTimeout`, so a drag may glide twice for 5 seconds.
|
|
30
|
+
*/
|
|
31
|
+
readonly plan: (from: Point, to: Point) => Effect.Effect<ReadonlyArray<Sample>>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The research's tuned two-stroke sigma-lognormal model: a fast stroke toward the target and a
|
|
35
|
+
* slower one that homes in on it, with a little bend, drawn from `Random`.
|
|
36
|
+
*/
|
|
37
|
+
declare const lognormal: Service;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { Service as a, maximumSamples as c, Sample as i, Plan as n, lognormal as o, Point as r, maximumDurationMillis as s, Motion_d_exports as t };
|
|
40
|
+
//# sourceMappingURL=Motion-DND6I-64.d.mts.map
|
package/dist/Motion.d.mts
CHANGED
|
@@ -1,40 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export { Plan, Point, Sample, Service, lognormal, maximumDurationMillis, maximumSamples };
|
|
4
|
-
}
|
|
5
|
-
export declare const maximumSamples = 2048;
|
|
6
|
-
export declare const maximumDurationMillis = 5000;
|
|
7
|
-
export declare const Point: Schema.Struct<{
|
|
8
|
-
readonly x: Schema.Finite;
|
|
9
|
-
readonly y: Schema.Finite;
|
|
10
|
-
}>;
|
|
11
|
-
export type Point = typeof Point.Type;
|
|
12
|
-
export declare const Sample: Schema.Struct<{
|
|
13
|
-
readonly x: Schema.Finite;
|
|
14
|
-
readonly y: Schema.Finite;
|
|
15
|
-
readonly afterMillis: Schema.Finite;
|
|
16
|
-
}>;
|
|
17
|
-
export type Sample = typeof Sample.Type;
|
|
18
|
-
/** A complete glide: 1 to 2,048 samples whose offsets never decrease. */
|
|
19
|
-
export declare const Plan: Schema.$Array<Schema.Struct<{
|
|
20
|
-
readonly x: Schema.Finite;
|
|
21
|
-
readonly y: Schema.Finite;
|
|
22
|
-
readonly afterMillis: Schema.Finite;
|
|
23
|
-
}>>;
|
|
24
|
-
export type Plan = typeof Plan.Type;
|
|
25
|
-
export interface Service {
|
|
26
|
-
/**
|
|
27
|
-
* Offsets start when the performer publishes the plan, before its first input. The browser
|
|
28
|
-
* decodes the result as a `Plan` whose last sample must be exactly `to`. Glide time has a budget
|
|
29
|
-
* of its own, outside the browser's `actionTimeout`, so a drag may glide twice for 5 seconds.
|
|
30
|
-
*/
|
|
31
|
-
readonly plan: (from: Point, to: Point) => Effect.Effect<ReadonlyArray<Sample>>;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* The research's tuned two-stroke sigma-lognormal model: a fast stroke toward the target and a
|
|
35
|
-
* slower one that homes in on it, with a little bend, drawn from `Random`.
|
|
36
|
-
*/
|
|
37
|
-
export declare const lognormal: Service;
|
|
38
|
-
//#endregion
|
|
39
|
-
export { Motion_d_exports as t };
|
|
40
|
-
//# sourceMappingURL=Motion.d.mts.map
|
|
1
|
+
import { a as Service, c as maximumSamples, i as Sample, n as Plan, o as lognormal, r as Point, s as maximumDurationMillis } from "./Motion-DND6I-64.mjs";
|
|
2
|
+
export { Plan, Point, Sample, Service, lognormal, maximumDurationMillis, maximumSamples };
|
package/dist/Motion.mjs
CHANGED
|
@@ -22,8 +22,7 @@ const Point = Schema.Struct({
|
|
|
22
22
|
y: Schema.Finite
|
|
23
23
|
});
|
|
24
24
|
const Sample = Schema.Struct({
|
|
25
|
-
|
|
26
|
-
y: Schema.Finite,
|
|
25
|
+
...Point.fields,
|
|
27
26
|
afterMillis: Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(maximumDurationMillis))
|
|
28
27
|
});
|
|
29
28
|
/** A complete glide: 1 to 2,048 samples whose offsets never decrease. */
|
package/dist/Motion.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Motion.mjs","names":[],"sources":["../src/Motion.ts"],"sourcesContent":["/**\n * Pointer motion as a complete, bounded schedule, independent of browser input and transport. A\n * presenter takes a planner as a value: `lognormal` here, or another, such as recorded strokes.\n *\n * @since 0.3.0\n */\nimport { Effect, Random, Schema } from \"effect\";\n\nexport const maximumSamples = 2048;\nexport const maximumDurationMillis = 5000;\n\nexport const Point = Schema.Struct({ x: Schema.Finite, y: Schema.Finite });\nexport type Point = typeof Point.Type;\n\nexport const Sample = Schema.Struct({\n x: Schema.Finite,\n y: Schema.Finite,\n afterMillis: Schema.Finite.check(\n Schema.isGreaterThanOrEqualTo(0),\n Schema.isLessThanOrEqualTo(maximumDurationMillis),\n ),\n});\n\nexport type Sample = typeof Sample.Type;\n\n/** A complete glide: 1 to 2,048 samples whose offsets never decrease. */\nexport const Plan = Schema.Array(Sample).check(\n Schema.isBetweenLength(1, maximumSamples),\n Schema.makeFilter(\n (samples) =>\n samples.every(\n (sample, index) => sample.afterMillis >= (samples[index - 1]?.afterMillis ?? 0),\n ),\n { expected: \"nondecreasing sample offsets\" },\n ),\n);\n\nexport type Plan = typeof Plan.Type;\n\nexport interface Service {\n /**\n * Offsets start when the performer publishes the plan, before its first input. The browser\n * decodes the result as a `Plan` whose last sample must be exactly `to`. Glide time has a budget\n * of its own, outside the browser's `actionTimeout`, so a drag may glide twice for 5 seconds.\n */\n readonly plan: (from: Point, to: Point) => Effect.Effect<ReadonlyArray<Sample>>;\n}\n\n// These are the research's tuned two-stroke parameters. Width scaling was not evaluated, so the\n// model keeps its 40px reference width rather than implying measured target-size behavior.\nconst tuning = {\n intercept: 115.8,\n slope: 291.8,\n durationSigma: 0.407,\n amplitude: 0.989,\n amplitudeSigma: 0.138,\n lateral: 0.0934,\n primaryDuration: 0.512,\n correctionDuration: 0.586,\n overlap: 0.452,\n sigmaLow: 0.155,\n sigmaHigh: 0.53,\n} as const;\n\nconst sampleMillis = 16.7;\n\nconst normal = Effect.gen(function* () {\n const radius = Math.sqrt(-2 * Math.log(1 - (yield* Random.next)));\n\n return radius * Math.cos(2 * Math.PI * (yield* Random.next));\n});\n\n// Abramowitz-Stegun 7.1.26 supplies erf without another runtime dependency (error < 1.5e-7).\nconst erf = (value: number) => {\n const x = Math.abs(value);\n const t = 1 / (1 + 0.3275911 * x);\n\n const polynomial =\n ((((1.061405429 * t - 1.453152027) * t + 1.421413741) * t - 0.284496736) * t + 0.254829592) * t;\n\n return Math.sign(value) * (1 - polynomial * Math.exp(-x * x));\n};\n\nconst cumulative = (time: number, onset: number, mu: number, sigma: number) =>\n time <= onset ? 0 : (1 + erf((Math.log(time - onset) - mu) / (sigma * Math.SQRT2))) / 2;\n\nconst plan: Service[\"plan\"] = Effect.fnUntraced(function* (from, to) {\n // Work in normalized coordinates so finite extreme inputs cannot overflow the displacement.\n const scale = Math.max(1, Math.abs(from.x), Math.abs(from.y), Math.abs(to.x), Math.abs(to.y));\n const startX = from.x / scale;\n const startY = from.y / scale;\n const deltaX = to.x / scale - startX;\n const deltaY = to.y / scale - startY;\n const distance = Math.hypot(deltaX, deltaY);\n\n if (distance * scale < 2) return [{ ...to, afterMillis: 0 }];\n const unitX = deltaX / distance;\n const unitY = deltaY / distance;\n\n const drawnDuration =\n (tuning.intercept + tuning.slope * Math.log2(1 + distance * (scale / 40))) *\n Math.exp((yield* normal) * tuning.durationSigma);\n\n const endFactor = Math.max(\n tuning.primaryDuration,\n tuning.overlap * tuning.primaryDuration + tuning.correctionDuration,\n );\n\n // Bound the duration before evaluating either stroke: dropping a sampled tail would remove\n // its homing correction. The last regular 16.7ms sample remains inside the public time bound.\n const lastRegularSample = Math.floor(maximumDurationMillis / sampleMillis) * sampleMillis;\n const duration = Math.min(drawnDuration, lastRegularSample / endFactor);\n const amplitude = distance * (tuning.amplitude + (yield* normal) * tuning.amplitudeSigma);\n const angle = ((yield* normal) * Math.PI) / 60;\n const primaryX = amplitude * (unitX * Math.cos(angle) - unitY * Math.sin(angle));\n const primaryY = amplitude * (unitY * Math.cos(angle) + unitX * Math.sin(angle));\n const sigma1 = yield* Random.nextBetween(tuning.sigmaLow, tuning.sigmaHigh);\n const primaryDuration = tuning.primaryDuration * duration;\n const mu1 = Math.log(primaryDuration / (Math.exp(3 * sigma1) - Math.exp(-3 * sigma1)));\n const onset1 = -Math.exp(mu1 - 3 * sigma1);\n const sigma2 = yield* Random.nextBetween(tuning.sigmaLow, tuning.sigmaHigh);\n const correctionDuration = tuning.correctionDuration * duration;\n const mu2 = Math.log(correctionDuration / (Math.exp(3 * sigma2) - Math.exp(-3 * sigma2)));\n const onset2 = tuning.overlap * primaryDuration - Math.exp(mu2 - 3 * sigma2);\n const end = Math.max(primaryDuration, onset2 + Math.exp(mu2 + 3 * sigma2));\n const centered = Math.max(Number.EPSILON, yield* Random.next) - 0.5;\n\n const lateral =\n -tuning.lateral * Math.sign(centered) * Math.log(1 - 2 * Math.abs(centered)) * distance;\n\n const count = Math.min(\n Math.ceil(end / sampleMillis),\n Math.floor(lastRegularSample / sampleMillis),\n );\n\n const samples: Array<Sample> = [];\n let last: Point = from;\n\n const coordinate = (value: number) =>\n Math.round(Math.max(-Number.MAX_VALUE, Math.min(Number.MAX_VALUE, value * scale)));\n\n for (let index = 0; index < count; index++) {\n const afterMillis = index * sampleMillis;\n const first = cumulative(afterMillis, onset1, mu1, sigma1);\n const second = cumulative(afterMillis, onset2, mu2, sigma2);\n const bend = lateral * Math.sin(Math.PI * first);\n const x = coordinate(startX + primaryX * first + (deltaX - primaryX) * second - unitY * bend);\n const y = coordinate(startY + primaryY * first + (deltaY - primaryY) * second + unitX * bend);\n\n // A pointer that stays on its pixel reports nothing; the model's timing is unchanged.\n if (x === last.x && y === last.y) continue;\n last = { x, y };\n samples.push({ x, y, afterMillis });\n }\n\n // The exact destination always lands at the model's end, even if a dwell precedes it.\n samples.push({ ...to, afterMillis: count * sampleMillis });\n\n return samples;\n});\n\n/**\n * The research's tuned two-stroke sigma-lognormal model: a fast stroke toward the target and a\n * slower one that homes in on it, with a little bend, drawn from `Random`.\n */\nexport const lognormal: Service = { plan };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Motion.mjs","names":[],"sources":["../src/Motion.ts"],"sourcesContent":["/**\n * Pointer motion as a complete, bounded schedule, independent of browser input and transport. A\n * presenter takes a planner as a value: `lognormal` here, or another, such as recorded strokes.\n *\n * @since 0.3.0\n */\nimport { Effect, Random, Schema } from \"effect\";\n\nexport const maximumSamples = 2048;\nexport const maximumDurationMillis = 5000;\n\nexport const Point = Schema.Struct({ x: Schema.Finite, y: Schema.Finite });\nexport type Point = typeof Point.Type;\n\nexport const Sample = Schema.Struct({\n ...Point.fields,\n afterMillis: Schema.Finite.check(\n Schema.isGreaterThanOrEqualTo(0),\n Schema.isLessThanOrEqualTo(maximumDurationMillis),\n ),\n});\n\nexport type Sample = typeof Sample.Type;\n\n/** A complete glide: 1 to 2,048 samples whose offsets never decrease. */\nexport const Plan = Schema.Array(Sample).check(\n Schema.isBetweenLength(1, maximumSamples),\n Schema.makeFilter(\n (samples) =>\n samples.every(\n (sample, index) => sample.afterMillis >= (samples[index - 1]?.afterMillis ?? 0),\n ),\n { expected: \"nondecreasing sample offsets\" },\n ),\n);\n\nexport type Plan = typeof Plan.Type;\n\nexport interface Service {\n /**\n * Offsets start when the performer publishes the plan, before its first input. The browser\n * decodes the result as a `Plan` whose last sample must be exactly `to`. Glide time has a budget\n * of its own, outside the browser's `actionTimeout`, so a drag may glide twice for 5 seconds.\n */\n readonly plan: (from: Point, to: Point) => Effect.Effect<ReadonlyArray<Sample>>;\n}\n\n// These are the research's tuned two-stroke parameters. Width scaling was not evaluated, so the\n// model keeps its 40px reference width rather than implying measured target-size behavior.\nconst tuning = {\n intercept: 115.8,\n slope: 291.8,\n durationSigma: 0.407,\n amplitude: 0.989,\n amplitudeSigma: 0.138,\n lateral: 0.0934,\n primaryDuration: 0.512,\n correctionDuration: 0.586,\n overlap: 0.452,\n sigmaLow: 0.155,\n sigmaHigh: 0.53,\n} as const;\n\nconst sampleMillis = 16.7;\n\nconst normal = Effect.gen(function* () {\n const radius = Math.sqrt(-2 * Math.log(1 - (yield* Random.next)));\n\n return radius * Math.cos(2 * Math.PI * (yield* Random.next));\n});\n\n// Abramowitz-Stegun 7.1.26 supplies erf without another runtime dependency (error < 1.5e-7).\nconst erf = (value: number) => {\n const x = Math.abs(value);\n const t = 1 / (1 + 0.3275911 * x);\n\n const polynomial =\n ((((1.061405429 * t - 1.453152027) * t + 1.421413741) * t - 0.284496736) * t + 0.254829592) * t;\n\n return Math.sign(value) * (1 - polynomial * Math.exp(-x * x));\n};\n\nconst cumulative = (time: number, onset: number, mu: number, sigma: number) =>\n time <= onset ? 0 : (1 + erf((Math.log(time - onset) - mu) / (sigma * Math.SQRT2))) / 2;\n\nconst plan: Service[\"plan\"] = Effect.fnUntraced(function* (from, to) {\n // Work in normalized coordinates so finite extreme inputs cannot overflow the displacement.\n const scale = Math.max(1, Math.abs(from.x), Math.abs(from.y), Math.abs(to.x), Math.abs(to.y));\n const startX = from.x / scale;\n const startY = from.y / scale;\n const deltaX = to.x / scale - startX;\n const deltaY = to.y / scale - startY;\n const distance = Math.hypot(deltaX, deltaY);\n\n if (distance * scale < 2) return [{ ...to, afterMillis: 0 }];\n const unitX = deltaX / distance;\n const unitY = deltaY / distance;\n\n const drawnDuration =\n (tuning.intercept + tuning.slope * Math.log2(1 + distance * (scale / 40))) *\n Math.exp((yield* normal) * tuning.durationSigma);\n\n const endFactor = Math.max(\n tuning.primaryDuration,\n tuning.overlap * tuning.primaryDuration + tuning.correctionDuration,\n );\n\n // Bound the duration before evaluating either stroke: dropping a sampled tail would remove\n // its homing correction. The last regular 16.7ms sample remains inside the public time bound.\n const lastRegularSample = Math.floor(maximumDurationMillis / sampleMillis) * sampleMillis;\n const duration = Math.min(drawnDuration, lastRegularSample / endFactor);\n const amplitude = distance * (tuning.amplitude + (yield* normal) * tuning.amplitudeSigma);\n const angle = ((yield* normal) * Math.PI) / 60;\n const primaryX = amplitude * (unitX * Math.cos(angle) - unitY * Math.sin(angle));\n const primaryY = amplitude * (unitY * Math.cos(angle) + unitX * Math.sin(angle));\n const sigma1 = yield* Random.nextBetween(tuning.sigmaLow, tuning.sigmaHigh);\n const primaryDuration = tuning.primaryDuration * duration;\n const mu1 = Math.log(primaryDuration / (Math.exp(3 * sigma1) - Math.exp(-3 * sigma1)));\n const onset1 = -Math.exp(mu1 - 3 * sigma1);\n const sigma2 = yield* Random.nextBetween(tuning.sigmaLow, tuning.sigmaHigh);\n const correctionDuration = tuning.correctionDuration * duration;\n const mu2 = Math.log(correctionDuration / (Math.exp(3 * sigma2) - Math.exp(-3 * sigma2)));\n const onset2 = tuning.overlap * primaryDuration - Math.exp(mu2 - 3 * sigma2);\n const end = Math.max(primaryDuration, onset2 + Math.exp(mu2 + 3 * sigma2));\n const centered = Math.max(Number.EPSILON, yield* Random.next) - 0.5;\n\n const lateral =\n -tuning.lateral * Math.sign(centered) * Math.log(1 - 2 * Math.abs(centered)) * distance;\n\n const count = Math.min(\n Math.ceil(end / sampleMillis),\n Math.floor(lastRegularSample / sampleMillis),\n );\n\n const samples: Array<Sample> = [];\n let last: Point = from;\n\n const coordinate = (value: number) =>\n Math.round(Math.max(-Number.MAX_VALUE, Math.min(Number.MAX_VALUE, value * scale)));\n\n for (let index = 0; index < count; index++) {\n const afterMillis = index * sampleMillis;\n const first = cumulative(afterMillis, onset1, mu1, sigma1);\n const second = cumulative(afterMillis, onset2, mu2, sigma2);\n const bend = lateral * Math.sin(Math.PI * first);\n const x = coordinate(startX + primaryX * first + (deltaX - primaryX) * second - unitY * bend);\n const y = coordinate(startY + primaryY * first + (deltaY - primaryY) * second + unitX * bend);\n\n // A pointer that stays on its pixel reports nothing; the model's timing is unchanged.\n if (x === last.x && y === last.y) continue;\n last = { x, y };\n samples.push({ x, y, afterMillis });\n }\n\n // The exact destination always lands at the model's end, even if a dwell precedes it.\n samples.push({ ...to, afterMillis: count * sampleMillis });\n\n return samples;\n});\n\n/**\n * The research's tuned two-stroke sigma-lognormal model: a fast stroke toward the target and a\n * slower one that homes in on it, with a little bend, drawn from `Random`.\n */\nexport const lognormal: Service = { plan };\n"],"mappings":";;;;;;;;;;;;;;;;;AAQA,MAAa,iBAAiB;AAC9B,MAAa,wBAAwB;AAErC,MAAa,QAAQ,OAAO,OAAO;CAAE,GAAG,OAAO;CAAQ,GAAG,OAAO;AAAO,CAAC;AAGzE,MAAa,SAAS,OAAO,OAAO;CAClC,GAAG,MAAM;CACT,aAAa,OAAO,OAAO,MACzB,OAAO,uBAAuB,CAAC,GAC/B,OAAO,oBAAoB,qBAAqB,CAClD;AACF,CAAC;;AAKD,MAAa,OAAO,OAAO,MAAM,MAAM,CAAC,CAAC,MACvC,OAAO,gBAAgB,GAAG,cAAc,GACxC,OAAO,YACJ,YACC,QAAQ,OACL,QAAQ,UAAU,OAAO,gBAAgB,QAAQ,QAAQ,EAAE,EAAE,eAAe,EAC/E,GACF,EAAE,UAAU,+BAA+B,CAC7C,CACF;AAeA,MAAM,SAAS;CACb,WAAW;CACX,OAAO;CACP,eAAe;CACf,WAAW;CACX,gBAAgB;CAChB,SAAS;CACT,iBAAiB;CACjB,oBAAoB;CACpB,SAAS;CACT,UAAU;CACV,WAAW;AACb;AAEA,MAAM,eAAe;AAErB,MAAM,SAAS,OAAO,IAAI,aAAa;CAGrC,OAFe,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,OAAO,OAAO,KAAK,CAEnD,IAAI,KAAK,IAAI,IAAI,KAAK,MAAM,OAAO,OAAO,KAAK;AAC7D,CAAC;AAGD,MAAM,OAAO,UAAkB;CAC7B,MAAM,IAAI,KAAK,IAAI,KAAK;CACxB,MAAM,IAAI,KAAK,IAAI,WAAY;CAE/B,MAAM,iBACA,cAAc,IAAI,eAAe,IAAI,eAAe,IAAI,cAAe,IAAI,cAAe;CAEhG,OAAO,KAAK,KAAK,KAAK,KAAK,IAAI,aAAa,KAAK,IAAI,CAAC,IAAI,CAAC;AAC7D;AAEA,MAAM,cAAc,MAAc,OAAe,IAAY,UAC3D,QAAQ,QAAQ,KAAK,IAAI,KAAK,KAAK,IAAI,OAAO,KAAK,IAAI,OAAO,QAAQ,KAAK,MAAM,KAAK;;;;;AAiFxF,MAAa,YAAqB,EAAE,MA/EN,OAAO,WAAW,WAAW,MAAM,IAAI;CAEnE,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;CAC5F,MAAM,SAAS,KAAK,IAAI;CACxB,MAAM,SAAS,KAAK,IAAI;CACxB,MAAM,SAAS,GAAG,IAAI,QAAQ;CAC9B,MAAM,SAAS,GAAG,IAAI,QAAQ;CAC9B,MAAM,WAAW,KAAK,MAAM,QAAQ,MAAM;CAE1C,IAAI,WAAW,QAAQ,GAAG,OAAO,CAAC;EAAE,GAAG;EAAI,aAAa;CAAE,CAAC;CAC3D,MAAM,QAAQ,SAAS;CACvB,MAAM,QAAQ,SAAS;CAEvB,MAAM,iBACH,OAAO,YAAY,OAAO,QAAQ,KAAK,KAAK,IAAI,YAAY,QAAQ,GAAG,KACxE,KAAK,KAAK,OAAO,UAAU,OAAO,aAAa;CAEjD,MAAM,YAAY,KAAK,IACrB,OAAO,iBACP,OAAO,UAAU,OAAO,kBAAkB,OAAO,kBACnD;CAIA,MAAM,oBAAoB,KAAK,MAAM,wBAAwB,YAAY,IAAI;CAC7E,MAAM,WAAW,KAAK,IAAI,eAAe,oBAAoB,SAAS;CACtE,MAAM,YAAY,YAAY,OAAO,aAAa,OAAO,UAAU,OAAO;CAC1E,MAAM,SAAU,OAAO,UAAU,KAAK,KAAM;CAC5C,MAAM,WAAW,aAAa,QAAQ,KAAK,IAAI,KAAK,IAAI,QAAQ,KAAK,IAAI,KAAK;CAC9E,MAAM,WAAW,aAAa,QAAQ,KAAK,IAAI,KAAK,IAAI,QAAQ,KAAK,IAAI,KAAK;CAC9E,MAAM,SAAS,OAAO,OAAO,YAAY,OAAO,UAAU,OAAO,SAAS;CAC1E,MAAM,kBAAkB,OAAO,kBAAkB;CACjD,MAAM,MAAM,KAAK,IAAI,mBAAmB,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,MAAM,EAAE;CACrF,MAAM,SAAS,CAAC,KAAK,IAAI,MAAM,IAAI,MAAM;CACzC,MAAM,SAAS,OAAO,OAAO,YAAY,OAAO,UAAU,OAAO,SAAS;CAC1E,MAAM,qBAAqB,OAAO,qBAAqB;CACvD,MAAM,MAAM,KAAK,IAAI,sBAAsB,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,MAAM,EAAE;CACxF,MAAM,SAAS,OAAO,UAAU,kBAAkB,KAAK,IAAI,MAAM,IAAI,MAAM;CAC3E,MAAM,MAAM,KAAK,IAAI,iBAAiB,SAAS,KAAK,IAAI,MAAM,IAAI,MAAM,CAAC;CACzE,MAAM,WAAW,KAAK,IAAI,OAAO,SAAS,OAAO,OAAO,IAAI,IAAI;CAEhE,MAAM,UACJ,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,QAAQ,CAAC,IAAI;CAEjF,MAAM,QAAQ,KAAK,IACjB,KAAK,KAAK,MAAM,YAAY,GAC5B,KAAK,MAAM,oBAAoB,YAAY,CAC7C;CAEA,MAAM,UAAyB,CAAC;CAChC,IAAI,OAAc;CAElB,MAAM,cAAc,UAClB,KAAK,MAAM,KAAK,IAAI,CAAC,OAAO,WAAW,KAAK,IAAI,OAAO,WAAW,QAAQ,KAAK,CAAC,CAAC;CAEnF,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,SAAS;EAC1C,MAAM,cAAc,QAAQ;EAC5B,MAAM,QAAQ,WAAW,aAAa,QAAQ,KAAK,MAAM;EACzD,MAAM,SAAS,WAAW,aAAa,QAAQ,KAAK,MAAM;EAC1D,MAAM,OAAO,UAAU,KAAK,IAAI,KAAK,KAAK,KAAK;EAC/C,MAAM,IAAI,WAAW,SAAS,WAAW,SAAS,SAAS,YAAY,SAAS,QAAQ,IAAI;EAC5F,MAAM,IAAI,WAAW,SAAS,WAAW,SAAS,SAAS,YAAY,SAAS,QAAQ,IAAI;EAG5F,IAAI,MAAM,KAAK,KAAK,MAAM,KAAK,GAAG;EAClC,OAAO;GAAE;GAAG;EAAE;EACd,QAAQ,KAAK;GAAE;GAAG;GAAG;EAAY,CAAC;CACpC;CAGA,QAAQ,KAAK;EAAE,GAAG;EAAI,aAAa,QAAQ;CAAa,CAAC;CAEzD,OAAO;AACT,CAMoC,EAAK"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { Point } from "./Motion.mjs";
|
|
3
|
+
import { Box, PageLoaded, Subject } from "./BrowserEvent.mjs";
|
|
3
4
|
import { c as FailFast, o as withheld, s as Correlation } from "./url-Cd04Okid.mjs";
|
|
4
5
|
import { Frame, Image } from "./Frame.mjs";
|
|
5
6
|
import { Effect, Schema } from "effect";
|
|
@@ -402,6 +403,7 @@ const PreparedInputResultSchema = Schema.Union([Schema.Struct({
|
|
|
402
403
|
name: Schema.String,
|
|
403
404
|
cursor: Schema.String,
|
|
404
405
|
href: Schema.optional(Schema.String),
|
|
406
|
+
/** A field the DOM marks as holding a password, a one-time code or a card's details. */
|
|
405
407
|
secret: Schema.Boolean,
|
|
406
408
|
fingerprint: Schema.String
|
|
407
409
|
}))),
|
|
@@ -458,16 +460,9 @@ var Zoom = class extends Schema.Class("effect-browser/Zoom")({
|
|
|
458
460
|
}) {};
|
|
459
461
|
/** The target as it read before input. Point coordinates are never snapped to another position. */
|
|
460
462
|
var ResolvedTarget = class extends Schema.Class("effect-browser/ResolvedTarget")({
|
|
461
|
-
point:
|
|
462
|
-
|
|
463
|
-
y: Schema.Finite
|
|
464
|
-
}),
|
|
463
|
+
point: Point,
|
|
464
|
+
...Subject.fields,
|
|
465
465
|
element: Schema.String,
|
|
466
|
-
/** The element's lowercase tag name. */
|
|
467
|
-
tag: Schema.String,
|
|
468
|
-
role: Schema.NullOr(Schema.String),
|
|
469
|
-
name: Schema.String,
|
|
470
|
-
context: SubjectContext,
|
|
471
466
|
/** For a point target, the box of what it found there. */
|
|
472
467
|
box: Schema.optional(Box),
|
|
473
468
|
cursor: Schema.String,
|
|
@@ -568,10 +563,7 @@ var InputRequest = class extends Schema.Class("effect-browser/InputRequest")({
|
|
|
568
563
|
target: Schema.optional(Schema.String),
|
|
569
564
|
element: Schema.optional(Schema.String),
|
|
570
565
|
/** Literal pixel targets only; ref coordinates are resolved after the policy allows them. */
|
|
571
|
-
point: Schema.optional(
|
|
572
|
-
x: Schema.Finite,
|
|
573
|
-
y: Schema.Finite
|
|
574
|
-
})),
|
|
566
|
+
point: Schema.optional(Point),
|
|
575
567
|
text: Schema.optional(Schema.String),
|
|
576
568
|
role: Schema.optional(Schema.NullOr(Schema.String)),
|
|
577
569
|
name: Schema.optional(Schema.String),
|
|
@@ -615,4 +607,4 @@ const correlate = (id) => (effect) => Effect.provideService(effect, Correlation,
|
|
|
615
607
|
//#endregion
|
|
616
608
|
export { evidence as _, Page_exports as a, State as c, correlate as d, failFast as f, guard as g, ValidatedInputResultSchema as h, InputRequest as i, Text as l, PreparedInputResultSchema as m, Fact as n, Region as o, redacted as p, Found as r, ResolvedTarget as s, ElementState as t, Zoom as u };
|
|
617
609
|
|
|
618
|
-
//# sourceMappingURL=Page-
|
|
610
|
+
//# sourceMappingURL=Page-CfB6Zn1p.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Page-CfB6Zn1p.mjs","names":["Fact","Motion.Point","Guard.Fact","Url.withheld"],"sources":["../src/internal/input/evidence.inpage.ts","../src/internal/input/guard.inpage.ts","../src/Page.ts"],"sourcesContent":["/**\n * In the page: what the page says about an input's first target, for a judge, and which fields a\n * form would send. It never reads what a field holds. See `reading/names.inpage.ts` for what a page-side part may use.\n */\nimport { Schema } from \"effect\";\n\nimport type { ContextReader } from \"../reading/context.inpage.ts\";\nimport type { Names } from \"../reading/names.inpage.ts\";\n\n/** Page text about the first target. It never includes what a field holds. */\nexport type Evidence = typeof EvidenceSchema.Encoded;\n\ntype Field = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\n\nexport const evidence = (names: Names, placing: ContextReader) => {\n const { clean, isDocument, isInput, isSelect, isTextArea, nameOf, parentOf, roleOf, textOf } =\n names;\n\n const { groups, headingBefore, textBeside, treeOf } = placing;\n\n /** A field a submission would send. */\n const isField = (element: Element): element is Field =>\n ((isInput(element) && ![\"button\", \"submit\", \"reset\", \"image\"].includes(element.type)) ||\n isSelect(element) ||\n isTextArea(element)) &&\n !element.matches(\":disabled\");\n\n const isFilled = (field: Field): boolean =>\n isInput(field) && (field.type === \"checkbox\" || field.type === \"radio\")\n ? field.checked\n : isInput(field) && field.type === \"file\"\n ? (field.files?.length ?? 0) > 0\n : field.value !== \"\";\n\n const dialogOf = (element: Element): Element | undefined => {\n for (let node: Element | null = element; node !== null; node = parentOf(node))\n if (node.tagName === \"DIALOG\" || /^(?:alert)?dialog$/.test(node.getAttribute(\"role\") ?? \"\"))\n return node;\n\n return undefined;\n };\n\n /** What the page says about an input's first target, for a judge. Never a field's value. */\n const evidenceOf = (\n element: Element,\n form: HTMLFormElement | null,\n method: string | undefined,\n action: string | undefined,\n ): Evidence => {\n const name = nameOf(element, roleOf(element));\n const ids = element.getAttribute(\"aria-describedby\");\n\n const description = clean(\n ids === null\n ? (element.getAttribute(\"aria-description\") ?? element.getAttribute(\"title\"))\n : ids\n .split(/\\s+/)\n .map((id) => element.ownerDocument.getElementById(id)?.textContent ?? \"\")\n .join(\" \"),\n 120,\n );\n\n const dialog = dialogOf(element);\n\n const title = dialog?.querySelector(\"h1,h2,h3,h4,h5,h6,[role=heading]\");\n\n const dialogName =\n dialog === undefined\n ? \"\"\n : clean(nameOf(dialog, \"dialog\"), 120) ||\n (title === null || title === undefined ? \"\" : clean(textOf(title), 120));\n\n // Each scope stays in the target's own tree: a walker cannot leave a shadow root.\n const root = element.getRootNode();\n const top = isDocument(root) ? (root.body ?? root) : root;\n const inTree = element.closest(\"dialog,[role=dialog],[role=alertdialog]\");\n let nearby = \"\";\n\n for (const scope of new Set([element.closest(groups), inTree, top]))\n if (scope !== null && nearby === \"\")\n nearby = textBeside(element, scope, true) || textBeside(element, scope, false);\n\n const heading = headingBefore(element, treeOf(element));\n\n const fields =\n form === null\n ? []\n : Array.from(form.elements)\n .filter(isField)\n .slice(0, 16)\n .map((field) => {\n const autocomplete = clean(field.getAttribute(\"autocomplete\"), 40);\n\n return {\n type: isInput(field) ? field.type : field.tagName.toLowerCase(),\n name: clean(\n isInput(field) && field.type === \"hidden\"\n ? field.getAttribute(\"name\")\n : nameOf(field, roleOf(field)),\n 40,\n ),\n ...(autocomplete === \"\" ? {} : { autocomplete }),\n filled: isFilled(field),\n };\n });\n\n return {\n title: clean(document.title, 120),\n ...(description === \"\" || description === name ? {} : { description }),\n ...(dialogName === \"\" ? {} : { dialog: dialogName }),\n ...(heading === undefined ? {} : { heading }),\n ...(nearby === \"\" ? {} : { nearby }),\n ...(form === null\n ? {}\n : { form: { method: method ?? form.method, action: action ?? form.action, fields } }),\n };\n };\n\n return { evidenceOf, isField, isFilled };\n};\n\nexport type EvidenceReader = ReturnType<typeof evidence>;\n\nexport const FormFieldSchema = Schema.Struct({\n type: Schema.String,\n name: Schema.String,\n autocomplete: Schema.optional(Schema.String),\n filled: Schema.Boolean,\n});\n\nexport const EvidenceSchema = Schema.Struct({\n title: Schema.String,\n description: Schema.optional(Schema.String),\n dialog: Schema.optional(Schema.String),\n heading: Schema.optional(Schema.String),\n nearby: Schema.optional(Schema.String),\n form: Schema.optional(\n Schema.Struct({\n method: Schema.String,\n action: Schema.String,\n fields: Schema.Array(FormFieldSchema),\n }),\n ),\n});\n","/**\n * In the page: what the input guard decides on. It inspects an input's targets for the facts a\n * policy weighs, such as a form submission or a secret field, binds an approval to them, and\n * checks before each press that the approved target would still receive it. See `reading/names.inpage.ts` for what a page-side part may use.\n */\nimport { Schema } from \"effect\";\n\nimport type { Point } from \"../../Motion.ts\";\nimport type { Names } from \"../reading/names.inpage.ts\";\nimport { type Evidence, type EvidenceReader, EvidenceSchema } from \"./evidence.inpage.ts\";\nimport type { Targets } from \"./targets.inpage.ts\";\n\nexport const Fact = Schema.Literals([\n \"form-submit\",\n \"cross-origin\",\n \"download\",\n \"upload\",\n \"secret\",\n \"scripted\",\n \"opaque\",\n]);\n\nexport type Fact = typeof Fact.Type;\n\nexport interface InputPlan {\n readonly action: string;\n readonly targets: ReadonlyArray<string | Point | null>;\n readonly submit: boolean;\n readonly keys: string | null;\n readonly destination: string | null;\n}\n\nexport type InspectedTarget = NonNullable<PreparedInput[\"targets\"][number]>;\n\nexport type PreparedInput = Exclude<PreparedInputResult, InputFailure>;\n\n/** A refusal; a stale target is named by its index in the plan. */\nexport type InputFailure = typeof InputPreparationError.Encoded;\n\nexport type PreparedInputResult = typeof PreparedInputResultSchema.Encoded;\n\nexport type ValidatedInputResult = typeof ValidatedInputResultSchema.Encoded;\n\n/** A point where a target, by its index in the plan, is about to receive a press. */\nexport interface Press extends Point {\n readonly index: number;\n}\n\nexport interface ValidationOptions {\n /** Require focus on the first target. */\n readonly focused?: boolean;\n /** After the pointer's own events have run, each target must still receive its press. */\n readonly presses?: ReadonlyArray<Press>;\n}\n\nexport const guard = (names: Names, targets: Targets, evidence: EvidenceReader) => {\n const {\n activeElement,\n clean,\n describe,\n inCurrentDocument,\n interactiveRoles,\n isButton,\n isDisabled,\n isHtml,\n isInput,\n isLabel,\n isRoot,\n isSecret,\n isSelect,\n isTextArea,\n lookup,\n parentOf,\n refFor,\n roleOf,\n } = names;\n\n const { controlOf, details, hitAt, hrefAttribute, linkOf, receives, within } = targets;\n const { evidenceOf, isField, isFilled } = evidence;\n\n /**\n * The element whose activation behaviour a click or key on `element` runs, as the browser\n * resolves it along the composed path: a link, button, input, summary or a label's control.\n */\n const activationTarget = (element: Element): Element | undefined => {\n for (let node: Element | null = element; node !== null; node = parentOf(node)) {\n if (\n hrefAttribute(node) !== null ||\n node.tagName === \"BUTTON\" ||\n node.tagName === \"SUMMARY\" ||\n (isInput(node) && node.type !== \"hidden\")\n )\n return node;\n if (isLabel(node) && node.control !== null) return node.control;\n }\n\n return undefined;\n };\n\n /**\n * A control between a press's hit and the approved target that is not the target's own\n * activation, such as a link or button a hover handler nested into it. The approval inspected\n * the target, so that control would act unapproved.\n */\n const nestedControl = (element: Element, hit: Element): Element | undefined => {\n // A container of the target is covered by the target's own facts.\n if (!within(element, hit)) return undefined;\n const own = activationTarget(element);\n\n for (\n let node: Element | null = hit;\n node !== null && node !== element;\n node = parentOf(node) ?? node.ownerDocument.defaultView?.frameElement ?? null\n )\n if (\n node !== own &&\n (hrefAttribute(node) !== null ||\n node.tagName === \"BUTTON\" ||\n node.tagName === \"SUMMARY\" ||\n (isInput(node) && node.type !== \"hidden\") ||\n isSelect(node) ||\n isTextArea(node) ||\n (isLabel(node) && node.control !== null && node.control !== own) ||\n activatingRoles.has(roleOf(node) ?? \"\"))\n )\n return node;\n\n return undefined;\n };\n\n const textEntry = (element: Element): boolean =>\n (isInput(element) &&\n ![\n \"button\",\n \"reset\",\n \"submit\",\n \"image\",\n \"checkbox\",\n \"radio\",\n \"file\",\n \"range\",\n \"color\",\n \"hidden\",\n ].includes(element.type)) ||\n isTextArea(element) ||\n (isHtml(element) && element.isContentEditable);\n\n const activatingRoles = new Set([\n \"button\",\n \"link\",\n \"checkbox\",\n \"radio\",\n \"switch\",\n \"tab\",\n \"menuitem\",\n \"menuitemcheckbox\",\n \"menuitemradio\",\n \"option\",\n \"treeitem\",\n ]);\n\n // Typed text goes wherever focus is, and a typed space or letter can press a focused button,\n // toggle a box, follow a link or change a select. Only fields, or elements that are none of\n // these (a page or a canvas game), may receive text.\n const typingRefusal = (element: Element, explicit: boolean): string | undefined =>\n textEntry(element)\n ? undefined\n : explicit\n ? `${describe(element)} is not a text field`\n : activationTarget(element) !== undefined ||\n isSelect(element) ||\n activatingRoles.has(roleOf(element) ?? \"\")\n ? `focus is on ${describe(element)}, which typed text could activate or change; type into a text field by ref, or use press for keys`\n : undefined;\n\n const isSubmitter = (element: Element): element is HTMLButtonElement | HTMLInputElement =>\n (isButton(element) && element.type === \"submit\") ||\n (isInput(element) && (element.type === \"submit\" || element.type === \"image\"));\n\n // form.elements omits image submitters. Walk the whole root in tree order so an Enter\n // submission uses the real default button, including controls associated from outside the form.\n const defaultSubmitter = (form: HTMLFormElement) => {\n const root = form.getRootNode();\n\n return isRoot(root)\n ? Array.from(root.querySelectorAll(\"button,input\")).find(\n (candidate): candidate is HTMLButtonElement | HTMLInputElement =>\n isSubmitter(candidate) && candidate.form === form,\n )\n : undefined;\n };\n\n // Attributes that say what a field is for. They bind an approval.\n const purpose = (control: Element, form: HTMLFormElement | null) => [\n control.getAttribute(\"id\"),\n control.getAttribute(\"name\"),\n control.getAttribute(\"inputmode\"),\n control.getAttribute(\"autocomplete\"),\n control.getAttribute(\"aria-label\"),\n form?.getAttribute(\"id\"),\n form?.getAttribute(\"name\"),\n form?.getAttribute(\"aria-label\"),\n ];\n\n // What an approval binds of a URL. A fragment that names a place on the page, which scroll-spy\n // and feed pages rewrite as they scroll, is left out. A hash route (#/… or #!…) stays: it\n // selects what the page's controls act on.\n const boundUrl = (url: string): string => {\n const hash = url.indexOf(\"#\");\n\n return hash === -1 || /^#[/!]/.test(url.slice(hash)) ? url : url.slice(0, hash);\n };\n\n const inspectInput = (element: Element, plan: InputPlan) => {\n const metadata = details(element, element, 0, 0);\n // Facts are about what the input activates, such as the submit button around a painted label.\n const control = activationTarget(element) ?? element;\n\n const form =\n isInput(control) || isButton(control) || isTextArea(control) || isSelect(control)\n ? control.form\n : null;\n\n // The chord's last key, which may be the plus key itself: Control++.\n const key = plan.keys === null ? undefined : /(?:^|\\+)(\\+|[^+]+)$/.exec(plan.keys)?.[1];\n const enter = key === \"Enter\";\n\n const activation =\n plan.action === \"click\" || (plan.action === \"press\" && (enter || key === \"Space\"));\n\n // Enter submits a form from any input but buttons, file and color pickers, including\n // checkboxes, radios and ranges.\n const fieldEnter =\n isInput(control) &&\n ![\"button\", \"reset\", \"submit\", \"image\", \"file\", \"color\", \"hidden\"].includes(control.type) &&\n ((plan.action === \"press\" && enter) || (plan.action === \"type\" && plan.submit));\n\n const submits = form !== null && ((activation && isSubmitter(control)) || fieldEnter);\n\n const submitter = isSubmitter(control)\n ? control\n : form === null\n ? undefined\n : defaultSubmitter(form);\n\n const formDestination =\n form === null\n ? undefined\n : submitter?.hasAttribute(\"formaction\") === true\n ? submitter.formAction\n : form.action;\n\n const formMethod =\n form === null\n ? undefined\n : submitter?.hasAttribute(\"formmethod\") === true\n ? submitter.formMethod\n : form.method;\n\n const formTarget =\n form === null\n ? undefined\n : submitter?.hasAttribute(\"formtarget\") === true\n ? submitter.formTarget\n : form.target;\n\n const link = linkOf(element);\n const href = link === undefined ? null : hrefAttribute(link);\n // A dialog form only closes its dialog; the page's script decides what that means.\n const sends = submits && formMethod !== \"dialog\";\n // Only activation follows a link or opens a file chooser; hovering or scrolling over a\n // control does neither.\n const destination = sends ? formDestination : activation ? metadata.href : undefined;\n const acts = plan.action !== \"hover\" && plan.action !== \"scroll\";\n\n // What the browser itself does on activation: follow a link, submit or reset a form, choose\n // a file or a value, toggle a box or a disclosure, or focus a field. Anything else is the\n // page's script.\n const builtIn =\n sends ||\n (href !== null && !/^\\s*(?:#\\s*|javascript:[^]*)$/i.test(href)) ||\n (isInput(control) && ![\"button\", \"submit\", \"image\", \"reset\"].includes(control.type)) ||\n ((isInput(control) || isButton(control)) && control.type === \"reset\" && form !== null) ||\n control.tagName === \"SUMMARY\" ||\n control.closest(\"select\") !== null ||\n textEntry(control);\n\n const facts: Array<Fact> = [];\n\n // Facts come from structure only. What a name or the text around it says is evidence for a\n // judge, never a fact: words change meaning with context and language.\n if (sends) facts.push(\"form-submit\");\n if (activation && link?.hasAttribute(\"download\") === true) facts.push(\"download\");\n if (activation && isInput(control) && control.type === \"file\") facts.push(\"upload\");\n if (\n (plan.action === \"type\" && isSecret(control)) ||\n (sends &&\n form !== null &&\n Array.from(form.elements).some(\n (field) => isField(field) && isSecret(field) && isFilled(field),\n ))\n )\n facts.push(\"secret\");\n if (activation && !builtIn) facts.push(\"scripted\");\n if (acts && (metadata.role === \"canvas\" || metadata.role === \"iframe\" || metadata.name === \"\"))\n facts.push(\"opaque\");\n\n // Bind what decides the consequence and the control's identity. Names bind interactive\n // controls only: other text, such as a live price or a page's own text, may change freely.\n const role = metadata.role;\n\n const boundName =\n role !== null &&\n (interactiveRoles.has(role) || role === \"canvas\" || role === \"iframe\") &&\n !(isHtml(element) && element.isContentEditable)\n ? metadata.name\n : null;\n\n // A focus or scroll handler changing these attributes must not leave an old permission behind.\n const fingerprint = JSON.stringify([\n purpose(control, form),\n element.tagName,\n element.id,\n role,\n boundName,\n metadata.href,\n control === element ? null : refFor(control),\n isInput(control) || isButton(control) ? control.type : control.tagName,\n control.matches(\":disabled\") || isDisabled(control),\n control.getAttribute(\"readonly\"),\n control.getAttribute(\"aria-readonly\"),\n isHtml(control) && control.isContentEditable,\n control.getAttribute(\"name\"),\n control.getAttribute(\"accept\"),\n control.hasAttribute(\"multiple\"),\n link?.getAttribute(\"download\"),\n form === null ? null : refFor(form),\n form === null ? null : boundUrl(form.action),\n form?.method,\n form?.target,\n submitter === undefined ? null : refFor(submitter),\n formDestination === undefined ? undefined : boundUrl(formDestination),\n formMethod,\n formTarget,\n submitter?.formNoValidate,\n form?.noValidate,\n ]);\n\n const inspected: InspectedTarget = {\n ref: refFor(element),\n element: metadata.element,\n role: metadata.role,\n name: metadata.name,\n cursor: metadata.cursor,\n ...(metadata.href === undefined ? {} : { href: metadata.href }),\n secret: isSecret(control),\n fingerprint,\n };\n\n return {\n inspected,\n facts,\n destination,\n explain: () => evidenceOf(element, form, formMethod, formDestination),\n };\n };\n\n // Approval preparation only reads the DOM. In particular, an offscreen ref must not scroll\n // before the policy has had a chance to deny it.\n const inspect = (\n plan: InputPlan,\n ): (Omit<PreparedInput, \"evidence\"> & { readonly explain: () => Evidence }) | InputFailure => {\n const targets: Array<InspectedTarget | null> = [];\n const facts = new Set<Fact>();\n let destination = plan.destination ?? undefined;\n let explain = (): Evidence => ({ title: clean(document.title, 120) });\n\n for (const [index, target] of plan.targets.entries()) {\n let element: Element | null | undefined;\n\n if (target === null) {\n element = activeElement();\n } else if (typeof target === \"string\") {\n element = lookup(target);\n if (element === undefined)\n return { error: \"stale\", detail: target + \" is not on the page any more\", index };\n } else {\n if (\n !Number.isFinite(target.x) ||\n !Number.isFinite(target.y) ||\n target.x < 0 ||\n target.y < 0 ||\n target.x >= window.innerWidth ||\n target.y >= window.innerHeight\n )\n return { error: \"outside\", detail: \"the point is outside the viewport\" };\n const hit = hitAt(document, target.x, target.y);\n\n element = hit === null ? null : controlOf(hit);\n if (element === null)\n return { error: \"offscreen\", detail: \"nothing is painted at the point\" };\n }\n\n if (element === null) {\n targets.push(null);\n continue;\n }\n if (!inCurrentDocument(element))\n return { error: \"stale\", detail: \"the input target belongs to a replaced document\", index };\n const refusal = plan.action === \"type\" ? typingRefusal(element, target !== null) : undefined;\n\n if (refusal !== undefined) return { error: \"untypeable\", detail: refusal };\n const inspected = inspectInput(element, plan);\n\n if (index === 0) explain = inspected.explain;\n targets.push(inspected.inspected);\n for (const fact of inspected.facts) facts.add(fact);\n destination ??= inspected.destination;\n if (inspected.destination !== undefined) {\n try {\n if (new URL(inspected.destination, location.href).origin !== location.origin)\n facts.add(\"cross-origin\");\n } catch {\n return { error: \"outside\", detail: \"the input destination is not a valid URL\" };\n }\n }\n }\n\n if (destination !== undefined) {\n try {\n destination = new URL(destination, location.href).href;\n if (new URL(destination).origin !== location.origin) facts.add(\"cross-origin\");\n } catch {\n return { error: \"outside\", detail: \"the input destination is not a valid URL\" };\n }\n }\n\n return {\n url: boundUrl(location.href),\n targets,\n facts: [...facts],\n ...(destination === undefined ? {} : { destination }),\n explain,\n };\n };\n\n // Evidence is read once, for the policy. Validation binds the facts and the targets, not the\n // text around them, which live pages change freely.\n const prepareInput = (plan: InputPlan): PreparedInputResult => {\n const inspected = inspect(plan);\n\n if (\"error\" in inspected) return inspected;\n const { explain, ...prepared } = inspected;\n\n return { ...prepared, evidence: explain() };\n };\n\n const validate = (\n plan: InputPlan,\n prepared: PreparedInput,\n options: ValidationOptions,\n ): ValidatedInputResult => {\n const current = inspect(plan);\n\n if (\"error\" in current)\n return current.error === \"stale\" ? current : { error: \"changed\", detail: current.detail };\n if (\n current.url !== prepared.url ||\n (current.destination === undefined || prepared.destination === undefined\n ? current.destination !== prepared.destination\n : boundUrl(current.destination) !== boundUrl(prepared.destination)) ||\n JSON.stringify(current.facts) !== JSON.stringify(prepared.facts) ||\n current.targets.length !== prepared.targets.length ||\n current.targets.some((target, index) => {\n const previous = prepared.targets[index];\n\n return target === null\n ? previous !== null\n : previous === null ||\n previous === undefined ||\n target.ref !== previous.ref ||\n target.fingerprint !== previous.fingerprint;\n })\n )\n return {\n error: \"changed\",\n detail: \"the page or input target changed while the policy was deciding\",\n };\n\n if (options.focused === true) {\n const active = activeElement();\n const expected = prepared.targets[0];\n\n if (\n active === null ||\n expected === null ||\n expected === undefined ||\n refFor(active) !== expected.ref\n )\n return { error: \"changed\", detail: \"focus moved away from the approved element\" };\n }\n\n for (const press of options.presses ?? []) {\n const expected = prepared.targets[press.index];\n\n const element =\n expected === null || expected === undefined ? undefined : lookup(expected.ref);\n\n const hit = hitAt(document, press.x, press.y);\n\n if (element === undefined || hit === null || !receives(element, hit))\n return {\n error: \"changed\",\n detail: `the approved target is no longer under the pointer at (${press.x}, ${press.y})`,\n };\n\n const nested = nestedControl(element, hit);\n\n if (nested !== undefined)\n return {\n error: \"changed\",\n detail: `${describe(nested)} inside the approved target would receive the press at (${press.x}, ${press.y})`,\n };\n }\n\n return { ok: true };\n };\n\n // Chromium delivers pointer moves with the next frame. A press check waits until the frame\n // after it, so it sees what the page did when the pointer arrived, such as a menu opened over\n // the target. A hidden document draws no frames, and its moves wait for the press instead.\n const validateInput = (\n plan: InputPlan,\n prepared: PreparedInput,\n options: ValidationOptions = {},\n ): ValidatedInputResult | Promise<ValidatedInputResult> => {\n if ((options.presses ?? []).length === 0) return validate(plan, prepared, options);\n const { promise, resolve } = Promise.withResolvers<void>();\n\n if (document.visibilityState === \"hidden\") resolve();\n else requestAnimationFrame(() => requestAnimationFrame(() => resolve()));\n\n return promise.then(() => validate(plan, prepared, options));\n };\n\n return { prepareInput, textEntry, typingRefusal, validateInput };\n};\n\nexport type Guard = ReturnType<typeof guard>;\n\nconst InputPreparationError = Schema.Struct({\n error: Schema.String,\n detail: Schema.String,\n index: Schema.optional(Schema.Finite),\n});\n\nexport const PreparedInputResultSchema = Schema.Union([\n Schema.Struct({\n url: Schema.String,\n targets: Schema.Array(\n Schema.NullOr(\n Schema.Struct({\n ref: Schema.String,\n element: Schema.String,\n role: Schema.NullOr(Schema.String),\n name: Schema.String,\n cursor: Schema.String,\n href: Schema.optional(Schema.String),\n /** A field the DOM marks as holding a password, a one-time code or a card's details. */\n secret: Schema.Boolean,\n fingerprint: Schema.String,\n }),\n ),\n ),\n facts: Schema.Array(Fact),\n destination: Schema.optional(Schema.String),\n evidence: EvidenceSchema,\n }),\n InputPreparationError,\n]);\n\nexport const ValidatedInputResultSchema = Schema.Union([\n Schema.Struct({ ok: Schema.Literal(true) }),\n InputPreparationError,\n]);\n","/**\n * One browser tab: navigation, snapshots, pictures and input.\n *\n * A page waits only for itself: its operations take turns in one lane of its own. An action, which\n * sends input or navigates, has the page to itself, in the order actions were asked; reads share\n * it, after the action in flight and every action asked before them, so a read describes the page\n * an action left. A wait for a turn ends at the operation's deadline as `Busy`, never `Timeout`,\n * and a full deadline then bounds the operation itself; `failFast` fails it at once instead.\n * Identical reads asked between the same actions share one call to the page, and one whose\n * callers gave up finishes for the next caller to ask it. A policy holds outside the lane while\n * other operations continue; its target is revalidated before dispatch. Element targets are refs\n * from a snapshot; point targets are viewport coordinates in CSS pixels, the same coordinates as a\n * screenshot's pixels. Mouse and keyboard input share a bounded pipeline, so pacing does not wait\n * for each protocol reply. Target lookup happens before the input is sent.\n *\n * @since 0.3.0\n */\nimport { type Duration, Effect, Schema, type Stream } from \"effect\";\nimport type { Page as PlaywrightPage } from \"playwright-core\";\n\nimport { type BrowserError, type PolicyDenied } from \"./BrowserError.ts\";\nimport { Box, type BrowserEvent, PageLoaded, Subject } from \"./BrowserEvent.ts\";\nimport type { Changes } from \"./Change.ts\";\nimport { type CaptureStats, Frame, Image, type ScreencastOptions } from \"./Frame.ts\";\nimport { FormFieldSchema } from \"./internal/input/evidence.inpage.ts\";\nimport * as Guard from \"./internal/input/guard.inpage.ts\";\nimport { Correlation, FailFast } from \"./internal/page/lane.ts\";\nimport * as Url from \"./internal/page/url.ts\";\nimport type { Window } from \"./Moment.ts\";\nimport * as Motion from \"./Motion.ts\";\nimport { type Snapshot, type SnapshotOptions } from \"./Snapshot.ts\";\n\nexport type Point = Motion.Point;\n\n/** A ref from a snapshot, such as `\"e12\"`, or a viewport point. */\nexport type Target = string | Point;\n\n/** An integer rectangle in viewport CSS pixels. */\nexport class Region extends Schema.Class<Region>(\"effect-browser/Region\")({\n x: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n y: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n width: Schema.Int.check(Schema.isGreaterThan(0)),\n height: Schema.Int.check(Schema.isGreaterThan(0)),\n}) {}\n\n/** A crop and its viewport origin: add that origin to a point read from the crop. */\nexport class Zoom extends Schema.Class<Zoom>(\"effect-browser/Zoom\")({\n page: Schema.String,\n region: Region,\n image: Image,\n}) {}\n\n/** The target as it read before input. Point coordinates are never snapped to another position. */\nexport class ResolvedTarget extends Schema.Class<ResolvedTarget>(\"effect-browser/ResolvedTarget\")({\n point: Motion.Point,\n ...Subject.fields,\n element: Schema.String,\n /** For a point target, the box of what it found there. */\n box: Schema.optional(Box),\n cursor: Schema.String,\n href: Schema.optional(Schema.String),\n}) {}\n\nexport interface ClickOptions {\n readonly button?: \"left\" | \"right\" | \"middle\" | undefined;\n /** 2 for a double click. */\n readonly clickCount?: number | undefined;\n /** Hold the button down this long before releasing it. */\n readonly holdMillis?: number | undefined;\n}\n\nexport interface TypeOptions {\n /** Type into this text field: it is focused first, and its content replaced unless `replace` is false. */\n readonly into?: string | undefined;\n readonly replace?: boolean | undefined;\n /** Press Enter afterwards. */\n readonly submit?: boolean | undefined;\n /**\n * The text is a secret: type it only into a field the page marks secret, such as a password,\n * and otherwise refuse with `NotActionable` before any input. A replayed password asks this.\n */\n readonly secret?: boolean | undefined;\n}\n\nexport interface PressOptions {\n /**\n * Focus this element, by ref, before the first press: a link, a button or a field. The keys go to\n * whatever has focus otherwise.\n */\n readonly on?: string | undefined;\n /** Press the keys this many times. */\n readonly times?: number | undefined;\n /** Hold the keys down this long before releasing them, as a game control might need. */\n readonly holdMillis?: number | undefined;\n}\n\nexport interface ScrollOptions {\n readonly dx?: number | undefined;\n /** Pixels to scroll down; negative scrolls up. Defaults to most of a viewport. */\n readonly dy?: number | undefined;\n /** Scroll whatever is under this point or element. Defaults to the middle of the viewport. */\n readonly at?: Target | undefined;\n}\n\n/**\n * How current a picture must be. The newest screencast frame serves when it qualifies, at no cost;\n * otherwise a new screenshot is taken.\n */\nexport interface FrameOptions {\n /**\n * The oldest a reused frame may be, from its paint, at the earliest its timing allows, to now.\n * Defaults to 250 milliseconds; 0 always takes a new screenshot.\n */\n readonly maxAge?: Duration.Input | undefined;\n /**\n * `\"input\"`: reuse only a frame painted after this page's latest input, including input of an\n * interrupted action, and never while an action is changing the page. For a caller that has\n * just acted on the page.\n */\n readonly after?: \"input\" | undefined;\n}\n\n/** A screenshot reuses only a frame painted after the page's latest input, as `after: \"input\"`. */\nexport interface ScreenshotOptions {\n /** The oldest a reused frame may be, as for `frame`. Defaults to 250 milliseconds. */\n readonly maxAge?: Duration.Input | undefined;\n /** A region of the viewport, captured in CSS pixels at the viewport's own scale; always new. */\n readonly clip?: Box | undefined;\n /** JPEG quality, 0 to 100. Defaults to 80. */\n readonly quality?: number | undefined;\n /** `\"jpeg\"`, the default, or `\"png\"`, which is always a new picture. */\n readonly format?: \"jpeg\" | \"png\" | undefined;\n}\n\n/**\n * What `find` looks for. Every rule given must hold; with none, it finds every element in scope\n * that has a role or is a control.\n */\nexport interface FindQuery {\n /** An ARIA role, such as `\"button\"` or `\"heading\"`, ignoring case. */\n readonly role?: string | undefined;\n /**\n * The accessible name: a string that reads the same once spaces are collapsed and case folded,\n * or a pattern found in it.\n */\n readonly name?: string | RegExp | undefined;\n /**\n * Text it shows, ignoring case and spacing, or a pattern. Text inside a control or a heading is\n * that control's or heading's, and only the smallest element showing it matches, not every\n * element around it.\n */\n readonly text?: string | RegExp | undefined;\n /** Whole words in its context (row, column, label or heading), ignoring case and spacing. */\n readonly near?: string | undefined;\n /** Only what a point action at this viewport point would reach: the control there, or else what is painted there. */\n readonly at?: Point | undefined;\n /** The viewport (the default), or the whole document. */\n readonly scope?: \"viewport\" | \"document\" | undefined;\n}\n\n/**\n * An element's state as its markup gives it: `checked` for what can be checked, `expanded`,\n * `selected` and `pressed` where the page says either way, and `level` for headings.\n */\nexport const ElementState = Schema.Struct({\n disabled: Schema.Boolean,\n focused: Schema.Boolean,\n checked: Schema.optional(Schema.Boolean),\n expanded: Schema.optional(Schema.Boolean),\n selected: Schema.optional(Schema.Boolean),\n pressed: Schema.optional(Schema.Boolean),\n level: Schema.optional(Schema.Int),\n});\n\nexport type ElementState = typeof ElementState.Type;\n\n/** An element `find` found: a ref for the actions, what it is, where it is and its state. */\nexport class Found extends Schema.Class<Found>(\"effect-browser/Found\")({\n ref: Schema.String,\n subject: Subject,\n /** Its box, rounded. Reading the document, it may be out of view. */\n box: Box,\n inViewport: Schema.Boolean,\n state: ElementState,\n}) {}\n\nexport interface TextOptions {\n /** `\"viewport\"` (the default) reads what the viewport shows; a ref reads that element whole. */\n readonly scope?: string | undefined;\n /** Bound on the text's length, cut at a line. Defaults to 12,000 characters. */\n readonly maxChars?: number | undefined;\n /** Show what fields hold; a secret field still reads `••••`. Defaults to false. */\n readonly unmask?: boolean | undefined;\n}\n\n/** What a page showed as text: a line per block, with table cells apart by tabs. */\nexport class Text extends Schema.Class<Text>(\"effect-browser/Text\")({\n url: Schema.String,\n title: Schema.String,\n text: Schema.String,\n /** True when `text` was cut at `maxChars`. */\n truncated: Schema.Boolean,\n /** Host monotonic milliseconds from the browser's captured Effect Clock. */\n at: Schema.Finite,\n}) {}\n\n/** What `waitFor` waits for. */\nexport interface WaitCondition {\n /** A CSS selector for what to watch; the document's body without one. */\n readonly selector?: string | undefined;\n /**\n * `\"visible\"` (the default): something it matches shows; `\"hidden\"`: nothing it matches shows;\n * `\"enabled\"`: something it matches shows and is not disabled.\n */\n readonly state?: \"visible\" | \"hidden\" | \"enabled\" | undefined;\n /** Only what shows this text counts, case and all, with runs of spaces read as one. */\n readonly text?: string | undefined;\n}\n\nexport interface ReadyOptions {\n /**\n * What must stay still during quietMillis: screen paint (default); recorded content; or the\n * `\"foreground\"`, the screen but for what was already moving before the page's latest input.\n */\n readonly still?: \"screen\" | \"content\" | \"foreground\" | undefined;\n /** How long the selected evidence must stay still; screen paint by default. */\n readonly quietMillis?: number | undefined;\n readonly timeout?: Duration.Input | undefined;\n}\n\n/** The window `changes` reads, and whether to show what fields hold. */\nexport interface ChangesOptions {\n /**\n * Where the window starts: the changes a previous read returned, to continue exactly where they\n * ended; a frame, at its paint; or host monotonic milliseconds, which mapped to the page's clock\n * may miss or repeat changes near the start if the browser's clock mapping changed since. Defaults\n * to the start of the record.\n */\n readonly since?: Changes | Frame | number | undefined;\n /**\n * Where it ends: a frame, at its paint, so a delayed frame's window holds nothing it does not\n * show; or host monotonic milliseconds. Defaults to now, and is never later.\n */\n readonly until?: Frame | number | undefined;\n /** Show what fields hold; a secret field still reads `••••`. Defaults to false. */\n readonly unmask?: boolean | undefined;\n}\n\n/** The window `window` reads, and whether to show what fields hold. */\nexport interface WindowOptions {\n /**\n * Where the window starts: a previous window, to continue exactly where it ended; a frame, at its\n * paint; host monotonic milliseconds; or a `Duration` back from `until`. A start after `until`\n * leaves the window empty there.\n */\n readonly since: Window | Frame | Duration.Duration | number;\n /**\n * Where it ends: a frame, at its paint, such as one a delayed consumer airs now; or host\n * monotonic milliseconds. Defaults to now, and is never later.\n */\n readonly until?: Frame | number | undefined;\n /** Show what fields hold in its changes; a secret field still reads `••••`. Defaults to false. */\n readonly unmask?: boolean | undefined;\n}\n\n/**\n * What the library knows of a page now, without asking it, each part with when it learned it, in\n * host monotonic milliseconds: a part's age is `at` less its time. Text read before the current\n * document began is left out, since it tells of a document that has gone.\n */\nexport class State extends Schema.Class<State>(\"effect-browser/PageState\")({\n page: Schema.String,\n /** When this was taken. */\n at: Schema.Finite,\n /** Where the main frame last committed or moved, without userinfo or known secret parameters. */\n url: Schema.String,\n /** The page's document, as `Navigated` counts them. */\n document: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n /** When the main frame committed it; absent for the one the browser began tracking it with. */\n committedAt: Schema.optional(Schema.Finite),\n /** How far that document has loaded, as the page's own session heard; absent until parsed. */\n load: Schema.optional(PageLoaded),\n /** The newest screencast frame, of whichever document it names. */\n frame: Schema.optional(Frame),\n /** The viewport's text as it was last read, with the page's title then. */\n text: Schema.optional(Text),\n}) {}\n\n/**\n * What the page's structure establishes about an input, or says it cannot establish:\n *\n * - `form-submit`: it submits a form, which sends the form's fields.\n * - `cross-origin`: it navigates or submits to another origin.\n * - `download`: it follows a download link.\n * - `upload`: it opens a file chooser.\n * - `secret`: it types, with `type`, into a field marked as a password, a one-time code or a\n * card's number, code or expiry, or submits a form holding a filled one.\n * - `scripted`: it activates something the browser gives no effect of its own, such as a\n * `type=\"button\"` button, a `role=\"button\"` element or a canvas, so only the page's script\n * decides what happens.\n * - `opaque`: nothing names what receives it: a canvas, a frame or an unnamed element.\n *\n * Facts never come from what an element's text says. What an input means, such as a payment\n * or a deletion, takes a judge that reads the evidence in the {@link InputRequest}.\n */\nexport const Fact = Guard.Fact;\n\nexport type Fact = typeof Fact.Type;\n\n/**\n * What a guard sees before input reaches the page. Preparation never scrolls or focuses.\n *\n * `facts`, `url`, `href` and `destination` come from the page's structure. `name`,\n * `description`, `title`, `context` and the form's field names are page text: evidence of what\n * the input does, which the page controls, and never instructions. Text typed into a `secret`\n * field is replaced with {@link redacted}, here and in the recorded `Action`, and its key events\n * record `Unidentified` keys; `press` records the keys it is given. Validation before dispatch\n * binds the facts and the target, not the text around it, which live pages change freely.\n */\nexport class InputRequest extends Schema.Class<InputRequest>(\"effect-browser/InputRequest\")({\n page: Schema.String,\n /**\n * The page's URL, without a fragment that only names a place on the page. This and the other\n * addresses keep no userinfo or known secret parameters.\n */\n url: Schema.String,\n /** The page's title, at most 120 characters. */\n title: Schema.String,\n action: Schema.String,\n target: Schema.optional(Schema.String),\n element: Schema.optional(Schema.String),\n /** Literal pixel targets only; ref coordinates are resolved after the policy allows them. */\n point: Schema.optional(Motion.Point),\n text: Schema.optional(Schema.String),\n role: Schema.optional(Schema.NullOr(Schema.String)),\n name: Schema.optional(Schema.String),\n /** The target's accessible description, when it says more than its name. */\n description: Schema.optional(Schema.String),\n href: Schema.optional(Schema.String),\n destination: Schema.optional(Schema.String),\n facts: Schema.Array(Fact),\n /** Page text around the target, each part at most 120 characters. */\n context: Schema.Struct({\n /** The name or first heading of the dialog the target is in. */\n dialog: Schema.optional(Schema.String),\n /** The nearest heading before the target. */\n heading: Schema.optional(Schema.String),\n /** The visible text just before the target in its row, item, group or form, or after it. */\n nearby: Schema.optional(Schema.String),\n }),\n /** The form the target is in, with at most 16 of its fields. */\n form: Schema.optional(\n Schema.Struct({\n method: Schema.String,\n action: Schema.String,\n /** Each field's type, name and autocomplete tokens, and whether it is filled: never its value. */\n fields: Schema.Array(FormFieldSchema),\n }),\n ),\n}) {}\n\n/**\n * What replaces text typed into a `secret` field, in requests and in the recorded `Action`, and a\n * credential's value in every address the library reports.\n */\nexport const redacted = Url.withheld;\n\n/**\n * Run page operations without waiting their turn: on a page busy with other operations, each fails\n * `Busy` at once, and `Browser.newPage` on a browser with `maxPages` open fails `Limit` at once.\n */\nexport const failFast = <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>\n Effect.provideService(effect, FailFast, true);\n\n/**\n * Give every action `effect` performs a caller's id, such as a model's tool call id, which its\n * recorded `Action` carries as `correlation`.\n */\nexport const correlate =\n (id: string) =>\n <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>\n Effect.provideService(effect, Correlation, id);\n\n/** Succeed to allow, fail to deny, or await an external signal to hold the input. */\nexport type InputGuard = (request: InputRequest) => Effect.Effect<void, PolicyDenied>;\n\nexport interface Page {\n /** The page's CDP target id: the same page has it again after a reconnect to its browser. */\n readonly id: string;\n /** The Playwright page, for anything this API does not cover. Never give it to a model. */\n readonly playwright: PlaywrightPage;\n /** The page's address, without its userinfo or known secret parameters. */\n readonly url: Effect.Effect<string>;\n /**\n * The document's title as the page last set it, empty for an untitled page. The browser answers\n * it, in one call, so a page busy with a script cannot hold it up.\n */\n readonly title: Effect.Effect<string, BrowserError>;\n\n readonly goto: (url: string) => Effect.Effect<void, BrowserError>;\n /** The previous history entry, including one only a frame created; `NotFound` when none. */\n readonly back: Effect.Effect<void, BrowserError>;\n readonly reload: Effect.Effect<void, BrowserError>;\n /** Make this the visible tab. Background tabs paint rarely and send few screencast frames. */\n readonly bringToFront: Effect.Effect<void, BrowserError>;\n /** Close the tab, succeeding once it has closed, or at once when it already had. */\n readonly close: Effect.Effect<void, BrowserError>;\n\n readonly snapshot: (options?: SnapshotOptions) => Effect.Effect<Snapshot, BrowserError>;\n /**\n * A picture of the viewport, in CSS pixels: a screencast frame painted since the page's latest\n * input, if one qualifies, or a new one. A caller that has just acted sees what its action did.\n */\n readonly screenshot: (options?: ScreenshotOptions) => Effect.Effect<Image, BrowserError>;\n /**\n * The viewport with its timing: the newest screencast frame if it qualifies, else a new\n * screenshot timed by the host interval in which it was taken.\n */\n readonly frame: (options?: FrameOptions) => Effect.Effect<Frame, BrowserError>;\n /** A crop in CSS pixels, unmagnified, with the origin that keeps later input in viewport pixels. */\n readonly zoom: (region: Region) => Effect.Effect<Zoom, BrowserError>;\n /**\n * The viewport's size in CSS pixels, the space of points, crops and page scrolls. Over CDP the\n * page reports it, within the action timeout.\n */\n readonly viewport: Effect.Effect<\n { readonly width: number; readonly height: number },\n BrowserError\n >;\n /**\n * The elements that match a query, in tree order, with refs the actions take, in one call to the\n * page. All that match are returned, so a caller tells them apart by their context; none is an\n * empty result, not a failure.\n */\n readonly find: (query?: FindQuery) => Effect.Effect<ReadonlyArray<Found>, BrowserError>;\n /**\n * The text the viewport shows, or one element whole, in one call to the page. Field values read\n * `••••` unless `unmask`, and a secret field's always do, as does one that was secret when the\n * library saw it.\n */\n readonly text: (options?: TextOptions) => Effect.Effect<Text, BrowserError>;\n /**\n * What visibly changed over a window, in one call to the page. The first read starts the page's\n * record, so it finds none; from then the page records, and from the start of each later\n * document, until nobody has read it for two minutes. See `Change`.\n */\n readonly changes: (options?: ChangesOptions) => Effect.Effect<Changes, BrowserError>;\n /**\n * The page's events, changes and frames over a window: the frames and events it keeps, at no\n * call, and its changes, in one call, the first starting its record as `changes` does. A part\n * that cannot be read is missing, with why; the window fails only for bounds that are not finite.\n */\n readonly window: (options: WindowOptions) => Effect.Effect<Window, BrowserError>;\n /**\n * What the library knows of the page now, at no call and with no wait for its turn: where it is,\n * its document and how far it has loaded, its newest frame, and its text and title as last read.\n */\n readonly state: Effect.Effect<State>;\n\n readonly click: (\n target: Target,\n options?: ClickOptions,\n ) => Effect.Effect<ResolvedTarget, BrowserError>;\n readonly hover: (target: Target) => Effect.Effect<void, BrowserError>;\n readonly drag: (from: Target, to: Target) => Effect.Effect<void, BrowserError>;\n /** Type into a text field, or to whatever has focus unless a typed key could activate it. */\n readonly type: (text: string, options?: TypeOptions) => Effect.Effect<void, BrowserError>;\n /** Keys such as `\"Enter\"`, `\"Space\"`, `\"ArrowLeft\"` or `\"Control+A\"`. */\n readonly press: (keys: string, options?: PressOptions) => Effect.Effect<void, BrowserError>;\n readonly scroll: (options?: ScrollOptions) => Effect.Effect<void, BrowserError>;\n /**\n * Choose options of a `<select>` by value or label; returns the chosen labels. A refusal, such\n * as no matching option, is undispatched.\n */\n readonly select: (\n ref: string,\n values: ReadonlyArray<string>,\n ) => Effect.Effect<string, BrowserError>;\n\n /**\n * Wait until a condition holds, in one call that the page answers as it comes, looking every\n * 100 ms, or `Timeout` after `timeout`, 10 seconds by default. A selector that is not CSS is an\n * `InvalidRequest`.\n */\n readonly waitFor: (\n condition: WaitCondition,\n timeout?: Duration.Input,\n ) => Effect.Effect<void, BrowserError>;\n /**\n * Wait until the page is ready to be shown, asking the page every 100 ms: its document is parsed\n * and has painted since, nothing that ends is animating in view, its fonts and the images in\n * view have loaded, and the viewport shows something. With `quietMillis`, the screen must then\n * also stay still that long: nothing in view changed, where the page's changes are recorded, and\n * no frame comes, counted from the first frame of a capture the wait starts itself. A canvas\n * that keeps drawing, such as a live chart, is never still. With `still: \"foreground\"`, frames\n * may keep coming, but nothing may move in them outside what moved in the frames of the 1.5 s\n * before the page's latest input, such as an idle animation; reels set spinning, or a counter\n * set rolling, by the input keep the wait going. Without those frames, as where they are older\n * than the browser's `frameHistory`, nothing may move at all. A page is never ready without a\n * painted frame, as a hidden tab may be. `Timeout` after `timeout`, 15 seconds by default.\n */\n readonly ready: (options?: ReadyOptions) => Effect.Effect<void, BrowserError>;\n\n /**\n * Screencast frames for as long as the stream runs. Concurrent streams share one screencast and\n * its settings; explicit options that differ from a running screencast's fail with InvalidRequest.\n */\n readonly screencast: (options?: ScreencastOptions) => Stream.Stream<Frame, BrowserError>;\n /**\n * What this page's captures received, delivered and dropped, over its life or the latest\n * `window`, which reaches back at most a minute; a longer one is an `InvalidRequest`.\n */\n readonly captureStats: (options?: {\n readonly window?: Duration.Input | undefined;\n }) => Effect.Effect<CaptureStats, BrowserError>;\n /** Screencast frames painted within `frameHistory` of the newest, oldest first. */\n readonly recentFrames: Effect.Effect<ReadonlyArray<Frame>>;\n /** This page's events among the browser's latest `eventHistory`, oldest first. */\n readonly recentEvents: Effect.Effect<ReadonlyArray<BrowserEvent>>;\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { p as PolicyDenied, t as BrowserError } from "./BrowserError-Coy7EW1N.mjs";
|
|
2
|
-
import { E as WheelScrolled, S as TextInserted, T as TrackPlanned, _ as PointerReleased, b as Subject, d as Navigated, f as PageClosed, g as PointerPressed, h as PageUntracked, i as BrowserEvent, l as Disconnected, m as PageOpened, o as CursorChanged, p as PageLoaded, s as DialogShown, t as Action, u as KeyChanged, w as TrackPerformed, y as SessionEnding } from "./BrowserEvent-
|
|
3
|
-
import { r as Changes, t as Change } from "./Change-
|
|
2
|
+
import { E as WheelScrolled, S as TextInserted, T as TrackPlanned, _ as PointerReleased, b as Subject, d as Navigated, f as PageClosed, g as PointerPressed, h as PageUntracked, i as BrowserEvent, l as Disconnected, m as PageOpened, o as CursorChanged, p as PageLoaded, r as Box, s as DialogShown, t as Action, u as KeyChanged, w as TrackPerformed, y as SessionEnding } from "./BrowserEvent-dq6FRT8w.mjs";
|
|
3
|
+
import { r as Changes, t as Change } from "./Change-DqING3tr.mjs";
|
|
4
4
|
import { a as Image, n as CaptureStats, o as ScreencastOptions, r as Frame } from "./Frame-DkNdjjjr.mjs";
|
|
5
5
|
import { n as Snapshot, r as SnapshotOptions } from "./Snapshot-B34hZ4Jl.mjs";
|
|
6
|
+
import { r as Point$1, t as Motion_d_exports } from "./Motion-DND6I-64.mjs";
|
|
6
7
|
import { Duration, Effect, Schema, Stream } from "effect";
|
|
7
8
|
import { Prompt } from "effect/ai";
|
|
8
9
|
import { Page } from "playwright-core";
|
|
@@ -104,10 +105,7 @@ declare const toPrompt: (moment: Moment) => Prompt.Prompt;
|
|
|
104
105
|
declare namespace Page_d_exports {
|
|
105
106
|
export { ChangesOptions, ClickOptions, ElementState, Fact, FindQuery, Found, FrameOptions, InputGuard, InputRequest, Page$1 as Page, Point, PressOptions, ReadyOptions, Region, ResolvedTarget, ScreenshotOptions, ScrollOptions, State, Target, Text, TextOptions, TypeOptions, WaitCondition, WindowOptions, Zoom, correlate, failFast, redacted };
|
|
106
107
|
}
|
|
107
|
-
|
|
108
|
-
readonly x: number;
|
|
109
|
-
readonly y: number;
|
|
110
|
-
}
|
|
108
|
+
type Point = Point$1;
|
|
111
109
|
/** A ref from a snapshot, such as `"e12"`, or a viewport point. */
|
|
112
110
|
type Target = string | Point;
|
|
113
111
|
declare const Region_base: Schema.Class<Region, Schema.Struct<{
|
|
@@ -126,21 +124,20 @@ declare const Zoom_base: Schema.Class<Zoom, Schema.Struct<{
|
|
|
126
124
|
/** A crop and its viewport origin: add that origin to a point read from the crop. */
|
|
127
125
|
declare class Zoom extends Zoom_base {}
|
|
128
126
|
declare const ResolvedTarget_base: Schema.Class<ResolvedTarget, Schema.Struct<{
|
|
129
|
-
readonly point: Schema.Struct<{
|
|
130
|
-
readonly x: Schema.Finite;
|
|
131
|
-
readonly y: Schema.Finite;
|
|
132
|
-
}>;
|
|
133
|
-
readonly element: Schema.String;
|
|
134
|
-
/** The element's lowercase tag name. */
|
|
135
|
-
readonly tag: Schema.String;
|
|
136
127
|
readonly role: Schema.NullOr<Schema.String>;
|
|
137
128
|
readonly name: Schema.String;
|
|
129
|
+
readonly tag: Schema.String;
|
|
138
130
|
readonly context: Schema.Struct<{
|
|
139
131
|
readonly row: Schema.optional<Schema.String>;
|
|
140
132
|
readonly column: Schema.optional<Schema.String>;
|
|
141
133
|
readonly label: Schema.optional<Schema.String>;
|
|
142
134
|
readonly heading: Schema.optional<Schema.String>;
|
|
143
135
|
}>;
|
|
136
|
+
readonly point: Schema.Struct<{
|
|
137
|
+
readonly x: Schema.Finite;
|
|
138
|
+
readonly y: Schema.Finite;
|
|
139
|
+
}>;
|
|
140
|
+
readonly element: Schema.String;
|
|
144
141
|
/** For a point target, the box of what it found there. */
|
|
145
142
|
readonly box: Schema.optional<Schema.Struct<{
|
|
146
143
|
readonly x: Schema.Finite;
|
|
@@ -212,12 +209,7 @@ interface ScreenshotOptions {
|
|
|
212
209
|
/** The oldest a reused frame may be, as for `frame`. Defaults to 250 milliseconds. */
|
|
213
210
|
readonly maxAge?: Duration.Input | undefined;
|
|
214
211
|
/** A region of the viewport, captured in CSS pixels at the viewport's own scale; always new. */
|
|
215
|
-
readonly clip?:
|
|
216
|
-
readonly x: number;
|
|
217
|
-
readonly y: number;
|
|
218
|
-
readonly width: number;
|
|
219
|
-
readonly height: number;
|
|
220
|
-
} | undefined;
|
|
212
|
+
readonly clip?: Box | undefined;
|
|
221
213
|
/** JPEG quality, 0 to 100. Defaults to 80. */
|
|
222
214
|
readonly quality?: number | undefined;
|
|
223
215
|
/** `"jpeg"`, the default, or `"png"`, which is always a new picture. */
|
|
@@ -317,8 +309,11 @@ interface WaitCondition {
|
|
|
317
309
|
readonly text?: string | undefined;
|
|
318
310
|
}
|
|
319
311
|
interface ReadyOptions {
|
|
320
|
-
/**
|
|
321
|
-
|
|
312
|
+
/**
|
|
313
|
+
* What must stay still during quietMillis: screen paint (default); recorded content; or the
|
|
314
|
+
* `"foreground"`, the screen but for what was already moving before the page's latest input.
|
|
315
|
+
*/
|
|
316
|
+
readonly still?: "screen" | "content" | "foreground" | undefined;
|
|
322
317
|
/** How long the selected evidence must stay still; screen paint by default. */
|
|
323
318
|
readonly quietMillis?: number | undefined;
|
|
324
319
|
readonly timeout?: Duration.Input | undefined;
|
|
@@ -568,9 +563,12 @@ interface Page$1 {
|
|
|
568
563
|
* view have loaded, and the viewport shows something. With `quietMillis`, the screen must then
|
|
569
564
|
* also stay still that long: nothing in view changed, where the page's changes are recorded, and
|
|
570
565
|
* no frame comes, counted from the first frame of a capture the wait starts itself. A canvas
|
|
571
|
-
* that keeps drawing, such as a live chart, is never still
|
|
572
|
-
*
|
|
573
|
-
*
|
|
566
|
+
* that keeps drawing, such as a live chart, is never still. With `still: "foreground"`, frames
|
|
567
|
+
* may keep coming, but nothing may move in them outside what moved in the frames of the 1.5 s
|
|
568
|
+
* before the page's latest input, such as an idle animation; reels set spinning, or a counter
|
|
569
|
+
* set rolling, by the input keep the wait going. Without those frames, as where they are older
|
|
570
|
+
* than the browser's `frameHistory`, nothing may move at all. A page is never ready without a
|
|
571
|
+
* painted frame, as a hidden tab may be. `Timeout` after `timeout`, 15 seconds by default.
|
|
574
572
|
*/
|
|
575
573
|
readonly ready: (options?: ReadyOptions) => Effect.Effect<void, BrowserError>;
|
|
576
574
|
/**
|
|
@@ -592,4 +590,4 @@ interface Page$1 {
|
|
|
592
590
|
}
|
|
593
591
|
//#endregion
|
|
594
592
|
export { Account as A, TypeOptions as C, correlate as D, Zoom as E, account as F, capture as I, toPrompt as L, Moment as M, Moment_d_exports as N, failFast as O, Window as P, TextOptions as S, WindowOptions as T, ScreenshotOptions as _, FindQuery as a, Target as b, InputGuard as c, Page_d_exports as d, Point as f, ResolvedTarget as g, Region as h, Fact as i, CaptureOptions as j, redacted as k, InputRequest as l, ReadyOptions as m, ClickOptions as n, Found as o, PressOptions as p, ElementState as r, FrameOptions as s, ChangesOptions as t, Page$1 as u, ScrollOptions as v, WaitCondition as w, Text as x, State as y };
|
|
595
|
-
//# sourceMappingURL=Page-
|
|
593
|
+
//# sourceMappingURL=Page-ku6j5t-v.d.mts.map
|