mcp-scraper 0.43.2 → 0.43.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/README.md +1 -1
- package/dist/bin/api-server.cjs +92 -52
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +1 -1
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +3 -3
- package/dist/bin/paa-harvest.cjs +42 -22
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +2 -2
- package/dist/{chunk-H7LQ6PTI.js → chunk-6TAQ2MXK.js} +50 -24
- package/dist/chunk-6TAQ2MXK.js.map +1 -0
- package/dist/{chunk-YJNGNMDO.js → chunk-SXLQZKWC.js} +3 -3
- package/dist/chunk-XQIVXIAL.js +7 -0
- package/dist/chunk-XQIVXIAL.js.map +1 -0
- package/dist/{chunk-DAS7L4SF.js → chunk-ZDVQARDQ.js} +3 -1
- package/dist/chunk-ZDVQARDQ.js.map +1 -0
- package/dist/index.cjs +42 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/{server-BPEXEKA6.js → server-K76DL4S7.js} +39 -32
- package/dist/server-K76DL4S7.js.map +1 -0
- package/dist/{worker-2LIOH744.js → worker-OB6WSWOD.js} +3 -3
- package/package.json +2 -1
- package/dist/chunk-DAS7L4SF.js.map +0 -1
- package/dist/chunk-H7LQ6PTI.js.map +0 -1
- package/dist/chunk-MD75M2L5.js +0 -7
- package/dist/chunk-MD75M2L5.js.map +0 -1
- package/dist/server-BPEXEKA6.js.map +0 -1
- /package/dist/{chunk-YJNGNMDO.js.map → chunk-SXLQZKWC.js.map} +0 -0
- /package/dist/{worker-2LIOH744.js.map → worker-OB6WSWOD.js.map} +0 -0
|
@@ -18,10 +18,10 @@ import {
|
|
|
18
18
|
browserServiceProfileSaveChanges,
|
|
19
19
|
recordVendorUsage,
|
|
20
20
|
vendorCostUsd
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-ZDVQARDQ.js";
|
|
22
22
|
import {
|
|
23
23
|
PACKAGE_VERSION
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-XQIVXIAL.js";
|
|
25
25
|
import {
|
|
26
26
|
MC_PER_CREDIT
|
|
27
27
|
} from "./chunk-X5WDJ7D7.js";
|
|
@@ -12665,4 +12665,4 @@ export {
|
|
|
12665
12665
|
ScheduledResultsMcpExecutor,
|
|
12666
12666
|
registerScheduledResultsMcpTools
|
|
12667
12667
|
};
|
|
12668
|
-
//# sourceMappingURL=chunk-
|
|
12668
|
+
//# sourceMappingURL=chunk-SXLQZKWC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["export const PACKAGE_VERSION = '0.43.4'\n"],"mappings":";AAAO,IAAM,kBAAkB;","names":[]}
|
|
@@ -24,6 +24,7 @@ function browserServiceProfileSaveChanges() {
|
|
|
24
24
|
|
|
25
25
|
// src/api/cost-context.ts
|
|
26
26
|
import { AsyncLocalStorage } from "async_hooks";
|
|
27
|
+
var HEADLESS_HARVEST_TEST_ENV = "MCP_SCRAPER_ALLOW_HEADLESS_HARVEST_TEST";
|
|
27
28
|
var storage = new AsyncLocalStorage();
|
|
28
29
|
function runWithCostContext(ctx, fn) {
|
|
29
30
|
return storage.run(ctx, fn);
|
|
@@ -266,6 +267,7 @@ export {
|
|
|
266
267
|
browserServiceProxyId,
|
|
267
268
|
browserServiceProfileName,
|
|
268
269
|
browserServiceProfileSaveChanges,
|
|
270
|
+
HEADLESS_HARVEST_TEST_ENV,
|
|
269
271
|
runWithCostContext,
|
|
270
272
|
currentCostContext,
|
|
271
273
|
HEADLESS_OPS,
|
|
@@ -273,4 +275,4 @@ export {
|
|
|
273
275
|
recordKernelSession,
|
|
274
276
|
recordVendorUsage
|
|
275
277
|
};
|
|
276
|
-
//# sourceMappingURL=chunk-
|
|
278
|
+
//# sourceMappingURL=chunk-ZDVQARDQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/browser-service-env.ts","../src/api/cost-context.ts","../src/api/cost-telemetry.ts","../src/api/cost-rates.ts"],"sourcesContent":["export function browserServiceApiKey(): string | undefined {\n const value = (process.env.BROWSER_SERVICE_API_KEY ?? process.env.KERNEL_API_KEY)?.trim()\n return value || undefined\n}\n\nexport function browserServiceProxyId(): string | undefined {\n return undefined\n}\n\nexport function browserServiceProfileName(): string | undefined {\n const value = (\n process.env.BROWSER_AGENT_PROFILE_NAME ??\n process.env.BROWSER_SERVICE_PROFILE_NAME ??\n process.env.KERNEL_BROWSER_PROFILE_NAME ??\n process.env.KERNEL_PROFILE_NAME\n )?.trim()\n return value || undefined\n}\n\nexport function browserServiceProfileSaveChanges(): boolean | undefined {\n const value = (\n process.env.BROWSER_AGENT_PROFILE_SAVE_CHANGES ??\n process.env.BROWSER_SERVICE_PROFILE_SAVE_CHANGES ??\n process.env.KERNEL_BROWSER_PROFILE_SAVE_CHANGES ??\n process.env.KERNEL_PROFILE_SAVE_CHANGES\n )?.trim().toLowerCase()\n if (!value) return undefined\n if (['1', 'true', 'yes', 'on'].includes(value)) return true\n if (['0', 'false', 'no', 'off'].includes(value)) return false\n return undefined\n}\n","import { AsyncLocalStorage } from 'node:async_hooks'\n\nexport interface CostContext {\n op: string\n probeRunId?: string | null\n userId?: number | null\n forceHeadless?: boolean\n forceHeadful?: boolean\n harvestBrowserMode?: 'headless-test'\n subOp?: string | null\n headlessSentOut?: { value: boolean | null }\n}\n\nexport const HEADLESS_HARVEST_TEST_ENV = 'MCP_SCRAPER_ALLOW_HEADLESS_HARVEST_TEST'\n\nconst storage = new AsyncLocalStorage<CostContext>()\n\nexport function runWithCostContext<T>(ctx: CostContext, fn: () => T): T {\n return storage.run(ctx, fn)\n}\n\nexport function currentCostContext(): CostContext | undefined {\n return storage.getStore()\n}\n","import { randomUUID } from 'node:crypto'\nimport { getDb } from './db.js'\nimport { currentCostContext } from './cost-context.js'\nimport { kernelCostUsd, vendorCostUsd } from './cost-rates.js'\n\nlet _ready = false\nlet _migrationPromise: Promise<void> | null = null\n\nexport async function migrateCostTelemetry(): Promise<void> {\n if (_ready) return\n if (_migrationPromise) return _migrationPromise\n _migrationPromise = runCostTelemetryMigration().finally(() => {\n _migrationPromise = null\n })\n return _migrationPromise\n}\n\nasync function runCostTelemetryMigration(): Promise<void> {\n const db = getDb()\n const existing = await db.execute(`\n SELECT\n (SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name IN ('kernel_session_log', 'vendor_usage_log', 'cost_probe_runs')) = 3\n AND (SELECT COUNT(*) FROM pragma_table_info('kernel_session_log') WHERE name IN ('proxy_source', 'proxy_type', 'method')) = 3\n AND (SELECT COUNT(*) FROM pragma_table_info('vendor_usage_log') WHERE name = 'method') = 1\n AND (SELECT COUNT(*) FROM pragma_table_info('cost_probe_runs') WHERE name IN ('units', 'unit_type', 'mode')) = 3\n AS ready\n `)\n if (Number(existing.rows[0]?.ready ?? 0) === 1) {\n _ready = true\n return\n }\n\n await db.execute(`\n CREATE TABLE IF NOT EXISTS kernel_session_log (\n id TEXT PRIMARY KEY,\n kernel_session_id TEXT,\n op TEXT,\n source TEXT NOT NULL,\n probe_run_id TEXT,\n user_id INTEGER,\n stealth INTEGER,\n headless_sent INTEGER,\n proxy_used INTEGER,\n fallback INTEGER NOT NULL DEFAULT 0,\n opened_at TEXT,\n closed_at TEXT,\n duration_ms INTEGER NOT NULL DEFAULT 0,\n est_cost_usd_headless REAL NOT NULL DEFAULT 0,\n est_cost_usd_headful REAL NOT NULL DEFAULT 0,\n error TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_op ON kernel_session_log(op)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_probe ON kernel_session_log(probe_run_id)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_created ON kernel_session_log(created_at)`)\n try { await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_source TEXT`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_type TEXT`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN method TEXT`) } catch { void 0 }\n await db.execute(`\n CREATE TABLE IF NOT EXISTS vendor_usage_log (\n id TEXT PRIMARY KEY,\n op TEXT,\n probe_run_id TEXT,\n user_id INTEGER,\n vendor TEXT NOT NULL,\n model TEXT,\n units REAL NOT NULL DEFAULT 0,\n unit_type TEXT,\n est_cost_usd REAL NOT NULL DEFAULT 0,\n error TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_op ON vendor_usage_log(op)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_probe ON vendor_usage_log(probe_run_id)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_created ON vendor_usage_log(created_at)`)\n try { await db.execute(`ALTER TABLE vendor_usage_log ADD COLUMN method TEXT`) } catch { void 0 }\n await db.execute(`\n CREATE TABLE IF NOT EXISTS cost_probe_runs (\n id TEXT PRIMARY KEY,\n tool TEXT NOT NULL,\n target TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n wall_ms INTEGER NOT NULL DEFAULT 0,\n success INTEGER NOT NULL DEFAULT 0,\n error TEXT,\n http_only INTEGER NOT NULL DEFAULT 0,\n kernel_used INTEGER NOT NULL DEFAULT 0,\n kernel_sessions INTEGER NOT NULL DEFAULT 0,\n kernel_seconds_total REAL NOT NULL DEFAULT 0,\n kernel_tier_observed TEXT,\n est_kernel_cost_usd_headless REAL NOT NULL DEFAULT 0,\n est_kernel_cost_usd_headful REAL NOT NULL DEFAULT 0,\n vendor_cost_usd REAL NOT NULL DEFAULT 0,\n charged_credits REAL NOT NULL DEFAULT 0,\n margin_usd_headless_starter REAL NOT NULL DEFAULT 0,\n margin_usd_headful_starter REAL NOT NULL DEFAULT 0,\n notes TEXT\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS cost_probe_runs_tool ON cost_probe_runs(tool)`)\n try { await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN units REAL`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN unit_type TEXT`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN mode TEXT`) } catch { void 0 }\n _ready = true\n}\n\nexport interface KernelSessionRecord {\n kernelSessionId?: string | null\n source: string\n stealth?: boolean | null\n headlessSent?: boolean | null\n proxyUsed?: boolean | null\n proxySource?: string | null\n proxyType?: string | null\n fallback?: boolean\n openedAtMs: number\n closedAtMs: number\n error?: string | null\n}\n\nexport async function recordKernelSession(r: KernelSessionRecord): Promise<void> {\n try {\n await migrateCostTelemetry()\n const ctx = currentCostContext()\n const durationMs = Math.max(0, r.closedAtMs - r.openedAtMs)\n const db = getDb()\n await db.execute({\n sql: `INSERT INTO kernel_session_log\n (id, kernel_session_id, op, source, probe_run_id, user_id, stealth, headless_sent, proxy_used, proxy_source, proxy_type, fallback, opened_at, closed_at, duration_ms, est_cost_usd_headless, est_cost_usd_headful, error, method)\n VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,\n args: [\n randomUUID(),\n r.kernelSessionId ?? null,\n ctx?.op ?? null,\n r.source,\n ctx?.probeRunId ?? null,\n ctx?.userId ?? null,\n boolToInt(r.stealth),\n boolToInt(r.headlessSent),\n boolToInt(r.proxyUsed),\n r.proxySource ?? null,\n r.proxyType ?? null,\n r.fallback ? 1 : 0,\n new Date(r.openedAtMs).toISOString(),\n new Date(r.closedAtMs).toISOString(),\n durationMs,\n kernelCostUsd(durationMs, false),\n kernelCostUsd(durationMs, true),\n r.error ?? null,\n ctx?.subOp ?? null,\n ],\n })\n } catch (err) {\n console.warn('[cost-telemetry] recordKernelSession failed:', err instanceof Error ? err.message : String(err))\n }\n}\n\nexport interface VendorUsageRecord {\n vendor: string\n model?: string | null\n units: number\n unitType: string\n error?: string | null\n}\n\nexport async function recordVendorUsage(r: VendorUsageRecord): Promise<void> {\n try {\n await migrateCostTelemetry()\n const ctx = currentCostContext()\n const db = getDb()\n await db.execute({\n sql: `INSERT INTO vendor_usage_log\n (id, op, probe_run_id, user_id, vendor, model, units, unit_type, est_cost_usd, error, method)\n VALUES (?,?,?,?,?,?,?,?,?,?,?)`,\n args: [\n randomUUID(),\n ctx?.op ?? null,\n ctx?.probeRunId ?? null,\n ctx?.userId ?? null,\n r.vendor,\n r.model ?? null,\n r.units,\n r.unitType,\n vendorCostUsd(r.vendor, r.units),\n r.error ?? null,\n ctx?.subOp ?? null,\n ],\n })\n } catch (err) {\n console.warn('[cost-telemetry] recordVendorUsage failed:', err instanceof Error ? err.message : String(err))\n }\n}\n\nexport interface ProbeRunRecord {\n id: string\n tool: string\n target?: string | null\n wallMs: number\n success: boolean\n error?: string | null\n httpOnly: boolean\n kernelUsed: boolean\n kernelSessions: number\n kernelSecondsTotal: number\n kernelTierObserved?: string | null\n estKernelCostUsdHeadless: number\n estKernelCostUsdHeadful: number\n vendorCostUsd: number\n chargedCredits: number\n marginUsdHeadlessStarter: number\n marginUsdHeadfulStarter: number\n units?: number | null\n unitType?: string | null\n mode?: string | null\n notes?: string | null\n}\n\nexport async function recordProbeRun(r: ProbeRunRecord): Promise<void> {\n await migrateCostTelemetry()\n const db = getDb()\n await db.execute({\n sql: `INSERT INTO cost_probe_runs\n (id, tool, target, wall_ms, success, error, http_only, kernel_used, kernel_sessions, kernel_seconds_total, kernel_tier_observed, est_kernel_cost_usd_headless, est_kernel_cost_usd_headful, vendor_cost_usd, charged_credits, margin_usd_headless_starter, margin_usd_headful_starter, units, unit_type, mode, notes)\n VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,\n args: [\n r.id, r.tool, r.target ?? null, r.wallMs, r.success ? 1 : 0, r.error ?? null,\n r.httpOnly ? 1 : 0, r.kernelUsed ? 1 : 0, r.kernelSessions, r.kernelSecondsTotal,\n r.kernelTierObserved ?? null, r.estKernelCostUsdHeadless, r.estKernelCostUsdHeadful,\n r.vendorCostUsd, r.chargedCredits, r.marginUsdHeadlessStarter, r.marginUsdHeadfulStarter,\n r.units ?? null, r.unitType ?? null, r.mode ?? null, r.notes ?? null,\n ],\n })\n}\n\nfunction boolToInt(v: boolean | null | undefined): number | null {\n if (v === null || v === undefined) return null\n return v ? 1 : 0\n}\n","export const KERNEL_HEADLESS_USD_PER_SEC = 0.0000166667\nexport const KERNEL_HEADFUL_USD_PER_SEC = 0.0001333336\n\nexport const HEADLESS_OPS = new Set<string>(['serp', 'fb_search', 'fb_ad', 'instagram'])\n\nexport const FAL_WIZPER_USD_PER_COMPUTE_SEC = 0.00111\nexport const FAL_WIZPER_WALLCLOCK_TO_COMPUTE_SEC_FACTOR = 4 // calibrated from 2 real Fal invoices (4.36x, 6.18x wall-clock vs actual)\nexport const DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS = 0.0004\n\nfunction envRate(name: string, fallback: number): number {\n const raw = process.env[name]?.trim()\n if (!raw) return fallback\n const parsed = Number(raw)\n return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback\n}\n\nexport const NANGO_USD_PER_CONNECTION_MONTH = envRate('NANGO_USD_PER_CONNECTION_MONTH', 1)\nexport const NANGO_USD_PER_FUNCTION_RUN = envRate('NANGO_USD_PER_FUNCTION_RUN', 0.0001)\nexport const NANGO_USD_PER_PROXY_REQUEST = envRate('NANGO_USD_PER_PROXY_REQUEST', 0.0001)\nexport const NANGO_USD_PER_COMPUTE_SEC = envRate('NANGO_USD_PER_COMPUTE_SEC', 0.0002)\n\nexport const CONNECTED_TARGET_MARGIN_MULTIPLE = 2.25\n\nexport function kernelCostUsd(ms: number, headful: boolean): number {\n const sec = Math.max(0, ms) / 1000\n return sec * (headful ? KERNEL_HEADFUL_USD_PER_SEC : KERNEL_HEADLESS_USD_PER_SEC)\n}\n\nexport function vendorCostUsd(vendor: string, units: number): number {\n if (vendor === 'fal_wizper') {\n const estimatedComputeSec = Math.max(0, units) / FAL_WIZPER_WALLCLOCK_TO_COMPUTE_SEC_FACTOR\n return estimatedComputeSec * FAL_WIZPER_USD_PER_COMPUTE_SEC\n }\n if (vendor === 'deepinfra_qwen') return (Math.max(0, units) / 1000) * DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS\n if (vendor === 'openrouter') return Math.max(0, units) // units IS the real USD cost OpenRouter reported, not a rate-multiplied estimate\n if (vendor === 'mcp_memory_video') return Math.max(0, units) // units IS the real costUsd mcp-memory's video pipeline reported (OpenRouter + transcription)\n if (vendor === 'mcp_memory_ai') return Math.max(0, units) // units IS the real costUsd mcp-memory reported via /ai-debit\n if (vendor === 'nango_connection') return Math.max(0, units) * NANGO_USD_PER_CONNECTION_MONTH\n if (vendor === 'nango_function_run') return Math.max(0, units) * NANGO_USD_PER_FUNCTION_RUN\n if (vendor === 'nango_proxy_request') return Math.max(0, units) * NANGO_USD_PER_PROXY_REQUEST\n if (vendor === 'nango_compute') return Math.max(0, units) * NANGO_USD_PER_COMPUTE_SEC\n return 0\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -329,6 +329,7 @@ var SiteAuditPhaseLogRowSchema = import_zod2.z.object({
|
|
|
329
329
|
|
|
330
330
|
// src/api/cost-context.ts
|
|
331
331
|
var import_node_async_hooks = require("async_hooks");
|
|
332
|
+
var HEADLESS_HARVEST_TEST_ENV = "MCP_SCRAPER_ALLOW_HEADLESS_HARVEST_TEST";
|
|
332
333
|
var storage = new import_node_async_hooks.AsyncLocalStorage();
|
|
333
334
|
function runWithCostContext(ctx, fn) {
|
|
334
335
|
return storage.run(ctx, fn);
|
|
@@ -563,10 +564,35 @@ function boolToInt(v) {
|
|
|
563
564
|
return v ? 1 : 0;
|
|
564
565
|
}
|
|
565
566
|
|
|
567
|
+
// src/lib/browser-user-agent.ts
|
|
568
|
+
var RUNTIME_BROWSER_UA = /\b(?:HeadlessChrome|Chrome|Chromium|Firefox)\/\d+|\bVersion\/\d+.*\bSafari\//;
|
|
569
|
+
async function detectPageUserAgent(page) {
|
|
570
|
+
try {
|
|
571
|
+
const value = await page.evaluate(() => navigator.userAgent);
|
|
572
|
+
return typeof value === "string" && RUNTIME_BROWSER_UA.test(value) ? value : null;
|
|
573
|
+
} catch {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
async function detectRuntimeUserAgent(browser) {
|
|
578
|
+
let probeContext = null;
|
|
579
|
+
try {
|
|
580
|
+
let page = browser.contexts().flatMap((context) => context.pages())[0];
|
|
581
|
+
if (!page) {
|
|
582
|
+
probeContext = await browser.newContext();
|
|
583
|
+
page = probeContext.pages()[0] ?? await probeContext.newPage();
|
|
584
|
+
}
|
|
585
|
+
return await detectPageUserAgent(page);
|
|
586
|
+
} catch {
|
|
587
|
+
return null;
|
|
588
|
+
} finally {
|
|
589
|
+
if (probeContext) await probeContext.close().catch(() => {
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
566
594
|
// src/driver/BrowserDriver.ts
|
|
567
595
|
import_playwright_extra.chromium.use((0, import_puppeteer_extra_plugin_stealth.default)());
|
|
568
|
-
var DESKTOP_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36";
|
|
569
|
-
var MOBILE_USER_AGENT = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1";
|
|
570
596
|
var DEFAULT_KERNEL_BROWSER_TIMEOUT_SECONDS = 180;
|
|
571
597
|
var KERNEL_BROWSER_CLOSE_TIMEOUT_MS = 3e3;
|
|
572
598
|
var KERNEL_SESSION_DELETE_TIMEOUT_MS = 5e3;
|
|
@@ -601,21 +627,11 @@ async function ensureKernelProfile(kernelClient, name) {
|
|
|
601
627
|
if (!isKernelProfileConflict(err)) throw err;
|
|
602
628
|
}
|
|
603
629
|
}
|
|
604
|
-
async function detectRuntimeUserAgent(browser) {
|
|
605
|
-
try {
|
|
606
|
-
const page = browser.contexts()[0]?.pages()[0];
|
|
607
|
-
if (!page) return null;
|
|
608
|
-
const ua = await page.evaluate(() => navigator.userAgent);
|
|
609
|
-
return typeof ua === "string" && /Chrome\/\d+/.test(ua) ? ua : null;
|
|
610
|
-
} catch {
|
|
611
|
-
return null;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
630
|
function rankCheckContextOptions(config, runtimeUserAgent) {
|
|
615
631
|
return {
|
|
616
632
|
viewport: config.viewport,
|
|
617
633
|
locale: config.locale,
|
|
618
|
-
|
|
634
|
+
...runtimeUserAgent ? { userAgent: runtimeUserAgent } : {},
|
|
619
635
|
...config.deviceScaleFactor ? { deviceScaleFactor: config.deviceScaleFactor } : {},
|
|
620
636
|
...config.isMobile !== void 0 ? { isMobile: config.isMobile } : {},
|
|
621
637
|
...config.hasTouch !== void 0 ? { hasTouch: config.hasTouch } : {}
|
|
@@ -690,7 +706,7 @@ var BrowserDriver = class {
|
|
|
690
706
|
viewport: config.viewport,
|
|
691
707
|
locale: config.locale,
|
|
692
708
|
device,
|
|
693
|
-
userAgent:
|
|
709
|
+
userAgent: null,
|
|
694
710
|
deviceScaleFactor: config.deviceScaleFactor ?? null,
|
|
695
711
|
isMobile: config.isMobile === true,
|
|
696
712
|
hasTouch: config.hasTouch === true
|
|
@@ -778,7 +794,7 @@ var BrowserDriver = class {
|
|
|
778
794
|
}
|
|
779
795
|
this.browser = await import_playwright.chromium.connectOverCDP(kernelBrowser.cdp_ws_url);
|
|
780
796
|
const runtimeUserAgent = await detectRuntimeUserAgent(this.browser);
|
|
781
|
-
this.debugSnapshot.context.userAgent =
|
|
797
|
+
this.debugSnapshot.context.userAgent = runtimeUserAgent;
|
|
782
798
|
this.context = await this.browser.newContext(rankCheckContextOptions(config, runtimeUserAgent));
|
|
783
799
|
await this.installEsbuildHelperShims(this.context);
|
|
784
800
|
this.page = await this.context.newPage();
|
|
@@ -800,17 +816,19 @@ var BrowserDriver = class {
|
|
|
800
816
|
...config.browserExecutablePath ? { executablePath: config.browserExecutablePath } : {},
|
|
801
817
|
...config.ignoreDefaultArgs ? { ignoreDefaultArgs: config.ignoreDefaultArgs } : {}
|
|
802
818
|
};
|
|
803
|
-
const ctxOpts = rankCheckContextOptions(config);
|
|
804
819
|
if (config.profileDir) {
|
|
805
820
|
this.context = await import_playwright_extra.chromium.launchPersistentContext(config.profileDir, {
|
|
806
821
|
...launchOpts,
|
|
807
|
-
...
|
|
822
|
+
...rankCheckContextOptions(config)
|
|
808
823
|
});
|
|
809
824
|
await this.installEsbuildHelperShims(this.context);
|
|
810
825
|
this.page = await this.context.newPage();
|
|
826
|
+
this.debugSnapshot.context.userAgent = await detectPageUserAgent(this.page);
|
|
811
827
|
} else {
|
|
812
828
|
this.browser = await import_playwright_extra.chromium.launch(launchOpts);
|
|
813
|
-
|
|
829
|
+
const runtimeUserAgent = await detectRuntimeUserAgent(this.browser);
|
|
830
|
+
this.debugSnapshot.context.userAgent = runtimeUserAgent;
|
|
831
|
+
this.context = await this.browser.newContext(rankCheckContextOptions(config, runtimeUserAgent));
|
|
814
832
|
await this.installEsbuildHelperShims(this.context);
|
|
815
833
|
this.page = await this.context.newPage();
|
|
816
834
|
}
|
|
@@ -1737,8 +1755,6 @@ async function extractAISurfacesFromDocument(config) {
|
|
|
1737
1755
|
}
|
|
1738
1756
|
|
|
1739
1757
|
// src/extractor/PAAExtractor.ts
|
|
1740
|
-
var DESKTOP_USER_AGENT2 = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36";
|
|
1741
|
-
var MOBILE_USER_AGENT2 = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1";
|
|
1742
1758
|
var PAAExtractor = class {
|
|
1743
1759
|
constructor(driver, reporter) {
|
|
1744
1760
|
this.driver = driver;
|
|
@@ -2548,7 +2564,6 @@ var PAAExtractor = class {
|
|
|
2548
2564
|
requireUsEgress: options.requireUsEgress,
|
|
2549
2565
|
viewport: isMobile ? { width: 390, height: 844 } : { width: 1280, height: 800 },
|
|
2550
2566
|
locale: `${options.hl}-${options.gl.toUpperCase()}`,
|
|
2551
|
-
userAgent: isMobile ? MOBILE_USER_AGENT2 : DESKTOP_USER_AGENT2,
|
|
2552
2567
|
deviceScaleFactor: isMobile ? 3 : 1,
|
|
2553
2568
|
isMobile,
|
|
2554
2569
|
hasTouch: isMobile,
|
|
@@ -3671,7 +3686,12 @@ async function harvest(rawOptions) {
|
|
|
3671
3686
|
max_questions: attemptOptions.maxQuestions
|
|
3672
3687
|
}));
|
|
3673
3688
|
const baseCtx = currentCostContext();
|
|
3674
|
-
const
|
|
3689
|
+
const allowHeadlessTest = baseCtx?.harvestBrowserMode === "headless-test" && process.env[HEADLESS_HARVEST_TEST_ENV] === "true";
|
|
3690
|
+
const attempt = baseCtx ? await runWithCostContext({
|
|
3691
|
+
...baseCtx,
|
|
3692
|
+
forceHeadless: allowHeadlessTest,
|
|
3693
|
+
forceHeadful: !allowHeadlessTest
|
|
3694
|
+
}, () => extractOnce(attemptOptions, signal)) : await extractOnce(attemptOptions, signal);
|
|
3675
3695
|
if (attempt.error) {
|
|
3676
3696
|
const err = attempt.error;
|
|
3677
3697
|
const outcome2 = classifyAttemptError(err);
|