webpeel 0.14.2 → 0.14.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.
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +11 -4
- package/dist/cache.js.map +1 -1
- package/dist/cli.bundle.cjs +159248 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/agent.js +12 -8
- package/dist/core/agent.js.map +1 -1
- package/dist/core/application-tracker.js +3 -2
- package/dist/core/application-tracker.js.map +1 -1
- package/dist/core/auto-extract.js +6 -4
- package/dist/core/auto-extract.js.map +1 -1
- package/dist/core/browser-fetch.d.ts +90 -0
- package/dist/core/browser-fetch.d.ts.map +1 -0
- package/dist/core/browser-fetch.js +599 -0
- package/dist/core/browser-fetch.js.map +1 -0
- package/dist/core/browser-pool.d.ts +70 -0
- package/dist/core/browser-pool.d.ts.map +1 -0
- package/dist/core/browser-pool.js +378 -0
- package/dist/core/browser-pool.js.map +1 -0
- package/dist/core/change-tracking.js +3 -2
- package/dist/core/change-tracking.js.map +1 -1
- package/dist/core/diff.js +3 -2
- package/dist/core/diff.js.map +1 -1
- package/dist/core/domain-extractors.js +3 -2
- package/dist/core/domain-extractors.js.map +1 -1
- package/dist/core/extract-inline.js +6 -4
- package/dist/core/extract-inline.js.map +1 -1
- package/dist/core/fetcher.d.ts +9 -116
- package/dist/core/fetcher.d.ts.map +1 -1
- package/dist/core/fetcher.js +10 -1484
- package/dist/core/fetcher.js.map +1 -1
- package/dist/core/http-fetch.d.ts +37 -0
- package/dist/core/http-fetch.d.ts.map +1 -0
- package/dist/core/http-fetch.js +618 -0
- package/dist/core/http-fetch.js.map +1 -0
- package/dist/core/metadata.js +18 -12
- package/dist/core/metadata.js.map +1 -1
- package/dist/core/pipeline.d.ts +104 -0
- package/dist/core/pipeline.d.ts.map +1 -0
- package/dist/core/pipeline.js +623 -0
- package/dist/core/pipeline.js.map +1 -0
- package/dist/core/profiles.js +15 -10
- package/dist/core/profiles.js.map +1 -1
- package/dist/core/quick-answer.d.ts.map +1 -1
- package/dist/core/quick-answer.js +120 -9
- package/dist/core/quick-answer.js.map +1 -1
- package/dist/core/rate-governor.js +3 -2
- package/dist/core/rate-governor.js.map +1 -1
- package/dist/core/readability.d.ts.map +1 -1
- package/dist/core/readability.js +19 -6
- package/dist/core/readability.js.map +1 -1
- package/dist/core/research.js +9 -6
- package/dist/core/research.js.map +1 -1
- package/dist/core/search-provider.js +12 -8
- package/dist/core/search-provider.js.map +1 -1
- package/dist/core/strategies.d.ts.map +1 -1
- package/dist/core/strategies.js +14 -5
- package/dist/core/strategies.js.map +1 -1
- package/dist/core/timing.d.ts +22 -0
- package/dist/core/timing.d.ts.map +1 -0
- package/dist/core/timing.js +34 -0
- package/dist/core/timing.js.map +1 -0
- package/dist/core/youtube.d.ts.map +1 -1
- package/dist/core/youtube.js +19 -6
- package/dist/core/youtube.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -444
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/server/middleware/auth.js +3 -2
- package/dist/server/middleware/auth.js.map +1 -1
- package/dist/server/routes/answer.d.ts.map +1 -1
- package/dist/server/routes/answer.js +5 -0
- package/dist/server/routes/answer.js.map +1 -1
- package/dist/server/routes/compat.js +3 -2
- package/dist/server/routes/compat.js.map +1 -1
- package/dist/server/routes/deep-fetch.d.ts.map +1 -1
- package/dist/server/routes/deep-fetch.js +5 -0
- package/dist/server/routes/deep-fetch.js.map +1 -1
- package/dist/server/routes/fetch.d.ts.map +1 -1
- package/dist/server/routes/fetch.js +44 -4
- package/dist/server/routes/fetch.js.map +1 -1
- package/dist/server/routes/health.js +3 -2
- package/dist/server/routes/health.js.map +1 -1
- package/dist/server/routes/mcp.js +1 -1
- package/dist/server/routes/mcp.js.map +1 -1
- package/dist/server/routes/quick-answer.d.ts.map +1 -1
- package/dist/server/routes/quick-answer.js +5 -0
- package/dist/server/routes/quick-answer.js.map +1 -1
- package/dist/server/routes/search.js +6 -4
- package/dist/server/routes/search.js.map +1 -1
- package/dist/server/routes/users.js +3 -2
- package/dist/server/routes/users.js.map +1 -1
- package/dist/server/routes/webhooks.d.ts +1 -0
- package/dist/server/routes/webhooks.d.ts.map +1 -1
- package/dist/server/routes/webhooks.js +1 -0
- package/dist/server/routes/webhooks.js.map +1 -1
- package/dist/server/routes/youtube.d.ts.map +1 -1
- package/dist/server/routes/youtube.js +5 -0
- package/dist/server/routes/youtube.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-based fetching — uses Playwright via the browser pool.
|
|
3
|
+
* Handles browserFetch, browserScreenshot, retryFetch, and scrollAndWait.
|
|
4
|
+
*/
|
|
5
|
+
import { TimeoutError, BlockedError, NetworkError, WebPeelError } from '../types.js';
|
|
6
|
+
import { detectChallenge } from './challenge-detection.js';
|
|
7
|
+
import { getRealisticUserAgent } from './user-agents.js';
|
|
8
|
+
import { getRandomUserAgent, getRandomViewport, applyStealthScripts, takePooledPage, ensurePagePool, recyclePooledPage, getBrowser, getStealthBrowser, getProfileBrowser, PAGE_POOL_SIZE, MAX_CONCURRENT_PAGES, getPooledPagesCount, } from './browser-pool.js';
|
|
9
|
+
import { validateUrl, validateUserAgent, createAbortError } from './http-fetch.js';
|
|
10
|
+
// ── Concurrency state (owned by this module) ─────────────────────────────────
|
|
11
|
+
let activePagesCount = 0;
|
|
12
|
+
// ── browserFetch ──────────────────────────────────────────────────────────────
|
|
13
|
+
/**
|
|
14
|
+
* Fetch using headless Chromium via Playwright
|
|
15
|
+
* Slower but can handle JavaScript-heavy sites and bypass some bot detection
|
|
16
|
+
*/
|
|
17
|
+
export async function browserFetch(url, options = {}) {
|
|
18
|
+
// SECURITY: Validate URL to prevent SSRF
|
|
19
|
+
validateUrl(url);
|
|
20
|
+
const { userAgent, waitMs = 0, timeoutMs = 30000, screenshot = false, screenshotFullPage = false, headers, cookies, stealth = false, actions, keepPageOpen = false, signal, profileDir, headed = false, storageState, proxy, } = options;
|
|
21
|
+
// Validate user agent if provided
|
|
22
|
+
// In stealth mode with no custom UA, always use a realistic Chrome UA
|
|
23
|
+
const validatedUserAgent = userAgent
|
|
24
|
+
? validateUserAgent(userAgent)
|
|
25
|
+
: (stealth ? getRealisticUserAgent() : getRandomUserAgent());
|
|
26
|
+
// Validate wait time
|
|
27
|
+
if (waitMs < 0 || waitMs > 60000) {
|
|
28
|
+
throw new WebPeelError('Wait time must be between 0 and 60000ms');
|
|
29
|
+
}
|
|
30
|
+
if (signal?.aborted) {
|
|
31
|
+
throw createAbortError();
|
|
32
|
+
}
|
|
33
|
+
// SECURITY: Validate custom headers if provided
|
|
34
|
+
if (headers) {
|
|
35
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
36
|
+
// Block Host header override
|
|
37
|
+
if (key.toLowerCase() === 'host') {
|
|
38
|
+
throw new WebPeelError('Custom Host header is not allowed');
|
|
39
|
+
}
|
|
40
|
+
if (typeof value !== 'string' || value.length > 500) {
|
|
41
|
+
throw new WebPeelError('Invalid header value');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// SECURITY: Limit concurrent browser pages with timeout
|
|
46
|
+
const queueStartTime = Date.now();
|
|
47
|
+
const QUEUE_TIMEOUT_MS = 30000; // 30 second max wait
|
|
48
|
+
while (activePagesCount >= MAX_CONCURRENT_PAGES) {
|
|
49
|
+
if (Date.now() - queueStartTime > QUEUE_TIMEOUT_MS) {
|
|
50
|
+
throw new TimeoutError('Browser page queue timeout - too many concurrent requests');
|
|
51
|
+
}
|
|
52
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
53
|
+
}
|
|
54
|
+
activePagesCount++;
|
|
55
|
+
let page = null;
|
|
56
|
+
let usingPooledPage = false;
|
|
57
|
+
let abortHandler;
|
|
58
|
+
// Declared here (outside try) so the finally block can reference it
|
|
59
|
+
const usingProfileBrowser = !!profileDir;
|
|
60
|
+
// Owned context created when storageState injection is requested
|
|
61
|
+
let ownedContext;
|
|
62
|
+
try {
|
|
63
|
+
const browser = usingProfileBrowser
|
|
64
|
+
? await getProfileBrowser(profileDir, headed, stealth)
|
|
65
|
+
: stealth
|
|
66
|
+
? await getStealthBrowser()
|
|
67
|
+
: await getBrowser();
|
|
68
|
+
// Only use the shared page pool for non-stealth, non-profile, non-keepOpen, non-storageState, non-proxy fetches
|
|
69
|
+
const shouldUsePagePool = !stealth && !userAgent && !keepPageOpen && !usingProfileBrowser && !storageState && !proxy;
|
|
70
|
+
if (shouldUsePagePool) {
|
|
71
|
+
page = takePooledPage();
|
|
72
|
+
usingPooledPage = !!page;
|
|
73
|
+
if (usingPooledPage && getPooledPagesCount() < PAGE_POOL_SIZE) {
|
|
74
|
+
void ensurePagePool(browser).catch(() => { });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!page) {
|
|
78
|
+
const fetchVp = getRandomViewport();
|
|
79
|
+
const pageOptions = {
|
|
80
|
+
userAgent: validatedUserAgent,
|
|
81
|
+
// viewport: null lets the browser use its natural window size (set via --window-size),
|
|
82
|
+
// avoiding the telltale Playwright default of 1280×720.
|
|
83
|
+
viewport: null,
|
|
84
|
+
...(stealth
|
|
85
|
+
? {
|
|
86
|
+
locale: 'en-US',
|
|
87
|
+
timezoneId: 'America/New_York',
|
|
88
|
+
javaScriptEnabled: true,
|
|
89
|
+
}
|
|
90
|
+
: {}),
|
|
91
|
+
};
|
|
92
|
+
if (proxy) {
|
|
93
|
+
// Parse proxy URL to extract auth credentials for Playwright
|
|
94
|
+
let playwrightProxy;
|
|
95
|
+
try {
|
|
96
|
+
const proxyUrl = new URL(proxy);
|
|
97
|
+
playwrightProxy = {
|
|
98
|
+
server: `${proxyUrl.protocol}//${proxyUrl.host}`,
|
|
99
|
+
username: proxyUrl.username || undefined,
|
|
100
|
+
password: proxyUrl.password || undefined,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
// Fallback: use proxy string as-is
|
|
105
|
+
if (process.env.DEBUG)
|
|
106
|
+
console.debug('[webpeel]', 'proxy URL parse failed, using as-is:', e instanceof Error ? e.message : e);
|
|
107
|
+
playwrightProxy = { server: proxy };
|
|
108
|
+
}
|
|
109
|
+
// Create an isolated context with the proxy and optional storageState
|
|
110
|
+
ownedContext = await browser.newContext({
|
|
111
|
+
...pageOptions,
|
|
112
|
+
proxy: playwrightProxy,
|
|
113
|
+
viewport: { width: fetchVp.width, height: fetchVp.height },
|
|
114
|
+
...(storageState ? { storageState } : {}),
|
|
115
|
+
});
|
|
116
|
+
page = await ownedContext.newPage();
|
|
117
|
+
}
|
|
118
|
+
else if (storageState) {
|
|
119
|
+
// Create an isolated context with the injected storage state (cookies + localStorage)
|
|
120
|
+
ownedContext = await browser.newContext({
|
|
121
|
+
...pageOptions,
|
|
122
|
+
storageState,
|
|
123
|
+
viewport: { width: fetchVp.width, height: fetchVp.height },
|
|
124
|
+
});
|
|
125
|
+
page = await ownedContext.newPage();
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
page = await browser.newPage(pageOptions);
|
|
129
|
+
}
|
|
130
|
+
await applyStealthScripts(page);
|
|
131
|
+
usingPooledPage = false;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
await page.setViewportSize({ width: 1280, height: 720 }).catch(() => { });
|
|
135
|
+
}
|
|
136
|
+
if (signal) {
|
|
137
|
+
abortHandler = () => {
|
|
138
|
+
if (page && !page.isClosed()) {
|
|
139
|
+
void page.close().catch(() => { });
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
signal.addEventListener('abort', abortHandler, { once: true });
|
|
143
|
+
}
|
|
144
|
+
await page.unroute('**/*').catch(() => { });
|
|
145
|
+
const mergedHeaders = { ...(headers || {}) };
|
|
146
|
+
if (usingPooledPage) {
|
|
147
|
+
mergedHeaders['User-Agent'] = validatedUserAgent;
|
|
148
|
+
}
|
|
149
|
+
if (usingPooledPage || Object.keys(mergedHeaders).length > 0) {
|
|
150
|
+
await page.setExtraHTTPHeaders(mergedHeaders);
|
|
151
|
+
}
|
|
152
|
+
// Set cookies if provided
|
|
153
|
+
if (cookies && cookies.length > 0) {
|
|
154
|
+
const parsedCookies = cookies.map(cookie => {
|
|
155
|
+
const [nameValue] = cookie.split(';').map(s => s.trim());
|
|
156
|
+
const [name, value] = nameValue.split('=');
|
|
157
|
+
if (!name || value === undefined) {
|
|
158
|
+
throw new WebPeelError(`Invalid cookie format: ${cookie}`);
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
name: name.trim(),
|
|
162
|
+
value: value.trim(),
|
|
163
|
+
url,
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
await page.context().addCookies(parsedCookies);
|
|
167
|
+
}
|
|
168
|
+
if (signal?.aborted) {
|
|
169
|
+
throw createAbortError();
|
|
170
|
+
}
|
|
171
|
+
// Block images/fonts/etc for speed in non-stealth mode.
|
|
172
|
+
// In stealth mode, blocking common resources can be a bot-detection signal.
|
|
173
|
+
if (!screenshot && !stealth) {
|
|
174
|
+
await page.route('**/*', (route) => {
|
|
175
|
+
const resourceType = route.request().resourceType();
|
|
176
|
+
if (['image', 'font', 'media', 'stylesheet'].includes(resourceType)) {
|
|
177
|
+
route.abort();
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
route.continue();
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
// For screenshots and stealth mode, allow all resources
|
|
186
|
+
await page.route('**/*', (route) => route.continue());
|
|
187
|
+
}
|
|
188
|
+
// SECURITY: Wrap entire operation in timeout
|
|
189
|
+
let screenshotBuffer;
|
|
190
|
+
const throwIfAborted = () => {
|
|
191
|
+
if (signal?.aborted) {
|
|
192
|
+
throw createAbortError();
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
const fetchPromise = (async () => {
|
|
196
|
+
const response = await page.goto(url, {
|
|
197
|
+
waitUntil: 'domcontentloaded',
|
|
198
|
+
timeout: timeoutMs,
|
|
199
|
+
});
|
|
200
|
+
throwIfAborted();
|
|
201
|
+
// Quick check: if body text is very thin, wait for JS to render more content.
|
|
202
|
+
// Only adds latency when the page clearly hasn't loaded yet.
|
|
203
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
204
|
+
const bodyTextLength = await page.evaluate('document.body?.innerText?.trim().length || 0').catch(() => 0);
|
|
205
|
+
if (bodyTextLength < 500) {
|
|
206
|
+
await page.waitForLoadState('networkidle', { timeout: 1500 }).catch(() => { });
|
|
207
|
+
throwIfAborted();
|
|
208
|
+
}
|
|
209
|
+
// DOM stability check: wait for SPA hydration to settle.
|
|
210
|
+
// Polls innerText length every 500ms — if still growing, keep waiting (max 3s extra).
|
|
211
|
+
{
|
|
212
|
+
const stabilityStart = Date.now();
|
|
213
|
+
const MAX_STABILITY_WAIT_MS = 3000;
|
|
214
|
+
const POLL_INTERVAL_MS = 500;
|
|
215
|
+
let prevLength = await page.evaluate('document.body?.innerText?.length || 0').catch(() => 0);
|
|
216
|
+
let stableCount = 0;
|
|
217
|
+
while (Date.now() - stabilityStart < MAX_STABILITY_WAIT_MS) {
|
|
218
|
+
throwIfAborted();
|
|
219
|
+
await page.waitForTimeout(POLL_INTERVAL_MS);
|
|
220
|
+
const curLength = await page.evaluate('document.body?.innerText?.length || 0').catch(() => 0);
|
|
221
|
+
if (curLength === prevLength) {
|
|
222
|
+
stableCount++;
|
|
223
|
+
if (stableCount >= 2)
|
|
224
|
+
break; // stable for 2 consecutive checks (~1s)
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
stableCount = 0;
|
|
228
|
+
}
|
|
229
|
+
prevLength = curLength;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const finalUrl = page.url();
|
|
233
|
+
const contentType = response?.headers()?.['content-type'] || '';
|
|
234
|
+
const contentTypeLower = contentType.toLowerCase();
|
|
235
|
+
const urlLower = finalUrl.toLowerCase();
|
|
236
|
+
const isPdf = contentTypeLower.includes('application/pdf') || urlLower.endsWith('.pdf');
|
|
237
|
+
const isDocx = contentTypeLower.includes('wordprocessingml.document') || urlLower.endsWith('.docx');
|
|
238
|
+
const isBinaryDoc = !!response && (isPdf || isDocx);
|
|
239
|
+
// Small randomized delay in stealth mode (simulate human behavior)
|
|
240
|
+
// Keep it short — enough to look human, not enough to kill latency
|
|
241
|
+
if (stealth) {
|
|
242
|
+
const extraDelayMs = 200 + Math.floor(Math.random() * 601);
|
|
243
|
+
await page.waitForTimeout(extraDelayMs);
|
|
244
|
+
throwIfAborted();
|
|
245
|
+
}
|
|
246
|
+
// Wait for additional time if requested (for dynamic content / screenshots)
|
|
247
|
+
if (waitMs > 0) {
|
|
248
|
+
await page.waitForTimeout(waitMs);
|
|
249
|
+
throwIfAborted();
|
|
250
|
+
}
|
|
251
|
+
// Execute page actions if provided
|
|
252
|
+
if (actions && actions.length > 0) {
|
|
253
|
+
const { executeActions } = await import('./actions.js');
|
|
254
|
+
const actionScreenshot = await executeActions(page, actions);
|
|
255
|
+
if (actionScreenshot) {
|
|
256
|
+
screenshotBuffer = actionScreenshot;
|
|
257
|
+
}
|
|
258
|
+
throwIfAborted();
|
|
259
|
+
}
|
|
260
|
+
// If the navigation returned a binary document (PDF/DOCX), grab the raw body.
|
|
261
|
+
if (isBinaryDoc) {
|
|
262
|
+
const buffer = await response.body();
|
|
263
|
+
throwIfAborted();
|
|
264
|
+
// Capture screenshot if requested (and not already captured by actions)
|
|
265
|
+
if (screenshot && !screenshotBuffer) {
|
|
266
|
+
screenshotBuffer = await page.screenshot({
|
|
267
|
+
fullPage: screenshotFullPage,
|
|
268
|
+
type: 'png',
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
html: '',
|
|
273
|
+
finalUrl,
|
|
274
|
+
buffer,
|
|
275
|
+
contentType,
|
|
276
|
+
statusCode: response.status(),
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
const html = await page.content();
|
|
280
|
+
throwIfAborted();
|
|
281
|
+
return {
|
|
282
|
+
html,
|
|
283
|
+
finalUrl,
|
|
284
|
+
contentType,
|
|
285
|
+
statusCode: response?.status(),
|
|
286
|
+
};
|
|
287
|
+
})();
|
|
288
|
+
let operationTimeout;
|
|
289
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
290
|
+
operationTimeout = setTimeout(() => reject(new TimeoutError(`Operation timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
291
|
+
});
|
|
292
|
+
const fetchData = await Promise.race([fetchPromise, timeoutPromise]);
|
|
293
|
+
if (operationTimeout) {
|
|
294
|
+
clearTimeout(operationTimeout);
|
|
295
|
+
}
|
|
296
|
+
const { html, finalUrl } = fetchData;
|
|
297
|
+
const fetchBuffer = 'buffer' in fetchData ? fetchData.buffer : undefined;
|
|
298
|
+
const fetchContentType = 'contentType' in fetchData ? fetchData.contentType : undefined;
|
|
299
|
+
const fetchStatusCode = 'statusCode' in fetchData ? fetchData.statusCode : undefined;
|
|
300
|
+
const isBinaryDoc = !!fetchBuffer;
|
|
301
|
+
// SECURITY: Limit HTML size (skip for binary documents where html is empty)
|
|
302
|
+
if (!isBinaryDoc) {
|
|
303
|
+
if (html.length > 10 * 1024 * 1024) { // 10MB limit
|
|
304
|
+
throw new WebPeelError('Response too large (max 10MB)');
|
|
305
|
+
}
|
|
306
|
+
if (!html || html.length < 100) {
|
|
307
|
+
throw new BlockedError('Empty or suspiciously small response from browser.');
|
|
308
|
+
}
|
|
309
|
+
// Run challenge detection on browser-fetched HTML (covers both regular and stealth modes)
|
|
310
|
+
// Note: skip empty-shell type — that's a rendering quality issue (SPA needs more JS time),
|
|
311
|
+
// not a bot challenge. The caller's escalation logic handles empty-shell separately.
|
|
312
|
+
const browserChallengeResult = detectChallenge(html, fetchStatusCode);
|
|
313
|
+
if (browserChallengeResult.isChallenge && browserChallengeResult.type !== 'empty-shell') {
|
|
314
|
+
throw new BlockedError(`Challenge page detected (${browserChallengeResult.type || 'unknown'}, confidence: ${browserChallengeResult.confidence.toFixed(2)}). ` +
|
|
315
|
+
`Site requires human verification. Try a different approach or use a CAPTCHA solving service.`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
// Capture screenshot if requested (and not already captured by actions or document handler)
|
|
319
|
+
if (screenshot && !screenshotBuffer) {
|
|
320
|
+
screenshotBuffer = await page.screenshot({
|
|
321
|
+
fullPage: screenshotFullPage,
|
|
322
|
+
type: 'png'
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
// If keepPageOpen, return page/browser for caller to use (e.g., branding extraction)
|
|
326
|
+
if (keepPageOpen && page) {
|
|
327
|
+
return {
|
|
328
|
+
html,
|
|
329
|
+
buffer: fetchBuffer,
|
|
330
|
+
url: finalUrl,
|
|
331
|
+
statusCode: fetchStatusCode,
|
|
332
|
+
contentType: fetchContentType,
|
|
333
|
+
screenshot: screenshotBuffer,
|
|
334
|
+
page,
|
|
335
|
+
browser,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
html,
|
|
340
|
+
buffer: fetchBuffer,
|
|
341
|
+
url: finalUrl,
|
|
342
|
+
statusCode: fetchStatusCode,
|
|
343
|
+
contentType: fetchContentType,
|
|
344
|
+
screenshot: screenshotBuffer,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
if (error instanceof BlockedError || error instanceof WebPeelError || error instanceof TimeoutError) {
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
352
|
+
throw error;
|
|
353
|
+
}
|
|
354
|
+
if (error instanceof Error && error.message.includes('Timeout')) {
|
|
355
|
+
throw new TimeoutError(`Browser navigation timed out`);
|
|
356
|
+
}
|
|
357
|
+
throw new NetworkError(`Browser fetch failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
358
|
+
}
|
|
359
|
+
finally {
|
|
360
|
+
if (signal && abortHandler) {
|
|
361
|
+
signal.removeEventListener('abort', abortHandler);
|
|
362
|
+
}
|
|
363
|
+
// CRITICAL: Always release/close page and decrement counter (unless keepPageOpen and no error)
|
|
364
|
+
if (page && !keepPageOpen) {
|
|
365
|
+
if (usingPooledPage) {
|
|
366
|
+
await recyclePooledPage(page);
|
|
367
|
+
}
|
|
368
|
+
else if (ownedContext) {
|
|
369
|
+
// Close the owned context (also closes the page)
|
|
370
|
+
await ownedContext.close().catch(() => { });
|
|
371
|
+
}
|
|
372
|
+
else if (!usingProfileBrowser) {
|
|
373
|
+
// Profile browser pages are NOT closed — the profile browser stays alive
|
|
374
|
+
// so that the next fetch in the same process reuses the session.
|
|
375
|
+
await page.close().catch(() => { });
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
activePagesCount--;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
// ── browserScreenshot ─────────────────────────────────────────────────────────
|
|
382
|
+
/**
|
|
383
|
+
* Capture a screenshot of a URL using headless Chromium via Playwright.
|
|
384
|
+
*/
|
|
385
|
+
export async function browserScreenshot(url, options = {}) {
|
|
386
|
+
// SECURITY: Validate URL to prevent SSRF
|
|
387
|
+
validateUrl(url);
|
|
388
|
+
const { fullPage = false, width, height, format = 'png', quality, waitMs = 0, timeoutMs = 30000, userAgent, headers, cookies, stealth = false, actions, } = options;
|
|
389
|
+
const validatedUserAgent = userAgent ? validateUserAgent(userAgent) : getRandomUserAgent();
|
|
390
|
+
// Basic validation
|
|
391
|
+
if (waitMs < 0 || waitMs > 60000) {
|
|
392
|
+
throw new WebPeelError('Wait time must be between 0 and 60000ms');
|
|
393
|
+
}
|
|
394
|
+
if (timeoutMs < 1000 || timeoutMs > 120000) {
|
|
395
|
+
throw new WebPeelError('Timeout must be between 1000 and 120000ms');
|
|
396
|
+
}
|
|
397
|
+
if (width !== undefined && (!Number.isFinite(width) || width < 100 || width > 5000)) {
|
|
398
|
+
throw new WebPeelError('Width must be between 100 and 5000');
|
|
399
|
+
}
|
|
400
|
+
if (height !== undefined && (!Number.isFinite(height) || height < 100 || height > 5000)) {
|
|
401
|
+
throw new WebPeelError('Height must be between 100 and 5000');
|
|
402
|
+
}
|
|
403
|
+
if (format !== 'png' && format !== 'jpeg') {
|
|
404
|
+
throw new WebPeelError('Format must be png or jpeg');
|
|
405
|
+
}
|
|
406
|
+
if (format === 'jpeg' && quality !== undefined) {
|
|
407
|
+
if (!Number.isFinite(quality) || quality < 1 || quality > 100) {
|
|
408
|
+
throw new WebPeelError('JPEG quality must be between 1 and 100');
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
// SECURITY: Validate custom headers if provided
|
|
412
|
+
if (headers) {
|
|
413
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
414
|
+
if (key.toLowerCase() === 'host') {
|
|
415
|
+
throw new WebPeelError('Custom Host header is not allowed');
|
|
416
|
+
}
|
|
417
|
+
if (typeof value !== 'string' || value.length > 500) {
|
|
418
|
+
throw new WebPeelError('Invalid header value');
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
// SECURITY: Limit concurrent browser pages with timeout
|
|
423
|
+
const queueStartTime = Date.now();
|
|
424
|
+
const QUEUE_TIMEOUT_MS = 30000;
|
|
425
|
+
while (activePagesCount >= MAX_CONCURRENT_PAGES) {
|
|
426
|
+
if (Date.now() - queueStartTime > QUEUE_TIMEOUT_MS) {
|
|
427
|
+
throw new TimeoutError('Browser page queue timeout - too many concurrent requests');
|
|
428
|
+
}
|
|
429
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
430
|
+
}
|
|
431
|
+
activePagesCount++;
|
|
432
|
+
let page = null;
|
|
433
|
+
let usingPooledPage = false;
|
|
434
|
+
try {
|
|
435
|
+
const browser = stealth ? await getStealthBrowser() : await getBrowser();
|
|
436
|
+
const shouldUsePagePool = !stealth && !userAgent;
|
|
437
|
+
if (shouldUsePagePool) {
|
|
438
|
+
page = takePooledPage();
|
|
439
|
+
usingPooledPage = !!page;
|
|
440
|
+
if (usingPooledPage && getPooledPagesCount() < PAGE_POOL_SIZE) {
|
|
441
|
+
void ensurePagePool(browser).catch(() => { });
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
if (!page) {
|
|
445
|
+
page = await browser.newPage({
|
|
446
|
+
userAgent: validatedUserAgent,
|
|
447
|
+
viewport: width || height ? {
|
|
448
|
+
width: width || 1280,
|
|
449
|
+
height: height || 720,
|
|
450
|
+
} : null, // Use browser window size when no explicit dimensions requested
|
|
451
|
+
});
|
|
452
|
+
await applyStealthScripts(page);
|
|
453
|
+
usingPooledPage = false;
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
await page.setViewportSize({
|
|
457
|
+
width: width || 1280,
|
|
458
|
+
height: height || 720,
|
|
459
|
+
}).catch(() => { });
|
|
460
|
+
}
|
|
461
|
+
await page.unroute('**/*').catch(() => { });
|
|
462
|
+
const mergedHeaders = { ...(headers || {}) };
|
|
463
|
+
if (usingPooledPage) {
|
|
464
|
+
mergedHeaders['User-Agent'] = validatedUserAgent;
|
|
465
|
+
}
|
|
466
|
+
if (usingPooledPage || Object.keys(mergedHeaders).length > 0) {
|
|
467
|
+
await page.setExtraHTTPHeaders(mergedHeaders);
|
|
468
|
+
}
|
|
469
|
+
if (cookies && cookies.length > 0) {
|
|
470
|
+
const parsedCookies = cookies.map(cookie => {
|
|
471
|
+
const [nameValue] = cookie.split(';').map(s => s.trim());
|
|
472
|
+
const [name, value] = nameValue.split('=');
|
|
473
|
+
if (!name || value === undefined) {
|
|
474
|
+
throw new WebPeelError(`Invalid cookie format: ${cookie}`);
|
|
475
|
+
}
|
|
476
|
+
return {
|
|
477
|
+
name: name.trim(),
|
|
478
|
+
value: value.trim(),
|
|
479
|
+
url,
|
|
480
|
+
};
|
|
481
|
+
});
|
|
482
|
+
await page.context().addCookies(parsedCookies);
|
|
483
|
+
}
|
|
484
|
+
// For screenshots, allow all resources
|
|
485
|
+
await page.route('**/*', (route) => route.continue());
|
|
486
|
+
let screenshotBuffer;
|
|
487
|
+
const doWork = (async () => {
|
|
488
|
+
await page.goto(url, {
|
|
489
|
+
waitUntil: 'domcontentloaded',
|
|
490
|
+
timeout: timeoutMs,
|
|
491
|
+
});
|
|
492
|
+
if (waitMs > 0) {
|
|
493
|
+
await page.waitForTimeout(waitMs);
|
|
494
|
+
}
|
|
495
|
+
if (actions && actions.length > 0) {
|
|
496
|
+
const { executeActions } = await import('./actions.js');
|
|
497
|
+
const actionScreenshot = await executeActions(page, actions, {
|
|
498
|
+
fullPage,
|
|
499
|
+
type: format,
|
|
500
|
+
quality,
|
|
501
|
+
});
|
|
502
|
+
if (actionScreenshot) {
|
|
503
|
+
screenshotBuffer = actionScreenshot;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
const finalUrl = page.url();
|
|
507
|
+
// Capture screenshot if not captured via actions
|
|
508
|
+
if (!screenshotBuffer) {
|
|
509
|
+
screenshotBuffer = await page.screenshot({
|
|
510
|
+
fullPage,
|
|
511
|
+
type: format,
|
|
512
|
+
...(format === 'jpeg' && typeof quality === 'number' ? { quality } : {}),
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
return { finalUrl, screenshotBuffer: screenshotBuffer };
|
|
516
|
+
})();
|
|
517
|
+
let operationTimeout;
|
|
518
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
519
|
+
operationTimeout = setTimeout(() => reject(new TimeoutError(`Operation timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
520
|
+
});
|
|
521
|
+
const { finalUrl, screenshotBuffer: buf } = await Promise.race([doWork, timeoutPromise]);
|
|
522
|
+
if (operationTimeout) {
|
|
523
|
+
clearTimeout(operationTimeout);
|
|
524
|
+
}
|
|
525
|
+
return { buffer: buf, finalUrl };
|
|
526
|
+
}
|
|
527
|
+
catch (error) {
|
|
528
|
+
if (error instanceof BlockedError || error instanceof WebPeelError || error instanceof TimeoutError) {
|
|
529
|
+
throw error;
|
|
530
|
+
}
|
|
531
|
+
if (error instanceof Error && error.message.includes('Timeout')) {
|
|
532
|
+
throw new TimeoutError('Browser screenshot timed out');
|
|
533
|
+
}
|
|
534
|
+
throw new NetworkError(`Browser screenshot failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
535
|
+
}
|
|
536
|
+
finally {
|
|
537
|
+
if (page) {
|
|
538
|
+
if (usingPooledPage) {
|
|
539
|
+
await recyclePooledPage(page);
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
await page.close().catch(() => { });
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
activePagesCount--;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
// ── retryFetch ────────────────────────────────────────────────────────────────
|
|
549
|
+
/**
|
|
550
|
+
* Retry a fetch operation with exponential backoff
|
|
551
|
+
*/
|
|
552
|
+
export async function retryFetch(fn, maxAttempts = 3, baseDelayMs = 1000) {
|
|
553
|
+
let lastError = null;
|
|
554
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
555
|
+
try {
|
|
556
|
+
return await fn();
|
|
557
|
+
}
|
|
558
|
+
catch (error) {
|
|
559
|
+
lastError = error instanceof Error ? error : new Error('Unknown error');
|
|
560
|
+
// Don't retry on blocked errors or timeouts
|
|
561
|
+
if (error instanceof BlockedError || error instanceof TimeoutError) {
|
|
562
|
+
throw error;
|
|
563
|
+
}
|
|
564
|
+
if (attempt < maxAttempts) {
|
|
565
|
+
const delay = baseDelayMs * Math.pow(2, attempt - 1);
|
|
566
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
throw lastError || new NetworkError('Retry failed');
|
|
571
|
+
}
|
|
572
|
+
// ── scrollAndWait ─────────────────────────────────────────────────────────────
|
|
573
|
+
/**
|
|
574
|
+
* Scroll to the bottom of the page N times, waiting for the network to
|
|
575
|
+
* settle between each scroll. Useful for triggering lazy-loaded content
|
|
576
|
+
* (infinite scroll, deferred images, etc.).
|
|
577
|
+
*
|
|
578
|
+
* @param page - Playwright Page instance.
|
|
579
|
+
* @param times - Number of scroll-and-wait cycles (default: 3).
|
|
580
|
+
* @returns The final page HTML after all scrolls complete.
|
|
581
|
+
*/
|
|
582
|
+
export async function scrollAndWait(page, times = 3) {
|
|
583
|
+
for (let i = 0; i < times; i++) {
|
|
584
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
585
|
+
await page.evaluate('window.scrollTo(0, document.body.scrollHeight)');
|
|
586
|
+
// Wait for network to settle (500 ms of no new requests) or 2 s max.
|
|
587
|
+
try {
|
|
588
|
+
await page.waitForLoadState('networkidle', { timeout: 2000 });
|
|
589
|
+
}
|
|
590
|
+
catch (e) {
|
|
591
|
+
// networkidle may never fire — fall back to a flat delay.
|
|
592
|
+
if (process.env.DEBUG)
|
|
593
|
+
console.debug('[webpeel]', 'networkidle timeout, falling back to flat delay:', e instanceof Error ? e.message : e);
|
|
594
|
+
await page.waitForTimeout(1000);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return page.content();
|
|
598
|
+
}
|
|
599
|
+
//# sourceMappingURL=browser-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-fetch.js","sourceRoot":"","sources":["../../src/core/browser-fetch.ts"],"names":[],"mappings":"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"}
|