effect-browser 0.2.0-beta.9 → 0.3.0-beta.10
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 +849 -1161
- package/dist/Browser-S4kvpmqa.mjs +605 -0
- package/dist/Browser-S4kvpmqa.mjs.map +1 -0
- package/dist/Browser.d.mts +127 -3
- package/dist/Browser.mjs +2 -22
- package/dist/BrowserError-Coy7EW1N.d.mts +140 -0
- package/dist/BrowserError.d.mts +2 -0
- package/dist/BrowserError.mjs +211 -0
- package/dist/BrowserError.mjs.map +1 -0
- package/dist/BrowserEvent-BRu2juEz.d.mts +279 -0
- package/dist/BrowserEvent.d.mts +2 -0
- package/dist/BrowserEvent.mjs +297 -0
- package/dist/BrowserEvent.mjs.map +1 -0
- package/dist/Cdp.d.mts +32 -0
- package/dist/Cdp.mjs +61 -0
- package/dist/Cdp.mjs.map +1 -0
- package/dist/Change-DNvztNLu.mjs +138 -0
- package/dist/Change-DNvztNLu.mjs.map +1 -0
- package/dist/Change-iMlcuzVD.d.mts +71 -0
- package/dist/Change.d.mts +2 -0
- package/dist/Change.mjs +2 -0
- package/dist/Chromium.d.mts +29 -81
- package/dist/Chromium.mjs +57 -392
- package/dist/Chromium.mjs.map +1 -1
- package/dist/Expect.d.mts +62 -0
- package/dist/Expect.mjs +114 -0
- package/dist/Expect.mjs.map +1 -0
- package/dist/Frame-BERmf_gM.d.mts +117 -0
- package/dist/Frame.d.mts +2 -0
- package/dist/Frame.mjs +123 -0
- package/dist/Frame.mjs.map +1 -0
- package/dist/Moment.d.mts +2 -0
- package/dist/Moment.mjs +288 -0
- package/dist/Moment.mjs.map +1 -0
- package/dist/Motion.d.mts +40 -0
- package/dist/Motion.mjs +122 -0
- package/dist/Motion.mjs.map +1 -0
- package/dist/Page-B5cjaUp5.mjs +618 -0
- package/dist/Page-B5cjaUp5.mjs.map +1 -0
- package/dist/Page-BlPjfibv.d.mts +595 -0
- package/dist/Page.d.mts +2 -0
- package/dist/Page.mjs +2 -0
- package/dist/Plan-BI8XGvDu.d.mts +209 -0
- package/dist/Plan-D1wrJVs8.mjs +508 -0
- package/dist/Plan-D1wrJVs8.mjs.map +1 -0
- package/dist/Plan.d.mts +2 -3
- package/dist/Plan.mjs +2 -2
- package/dist/Policy.d.mts +76 -0
- package/dist/Policy.mjs +237 -0
- package/dist/Policy.mjs.map +1 -0
- package/dist/Presentation.d.mts +48 -0
- package/dist/Presentation.mjs +117 -0
- package/dist/Presentation.mjs.map +1 -0
- package/dist/Snapshot-B34hZ4Jl.d.mts +68 -0
- package/dist/Snapshot.d.mts +2 -0
- package/dist/Snapshot.mjs +79 -0
- package/dist/Snapshot.mjs.map +1 -0
- package/dist/Stage.d.mts +64 -0
- package/dist/Stage.mjs +237 -0
- package/dist/Stage.mjs.map +1 -0
- package/dist/Supervisor-CYWFK3vM.d.mts +280 -0
- package/dist/Supervisor-TNKNOVzu.mjs +599 -0
- package/dist/Supervisor-TNKNOVzu.mjs.map +1 -0
- package/dist/Supervisor.d.mts +2 -0
- package/dist/Supervisor.mjs +2 -0
- package/dist/context-B6xr8nVi.mjs +261 -0
- package/dist/context-B6xr8nVi.mjs.map +1 -0
- package/dist/index.d.mts +17 -14
- package/dist/index.mjs +18 -13
- package/dist/match.inpage-xOe9LNO0.mjs +48 -0
- package/dist/match.inpage-xOe9LNO0.mjs.map +1 -0
- package/dist/page-B8tUQELg.mjs +5073 -0
- package/dist/page-B8tUQELg.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/url-Cd04Okid.mjs +264 -0
- package/dist/url-Cd04Okid.mjs.map +1 -0
- package/package.json +96 -61
- package/src/Browser.ts +666 -0
- package/src/BrowserError.ts +234 -0
- package/src/BrowserEvent.ts +296 -0
- package/src/Cdp.ts +101 -0
- package/src/Change.ts +88 -0
- package/src/Chromium.ts +102 -0
- package/src/Expect.ts +180 -0
- package/src/Frame.ts +130 -0
- package/src/Moment.ts +479 -0
- package/src/Motion.ts +166 -0
- package/src/Page.ts +522 -0
- package/src/Plan.ts +663 -0
- package/src/Policy.ts +325 -0
- package/src/Presentation.ts +195 -0
- package/src/Snapshot.ts +89 -0
- package/src/Stage.ts +467 -0
- package/src/Supervisor.ts +599 -0
- package/src/index.ts +20 -0
- package/src/internal/input/actions.ts +610 -0
- package/src/internal/input/dispatch.ts +161 -0
- package/src/internal/input/edit.inpage.ts +162 -0
- package/src/internal/input/evidence.inpage.ts +164 -0
- package/src/internal/input/gate.ts +224 -0
- package/src/internal/input/guard.inpage.ts +605 -0
- package/src/internal/input/guard.ts +184 -0
- package/src/internal/input/keyboard.ts +112 -0
- package/src/internal/input/keys.ts +127 -0
- package/src/internal/input/perform.ts +376 -0
- package/src/internal/input/pointer.ts +153 -0
- package/src/internal/input/replies.ts +195 -0
- package/src/internal/input/settle.ts +50 -0
- package/src/internal/input/style.ts +186 -0
- package/src/internal/input/targets.inpage.ts +293 -0
- package/src/internal/input/targets.ts +148 -0
- package/src/internal/page/bridge.ts +386 -0
- package/src/internal/page/context.ts +312 -0
- package/src/internal/page/lane.ts +311 -0
- package/src/internal/page/navigation.ts +183 -0
- package/src/internal/page/openings.ts +87 -0
- package/src/internal/page/page.ts +165 -0
- package/src/internal/page/url.ts +100 -0
- package/src/internal/page/viewport.ts +43 -0
- package/src/internal/pictures/capture.ts +776 -0
- package/src/internal/pictures/clock.ts +141 -0
- package/src/internal/pictures/counts.ts +92 -0
- package/src/internal/pictures/pictures.ts +520 -0
- package/src/internal/pictures/transport.ts +242 -0
- package/src/internal/reading/choose.ts +100 -0
- package/src/internal/reading/context.inpage.ts +201 -0
- package/src/internal/reading/controls.inpage.ts +158 -0
- package/src/internal/reading/expect.inpage.ts +70 -0
- package/src/internal/reading/match.inpage.ts +92 -0
- package/src/internal/reading/names.inpage.ts +306 -0
- package/src/internal/reading/outline.inpage.ts +260 -0
- package/src/internal/reading/reading.ts +223 -0
- package/src/internal/reading/ready.inpage.ts +164 -0
- package/src/internal/reading/ready.ts +111 -0
- package/src/internal/reading/subjects.inpage.ts +188 -0
- package/src/internal/reading/text.inpage.ts +135 -0
- package/src/internal/reading/walk.inpage.ts +220 -0
- package/src/internal/supervisor/lifecycle.ts +416 -0
- package/src/internal/timeline/changes.inpage.ts +216 -0
- package/src/internal/timeline/changes.ts +100 -0
- package/src/internal/timeline/events.ts +94 -0
- package/src/internal/timeline/fold.inpage.ts +123 -0
- package/src/internal/timeline/history.inpage.ts +229 -0
- package/src/internal/timeline/marks.inpage.ts +207 -0
- package/src/internal/timeline/record.inpage.ts +133 -0
- package/src/internal/timeline/sight.inpage.ts +122 -0
- package/src/internal/timeline/window.ts +96 -0
- package/src/internal/timeline/words.ts +65 -0
- package/dist/Bootstrap-B9UUXsvF.d.mts +0 -183
- package/dist/Bootstrap-CeQOWBy6.mjs +0 -189
- package/dist/Bootstrap-CeQOWBy6.mjs.map +0 -1
- package/dist/Bootstrap.d.mts +0 -3
- package/dist/Bootstrap.mjs +0 -2
- package/dist/Browser-BF9_sORP.d.mts +0 -388
- package/dist/Browser.mjs.map +0 -1
- package/dist/BrowserData-CPIIIHol.d.mts +0 -585
- package/dist/BrowserData.d.mts +0 -3
- package/dist/BrowserData.mjs +0 -695
- package/dist/BrowserData.mjs.map +0 -1
- package/dist/BrowserRuntime-B6nT1G4X.d.mts +0 -148
- package/dist/BrowserRuntime-C1r2aSRK.mjs +0 -6820
- package/dist/BrowserRuntime-C1r2aSRK.mjs.map +0 -1
- package/dist/BrowserRuntime.d.mts +0 -3
- package/dist/BrowserRuntime.mjs +0 -3
- package/dist/Capture.d.mts +0 -56
- package/dist/Capture.mjs +0 -678
- package/dist/Capture.mjs.map +0 -1
- package/dist/CaptureData-CYriZHX1.mjs +0 -201
- package/dist/CaptureData-CYriZHX1.mjs.map +0 -1
- package/dist/CaptureData.d.mts +0 -219
- package/dist/CaptureData.mjs +0 -2
- package/dist/Errors.d.mts +0 -158
- package/dist/Errors.mjs +0 -207
- package/dist/Errors.mjs.map +0 -1
- package/dist/Images-yCG9BmRU.mjs +0 -76
- package/dist/Images-yCG9BmRU.mjs.map +0 -1
- package/dist/OperationOptions-DAeRS6O9.mjs +0 -55
- package/dist/OperationOptions-DAeRS6O9.mjs.map +0 -1
- package/dist/PageControl.d.mts +0 -15
- package/dist/PageControl.mjs +0 -34
- package/dist/PageControl.mjs.map +0 -1
- package/dist/PageRegistry-B3q9DS3g.mjs +0 -164
- package/dist/PageRegistry-B3q9DS3g.mjs.map +0 -1
- package/dist/Plan-Dyxu2q8C.mjs +0 -543
- package/dist/Plan-Dyxu2q8C.mjs.map +0 -1
- package/dist/PlanData-B668RxbQ.d.mts +0 -4831
- package/dist/PlanData.d.mts +0 -3
- package/dist/PlanData.mjs +0 -268
- package/dist/PlanData.mjs.map +0 -1
- package/dist/PlanInput-BJcPPncs.mjs +0 -75
- package/dist/PlanInput-BJcPPncs.mjs.map +0 -1
- package/dist/PublicSession-DCSMMqOj.mjs +0 -5602
- package/dist/PublicSession-DCSMMqOj.mjs.map +0 -1
- package/dist/Testing.d.mts +0 -479
- package/dist/Testing.mjs +0 -2147
- package/dist/Testing.mjs.map +0 -1
- package/dist/Timeline-fV22Xk-S.d.mts +0 -29
- package/dist/Timeline.d.mts +0 -4
- package/dist/Timeline.mjs +0 -20
- package/dist/Timeline.mjs.map +0 -1
- package/dist/TimelineData-BsOn-YGZ.d.mts +0 -3818
- package/dist/TimelineData.d.mts +0 -3
- package/dist/TimelineData.mjs +0 -482
- package/dist/TimelineData.mjs.map +0 -1
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { Box, PageLoaded, Subject, SubjectContext } from "./BrowserEvent.mjs";
|
|
3
|
+
import { c as FailFast, o as withheld, s as Correlation } from "./url-Cd04Okid.mjs";
|
|
4
|
+
import { Frame, Image } from "./Frame.mjs";
|
|
5
|
+
import { Effect, Schema } from "effect";
|
|
6
|
+
//#region src/internal/input/evidence.inpage.ts
|
|
7
|
+
/**
|
|
8
|
+
* In the page: what the page says about an input's first target, for a judge, and which fields a
|
|
9
|
+
* form would send. It never reads what a field holds. See `reading/names.inpage.ts` for what a page-side part may use.
|
|
10
|
+
*/
|
|
11
|
+
const evidence = (names, placing) => {
|
|
12
|
+
const { clean, isDocument, isInput, isSelect, isTextArea, nameOf, parentOf, roleOf, textOf } = names;
|
|
13
|
+
const { groups, headingBefore, textBeside, treeOf } = placing;
|
|
14
|
+
/** A field a submission would send. */
|
|
15
|
+
const isField = (element) => (isInput(element) && ![
|
|
16
|
+
"button",
|
|
17
|
+
"submit",
|
|
18
|
+
"reset",
|
|
19
|
+
"image"
|
|
20
|
+
].includes(element.type) || isSelect(element) || isTextArea(element)) && !element.matches(":disabled");
|
|
21
|
+
const isFilled = (field) => isInput(field) && (field.type === "checkbox" || field.type === "radio") ? field.checked : isInput(field) && field.type === "file" ? (field.files?.length ?? 0) > 0 : field.value !== "";
|
|
22
|
+
const dialogOf = (element) => {
|
|
23
|
+
for (let node = element; node !== null; node = parentOf(node)) if (node.tagName === "DIALOG" || /^(?:alert)?dialog$/.test(node.getAttribute("role") ?? "")) return node;
|
|
24
|
+
};
|
|
25
|
+
/** What the page says about an input's first target, for a judge. Never a field's value. */
|
|
26
|
+
const evidenceOf = (element, form, method, action) => {
|
|
27
|
+
const name = nameOf(element, roleOf(element));
|
|
28
|
+
const ids = element.getAttribute("aria-describedby");
|
|
29
|
+
const description = clean(ids === null ? element.getAttribute("aria-description") ?? element.getAttribute("title") : ids.split(/\s+/).map((id) => element.ownerDocument.getElementById(id)?.textContent ?? "").join(" "), 120);
|
|
30
|
+
const dialog = dialogOf(element);
|
|
31
|
+
const title = dialog?.querySelector("h1,h2,h3,h4,h5,h6,[role=heading]");
|
|
32
|
+
const dialogName = dialog === void 0 ? "" : clean(nameOf(dialog, "dialog"), 120) || (title === null || title === void 0 ? "" : clean(textOf(title), 120));
|
|
33
|
+
const root = element.getRootNode();
|
|
34
|
+
const top = isDocument(root) ? root.body ?? root : root;
|
|
35
|
+
const inTree = element.closest("dialog,[role=dialog],[role=alertdialog]");
|
|
36
|
+
let nearby = "";
|
|
37
|
+
for (const scope of /* @__PURE__ */ new Set([
|
|
38
|
+
element.closest(groups),
|
|
39
|
+
inTree,
|
|
40
|
+
top
|
|
41
|
+
])) if (scope !== null && nearby === "") nearby = textBeside(element, scope, true) || textBeside(element, scope, false);
|
|
42
|
+
const heading = headingBefore(element, treeOf(element));
|
|
43
|
+
const fields = form === null ? [] : Array.from(form.elements).filter(isField).slice(0, 16).map((field) => {
|
|
44
|
+
const autocomplete = clean(field.getAttribute("autocomplete"), 40);
|
|
45
|
+
return {
|
|
46
|
+
type: isInput(field) ? field.type : field.tagName.toLowerCase(),
|
|
47
|
+
name: clean(isInput(field) && field.type === "hidden" ? field.getAttribute("name") : nameOf(field, roleOf(field)), 40),
|
|
48
|
+
...autocomplete === "" ? {} : { autocomplete },
|
|
49
|
+
filled: isFilled(field)
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
title: clean(document.title, 120),
|
|
54
|
+
...description === "" || description === name ? {} : { description },
|
|
55
|
+
...dialogName === "" ? {} : { dialog: dialogName },
|
|
56
|
+
...heading === void 0 ? {} : { heading },
|
|
57
|
+
...nearby === "" ? {} : { nearby },
|
|
58
|
+
...form === null ? {} : { form: {
|
|
59
|
+
method: method ?? form.method,
|
|
60
|
+
action: action ?? form.action,
|
|
61
|
+
fields
|
|
62
|
+
} }
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
evidenceOf,
|
|
67
|
+
isField,
|
|
68
|
+
isFilled
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
const FormFieldSchema = Schema.Struct({
|
|
72
|
+
type: Schema.String,
|
|
73
|
+
name: Schema.String,
|
|
74
|
+
autocomplete: Schema.optional(Schema.String),
|
|
75
|
+
filled: Schema.Boolean
|
|
76
|
+
});
|
|
77
|
+
const EvidenceSchema = Schema.Struct({
|
|
78
|
+
title: Schema.String,
|
|
79
|
+
description: Schema.optional(Schema.String),
|
|
80
|
+
dialog: Schema.optional(Schema.String),
|
|
81
|
+
heading: Schema.optional(Schema.String),
|
|
82
|
+
nearby: Schema.optional(Schema.String),
|
|
83
|
+
form: Schema.optional(Schema.Struct({
|
|
84
|
+
method: Schema.String,
|
|
85
|
+
action: Schema.String,
|
|
86
|
+
fields: Schema.Array(FormFieldSchema)
|
|
87
|
+
}))
|
|
88
|
+
});
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/internal/input/guard.inpage.ts
|
|
91
|
+
/**
|
|
92
|
+
* In the page: what the input guard decides on. It inspects an input's targets for the facts a
|
|
93
|
+
* policy weighs, such as a form submission or a secret field, binds an approval to them, and
|
|
94
|
+
* checks before each press that the approved target would still receive it. See `reading/names.inpage.ts` for what a page-side part may use.
|
|
95
|
+
*/
|
|
96
|
+
const Fact$1 = Schema.Literals([
|
|
97
|
+
"form-submit",
|
|
98
|
+
"cross-origin",
|
|
99
|
+
"download",
|
|
100
|
+
"upload",
|
|
101
|
+
"secret",
|
|
102
|
+
"scripted",
|
|
103
|
+
"opaque"
|
|
104
|
+
]);
|
|
105
|
+
const guard = (names, targets, evidence) => {
|
|
106
|
+
const { activeElement, clean, describe, inCurrentDocument, interactiveRoles, isButton, isDisabled, isHtml, isInput, isLabel, isRoot, isSecret, isSelect, isTextArea, lookup, parentOf, refFor, roleOf } = names;
|
|
107
|
+
const { controlOf, details, hitAt, hrefAttribute, linkOf, receives, within } = targets;
|
|
108
|
+
const { evidenceOf, isField, isFilled } = evidence;
|
|
109
|
+
/**
|
|
110
|
+
* The element whose activation behaviour a click or key on `element` runs, as the browser
|
|
111
|
+
* resolves it along the composed path: a link, button, input, summary or a label's control.
|
|
112
|
+
*/
|
|
113
|
+
const activationTarget = (element) => {
|
|
114
|
+
for (let node = element; node !== null; node = parentOf(node)) {
|
|
115
|
+
if (hrefAttribute(node) !== null || node.tagName === "BUTTON" || node.tagName === "SUMMARY" || isInput(node) && node.type !== "hidden") return node;
|
|
116
|
+
if (isLabel(node) && node.control !== null) return node.control;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* A control between a press's hit and the approved target that is not the target's own
|
|
121
|
+
* activation, such as a link or button a hover handler nested into it. The approval inspected
|
|
122
|
+
* the target, so that control would act unapproved.
|
|
123
|
+
*/
|
|
124
|
+
const nestedControl = (element, hit) => {
|
|
125
|
+
if (!within(element, hit)) return void 0;
|
|
126
|
+
const own = activationTarget(element);
|
|
127
|
+
for (let node = hit; node !== null && node !== element; node = parentOf(node) ?? node.ownerDocument.defaultView?.frameElement ?? null) if (node !== own && (hrefAttribute(node) !== null || node.tagName === "BUTTON" || node.tagName === "SUMMARY" || isInput(node) && node.type !== "hidden" || isSelect(node) || isTextArea(node) || isLabel(node) && node.control !== null && node.control !== own || activatingRoles.has(roleOf(node) ?? ""))) return node;
|
|
128
|
+
};
|
|
129
|
+
const textEntry = (element) => isInput(element) && ![
|
|
130
|
+
"button",
|
|
131
|
+
"reset",
|
|
132
|
+
"submit",
|
|
133
|
+
"image",
|
|
134
|
+
"checkbox",
|
|
135
|
+
"radio",
|
|
136
|
+
"file",
|
|
137
|
+
"range",
|
|
138
|
+
"color",
|
|
139
|
+
"hidden"
|
|
140
|
+
].includes(element.type) || isTextArea(element) || isHtml(element) && element.isContentEditable;
|
|
141
|
+
const activatingRoles = /* @__PURE__ */ new Set([
|
|
142
|
+
"button",
|
|
143
|
+
"link",
|
|
144
|
+
"checkbox",
|
|
145
|
+
"radio",
|
|
146
|
+
"switch",
|
|
147
|
+
"tab",
|
|
148
|
+
"menuitem",
|
|
149
|
+
"menuitemcheckbox",
|
|
150
|
+
"menuitemradio",
|
|
151
|
+
"option",
|
|
152
|
+
"treeitem"
|
|
153
|
+
]);
|
|
154
|
+
const typingRefusal = (element, explicit) => textEntry(element) ? void 0 : explicit ? `${describe(element)} is not a text field` : activationTarget(element) !== void 0 || isSelect(element) || activatingRoles.has(roleOf(element) ?? "") ? `focus is on ${describe(element)}, which typed text could activate or change; type into a text field by ref, or use press for keys` : void 0;
|
|
155
|
+
const isSubmitter = (element) => isButton(element) && element.type === "submit" || isInput(element) && (element.type === "submit" || element.type === "image");
|
|
156
|
+
const defaultSubmitter = (form) => {
|
|
157
|
+
const root = form.getRootNode();
|
|
158
|
+
return isRoot(root) ? Array.from(root.querySelectorAll("button,input")).find((candidate) => isSubmitter(candidate) && candidate.form === form) : void 0;
|
|
159
|
+
};
|
|
160
|
+
const purpose = (control, form) => [
|
|
161
|
+
control.getAttribute("id"),
|
|
162
|
+
control.getAttribute("name"),
|
|
163
|
+
control.getAttribute("inputmode"),
|
|
164
|
+
control.getAttribute("autocomplete"),
|
|
165
|
+
control.getAttribute("aria-label"),
|
|
166
|
+
form?.getAttribute("id"),
|
|
167
|
+
form?.getAttribute("name"),
|
|
168
|
+
form?.getAttribute("aria-label")
|
|
169
|
+
];
|
|
170
|
+
const boundUrl = (url) => {
|
|
171
|
+
const hash = url.indexOf("#");
|
|
172
|
+
return hash === -1 || /^#[/!]/.test(url.slice(hash)) ? url : url.slice(0, hash);
|
|
173
|
+
};
|
|
174
|
+
const inspectInput = (element, plan) => {
|
|
175
|
+
const metadata = details(element, element, 0, 0);
|
|
176
|
+
const control = activationTarget(element) ?? element;
|
|
177
|
+
const form = isInput(control) || isButton(control) || isTextArea(control) || isSelect(control) ? control.form : null;
|
|
178
|
+
const key = plan.keys === null ? void 0 : /(?:^|\+)(\+|[^+]+)$/.exec(plan.keys)?.[1];
|
|
179
|
+
const enter = key === "Enter";
|
|
180
|
+
const activation = plan.action === "click" || plan.action === "press" && (enter || key === "Space");
|
|
181
|
+
const fieldEnter = isInput(control) && ![
|
|
182
|
+
"button",
|
|
183
|
+
"reset",
|
|
184
|
+
"submit",
|
|
185
|
+
"image",
|
|
186
|
+
"file",
|
|
187
|
+
"color",
|
|
188
|
+
"hidden"
|
|
189
|
+
].includes(control.type) && (plan.action === "press" && enter || plan.action === "type" && plan.submit);
|
|
190
|
+
const submits = form !== null && (activation && isSubmitter(control) || fieldEnter);
|
|
191
|
+
const submitter = isSubmitter(control) ? control : form === null ? void 0 : defaultSubmitter(form);
|
|
192
|
+
const formDestination = form === null ? void 0 : submitter?.hasAttribute("formaction") === true ? submitter.formAction : form.action;
|
|
193
|
+
const formMethod = form === null ? void 0 : submitter?.hasAttribute("formmethod") === true ? submitter.formMethod : form.method;
|
|
194
|
+
const formTarget = form === null ? void 0 : submitter?.hasAttribute("formtarget") === true ? submitter.formTarget : form.target;
|
|
195
|
+
const link = linkOf(element);
|
|
196
|
+
const href = link === void 0 ? null : hrefAttribute(link);
|
|
197
|
+
const sends = submits && formMethod !== "dialog";
|
|
198
|
+
const destination = sends ? formDestination : activation ? metadata.href : void 0;
|
|
199
|
+
const acts = plan.action !== "hover" && plan.action !== "scroll";
|
|
200
|
+
const builtIn = sends || href !== null && !/^\s*(?:#\s*|javascript:[^]*)$/i.test(href) || isInput(control) && ![
|
|
201
|
+
"button",
|
|
202
|
+
"submit",
|
|
203
|
+
"image",
|
|
204
|
+
"reset"
|
|
205
|
+
].includes(control.type) || (isInput(control) || isButton(control)) && control.type === "reset" && form !== null || control.tagName === "SUMMARY" || control.closest("select") !== null || textEntry(control);
|
|
206
|
+
const facts = [];
|
|
207
|
+
if (sends) facts.push("form-submit");
|
|
208
|
+
if (activation && link?.hasAttribute("download") === true) facts.push("download");
|
|
209
|
+
if (activation && isInput(control) && control.type === "file") facts.push("upload");
|
|
210
|
+
if (plan.action === "type" && isSecret(control) || sends && form !== null && Array.from(form.elements).some((field) => isField(field) && isSecret(field) && isFilled(field))) facts.push("secret");
|
|
211
|
+
if (activation && !builtIn) facts.push("scripted");
|
|
212
|
+
if (acts && (metadata.role === "canvas" || metadata.role === "iframe" || metadata.name === "")) facts.push("opaque");
|
|
213
|
+
const role = metadata.role;
|
|
214
|
+
const boundName = role !== null && (interactiveRoles.has(role) || role === "canvas" || role === "iframe") && !(isHtml(element) && element.isContentEditable) ? metadata.name : null;
|
|
215
|
+
const fingerprint = JSON.stringify([
|
|
216
|
+
purpose(control, form),
|
|
217
|
+
element.tagName,
|
|
218
|
+
element.id,
|
|
219
|
+
role,
|
|
220
|
+
boundName,
|
|
221
|
+
metadata.href,
|
|
222
|
+
control === element ? null : refFor(control),
|
|
223
|
+
isInput(control) || isButton(control) ? control.type : control.tagName,
|
|
224
|
+
control.matches(":disabled") || isDisabled(control),
|
|
225
|
+
control.getAttribute("readonly"),
|
|
226
|
+
control.getAttribute("aria-readonly"),
|
|
227
|
+
isHtml(control) && control.isContentEditable,
|
|
228
|
+
control.getAttribute("name"),
|
|
229
|
+
control.getAttribute("accept"),
|
|
230
|
+
control.hasAttribute("multiple"),
|
|
231
|
+
link?.getAttribute("download"),
|
|
232
|
+
form === null ? null : refFor(form),
|
|
233
|
+
form === null ? null : boundUrl(form.action),
|
|
234
|
+
form?.method,
|
|
235
|
+
form?.target,
|
|
236
|
+
submitter === void 0 ? null : refFor(submitter),
|
|
237
|
+
formDestination === void 0 ? void 0 : boundUrl(formDestination),
|
|
238
|
+
formMethod,
|
|
239
|
+
formTarget,
|
|
240
|
+
submitter?.formNoValidate,
|
|
241
|
+
form?.noValidate
|
|
242
|
+
]);
|
|
243
|
+
return {
|
|
244
|
+
inspected: {
|
|
245
|
+
ref: refFor(element),
|
|
246
|
+
element: metadata.element,
|
|
247
|
+
role: metadata.role,
|
|
248
|
+
name: metadata.name,
|
|
249
|
+
cursor: metadata.cursor,
|
|
250
|
+
...metadata.href === void 0 ? {} : { href: metadata.href },
|
|
251
|
+
secret: isSecret(control),
|
|
252
|
+
fingerprint
|
|
253
|
+
},
|
|
254
|
+
facts,
|
|
255
|
+
destination,
|
|
256
|
+
explain: () => evidenceOf(element, form, formMethod, formDestination)
|
|
257
|
+
};
|
|
258
|
+
};
|
|
259
|
+
const inspect = (plan) => {
|
|
260
|
+
const targets = [];
|
|
261
|
+
const facts = /* @__PURE__ */ new Set();
|
|
262
|
+
let destination = plan.destination ?? void 0;
|
|
263
|
+
let explain = () => ({ title: clean(document.title, 120) });
|
|
264
|
+
for (const [index, target] of plan.targets.entries()) {
|
|
265
|
+
let element;
|
|
266
|
+
if (target === null) element = activeElement();
|
|
267
|
+
else if (typeof target === "string") {
|
|
268
|
+
element = lookup(target);
|
|
269
|
+
if (element === void 0) return {
|
|
270
|
+
error: "stale",
|
|
271
|
+
detail: target + " is not on the page any more",
|
|
272
|
+
index
|
|
273
|
+
};
|
|
274
|
+
} else {
|
|
275
|
+
if (!Number.isFinite(target.x) || !Number.isFinite(target.y) || target.x < 0 || target.y < 0 || target.x >= window.innerWidth || target.y >= window.innerHeight) return {
|
|
276
|
+
error: "outside",
|
|
277
|
+
detail: "the point is outside the viewport"
|
|
278
|
+
};
|
|
279
|
+
const hit = hitAt(document, target.x, target.y);
|
|
280
|
+
element = hit === null ? null : controlOf(hit);
|
|
281
|
+
if (element === null) return {
|
|
282
|
+
error: "offscreen",
|
|
283
|
+
detail: "nothing is painted at the point"
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
if (element === null) {
|
|
287
|
+
targets.push(null);
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (!inCurrentDocument(element)) return {
|
|
291
|
+
error: "stale",
|
|
292
|
+
detail: "the input target belongs to a replaced document",
|
|
293
|
+
index
|
|
294
|
+
};
|
|
295
|
+
const refusal = plan.action === "type" ? typingRefusal(element, target !== null) : void 0;
|
|
296
|
+
if (refusal !== void 0) return {
|
|
297
|
+
error: "untypeable",
|
|
298
|
+
detail: refusal
|
|
299
|
+
};
|
|
300
|
+
const inspected = inspectInput(element, plan);
|
|
301
|
+
if (index === 0) explain = inspected.explain;
|
|
302
|
+
targets.push(inspected.inspected);
|
|
303
|
+
for (const fact of inspected.facts) facts.add(fact);
|
|
304
|
+
destination ??= inspected.destination;
|
|
305
|
+
if (inspected.destination !== void 0) try {
|
|
306
|
+
if (new URL(inspected.destination, location.href).origin !== location.origin) facts.add("cross-origin");
|
|
307
|
+
} catch {
|
|
308
|
+
return {
|
|
309
|
+
error: "outside",
|
|
310
|
+
detail: "the input destination is not a valid URL"
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (destination !== void 0) try {
|
|
315
|
+
destination = new URL(destination, location.href).href;
|
|
316
|
+
if (new URL(destination).origin !== location.origin) facts.add("cross-origin");
|
|
317
|
+
} catch {
|
|
318
|
+
return {
|
|
319
|
+
error: "outside",
|
|
320
|
+
detail: "the input destination is not a valid URL"
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
url: boundUrl(location.href),
|
|
325
|
+
targets,
|
|
326
|
+
facts: [...facts],
|
|
327
|
+
...destination === void 0 ? {} : { destination },
|
|
328
|
+
explain
|
|
329
|
+
};
|
|
330
|
+
};
|
|
331
|
+
const prepareInput = (plan) => {
|
|
332
|
+
const inspected = inspect(plan);
|
|
333
|
+
if ("error" in inspected) return inspected;
|
|
334
|
+
const { explain, ...prepared } = inspected;
|
|
335
|
+
return {
|
|
336
|
+
...prepared,
|
|
337
|
+
evidence: explain()
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
const validate = (plan, prepared, options) => {
|
|
341
|
+
const current = inspect(plan);
|
|
342
|
+
if ("error" in current) return current.error === "stale" ? current : {
|
|
343
|
+
error: "changed",
|
|
344
|
+
detail: current.detail
|
|
345
|
+
};
|
|
346
|
+
if (current.url !== prepared.url || (current.destination === void 0 || prepared.destination === void 0 ? current.destination !== prepared.destination : boundUrl(current.destination) !== boundUrl(prepared.destination)) || JSON.stringify(current.facts) !== JSON.stringify(prepared.facts) || current.targets.length !== prepared.targets.length || current.targets.some((target, index) => {
|
|
347
|
+
const previous = prepared.targets[index];
|
|
348
|
+
return target === null ? previous !== null : previous === null || previous === void 0 || target.ref !== previous.ref || target.fingerprint !== previous.fingerprint;
|
|
349
|
+
})) return {
|
|
350
|
+
error: "changed",
|
|
351
|
+
detail: "the page or input target changed while the policy was deciding"
|
|
352
|
+
};
|
|
353
|
+
if (options.focused === true) {
|
|
354
|
+
const active = activeElement();
|
|
355
|
+
const expected = prepared.targets[0];
|
|
356
|
+
if (active === null || expected === null || expected === void 0 || refFor(active) !== expected.ref) return {
|
|
357
|
+
error: "changed",
|
|
358
|
+
detail: "focus moved away from the approved element"
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
for (const press of options.presses ?? []) {
|
|
362
|
+
const expected = prepared.targets[press.index];
|
|
363
|
+
const element = expected === null || expected === void 0 ? void 0 : lookup(expected.ref);
|
|
364
|
+
const hit = hitAt(document, press.x, press.y);
|
|
365
|
+
if (element === void 0 || hit === null || !receives(element, hit)) return {
|
|
366
|
+
error: "changed",
|
|
367
|
+
detail: `the approved target is no longer under the pointer at (${press.x}, ${press.y})`
|
|
368
|
+
};
|
|
369
|
+
const nested = nestedControl(element, hit);
|
|
370
|
+
if (nested !== void 0) return {
|
|
371
|
+
error: "changed",
|
|
372
|
+
detail: `${describe(nested)} inside the approved target would receive the press at (${press.x}, ${press.y})`
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
return { ok: true };
|
|
376
|
+
};
|
|
377
|
+
const validateInput = (plan, prepared, options = {}) => {
|
|
378
|
+
if ((options.presses ?? []).length === 0) return validate(plan, prepared, options);
|
|
379
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
380
|
+
if (document.visibilityState === "hidden") resolve();
|
|
381
|
+
else requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
382
|
+
return promise.then(() => validate(plan, prepared, options));
|
|
383
|
+
};
|
|
384
|
+
return {
|
|
385
|
+
prepareInput,
|
|
386
|
+
textEntry,
|
|
387
|
+
typingRefusal,
|
|
388
|
+
validateInput
|
|
389
|
+
};
|
|
390
|
+
};
|
|
391
|
+
const InputPreparationError = Schema.Struct({
|
|
392
|
+
error: Schema.String,
|
|
393
|
+
detail: Schema.String,
|
|
394
|
+
index: Schema.optional(Schema.Finite)
|
|
395
|
+
});
|
|
396
|
+
const PreparedInputResultSchema = Schema.Union([Schema.Struct({
|
|
397
|
+
url: Schema.String,
|
|
398
|
+
targets: Schema.Array(Schema.NullOr(Schema.Struct({
|
|
399
|
+
ref: Schema.String,
|
|
400
|
+
element: Schema.String,
|
|
401
|
+
role: Schema.NullOr(Schema.String),
|
|
402
|
+
name: Schema.String,
|
|
403
|
+
cursor: Schema.String,
|
|
404
|
+
href: Schema.optional(Schema.String),
|
|
405
|
+
secret: Schema.Boolean,
|
|
406
|
+
fingerprint: Schema.String
|
|
407
|
+
}))),
|
|
408
|
+
facts: Schema.Array(Fact$1),
|
|
409
|
+
destination: Schema.optional(Schema.String),
|
|
410
|
+
evidence: EvidenceSchema
|
|
411
|
+
}), InputPreparationError]);
|
|
412
|
+
const ValidatedInputResultSchema = Schema.Union([Schema.Struct({ ok: Schema.Literal(true) }), InputPreparationError]);
|
|
413
|
+
//#endregion
|
|
414
|
+
//#region src/Page.ts
|
|
415
|
+
/**
|
|
416
|
+
* One browser tab: navigation, snapshots, pictures and input.
|
|
417
|
+
*
|
|
418
|
+
* A page waits only for itself: its operations take turns in one lane of its own. An action, which
|
|
419
|
+
* sends input or navigates, has the page to itself, in the order actions were asked; reads share
|
|
420
|
+
* it, after the action in flight and every action asked before them, so a read describes the page
|
|
421
|
+
* an action left. A wait for a turn ends at the operation's deadline as `Busy`, never `Timeout`,
|
|
422
|
+
* and a full deadline then bounds the operation itself; `failFast` fails it at once instead.
|
|
423
|
+
* Identical reads asked between the same actions share one call to the page, and one whose
|
|
424
|
+
* callers gave up finishes for the next caller to ask it. A policy holds outside the lane while
|
|
425
|
+
* other operations continue; its target is revalidated before dispatch. Element targets are refs
|
|
426
|
+
* from a snapshot; point targets are viewport coordinates in CSS pixels, the same coordinates as a
|
|
427
|
+
* screenshot's pixels. Mouse and keyboard input share a bounded pipeline, so pacing does not wait
|
|
428
|
+
* for each protocol reply. Target lookup happens before the input is sent.
|
|
429
|
+
*
|
|
430
|
+
* @since 0.3.0
|
|
431
|
+
*/
|
|
432
|
+
var Page_exports = /* @__PURE__ */ __exportAll({
|
|
433
|
+
ElementState: () => ElementState,
|
|
434
|
+
Fact: () => Fact,
|
|
435
|
+
Found: () => Found,
|
|
436
|
+
InputRequest: () => InputRequest,
|
|
437
|
+
Region: () => Region,
|
|
438
|
+
ResolvedTarget: () => ResolvedTarget,
|
|
439
|
+
State: () => State,
|
|
440
|
+
Text: () => Text,
|
|
441
|
+
Zoom: () => Zoom,
|
|
442
|
+
correlate: () => correlate,
|
|
443
|
+
failFast: () => failFast,
|
|
444
|
+
redacted: () => redacted
|
|
445
|
+
});
|
|
446
|
+
/** An integer rectangle in viewport CSS pixels. */
|
|
447
|
+
var Region = class extends Schema.Class("effect-browser/Region")({
|
|
448
|
+
x: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
|
|
449
|
+
y: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
|
|
450
|
+
width: Schema.Int.check(Schema.isGreaterThan(0)),
|
|
451
|
+
height: Schema.Int.check(Schema.isGreaterThan(0))
|
|
452
|
+
}) {};
|
|
453
|
+
/** A crop and its viewport origin: add that origin to a point read from the crop. */
|
|
454
|
+
var Zoom = class extends Schema.Class("effect-browser/Zoom")({
|
|
455
|
+
page: Schema.String,
|
|
456
|
+
region: Region,
|
|
457
|
+
image: Image
|
|
458
|
+
}) {};
|
|
459
|
+
/** The target as it read before input. Point coordinates are never snapped to another position. */
|
|
460
|
+
var ResolvedTarget = class extends Schema.Class("effect-browser/ResolvedTarget")({
|
|
461
|
+
point: Schema.Struct({
|
|
462
|
+
x: Schema.Finite,
|
|
463
|
+
y: Schema.Finite
|
|
464
|
+
}),
|
|
465
|
+
element: Schema.String,
|
|
466
|
+
/** The element's lowercase tag name. */
|
|
467
|
+
tag: Schema.String,
|
|
468
|
+
role: Schema.NullOr(Schema.String),
|
|
469
|
+
name: Schema.String,
|
|
470
|
+
context: SubjectContext,
|
|
471
|
+
/** For a point target, the box of what it found there. */
|
|
472
|
+
box: Schema.optional(Box),
|
|
473
|
+
cursor: Schema.String,
|
|
474
|
+
href: Schema.optional(Schema.String)
|
|
475
|
+
}) {};
|
|
476
|
+
/**
|
|
477
|
+
* An element's state as its markup gives it: `checked` for what can be checked, `expanded`,
|
|
478
|
+
* `selected` and `pressed` where the page says either way, and `level` for headings.
|
|
479
|
+
*/
|
|
480
|
+
const ElementState = Schema.Struct({
|
|
481
|
+
disabled: Schema.Boolean,
|
|
482
|
+
focused: Schema.Boolean,
|
|
483
|
+
checked: Schema.optional(Schema.Boolean),
|
|
484
|
+
expanded: Schema.optional(Schema.Boolean),
|
|
485
|
+
selected: Schema.optional(Schema.Boolean),
|
|
486
|
+
pressed: Schema.optional(Schema.Boolean),
|
|
487
|
+
level: Schema.optional(Schema.Int)
|
|
488
|
+
});
|
|
489
|
+
/** An element `find` found: a ref for the actions, what it is, where it is and its state. */
|
|
490
|
+
var Found = class extends Schema.Class("effect-browser/Found")({
|
|
491
|
+
ref: Schema.String,
|
|
492
|
+
subject: Subject,
|
|
493
|
+
/** Its box, rounded. Reading the document, it may be out of view. */
|
|
494
|
+
box: Box,
|
|
495
|
+
inViewport: Schema.Boolean,
|
|
496
|
+
state: ElementState
|
|
497
|
+
}) {};
|
|
498
|
+
/** What a page showed as text: a line per block, with table cells apart by tabs. */
|
|
499
|
+
var Text = class extends Schema.Class("effect-browser/Text")({
|
|
500
|
+
url: Schema.String,
|
|
501
|
+
title: Schema.String,
|
|
502
|
+
text: Schema.String,
|
|
503
|
+
/** True when `text` was cut at `maxChars`. */
|
|
504
|
+
truncated: Schema.Boolean,
|
|
505
|
+
/** Host monotonic milliseconds from the browser's captured Effect Clock. */
|
|
506
|
+
at: Schema.Finite
|
|
507
|
+
}) {};
|
|
508
|
+
/**
|
|
509
|
+
* What the library knows of a page now, without asking it, each part with when it learned it, in
|
|
510
|
+
* host monotonic milliseconds: a part's age is `at` less its time. Text read before the current
|
|
511
|
+
* document began is left out, since it tells of a document that has gone.
|
|
512
|
+
*/
|
|
513
|
+
var State = class extends Schema.Class("effect-browser/PageState")({
|
|
514
|
+
page: Schema.String,
|
|
515
|
+
/** When this was taken. */
|
|
516
|
+
at: Schema.Finite,
|
|
517
|
+
/** Where the main frame last committed or moved, without userinfo or known secret parameters. */
|
|
518
|
+
url: Schema.String,
|
|
519
|
+
/** The page's document, as `Navigated` counts them. */
|
|
520
|
+
document: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
|
|
521
|
+
/** When the main frame committed it; absent for the one the browser began tracking it with. */
|
|
522
|
+
committedAt: Schema.optional(Schema.Finite),
|
|
523
|
+
/** How far that document has loaded, as the page's own session heard; absent until parsed. */
|
|
524
|
+
load: Schema.optional(PageLoaded),
|
|
525
|
+
/** The newest screencast frame, of whichever document it names. */
|
|
526
|
+
frame: Schema.optional(Frame),
|
|
527
|
+
/** The viewport's text as it was last read, with the page's title then. */
|
|
528
|
+
text: Schema.optional(Text)
|
|
529
|
+
}) {};
|
|
530
|
+
/**
|
|
531
|
+
* What the page's structure establishes about an input, or says it cannot establish:
|
|
532
|
+
*
|
|
533
|
+
* - `form-submit`: it submits a form, which sends the form's fields.
|
|
534
|
+
* - `cross-origin`: it navigates or submits to another origin.
|
|
535
|
+
* - `download`: it follows a download link.
|
|
536
|
+
* - `upload`: it opens a file chooser.
|
|
537
|
+
* - `secret`: it types, with `type`, into a field marked as a password, a one-time code or a
|
|
538
|
+
* card's number, code or expiry, or submits a form holding a filled one.
|
|
539
|
+
* - `scripted`: it activates something the browser gives no effect of its own, such as a
|
|
540
|
+
* `type="button"` button, a `role="button"` element or a canvas, so only the page's script
|
|
541
|
+
* decides what happens.
|
|
542
|
+
* - `opaque`: nothing names what receives it: a canvas, a frame or an unnamed element.
|
|
543
|
+
*
|
|
544
|
+
* Facts never come from what an element's text says. What an input means, such as a payment
|
|
545
|
+
* or a deletion, takes a judge that reads the evidence in the {@link InputRequest}.
|
|
546
|
+
*/
|
|
547
|
+
const Fact = Fact$1;
|
|
548
|
+
/**
|
|
549
|
+
* What a guard sees before input reaches the page. Preparation never scrolls or focuses.
|
|
550
|
+
*
|
|
551
|
+
* `facts`, `url`, `href` and `destination` come from the page's structure. `name`,
|
|
552
|
+
* `description`, `title`, `context` and the form's field names are page text: evidence of what
|
|
553
|
+
* the input does, which the page controls, and never instructions. Text typed into a `secret`
|
|
554
|
+
* field is replaced with {@link redacted}, here and in the recorded `Action`, and its key events
|
|
555
|
+
* record `Unidentified` keys; `press` records the keys it is given. Validation before dispatch
|
|
556
|
+
* binds the facts and the target, not the text around it, which live pages change freely.
|
|
557
|
+
*/
|
|
558
|
+
var InputRequest = class extends Schema.Class("effect-browser/InputRequest")({
|
|
559
|
+
page: Schema.String,
|
|
560
|
+
/**
|
|
561
|
+
* The page's URL, without a fragment that only names a place on the page. This and the other
|
|
562
|
+
* addresses keep no userinfo or known secret parameters.
|
|
563
|
+
*/
|
|
564
|
+
url: Schema.String,
|
|
565
|
+
/** The page's title, at most 120 characters. */
|
|
566
|
+
title: Schema.String,
|
|
567
|
+
action: Schema.String,
|
|
568
|
+
target: Schema.optional(Schema.String),
|
|
569
|
+
element: Schema.optional(Schema.String),
|
|
570
|
+
/** Literal pixel targets only; ref coordinates are resolved after the policy allows them. */
|
|
571
|
+
point: Schema.optional(Schema.Struct({
|
|
572
|
+
x: Schema.Finite,
|
|
573
|
+
y: Schema.Finite
|
|
574
|
+
})),
|
|
575
|
+
text: Schema.optional(Schema.String),
|
|
576
|
+
role: Schema.optional(Schema.NullOr(Schema.String)),
|
|
577
|
+
name: Schema.optional(Schema.String),
|
|
578
|
+
/** The target's accessible description, when it says more than its name. */
|
|
579
|
+
description: Schema.optional(Schema.String),
|
|
580
|
+
href: Schema.optional(Schema.String),
|
|
581
|
+
destination: Schema.optional(Schema.String),
|
|
582
|
+
facts: Schema.Array(Fact),
|
|
583
|
+
/** Page text around the target, each part at most 120 characters. */
|
|
584
|
+
context: Schema.Struct({
|
|
585
|
+
/** The name or first heading of the dialog the target is in. */
|
|
586
|
+
dialog: Schema.optional(Schema.String),
|
|
587
|
+
/** The nearest heading before the target. */
|
|
588
|
+
heading: Schema.optional(Schema.String),
|
|
589
|
+
/** The visible text just before the target in its row, item, group or form, or after it. */
|
|
590
|
+
nearby: Schema.optional(Schema.String)
|
|
591
|
+
}),
|
|
592
|
+
/** The form the target is in, with at most 16 of its fields. */
|
|
593
|
+
form: Schema.optional(Schema.Struct({
|
|
594
|
+
method: Schema.String,
|
|
595
|
+
action: Schema.String,
|
|
596
|
+
/** Each field's type, name and autocomplete tokens, and whether it is filled: never its value. */
|
|
597
|
+
fields: Schema.Array(FormFieldSchema)
|
|
598
|
+
}))
|
|
599
|
+
}) {};
|
|
600
|
+
/**
|
|
601
|
+
* What replaces text typed into a `secret` field, in requests and in the recorded `Action`, and a
|
|
602
|
+
* credential's value in every address the library reports.
|
|
603
|
+
*/
|
|
604
|
+
const redacted = withheld;
|
|
605
|
+
/**
|
|
606
|
+
* Run page operations without waiting their turn: on a page busy with other operations, each fails
|
|
607
|
+
* `Busy` at once, and `Browser.newPage` on a browser with `maxPages` open fails `Limit` at once.
|
|
608
|
+
*/
|
|
609
|
+
const failFast = (effect) => Effect.provideService(effect, FailFast, true);
|
|
610
|
+
/**
|
|
611
|
+
* Give every action `effect` performs a caller's id, such as a model's tool call id, which its
|
|
612
|
+
* recorded `Action` carries as `correlation`.
|
|
613
|
+
*/
|
|
614
|
+
const correlate = (id) => (effect) => Effect.provideService(effect, Correlation, id);
|
|
615
|
+
//#endregion
|
|
616
|
+
export { evidence as _, Page_exports as a, State as c, correlate as d, failFast as f, guard as g, ValidatedInputResultSchema as h, InputRequest as i, Text as l, PreparedInputResultSchema as m, Fact as n, Region as o, redacted as p, Found as r, ResolvedTarget as s, ElementState as t, Zoom as u };
|
|
617
|
+
|
|
618
|
+
//# sourceMappingURL=Page-B5cjaUp5.mjs.map
|