mcp-scraper 0.3.24 → 0.3.25
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/bin/api-server.cjs +8140 -5941
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +3 -3
- package/dist/bin/mcp-scraper-cli.cjs +320 -58
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +4 -3
- package/dist/bin/mcp-scraper-cli.js.map +1 -1
- package/dist/bin/mcp-scraper-install.cjs +3 -3
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.cjs +121 -24
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +5 -5
- package/dist/bin/paa-harvest.cjs +284 -10
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +5 -3
- package/dist/bin/paa-harvest.js.map +1 -1
- package/dist/{chunk-ZAP7MYVO.js → chunk-3PRO376E.js} +2 -3
- package/dist/chunk-3PRO376E.js.map +1 -0
- package/dist/{chunk-LFATOGDF.js → chunk-BP27CZ5Q.js} +4 -3
- package/dist/chunk-BP27CZ5Q.js.map +1 -0
- package/dist/{chunk-DE7WP4UU.js → chunk-DOBQN3EY.js} +3 -3
- package/dist/chunk-DOBQN3EY.js.map +1 -0
- package/dist/{chunk-GZ4W72WF.js → chunk-FE2WC4JR.js} +119 -23
- package/dist/chunk-FE2WC4JR.js.map +1 -0
- package/dist/{chunk-IGOEAKC7.js → chunk-G7PQ64LM.js} +274 -9
- package/dist/chunk-G7PQ64LM.js.map +1 -0
- package/dist/chunk-K443GQY5.js +24 -0
- package/dist/chunk-K443GQY5.js.map +1 -0
- package/dist/{chunk-H2R232HK.js → chunk-NNEIXK5L.js} +307 -62
- package/dist/chunk-NNEIXK5L.js.map +1 -0
- package/dist/{chunk-3KYRG7O7.js → chunk-TRNSXR46.js} +185 -2
- package/dist/chunk-TRNSXR46.js.map +1 -0
- package/dist/chunk-WPHAMNT7.js +7 -0
- package/dist/chunk-WPHAMNT7.js.map +1 -0
- package/dist/{chunk-JTWQGPKF.js → chunk-WYCER2HW.js} +33 -10
- package/dist/chunk-WYCER2HW.js.map +1 -0
- package/dist/{db-EG5ETPTY.js → db-FP2ABUU4.js} +32 -2
- package/dist/index.cjs +284 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/{server-2SRARAO5.js → server-RRCKVBHG.js} +1563 -265
- package/dist/server-RRCKVBHG.js.map +1 -0
- package/dist/{worker-UM5UM6O5.js → worker-UC6D2756.js} +7 -6
- package/dist/{worker-UM5UM6O5.js.map → worker-UC6D2756.js.map} +1 -1
- package/docs/kernel-proxy-future-enhancements.md +80 -0
- package/docs/spec-browser-routing.md +108 -0
- package/docs/spec-mcp-tools.md +146 -0
- package/docs/specs/audit-visual-demo.md +309 -0
- package/package.json +5 -2
- package/dist/chunk-3KYRG7O7.js.map +0 -1
- package/dist/chunk-DE7WP4UU.js.map +0 -1
- package/dist/chunk-GZ4W72WF.js.map +0 -1
- package/dist/chunk-H2R232HK.js.map +0 -1
- package/dist/chunk-H7R4PPMG.js +0 -7
- package/dist/chunk-H7R4PPMG.js.map +0 -1
- package/dist/chunk-IGOEAKC7.js.map +0 -1
- package/dist/chunk-JTWQGPKF.js.map +0 -1
- package/dist/chunk-LFATOGDF.js.map +0 -1
- package/dist/chunk-ZAP7MYVO.js.map +0 -1
- package/dist/server-2SRARAO5.js.map +0 -1
- /package/dist/{db-EG5ETPTY.js.map → db-FP2ABUU4.js.map} +0 -0
|
@@ -7,12 +7,206 @@ import {
|
|
|
7
7
|
browserServiceApiKey,
|
|
8
8
|
browserServiceProxyId,
|
|
9
9
|
sanitizeVendorName
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3PRO376E.js";
|
|
11
|
+
import {
|
|
12
|
+
postToMemoryLibrary
|
|
13
|
+
} from "./chunk-K443GQY5.js";
|
|
11
14
|
import {
|
|
12
15
|
DEFAULT_PROXY_MODE,
|
|
13
16
|
HarvestOptionsSchema,
|
|
14
17
|
RawPAAItemSchema
|
|
15
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-BP27CZ5Q.js";
|
|
19
|
+
import {
|
|
20
|
+
getDb
|
|
21
|
+
} from "./chunk-TRNSXR46.js";
|
|
22
|
+
|
|
23
|
+
// src/api/cost-context.ts
|
|
24
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
25
|
+
var storage = new AsyncLocalStorage();
|
|
26
|
+
function runWithCostContext(ctx, fn) {
|
|
27
|
+
return storage.run(ctx, fn);
|
|
28
|
+
}
|
|
29
|
+
function currentCostContext() {
|
|
30
|
+
return storage.getStore();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/api/cost-telemetry.ts
|
|
34
|
+
import { randomUUID } from "crypto";
|
|
35
|
+
|
|
36
|
+
// src/api/cost-rates.ts
|
|
37
|
+
var KERNEL_HEADLESS_USD_PER_SEC = 166667e-10;
|
|
38
|
+
var KERNEL_HEADFUL_USD_PER_SEC = 1333336e-10;
|
|
39
|
+
var HEADLESS_OPS = /* @__PURE__ */ new Set(["harvest", "maps_search", "yt_channel", "fb_search", "fb_ad", "instagram"]);
|
|
40
|
+
var FAL_WIZPER_USD_PER_AUDIO_MIN = 5e-3;
|
|
41
|
+
var DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS = 4e-4;
|
|
42
|
+
function kernelCostUsd(ms, headful) {
|
|
43
|
+
const sec = Math.max(0, ms) / 1e3;
|
|
44
|
+
return sec * (headful ? KERNEL_HEADFUL_USD_PER_SEC : KERNEL_HEADLESS_USD_PER_SEC);
|
|
45
|
+
}
|
|
46
|
+
function vendorCostUsd(vendor, units) {
|
|
47
|
+
if (vendor === "fal_wizper") return Math.max(0, units) * FAL_WIZPER_USD_PER_AUDIO_MIN;
|
|
48
|
+
if (vendor === "deepinfra_qwen") return Math.max(0, units) / 1e3 * DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS;
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/api/cost-telemetry.ts
|
|
53
|
+
var _ready = false;
|
|
54
|
+
async function migrateCostTelemetry() {
|
|
55
|
+
if (_ready) return;
|
|
56
|
+
const db = getDb();
|
|
57
|
+
await db.execute(`
|
|
58
|
+
CREATE TABLE IF NOT EXISTS kernel_session_log (
|
|
59
|
+
id TEXT PRIMARY KEY,
|
|
60
|
+
kernel_session_id TEXT,
|
|
61
|
+
op TEXT,
|
|
62
|
+
source TEXT NOT NULL,
|
|
63
|
+
probe_run_id TEXT,
|
|
64
|
+
user_id INTEGER,
|
|
65
|
+
stealth INTEGER,
|
|
66
|
+
headless_sent INTEGER,
|
|
67
|
+
proxy_used INTEGER,
|
|
68
|
+
fallback INTEGER NOT NULL DEFAULT 0,
|
|
69
|
+
opened_at TEXT,
|
|
70
|
+
closed_at TEXT,
|
|
71
|
+
duration_ms INTEGER NOT NULL DEFAULT 0,
|
|
72
|
+
est_cost_usd_headless REAL NOT NULL DEFAULT 0,
|
|
73
|
+
est_cost_usd_headful REAL NOT NULL DEFAULT 0,
|
|
74
|
+
error TEXT,
|
|
75
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
76
|
+
)
|
|
77
|
+
`);
|
|
78
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_op ON kernel_session_log(op)`);
|
|
79
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_probe ON kernel_session_log(probe_run_id)`);
|
|
80
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_created ON kernel_session_log(created_at)`);
|
|
81
|
+
try {
|
|
82
|
+
await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_source TEXT`);
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_type TEXT`);
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
await db.execute(`
|
|
90
|
+
CREATE TABLE IF NOT EXISTS vendor_usage_log (
|
|
91
|
+
id TEXT PRIMARY KEY,
|
|
92
|
+
op TEXT,
|
|
93
|
+
probe_run_id TEXT,
|
|
94
|
+
user_id INTEGER,
|
|
95
|
+
vendor TEXT NOT NULL,
|
|
96
|
+
model TEXT,
|
|
97
|
+
units REAL NOT NULL DEFAULT 0,
|
|
98
|
+
unit_type TEXT,
|
|
99
|
+
est_cost_usd REAL NOT NULL DEFAULT 0,
|
|
100
|
+
error TEXT,
|
|
101
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
102
|
+
)
|
|
103
|
+
`);
|
|
104
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_op ON vendor_usage_log(op)`);
|
|
105
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_probe ON vendor_usage_log(probe_run_id)`);
|
|
106
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_created ON vendor_usage_log(created_at)`);
|
|
107
|
+
await db.execute(`
|
|
108
|
+
CREATE TABLE IF NOT EXISTS cost_probe_runs (
|
|
109
|
+
id TEXT PRIMARY KEY,
|
|
110
|
+
tool TEXT NOT NULL,
|
|
111
|
+
target TEXT,
|
|
112
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
113
|
+
wall_ms INTEGER NOT NULL DEFAULT 0,
|
|
114
|
+
success INTEGER NOT NULL DEFAULT 0,
|
|
115
|
+
error TEXT,
|
|
116
|
+
http_only INTEGER NOT NULL DEFAULT 0,
|
|
117
|
+
kernel_used INTEGER NOT NULL DEFAULT 0,
|
|
118
|
+
kernel_sessions INTEGER NOT NULL DEFAULT 0,
|
|
119
|
+
kernel_seconds_total REAL NOT NULL DEFAULT 0,
|
|
120
|
+
kernel_tier_observed TEXT,
|
|
121
|
+
est_kernel_cost_usd_headless REAL NOT NULL DEFAULT 0,
|
|
122
|
+
est_kernel_cost_usd_headful REAL NOT NULL DEFAULT 0,
|
|
123
|
+
vendor_cost_usd REAL NOT NULL DEFAULT 0,
|
|
124
|
+
charged_credits REAL NOT NULL DEFAULT 0,
|
|
125
|
+
margin_usd_headless_starter REAL NOT NULL DEFAULT 0,
|
|
126
|
+
margin_usd_headful_starter REAL NOT NULL DEFAULT 0,
|
|
127
|
+
notes TEXT
|
|
128
|
+
)
|
|
129
|
+
`);
|
|
130
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS cost_probe_runs_tool ON cost_probe_runs(tool)`);
|
|
131
|
+
try {
|
|
132
|
+
await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN units REAL`);
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN unit_type TEXT`);
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN mode TEXT`);
|
|
141
|
+
} catch {
|
|
142
|
+
}
|
|
143
|
+
_ready = true;
|
|
144
|
+
}
|
|
145
|
+
async function recordKernelSession(r) {
|
|
146
|
+
try {
|
|
147
|
+
await migrateCostTelemetry();
|
|
148
|
+
const ctx = currentCostContext();
|
|
149
|
+
const durationMs = Math.max(0, r.closedAtMs - r.openedAtMs);
|
|
150
|
+
const db = getDb();
|
|
151
|
+
await db.execute({
|
|
152
|
+
sql: `INSERT INTO kernel_session_log
|
|
153
|
+
(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)
|
|
154
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
|
|
155
|
+
args: [
|
|
156
|
+
randomUUID(),
|
|
157
|
+
r.kernelSessionId ?? null,
|
|
158
|
+
ctx?.op ?? null,
|
|
159
|
+
r.source,
|
|
160
|
+
ctx?.probeRunId ?? null,
|
|
161
|
+
ctx?.userId ?? null,
|
|
162
|
+
boolToInt(r.stealth),
|
|
163
|
+
boolToInt(r.headlessSent),
|
|
164
|
+
boolToInt(r.proxyUsed),
|
|
165
|
+
r.proxySource ?? null,
|
|
166
|
+
r.proxyType ?? null,
|
|
167
|
+
r.fallback ? 1 : 0,
|
|
168
|
+
new Date(r.openedAtMs).toISOString(),
|
|
169
|
+
new Date(r.closedAtMs).toISOString(),
|
|
170
|
+
durationMs,
|
|
171
|
+
kernelCostUsd(durationMs, false),
|
|
172
|
+
kernelCostUsd(durationMs, true),
|
|
173
|
+
r.error ?? null
|
|
174
|
+
]
|
|
175
|
+
});
|
|
176
|
+
} catch (err) {
|
|
177
|
+
console.warn("[cost-telemetry] recordKernelSession failed:", err instanceof Error ? err.message : String(err));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async function recordVendorUsage(r) {
|
|
181
|
+
try {
|
|
182
|
+
await migrateCostTelemetry();
|
|
183
|
+
const ctx = currentCostContext();
|
|
184
|
+
const db = getDb();
|
|
185
|
+
await db.execute({
|
|
186
|
+
sql: `INSERT INTO vendor_usage_log
|
|
187
|
+
(id, op, probe_run_id, user_id, vendor, model, units, unit_type, est_cost_usd, error)
|
|
188
|
+
VALUES (?,?,?,?,?,?,?,?,?,?)`,
|
|
189
|
+
args: [
|
|
190
|
+
randomUUID(),
|
|
191
|
+
ctx?.op ?? null,
|
|
192
|
+
ctx?.probeRunId ?? null,
|
|
193
|
+
ctx?.userId ?? null,
|
|
194
|
+
r.vendor,
|
|
195
|
+
r.model ?? null,
|
|
196
|
+
r.units,
|
|
197
|
+
r.unitType,
|
|
198
|
+
vendorCostUsd(r.vendor, r.units),
|
|
199
|
+
r.error ?? null
|
|
200
|
+
]
|
|
201
|
+
});
|
|
202
|
+
} catch (err) {
|
|
203
|
+
console.warn("[cost-telemetry] recordVendorUsage failed:", err instanceof Error ? err.message : String(err));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function boolToInt(v) {
|
|
207
|
+
if (v === null || v === void 0) return null;
|
|
208
|
+
return v ? 1 : 0;
|
|
209
|
+
}
|
|
16
210
|
|
|
17
211
|
// src/driver/BrowserDriver.ts
|
|
18
212
|
import { chromium } from "playwright-extra";
|
|
@@ -206,6 +400,12 @@ var BrowserDriver = class {
|
|
|
206
400
|
page = null;
|
|
207
401
|
kernelClient = null;
|
|
208
402
|
kernelSessionId = null;
|
|
403
|
+
kernelOpenedAtMs = null;
|
|
404
|
+
kernelStealth = null;
|
|
405
|
+
kernelProxyUsed = null;
|
|
406
|
+
kernelProxySource = null;
|
|
407
|
+
kernelProxyType = null;
|
|
408
|
+
kernelHeadlessSent = null;
|
|
209
409
|
debugEnabled = false;
|
|
210
410
|
debugSnapshot = {
|
|
211
411
|
kernel: null,
|
|
@@ -237,9 +437,16 @@ var BrowserDriver = class {
|
|
|
237
437
|
if (config.kernelProfileName && config.kernelProfileSaveChanges === true) {
|
|
238
438
|
await ensureKernelProfile(this.kernelClient, config.kernelProfileName);
|
|
239
439
|
}
|
|
440
|
+
const costCtx = currentCostContext();
|
|
441
|
+
let useHeadless;
|
|
442
|
+
if (config.headlessMode === "headful" || costCtx?.forceHeadful === true) useHeadless = false;
|
|
443
|
+
else if (config.headlessMode === "headless") useHeadless = true;
|
|
444
|
+
else useHeadless = costCtx?.forceHeadless === true || process.env.KERNEL_HEADLESS_DISABLED !== "true" && !!costCtx?.op && HEADLESS_OPS.has(costCtx.op);
|
|
445
|
+
this.kernelHeadlessSent = useHeadless ? true : null;
|
|
240
446
|
const kernelBrowser = await this.kernelClient.browsers.create({
|
|
241
447
|
stealth: true,
|
|
242
448
|
timeout_seconds: timeoutSeconds,
|
|
449
|
+
...useHeadless ? { headless: true } : {},
|
|
243
450
|
...config.kernelProxyId ? { proxy_id: config.kernelProxyId } : {},
|
|
244
451
|
...config.kernelProfileName ? {
|
|
245
452
|
profile: {
|
|
@@ -249,9 +456,14 @@ var BrowserDriver = class {
|
|
|
249
456
|
} : {}
|
|
250
457
|
});
|
|
251
458
|
this.kernelSessionId = kernelBrowser.session_id;
|
|
459
|
+
this.kernelOpenedAtMs = Date.now();
|
|
460
|
+
this.kernelStealth = typeof kernelBrowser.stealth === "boolean" ? kernelBrowser.stealth : null;
|
|
461
|
+
this.kernelProxyUsed = typeof kernelBrowser.proxy_id === "string" ? Boolean(kernelBrowser.proxy_id) : Boolean(config.kernelProxyId);
|
|
462
|
+
this.kernelProxySource = config.kernelProxyResolution?.source ?? null;
|
|
463
|
+
this.kernelProxyType = config.kernelProxyResolution?.proxyType ?? null;
|
|
252
464
|
let defaultProxyDisabled = null;
|
|
253
465
|
let defaultProxyDisableError = null;
|
|
254
|
-
if (
|
|
466
|
+
if (!config.kernelProxyId) {
|
|
255
467
|
try {
|
|
256
468
|
await withTimeout(
|
|
257
469
|
this.kernelClient.browsers.update(this.kernelSessionId, { disable_default_proxy: true }),
|
|
@@ -602,11 +814,24 @@ var BrowserDriver = class {
|
|
|
602
814
|
const b = this.browser;
|
|
603
815
|
const sessionId = this.kernelSessionId;
|
|
604
816
|
const client = this.kernelClient;
|
|
817
|
+
const openedAtMs = this.kernelOpenedAtMs;
|
|
818
|
+
const stealth = this.kernelStealth;
|
|
819
|
+
const proxyUsed = this.kernelProxyUsed;
|
|
820
|
+
const proxySource = this.kernelProxySource;
|
|
821
|
+
const proxyType = this.kernelProxyType;
|
|
822
|
+
const headlessSent = this.kernelHeadlessSent;
|
|
605
823
|
this.browser = null;
|
|
606
824
|
this.context = null;
|
|
607
825
|
this.page = null;
|
|
608
826
|
this.kernelSessionId = null;
|
|
609
827
|
this.kernelClient = null;
|
|
828
|
+
this.kernelOpenedAtMs = null;
|
|
829
|
+
this.kernelHeadlessSent = null;
|
|
830
|
+
this.kernelProxySource = null;
|
|
831
|
+
this.kernelProxyType = null;
|
|
832
|
+
if (client && sessionId && openedAtMs != null) {
|
|
833
|
+
void recordKernelSession({ kernelSessionId: sessionId, source: "browser_driver", stealth, headlessSent, proxyUsed, proxySource, proxyType, openedAtMs, closedAtMs: Date.now() });
|
|
834
|
+
}
|
|
610
835
|
if (client && sessionId) {
|
|
611
836
|
console.info(JSON.stringify({
|
|
612
837
|
event: "kernel_browser_delete_started",
|
|
@@ -1321,6 +1546,7 @@ var PAAExtractor = class {
|
|
|
1321
1546
|
);
|
|
1322
1547
|
let round = 0;
|
|
1323
1548
|
while (seenQs.size < options.maxQuestions) {
|
|
1549
|
+
if (options.softDeadlineMs && Date.now() >= options.softDeadlineMs) break;
|
|
1324
1550
|
this.throwIfAborted(signal);
|
|
1325
1551
|
await this.throwIfCaptcha(page, "Google PAA expansion");
|
|
1326
1552
|
const beforeQs = await readAllQs();
|
|
@@ -1330,6 +1556,7 @@ var PAAExtractor = class {
|
|
|
1330
1556
|
if (unexpandedCount === 0) break;
|
|
1331
1557
|
this.reporter.onDepth(++round);
|
|
1332
1558
|
for (let ci = 0; ci < unexpandedCount; ci++) {
|
|
1559
|
+
if (options.softDeadlineMs && Date.now() >= options.softDeadlineMs) break;
|
|
1333
1560
|
this.throwIfAborted(signal);
|
|
1334
1561
|
try {
|
|
1335
1562
|
const btn = page.locator(unexpandedSel).first();
|
|
@@ -2000,6 +2227,7 @@ var OutputSerializer = class {
|
|
|
2000
2227
|
const filename = `${slug}-${Date.now()}.json`;
|
|
2001
2228
|
const fullPath = path.join(outputDir, filename);
|
|
2002
2229
|
await fs.writeFile(fullPath, JSON.stringify(result, null, 2), "utf8");
|
|
2230
|
+
await postToMemoryLibrary({ title: `${result.seed} scrape`, content: JSON.stringify(result), source: `mcp-scraper:${fullPath}` });
|
|
2003
2231
|
return fullPath;
|
|
2004
2232
|
}
|
|
2005
2233
|
async writeCSV(rows, outputDir) {
|
|
@@ -2197,11 +2425,13 @@ function proxyIdSuffix2(proxyId) {
|
|
|
2197
2425
|
return proxyId ? proxyId.slice(-6) : null;
|
|
2198
2426
|
}
|
|
2199
2427
|
function resolution(source, proxyMode, proxyId, target, error, disposable = false) {
|
|
2428
|
+
const proxyType = source === "disabled" ? "none" : source === "configured_fallback" ? "configured" : source === "isp_created" ? "isp" : source === "location_created" || source === "location_reused" ? "residential" : "unknown";
|
|
2200
2429
|
return {
|
|
2201
2430
|
kernelProxyId: proxyId,
|
|
2202
2431
|
...disposable && proxyId ? { disposableProxyId: proxyId } : {},
|
|
2203
2432
|
resolution: {
|
|
2204
2433
|
source,
|
|
2434
|
+
proxyType,
|
|
2205
2435
|
proxyMode,
|
|
2206
2436
|
proxyIdPresent: Boolean(proxyId),
|
|
2207
2437
|
proxyIdSuffix: proxyIdSuffix2(proxyId),
|
|
@@ -2396,6 +2626,22 @@ async function createFreshLocationProxy(kernel, options, target) {
|
|
|
2396
2626
|
createErrors.push(`${candidate.proxyName}: ${errorText2(err)}`);
|
|
2397
2627
|
}
|
|
2398
2628
|
}
|
|
2629
|
+
if (process.env.KERNEL_PROXY_TYPE !== "residential") {
|
|
2630
|
+
const ispTarget = stateTarget(target);
|
|
2631
|
+
try {
|
|
2632
|
+
const created = await kernel.proxies.create({
|
|
2633
|
+
type: "isp",
|
|
2634
|
+
name: freshProxyName(`mcp-serp-isp-${ispTarget.country.toLowerCase()}-${(ispTarget.state ?? "").toLowerCase()}`, options.attemptIndex),
|
|
2635
|
+
config: { country: ispTarget.country, ...ispTarget.state ? { state: ispTarget.state } : {} }
|
|
2636
|
+
});
|
|
2637
|
+
if (created.id) {
|
|
2638
|
+
return resolution("isp_created", options.proxyMode, created.id, ispTarget, null, true);
|
|
2639
|
+
}
|
|
2640
|
+
createErrors.push("isp: Kernel did not return a proxy id");
|
|
2641
|
+
} catch (err) {
|
|
2642
|
+
createErrors.push(`isp: ${errorText2(err)}`);
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2399
2645
|
return resolution("configured_fallback", options.proxyMode, options.configuredKernelProxyId, target, createErrors.join(" | "));
|
|
2400
2646
|
}
|
|
2401
2647
|
async function deleteKernelProxyId(kernelApiKey, proxyId) {
|
|
@@ -2679,9 +2925,11 @@ async function harvest(rawOptions) {
|
|
|
2679
2925
|
};
|
|
2680
2926
|
const requestedDebug = typeof raw.debug === "boolean" ? raw.debug : false;
|
|
2681
2927
|
const needsLocationEvidence = proxyMode === "location" && Boolean(proxyOpts.location);
|
|
2682
|
-
const maxAttempts = maxAttemptsForProxyMode(proxyMode);
|
|
2928
|
+
const maxAttempts = maxAttemptsForProxyMode(proxyMode) + 1;
|
|
2683
2929
|
const serializer = new OutputSerializer();
|
|
2684
2930
|
let lastError = null;
|
|
2931
|
+
let effectiveProxyMode = proxyMode;
|
|
2932
|
+
let proxyFailures = 0;
|
|
2685
2933
|
for (let i = 0; i < maxAttempts; i++) {
|
|
2686
2934
|
const attemptNumber = i + 1;
|
|
2687
2935
|
const startedAtMs = Date.now();
|
|
@@ -2689,18 +2937,19 @@ async function harvest(rawOptions) {
|
|
|
2689
2937
|
if (signal?.aborted) throw abortReason(signal);
|
|
2690
2938
|
const resolution2 = await resolveKernelProxyId({
|
|
2691
2939
|
...proxyOpts,
|
|
2940
|
+
proxyMode: effectiveProxyMode,
|
|
2692
2941
|
attemptIndex: i,
|
|
2693
|
-
fresh:
|
|
2942
|
+
fresh: effectiveProxyMode === "location"
|
|
2694
2943
|
});
|
|
2695
2944
|
const mergedAttempt = {
|
|
2696
2945
|
...raw,
|
|
2697
2946
|
kernelApiKey,
|
|
2698
2947
|
kernelProxyId: resolution2.kernelProxyId,
|
|
2699
2948
|
kernelProxyResolution: resolution2.resolution,
|
|
2700
|
-
proxyMode,
|
|
2949
|
+
proxyMode: effectiveProxyMode,
|
|
2701
2950
|
debug: requestedDebug || needsLocationEvidence
|
|
2702
2951
|
};
|
|
2703
|
-
if (
|
|
2952
|
+
if (effectiveProxyMode === "none") mergedAttempt.kernelProxyId = void 0;
|
|
2704
2953
|
const attemptOptions = HarvestOptionsSchema.parse(mergedAttempt);
|
|
2705
2954
|
await emitAttemptEvent(onAttemptEvent, {
|
|
2706
2955
|
type: "started",
|
|
@@ -2719,10 +2968,17 @@ async function harvest(rawOptions) {
|
|
|
2719
2968
|
location: attemptOptions.location ?? null,
|
|
2720
2969
|
max_questions: attemptOptions.maxQuestions
|
|
2721
2970
|
}));
|
|
2722
|
-
const
|
|
2971
|
+
const isHeadfulEscalation = i === maxAttempts - 1;
|
|
2972
|
+
const needHeadful = isHeadfulEscalation || !attemptOptions.serpOnly;
|
|
2973
|
+
const baseCtx = currentCostContext();
|
|
2974
|
+
const attempt = needHeadful && baseCtx ? await runWithCostContext({ ...baseCtx, forceHeadful: true }, () => extractOnce(attemptOptions, signal)) : await extractOnce(attemptOptions, signal);
|
|
2723
2975
|
if (attempt.error) {
|
|
2724
2976
|
const err = attempt.error;
|
|
2725
2977
|
const outcome = classifyAttemptError(err);
|
|
2978
|
+
if ((outcome === "captcha" || outcome === "proxy_tunnel_failed") && effectiveProxyMode === "location") {
|
|
2979
|
+
proxyFailures++;
|
|
2980
|
+
if (proxyFailures >= 2) effectiveProxyMode = "none";
|
|
2981
|
+
}
|
|
2726
2982
|
const willRetry = i < maxAttempts - 1 && (outcome === "captcha" || proxyMode === "location" && retryableLocationProxyError(outcome));
|
|
2727
2983
|
if (outcome === "captcha") {
|
|
2728
2984
|
console.warn(JSON.stringify({
|
|
@@ -2824,6 +3080,10 @@ async function harvest(rawOptions) {
|
|
|
2824
3080
|
return finalResult;
|
|
2825
3081
|
} catch (err) {
|
|
2826
3082
|
const outcome = classifyAttemptError(err);
|
|
3083
|
+
if ((outcome === "captcha" || outcome === "proxy_tunnel_failed") && effectiveProxyMode === "location") {
|
|
3084
|
+
proxyFailures++;
|
|
3085
|
+
if (proxyFailures >= 2) effectiveProxyMode = "none";
|
|
3086
|
+
}
|
|
2827
3087
|
const willRetry = i < maxAttempts - 1 && (outcome === "captcha" || proxyMode === "location" && retryableLocationProxyError(outcome));
|
|
2828
3088
|
if (outcome === "captcha") {
|
|
2829
3089
|
console.warn(JSON.stringify({
|
|
@@ -2881,10 +3141,15 @@ async function harvest(rawOptions) {
|
|
|
2881
3141
|
|
|
2882
3142
|
export {
|
|
2883
3143
|
MapsSelectors,
|
|
3144
|
+
runWithCostContext,
|
|
3145
|
+
currentCostContext,
|
|
3146
|
+
migrateCostTelemetry,
|
|
3147
|
+
recordKernelSession,
|
|
3148
|
+
recordVendorUsage,
|
|
2884
3149
|
buildYouTubeChannelVideosUrl,
|
|
2885
3150
|
BrowserDriver,
|
|
2886
3151
|
deleteKernelProxyId,
|
|
2887
3152
|
resolveKernelProxyId,
|
|
2888
3153
|
harvest
|
|
2889
3154
|
};
|
|
2890
|
-
//# sourceMappingURL=chunk-
|
|
3155
|
+
//# sourceMappingURL=chunk-G7PQ64LM.js.map
|