effect-browser 0.3.0-beta.13 → 0.3.0-beta.14
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 +50 -19
- package/dist/{Browser-QiT6Cdn_.mjs → Browser-BBSySyjT.mjs} +2 -2
- package/dist/{Browser-QiT6Cdn_.mjs.map → Browser-BBSySyjT.mjs.map} +1 -1
- package/dist/Browser.d.mts +1 -1
- package/dist/Browser.mjs +1 -1
- package/dist/Cdp.mjs +1 -1
- package/dist/Chromium.mjs +1 -1
- package/dist/Expect.d.mts +1 -1
- package/dist/Expect.mjs +1 -1
- package/dist/{Frame-Di2PxyF7.d.mts → Frame-DkNdjjjr.d.mts} +3 -5
- package/dist/Frame.d.mts +1 -1
- package/dist/Frame.mjs +2 -4
- package/dist/Frame.mjs.map +1 -1
- package/dist/Moment.d.mts +1 -1
- package/dist/Moment.mjs +7 -3
- package/dist/Moment.mjs.map +1 -1
- package/dist/{Page-B7X6DQUn.d.mts → Page-DL9eylp3.d.mts} +2 -2
- package/dist/Page.d.mts +1 -1
- package/dist/{Plan-BS0jpENY.d.mts → Plan-6As6vcwT.d.mts} +3 -3
- package/dist/{Plan-Bl2NM1D5.mjs → Plan-CXA2BW-G.mjs} +4 -6
- package/dist/Plan-CXA2BW-G.mjs.map +1 -0
- package/dist/Plan.d.mts +1 -1
- package/dist/Plan.mjs +1 -1
- package/dist/Policy.d.mts +1 -1
- package/dist/Presentation.d.mts +1 -1
- package/dist/Presentation.mjs +1 -1
- package/dist/Stage.d.mts +5 -4
- package/dist/Stage.mjs +53 -20
- package/dist/Stage.mjs.map +1 -1
- package/dist/{Supervisor-TNKNOVzu.mjs → Supervisor-BE2sGHBK.mjs} +67 -41
- package/dist/Supervisor-BE2sGHBK.mjs.map +1 -0
- package/dist/{Supervisor-CYWFK3vM.d.mts → Supervisor-W60pZWHh.d.mts} +24 -8
- package/dist/Supervisor.d.mts +2 -2
- package/dist/Supervisor.mjs +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +3 -3
- package/dist/{page-ZxMhw16l.mjs → page-B92QnRfT.mjs} +196 -166
- package/dist/page-B92QnRfT.mjs.map +1 -0
- package/package.json +1 -1
- package/src/Frame.ts +2 -4
- package/src/Moment.ts +14 -3
- package/src/Plan.ts +7 -6
- package/src/Stage.ts +61 -21
- package/src/Supervisor.ts +69 -37
- package/src/internal/pictures/capture.ts +172 -188
- package/src/internal/pictures/pictures.ts +50 -73
- package/src/internal/pictures/quiescence.ts +94 -0
- package/src/internal/reading/ready.ts +9 -3
- package/src/internal/supervisor/lifecycle.ts +27 -12
- package/dist/Plan-Bl2NM1D5.mjs.map +0 -1
- package/dist/Supervisor-TNKNOVzu.mjs.map +0 -1
- package/dist/page-ZxMhw16l.mjs.map +0 -1
package/dist/Moment.mjs
CHANGED
|
@@ -29,8 +29,8 @@ import { Prompt } from "effect/ai";
|
|
|
29
29
|
* part it could not read, which it names with why.
|
|
30
30
|
*
|
|
31
31
|
* Frames come from a running screencast, as far back as the browser's `frameHistory` keeps them.
|
|
32
|
-
* A moment's picture is the newest frame if it was painted after the page's latest input and
|
|
33
|
-
* most 250 ms ago, else a new screenshot timed by its capture.
|
|
32
|
+
* A moment's picture is the newest frame if it was painted after the page's latest input and
|
|
33
|
+
* completed action, at most 250 ms ago, else a new screenshot timed by its capture.
|
|
34
34
|
*
|
|
35
35
|
* @since 0.3.0
|
|
36
36
|
*/
|
|
@@ -77,12 +77,16 @@ const spread = (frames, count) => {
|
|
|
77
77
|
const step = (frames.length - 1) / (count - 1);
|
|
78
78
|
return Array.from({ length: count }, (_, index) => frames[Math.round(index * step)]).filter((frame) => frame !== void 0);
|
|
79
79
|
};
|
|
80
|
+
const pictureOf = Effect.fnUntraced(function* (page) {
|
|
81
|
+
const frame = yield* page.frame({ after: "input" });
|
|
82
|
+
return (yield* page.recentEvents).some((event) => event._tag === "Action" && event.at > frame.hostTime) ? yield* page.frame({ maxAge: 0 }) : frame;
|
|
83
|
+
});
|
|
80
84
|
const capture = Effect.fn("Moment.capture")(function* (page, options = {}) {
|
|
81
85
|
const count = options.frames ?? 2;
|
|
82
86
|
if (!Number.isSafeInteger(count) || count < 1) return yield* undispatched("moment", new InvalidRequest({ detail: "frames must be a positive safe integer" }));
|
|
83
87
|
const outline = options.snapshot ?? false;
|
|
84
88
|
const { pictured, outlined } = yield* Effect.all({
|
|
85
|
-
pictured: Effect.result(page
|
|
89
|
+
pictured: Effect.result(pictureOf(page)).pipe(Effect.flatMap((picture) => Effect.map(page.window({
|
|
86
90
|
since: options.since ?? Duration.seconds(5),
|
|
87
91
|
until: Result.getOrUndefined(picture),
|
|
88
92
|
unmask: options.unmask
|
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 at\n * 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\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(page.frame({ after: \"input\" })).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, 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,7 +1,7 @@
|
|
|
1
1
|
import { p as PolicyDenied, t as BrowserError } from "./BrowserError-Coy7EW1N.mjs";
|
|
2
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-BRu2juEz.mjs";
|
|
3
3
|
import { r as Changes, t as Change } from "./Change-iMlcuzVD.mjs";
|
|
4
|
-
import { a as Image, n as CaptureStats, o as ScreencastOptions, r as Frame } from "./Frame-
|
|
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
6
|
import { Duration, Effect, Schema, Stream } from "effect";
|
|
7
7
|
import { Prompt } from "effect/ai";
|
|
@@ -592,4 +592,4 @@ interface Page$1 {
|
|
|
592
592
|
}
|
|
593
593
|
//#endregion
|
|
594
594
|
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-
|
|
595
|
+
//# sourceMappingURL=Page-DL9eylp3.d.mts.map
|
package/dist/Page.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as TypeOptions, D as correlate, E as Zoom, O as failFast, S as TextOptions, T as WindowOptions, _ as ScreenshotOptions, a as FindQuery, b as Target, c as InputGuard, f as Point, g as ResolvedTarget, h as Region, i as Fact, k as redacted, l as InputRequest, m as ReadyOptions, n as ClickOptions, o as Found, p as PressOptions, r as ElementState, s as FrameOptions, t as ChangesOptions, u as Page, v as ScrollOptions, w as WaitCondition, x as Text, y as State } from "./Page-
|
|
1
|
+
import { C as TypeOptions, D as correlate, E as Zoom, O as failFast, S as TextOptions, T as WindowOptions, _ as ScreenshotOptions, a as FindQuery, b as Target, c as InputGuard, f as Point, g as ResolvedTarget, h as Region, i as Fact, k as redacted, l as InputRequest, m as ReadyOptions, n as ClickOptions, o as Found, p as PressOptions, r as ElementState, s as FrameOptions, t as ChangesOptions, u as Page, v as ScrollOptions, w as WaitCondition, x as Text, y as State } from "./Page-DL9eylp3.mjs";
|
|
2
2
|
export { ChangesOptions, ClickOptions, ElementState, Fact, FindQuery, Found, FrameOptions, InputGuard, InputRequest, Page, Point, PressOptions, ReadyOptions, Region, ResolvedTarget, ScreenshotOptions, ScrollOptions, State, Target, Text, TextOptions, TypeOptions, WaitCondition, WindowOptions, Zoom, correlate, failFast, redacted };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as BrowserError } from "./BrowserError-Coy7EW1N.mjs";
|
|
2
2
|
import { b as Subject, i as BrowserEvent } from "./BrowserEvent-BRu2juEz.mjs";
|
|
3
|
-
import { m as ReadyOptions, o as Found, u as Page } from "./Page-
|
|
3
|
+
import { m as ReadyOptions, o as Found, u as Page } from "./Page-DL9eylp3.mjs";
|
|
4
4
|
import { Duration, Effect, Schema } from "effect";
|
|
5
5
|
//#region src/internal/reading/choose.d.ts
|
|
6
6
|
declare const Missing_base: Schema.Class<Missing, Schema.TaggedStruct<"Missing", {}>, import("effect/Cause").YieldableError>;
|
|
@@ -182,7 +182,7 @@ declare const fromEvents: (events: Iterable<BrowserEvent>) => Plan;
|
|
|
182
182
|
*/
|
|
183
183
|
declare const locate: (page: Page, subject: Subject) => Effect.Effect<Found, Ambiguous | BrowserError | Drifted | Missing, never>;
|
|
184
184
|
interface TakeOptions {
|
|
185
|
-
/** How each step waits
|
|
185
|
+
/** How each step waits first, except an opening navigation, or false. No final-step wait. */
|
|
186
186
|
readonly settle?: ReadyOptions | false | undefined;
|
|
187
187
|
readonly inputs?: Readonly<Record<string, string>> | undefined;
|
|
188
188
|
/**
|
|
@@ -213,4 +213,4 @@ declare const restore: (page: Page, plan: Plan, options?: TakeOptions & {
|
|
|
213
213
|
}) => Effect.Effect<Receipt[], ReplayError, never>;
|
|
214
214
|
//#endregion
|
|
215
215
|
export { take as _, ReplayError as a, Missing as b, StepAction as c, Uncertain as d, fromEvents as f, restore as g, replay as h, Receipt as i, Stopped as l, repeatable as m, Plan as n, ReplayOptions as o, locate as p, Plan_d_exports as r, Step as s, Expected as t, TakeOptions as u, Ambiguous as v, Drifted as y };
|
|
216
|
-
//# sourceMappingURL=Plan-
|
|
216
|
+
//# sourceMappingURL=Plan-6As6vcwT.d.mts.map
|
|
@@ -88,7 +88,7 @@ const choose = (subject, found) => {
|
|
|
88
88
|
* as a named input slot, never the text itself. A navigation to an address whose credentials the
|
|
89
89
|
* events withheld is an input slot too, so replay goes where the caller says, or nowhere, and
|
|
90
90
|
* never to the address without them. `replay` takes the steps in turn. Before a step
|
|
91
|
-
*
|
|
91
|
+
* except an opening navigate, back or reload, it waits for `Page.ready`; then it finds the element its
|
|
92
92
|
* subject names, by role and name among those that repeat all its recorded context, and acts on
|
|
93
93
|
* it. Text typed into focus was typed into the focused field, which replay finds the same way, and
|
|
94
94
|
* text typed into a secret field goes into nothing else. An element step never falls back to
|
|
@@ -425,12 +425,11 @@ const take = Effect.fn("Plan.take")(function* (page, plan, at, options = {}) {
|
|
|
425
425
|
const expected = step.expect;
|
|
426
426
|
const durable = expected !== void 0 && (expected._tag === "Appeared" || expected._tag === "Navigated" && typeof expected.url === "string") && expected.durable === true;
|
|
427
427
|
if (!durable && (unresolved || expected !== void 0 && "durable" in expected && expected.durable === true)) return yield* uncertain;
|
|
428
|
-
|
|
429
|
-
if (![
|
|
428
|
+
if (options.settle !== false && (index > 0 || ![
|
|
430
429
|
"navigate",
|
|
431
430
|
"back",
|
|
432
431
|
"reload"
|
|
433
|
-
].includes(step.action)) yield* settle;
|
|
432
|
+
].includes(step.action))) yield* page.ready(options.settle);
|
|
434
433
|
const before = plan.steps[index - 1]?.url;
|
|
435
434
|
if (before !== void 0) yield* arrived(page, unresolved ? [before, step.url] : [before], millis);
|
|
436
435
|
const check = checkEffect(page, step);
|
|
@@ -439,7 +438,6 @@ const take = Effect.fn("Plan.take")(function* (page, plan, at, options = {}) {
|
|
|
439
438
|
orElse: () => Effect.fail(new Drifted({ detail: "the expected-effect read timed out" }))
|
|
440
439
|
}))).pipe(Effect.mapError((error) => unresolved ? uncertain : error));
|
|
441
440
|
const receipt = (outcome) => Effect.gen(function* () {
|
|
442
|
-
if (index === plan.steps.length - 1) yield* settle;
|
|
443
441
|
yield* arrived(page, [step.url], millis);
|
|
444
442
|
const now = yield* page.state;
|
|
445
443
|
return new Receipt({
|
|
@@ -514,4 +512,4 @@ const restore = (page, plan, options = {}) => run(page, plan, options, 0, option
|
|
|
514
512
|
//#endregion
|
|
515
513
|
export { Drifted as _, ReplayError as a, Stopped as c, locate as d, repeatable as f, Ambiguous as g, take as h, Receipt as i, Uncertain as l, restore as m, Plan as n, Step as o, replay as p, Plan_exports as r, StepAction as s, Expected as t, fromEvents as u, Missing as v };
|
|
516
514
|
|
|
517
|
-
//# sourceMappingURL=Plan-
|
|
515
|
+
//# sourceMappingURL=Plan-CXA2BW-G.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Plan-CXA2BW-G.mjs","names":[],"sources":["../src/internal/reading/choose.ts","../src/Plan.ts"],"sourcesContent":["/**\n * Choosing the one element a recorded subject names, among those `find` gives for its role and\n * name. Context tells them apart, and an element that does not repeat every part of the recorded\n * context is another subject, so a sole element left once its own has gone, such as Alice's\n * \"Remove\" after Bob has left, drifts rather than stands in:\n *\n * - a row is read whole: a row named \"Wrapped BTC\" is not the row \"BTC\". Laid out again without\n * rows, as cards, one of the element's fields must start with the row's words;\n * - a column counts where the element is under one;\n * - a label or heading must read the same, or its words appear, whole and in order, in one of the\n * element's fields, as `near` reads them.\n *\n * The rest are ranked by how much of the recorded context they read the same. There is no\n * ordinal, so a tie stays a tie.\n */\nimport { Effect, Schema } from \"effect\";\n\nimport type { Subject, SubjectContext } from \"../../BrowserEvent.ts\";\nimport type { Found } from \"../../Page.ts\";\nimport { match } from \"./match.inpage.ts\";\n\n/** Nothing on the page has the step's role and name. */\nexport class Missing extends Schema.TaggedError<Missing>()(\"Missing\", {}) {\n override get message() {\n return \"nothing on the page has the recorded role and name\";\n }\n}\n\n/** Several elements match the step's subject equally well, and nothing tells them apart. */\nexport class Ambiguous extends Schema.TaggedError<Ambiguous>()(\"Ambiguous\", {\n count: Schema.Int,\n}) {\n override get message() {\n return `${this.count} elements match the recorded subject equally well`;\n }\n}\n\n/** The page is not where the recording was: another site, or no element with its context. */\nexport class Drifted extends Schema.TaggedError<Drifted>()(\"Drifted\", {\n detail: Schema.String,\n}) {\n override get message() {\n return this.detail;\n }\n}\n\nconst { holds, normalize } = match();\nconst fields = [\"row\", \"column\", \"label\", \"heading\"] as const;\n\nconst said = (context: SubjectContext) =>\n Object.values(context).filter((value) => typeof value === \"string\");\n\n/** How an element repeats one recorded field: 2 read the same, 1 found as words, 0 not at all. */\nconst repeats = (field: (typeof fields)[number], value: string, context: SubjectContext) => {\n const own = context[field];\n\n if (own !== undefined && normalize(own) === normalize(value)) return 2;\n if (field === \"column\") return own === undefined ? 1 : 0;\n if (field === \"row\")\n return own === undefined &&\n said(context).some((other) => `${normalize(other)} `.startsWith(`${normalize(value)} `))\n ? 1\n : 0;\n\n return said(context).some((other) => holds(other, value)) ? 1 : 0;\n};\n\nexport const choose = (\n subject: Subject,\n found: ReadonlyArray<Found>,\n): Effect.Effect<Found, Missing | Ambiguous | Drifted> => {\n // `find` matched the role; a subject without one only matches elements without one.\n const named = found.filter((one) => subject.role !== null || one.subject.role === null);\n\n const kept = named.flatMap((one) => {\n let score = 0;\n\n for (const field of fields) {\n const value = subject.context[field];\n const repeated = value === undefined ? 0 : repeats(field, value, one.subject.context);\n\n if (value !== undefined && repeated === 0) return [];\n score += repeated;\n }\n\n return [{ one, score }];\n });\n\n const best = Math.max(...kept.map(({ score }) => score));\n const top = kept.filter(({ score }) => score === best);\n const [only] = top;\n\n if (named.length === 0) return Effect.fail(new Missing());\n if (kept.length === 0)\n return Effect.fail(new Drifted({ detail: \"no element named so repeats the recorded context\" }));\n\n return top.length === 1 && only !== undefined\n ? Effect.succeed(only.one)\n : Effect.fail(new Ambiguous({ count: top.length }));\n};\n","/**\n * A walk recorded once from a page's events and replayed later, on a fresh page, with no model\n * call.\n *\n * `fromEvents` keeps one page's completed actions with their subjects and the options they were\n * given, its navigations with both the address asked for and the one reached, and what was typed\n * as a named input slot, never the text itself. A navigation to an address whose credentials the\n * events withheld is an input slot too, so replay goes where the caller says, or nowhere, and\n * never to the address without them. `replay` takes the steps in turn. Before a step\n * except an opening navigate, back or reload, it waits for `Page.ready`; then it finds the element its\n * subject names, by role and name among those that repeat all its recorded context, and acts on\n * it. Text typed into focus was typed into the focused field, which replay finds the same way, and\n * text typed into a secret field goes into nothing else. An element step never falls back to\n * coordinates, and a step recorded at a point acts there only while the element found for it still\n * covers that point. `take` and `replay` return receipts; failure preserves a stopping point and\n * earlier receipts. Unknown consequential input is never resent. Only a positive durable read-back\n * can reconcile it; restoration follows the same rule. The consumer journals begun steps before\n * calling, treating interruption or a missing receipt as unknown. Plain recordings use version 1;\n * authored expected effects use version 2. Old 0.2 plans and unknown versions do not decode.\n *\n * @since 0.3.0\n */\nimport { Duration, Effect, Exit, Option, Schedule, Schema } from \"effect\";\n\nimport { BrowserError, InvalidRequest } from \"./BrowserError.ts\";\nimport {\n type Action,\n ActionOptions,\n Box,\n type BrowserEvent,\n type Navigated,\n Subject,\n} from \"./BrowserEvent.ts\";\nimport { undispatched } from \"./internal/page/context.ts\";\nimport { Ambiguous, choose, Drifted, Missing } from \"./internal/reading/choose.ts\";\nimport {\n type Found,\n type Page,\n type Point,\n type ReadyOptions,\n redacted,\n type Target,\n} from \"./Page.ts\";\n\nexport { Ambiguous, Drifted, Missing } from \"./internal/reading/choose.ts\";\n\nconst ViewportPoint = Schema.Struct({ x: Schema.Finite, y: Schema.Finite });\n\nexport const StepAction = Schema.Literals([\n \"navigate\",\n \"back\",\n \"reload\",\n \"click\",\n \"hover\",\n \"drag\",\n \"type\",\n \"press\",\n \"scroll\",\n \"select\",\n]);\n\nexport type StepAction = typeof StepAction.Type;\n\nconst Query = Schema.Struct({\n role: Schema.optional(Schema.String),\n name: Schema.optional(Schema.String),\n text: Schema.optional(Schema.String),\n});\n\n/**\n * What a step leaves. `durable` asserts an author-chosen, lasting read-back of this operation,\n * such as its uniquely named saved receipt or exact operation URL. Only Appeared and an exact\n * Navigated URL allow it; a toast, absence or relative navigation cannot establish recovery.\n * Relative navigation measures observed change from dispatch, without asserting causality.\n */\nexport const Expected = Schema.Union([\n Schema.TaggedStruct(\"Checked\", { checked: Schema.Boolean }),\n Schema.TaggedStruct(\"Appeared\", {\n query: Query,\n durable: Schema.optional(Schema.Literal(true)),\n }),\n Schema.TaggedStruct(\"Gone\", {\n query: Query,\n durable: Schema.optional(Schema.Never),\n }),\n Schema.TaggedStruct(\"Navigated\", {\n url: Schema.String,\n durable: Schema.optional(Schema.Literal(true)),\n }),\n Schema.TaggedStruct(\"Navigated\", {\n url: Schema.optional(Schema.Never),\n durable: Schema.optional(Schema.Never),\n }),\n]);\n\nexport type Expected = typeof Expected.Type;\n\n/** One recorded step: the action, what it acted on, and what else it was asked. */\nexport class Step extends Schema.Class<Step>(\"effect-browser/Plan/Step\")({\n action: StepAction,\n /**\n * The ending address, or a later recorded navigation before the next action began. Empty when\n * unknown; a delayed navigation can be stronger arrival evidence than the action's ending URL.\n */\n url: Schema.String,\n /** A navigation's requested address, or the keys a press pressed. */\n target: Schema.optional(Schema.String),\n subject: Schema.optional(Subject),\n /** Where a drag ended. */\n to: Schema.optional(Subject),\n /** The viewport point a step aimed at, when it aimed at a point, and a drag's end point. */\n point: Schema.optional(ViewportPoint),\n toPoint: Schema.optional(ViewportPoint),\n /** The box of what a step aimed at by point found there, so replay aims at the same place in it. */\n box: Schema.optional(Box),\n /**\n * The input slot whose text a `type` step types, or whose address a `navigate` step goes to, as\n * its recorded address had a credential withheld.\n */\n input: Schema.optional(Schema.String),\n /** The slot's text went into a secret field, so replay types it into nothing else. */\n secret: Schema.optional(Schema.Literal(true)),\n options: Schema.optional(ActionOptions),\n expect: Schema.optional(Expected),\n}) {}\n\nconst PlanData = Schema.Struct({\n version: Schema.Literals([1, 2]),\n steps: Schema.Array(Step),\n}).check(\n Schema.makeFilter((plan) =>\n plan.version === (plan.steps.some((step) => step.expect !== undefined) ? 2 : 1)\n ? undefined\n : \"only plans with expected effects use version 2\",\n ),\n);\n\nexport class Plan extends Schema.Class<Plan>(\"effect-browser/Plan\")(PlanData) {\n /** Choose the encoding version from the steps; simple recordings remain version 1. */\n static new(steps: ReadonlyArray<Step>): Plan {\n return new Plan({ version: steps.some((step) => step.expect !== undefined) ? 2 : 1, steps });\n }\n\n /** The input slots its steps type, in order; replay needs text for each. */\n get inputs(): ReadonlyArray<string> {\n return this.steps.flatMap((step) => (step.input === undefined ? [] : [step.input]));\n }\n}\n\n/** One completed step, on the page's host clock. `verified` means its expected effect was seen. */\nexport class Receipt extends Schema.Class<Receipt>(\"effect-browser/Plan/Receipt\")({\n step: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n outcome: Schema.Literals([\"taken\", \"verified\", \"skipped\"]),\n startedAt: Schema.Finite,\n at: Schema.Finite,\n}) {}\n\n/** Durable stopping data. A begun step without a receipt must be restored as `unknown`. */\nexport class Stopped extends Schema.Class<Stopped>(\"effect-browser/Plan/Stopped\")({\n step: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n input: Schema.Literals([\"unsent\", \"unknown\"]),\n}) {}\n\n/** Repeating this step could repeat an unresolved effect; the consumer must reconcile it. */\nexport class Uncertain extends Schema.TaggedError<Uncertain>()(\"Uncertain\", {\n detail: Schema.String,\n}) {\n override get message() {\n return this.detail;\n }\n}\n\n/** Where replay stopped, counting steps from 0, why, and the steps that completed before it. */\nexport class ReplayError extends Schema.TaggedError<ReplayError>()(\"ReplayError\", {\n step: Schema.Int,\n reason: Schema.Union([Missing, Ambiguous, Drifted, BrowserError, Uncertain]),\n input: Schema.Literals([\"unsent\", \"unknown\"]),\n receipts: Schema.Array(Receipt),\n}) {\n get stopped(): Stopped {\n return new Stopped({ step: this.step, input: this.input });\n }\n\n override get message() {\n return `step ${this.step} failed: ${this.reason.message}`;\n }\n}\n\nconst isStep = (event: BrowserEvent): event is Action & { readonly name: StepAction } =>\n event._tag === \"Action\" &&\n event.ok &&\n (StepAction.literals as ReadonlyArray<string>).includes(event.name);\n\n// A point target reads `x,y`, as `{\"x\":…,\"y\":…}` inside a drag's; a ref reads like e12.\nconst pointIn = (target: string | undefined): Point | undefined => {\n const parsed = /^\\{?(?:\"x\":)?(-?[\\d.]+),(?:\"y\":)?(-?[\\d.]+)\\}?$/.exec(target ?? \"\");\n\n return parsed === null ? undefined : { x: Number(parsed[1]), y: Number(parsed[2]) };\n};\n\n/** A slot named for the field it fills, such as `email`, unique within the plan. */\nconst slotFor = (taken: Set<string>, field: string | undefined) => {\n const base =\n field\n ?.toLowerCase()\n .match(/[\\p{L}\\p{N}]+/gu)\n ?.join(\"-\") ?? \"input\";\n\n let slot = base;\n\n for (let count = 2; taken.has(slot); count++) slot = `${base}-${count}`;\n taken.add(slot);\n\n return slot;\n};\n\n/**\n * The walk one page's events record: the completed actions of the page that acted first, in\n * order. `page.recentEvents` gives them, or `browser.events()` read until the walk ends.\n */\nexport const fromEvents = (events: Iterable<BrowserEvent>): Plan => {\n const all = Array.from(events);\n const page = all.find((event) => event._tag === \"Action\")?.page;\n const mine = all.filter((event) => \"page\" in event && event.page === page);\n const steps = mine.filter(isStep);\n const opened = mine.find((event) => event._tag === \"PageOpened\")?.url ?? \"\";\n const moves = mine.filter((event): event is Navigated => event._tag === \"Navigated\");\n const taken = new Set<string>();\n\n // Where the page was just before a time: the last address it reached by then.\n const before = (time: number) => moves.findLast((move) => move.at <= time)?.url ?? opened;\n\n return new Plan({\n version: 1,\n steps: steps.map((action, index) => {\n const drag = action.name === \"drag\" ? (action.target ?? \"\").split(\" -> \") : undefined;\n const point = pointIn(drag === undefined ? action.target : drag[0]);\n const until = steps[index + 1]?.startedAt ?? Number.POSITIVE_INFINITY;\n const arrival = moves.findLast((move) => move.at > action.at && move.at <= until);\n\n // Only a navigation and a press keep their target: an address, or keys.\n return new Step({\n action: action.name,\n url: arrival?.url ?? action.url ?? before(until),\n target: action.name === \"navigate\" || action.name === \"press\" ? action.target : undefined,\n subject: action.subject,\n to: action.to,\n point,\n toPoint: pointIn(drag?.[1]),\n box: point === undefined ? undefined : action.box,\n input:\n action.name === \"type\"\n ? slotFor(taken, action.subject?.name)\n : action.name === \"navigate\" && action.target?.includes(redacted) === true\n ? slotFor(taken, \"address\")\n : undefined,\n secret: action.name === \"type\" && action.text === redacted ? true : undefined,\n options: action.options,\n });\n }),\n });\n};\n\n/**\n * The one element on the page that a subject names, by role, name and context (see `Plan`),\n * looking again for two seconds while the page may still be drawing it.\n */\nexport const locate = (page: Page, subject: Subject) =>\n page\n .find({\n name: subject.name,\n scope: \"document\",\n ...(subject.role === null ? {} : { role: subject.role }),\n })\n .pipe(\n Effect.flatMap((found) => choose(subject, found)),\n Effect.retry({\n schedule: Schedule.spaced(Duration.millis(250)),\n times: 8,\n while: (error) => error._tag !== \"BrowserError\",\n }),\n Effect.withSpan(\"Plan.locate\", { attributes: { role: subject.role ?? \"\" } }),\n );\n\nconst invalid = (detail: string) => undispatched(\"replay\", new InvalidRequest({ detail }));\n\n/**\n * Where the step acts: the element its subject names, or, for a step recorded at a point, the same\n * place within that element, as long as a press there reaches that element and not one over it.\n * An element out of view is first brought into it, by hovering it, as a press by ref would be.\n */\nconst aim = (page: Page, subject: Subject | undefined, point?: Point, recorded?: Box) => {\n if (subject === undefined) return Effect.fail(invalid(\"the step names no element\"));\n if (point === undefined) return Effect.map(locate(page, subject), ({ ref }): Target => ref);\n\n const reach = ({ ref, box }: Found) => {\n const at =\n recorded === undefined || recorded.width <= 0 || recorded.height <= 0\n ? point\n : {\n x: box.x + ((point.x - recorded.x) / recorded.width) * box.width,\n y: box.y + ((point.y - recorded.y) / recorded.height) * box.height,\n };\n\n return Effect.map(page.find({ at }), ([reached]) => (reached?.ref === ref ? at : undefined));\n };\n\n const missed = new Drifted({ detail: \"a press at the subject's point reaches another element\" });\n\n return locate(page, subject).pipe(\n Effect.flatMap((found) =>\n Effect.flatMap(reach(found), (at) =>\n at !== undefined\n ? Effect.succeed<Target>(at)\n : page.hover(found.ref).pipe(\n Effect.andThen(locate(page, subject)),\n Effect.flatMap(reach),\n Effect.flatMap((again) =>\n again === undefined ? Effect.fail(missed) : Effect.succeed<Target>(again),\n ),\n ),\n ),\n ),\n );\n};\n\nconst dispatch = (\n page: Page,\n step: Step,\n text: string,\n): Effect.Effect<void, Missing | Ambiguous | Drifted | BrowserError> => {\n const options = step.options ?? {};\n\n switch (step.action) {\n case \"navigate\":\n return page.goto(step.input === undefined ? (step.target ?? step.url) : text);\n case \"back\":\n return page.back;\n case \"reload\":\n return page.reload;\n case \"press\":\n return step.subject === undefined\n ? page.press(step.target ?? \"\", options)\n : Effect.flatMap(locate(page, step.subject), ({ ref }) =>\n page.press(step.target ?? \"\", { ...options, on: ref }),\n );\n case \"click\":\n return aim(page, step.subject, step.point, step.box).pipe(\n Effect.flatMap((at) => page.click(at, options)),\n Effect.asVoid,\n );\n case \"hover\":\n return Effect.flatMap(aim(page, step.subject, step.point, step.box), page.hover);\n case \"drag\":\n return Effect.all([\n aim(page, step.subject, step.point),\n aim(page, step.to, step.toPoint),\n ]).pipe(Effect.flatMap(([from, to]) => page.drag(from, to)));\n case \"select\":\n return aim(page, step.subject).pipe(\n Effect.flatMap((at) => page.select(typeof at === \"string\" ? at : \"\", options.values ?? [])),\n Effect.asVoid,\n );\n // A scroll or a typing step may name no element: the page, or whatever has focus.\n case \"scroll\":\n return step.subject === undefined\n ? page.scroll(options)\n : Effect.flatMap(aim(page, step.subject, step.point, step.box), (at) =>\n page.scroll({ ...options, at }),\n );\n case \"type\":\n return step.subject === undefined\n ? page.type(text, { ...options, secret: step.secret })\n : Effect.flatMap(aim(page, step.subject), (into) =>\n page.type(text, {\n ...options,\n into: typeof into === \"string\" ? into : undefined,\n secret: step.secret,\n }),\n );\n }\n};\n\nexport interface TakeOptions {\n /** How each step waits first, except an opening navigation, or false. No final-step wait. */\n readonly settle?: ReadyOptions | false | undefined;\n readonly inputs?: Readonly<Record<string, string>> | undefined;\n /**\n * Bound for recorded arrival and expected effect, each. Defaults to 5 seconds. Zero makes one\n * read without polling; that read retains the page operation's timeout.\n */\n readonly arrival?: Duration.Input | undefined;\n}\n\nexport interface ReplayOptions extends TakeOptions {\n readonly from?: number | Stopped | undefined;\n}\n\n/**\n * Input that can be repeated without repeating a commitment. `take` also validates a Checked\n * target's boolean state before input. Back/reload can resubmit a form.\n */\nexport const repeatable = (step: Step): boolean =>\n [\"navigate\", \"hover\", \"scroll\", \"select\"].includes(step.action) ||\n (step.action === \"type\" &&\n step.subject !== undefined &&\n step.options?.replace !== false &&\n step.options?.submit !== true) ||\n (step.action === \"click\" && step.expect?._tag === \"Checked\");\n\ntype StepError = Missing | Ambiguous | Drifted | BrowserError | Uncertain;\n\n// Zero waits make one read; positive waits bound all reads and never repeat input.\nconst within = (check: Effect.Effect<boolean, StepError>, millis: number) =>\n millis === 0\n ? check\n : check.pipe(\n Effect.repeat({ until: (held) => held, schedule: Schedule.spaced(Duration.millis(25)) }),\n Effect.timeoutOrElse({\n duration: Duration.millis(millis),\n orElse: () => Effect.succeed(false),\n }),\n );\n\nconst sameSite = (url: string, recorded: string) => {\n const origin = URL.parse(recorded)?.origin;\n\n return (\n recorded === \"\" ||\n (origin === undefined || origin === \"null\"\n ? url === recorded\n : URL.parse(url)?.origin === origin)\n );\n};\n\nconst arrived = (page: Page, urls: ReadonlyArray<string>, millis: number) =>\n within(\n Effect.map(page.url, (url) => urls.some((recorded) => sameSite(url, recorded))),\n millis,\n ).pipe(\n Effect.filterOrFail(\n (held) => held,\n () =>\n new Drifted({ detail: \"the page did not reach the recorded site within the arrival wait\" }),\n ),\n Effect.asVoid,\n );\n\nconst checkEffect = (\n page: Page,\n step: Step,\n first?: { readonly url: string; readonly document: number },\n) => {\n const expected = step.expect;\n\n if (expected === undefined) return Effect.succeed(false);\n switch (expected._tag) {\n case \"Checked\":\n return step.subject === undefined\n ? Effect.fail(invalid(\"a checked effect needs a subject\"))\n : Effect.flatMap(locate(page, step.subject), (found) =>\n found.state.checked === undefined\n ? Effect.fail(invalid(\"a checked effect needs a checkable subject\"))\n : Effect.succeed(found.state.checked === expected.checked),\n );\n case \"Navigated\":\n if (expected.url === undefined && first === undefined) return Effect.succeed(false);\n\n return Effect.map(page.state, (now) =>\n expected.url === undefined\n ? now.url !== first?.url || now.document !== first?.document\n : now.url === expected.url,\n );\n case \"Appeared\":\n case \"Gone\":\n return Effect.map(page.find({ ...expected.query, scope: \"document\" }), (found) =>\n expected._tag === \"Appeared\" ? found.length > 0 : found.length === 0,\n );\n }\n};\n\n/**\n * Take one step. Unknown non-repeatable input is never resent: only positive durable read-back\n * can skip it. An interrupted call remains interrupted; persist begun-before-call in the consumer\n * and treat a missing receipt as Stopped{input: \"unknown\"}, including after process restart.\n */\nexport const take = Effect.fn(\"Plan.take\")(function* (\n page: Page,\n plan: Plan,\n at: number | Stopped,\n options: TakeOptions = {},\n): Effect.fn.Return<Receipt, ReplayError> {\n const index = typeof at === \"number\" ? at : at.step;\n let input: Stopped[\"input\"] = typeof at === \"number\" ? \"unsent\" : at.input;\n\n const work = Effect.gen(function* (): Effect.fn.Return<Receipt, StepError> {\n const step = plan.steps[index];\n\n if (!Number.isInteger(index) || index < 0 || step === undefined)\n return yield* invalid(\"the step index is outside the plan\");\n const duration = Duration.fromInput(options.arrival ?? Duration.seconds(5));\n\n if (\n Option.isNone(duration) ||\n Duration.isNegative(duration.value) ||\n !Duration.isFinite(duration.value)\n )\n return yield* invalid(\"arrival must be a finite nonnegative duration\");\n const millis = Duration.toMillis(duration.value);\n const first = yield* page.state;\n\n const uncertain = new Uncertain({\n detail: \"the step may have been sent; reconcile its durable effect before continuing\",\n });\n\n const unresolved = input === \"unknown\" && !repeatable(step);\n const expected = step.expect;\n\n const durable =\n expected !== undefined &&\n (expected._tag === \"Appeared\" ||\n (expected._tag === \"Navigated\" && typeof expected.url === \"string\")) &&\n expected.durable === true;\n\n if (\n !durable &&\n (unresolved || (expected !== undefined && \"durable\" in expected && expected.durable === true))\n )\n return yield* uncertain;\n if (\n options.settle !== false &&\n (index > 0 || ![\"navigate\", \"back\", \"reload\"].includes(step.action))\n )\n yield* page.ready(options.settle);\n const before = plan.steps[index - 1]?.url;\n\n if (before !== undefined)\n yield* arrived(page, unresolved ? [before, step.url] : [before], millis);\n const check = checkEffect(page, step);\n\n const read =\n millis === 0\n ? check\n : check.pipe(\n Effect.timeoutOrElse({\n duration: Duration.millis(millis),\n orElse: () =>\n Effect.fail(new Drifted({ detail: \"the expected-effect read timed out\" })),\n }),\n );\n\n const held = yield* read.pipe(Effect.mapError((error) => (unresolved ? uncertain : error)));\n\n const receipt = (outcome: Receipt[\"outcome\"]) =>\n Effect.gen(function* () {\n yield* arrived(page, [step.url], millis);\n const now = yield* page.state;\n\n return new Receipt({ step: index, outcome, startedAt: first.at, at: now.at });\n });\n\n if (held) return yield* receipt(\"skipped\");\n if (unresolved) return yield* uncertain;\n const text = step.input === undefined ? \"\" : options.inputs?.[step.input];\n\n if (text === undefined) return yield* invalid(`no text for the input \"${step.input ?? \"\"}\"`);\n const verify = checkEffect(page, step, yield* page.state);\n const acted = yield* Effect.exit(dispatch(page, step, text));\n\n if (Exit.isFailure(acted)) {\n const error = Exit.findErrorOption(acted);\n\n if (Option.isSome(error) && error.value._tag === \"BrowserError\" && error.value.dispatched) {\n input = \"unknown\";\n if (expected !== undefined && (repeatable(step) || durable)) {\n const observed = yield* Effect.exit(within(verify, millis));\n\n if (Exit.isSuccess(observed) && observed.value) return yield* receipt(\"verified\");\n }\n }\n\n return yield* Effect.failCause(acted.cause);\n }\n input = \"unknown\";\n if (expected !== undefined && !(yield* within(verify, millis)))\n return yield* new Drifted({ detail: \"the step's expected effect did not arrive\" });\n\n return yield* receipt(expected === undefined ? \"taken\" : \"verified\");\n });\n\n return yield* work.pipe(\n Effect.mapError(\n (reason) =>\n new ReplayError({\n step: index,\n reason,\n input,\n receipts: [],\n }),\n ),\n );\n});\n\nconst run = Effect.fnUntraced(function* (\n page: Page,\n plan: Plan,\n options: TakeOptions,\n from: number | Stopped,\n until: number,\n restoring: boolean,\n) {\n const receipts: Array<Receipt> = [];\n const start = typeof from === \"number\" ? from : from.step;\n\n if (\n !Number.isInteger(start) ||\n start < 0 ||\n start > plan.steps.length ||\n !Number.isInteger(until) ||\n until < start ||\n until > plan.steps.length\n )\n return yield* new ReplayError({\n step: start,\n input: \"unsent\",\n receipts,\n reason: invalid(\"the run bounds are outside the plan\"),\n });\n // Fresh runs still ask for all input slots before changing the page. Restoration checks first.\n if (!restoring && typeof from === \"number\") {\n const unfilled = plan.steps.findIndex(\n (step, index) =>\n index >= start && step.input !== undefined && options.inputs?.[step.input] === undefined,\n );\n\n if (unfilled !== -1)\n return yield* new ReplayError({\n step: start,\n input: \"unsent\",\n receipts,\n reason: invalid(`no text for the input \"${plan.steps[unfilled]?.input ?? \"\"}\"`),\n });\n }\n for (let index = start; index < until; index++) {\n const at = restoring\n ? new Stopped({ step: index, input: \"unknown\" })\n : index === start\n ? from\n : index;\n\n const receipt = yield* take(page, plan, at, options).pipe(\n Effect.mapError((error) => new ReplayError({ ...error, receipts: [...receipts] })),\n );\n\n receipts.push(receipt);\n }\n\n return receipts;\n});\n\n/** Take a plan's steps from a fresh index or durable stopping point, returning completed receipts. */\nexport const replay = (page: Page, plan: Plan, options: ReplayOptions = {}) =>\n run(page, plan, options, options.from ?? 0, plan.steps.length, false).pipe(\n Effect.withSpan(\"Plan.replay\"),\n );\n\n/** Restore prior steps on a fresh page; unresolved commitments require positive durable evidence. */\nexport const restore = (\n page: Page,\n plan: Plan,\n options: TakeOptions & { readonly upTo?: number | undefined } = {},\n) =>\n run(page, plan, options, 0, options.upTo ?? plan.steps.length, true).pipe(\n Effect.withSpan(\"Plan.restore\"),\n );\n"],"mappings":"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"}
|
package/dist/Plan.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as take, a as ReplayError, b as Missing, c as StepAction, d as Uncertain, f as fromEvents, g as restore, h as replay, i as Receipt, l as Stopped, m as repeatable, n as Plan, o as ReplayOptions, p as locate, s as Step, t as Expected, u as TakeOptions, v as Ambiguous, y as Drifted } from "./Plan-
|
|
1
|
+
import { _ as take, a as ReplayError, b as Missing, c as StepAction, d as Uncertain, f as fromEvents, g as restore, h as replay, i as Receipt, l as Stopped, m as repeatable, n as Plan, o as ReplayOptions, p as locate, s as Step, t as Expected, u as TakeOptions, v as Ambiguous, y as Drifted } from "./Plan-6As6vcwT.mjs";
|
|
2
2
|
export { Ambiguous, Drifted, Expected, Missing, Plan, Receipt, ReplayError, ReplayOptions, Step, StepAction, Stopped, TakeOptions, Uncertain, fromEvents, locate, repeatable, replay, restore, take };
|
package/dist/Plan.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as Drifted, a as ReplayError, c as Stopped, d as locate, f as repeatable, g as Ambiguous, h as take, i as Receipt, l as Uncertain, m as restore, n as Plan, o as Step, p as replay, s as StepAction, t as Expected, u as fromEvents, v as Missing } from "./Plan-
|
|
1
|
+
import { _ as Drifted, a as ReplayError, c as Stopped, d as locate, f as repeatable, g as Ambiguous, h as take, i as Receipt, l as Uncertain, m as restore, n as Plan, o as Step, p as replay, s as StepAction, t as Expected, u as fromEvents, v as Missing } from "./Plan-CXA2BW-G.mjs";
|
|
2
2
|
export { Ambiguous, Drifted, Expected, Missing, Plan, Receipt, ReplayError, Step, StepAction, Stopped, Uncertain, fromEvents, locate, repeatable, replay, restore, take };
|
package/dist/Policy.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as InputGuard, i as Fact, l as InputRequest } from "./Page-
|
|
1
|
+
import { c as InputGuard, i as Fact, l as InputRequest } from "./Page-DL9eylp3.mjs";
|
|
2
2
|
import { Context, Duration, Effect, Schema } from "effect";
|
|
3
3
|
import { AiError, DecisionModel, LanguageModel } from "effect/ai";
|
|
4
4
|
declare namespace Policy_d_exports {
|
package/dist/Presentation.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as Target, u as Page } from "./Page-
|
|
1
|
+
import { b as Target, u as Page } from "./Page-DL9eylp3.mjs";
|
|
2
2
|
import { Service, t as Motion_d_exports } from "./Motion.mjs";
|
|
3
3
|
import { Duration, Effect } from "effect";
|
|
4
4
|
declare namespace Presentation_d_exports {
|
package/dist/Presentation.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { lognormal } from "./Motion.mjs";
|
|
3
|
-
import { a as performed, i as pause, r as viewOf, t as internalsOf } from "./page-
|
|
3
|
+
import { a as performed, i as pause, r as viewOf, t as internalsOf } from "./page-B92QnRfT.mjs";
|
|
4
4
|
import { Clock, Duration, Effect, Fiber, MutableRef, Option, Semaphore } from "effect";
|
|
5
5
|
//#region src/Presentation.ts
|
|
6
6
|
/**
|
package/dist/Stage.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as BrowserError } from "./BrowserError-Coy7EW1N.mjs";
|
|
2
|
-
import { n as CaptureStats, o as ScreencastOptions, r as Frame } from "./Frame-
|
|
3
|
-
import { u as Page } from "./Page-
|
|
2
|
+
import { n as CaptureStats, o as ScreencastOptions, r as Frame } from "./Frame-DkNdjjjr.mjs";
|
|
3
|
+
import { u as Page } from "./Page-DL9eylp3.mjs";
|
|
4
4
|
import { Duration, Effect, Option, Schema, Scope, Stream } from "effect";
|
|
5
5
|
declare namespace Stage_d_exports {
|
|
6
6
|
export { Cue, Options, Presented, Shown, Stage, make };
|
|
@@ -25,10 +25,11 @@ export interface Cue {
|
|
|
25
25
|
readonly at?: number | undefined;
|
|
26
26
|
}) => Effect.Effect<Presented, BrowserError>;
|
|
27
27
|
}
|
|
28
|
-
/** What the output establishes
|
|
28
|
+
/** What the output establishes at nondecreasing host times; frames retain their capture times. */
|
|
29
29
|
export type Shown = {
|
|
30
30
|
readonly _tag: "Painted";
|
|
31
31
|
readonly frame: Frame;
|
|
32
|
+
readonly at: number;
|
|
32
33
|
} | {
|
|
33
34
|
readonly _tag: "Still";
|
|
34
35
|
readonly frame: Frame;
|
|
@@ -51,7 +52,7 @@ export interface Stage {
|
|
|
51
52
|
readonly shown: (options: {
|
|
52
53
|
readonly hold: Duration.Input;
|
|
53
54
|
}) => Stream.Stream<Shown>;
|
|
54
|
-
/**
|
|
55
|
+
/** Capture-timed current-page paint; use `shown` for output time. Readers retain 16 frames. */
|
|
55
56
|
readonly frames: Stream.Stream<Frame>;
|
|
56
57
|
readonly current: Effect.Effect<Option.Option<Page>>;
|
|
57
58
|
readonly stats: (options?: {
|
package/dist/Stage.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { Closed, InvalidRequest, Timeout, consequence } from "./BrowserError.mjs";
|
|
3
3
|
import { i as failWith, s as undispatched } from "./context-BAjRj7Xo.mjs";
|
|
4
|
-
import { t as internalsOf } from "./page-
|
|
4
|
+
import { t as internalsOf } from "./page-B92QnRfT.mjs";
|
|
5
5
|
import { Cause, Clock, Deferred, Duration, Effect, Exit, Fiber, Option, PubSub, Result, Schedule, Schema, Scope, Stream } from "effect";
|
|
6
6
|
//#region src/Stage.ts
|
|
7
7
|
/**
|
|
@@ -21,7 +21,7 @@ var Presented = class extends Schema.Class("effect-browser/Presented")({
|
|
|
21
21
|
at: Schema.Finite,
|
|
22
22
|
latency: Schema.Finite
|
|
23
23
|
}) {};
|
|
24
|
-
const
|
|
24
|
+
const unavailable = () => undispatched("cue", new InvalidRequest({ detail: "the cue's capture is no longer available" }));
|
|
25
25
|
/** The sole writer of a cue's capture lifecycle; presentation ownership belongs to the stage. */
|
|
26
26
|
const update = (feed, input) => {
|
|
27
27
|
if (feed.state._tag === "Stopped") return;
|
|
@@ -48,9 +48,9 @@ const frameOf = (feed) => {
|
|
|
48
48
|
const internals = internalsOf(feed.page);
|
|
49
49
|
return frame !== void 0 && (internals === void 0 || internals.current(frame)) ? frame : void 0;
|
|
50
50
|
};
|
|
51
|
-
const ended = (feed) => feed.fiber === void 0 ? Effect.never : Fiber.await(feed.fiber).pipe(Effect.flatMap((exit) => Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause) ? Effect.failCause(exit.cause) : Effect.fail(
|
|
51
|
+
const ended = (feed) => feed.fiber === void 0 ? Effect.never : Fiber.await(feed.fiber).pipe(Effect.flatMap((exit) => Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause) ? Effect.failCause(exit.cause) : Effect.fail(unavailable())));
|
|
52
52
|
const firstOf = (feed, wait) => Effect.suspend(() => {
|
|
53
|
-
if (feed.state._tag === "Stopped") return Effect.fail(
|
|
53
|
+
if (feed.state._tag === "Stopped") return Effect.fail(unavailable());
|
|
54
54
|
if (feed.page.playwright.isClosed()) return failWith("cue", new Closed({ cause: "page" }));
|
|
55
55
|
if (frameOf(feed) !== void 0) return Effect.void;
|
|
56
56
|
return Effect.raceFirst(Stream.fromPubSub(feed.changed).pipe(Stream.filter(() => frameOf(feed) !== void 0), Stream.runHead, Effect.asVoid), ended(feed)).pipe(Effect.timeoutOrElse({
|
|
@@ -86,6 +86,8 @@ const evidence = (output, current, now, hold) => Stream.unwrap(Effect.sync(() =>
|
|
|
86
86
|
if (Option.isNone(parsed) || !Duration.isFinite(parsed.value) || !Duration.isPositive(parsed.value)) throw new RangeError("shown hold must be a finite positive duration");
|
|
87
87
|
const millis = Duration.toMillis(parsed.value);
|
|
88
88
|
let checkedAt = now();
|
|
89
|
+
let shownAt = Number.NEGATIVE_INFINITY;
|
|
90
|
+
let seen = current();
|
|
89
91
|
let gone;
|
|
90
92
|
const probe = Effect.gen(function* () {
|
|
91
93
|
yield* until(Math.max(checkedAt, current()?.changedAt ?? checkedAt) + millis, now);
|
|
@@ -98,24 +100,54 @@ const evidence = (output, current, now, hold) => Stream.unwrap(Effect.sync(() =>
|
|
|
98
100
|
if (current()?.feed !== feed || current()?.frame !== frame) return Option.none();
|
|
99
101
|
const at = now();
|
|
100
102
|
checkedAt = at;
|
|
101
|
-
if (Result.isFailure(confirmed) && consequence(confirmed.failure).lost !== "nothing") {
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
if (Result.isFailure(confirmed) && consequence(confirmed.failure).lost !== "nothing") return Option.some({
|
|
104
|
+
feed,
|
|
105
|
+
frame,
|
|
106
|
+
value: {
|
|
104
107
|
_tag: "Gone",
|
|
105
108
|
page: feed.page.id,
|
|
106
109
|
at
|
|
107
|
-
}
|
|
108
|
-
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
109
112
|
return Option.some({
|
|
110
|
-
|
|
113
|
+
feed,
|
|
111
114
|
frame,
|
|
112
|
-
|
|
115
|
+
value: {
|
|
116
|
+
_tag: Result.isSuccess(confirmed) && confirmed.success ? "Still" : "Stalled",
|
|
117
|
+
frame,
|
|
118
|
+
at
|
|
119
|
+
}
|
|
113
120
|
});
|
|
114
121
|
});
|
|
115
|
-
return Stream.merge(Stream.fromPubSub(output).pipe(Stream.
|
|
116
|
-
|
|
117
|
-
frame
|
|
118
|
-
|
|
122
|
+
return Stream.merge(Stream.fromPubSub(output).pipe(Stream.map(({ feed, frame, at }) => ({
|
|
123
|
+
feed,
|
|
124
|
+
frame,
|
|
125
|
+
value: {
|
|
126
|
+
_tag: "Painted",
|
|
127
|
+
frame,
|
|
128
|
+
at
|
|
129
|
+
}
|
|
130
|
+
}))), Stream.fromEffectRepeat(probe).pipe(Stream.filter(Option.isSome), Stream.map(({ value }) => value))).pipe(Stream.filter(({ feed, frame, value }) => {
|
|
131
|
+
if (value._tag === "Painted" && gone !== feed) {
|
|
132
|
+
seen = {
|
|
133
|
+
feed,
|
|
134
|
+
frame
|
|
135
|
+
};
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
seen ??= {
|
|
139
|
+
feed,
|
|
140
|
+
frame
|
|
141
|
+
};
|
|
142
|
+
return value._tag !== "Painted" && seen?.feed === feed && seen.frame === frame;
|
|
143
|
+
}), Stream.map(({ feed, value }) => {
|
|
144
|
+
if (value._tag === "Gone") gone = feed;
|
|
145
|
+
shownAt = Math.max(shownAt, value.at);
|
|
146
|
+
return value.at === shownAt ? value : {
|
|
147
|
+
...value,
|
|
148
|
+
at: shownAt
|
|
149
|
+
};
|
|
150
|
+
}));
|
|
119
151
|
}));
|
|
120
152
|
const openFeed = (page, owner, clock, settings, current, publish) => Effect.gen(function* () {
|
|
121
153
|
const scope = yield* Scope.fork(owner);
|
|
@@ -174,15 +206,16 @@ const make = Effect.fn("Stage.make")(function* (options = {}) {
|
|
|
174
206
|
let showing;
|
|
175
207
|
let painted = Number.NEGATIVE_INFINITY;
|
|
176
208
|
yield* Effect.addFinalizer(() => PubSub.shutdown(output));
|
|
177
|
-
const publish = (feed, frame) => Effect.suspend(() => {
|
|
178
|
-
painted = Math.max(painted,
|
|
209
|
+
const publish = (feed, frame, at = frame.hostTime) => Effect.suspend(() => {
|
|
210
|
+
painted = Math.max(painted, at);
|
|
179
211
|
if (showing !== void 0) {
|
|
180
212
|
showing.changedAt = now();
|
|
181
213
|
showing.frame = frame;
|
|
182
214
|
}
|
|
183
215
|
return PubSub.publish(output, {
|
|
184
216
|
feed,
|
|
185
|
-
frame
|
|
217
|
+
frame,
|
|
218
|
+
at: painted
|
|
186
219
|
});
|
|
187
220
|
});
|
|
188
221
|
const commit = (feed, options = {}) => Effect.suspend(() => {
|
|
@@ -195,7 +228,7 @@ const make = Effect.fn("Stage.make")(function* (options = {}) {
|
|
|
195
228
|
yield* Effect.raceFirst(until(asked, now), ended(feed));
|
|
196
229
|
const switchTo = Effect.suspend(() => {
|
|
197
230
|
const frame = frameOf(feed);
|
|
198
|
-
if (frame === void 0) return Effect.fail(
|
|
231
|
+
if (frame === void 0) return Effect.fail(unavailable());
|
|
199
232
|
const at = Math.max(now(), asked, frame.hostTime, painted);
|
|
200
233
|
showing = {
|
|
201
234
|
feed,
|
|
@@ -207,7 +240,7 @@ const make = Effect.fn("Stage.make")(function* (options = {}) {
|
|
|
207
240
|
}),
|
|
208
241
|
changedAt: at
|
|
209
242
|
};
|
|
210
|
-
return publish(feed, frame).pipe(Effect.as(showing.presented));
|
|
243
|
+
return publish(feed, frame, at).pipe(Effect.as(showing.presented));
|
|
211
244
|
}).pipe(Effect.uninterruptible);
|
|
212
245
|
const readyToSwitch = firstOf(feed, firstFrame).pipe(Effect.andThen(switchTo), Effect.provideService(Clock.Clock, clock));
|
|
213
246
|
const before = old === void 0 ? void 0 : internalsOf(old.feed.page);
|