mcp-scraper 0.33.6 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/bin/api-server.cjs +13558 -12516
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +3 -3
- package/dist/bin/mcp-scraper-cli.cjs +13 -2
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +14 -4
- package/dist/bin/mcp-scraper-cli.js.map +1 -1
- package/dist/bin/mcp-scraper-install.cjs +2 -2
- 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 +117 -7
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +7 -7
- package/dist/bin/paa-harvest.cjs +128 -13
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +4 -4
- package/dist/{chunk-DUS4ENOY.js → chunk-2EDFOQD7.js} +2 -2
- package/dist/{chunk-DUS4ENOY.js.map → chunk-2EDFOQD7.js.map} +1 -1
- package/dist/{chunk-C2OD4ELT.js → chunk-3HBPKR5G.js} +2 -2
- package/dist/{chunk-A54ELKJK.js → chunk-4KQVIYIH.js} +139 -17
- package/dist/chunk-4KQVIYIH.js.map +1 -0
- package/dist/{chunk-AIK7WQD5.js → chunk-62DQAWPF.js} +141 -3
- package/dist/chunk-62DQAWPF.js.map +1 -0
- package/dist/{chunk-V73MPRU6.js → chunk-CB5C3BPB.js} +17 -1
- package/dist/chunk-CB5C3BPB.js.map +1 -0
- package/dist/{chunk-6ZUK4H66.js → chunk-J32XSMJI.js} +117 -8
- package/dist/chunk-J32XSMJI.js.map +1 -0
- package/dist/{chunk-LKIP7VDN.js → chunk-JBSGBSGT.js} +46 -3
- package/dist/chunk-JBSGBSGT.js.map +1 -0
- package/dist/chunk-NFMIHEYE.js +7 -0
- package/dist/chunk-NFMIHEYE.js.map +1 -0
- package/dist/{chunk-XL6YIWJ3.js → chunk-SUOHUXQS.js} +3 -3
- package/dist/{chunk-WJJTGRK4.js → chunk-V36LS5YV.js} +2 -2
- package/dist/{chunk-AT2PFWHW.js → chunk-ZID3WQID.js} +2 -2
- package/dist/{db-5SZQUI7A.js → db-YAI5AQOI.js} +16 -2
- package/dist/{extract-bundle-YNXTFCC3.js → extract-bundle-GPZRLBVY.js} +2 -2
- package/dist/index.cjs +128 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -4
- package/dist/{server-SHOYO52X.js → server-LKVPEQFE.js} +1386 -778
- package/dist/server-LKVPEQFE.js.map +1 -0
- package/dist/{site-extract-repository-ZDTO7ODZ.js → site-extract-repository-JHMVHENZ.js} +4 -4
- package/dist/{worker-BJ64GCDE.js → worker-ZZHSYI3Y.js} +7 -7
- package/docs/mcp-tool-manifest.generated.json +213 -3
- package/package.json +1 -1
- package/dist/chunk-6ZUK4H66.js.map +0 -1
- package/dist/chunk-A54ELKJK.js.map +0 -1
- package/dist/chunk-AIK7WQD5.js.map +0 -1
- package/dist/chunk-F65IIUHI.js +0 -7
- package/dist/chunk-F65IIUHI.js.map +0 -1
- package/dist/chunk-LKIP7VDN.js.map +0 -1
- package/dist/chunk-V73MPRU6.js.map +0 -1
- package/dist/server-SHOYO52X.js.map +0 -1
- /package/dist/{chunk-C2OD4ELT.js.map → chunk-3HBPKR5G.js.map} +0 -0
- /package/dist/{chunk-XL6YIWJ3.js.map → chunk-SUOHUXQS.js.map} +0 -0
- /package/dist/{chunk-WJJTGRK4.js.map → chunk-V36LS5YV.js.map} +0 -0
- /package/dist/{chunk-AT2PFWHW.js.map → chunk-ZID3WQID.js.map} +0 -0
- /package/dist/{db-5SZQUI7A.js.map → db-YAI5AQOI.js.map} +0 -0
- /package/dist/{extract-bundle-YNXTFCC3.js.map → extract-bundle-GPZRLBVY.js.map} +0 -0
- /package/dist/{site-extract-repository-ZDTO7ODZ.js.map → site-extract-repository-JHMVHENZ.js.map} +0 -0
- /package/dist/{worker-BJ64GCDE.js.map → worker-ZZHSYI3Y.js.map} +0 -0
|
@@ -7,19 +7,19 @@ import {
|
|
|
7
7
|
registerMemoryMcpTools,
|
|
8
8
|
registerPaaExtractorMcpTools,
|
|
9
9
|
registerSerpIntelligenceCaptureTools
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-J32XSMJI.js";
|
|
11
11
|
import "../chunk-R7EETU7Z.js";
|
|
12
|
-
import "../chunk-
|
|
12
|
+
import "../chunk-V36LS5YV.js";
|
|
13
13
|
import {
|
|
14
14
|
renderInstallTerminal
|
|
15
|
-
} from "../chunk-
|
|
16
|
-
import "../chunk-
|
|
15
|
+
} from "../chunk-2EDFOQD7.js";
|
|
16
|
+
import "../chunk-CB5C3BPB.js";
|
|
17
17
|
import {
|
|
18
18
|
PACKAGE_VERSION
|
|
19
|
-
} from "../chunk-
|
|
20
|
-
import "../chunk-
|
|
19
|
+
} from "../chunk-NFMIHEYE.js";
|
|
20
|
+
import "../chunk-JBSGBSGT.js";
|
|
21
21
|
import "../chunk-M2S27J6Z.js";
|
|
22
|
-
import "../chunk-
|
|
22
|
+
import "../chunk-62DQAWPF.js";
|
|
23
23
|
|
|
24
24
|
// bin/mcp-stdio-server.ts
|
|
25
25
|
import { readFileSync } from "fs";
|
package/dist/bin/paa-harvest.cjs
CHANGED
|
@@ -63,8 +63,23 @@ var HarvestOptionsSchema = import_zod.z.object({
|
|
|
63
63
|
format: import_zod.z.enum(["json", "csv", "both"]).default("both"),
|
|
64
64
|
serpOnly: import_zod.z.boolean().default(false),
|
|
65
65
|
pages: import_zod.z.number().int().min(1).max(2).default(1),
|
|
66
|
+
recency: import_zod.z.enum(["day", "week", "month", "year"]).optional(),
|
|
66
67
|
softDeadlineMs: import_zod.z.number().optional()
|
|
67
68
|
});
|
|
69
|
+
function recencyToTbs(recency) {
|
|
70
|
+
switch (recency) {
|
|
71
|
+
case "day":
|
|
72
|
+
return "qdr:d";
|
|
73
|
+
case "week":
|
|
74
|
+
return "qdr:w";
|
|
75
|
+
case "month":
|
|
76
|
+
return "qdr:m";
|
|
77
|
+
case "year":
|
|
78
|
+
return "qdr:y";
|
|
79
|
+
default:
|
|
80
|
+
return void 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
68
83
|
var MapsPlaceOptionsSchema = import_zod.z.object({
|
|
69
84
|
businessName: import_zod.z.string().min(1),
|
|
70
85
|
location: import_zod.z.string().min(1),
|
|
@@ -836,6 +851,7 @@ var BrowserDriver = class {
|
|
|
836
851
|
async navigateToSERP(query, uule, gl, hl, options) {
|
|
837
852
|
const params = new URLSearchParams({ q: query, gl, hl, pws: "0" });
|
|
838
853
|
if (options?.num) params.set("num", String(options.num));
|
|
854
|
+
if (options?.tbs) params.set("tbs", options.tbs);
|
|
839
855
|
if (uule) params.set("uule", uule);
|
|
840
856
|
const url = "https://www.google.com/search?" + params.toString();
|
|
841
857
|
const navUrl = serpArrivalUrl(url);
|
|
@@ -2402,6 +2418,7 @@ var PAAExtractor = class {
|
|
|
2402
2418
|
options.hl,
|
|
2403
2419
|
{
|
|
2404
2420
|
...options.serpOnly ? { num: 100 } : {},
|
|
2421
|
+
...recencyToTbs(options.recency) ? { tbs: recencyToTbs(options.recency) } : {},
|
|
2405
2422
|
debug: options.debug
|
|
2406
2423
|
}
|
|
2407
2424
|
);
|
|
@@ -2421,6 +2438,8 @@ var PAAExtractor = class {
|
|
|
2421
2438
|
let allOrganic2 = organicResults2;
|
|
2422
2439
|
if ((options.pages ?? 1) >= 2) {
|
|
2423
2440
|
const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, pws: "0", start: "10" });
|
|
2441
|
+
if (recencyToTbs(options.recency)) p2params.set("tbs", recencyToTbs(options.recency));
|
|
2442
|
+
if (recencyToTbs(options.recency)) p2params.set("tbs", recencyToTbs(options.recency));
|
|
2424
2443
|
if (uule) p2params.set("uule", uule);
|
|
2425
2444
|
await this.driver.navigateTo("https://www.google.com/search?" + p2params.toString());
|
|
2426
2445
|
await this.throwIfCaptcha(page, "Google SERP page 2");
|
|
@@ -2480,6 +2499,8 @@ var PAAExtractor = class {
|
|
|
2480
2499
|
let locationEvidence2 = initialLocationEvidence;
|
|
2481
2500
|
if ((options.pages ?? 1) >= 2) {
|
|
2482
2501
|
const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, pws: "0", start: "10" });
|
|
2502
|
+
if (recencyToTbs(options.recency)) p2params.set("tbs", recencyToTbs(options.recency));
|
|
2503
|
+
if (recencyToTbs(options.recency)) p2params.set("tbs", recencyToTbs(options.recency));
|
|
2483
2504
|
if (uule) p2params.set("uule", uule);
|
|
2484
2505
|
await this.driver.navigateTo("https://www.google.com/search?" + p2params.toString());
|
|
2485
2506
|
await this.throwIfCaptcha(page, "Google SERP page 2");
|
|
@@ -2546,6 +2567,7 @@ var PAAExtractor = class {
|
|
|
2546
2567
|
let locationEvidence = initialLocationEvidence;
|
|
2547
2568
|
if ((options.pages ?? 1) >= 2) {
|
|
2548
2569
|
const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, pws: "0", start: "10" });
|
|
2570
|
+
if (recencyToTbs(options.recency)) p2params.set("tbs", recencyToTbs(options.recency));
|
|
2549
2571
|
if (uule) p2params.set("uule", uule);
|
|
2550
2572
|
await this.driver.navigateTo("https://www.google.com/search?" + p2params.toString());
|
|
2551
2573
|
await this.throwIfCaptcha(page, "Google SERP page 2");
|
|
@@ -2731,7 +2753,76 @@ var ProgressReporter = class {
|
|
|
2731
2753
|
};
|
|
2732
2754
|
|
|
2733
2755
|
// src/kernel-proxy-resolver.ts
|
|
2756
|
+
var import_sdk3 = __toESM(require("@onkernel/sdk"), 1);
|
|
2757
|
+
|
|
2758
|
+
// src/backup-proxy.ts
|
|
2759
|
+
var import_node_crypto3 = require("crypto");
|
|
2734
2760
|
var import_sdk2 = __toESM(require("@onkernel/sdk"), 1);
|
|
2761
|
+
var BACKUP_PROXY_HOST = "pr.oxylabs.io";
|
|
2762
|
+
var BACKUP_PROXY_PORT = 7777;
|
|
2763
|
+
var BACKUP_STICKY_SESSION_MINUTES = 10;
|
|
2764
|
+
var BACKUP_LAST_RESORT_ATTEMPTS = 2;
|
|
2765
|
+
function backupProxyUsername() {
|
|
2766
|
+
const value = process.env.OXYLABS_USERNAME?.trim();
|
|
2767
|
+
return value || void 0;
|
|
2768
|
+
}
|
|
2769
|
+
function backupProxyPassword() {
|
|
2770
|
+
const value = process.env.OXYLABS_PASSWORD?.trim();
|
|
2771
|
+
return value || void 0;
|
|
2772
|
+
}
|
|
2773
|
+
function backupProxyCountry() {
|
|
2774
|
+
const value = process.env.OXYLABS_COUNTRY?.trim();
|
|
2775
|
+
return (value || "US").toUpperCase();
|
|
2776
|
+
}
|
|
2777
|
+
function backupProxyAvailable() {
|
|
2778
|
+
return Boolean(backupProxyUsername() && backupProxyPassword());
|
|
2779
|
+
}
|
|
2780
|
+
function randomStickySessionId() {
|
|
2781
|
+
let digits = "";
|
|
2782
|
+
for (let i = 0; i < 10; i++) digits += String((0, import_node_crypto3.randomInt)(0, 10));
|
|
2783
|
+
return digits;
|
|
2784
|
+
}
|
|
2785
|
+
function buildBackupUsername(opts = {}) {
|
|
2786
|
+
const user = backupProxyUsername();
|
|
2787
|
+
if (!user) return void 0;
|
|
2788
|
+
const base = user.startsWith("customer-") ? user : `customer-${user}`;
|
|
2789
|
+
const country = (opts.country?.trim() || backupProxyCountry()).toUpperCase();
|
|
2790
|
+
const sticky = opts.sticky ? `-sessid-${randomStickySessionId()}-sesstime-${BACKUP_STICKY_SESSION_MINUTES}` : "";
|
|
2791
|
+
return `${base}-cc-${country}${sticky}`;
|
|
2792
|
+
}
|
|
2793
|
+
function scrubBackupProxyText(message) {
|
|
2794
|
+
return message.replace(/pr\.oxylabs\.io(:\d+)?/gi, "backup proxy").replace(/oxylabs/gi, "backup proxy");
|
|
2795
|
+
}
|
|
2796
|
+
function backupProxyName(attemptIndex) {
|
|
2797
|
+
const stamp = `${Date.now()}-${attemptIndex ?? 0}-${Math.random().toString(36).slice(2, 8)}`;
|
|
2798
|
+
return `mcp-backup-custom-${stamp}`;
|
|
2799
|
+
}
|
|
2800
|
+
async function createBackupProxyId(kernelApiKey, opts = {}) {
|
|
2801
|
+
const username = buildBackupUsername({ sticky: opts.sticky });
|
|
2802
|
+
const password = backupProxyPassword();
|
|
2803
|
+
if (!username || !password) throw new Error("backup proxy pool is not configured");
|
|
2804
|
+
const kernel = new import_sdk2.default({ apiKey: kernelApiKey });
|
|
2805
|
+
try {
|
|
2806
|
+
const created = await kernel.proxies.create({
|
|
2807
|
+
type: "custom",
|
|
2808
|
+
name: backupProxyName(opts.attemptIndex),
|
|
2809
|
+
protocol: "http",
|
|
2810
|
+
config: {
|
|
2811
|
+
host: BACKUP_PROXY_HOST,
|
|
2812
|
+
port: BACKUP_PROXY_PORT,
|
|
2813
|
+
username,
|
|
2814
|
+
password
|
|
2815
|
+
}
|
|
2816
|
+
});
|
|
2817
|
+
if (!created.id) throw new Error("backup proxy creation did not return a proxy id");
|
|
2818
|
+
return created.id;
|
|
2819
|
+
} catch (err) {
|
|
2820
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2821
|
+
throw new Error(scrubBackupProxyText(message));
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
// src/kernel-proxy-resolver.ts
|
|
2735
2826
|
var US_STATE_CODES = {
|
|
2736
2827
|
alabama: "AL",
|
|
2737
2828
|
alaska: "AK",
|
|
@@ -2829,7 +2920,7 @@ function proxyIdSuffix2(proxyId) {
|
|
|
2829
2920
|
return proxyId ? proxyId.slice(-6) : null;
|
|
2830
2921
|
}
|
|
2831
2922
|
function resolution(source, proxyMode, proxyId, target, error, disposable = false) {
|
|
2832
|
-
const proxyType = source === "disabled" ? "none" : source === "configured_fallback" ? "configured" : source === "isp_created" ? "isp" : source === "location_created" || source === "location_reused" ? "residential" : "unknown";
|
|
2923
|
+
const proxyType = source === "disabled" ? "none" : source === "configured_fallback" ? "configured" : source === "isp_created" ? "isp" : source === "backup_custom" ? "custom" : source === "location_created" || source === "location_reused" ? "residential" : "unknown";
|
|
2833
2924
|
return {
|
|
2834
2925
|
kernelProxyId: proxyId,
|
|
2835
2926
|
...disposable && proxyId ? { disposableProxyId: proxyId } : {},
|
|
@@ -3013,6 +3104,26 @@ function freshTargetCandidates(target, explicitZip, attemptIndex) {
|
|
|
3013
3104
|
out.push(withProxyName(fallbackTarget, freshProxyName(fallbackTarget.proxyName, attemptIndex)));
|
|
3014
3105
|
return out;
|
|
3015
3106
|
}
|
|
3107
|
+
async function settleCreateExhaustion(options, target, createErrors) {
|
|
3108
|
+
if (options.backupOnExhaustion && createErrors.length > 0 && options.kernelApiKey && backupProxyAvailable()) {
|
|
3109
|
+
try {
|
|
3110
|
+
const backupId = await createBackupProxyId(options.kernelApiKey, { attemptIndex: options.attemptIndex });
|
|
3111
|
+
return resolution("backup_custom", options.proxyMode, backupId, target, null, true);
|
|
3112
|
+
} catch (err) {
|
|
3113
|
+
createErrors.push(`backup: ${scrubBackupProxyText(errorText2(err))}`);
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
return resolution("configured_fallback", options.proxyMode, options.configuredKernelProxyId, target, createErrors.join(" | "));
|
|
3117
|
+
}
|
|
3118
|
+
async function resolveBackupKernelProxyId(options) {
|
|
3119
|
+
if (!options.kernelApiKey || !backupProxyAvailable()) return null;
|
|
3120
|
+
try {
|
|
3121
|
+
const backupId = await createBackupProxyId(options.kernelApiKey, { attemptIndex: options.attemptIndex });
|
|
3122
|
+
return resolution("backup_custom", options.proxyMode, backupId, null, null, true);
|
|
3123
|
+
} catch {
|
|
3124
|
+
return null;
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3016
3127
|
async function createFreshLocationProxy(kernel, options, target) {
|
|
3017
3128
|
const createErrors = [];
|
|
3018
3129
|
for (const candidate of freshTargetCandidates(target, options.proxyZip, options.attemptIndex)) {
|
|
@@ -3046,11 +3157,11 @@ async function createFreshLocationProxy(kernel, options, target) {
|
|
|
3046
3157
|
createErrors.push(`isp: ${errorText2(err)}`);
|
|
3047
3158
|
}
|
|
3048
3159
|
}
|
|
3049
|
-
return
|
|
3160
|
+
return settleCreateExhaustion(options, target, createErrors);
|
|
3050
3161
|
}
|
|
3051
3162
|
async function deleteKernelProxyId(kernelApiKey, proxyId) {
|
|
3052
3163
|
if (!kernelApiKey || !proxyId) return;
|
|
3053
|
-
const kernel = new
|
|
3164
|
+
const kernel = new import_sdk3.default({ apiKey: kernelApiKey });
|
|
3054
3165
|
await kernel.proxies.delete(proxyId);
|
|
3055
3166
|
}
|
|
3056
3167
|
async function resolveKernelProxyId(options) {
|
|
@@ -3064,7 +3175,7 @@ async function resolveKernelProxyId(options) {
|
|
|
3064
3175
|
if (!target || !options.kernelApiKey) {
|
|
3065
3176
|
return resolution("configured_fallback", options.proxyMode, options.configuredKernelProxyId, target, target ? null : "location could not be normalized to a US city/state proxy target");
|
|
3066
3177
|
}
|
|
3067
|
-
const kernel = new
|
|
3178
|
+
const kernel = new import_sdk3.default({ apiKey: options.kernelApiKey });
|
|
3068
3179
|
try {
|
|
3069
3180
|
const attemptIndex = options.attemptIndex ?? 0;
|
|
3070
3181
|
if (options.fresh) {
|
|
@@ -3086,7 +3197,7 @@ async function resolveKernelProxyId(options) {
|
|
|
3086
3197
|
} catch (err) {
|
|
3087
3198
|
createErrors2.push(`${escalatedTarget.state}: ${errorText2(err)}`);
|
|
3088
3199
|
}
|
|
3089
|
-
return
|
|
3200
|
+
return settleCreateExhaustion(options, escalatedTarget, createErrors2);
|
|
3090
3201
|
}
|
|
3091
3202
|
const proxies = await kernel.proxies.list();
|
|
3092
3203
|
const zip = knownZipFor(target, options.proxyZip);
|
|
@@ -3165,7 +3276,7 @@ async function resolveKernelProxyId(options) {
|
|
|
3165
3276
|
} catch (err) {
|
|
3166
3277
|
createErrors.push(`${fallbackTarget.state}: ${errorText2(err)}`);
|
|
3167
3278
|
}
|
|
3168
|
-
return
|
|
3279
|
+
return settleCreateExhaustion(options, target, createErrors);
|
|
3169
3280
|
} catch (err) {
|
|
3170
3281
|
return resolution("configured_fallback", options.proxyMode, options.configuredKernelProxyId, target, errorText2(err));
|
|
3171
3282
|
}
|
|
@@ -3330,7 +3441,9 @@ async function harvest(rawOptions) {
|
|
|
3330
3441
|
const requestedDebug = typeof raw.debug === "boolean" ? raw.debug : false;
|
|
3331
3442
|
const needsLocationEvidence = proxyMode === "location" && Boolean(proxyOpts.location);
|
|
3332
3443
|
const requestedMaxAttempts = raw.maxAttempts;
|
|
3333
|
-
const
|
|
3444
|
+
const baseMaxAttempts = typeof requestedMaxAttempts === "number" && Number.isInteger(requestedMaxAttempts) && requestedMaxAttempts >= 1 ? requestedMaxAttempts : maxAttemptsForProxyMode(proxyMode) + 1;
|
|
3445
|
+
const maxAttempts = baseMaxAttempts + (backupProxyAvailable() ? BACKUP_LAST_RESORT_ATTEMPTS : 0);
|
|
3446
|
+
const softDeadlineMs = typeof raw.softDeadlineMs === "number" ? raw.softDeadlineMs : null;
|
|
3334
3447
|
const serializer = new OutputSerializer();
|
|
3335
3448
|
let lastError = null;
|
|
3336
3449
|
let effectiveProxyMode = proxyMode;
|
|
@@ -3340,12 +3453,16 @@ async function harvest(rawOptions) {
|
|
|
3340
3453
|
const startedAtMs = Date.now();
|
|
3341
3454
|
try {
|
|
3342
3455
|
if (signal?.aborted) throw abortReason(signal);
|
|
3343
|
-
const
|
|
3456
|
+
const isBackupAttempt = i >= baseMaxAttempts;
|
|
3457
|
+
if (isBackupAttempt && softDeadlineMs !== null && Date.now() >= softDeadlineMs) break;
|
|
3458
|
+
const resolution2 = isBackupAttempt ? await resolveBackupKernelProxyId({ kernelApiKey, proxyMode: effectiveProxyMode, attemptIndex: i }) : await resolveKernelProxyId({
|
|
3344
3459
|
...proxyOpts,
|
|
3345
3460
|
proxyMode: effectiveProxyMode,
|
|
3346
3461
|
attemptIndex: i,
|
|
3347
|
-
fresh: effectiveProxyMode === "location"
|
|
3462
|
+
fresh: effectiveProxyMode === "location",
|
|
3463
|
+
backupOnExhaustion: true
|
|
3348
3464
|
});
|
|
3465
|
+
if (!resolution2) break;
|
|
3349
3466
|
const mergedAttempt = {
|
|
3350
3467
|
...raw,
|
|
3351
3468
|
kernelApiKey,
|
|
@@ -3354,7 +3471,7 @@ async function harvest(rawOptions) {
|
|
|
3354
3471
|
proxyMode: effectiveProxyMode,
|
|
3355
3472
|
debug: requestedDebug || needsLocationEvidence
|
|
3356
3473
|
};
|
|
3357
|
-
if (effectiveProxyMode === "none") mergedAttempt.kernelProxyId = void 0;
|
|
3474
|
+
if (effectiveProxyMode === "none" && !isBackupAttempt) mergedAttempt.kernelProxyId = void 0;
|
|
3358
3475
|
const attemptOptions = HarvestOptionsSchema.parse(mergedAttempt);
|
|
3359
3476
|
await emitAttemptEvent(onAttemptEvent, {
|
|
3360
3477
|
type: "started",
|
|
@@ -3373,10 +3490,8 @@ async function harvest(rawOptions) {
|
|
|
3373
3490
|
location: attemptOptions.location ?? null,
|
|
3374
3491
|
max_questions: attemptOptions.maxQuestions
|
|
3375
3492
|
}));
|
|
3376
|
-
const isHeadfulEscalation = i === maxAttempts - 1;
|
|
3377
|
-
const needHeadful = isHeadfulEscalation || !attemptOptions.serpOnly;
|
|
3378
3493
|
const baseCtx = currentCostContext();
|
|
3379
|
-
const attempt =
|
|
3494
|
+
const attempt = baseCtx ? await runWithCostContext({ ...baseCtx, forceHeadful: true }, () => extractOnce(attemptOptions, signal)) : await extractOnce(attemptOptions, signal);
|
|
3380
3495
|
if (attempt.error) {
|
|
3381
3496
|
const err = attempt.error;
|
|
3382
3497
|
const outcome = classifyAttemptError(err);
|