@particle-academy/agent-integrations 0.46.0 → 0.47.1
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/CHANGELOG.md +885 -0
- package/LICENSE +21 -0
- package/README.md +53 -3
- package/dist/bridges/artboard.d.cts +3 -3
- package/dist/bridges/artboard.d.ts +3 -3
- package/dist/bridges/catalog.d.cts +3 -3
- package/dist/bridges/catalog.d.ts +3 -3
- package/dist/bridges/charts.d.cts +3 -3
- package/dist/bridges/charts.d.ts +3 -3
- package/dist/bridges/cms.d.cts +3 -3
- package/dist/bridges/cms.d.ts +3 -3
- package/dist/bridges/code.d.cts +3 -3
- package/dist/bridges/code.d.ts +3 -3
- package/dist/bridges/doc.d.cts +3 -3
- package/dist/bridges/doc.d.ts +3 -3
- package/dist/bridges/features.d.cts +3 -3
- package/dist/bridges/features.d.ts +3 -3
- package/dist/bridges/files.d.cts +3 -3
- package/dist/bridges/files.d.ts +3 -3
- package/dist/bridges/flow.d.cts +3 -3
- package/dist/bridges/flow.d.ts +3 -3
- package/dist/bridges/forms.d.cts +3 -3
- package/dist/bridges/forms.d.ts +3 -3
- package/dist/bridges/git.d.cts +3 -3
- package/dist/bridges/git.d.ts +3 -3
- package/dist/bridges/grid.d.cts +3 -3
- package/dist/bridges/grid.d.ts +3 -3
- package/dist/bridges/map.d.cts +3 -3
- package/dist/bridges/map.d.ts +3 -3
- package/dist/bridges/navigation.d.cts +140 -0
- package/dist/bridges/navigation.d.ts +140 -0
- package/dist/bridges/passkeys.d.cts +4 -4
- package/dist/bridges/passkeys.d.ts +4 -4
- package/dist/bridges/scene.d.cts +3 -3
- package/dist/bridges/scene.d.ts +3 -3
- package/dist/bridges/screens.d.cts +3 -3
- package/dist/bridges/screens.d.ts +3 -3
- package/dist/bridges/sheets.d.cts +3 -3
- package/dist/bridges/sheets.d.ts +3 -3
- package/dist/bridges/slides.d.cts +3 -3
- package/dist/bridges/slides.d.ts +3 -3
- package/dist/bridges/terminal.d.cts +3 -3
- package/dist/bridges/terminal.d.ts +3 -3
- package/dist/bridges/tui.d.cts +2 -2
- package/dist/bridges/tui.d.ts +2 -2
- package/dist/bridges/whiteboard.d.cts +3 -3
- package/dist/bridges/whiteboard.d.ts +3 -3
- package/dist/bridges-navigation.cjs +437 -0
- package/dist/bridges-navigation.cjs.map +1 -0
- package/dist/bridges-navigation.js +7 -0
- package/dist/bridges-navigation.js.map +1 -0
- package/dist/bridges-passkeys.cjs.map +1 -1
- package/dist/bridges-passkeys.js +1 -1
- package/dist/{chunk-PWYEW6NL.js → chunk-G6CRHFWU.js} +2 -2
- package/dist/{chunk-PWYEW6NL.js.map → chunk-G6CRHFWU.js.map} +1 -1
- package/dist/chunk-OHNGURUJ.js +317 -0
- package/dist/chunk-OHNGURUJ.js.map +1 -0
- package/dist/dom-navigation/index.d.cts +175 -0
- package/dist/dom-navigation/index.d.ts +175 -0
- package/dist/dom-navigation/script.d.cts +3 -0
- package/dist/dom-navigation/script.d.ts +3 -0
- package/dist/dom-navigation-script.cjs +11 -0
- package/dist/dom-navigation-script.cjs.map +1 -0
- package/dist/dom-navigation-script.js +9 -0
- package/dist/dom-navigation-script.js.map +1 -0
- package/dist/dom-navigation.cjs +405 -0
- package/dist/dom-navigation.cjs.map +1 -0
- package/dist/dom-navigation.js +388 -0
- package/dist/dom-navigation.js.map +1 -0
- package/dist/index.cjs +94 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -125
- package/dist/index.d.ts +10 -125
- package/dist/index.js +12 -275
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.cts +5 -5
- package/dist/mcp/index.d.ts +5 -5
- package/dist/mcp/stdio.d.cts +3 -3
- package/dist/mcp/stdio.d.ts +3 -3
- package/dist/presence/index.d.cts +1 -1
- package/dist/presence/index.d.ts +1 -1
- package/dist/{server-BIcA3ZtK.d.cts → server-1y0n61R5.d.cts} +2 -2
- package/dist/{server-DnUyeavY.d.ts → server-vq6qVl3T.d.ts} +2 -2
- package/dist/sharing/index.d.cts +3 -3
- package/dist/sharing/index.d.ts +3 -3
- package/dist/sheets-adapter.d.cts +3 -3
- package/dist/sheets-adapter.d.ts +3 -3
- package/dist/{tool-host-LVBgCN5m.d.cts → tool-host-D67N2a2h.d.cts} +1 -1
- package/dist/{tool-host-Wo0pkY83.d.ts → tool-host-LYfdPE8u.d.ts} +1 -1
- package/dist/{types-EcElKOlk.d.cts → types-DP5yQZQU.d.cts} +1 -1
- package/dist/{types-BxNRKSVd.d.ts → types-VX_9je7w.d.ts} +1 -1
- package/dist/{types-C2DtnHIn.d.cts → types-gzIpsUDE.d.cts} +1 -1
- package/dist/{types-C2DtnHIn.d.ts → types-gzIpsUDE.d.ts} +1 -1
- package/dist/undo/index.d.cts +2 -2
- package/dist/undo/index.d.ts +2 -2
- package/package.json +35 -3
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
// src/dom-navigation/agent.ts
|
|
2
|
+
var INTERACTIVE = "a[href], button, input, select, textarea, [role=button], [role=link], [role=checkbox], [role=tab], [data-co-handle]";
|
|
3
|
+
var DOM_NAVIGATION_METHODS = [
|
|
4
|
+
"getLocation",
|
|
5
|
+
"describe",
|
|
6
|
+
"read",
|
|
7
|
+
"visit",
|
|
8
|
+
"back",
|
|
9
|
+
"forward",
|
|
10
|
+
"scrollTo",
|
|
11
|
+
"scrollBy",
|
|
12
|
+
"setField",
|
|
13
|
+
"click",
|
|
14
|
+
"submit",
|
|
15
|
+
"rectFor"
|
|
16
|
+
];
|
|
17
|
+
var tag = (el) => el.tagName.toUpperCase();
|
|
18
|
+
function isVisible(el) {
|
|
19
|
+
const he = el;
|
|
20
|
+
if (el.type === "hidden") return false;
|
|
21
|
+
if (he.hidden || he.getAttribute("aria-hidden") === "true") return false;
|
|
22
|
+
return he.offsetParent !== null || he.getClientRects().length > 0;
|
|
23
|
+
}
|
|
24
|
+
function isSensitive(el) {
|
|
25
|
+
const input = el;
|
|
26
|
+
const ac = (el.getAttribute("autocomplete") ?? "").toLowerCase();
|
|
27
|
+
return input.type === "password" || ac.startsWith("cc-") || ac === "one-time-code" || el.hasAttribute("data-private");
|
|
28
|
+
}
|
|
29
|
+
function insideSensitive(node) {
|
|
30
|
+
for (let el = node.parentElement; el; el = el.parentElement) {
|
|
31
|
+
if (isSensitive(el)) return true;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
function safeText(root) {
|
|
36
|
+
const doc = root.ownerDocument ?? root;
|
|
37
|
+
const walker = doc.createTreeWalker(root, 4);
|
|
38
|
+
let out = "";
|
|
39
|
+
for (let n = walker.nextNode(); n; n = walker.nextNode()) {
|
|
40
|
+
if (!insideSensitive(n)) out += n.nodeValue ?? "";
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
function roleOf(el) {
|
|
45
|
+
const explicit = el.getAttribute("role");
|
|
46
|
+
if (explicit) return explicit;
|
|
47
|
+
const t = tag(el);
|
|
48
|
+
if (t === "A") return "link";
|
|
49
|
+
if (t === "BUTTON") return "button";
|
|
50
|
+
if (t === "SELECT") return "select";
|
|
51
|
+
if (t === "TEXTAREA") return "textbox";
|
|
52
|
+
if (t === "INPUT") {
|
|
53
|
+
const type = el.type;
|
|
54
|
+
if (type === "checkbox") return "checkbox";
|
|
55
|
+
if (type === "radio") return "radio";
|
|
56
|
+
if (type === "submit" || type === "button") return "button";
|
|
57
|
+
return "textbox";
|
|
58
|
+
}
|
|
59
|
+
return "generic";
|
|
60
|
+
}
|
|
61
|
+
function labelFor(doc, id) {
|
|
62
|
+
for (const lbl of Array.from(doc.querySelectorAll("label[for]"))) {
|
|
63
|
+
if (lbl.getAttribute("for") === id) return lbl;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
function accessibleName(el) {
|
|
68
|
+
const doc = el.ownerDocument;
|
|
69
|
+
const aria = el.getAttribute("aria-label");
|
|
70
|
+
if (aria) return aria.trim();
|
|
71
|
+
const labelledby = el.getAttribute("aria-labelledby");
|
|
72
|
+
if (labelledby) {
|
|
73
|
+
const txt = labelledby.split(/\s+/).map((id2) => doc.getElementById(id2)?.textContent ?? "").join(" ").trim();
|
|
74
|
+
if (txt) return txt;
|
|
75
|
+
}
|
|
76
|
+
const id = el.getAttribute("id");
|
|
77
|
+
if (id) {
|
|
78
|
+
const lbl = labelFor(doc, id);
|
|
79
|
+
if (lbl?.textContent?.trim()) return lbl.textContent.trim();
|
|
80
|
+
}
|
|
81
|
+
const wrapping = el.closest("label");
|
|
82
|
+
if (wrapping) {
|
|
83
|
+
const txt = safeText(wrapping).trim();
|
|
84
|
+
if (txt) return txt;
|
|
85
|
+
}
|
|
86
|
+
const placeholder = el.getAttribute("placeholder");
|
|
87
|
+
if (placeholder) return placeholder.trim();
|
|
88
|
+
const text = isSensitive(el) ? "" : el.textContent?.trim();
|
|
89
|
+
if (text) return text.replace(/\s+/g, " ").slice(0, 80);
|
|
90
|
+
return el.getAttribute("name") ?? el.getAttribute("id") ?? roleOf(el);
|
|
91
|
+
}
|
|
92
|
+
function isDestructive(el, label) {
|
|
93
|
+
if (el.hasAttribute("data-co-confirm")) return true;
|
|
94
|
+
if (el.type === "submit") return true;
|
|
95
|
+
if (tag(el) === "BUTTON" && el.type === "submit") return true;
|
|
96
|
+
return /\b(delete|remove|destroy|sign out|log ?out|cancel subscription|deactivate)\b/i.test(label);
|
|
97
|
+
}
|
|
98
|
+
function attributeHandle(el) {
|
|
99
|
+
return el.getAttribute("data-co-handle") || el.getAttribute("name") || el.getAttribute("id") || "";
|
|
100
|
+
}
|
|
101
|
+
function walk(doc = document) {
|
|
102
|
+
const registry = /* @__PURE__ */ new Map();
|
|
103
|
+
const actions = [];
|
|
104
|
+
const seen = /* @__PURE__ */ new Set();
|
|
105
|
+
let synthetic = 0;
|
|
106
|
+
for (const el of Array.from(doc.querySelectorAll(INTERACTIVE))) {
|
|
107
|
+
if (seen.has(el) || !isVisible(el)) continue;
|
|
108
|
+
seen.add(el);
|
|
109
|
+
const label = accessibleName(el);
|
|
110
|
+
const role = roleOf(el);
|
|
111
|
+
let handle = attributeHandle(el);
|
|
112
|
+
if (!handle || registry.has(handle)) handle = `${role}#${synthetic++}`;
|
|
113
|
+
registry.set(handle, el);
|
|
114
|
+
let value;
|
|
115
|
+
if (role === "textbox" || role === "select") {
|
|
116
|
+
value = isSensitive(el) ? void 0 : el.value;
|
|
117
|
+
} else if (role === "checkbox" || role === "radio") {
|
|
118
|
+
value = el.checked;
|
|
119
|
+
}
|
|
120
|
+
const action = { handle, role, label, destructive: isDestructive(el, label) };
|
|
121
|
+
if (value !== void 0) action.value = value;
|
|
122
|
+
actions.push(action);
|
|
123
|
+
}
|
|
124
|
+
const loc = doc.defaultView?.location;
|
|
125
|
+
return {
|
|
126
|
+
snapshot: { url: loc ? loc.pathname + loc.search : "", title: doc.title, actions },
|
|
127
|
+
registry
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function isField(el) {
|
|
131
|
+
const t = tag(el);
|
|
132
|
+
return t === "INPUT" || t === "TEXTAREA" || t === "SELECT";
|
|
133
|
+
}
|
|
134
|
+
function setNativeValue(el, value) {
|
|
135
|
+
const view = el.ownerDocument.defaultView ?? globalThis;
|
|
136
|
+
const fire = () => {
|
|
137
|
+
el.dispatchEvent(new view.Event("input", { bubbles: true }));
|
|
138
|
+
el.dispatchEvent(new view.Event("change", { bubbles: true }));
|
|
139
|
+
};
|
|
140
|
+
const t = tag(el);
|
|
141
|
+
if (t === "INPUT" && (el.type === "checkbox" || el.type === "radio")) {
|
|
142
|
+
const input = el;
|
|
143
|
+
const want = Boolean(value);
|
|
144
|
+
if (input.checked === want) return;
|
|
145
|
+
if (input.type === "checkbox" || want) {
|
|
146
|
+
input.click();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const setter2 = Object.getOwnPropertyDescriptor(view.HTMLInputElement.prototype, "checked")?.set;
|
|
150
|
+
setter2?.call(el, false);
|
|
151
|
+
fire();
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const proto = t === "TEXTAREA" ? view.HTMLTextAreaElement.prototype : t === "SELECT" ? view.HTMLSelectElement.prototype : view.HTMLInputElement.prototype;
|
|
155
|
+
const setter = Object.getOwnPropertyDescriptor(proto, "value")?.set;
|
|
156
|
+
setter?.call(el, String(value));
|
|
157
|
+
fire();
|
|
158
|
+
}
|
|
159
|
+
function readPage(doc = document) {
|
|
160
|
+
const main = doc.querySelector("main") ?? doc.body;
|
|
161
|
+
if (!main) return { title: doc.title, headings: [], text: "" };
|
|
162
|
+
const headings = Array.from(main.querySelectorAll("h1, h2, h3")).map((h) => ({
|
|
163
|
+
level: Number(h.tagName.slice(1)),
|
|
164
|
+
text: safeText(h).trim()
|
|
165
|
+
}));
|
|
166
|
+
const text = safeText(main).replace(/\s+/g, " ").trim().slice(0, 4e3);
|
|
167
|
+
return { title: doc.title, headings, text };
|
|
168
|
+
}
|
|
169
|
+
function findByAttribute(doc, attr, value) {
|
|
170
|
+
for (const el of Array.from(doc.querySelectorAll(`[${attr}]`))) {
|
|
171
|
+
if (el.getAttribute(attr) === value) return el;
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
var num = (v) => typeof v === "number" ? v : void 0;
|
|
176
|
+
function createDomNavigationAgent(options = {}) {
|
|
177
|
+
let registry = /* @__PURE__ */ new Map();
|
|
178
|
+
const doc = () => options.document ?? document;
|
|
179
|
+
const win = () => doc().defaultView ?? window;
|
|
180
|
+
const before = (action) => options.beforeAction?.(action);
|
|
181
|
+
const resolve = (handle) => {
|
|
182
|
+
const hit = registry.get(handle);
|
|
183
|
+
if (hit && hit.isConnected) return hit;
|
|
184
|
+
const d = doc();
|
|
185
|
+
return findByAttribute(d, "data-co-handle", handle) ?? findByAttribute(d, "name", handle) ?? d.getElementById(handle);
|
|
186
|
+
};
|
|
187
|
+
const agent = {
|
|
188
|
+
getLocation: () => {
|
|
189
|
+
const loc = win().location;
|
|
190
|
+
return { url: loc.pathname + loc.search, title: doc().title };
|
|
191
|
+
},
|
|
192
|
+
describe: () => {
|
|
193
|
+
const res = walk(doc());
|
|
194
|
+
registry = res.registry;
|
|
195
|
+
return res.snapshot;
|
|
196
|
+
},
|
|
197
|
+
read: () => readPage(doc()),
|
|
198
|
+
visit: (url) => {
|
|
199
|
+
const w = win();
|
|
200
|
+
const target = new URL(String(url), w.location.href);
|
|
201
|
+
if (target.protocol !== "http:" && target.protocol !== "https:") {
|
|
202
|
+
throw new Error(`Refusing to navigate to a '${target.protocol}' URL.`);
|
|
203
|
+
}
|
|
204
|
+
w.setTimeout(() => w.location.assign(target.href), 0);
|
|
205
|
+
},
|
|
206
|
+
back: () => win().history.back(),
|
|
207
|
+
forward: () => win().history.forward(),
|
|
208
|
+
scrollTo: ({ x, y, handle }) => {
|
|
209
|
+
const w = win();
|
|
210
|
+
if (handle) {
|
|
211
|
+
resolve(handle)?.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
w.scrollTo({ left: x ?? w.scrollX, top: y ?? w.scrollY, behavior: "smooth" });
|
|
215
|
+
},
|
|
216
|
+
scrollBy: (dy) => win().scrollBy({ top: dy, behavior: "smooth" }),
|
|
217
|
+
setField: (handle, value) => {
|
|
218
|
+
before("setField");
|
|
219
|
+
const el = resolve(handle);
|
|
220
|
+
if (!el) return { ok: false, error: `No element for handle "${handle}"` };
|
|
221
|
+
if (isField(el)) {
|
|
222
|
+
setNativeValue(el, value);
|
|
223
|
+
return { ok: true };
|
|
224
|
+
}
|
|
225
|
+
return { ok: false, error: `Handle "${handle}" is not a form field` };
|
|
226
|
+
},
|
|
227
|
+
click: (handle) => {
|
|
228
|
+
const el = resolve(handle);
|
|
229
|
+
if (!el) return { ok: false, error: `No element for handle "${handle}"` };
|
|
230
|
+
before("click");
|
|
231
|
+
el.click();
|
|
232
|
+
return { ok: true };
|
|
233
|
+
},
|
|
234
|
+
submit: (handle) => {
|
|
235
|
+
const el = resolve(handle);
|
|
236
|
+
if (!el) return { ok: false, error: `No element for handle "${handle}"` };
|
|
237
|
+
const form = tag(el) === "FORM" ? el : el.closest("form");
|
|
238
|
+
if (!form) return { ok: false, error: `Handle "${handle}" is not inside a form` };
|
|
239
|
+
before("submit");
|
|
240
|
+
if (typeof form.requestSubmit === "function") form.requestSubmit();
|
|
241
|
+
else form.submit();
|
|
242
|
+
return { ok: true };
|
|
243
|
+
},
|
|
244
|
+
rectFor: (handle) => {
|
|
245
|
+
const el = resolve(handle);
|
|
246
|
+
if (!el) return null;
|
|
247
|
+
const r = el.getBoundingClientRect();
|
|
248
|
+
return { x: r.left, y: r.top, width: r.width, height: r.height };
|
|
249
|
+
},
|
|
250
|
+
resolve,
|
|
251
|
+
call: (method, args = []) => {
|
|
252
|
+
const a = Array.isArray(args) ? args : [];
|
|
253
|
+
const handle = String(a[0] ?? "");
|
|
254
|
+
switch (method) {
|
|
255
|
+
case "getLocation":
|
|
256
|
+
return agent.getLocation();
|
|
257
|
+
case "describe":
|
|
258
|
+
return agent.describe();
|
|
259
|
+
case "read":
|
|
260
|
+
return agent.read();
|
|
261
|
+
case "visit":
|
|
262
|
+
agent.visit(String(a[0] ?? ""));
|
|
263
|
+
return void 0;
|
|
264
|
+
case "back":
|
|
265
|
+
agent.back();
|
|
266
|
+
return void 0;
|
|
267
|
+
case "forward":
|
|
268
|
+
agent.forward();
|
|
269
|
+
return void 0;
|
|
270
|
+
case "scrollTo": {
|
|
271
|
+
const o = a[0] && typeof a[0] === "object" ? a[0] : {};
|
|
272
|
+
agent.scrollTo({
|
|
273
|
+
x: num(o.x),
|
|
274
|
+
y: num(o.y),
|
|
275
|
+
handle: typeof o.handle === "string" ? o.handle : void 0
|
|
276
|
+
});
|
|
277
|
+
return void 0;
|
|
278
|
+
}
|
|
279
|
+
case "scrollBy":
|
|
280
|
+
agent.scrollBy(Number(a[0] ?? 0));
|
|
281
|
+
return void 0;
|
|
282
|
+
case "setField":
|
|
283
|
+
return agent.setField(handle, a[1]);
|
|
284
|
+
case "click":
|
|
285
|
+
return agent.click(handle);
|
|
286
|
+
case "submit":
|
|
287
|
+
return agent.submit(handle);
|
|
288
|
+
case "rectFor":
|
|
289
|
+
return agent.rectFor(handle);
|
|
290
|
+
default:
|
|
291
|
+
throw new Error(`Unknown dom-navigation method: ${String(method)}`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
return agent;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// src/dom-navigation/remote.ts
|
|
299
|
+
var DOM_NAVIGATION_GLOBAL = "__fancyDomNavigation";
|
|
300
|
+
var DOM_NAVIGATION_PROTOCOL = 1;
|
|
301
|
+
var METHODS = new Set(DOM_NAVIGATION_METHODS);
|
|
302
|
+
function assertMethod(method) {
|
|
303
|
+
if (!METHODS.has(method)) throw new Error(`Unknown dom-navigation method: ${method}`);
|
|
304
|
+
}
|
|
305
|
+
function domNavigationCallScript(method, args = []) {
|
|
306
|
+
assertMethod(method);
|
|
307
|
+
const g = JSON.stringify(DOM_NAVIGATION_GLOBAL);
|
|
308
|
+
return `(function(){var n=globalThis[${g}];if(!n||typeof n.call!=="function")throw new Error("fancy dom-navigation is not injected in this world");return n.call(${JSON.stringify(method)},${JSON.stringify(args)});})()`;
|
|
309
|
+
}
|
|
310
|
+
var str = (v, fallback = "") => typeof v === "string" ? v : fallback;
|
|
311
|
+
var isObj = (v) => typeof v === "object" && v !== null;
|
|
312
|
+
function coerceAction(v) {
|
|
313
|
+
if (!isObj(v) || typeof v.handle !== "string" || v.handle === "") return null;
|
|
314
|
+
const action = {
|
|
315
|
+
handle: v.handle,
|
|
316
|
+
role: str(v.role, "generic"),
|
|
317
|
+
label: str(v.label),
|
|
318
|
+
destructive: v.destructive === true
|
|
319
|
+
};
|
|
320
|
+
const value = v.value;
|
|
321
|
+
if (typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) {
|
|
322
|
+
action.value = value;
|
|
323
|
+
}
|
|
324
|
+
return action;
|
|
325
|
+
}
|
|
326
|
+
function coerceSnapshot(v) {
|
|
327
|
+
const o = isObj(v) ? v : {};
|
|
328
|
+
const actions = Array.isArray(o.actions) ? o.actions.map(coerceAction).filter((a) => a !== null) : [];
|
|
329
|
+
return { url: str(o.url), title: str(o.title), actions };
|
|
330
|
+
}
|
|
331
|
+
function coerceReadout(v) {
|
|
332
|
+
if (typeof v === "string") return v;
|
|
333
|
+
const o = isObj(v) ? v : {};
|
|
334
|
+
const headings = (Array.isArray(o.headings) ? o.headings : []).flatMap(
|
|
335
|
+
(h) => isObj(h) && typeof h.text === "string" && typeof h.level === "number" && Number.isFinite(h.level) ? [{ level: h.level, text: h.text }] : []
|
|
336
|
+
);
|
|
337
|
+
return { title: str(o.title), headings, text: str(o.text) };
|
|
338
|
+
}
|
|
339
|
+
function coerceResult(v) {
|
|
340
|
+
const o = isObj(v) ? v : {};
|
|
341
|
+
return { ok: o.ok === true, error: typeof o.error === "string" ? o.error : void 0 };
|
|
342
|
+
}
|
|
343
|
+
function coerceRect(v) {
|
|
344
|
+
if (!isObj(v)) return null;
|
|
345
|
+
const { x, y, width, height } = v;
|
|
346
|
+
const finite = (n) => typeof n === "number" && Number.isFinite(n);
|
|
347
|
+
return finite(x) && finite(y) && finite(width) && finite(height) ? { x, y, width, height } : null;
|
|
348
|
+
}
|
|
349
|
+
function createRemoteNavigationAdapter(options) {
|
|
350
|
+
const { transport } = options;
|
|
351
|
+
const call = (method, ...args) => transport.call(method, args);
|
|
352
|
+
const fail = (e) => ({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
353
|
+
return {
|
|
354
|
+
screenId: options.screenId,
|
|
355
|
+
getRevision: options.getRevision,
|
|
356
|
+
confirm: options.confirm,
|
|
357
|
+
getLocation: async () => {
|
|
358
|
+
const o = await call("getLocation");
|
|
359
|
+
const loc = isObj(o) ? o : {};
|
|
360
|
+
return { url: str(loc.url), title: str(loc.title) };
|
|
361
|
+
},
|
|
362
|
+
describe: async () => coerceSnapshot(await call("describe")),
|
|
363
|
+
read: async () => coerceReadout(await call("read")),
|
|
364
|
+
visit: async (url) => {
|
|
365
|
+
await call("visit", url);
|
|
366
|
+
},
|
|
367
|
+
back: async () => {
|
|
368
|
+
await call("back");
|
|
369
|
+
},
|
|
370
|
+
forward: async () => {
|
|
371
|
+
await call("forward");
|
|
372
|
+
},
|
|
373
|
+
scrollTo: async (opts) => {
|
|
374
|
+
await call("scrollTo", { x: opts.x, y: opts.y, handle: opts.handle });
|
|
375
|
+
},
|
|
376
|
+
scrollBy: async (dy) => {
|
|
377
|
+
await call("scrollBy", dy);
|
|
378
|
+
},
|
|
379
|
+
setField: async (handle, value) => coerceResult(await call("setField", handle, value).catch(fail)),
|
|
380
|
+
click: async (handle) => coerceResult(await call("click", handle).catch(fail)),
|
|
381
|
+
submit: async (handle) => coerceResult(await call("submit", handle).catch(fail)),
|
|
382
|
+
rectFor: async (handle) => coerceRect(await call("rectFor", handle).catch(() => null))
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export { DOM_NAVIGATION_GLOBAL, DOM_NAVIGATION_METHODS, DOM_NAVIGATION_PROTOCOL, INTERACTIVE, accessibleName, attributeHandle, createDomNavigationAgent, createRemoteNavigationAdapter, domNavigationCallScript, isDestructive, isSensitive, isVisible, readPage, roleOf, setNativeValue, walk };
|
|
387
|
+
//# sourceMappingURL=dom-navigation.js.map
|
|
388
|
+
//# sourceMappingURL=dom-navigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dom-navigation/agent.ts","../src/dom-navigation/remote.ts"],"names":["id","setter"],"mappings":"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","file":"dom-navigation.js","sourcesContent":["/**\n * The in-page half of DOM co-browsing: a framework-free walker that turns a\n * live document into a {@link PageSnapshot} of stable handles, and acts on\n * those handles.\n *\n * Extracted from px-ui-sandbox's CoBrowseProvider so a host that does NOT own\n * the page (Genie's browser, showing sites through an Electron\n * WebContentsView) can run the same walker, injected into an isolated world.\n *\n * Constraints this file holds, because the injected IIFE is built from it:\n *\n * - NO runtime imports. Type-only imports are erased; anything else would be\n * bundled into a script that must run with no module loader.\n * - Nothing touches `document` / `window` until a method is called, so the\n * script can be evaluated in a context with no DOM at all.\n * - Every result is plain, structured-cloneable data.\n *\n * Trust boundary: the page is hostile input. It controls every attribute,\n * label and text node read here. Two consequences:\n * - Sensitive values (passwords, card fields, one-time codes, anything marked\n * `data-private`) are masked HERE, before anything leaves the page — the host\n * cannot mask what it has already received.\n * - Handles are compared as plain strings, never spliced into a CSS selector,\n * so a crafted handle cannot change what a lookup matches.\n */\nimport type { PageAction, PageReadout, PageSnapshot } from \"../bridges/navigation\";\n\n/** Elements the walker considers actionable. */\nexport const INTERACTIVE =\n \"a[href], button, input, select, textarea, [role=button], [role=link], [role=checkbox], [role=tab], [data-co-handle]\";\n\n/** Every method the in-page agent answers. The wire protocol is exactly this list. */\nexport const DOM_NAVIGATION_METHODS = [\n \"getLocation\",\n \"describe\",\n \"read\",\n \"visit\",\n \"back\",\n \"forward\",\n \"scrollTo\",\n \"scrollBy\",\n \"setField\",\n \"click\",\n \"submit\",\n \"rectFor\",\n] as const;\n\nexport type DomNavigationMethod = (typeof DOM_NAVIGATION_METHODS)[number];\n\nexport type ActionResult = { ok: boolean; error?: string };\nexport type HandleRect = { x: number; y: number; width: number; height: number };\n\ntype FieldElement = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n\nconst tag = (el: Element) => el.tagName.toUpperCase();\n\nexport function isVisible(el: Element): boolean {\n const he = el as HTMLElement;\n if ((el as HTMLInputElement).type === \"hidden\") return false;\n if (he.hidden || he.getAttribute(\"aria-hidden\") === \"true\") return false;\n return he.offsetParent !== null || he.getClientRects().length > 0;\n}\n\n/** Sensitive fields whose value is never read into the snapshot. */\nexport function isSensitive(el: Element): boolean {\n const input = el as HTMLInputElement;\n const ac = (el.getAttribute(\"autocomplete\") ?? \"\").toLowerCase();\n return (\n input.type === \"password\" ||\n ac.startsWith(\"cc-\") ||\n ac === \"one-time-code\" ||\n el.hasAttribute(\"data-private\")\n );\n}\n\n/** True when this node, or any element containing it, is sensitive. */\nfunction insideSensitive(node: Node): boolean {\n for (let el = node.parentElement; el; el = el.parentElement) {\n if (isSensitive(el)) return true;\n }\n return false;\n}\n\n/** textContent, minus any text that sits inside a sensitive element. */\nfunction safeText(root: Node): string {\n const doc = root.ownerDocument ?? (root as Document);\n // NodeFilter.SHOW_TEXT === 4; the literal avoids depending on a NodeFilter global.\n const walker = doc.createTreeWalker(root, 4);\n let out = \"\";\n for (let n = walker.nextNode(); n; n = walker.nextNode()) {\n if (!insideSensitive(n)) out += n.nodeValue ?? \"\";\n }\n return out;\n}\n\nexport function roleOf(el: Element): string {\n const explicit = el.getAttribute(\"role\");\n if (explicit) return explicit;\n const t = tag(el);\n if (t === \"A\") return \"link\";\n if (t === \"BUTTON\") return \"button\";\n if (t === \"SELECT\") return \"select\";\n if (t === \"TEXTAREA\") return \"textbox\";\n if (t === \"INPUT\") {\n const type = (el as HTMLInputElement).type;\n if (type === \"checkbox\") return \"checkbox\";\n if (type === \"radio\") return \"radio\";\n if (type === \"submit\" || type === \"button\") return \"button\";\n return \"textbox\";\n }\n return \"generic\";\n}\n\nfunction labelFor(doc: Document, id: string): Element | null {\n // Equivalent to querySelector(`label[for=\"${CSS.escape(id)}\"]`) — first match\n // in document order — without building a selector from page-controlled text.\n for (const lbl of Array.from(doc.querySelectorAll(\"label[for]\"))) {\n if (lbl.getAttribute(\"for\") === id) return lbl;\n }\n return null;\n}\n\nexport function accessibleName(el: Element): string {\n const doc = el.ownerDocument;\n const aria = el.getAttribute(\"aria-label\");\n if (aria) return aria.trim();\n const labelledby = el.getAttribute(\"aria-labelledby\");\n if (labelledby) {\n const txt = labelledby\n .split(/\\s+/)\n .map((id) => doc.getElementById(id)?.textContent ?? \"\")\n .join(\" \")\n .trim();\n if (txt) return txt;\n }\n const id = el.getAttribute(\"id\");\n if (id) {\n const lbl = labelFor(doc, id);\n if (lbl?.textContent?.trim()) return lbl.textContent.trim();\n }\n const wrapping = el.closest(\"label\");\n if (wrapping) {\n const txt = safeText(wrapping).trim();\n if (txt) return txt;\n }\n const placeholder = el.getAttribute(\"placeholder\");\n if (placeholder) return placeholder.trim();\n // A sensitive field's own text is its value (a textarea's content), so it is\n // never used as its name.\n const text = isSensitive(el) ? \"\" : (el as HTMLElement).textContent?.trim();\n if (text) return text.replace(/\\s+/g, \" \").slice(0, 80);\n return el.getAttribute(\"name\") ?? el.getAttribute(\"id\") ?? roleOf(el);\n}\n\nexport function isDestructive(el: Element, label: string): boolean {\n if (el.hasAttribute(\"data-co-confirm\")) return true;\n if ((el as HTMLInputElement).type === \"submit\") return true;\n if (tag(el) === \"BUTTON\" && (el as HTMLButtonElement).type === \"submit\") return true;\n return /\\b(delete|remove|destroy|sign out|log ?out|cancel subscription|deactivate)\\b/i.test(label);\n}\n\n/**\n * The element's own stable handle: data-co-handle → name → id, or \"\" when it\n * has none. An EMPTY attribute counts as absent — `button.name` is `\"\"`, not\n * null, on every button, anchor and input without one, so a plain `??` chain\n * never reaches the id.\n */\nexport function attributeHandle(el: Element): string {\n return (\n el.getAttribute(\"data-co-handle\") ||\n el.getAttribute(\"name\") ||\n el.getAttribute(\"id\") ||\n \"\"\n );\n}\n\n/**\n * Build a fresh snapshot + a handle→element registry. Handle preference:\n * data-co-handle → name → id → `role#index` (stable within a snapshot).\n */\nexport function walk(doc: Document = document): { snapshot: PageSnapshot; registry: Map<string, Element> } {\n const registry = new Map<string, Element>();\n const actions: PageAction[] = [];\n const seen = new Set<Element>();\n let synthetic = 0;\n\n for (const el of Array.from(doc.querySelectorAll(INTERACTIVE))) {\n if (seen.has(el) || !isVisible(el)) continue;\n seen.add(el);\n const label = accessibleName(el);\n const role = roleOf(el);\n let handle = attributeHandle(el);\n if (!handle || registry.has(handle)) handle = `${role}#${synthetic++}`;\n registry.set(handle, el);\n\n let value: unknown;\n if (role === \"textbox\" || role === \"select\") {\n value = isSensitive(el) ? undefined : (el as HTMLInputElement).value;\n } else if (role === \"checkbox\" || role === \"radio\") {\n value = (el as HTMLInputElement).checked;\n }\n\n const action: PageAction = { handle, role, label, destructive: isDestructive(el, label) };\n if (value !== undefined) action.value = value;\n actions.push(action);\n }\n\n const loc = doc.defaultView?.location;\n return {\n snapshot: { url: loc ? loc.pathname + loc.search : \"\", title: doc.title, actions },\n registry,\n };\n}\n\nfunction isField(el: Element): el is FieldElement {\n const t = tag(el);\n return t === \"INPUT\" || t === \"TEXTAREA\" || t === \"SELECT\";\n}\n\n/**\n * Set a field's value so a React-controlled input sees the change.\n *\n * - Text, textarea, select: call the PROTOTYPE `value` setter (React shadows\n * `value` on the instance with its value tracker), then dispatch bubbling\n * `input` + `change`.\n * - Checkbox, radio: React's onChange for these listens to `click`, not\n * `input` / `change`, so the write is a real `click()` — the browser toggles\n * the box and fires click, input and change itself. Only when the state\n * actually differs, so setting the current value is a no-op rather than a\n * toggle. A radio cannot be unchecked by clicking it; that one case falls\n * back to the setter.\n */\nexport function setNativeValue(el: FieldElement, value: unknown): void {\n const view = (el.ownerDocument.defaultView ?? globalThis) as typeof globalThis;\n const fire = () => {\n el.dispatchEvent(new view.Event(\"input\", { bubbles: true }));\n el.dispatchEvent(new view.Event(\"change\", { bubbles: true }));\n };\n const t = tag(el);\n if (t === \"INPUT\" && ((el as HTMLInputElement).type === \"checkbox\" || (el as HTMLInputElement).type === \"radio\")) {\n const input = el as HTMLInputElement;\n const want = Boolean(value);\n if (input.checked === want) return;\n if (input.type === \"checkbox\" || want) {\n input.click();\n return;\n }\n const setter = Object.getOwnPropertyDescriptor(view.HTMLInputElement.prototype, \"checked\")?.set;\n setter?.call(el, false);\n fire();\n return;\n }\n const proto =\n t === \"TEXTAREA\"\n ? view.HTMLTextAreaElement.prototype\n : t === \"SELECT\"\n ? view.HTMLSelectElement.prototype\n : view.HTMLInputElement.prototype;\n const setter = Object.getOwnPropertyDescriptor(proto, \"value\")?.set;\n setter?.call(el, String(value));\n fire();\n}\n\n/**\n * Visible text / heading outline, with sensitive text removed. Structured, so\n * the bridge can render each page-supplied string on its own single line.\n */\nexport function readPage(doc: Document = document): PageReadout {\n const main = doc.querySelector(\"main\") ?? doc.body;\n if (!main) return { title: doc.title, headings: [], text: \"\" };\n const headings = Array.from(main.querySelectorAll(\"h1, h2, h3\")).map((h) => ({\n level: Number(h.tagName.slice(1)),\n text: safeText(h).trim(),\n }));\n const text = safeText(main).replace(/\\s+/g, \" \").trim().slice(0, 4000);\n return { title: doc.title, headings, text };\n}\n\nexport type DomNavigationAgentOptions = {\n /** Document to drive. Default: the global `document`, read lazily. */\n document?: Document;\n /**\n * Called just before the agent acts on the page — before resolving a field\n * for `setField`, and after resolving (only when the element exists) for\n * `click` / `submit`. The sandbox uses it to attribute the request an action\n * causes to the agent.\n */\n beforeAction?: (action: \"setField\" | \"click\" | \"submit\") => void;\n};\n\nexport type DomNavigationAgent = {\n getLocation(): { url: string; title: string };\n describe(): PageSnapshot;\n read(): PageReadout;\n /** Navigate. Only http(s) or same-site paths; deferred a tick so a remote call returns first. */\n visit(url: string): void;\n back(): void;\n forward(): void;\n scrollTo(opts: { x?: number; y?: number; handle?: string }): void;\n scrollBy(dy: number): void;\n setField(handle: string, value: unknown): ActionResult;\n click(handle: string): ActionResult;\n submit(handle: string): ActionResult;\n rectFor(handle: string): HandleRect | null;\n /** Element for a handle: this snapshot's registry, then a live attribute lookup. */\n resolve(handle: string): Element | null;\n /** Serialisable dispatch — what the injected script exposes to a host. */\n call(method: DomNavigationMethod, args?: unknown[]): unknown;\n};\n\nfunction findByAttribute(doc: Document, attr: string, value: string): Element | null {\n for (const el of Array.from(doc.querySelectorAll(`[${attr}]`))) {\n if (el.getAttribute(attr) === value) return el;\n }\n return null;\n}\n\nconst num = (v: unknown) => (typeof v === \"number\" ? v : undefined);\n\nexport function createDomNavigationAgent(options: DomNavigationAgentOptions = {}): DomNavigationAgent {\n let registry = new Map<string, Element>();\n const doc = () => options.document ?? document;\n const win = () => (doc().defaultView ?? window) as Window;\n const before = (action: \"setField\" | \"click\" | \"submit\") => options.beforeAction?.(action);\n\n const resolve = (handle: string): Element | null => {\n const hit = registry.get(handle);\n if (hit && hit.isConnected) return hit;\n // Fallback: a real attribute handle the agent may use before describe().\n const d = doc();\n return (\n findByAttribute(d, \"data-co-handle\", handle) ??\n findByAttribute(d, \"name\", handle) ??\n d.getElementById(handle)\n );\n };\n\n const agent: DomNavigationAgent = {\n getLocation: () => {\n const loc = win().location;\n return { url: loc.pathname + loc.search, title: doc().title };\n },\n describe: () => {\n const res = walk(doc());\n registry = res.registry;\n return res.snapshot;\n },\n read: () => readPage(doc()),\n visit: (url) => {\n const w = win();\n const target = new URL(String(url), w.location.href);\n if (target.protocol !== \"http:\" && target.protocol !== \"https:\") {\n throw new Error(`Refusing to navigate to a '${target.protocol}' URL.`);\n }\n w.setTimeout(() => w.location.assign(target.href), 0);\n },\n back: () => win().history.back(),\n forward: () => win().history.forward(),\n scrollTo: ({ x, y, handle }) => {\n const w = win();\n if (handle) {\n resolve(handle)?.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n return;\n }\n w.scrollTo({ left: x ?? w.scrollX, top: y ?? w.scrollY, behavior: \"smooth\" });\n },\n scrollBy: (dy) => win().scrollBy({ top: dy, behavior: \"smooth\" }),\n setField: (handle, value) => {\n before(\"setField\");\n const el = resolve(handle);\n if (!el) return { ok: false, error: `No element for handle \"${handle}\"` };\n if (isField(el)) {\n setNativeValue(el, value);\n return { ok: true };\n }\n return { ok: false, error: `Handle \"${handle}\" is not a form field` };\n },\n click: (handle) => {\n const el = resolve(handle);\n if (!el) return { ok: false, error: `No element for handle \"${handle}\"` };\n // Before the click: an Inertia link fires its visit synchronously inside click().\n before(\"click\");\n (el as HTMLElement).click();\n return { ok: true };\n },\n submit: (handle) => {\n const el = resolve(handle);\n if (!el) return { ok: false, error: `No element for handle \"${handle}\"` };\n const form = (tag(el) === \"FORM\" ? el : el.closest(\"form\")) as HTMLFormElement | null;\n if (!form) return { ok: false, error: `Handle \"${handle}\" is not inside a form` };\n before(\"submit\");\n if (typeof form.requestSubmit === \"function\") form.requestSubmit();\n else form.submit();\n return { ok: true };\n },\n rectFor: (handle) => {\n const el = resolve(handle);\n if (!el) return null;\n const r = el.getBoundingClientRect();\n return { x: r.left, y: r.top, width: r.width, height: r.height };\n },\n resolve,\n call: (method, args = []) => {\n const a = Array.isArray(args) ? args : [];\n const handle = String(a[0] ?? \"\");\n switch (method) {\n case \"getLocation\":\n return agent.getLocation();\n case \"describe\":\n return agent.describe();\n case \"read\":\n return agent.read();\n case \"visit\":\n agent.visit(String(a[0] ?? \"\"));\n return undefined;\n case \"back\":\n agent.back();\n return undefined;\n case \"forward\":\n agent.forward();\n return undefined;\n case \"scrollTo\": {\n const o = (a[0] && typeof a[0] === \"object\" ? a[0] : {}) as Record<string, unknown>;\n agent.scrollTo({\n x: num(o.x),\n y: num(o.y),\n handle: typeof o.handle === \"string\" ? o.handle : undefined,\n });\n return undefined;\n }\n case \"scrollBy\":\n agent.scrollBy(Number(a[0] ?? 0));\n return undefined;\n case \"setField\":\n return agent.setField(handle, a[1]);\n case \"click\":\n return agent.click(handle);\n case \"submit\":\n return agent.submit(handle);\n case \"rectFor\":\n return agent.rectFor(handle);\n default:\n throw new Error(`Unknown dom-navigation method: ${String(method)}`);\n }\n },\n };\n return agent;\n}\n","/**\n * The host half: a {@link NavigationBridgeAdapter} that drives a page it does\n * not run in, through any transport that can carry a method name and plain\n * arguments into the page and a plain result back — Electron's\n * `executeJavaScript` / `executeJavaScriptInIsolatedWorld`, a MessagePort, a\n * WebSocket to a remote browser.\n *\n * Every result is treated as hostile: the page owns the DOM the in-page walker\n * reads, and if the script was injected into the MAIN world the page can\n * replace the walker outright. So results are coerced to the declared shapes\n * here, and anything malformed is dropped rather than passed on to the agent.\n */\nimport type {\n NavigationBridgeAdapter,\n NavigationConfirmRequest,\n PageAction,\n PageReadout,\n PageSnapshot,\n} from \"../bridges/navigation\";\nimport { DOM_NAVIGATION_METHODS, type ActionResult, type DomNavigationMethod, type HandleRect } from \"./agent\";\n\n/** The global the injected script installs in the world it runs in. */\nexport const DOM_NAVIGATION_GLOBAL = \"__fancyDomNavigation\";\n\n/** Bumped only if the wire protocol changes incompatibly. */\nexport const DOM_NAVIGATION_PROTOCOL = 1;\n\n/**\n * Carries one call into the page. `args` and the resolved value are plain,\n * structured-cloneable data. Reject (or throw) when the call could not be\n * delivered — e.g. the page navigated and the script must be re-injected.\n */\nexport type DomNavigationTransport = {\n call(method: DomNavigationMethod, args: unknown[]): Promise<unknown>;\n};\n\nexport type RemoteNavigationAdapterOptions = {\n transport: DomNavigationTransport;\n /** Optional fancy-screens screen id for presence targeting. */\n screenId?: string;\n /** Human-control revision, if the host tracks one. Omit to disable stale-intent protection. */\n getRevision?: () => number | Promise<number>;\n /**\n * Trust-but-verify. Without it, `page_submit` and destructive `page_click`\n * are NOT staged — they run as soon as the agent asks. A host showing pages\n * it does not own should always supply one.\n */\n confirm?: (req: NavigationConfirmRequest) => Promise<boolean>;\n};\n\nconst METHODS = new Set<string>(DOM_NAVIGATION_METHODS);\n\nfunction assertMethod(method: string): asserts method is DomNavigationMethod {\n if (!METHODS.has(method)) throw new Error(`Unknown dom-navigation method: ${method}`);\n}\n\n/**\n * A JavaScript expression that performs one call against the injected global —\n * what a host passes to `executeJavaScript`. Arguments are embedded as JSON,\n * which is a valid JS expression, so no argument can break out of its literal.\n */\nexport function domNavigationCallScript(method: DomNavigationMethod, args: unknown[] = []): string {\n assertMethod(method);\n const g = JSON.stringify(DOM_NAVIGATION_GLOBAL);\n return (\n `(function(){var n=globalThis[${g}];` +\n `if(!n||typeof n.call!==\"function\")throw new Error(\"fancy dom-navigation is not injected in this world\");` +\n `return n.call(${JSON.stringify(method)},${JSON.stringify(args)});})()`\n );\n}\n\nconst str = (v: unknown, fallback = \"\") => (typeof v === \"string\" ? v : fallback);\nconst isObj = (v: unknown): v is Record<string, unknown> => typeof v === \"object\" && v !== null;\n\nfunction coerceAction(v: unknown): PageAction | null {\n if (!isObj(v) || typeof v.handle !== \"string\" || v.handle === \"\") return null;\n const action: PageAction = {\n handle: v.handle,\n role: str(v.role, \"generic\"),\n label: str(v.label),\n destructive: v.destructive === true,\n };\n const value = v.value;\n if (typeof value === \"string\" || typeof value === \"boolean\" || (typeof value === \"number\" && Number.isFinite(value))) {\n action.value = value;\n }\n return action;\n}\n\nfunction coerceSnapshot(v: unknown): PageSnapshot {\n const o = isObj(v) ? v : {};\n const actions = Array.isArray(o.actions)\n ? o.actions.map(coerceAction).filter((a): a is PageAction => a !== null)\n : [];\n return { url: str(o.url), title: str(o.title), actions };\n}\n\n/** A plain string stays a string (the bridge renders it as one line). */\nfunction coerceReadout(v: unknown): string | PageReadout {\n if (typeof v === \"string\") return v;\n const o = isObj(v) ? v : {};\n const headings = (Array.isArray(o.headings) ? o.headings : []).flatMap((h) =>\n isObj(h) && typeof h.text === \"string\" && typeof h.level === \"number\" && Number.isFinite(h.level)\n ? [{ level: h.level, text: h.text }]\n : [],\n );\n return { title: str(o.title), headings, text: str(o.text) };\n}\n\nfunction coerceResult(v: unknown): ActionResult {\n const o = isObj(v) ? v : {};\n return { ok: o.ok === true, error: typeof o.error === \"string\" ? o.error : undefined };\n}\n\nfunction coerceRect(v: unknown): HandleRect | null {\n if (!isObj(v)) return null;\n const { x, y, width, height } = v;\n const finite = (n: unknown): n is number => typeof n === \"number\" && Number.isFinite(n);\n return finite(x) && finite(y) && finite(width) && finite(height) ? { x, y, width, height } : null;\n}\n\n/** Build a NavigationBridgeAdapter backed by a transport into the page. */\nexport function createRemoteNavigationAdapter(options: RemoteNavigationAdapterOptions): NavigationBridgeAdapter {\n const { transport } = options;\n const call = (method: DomNavigationMethod, ...args: unknown[]) => transport.call(method, args);\n const fail = (e: unknown): ActionResult => ({ ok: false, error: e instanceof Error ? e.message : String(e) });\n\n return {\n screenId: options.screenId,\n getRevision: options.getRevision,\n confirm: options.confirm,\n getLocation: async () => {\n const o = await call(\"getLocation\");\n const loc = isObj(o) ? o : {};\n return { url: str(loc.url), title: str(loc.title) };\n },\n describe: async () => coerceSnapshot(await call(\"describe\")),\n read: async () => coerceReadout(await call(\"read\")),\n visit: async (url) => {\n await call(\"visit\", url);\n },\n back: async () => {\n await call(\"back\");\n },\n forward: async () => {\n await call(\"forward\");\n },\n scrollTo: async (opts) => {\n await call(\"scrollTo\", { x: opts.x, y: opts.y, handle: opts.handle });\n },\n scrollBy: async (dy) => {\n await call(\"scrollBy\", dy);\n },\n setField: async (handle, value) => coerceResult(await call(\"setField\", handle, value).catch(fail)),\n click: async (handle) => coerceResult(await call(\"click\", handle).catch(fail)),\n submit: async (handle) => coerceResult(await call(\"submit\", handle).catch(fail)),\n rectFor: async (handle) => coerceRect(await call(\"rectFor\", handle).catch(() => null)),\n };\n}\n"]}
|