@webcrawl/mcp 1.4.2 → 1.4.4

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.
Files changed (135) hide show
  1. package/README.md +1 -1
  2. package/dist/bin.js +5 -7
  3. package/dist/core/engine/awswaf.d.ts +59 -0
  4. package/dist/core/engine/awswaf.js +164 -0
  5. package/dist/core/engine/cache.d.ts +70 -0
  6. package/dist/core/engine/cache.js +297 -0
  7. package/dist/core/engine/chrome-cdp.d.ts +22 -0
  8. package/dist/core/engine/chrome-cdp.js +318 -0
  9. package/dist/core/engine/chrome-launch.d.ts +38 -0
  10. package/dist/core/engine/chrome-launch.js +214 -0
  11. package/dist/core/engine/chrome.d.ts +28 -0
  12. package/dist/core/engine/chrome.js +208 -0
  13. package/dist/core/engine/crawl-policy.d.ts +36 -0
  14. package/dist/core/engine/crawl-policy.js +134 -0
  15. package/dist/core/engine/crawler.d.ts +152 -0
  16. package/dist/core/engine/crawler.js +918 -0
  17. package/dist/core/engine/fetcher.d.ts +92 -0
  18. package/dist/core/engine/fetcher.js +494 -0
  19. package/dist/core/engine/index.d.ts +7 -0
  20. package/dist/core/engine/index.js +7 -0
  21. package/dist/core/engine/markdown.d.ts +33 -0
  22. package/dist/core/engine/markdown.js +334 -0
  23. package/dist/core/engine/path-scope.d.ts +21 -0
  24. package/dist/core/engine/path-scope.js +88 -0
  25. package/dist/core/engine/render.d.ts +41 -0
  26. package/dist/core/engine/render.js +138 -0
  27. package/dist/core/engine/safe-url.d.ts +29 -0
  28. package/dist/core/engine/safe-url.js +109 -0
  29. package/dist/core/engine/session.d.ts +93 -0
  30. package/dist/core/engine/session.js +250 -0
  31. package/dist/core/engine/stealth.d.ts +83 -0
  32. package/dist/core/engine/stealth.js +222 -0
  33. package/dist/core/engine.d.ts +1 -0
  34. package/dist/core/engine.js +1 -0
  35. package/dist/core/extract/business.d.ts +28 -0
  36. package/dist/core/extract/business.js +344 -0
  37. package/dist/core/extract/currency.d.ts +15 -0
  38. package/dist/core/extract/currency.js +259 -0
  39. package/dist/core/extract/cve-cache.d.ts +62 -0
  40. package/dist/core/extract/cve-cache.js +277 -0
  41. package/dist/core/extract/cve.d.ts +57 -0
  42. package/dist/core/extract/cve.js +397 -0
  43. package/dist/core/extract/dedupe-key.d.ts +12 -0
  44. package/dist/core/extract/dedupe-key.js +36 -0
  45. package/dist/core/extract/flights.d.ts +37 -0
  46. package/dist/core/extract/flights.js +373 -0
  47. package/dist/core/extract/hotels.d.ts +35 -0
  48. package/dist/core/extract/hotels.js +473 -0
  49. package/dist/core/extract/index.d.ts +9 -0
  50. package/dist/core/extract/index.js +9 -0
  51. package/dist/core/extract/real-estate.d.ts +53 -0
  52. package/dist/core/extract/real-estate.js +835 -0
  53. package/dist/core/extract/scaledown.d.ts +14 -0
  54. package/dist/core/extract/scaledown.js +484 -0
  55. package/dist/core/extract/shopping.d.ts +44 -0
  56. package/dist/core/extract/shopping.js +393 -0
  57. package/dist/core/extract/structured.d.ts +33 -0
  58. package/dist/core/extract/structured.js +316 -0
  59. package/dist/core/image-url.d.ts +5 -0
  60. package/dist/core/image-url.js +13 -0
  61. package/dist/core/interact/driver.d.ts +72 -0
  62. package/dist/core/interact/driver.js +384 -0
  63. package/dist/core/interact/remote.d.ts +41 -0
  64. package/dist/core/interact/remote.js +133 -0
  65. package/dist/core/interact/spans.d.ts +46 -0
  66. package/dist/core/interact/spans.js +32 -0
  67. package/dist/core/interact/validate.d.ts +34 -0
  68. package/dist/core/interact/validate.js +135 -0
  69. package/dist/core/interact/vm.d.ts +43 -0
  70. package/dist/core/interact/vm.js +338 -0
  71. package/dist/core/local-engine.d.ts +62 -0
  72. package/dist/core/local-engine.js +726 -0
  73. package/dist/core/parse/detect.d.ts +29 -0
  74. package/dist/core/parse/detect.js +152 -0
  75. package/dist/core/parse/fetch.d.ts +20 -0
  76. package/dist/core/parse/fetch.js +39 -0
  77. package/dist/core/parse/image.d.ts +13 -0
  78. package/dist/core/parse/image.js +100 -0
  79. package/dist/core/parse/index.d.ts +53 -0
  80. package/dist/core/parse/index.js +153 -0
  81. package/dist/core/parse/limits.d.ts +12 -0
  82. package/dist/core/parse/limits.js +29 -0
  83. package/dist/core/parse/media.d.ts +42 -0
  84. package/dist/core/parse/media.js +238 -0
  85. package/dist/core/parse/merge.d.ts +19 -0
  86. package/dist/core/parse/merge.js +48 -0
  87. package/dist/core/parse/ocr.d.ts +25 -0
  88. package/dist/core/parse/ocr.js +121 -0
  89. package/dist/core/parse/office.d.ts +28 -0
  90. package/dist/core/parse/office.js +83 -0
  91. package/dist/core/parse/pdf.d.ts +27 -0
  92. package/dist/core/parse/pdf.js +156 -0
  93. package/dist/core/parse/types.d.ts +38 -0
  94. package/dist/core/parse/types.js +1 -0
  95. package/dist/core/parse/youtube.d.ts +30 -0
  96. package/dist/core/parse/youtube.js +264 -0
  97. package/dist/core/ranker/decision.d.ts +28 -0
  98. package/dist/core/ranker/decision.js +151 -0
  99. package/dist/core/ranker/index.d.ts +5 -0
  100. package/dist/core/ranker/index.js +361 -0
  101. package/dist/core/ranker/lexical.d.ts +82 -0
  102. package/dist/core/ranker/lexical.js +643 -0
  103. package/dist/core/ranker/types.d.ts +90 -0
  104. package/dist/core/ranker/types.js +1 -0
  105. package/dist/core/ranker.d.ts +1 -0
  106. package/dist/core/ranker.js +1 -0
  107. package/dist/core/sandbox.d.ts +29 -0
  108. package/dist/core/sandbox.js +222 -0
  109. package/dist/core/search/catalog.d.ts +176 -0
  110. package/dist/core/search/catalog.js +488 -0
  111. package/dist/core/search/index.d.ts +3 -0
  112. package/dist/core/search/index.js +3 -0
  113. package/dist/core/search/pipeline.d.ts +7 -0
  114. package/dist/core/search/pipeline.js +721 -0
  115. package/dist/core/search/providers.d.ts +84 -0
  116. package/dist/core/search/providers.js +1408 -0
  117. package/dist/core/search.d.ts +1 -0
  118. package/dist/core/search.js +1 -0
  119. package/dist/core/targets/developer.d.ts +44 -0
  120. package/dist/core/targets/developer.js +338 -0
  121. package/dist/core/targets/index.d.ts +3 -0
  122. package/dist/core/targets/index.js +3 -0
  123. package/dist/core/targets/registry.d.ts +32 -0
  124. package/dist/core/targets/registry.js +411 -0
  125. package/dist/core/targets/types.d.ts +72 -0
  126. package/dist/core/targets/types.js +8 -0
  127. package/dist/core/targets.d.ts +1 -0
  128. package/dist/core/targets.js +1 -0
  129. package/dist/format.js +5 -1
  130. package/dist/index.d.ts +1 -0
  131. package/dist/index.js +1 -0
  132. package/dist/load-local-engine.d.ts +7 -0
  133. package/dist/load-local-engine.js +22 -0
  134. package/dist/server.js +6 -0
  135. package/package.json +11 -3
