@anubhav-choubey/web-for-agents 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -515
- package/dist/bin.js +4 -4
- package/dist/chunk-CGIIB6AF.js +127 -0
- package/dist/{chunk-AZG5MLNG.js → chunk-F7PN5R25.js} +2 -0
- package/dist/chunk-LCVPXUFN.js +245 -0
- package/dist/{chunk-IF32TPGR.js → chunk-P6JSPAA2.js} +169 -124
- package/dist/{chunk-5TNG4QMP.js → chunk-PGZH33B5.js} +20 -2
- package/dist/chunk-PHTV5NAY.js +44 -0
- package/dist/{chunk-ZYMNO5AO.js → chunk-PSNLS4GL.js} +93 -57
- package/dist/{chunk-HONWT6GK.js → chunk-SMFRAZAA.js} +66 -34
- package/dist/cli.js +4 -4
- package/dist/{happyDom-XVDHYJDM.js → happyDom-WTYQ5UAC.js} +3 -3
- package/dist/index.js +41 -235
- package/dist/overlay.js +7 -32
- package/dist/{renderChild-Y2RFSYY4.js → renderChild-H6TR4SGV.js} +27 -4
- package/dist/vite.d.ts +88 -2
- package/dist/vite.js +628 -146
- package/package.json +1 -1
- package/dist/chunk-CKXHTGGT.js +0 -25
- package/dist/chunk-LCVI2PRP.js +0 -13
|
@@ -2,11 +2,16 @@ import {
|
|
|
2
2
|
collapseWhitespace
|
|
3
3
|
} from "./chunk-FEAKVNMG.js";
|
|
4
4
|
import {
|
|
5
|
+
ACTION_ATTR,
|
|
6
|
+
ACTION_DESCRIPTION_ATTR,
|
|
7
|
+
ACTION_DESTRUCTIVE_ATTR,
|
|
5
8
|
CONTENT_ATTR,
|
|
6
9
|
EXCLUDE_ATTR,
|
|
7
10
|
HIDDEN_SELECTOR,
|
|
11
|
+
WEBMCP_TOOLDESCRIPTION_ATTR,
|
|
12
|
+
WEBMCP_TOOLNAME_ATTR,
|
|
8
13
|
resolveUrl
|
|
9
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-F7PN5R25.js";
|
|
10
15
|
|
|
11
16
|
// src/shared/shortcut.ts
|
|
12
17
|
var DEFAULT_SHORTCUT = "alt+shift+a";
|
|
@@ -37,6 +42,60 @@ function matchesShortcut(e, s) {
|
|
|
37
42
|
return e.code === s.code && e.altKey === s.alt && e.shiftKey === s.shift && e.ctrlKey === s.ctrl && e.metaKey === s.meta;
|
|
38
43
|
}
|
|
39
44
|
|
|
45
|
+
// src/shared/content.ts
|
|
46
|
+
var DEFAULT_CONTENT_SELECTOR = "main";
|
|
47
|
+
var STRIP = `script, style, noscript, template, nav, [${EXCLUDE_ATTR}], ${HIDDEN_SELECTOR}`;
|
|
48
|
+
var BODY_STRIP = "header, nav, footer, aside";
|
|
49
|
+
function selectContentRegion(doc, opts = {}) {
|
|
50
|
+
const element = doc.createElement("div");
|
|
51
|
+
const take = (n) => opts.inPlace ? n : n.cloneNode(true);
|
|
52
|
+
let source;
|
|
53
|
+
const markers = Array.from(doc.querySelectorAll(`[${CONTENT_ATTR}]`)).filter(
|
|
54
|
+
(el) => !el.parentElement?.closest(`[${CONTENT_ATTR}]`)
|
|
55
|
+
);
|
|
56
|
+
let selected = null;
|
|
57
|
+
if (markers.length > 0) {
|
|
58
|
+
source = "marker";
|
|
59
|
+
for (const m of markers) element.appendChild(take(m));
|
|
60
|
+
} else {
|
|
61
|
+
try {
|
|
62
|
+
selected = doc.querySelector(opts.contentSelector ?? DEFAULT_CONTENT_SELECTOR);
|
|
63
|
+
} catch {
|
|
64
|
+
selected = null;
|
|
65
|
+
}
|
|
66
|
+
if (selected) {
|
|
67
|
+
source = "selector";
|
|
68
|
+
element.appendChild(take(selected));
|
|
69
|
+
} else {
|
|
70
|
+
source = "body";
|
|
71
|
+
for (const child of Array.from(doc.body?.childNodes ?? [])) {
|
|
72
|
+
element.appendChild(take(child));
|
|
73
|
+
}
|
|
74
|
+
for (const el of Array.from(element.querySelectorAll(BODY_STRIP))) el.remove();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
for (const el of Array.from(element.querySelectorAll(STRIP))) el.remove();
|
|
78
|
+
return { element, source };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/shared/pageMeta.ts
|
|
82
|
+
function readPageMeta(doc) {
|
|
83
|
+
const titleTag = (doc.title ?? "").trim();
|
|
84
|
+
const title = titleTag || (doc.querySelector("h1")?.textContent ?? "").trim();
|
|
85
|
+
const description = doc.querySelector('meta[name="description"]')?.getAttribute("content")?.trim() || null;
|
|
86
|
+
const robots = doc.querySelector('meta[name="robots"]')?.getAttribute("content") ?? null;
|
|
87
|
+
const canonical = doc.querySelector('link[rel~="canonical"]')?.getAttribute("href")?.trim() || null;
|
|
88
|
+
return {
|
|
89
|
+
title: title || null,
|
|
90
|
+
titleFromDocument: title !== "",
|
|
91
|
+
titleTag: titleTag !== "",
|
|
92
|
+
description,
|
|
93
|
+
robots,
|
|
94
|
+
noindex: /noindex/i.test(robots ?? ""),
|
|
95
|
+
canonical
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
40
99
|
// src/shared/markdown.ts
|
|
41
100
|
import TurndownService from "turndown";
|
|
42
101
|
import { gfm } from "turndown-plugin-gfm";
|
|
@@ -108,68 +167,45 @@ function buildPageMarkdown(title, contentHtml, pageUrl) {
|
|
|
108
167
|
${body}`.replace(/\n+$/, "\n");
|
|
109
168
|
}
|
|
110
169
|
|
|
111
|
-
// src/shared/
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
for (const el of Array.from(element.querySelectorAll(BODY_STRIP))) el.remove();
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
for (const el of Array.from(element.querySelectorAll(STRIP))) el.remove();
|
|
144
|
-
return { element, source };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// src/shared/pageMeta.ts
|
|
148
|
-
function readPageMeta(doc) {
|
|
149
|
-
const titleTag = (doc.title ?? "").trim();
|
|
150
|
-
const title = titleTag || (doc.querySelector("h1")?.textContent ?? "").trim();
|
|
151
|
-
const description = doc.querySelector('meta[name="description"]')?.getAttribute("content")?.trim() || null;
|
|
152
|
-
const robots = doc.querySelector('meta[name="robots"]')?.getAttribute("content") ?? null;
|
|
153
|
-
const canonical = doc.querySelector('link[rel~="canonical"]')?.getAttribute("href")?.trim() || null;
|
|
154
|
-
return {
|
|
155
|
-
title: title || null,
|
|
156
|
-
titleFromDocument: title !== "",
|
|
157
|
-
titleTag: titleTag !== "",
|
|
158
|
-
description,
|
|
159
|
-
robots,
|
|
160
|
-
noindex: /noindex/i.test(robots ?? ""),
|
|
161
|
-
canonical
|
|
162
|
-
};
|
|
170
|
+
// src/shared/markupActions.ts
|
|
171
|
+
function markupActions(doc) {
|
|
172
|
+
const out = [];
|
|
173
|
+
doc.querySelectorAll(`[${ACTION_ATTR}]`).forEach((el) => {
|
|
174
|
+
const name = el.getAttribute(ACTION_ATTR)?.trim();
|
|
175
|
+
if (!name) return;
|
|
176
|
+
out.push({
|
|
177
|
+
element: el,
|
|
178
|
+
name,
|
|
179
|
+
description: el.getAttribute(ACTION_DESCRIPTION_ATTR) || null,
|
|
180
|
+
kind: el.tagName === "FORM" ? "form" : "click",
|
|
181
|
+
destructive: el.getAttribute(ACTION_DESTRUCTIVE_ATTR) === "true",
|
|
182
|
+
source: "markup"
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
doc.querySelectorAll(`form[${WEBMCP_TOOLNAME_ATTR}]`).forEach((el) => {
|
|
186
|
+
const name = el.getAttribute(WEBMCP_TOOLNAME_ATTR)?.trim();
|
|
187
|
+
if (!name) return;
|
|
188
|
+
out.push({
|
|
189
|
+
element: el,
|
|
190
|
+
name,
|
|
191
|
+
description: el.getAttribute(WEBMCP_TOOLDESCRIPTION_ATTR) || null,
|
|
192
|
+
kind: "form",
|
|
193
|
+
destructive: false,
|
|
194
|
+
source: "webmcp-declarative"
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
return out;
|
|
163
198
|
}
|
|
164
199
|
|
|
165
200
|
export {
|
|
166
|
-
escapeMarkdownInline,
|
|
167
|
-
escapeLinkTarget,
|
|
168
|
-
buildPageMarkdown,
|
|
169
201
|
DEFAULT_CONTENT_SELECTOR,
|
|
170
202
|
selectContentRegion,
|
|
171
203
|
DEFAULT_SHORTCUT,
|
|
172
204
|
parseShortcut,
|
|
173
205
|
matchesShortcut,
|
|
174
|
-
readPageMeta
|
|
206
|
+
readPageMeta,
|
|
207
|
+
escapeMarkdownInline,
|
|
208
|
+
escapeLinkTarget,
|
|
209
|
+
buildPageMarkdown,
|
|
210
|
+
markupActions
|
|
175
211
|
};
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
READY_GLOBAL
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-F7PN5R25.js";
|
|
4
4
|
import {
|
|
5
5
|
POLL_MS,
|
|
6
6
|
RenderError,
|
|
7
7
|
SERIALIZE_EXPR,
|
|
8
8
|
SETTLED_POLL_MS,
|
|
9
|
+
SNAPSHOT_GRACE_MS,
|
|
10
|
+
TimeoutError,
|
|
11
|
+
assertNoPageErrors,
|
|
9
12
|
blockedHint,
|
|
10
13
|
createDeadline,
|
|
11
14
|
createOriginPolicy,
|
|
12
15
|
readyTimeoutMessage,
|
|
13
16
|
runInPage,
|
|
17
|
+
snapshotWarning,
|
|
14
18
|
waitForReady,
|
|
15
19
|
withoutBlockedLoads
|
|
16
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-PGZH33B5.js";
|
|
17
21
|
import {
|
|
18
22
|
LOG_PREFIX,
|
|
19
23
|
errorMessage
|
|
@@ -56,8 +60,11 @@ var PROBE_SCRIPT = `(function () {
|
|
|
56
60
|
};
|
|
57
61
|
}
|
|
58
62
|
if (w.MutationObserver) {
|
|
63
|
+
// Content changes only: attribute churn (class, style, aria-*, data-* animations) never settles
|
|
64
|
+
// on an animated page. Attributes are still saved, so a late attribute-only update (a meta tag or
|
|
65
|
+
// an img src changed alone, after the content is quiet) may be captured before or after it lands.
|
|
59
66
|
new w.MutationObserver(touch).observe(document, {
|
|
60
|
-
childList: true, subtree: true,
|
|
67
|
+
childList: true, subtree: true, characterData: true
|
|
61
68
|
});
|
|
62
69
|
}
|
|
63
70
|
w.addEventListener("error", function (e) {
|
|
@@ -74,12 +81,25 @@ var PROBE_SCRIPT = `(function () {
|
|
|
74
81
|
p.errors.push(String((r && r.message) || r || "unhandledrejection")); touch();
|
|
75
82
|
});
|
|
76
83
|
})();`;
|
|
77
|
-
function readyCheck(idleMs = IDLE_MS) {
|
|
78
|
-
|
|
84
|
+
function readyCheck(idleMs = IDLE_MS, readySelector) {
|
|
85
|
+
if (readySelector === void 0) {
|
|
86
|
+
return `(function () {
|
|
79
87
|
var p = window.${PROBE_GLOBAL};
|
|
80
88
|
if (!p) return { ready: false, errors: [], path: location.pathname };
|
|
81
89
|
var ready = document.readyState === "complete" && p.inflight === 0 && Date.now() - p.last >= ${idleMs} && window.${READY_GLOBAL} !== false;
|
|
82
90
|
return { ready: ready, errors: p.errors.slice(), path: location.pathname };
|
|
91
|
+
})()`;
|
|
92
|
+
}
|
|
93
|
+
const sel = JSON.stringify(readySelector);
|
|
94
|
+
const invalid = JSON.stringify(`prerender.readySelector ${sel} is not a valid CSS selector: `);
|
|
95
|
+
return `(function () {
|
|
96
|
+
var p = window.${PROBE_GLOBAL};
|
|
97
|
+
if (!p) return { ready: false, errors: [], path: location.pathname };
|
|
98
|
+
var found;
|
|
99
|
+
try { found = document.querySelector(${sel}) !== null; }
|
|
100
|
+
catch (e) { return { ready: false, errors: [${invalid} + String((e && e.message) || e)], path: location.pathname }; }
|
|
101
|
+
var ready = document.readyState === "complete" && p.inflight === 0 && found && window.${READY_GLOBAL} !== false;
|
|
102
|
+
return { ready: ready, errors: p.errors.slice(), path: location.pathname };
|
|
83
103
|
})()`;
|
|
84
104
|
}
|
|
85
105
|
var READY_CHECK = readyCheck(IDLE_MS);
|
|
@@ -250,6 +270,24 @@ function createHappyDomRenderer(opts = {}) {
|
|
|
250
270
|
}
|
|
251
271
|
}
|
|
252
272
|
});
|
|
273
|
+
const waitUntilReady = async (page, blocked, deadline, timeoutMs) => {
|
|
274
|
+
const poll = async (check2) => {
|
|
275
|
+
const r = page.evaluate(check2);
|
|
276
|
+
return { ready: r.ready, errors: withoutBlockedLoads([...r.errors], blocked) };
|
|
277
|
+
};
|
|
278
|
+
if (opts.readySelector !== void 0) {
|
|
279
|
+
const check2 = readyCheck(IDLE_MS, opts.readySelector);
|
|
280
|
+
return waitForReady(() => poll(check2), timeoutMs, POLL_MS);
|
|
281
|
+
}
|
|
282
|
+
let timer;
|
|
283
|
+
const settled = await Promise.race([
|
|
284
|
+
page.waitUntilComplete().then(() => true),
|
|
285
|
+
new Promise((r) => timer = setTimeout(() => r(false), Math.min(deadline.remaining(), 2e3)))
|
|
286
|
+
]).finally(() => clearTimeout(timer));
|
|
287
|
+
const idleMs = opts.idleMs ?? (settled ? SETTLED_IDLE_MS : IDLE_MS);
|
|
288
|
+
const check = readyCheck(idleMs);
|
|
289
|
+
return waitForReady(() => poll(check), timeoutMs, Math.min(settled ? SETTLED_POLL_MS : POLL_MS, idleMs));
|
|
290
|
+
};
|
|
253
291
|
return {
|
|
254
292
|
name: "happy-dom",
|
|
255
293
|
async render(url, timeoutMs, inPage) {
|
|
@@ -265,48 +303,42 @@ function createHappyDomRenderer(opts = {}) {
|
|
|
265
303
|
};
|
|
266
304
|
const sink = pageSink(page);
|
|
267
305
|
attach(sink);
|
|
268
|
-
const
|
|
306
|
+
const within = (d, text, work) => d.race(Promise.race([work, sink.failed]), text);
|
|
307
|
+
const step = (work) => within(deadline, timeoutText, work);
|
|
308
|
+
let timedOut = false;
|
|
269
309
|
try {
|
|
270
310
|
try {
|
|
271
311
|
await step(page.goto(url));
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
waitForReady(
|
|
283
|
-
async () => {
|
|
284
|
-
const r = page.evaluate(check);
|
|
285
|
-
return { ready: r.ready, errors: withoutBlockedLoads([...r.errors], state.blocked) };
|
|
286
|
-
},
|
|
287
|
-
timeoutMs,
|
|
288
|
-
Math.min(settled ? SETTLED_POLL_MS : POLL_MS, idleMs)
|
|
289
|
-
)
|
|
290
|
-
);
|
|
312
|
+
try {
|
|
313
|
+
await step(waitUntilReady(page, state.blocked, deadline, timeoutMs));
|
|
314
|
+
} catch (e) {
|
|
315
|
+
if (!(opts.onTimeout === "snapshot" && e instanceof TimeoutError)) throw e;
|
|
316
|
+
timedOut = true;
|
|
317
|
+
await assertNoPageErrors(() => {
|
|
318
|
+
const r = page.evaluate(readyCheck(IDLE_MS, opts.readySelector));
|
|
319
|
+
return withoutBlockedLoads([...r.errors], state.blocked);
|
|
320
|
+
});
|
|
321
|
+
}
|
|
291
322
|
} catch (e) {
|
|
292
323
|
throw new RenderError("happy-dom", errorMessage(e) + blockedHint(state.blocked) + syncHint(state.syncRefused));
|
|
293
324
|
}
|
|
294
325
|
const html = page.evaluate(SERIALIZE_EXPR);
|
|
295
326
|
const finalPath = new URL(page.url).pathname;
|
|
327
|
+
const after = timedOut ? createDeadline(SNAPSHOT_GRACE_MS) : deadline;
|
|
328
|
+
const afterMs = timedOut ? SNAPSHOT_GRACE_MS : timeoutMs;
|
|
296
329
|
const results = await runInPage(
|
|
297
330
|
"happy-dom",
|
|
298
331
|
inPage,
|
|
299
|
-
(expr) =>
|
|
300
|
-
|
|
301
|
-
|
|
332
|
+
(expr) => within(after, readyTimeoutMessage(afterMs), Promise.resolve().then(() => page.evaluate(expr))),
|
|
333
|
+
after,
|
|
334
|
+
afterMs
|
|
302
335
|
);
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
finalPath,
|
|
306
|
-
inPage: results,
|
|
336
|
+
const warnings = [
|
|
337
|
+
...timedOut ? [snapshotWarning(timeoutMs)] : [],
|
|
307
338
|
// The page rendered anyway, but without what the refused requests would have loaded.
|
|
308
|
-
...
|
|
309
|
-
|
|
339
|
+
...[...new Map(state.syncRefused.map((r) => [r.kind + r.url, r])).values()].map(syncRefusalText)
|
|
340
|
+
];
|
|
341
|
+
return { html, finalPath, inPage: results, ...warnings.length > 0 ? { warnings } : {} };
|
|
310
342
|
} finally {
|
|
311
343
|
active.delete(state);
|
|
312
344
|
await page.close().catch(() => {
|
package/dist/cli.js
CHANGED
|
@@ -2,12 +2,12 @@ import {
|
|
|
2
2
|
audit,
|
|
3
3
|
formatText,
|
|
4
4
|
runCli
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-P6JSPAA2.js";
|
|
6
|
+
import "./chunk-CGIIB6AF.js";
|
|
7
|
+
import "./chunk-PHTV5NAY.js";
|
|
8
8
|
import "./chunk-LCLDQ3A3.js";
|
|
9
9
|
import "./chunk-FEAKVNMG.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-F7PN5R25.js";
|
|
11
11
|
import "./chunk-JJN6FNJD.js";
|
|
12
12
|
export {
|
|
13
13
|
audit,
|
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
createHappyDomRenderer,
|
|
3
3
|
syncHint,
|
|
4
4
|
syncRefusalText
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-SMFRAZAA.js";
|
|
6
|
+
import "./chunk-F7PN5R25.js";
|
|
7
|
+
import "./chunk-PGZH33B5.js";
|
|
8
8
|
import "./chunk-JJN6FNJD.js";
|
|
9
9
|
export {
|
|
10
10
|
createHappyDomRenderer,
|