@@ -0,0 +1,316 @@
1
+ /**
2
+ * Prompt/schema-aware structured extraction used by `extractWebsiteData`.
3
+ * Deterministic (no LLM): quote/author cards, embedded JSON, and schema shaping.
4
+ *
5
+ * Nested objects/arrays follow a JSON-schema walk: shorthand
6
+ * `{items:[{quote,author}]}` is coerced to a real object/array schema,
7
+ * root arrays are wrapped as `{items: ...}`, and empty results are detectable.
8
+ */
9
+ import { decodeHtmlEntities } from "../engine/markdown.js";
10
+ const CACHE_META_KEYS = new Set(["cached", "cacheLayer"]);
11
+ function isPlainObject(v) {
12
+ return !!v && typeof v === "object" && !Array.isArray(v);
13
+ }
14
+ /** A bare property map or shorthand array becomes a JSON Schema. */
15
+ export function coerceExtractSchema(node) {
16
+ if (Array.isArray(node)) {
17
+ const item = node.length > 0 ? coerceExtractSchema(node[0]) : { type: "object" };
18
+ return { type: "array", items: item };
19
+ }
20
+ if (typeof node === "string") {
21
+ const t = node.trim() || "string";
22
+ return { type: t };
23
+ }
24
+ if (!isPlainObject(node)) {
25
+ return { type: "string" };
26
+ }
27
+ if (typeof node.type === "string" || Array.isArray(node.type)) {
28
+ const out = { ...node };
29
+ if (isPlainObject(out.properties)) {
30
+ out.properties = Object.fromEntries(Object.entries(out.properties).map(([k, v]) => [k, coerceExtractSchema(v)]));
31
+ }
32
+ if (out.items !== undefined) {
33
+ out.items = coerceExtractSchema(out.items);
34
+ }
35
+ return out;
36
+ }
37
+ const properties = Object.fromEntries(Object.entries(node).map(([k, v]) => [k, coerceExtractSchema(v)]));
38
+ return {
39
+ type: "object",
40
+ properties,
41
+ required: Object.keys(properties),
42
+ additionalProperties: false,
43
+ };
44
+ }
45
+ /**
46
+ * Root-array wrap: a top-level array becomes
47
+ * `{ type: object, properties: { items: <array> } }`.
48
+ */
49
+ export function normalizeExtractSchema(schema) {
50
+ if (!schema || typeof schema !== "object")
51
+ return undefined;
52
+ let coerced = coerceExtractSchema(schema);
53
+ if (coerced.type === "array") {
54
+ coerced = {
55
+ type: "object",
56
+ properties: { items: coerced },
57
+ required: ["items"],
58
+ additionalProperties: false,
59
+ };
60
+ }
61
+ return coerced;
62
+ }
63
+ export function schemaProperties(schema) {
64
+ const normalized = normalizeExtractSchema(schema);
65
+ if (!normalized)
66
+ return {};
67
+ const props = normalized.properties;
68
+ if (isPlainObject(props))
69
+ return props;
70
+ return normalized;
71
+ }
72
+ export function hasCustomExtractRequest(prompt, schema) {
73
+ if (prompt && prompt.trim())
74
+ return true;
75
+ return Object.keys(schemaProperties(schema)).length > 0;
76
+ }
77
+ function blobForIntent(prompt, schema) {
78
+ const keys = [];
79
+ const walk = (node) => {
80
+ if (Array.isArray(node)) {
81
+ for (const n of node)
82
+ walk(n);
83
+ return;
84
+ }
85
+ if (!isPlainObject(node))
86
+ return;
87
+ keys.push(...Object.keys(node));
88
+ if (isPlainObject(node.properties))
89
+ walk(node.properties);
90
+ if (node.items)
91
+ walk(node.items);
92
+ };
93
+ walk(schema);
94
+ walk(schemaProperties(schema));
95
+ return `${prompt ?? ""} ${keys.join(" ")}`.toLowerCase();
96
+ }
97
+ /** Nested object/array field names that look like quote+author records. */
98
+ export function nestedQuoteAuthorFields(schema) {
99
+ const normalized = normalizeExtractSchema(schema);
100
+ if (!normalized)
101
+ return null;
102
+ const visit = (node, path) => {
103
+ if (node.type === "array" && node.items) {
104
+ const items = coerceExtractSchema(node.items);
105
+ const itemProps = isPlainObject(items.properties) ? items.properties : {};
106
+ const itemKeys = Object.keys(itemProps);
107
+ const textKey = itemKeys.find((k) => /quote|text|content|body/i.test(k));
108
+ const authorKey = itemKeys.find((k) => /author|by|name/i.test(k));
109
+ if (textKey && authorKey) {
110
+ return { arrayPath: path, textKey, authorKey };
111
+ }
112
+ if (items.type === "object" && isPlainObject(items.properties)) {
113
+ const nested = visit(items, path);
114
+ if (nested)
115
+ return nested;
116
+ }
117
+ }
118
+ const props = isPlainObject(node.properties) ? node.properties : {};
119
+ for (const [key, value] of Object.entries(props)) {
120
+ if (!isPlainObject(value) && !Array.isArray(value))
121
+ continue;
122
+ const child = coerceExtractSchema(value);
123
+ const found = visit(child, [...path, key]);
124
+ if (found)
125
+ return found;
126
+ }
127
+ return null;
128
+ };
129
+ return visit(normalized, []);
130
+ }
131
+ export function wantsQuoteAuthorExtract(prompt, schema) {
132
+ const blob = blobForIntent(prompt, schema);
133
+ if (/\bquotes?\b/.test(blob) && /\bauthors?\b/.test(blob))
134
+ return true;
135
+ const props = schemaProperties(schema);
136
+ if (props.quotes || props.quote || props.authors)
137
+ return true;
138
+ if (nestedQuoteAuthorFields(schema))
139
+ return true;
140
+ return false;
141
+ }
142
+ /** Strip script/style/template (including unclosed tags) before reading visible DOM. */
143
+ export function stripNonContentHtml(html) {
144
+ return String(html ?? "")
145
+ .replace(/<!--[\s\S]*?-->/g, "")
146
+ .replace(/<(script|style|noscript|svg|canvas|template|iframe)(?:[^>"']|"[^"]*"|'[^']*')*>[\s\S]*?<\/\1>/gi, "")
147
+ .replace(/<(script|style|noscript|svg|canvas|template|iframe)(?:[^>"']|"[^"]*"|'[^']*')*>[\s\S]*/gi, "");
148
+ }
149
+ /** Inline `document.write("... " + d['text'] + ...)` leftovers, not real quotes. */
150
+ export function isJsTemplateJunk(text) {
151
+ const t = String(text ?? "");
152
+ return (/\+\s*d\s*\[/i.test(t) ||
153
+ /['"]\s*\+\s*d/i.test(t) ||
154
+ /\bd\s*\[\s*['"]text['"]\s*\]/.test(t) ||
155
+ /\bd\s*\[\s*['"]author['"]\s*\]/.test(t) ||
156
+ /document\.write/i.test(t));
157
+ }
158
+ export function isEmptyExtractResult(data) {
159
+ if (!data || typeof data !== "object")
160
+ return true;
161
+ const keys = Object.keys(data).filter((k) => !CACHE_META_KEYS.has(k));
162
+ if (keys.length === 0)
163
+ return true;
164
+ return keys.every((k) => {
165
+ const v = data[k];
166
+ if (v == null || v === "")
167
+ return true;
168
+ if (Array.isArray(v))
169
+ return v.length === 0;
170
+ if (typeof v === "object" && !Array.isArray(v)) {
171
+ return isEmptyExtractResult(v);
172
+ }
173
+ return false;
174
+ });
175
+ }
176
+ function cleanText(raw) {
177
+ return decodeHtmlEntities(raw.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim());
178
+ }
179
+ function pushPair(out, text, author) {
180
+ const t = cleanText(text).replace(/^["“]|["”]$/g, "").trim();
181
+ const a = cleanText(author);
182
+ if (t.length < 8 || a.length < 2)
183
+ return;
184
+ if (isJsTemplateJunk(t) || isJsTemplateJunk(a))
185
+ return;
186
+ if (out.some((p) => p.text === t && p.author === a))
187
+ return;
188
+ out.push({ text: t, author: a });
189
+ }
190
+ /** Pull quote/author pairs from HTML (cards, microdata, `var data = [...]`) and markdown. */
191
+ export function extractQuoteAuthorPairs(html, markdown = "") {
192
+ const out = [];
193
+ const source = String(html ?? "");
194
+ const dataAssign = source.match(/var\s+data\s*=\s*(\[[\s\S]*?\]);/);
195
+ if (dataAssign) {
196
+ try {
197
+ const parsed = JSON.parse(dataAssign[1]);
198
+ if (Array.isArray(parsed)) {
199
+ for (const row of parsed) {
200
+ const author = typeof row.author === "string" ? row.author : row.author?.name ?? "";
201
+ if (row.text && author)
202
+ pushPair(out, row.text, author);
203
+ }
204
+ }
205
+ }
206
+ catch {
207
+ /* not JSON */
208
+ }
209
+ }
210
+ const visible = stripNonContentHtml(source);
211
+ const cardRe = /<(?:div|figure|blockquote|li)[^>]*class=["'][^"']*\bquote\b[^"']*["'][^>]*>([\s\S]*?)<\/(?:div|figure|blockquote|li)>/gi;
212
+ let card;
213
+ while ((card = cardRe.exec(visible)) !== null) {
214
+ const block = card[1];
215
+ const text = block.match(/<(?:span|div|p|q)[^>]*class=["'][^"']*\btext\b[^"']*["'][^>]*>([\s\S]*?)<\//i)?.[1] ||
216
+ block.match(/itemprop=["']text["'][^>]*>([\s\S]*?)<\//i)?.[1] ||
217
+ "";
218
+ const author = block.match(/<(?:small|span|div|p)[^>]*class=["'][^"']*\bauthor\b[^"']*["'][^>]*>([\s\S]*?)<\//i)?.[1] ||
219
+ block.match(/itemprop=["']author["'][^>]*>([\s\S]*?)<\//i)?.[1] ||
220
+ "";
221
+ if (text && author)
222
+ pushPair(out, text, author);
223
+ }
224
+ const microRe = /itemprop=["']text["'][^>]*>([\s\S]*?)<\/[^>]+>[\s\S]{0,400}?itemprop=["']author["'][^>]*>([\s\S]*?)<\//gi;
225
+ let micro;
226
+ while ((micro = microRe.exec(visible)) !== null) {
227
+ pushPair(out, micro[1], micro[2]);
228
+ }
229
+ if (out.length === 0 && markdown) {
230
+ const mdRe = /[“"]([^”"]{12,400})[”"]\s*(?:\n+)?\s*(?:by\s+|\u2014\s*|\s+[-–—]\s+)([A-Z][^\n]{1,80})/g;
231
+ let md;
232
+ while ((md = mdRe.exec(markdown)) !== null) {
233
+ pushPair(out, md[1], md[2]);
234
+ }
235
+ }
236
+ return out;
237
+ }
238
+ function itemFieldNames(schema) {
239
+ const nested = nestedQuoteAuthorFields(schema);
240
+ if (nested && nested.arrayPath.length > 0) {
241
+ return {
242
+ arrayKey: nested.arrayPath[nested.arrayPath.length - 1] || "items",
243
+ textKey: nested.textKey,
244
+ authorKey: nested.authorKey,
245
+ };
246
+ }
247
+ const props = schemaProperties(schema);
248
+ const keys = Object.keys(props);
249
+ const arrayKey = keys.find((k) => {
250
+ const p = props[k];
251
+ if (!p || typeof p !== "object")
252
+ return /quotes?|items|results|entries/i.test(k);
253
+ const t = p.type;
254
+ return t === "array" || /quotes?|items|results|entries/i.test(k);
255
+ }) || (keys.length === 0 ? "quotes" : undefined);
256
+ const itemSchema = arrayKey && props[arrayKey] && typeof props[arrayKey] === "object"
257
+ ? props[arrayKey]
258
+ : undefined;
259
+ const itemProps = itemSchema?.items?.properties ?? {};
260
+ const itemKeys = Object.keys(itemProps);
261
+ const textKey = itemKeys.find((k) => /quote|text|content|body/i.test(k)) ?? "quote";
262
+ const authorKey = itemKeys.find((k) => /author|by|name/i.test(k)) ?? "author";
263
+ return { arrayKey: arrayKey ?? "quotes", textKey, authorKey };
264
+ }
265
+ function assignAtPath(root, path, value) {
266
+ if (path.length === 0) {
267
+ return isPlainObject(value) ? { ...root, ...value } : root;
268
+ }
269
+ let cursor = root;
270
+ for (let i = 0; i < path.length - 1; i++) {
271
+ const key = path[i];
272
+ const next = cursor[key];
273
+ if (!isPlainObject(next)) {
274
+ cursor[key] = {};
275
+ }
276
+ cursor = cursor[key];
277
+ }
278
+ cursor[path[path.length - 1]] = value;
279
+ return root;
280
+ }
281
+ export function shapeQuoteAuthors(pairs, schema) {
282
+ const props = schemaProperties(schema);
283
+ const keys = Object.keys(props);
284
+ const quoteArr = keys.find((k) => /quotes?/i.test(k) && props[k]?.type === "array");
285
+ const authorArr = keys.find((k) => /authors?/i.test(k) && props[k]?.type === "array");
286
+ const quoteArrItems = quoteArr && props[quoteArr]?.items?.type;
287
+ if (quoteArr && authorArr && quoteArrItems === "string") {
288
+ return {
289
+ [quoteArr]: pairs.map((p) => p.text),
290
+ [authorArr]: pairs.map((p) => p.author),
291
+ };
292
+ }
293
+ const nested = nestedQuoteAuthorFields(schema);
294
+ const { arrayKey, textKey, authorKey } = itemFieldNames(schema);
295
+ const rows = pairs.map((p) => ({ [textKey]: p.text, [authorKey]: p.author }));
296
+ if (nested && nested.arrayPath.length > 0) {
297
+ return assignAtPath({}, nested.arrayPath, rows);
298
+ }
299
+ return { [arrayKey]: rows };
300
+ }
301
+ /**
302
+ * Deterministic extract when the caller passed a prompt and/or JSON schema.
303
+ * Returns null when this page/request has nothing this extractor can fill.
304
+ */
305
+ export function extractByPromptAndSchema(html, markdown, prompt, schema) {
306
+ if (!hasCustomExtractRequest(prompt, schema))
307
+ return null;
308
+ const pairs = extractQuoteAuthorPairs(html, markdown);
309
+ if (wantsQuoteAuthorExtract(prompt, schema) && pairs.length > 0) {
310
+ return shapeQuoteAuthors(pairs, schema);
311
+ }
312
+ if (pairs.length > 0 && /\b(quotes?|items|results|entries)\b/i.test(blobForIntent(prompt, schema))) {
313
+ return shapeQuoteAuthors(pairs, schema);
314
+ }
315
+ return null;
316
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Client-safe helper (no Node imports): turn an external image URL into our
3
+ * same-origin `/img` proxy URL. See `image-proxy.ts` for the server side.
4
+ */
5
+ export declare function proxiedImage(src: string | undefined): string | undefined;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Client-safe helper (no Node imports): turn an external image URL into our
3
+ * same-origin `/img` proxy URL. See `image-proxy.ts` for the server side.
4
+ */
5
+ export function proxiedImage(src) {
6
+ if (!src) {
7
+ return undefined;
8
+ }
9
+ if (src.startsWith("/") && !src.startsWith("//")) {
10
+ return src; // already local
11
+ }
12
+ return `/img?url=${encodeURIComponent(src)}`;
13
+ }
@@ -0,0 +1,72 @@
1
+ import { CDP_PORT, type StepResultLine } from "./vm.js";
2
+ import { type RemoteProvider, type RemoteSessionCost } from "./remote.js";
3
+ /** Where STEP_SCRIPT runs when the browser itself is hosted by a remote provider. */
4
+ export type StepRunner = {
5
+ kind: "sandbox";
6
+ sandboxId: string;
7
+ } | {
8
+ kind: "local";
9
+ scriptPath: string;
10
+ playwright: string;
11
+ };
12
+ export type BrowserHandle = {
13
+ kind: "sandbox";
14
+ sandboxId: string;
15
+ } | {
16
+ kind: "local";
17
+ cdp: string;
18
+ pid: number;
19
+ scriptPath: string;
20
+ playwright: string;
21
+ } | {
22
+ kind: "remote";
23
+ provider: RemoteProvider;
24
+ sessionId: string;
25
+ cdpUrl: string;
26
+ /** Headers the CDP websocket needs (e.g. Cloudflare bearer auth). */
27
+ cdpHeaders?: Record<string, string>;
28
+ startedAt: number;
29
+ runner: StepRunner;
30
+ };
31
+ export type StepAction = Record<string, unknown> & {
32
+ type: string;
33
+ };
34
+ /**
35
+ * True when some browser backend can run. Checked before starting a run so we never fake success.
36
+ * On Vercel (VERCEL=1) the OIDC token is not in env at request time: it arrives in the
37
+ * `x-vercel-oidc-token` request header, which @vercel/sandbox reads via @vercel/oidc.
38
+ */
39
+ export declare function interactBrowserAvailable(): boolean;
40
+ export declare function interactBackend(): "local" | "sandbox" | "none";
41
+ /**
42
+ * Path to a real, user-installed Chrome when one exists, else null.
43
+ * Anti-bot vendors (DataDome, Akamai) fingerprint the automation build of
44
+ * Chromium and serve degraded pages to it, while the same engine driving a
45
+ * real installed Chrome gets full content — practitioner reports confirm
46
+ * this on DataDome-protected sites. Priority: explicit env override, then
47
+ * the standard per-OS install locations.
48
+ */
49
+ export declare function installedChromePath(): string | null;
50
+ export declare function startBrowser(opts?: {
51
+ timeoutMs?: number;
52
+ userAgent?: string;
53
+ remote?: RemoteProvider | null;
54
+ domain?: string;
55
+ proxy?: string;
56
+ }): Promise<BrowserHandle>;
57
+ export declare function runBrowserStep(handle: BrowserHandle, action: StepAction): Promise<StepResultLine>;
58
+ /**
59
+ * Stops the browser. For a remote provider, returns what the session cost (null
60
+ * when unknown). With `keepWarm`, a sandbox browser is left running and
61
+ * registered (domain + sandboxId + UA) so the next call reconnects to it via
62
+ * `Sandbox.get` instead of cold-booting — the caller must pass `domain`.
63
+ * Evicted warm entries (over the cap) are stopped here so idle compute
64
+ * does not linger.
65
+ */
66
+ export declare function stopBrowser(handle: BrowserHandle, opts?: {
67
+ keepWarm?: boolean;
68
+ domain?: string;
69
+ userAgent?: string;
70
+ cookieHeader?: string;
71
+ }): Promise<RemoteSessionCost | null>;
72
+ export { CDP_PORT };