findweb 0.1.2 → 0.1.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 +7 -6
- package/dist/index.js +323 -157
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ findweb login
|
|
|
42
42
|
|
|
43
43
|
- If the profile is already prepared, search runs immediately.
|
|
44
44
|
- If the profile has not been prepared yet, `findweb` automatically opens the login flow first.
|
|
45
|
-
- After
|
|
45
|
+
- After sign-in is detected, `findweb` saves a local prepared-profile marker and continues automatically.
|
|
46
46
|
- By default, the profile directory is `${XDG_DATA_HOME:-~/.local/share}/findweb/chrome-profile` unless you pass `--userDataDir` or set `GOOGLE_SEARCH_USER_DATA_DIR`.
|
|
47
47
|
|
|
48
48
|
In practice, the first search on a fresh profile behaves like this:
|
|
@@ -53,7 +53,7 @@ findweb "yc"
|
|
|
53
53
|
|
|
54
54
|
1. detect missing prepared-profile marker
|
|
55
55
|
2. open headed Chrome login flow
|
|
56
|
-
3. wait for you to
|
|
56
|
+
3. wait for you to finish signing in
|
|
57
57
|
4. continue the original search
|
|
58
58
|
|
|
59
59
|
## Options
|
|
@@ -72,9 +72,10 @@ findweb "yc"
|
|
|
72
72
|
|
|
73
73
|
1. Launches system Chrome (`/Applications/Google Chrome.app`) with a free debugging port
|
|
74
74
|
2. Connects via CDP using puppeteer-core
|
|
75
|
-
3.
|
|
76
|
-
4.
|
|
77
|
-
5.
|
|
75
|
+
3. Reuses a background headless Chrome for the same profile when available
|
|
76
|
+
4. Loads the [Ghostery adblocker](https://github.com/ghostery/adblocker) engine programmatically on each page
|
|
77
|
+
5. Navigates directly to Google search results and extracts data from the rendered page
|
|
78
|
+
6. Returns results as plain text or JSON, then disconnects from Chrome
|
|
78
79
|
|
|
79
80
|
No Chromium download. No browser extension. No user confirmation.
|
|
80
81
|
|
|
@@ -98,7 +99,7 @@ You can trigger that ahead of time with:
|
|
|
98
99
|
findweb login
|
|
99
100
|
```
|
|
100
101
|
|
|
101
|
-
This opens a visible Chrome window with the Google sign-in page. After
|
|
102
|
+
This opens a visible Chrome window with the Google sign-in page. After sign-in is detected, `findweb` saves the session to the profile directory and records that the profile is ready for future searches.
|
|
102
103
|
|
|
103
104
|
## Output
|
|
104
105
|
|
package/dist/index.js
CHANGED
|
@@ -66517,7 +66517,7 @@ var init_LaunchOptions = __esm(() => {
|
|
|
66517
66517
|
});
|
|
66518
66518
|
|
|
66519
66519
|
// src/index.ts
|
|
66520
|
-
import
|
|
66520
|
+
import process6 from "process";
|
|
66521
66521
|
|
|
66522
66522
|
// node_modules/citty/dist/_chunks/libs/scule.mjs
|
|
66523
66523
|
var NUMBER_CHAR_RE = /\d/;
|
|
@@ -66932,10 +66932,12 @@ async function runMain(cmd, opts = {}) {
|
|
|
66932
66932
|
}
|
|
66933
66933
|
|
|
66934
66934
|
// src/search/browser.ts
|
|
66935
|
+
import fs7 from "fs/promises";
|
|
66935
66936
|
import { spawn as spawn3 } from "child_process";
|
|
66936
66937
|
import http2 from "http";
|
|
66937
66938
|
import os9 from "os";
|
|
66938
66939
|
import path12 from "path";
|
|
66940
|
+
import process3 from "process";
|
|
66939
66941
|
|
|
66940
66942
|
// node_modules/puppeteer-core/lib/esm/puppeteer/api/api.js
|
|
66941
66943
|
init_Browser();
|
|
@@ -76219,9 +76221,42 @@ var puppeteer_core_default = puppeteer;
|
|
|
76219
76221
|
// src/search/browser.ts
|
|
76220
76222
|
var CHROME_BIN = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
|
|
76221
76223
|
var DEFAULT_TIMEOUT_MS = 30000;
|
|
76224
|
+
var CDP_POLL_MS = 100;
|
|
76225
|
+
var REUSABLE_PAGE_URL = "about:blank";
|
|
76222
76226
|
function createDebugServer() {
|
|
76223
76227
|
return http2.createServer();
|
|
76224
76228
|
}
|
|
76229
|
+
function persistentStatePath(userDataDir) {
|
|
76230
|
+
return path12.join(userDataDir, ".findweb-browser.json");
|
|
76231
|
+
}
|
|
76232
|
+
function isProcessRunning(pid) {
|
|
76233
|
+
try {
|
|
76234
|
+
process3.kill(pid, 0);
|
|
76235
|
+
return true;
|
|
76236
|
+
} catch {
|
|
76237
|
+
return false;
|
|
76238
|
+
}
|
|
76239
|
+
}
|
|
76240
|
+
async function readPersistentState(userDataDir) {
|
|
76241
|
+
try {
|
|
76242
|
+
const file = await fs7.readFile(persistentStatePath(userDataDir), "utf8");
|
|
76243
|
+
const parsed = JSON.parse(file);
|
|
76244
|
+
if (typeof parsed.pid !== "number" || typeof parsed.port !== "number") {
|
|
76245
|
+
return null;
|
|
76246
|
+
}
|
|
76247
|
+
return { pid: parsed.pid, port: parsed.port };
|
|
76248
|
+
} catch {
|
|
76249
|
+
return null;
|
|
76250
|
+
}
|
|
76251
|
+
}
|
|
76252
|
+
async function writePersistentState(userDataDir, state) {
|
|
76253
|
+
await fs7.mkdir(userDataDir, { recursive: true });
|
|
76254
|
+
await fs7.writeFile(persistentStatePath(userDataDir), `${JSON.stringify(state)}
|
|
76255
|
+
`, "utf8");
|
|
76256
|
+
}
|
|
76257
|
+
async function clearPersistentState(userDataDir) {
|
|
76258
|
+
await fs7.rm(persistentStatePath(userDataDir), { force: true });
|
|
76259
|
+
}
|
|
76225
76260
|
function wait(delayMs) {
|
|
76226
76261
|
return new Promise((resolve6) => setTimeout(resolve6, delayMs));
|
|
76227
76262
|
}
|
|
@@ -76266,16 +76301,66 @@ async function isCdpReady(port) {
|
|
|
76266
76301
|
async function waitForCdp(port, activeBrowser) {
|
|
76267
76302
|
const deadline = Date.now() + DEFAULT_TIMEOUT_MS;
|
|
76268
76303
|
while (Date.now() < deadline) {
|
|
76269
|
-
if (activeBrowser
|
|
76304
|
+
if (activeBrowser?.exitCode !== null) {
|
|
76270
76305
|
throw new Error(`Chrome exited before opening debugging port ${port}`);
|
|
76271
76306
|
}
|
|
76272
76307
|
if (await isCdpReady(port)) {
|
|
76273
76308
|
return;
|
|
76274
76309
|
}
|
|
76275
|
-
await wait(
|
|
76310
|
+
await wait(CDP_POLL_MS);
|
|
76276
76311
|
}
|
|
76277
76312
|
throw new Error(`Chrome debugging port ${port} did not become ready in time`);
|
|
76278
76313
|
}
|
|
76314
|
+
function reusablePageScore(url) {
|
|
76315
|
+
if (url.startsWith("https://www.google.com/search?")) {
|
|
76316
|
+
return 3;
|
|
76317
|
+
}
|
|
76318
|
+
if (url === REUSABLE_PAGE_URL) {
|
|
76319
|
+
return 2;
|
|
76320
|
+
}
|
|
76321
|
+
if (url.startsWith("https://www.google.com/")) {
|
|
76322
|
+
return 1;
|
|
76323
|
+
}
|
|
76324
|
+
return 0;
|
|
76325
|
+
}
|
|
76326
|
+
async function reusablePage(browser) {
|
|
76327
|
+
const pages = await browser.pages();
|
|
76328
|
+
const existing = pages.filter((page2) => !page2.isClosed()).sort((a, b) => reusablePageScore(b.url()) - reusablePageScore(a.url()))[0] ?? null;
|
|
76329
|
+
if (existing) {
|
|
76330
|
+
return existing;
|
|
76331
|
+
}
|
|
76332
|
+
const page = await browser.newPage().catch(() => null);
|
|
76333
|
+
if (!page) {
|
|
76334
|
+
return null;
|
|
76335
|
+
}
|
|
76336
|
+
await page.goto(REUSABLE_PAGE_URL, { waitUntil: "domcontentloaded" }).catch(() => {
|
|
76337
|
+
return;
|
|
76338
|
+
});
|
|
76339
|
+
return page;
|
|
76340
|
+
}
|
|
76341
|
+
async function connectToBrowser(port) {
|
|
76342
|
+
return puppeteer_core_default.connect({ browserURL: `http://127.0.0.1:${port}` });
|
|
76343
|
+
}
|
|
76344
|
+
async function connectPersistentBrowser(options) {
|
|
76345
|
+
const state = await readPersistentState(options.userDataDir);
|
|
76346
|
+
if (!state || !isProcessRunning(state.pid) || !await isCdpReady(state.port)) {
|
|
76347
|
+
await clearPersistentState(options.userDataDir);
|
|
76348
|
+
return null;
|
|
76349
|
+
}
|
|
76350
|
+
try {
|
|
76351
|
+
const browser = await connectToBrowser(state.port);
|
|
76352
|
+
return {
|
|
76353
|
+
browser,
|
|
76354
|
+
chromeProcess: null,
|
|
76355
|
+
initialPage: await reusablePage(browser),
|
|
76356
|
+
persistent: true,
|
|
76357
|
+
port: state.port
|
|
76358
|
+
};
|
|
76359
|
+
} catch {
|
|
76360
|
+
await clearPersistentState(options.userDataDir);
|
|
76361
|
+
return null;
|
|
76362
|
+
}
|
|
76363
|
+
}
|
|
76279
76364
|
function createChromeArgs(options, port) {
|
|
76280
76365
|
const args = [
|
|
76281
76366
|
`--remote-debugging-port=${port}`,
|
|
@@ -76292,31 +76377,55 @@ function createChromeArgs(options, port) {
|
|
|
76292
76377
|
return args;
|
|
76293
76378
|
}
|
|
76294
76379
|
async function launchSearchBrowser(options) {
|
|
76380
|
+
if (!options.headed) {
|
|
76381
|
+
const activeBrowser = await connectPersistentBrowser(options);
|
|
76382
|
+
if (activeBrowser) {
|
|
76383
|
+
return activeBrowser;
|
|
76384
|
+
}
|
|
76385
|
+
}
|
|
76295
76386
|
const port = await findFreePort();
|
|
76296
76387
|
const chromeProcess = spawn3(CHROME_BIN, createChromeArgs(options, port), {
|
|
76297
|
-
|
|
76388
|
+
detached: !options.headed,
|
|
76389
|
+
stdio: options.headed ? ["ignore", "ignore", "pipe"] : "ignore"
|
|
76298
76390
|
});
|
|
76391
|
+
if (!options.headed) {
|
|
76392
|
+
chromeProcess.unref();
|
|
76393
|
+
}
|
|
76299
76394
|
await waitForCdp(port, chromeProcess);
|
|
76300
|
-
const browser = await
|
|
76301
|
-
|
|
76395
|
+
const browser = await connectToBrowser(port);
|
|
76396
|
+
const initialPage = await reusablePage(browser);
|
|
76397
|
+
if (!options.headed && typeof chromeProcess.pid === "number") {
|
|
76398
|
+
await writePersistentState(options.userDataDir, { pid: chromeProcess.pid, port });
|
|
76399
|
+
}
|
|
76400
|
+
return {
|
|
76401
|
+
browser,
|
|
76402
|
+
chromeProcess,
|
|
76403
|
+
initialPage,
|
|
76404
|
+
persistent: !options.headed,
|
|
76405
|
+
port
|
|
76406
|
+
};
|
|
76302
76407
|
}
|
|
76303
76408
|
async function closeSearchBrowser(activeBrowser) {
|
|
76409
|
+
if (activeBrowser.persistent) {
|
|
76410
|
+
activeBrowser.browser.disconnect();
|
|
76411
|
+
return;
|
|
76412
|
+
}
|
|
76304
76413
|
await activeBrowser.browser.close().catch(() => {
|
|
76305
76414
|
return;
|
|
76306
76415
|
});
|
|
76307
|
-
if (activeBrowser.chromeProcess
|
|
76416
|
+
if (activeBrowser.chromeProcess?.exitCode === null) {
|
|
76308
76417
|
activeBrowser.chromeProcess.kill("SIGTERM");
|
|
76309
76418
|
}
|
|
76310
76419
|
}
|
|
76311
76420
|
function defaultXdgDataHome() {
|
|
76312
|
-
const configured =
|
|
76421
|
+
const configured = process3.env.XDG_DATA_HOME;
|
|
76313
76422
|
if (configured && path12.isAbsolute(configured)) {
|
|
76314
76423
|
return configured;
|
|
76315
76424
|
}
|
|
76316
76425
|
return path12.join(os9.homedir(), ".local", "share");
|
|
76317
76426
|
}
|
|
76318
76427
|
function defaultUserDataDir() {
|
|
76319
|
-
const configured =
|
|
76428
|
+
const configured = process3.env.GOOGLE_SEARCH_USER_DATA_DIR;
|
|
76320
76429
|
if (configured) {
|
|
76321
76430
|
return configured;
|
|
76322
76431
|
}
|
|
@@ -76326,6 +76435,17 @@ function defaultUserDataDir() {
|
|
|
76326
76435
|
// src/search/page.ts
|
|
76327
76436
|
var DEFAULT_TIMEOUT_MS2 = 30000;
|
|
76328
76437
|
var DEFAULT_PWS = "0";
|
|
76438
|
+
var SEARCH_READY_SCRIPT = `(() => {
|
|
76439
|
+
if (window.location.pathname.includes('/sorry/')) {
|
|
76440
|
+
return true;
|
|
76441
|
+
}
|
|
76442
|
+
|
|
76443
|
+
if (document.querySelector('a h3')) {
|
|
76444
|
+
return true;
|
|
76445
|
+
}
|
|
76446
|
+
|
|
76447
|
+
return window.location.pathname === '/search' && document.readyState !== 'loading' && Boolean(document.querySelector('textarea[name="q"], input[name="q"]'));
|
|
76448
|
+
})()`;
|
|
76329
76449
|
function userAgent() {
|
|
76330
76450
|
return [
|
|
76331
76451
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
|
|
@@ -76343,9 +76463,6 @@ function acceptLanguage(lang) {
|
|
|
76343
76463
|
}
|
|
76344
76464
|
return `${lang};q=1.0,en;q=0.8`;
|
|
76345
76465
|
}
|
|
76346
|
-
function createGoogleHomeUrl(lang, gl) {
|
|
76347
|
-
return `https://www.google.com/?hl=${encodeURIComponent(lang)}&gl=${encodeURIComponent(gl)}&pws=${DEFAULT_PWS}`;
|
|
76348
|
-
}
|
|
76349
76466
|
function createGoogleSearchUrl(query, lang, gl) {
|
|
76350
76467
|
return [
|
|
76351
76468
|
"https://www.google.com/search",
|
|
@@ -76355,62 +76472,6 @@ function createGoogleSearchUrl(query, lang, gl) {
|
|
|
76355
76472
|
`&q=${encodeURIComponent(query)}`
|
|
76356
76473
|
].join("");
|
|
76357
76474
|
}
|
|
76358
|
-
function createSubmitSearchScript(query, lang, gl) {
|
|
76359
|
-
return `(() => {
|
|
76360
|
-
const value = ${JSON.stringify(query)};
|
|
76361
|
-
const lang = ${JSON.stringify(lang)};
|
|
76362
|
-
const gl = ${JSON.stringify(gl)};
|
|
76363
|
-
const pws = ${JSON.stringify(DEFAULT_PWS)};
|
|
76364
|
-
const el = document.querySelector('textarea[name="q"], input[name="q"]');
|
|
76365
|
-
if (!el) {
|
|
76366
|
-
throw new Error("Google search input not found");
|
|
76367
|
-
}
|
|
76368
|
-
|
|
76369
|
-
const setHidden = (form, name, hiddenValue) => {
|
|
76370
|
-
let input = form.querySelector('input[name="' + name + '"]');
|
|
76371
|
-
if (!input) {
|
|
76372
|
-
input = document.createElement("input");
|
|
76373
|
-
input.setAttribute("type", "hidden");
|
|
76374
|
-
input.setAttribute("name", name);
|
|
76375
|
-
form.appendChild(input);
|
|
76376
|
-
}
|
|
76377
|
-
input.setAttribute("value", hiddenValue);
|
|
76378
|
-
};
|
|
76379
|
-
|
|
76380
|
-
el.focus();
|
|
76381
|
-
const proto = Object.getPrototypeOf(el);
|
|
76382
|
-
const descriptor = proto ? Object.getOwnPropertyDescriptor(proto, "value") : undefined;
|
|
76383
|
-
if (descriptor && typeof descriptor.set === "function") {
|
|
76384
|
-
descriptor.set.call(el, value);
|
|
76385
|
-
} else {
|
|
76386
|
-
el.value = value;
|
|
76387
|
-
}
|
|
76388
|
-
|
|
76389
|
-
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
76390
|
-
el.dispatchEvent(new Event("change", { bubbles: true }));
|
|
76391
|
-
|
|
76392
|
-
const form = el.form || document.querySelector('form[action="/search"]');
|
|
76393
|
-
if (form && typeof form.requestSubmit === "function") {
|
|
76394
|
-
setHidden(form, "hl", lang);
|
|
76395
|
-
setHidden(form, "gl", gl);
|
|
76396
|
-
setHidden(form, "pws", pws);
|
|
76397
|
-
form.requestSubmit();
|
|
76398
|
-
return;
|
|
76399
|
-
}
|
|
76400
|
-
|
|
76401
|
-
if (form) {
|
|
76402
|
-
const action = new URL(form.getAttribute("action") || "/search", window.location.origin);
|
|
76403
|
-
action.searchParams.set("hl", lang);
|
|
76404
|
-
action.searchParams.set("gl", gl);
|
|
76405
|
-
action.searchParams.set("pws", pws);
|
|
76406
|
-
form.setAttribute("action", action.toString());
|
|
76407
|
-
form.submit();
|
|
76408
|
-
return;
|
|
76409
|
-
}
|
|
76410
|
-
|
|
76411
|
-
window.location.href = ${JSON.stringify(createGoogleSearchUrl(query, lang, gl))};
|
|
76412
|
-
})()`;
|
|
76413
|
-
}
|
|
76414
76475
|
function createExtractResultsScript(limit) {
|
|
76415
76476
|
return `(() => {
|
|
76416
76477
|
const max = ${JSON.stringify(limit)};
|
|
@@ -76459,40 +76520,77 @@ async function preparePage(page, lang) {
|
|
|
76459
76520
|
"accept-language": acceptLanguage(lang)
|
|
76460
76521
|
});
|
|
76461
76522
|
}
|
|
76462
|
-
async function
|
|
76463
|
-
|
|
76464
|
-
|
|
76465
|
-
}
|
|
76466
|
-
|
|
76467
|
-
await
|
|
76468
|
-
page.waitForNavigation({ waitUntil: "networkidle2" }),
|
|
76469
|
-
page.evaluate(createSubmitSearchScript(query, lang, gl))
|
|
76470
|
-
]);
|
|
76523
|
+
async function gotoGoogleSearchResults(page, query, lang, gl) {
|
|
76524
|
+
const searchUrl = createGoogleSearchUrl(query, lang, gl);
|
|
76525
|
+
if (page.url() !== searchUrl) {
|
|
76526
|
+
await page.goto(searchUrl, { waitUntil: "domcontentloaded" });
|
|
76527
|
+
}
|
|
76528
|
+
await page.waitForFunction(SEARCH_READY_SCRIPT, { timeout: DEFAULT_TIMEOUT_MS2 });
|
|
76471
76529
|
}
|
|
76472
76530
|
async function extractResults(page, limit) {
|
|
76473
76531
|
return page.evaluate(createExtractResultsScript(limit));
|
|
76474
76532
|
}
|
|
76475
|
-
async function waitForIdle(page) {
|
|
76476
|
-
await page.waitForNetworkIdle({ idleTime: 700, timeout: DEFAULT_TIMEOUT_MS2 }).catch(() => {
|
|
76477
|
-
return;
|
|
76478
|
-
});
|
|
76479
|
-
}
|
|
76480
76533
|
|
|
76481
76534
|
// src/search/search.ts
|
|
76535
|
+
var LOGIN_POLL_MS = 250;
|
|
76536
|
+
function wait2(delayMs) {
|
|
76537
|
+
return new Promise((resolve6) => setTimeout(resolve6, delayMs));
|
|
76538
|
+
}
|
|
76539
|
+
function hostnameFromUrl(url) {
|
|
76540
|
+
try {
|
|
76541
|
+
return new URL(url).hostname.toLowerCase();
|
|
76542
|
+
} catch {
|
|
76543
|
+
return null;
|
|
76544
|
+
}
|
|
76545
|
+
}
|
|
76546
|
+
function isCompletedLoginUrl(url) {
|
|
76547
|
+
const hostname = hostnameFromUrl(url);
|
|
76548
|
+
return hostname !== null && hostname !== "accounts.google.com" && (hostname === "google.com" || hostname.endsWith(".google.com"));
|
|
76549
|
+
}
|
|
76550
|
+
function hasCompletedLoginPage(urls) {
|
|
76551
|
+
return urls.some((url) => isCompletedLoginUrl(url));
|
|
76552
|
+
}
|
|
76553
|
+
async function pageUrls(browser) {
|
|
76554
|
+
const pages = await browser.pages();
|
|
76555
|
+
return pages.map((page) => page.url());
|
|
76556
|
+
}
|
|
76557
|
+
async function waitForCompletedLogin(loginPage, browser) {
|
|
76558
|
+
let lastSeenUrls = [loginPage.url()];
|
|
76559
|
+
while (true) {
|
|
76560
|
+
if (browser.connected) {
|
|
76561
|
+
lastSeenUrls = await pageUrls(browser).catch(() => lastSeenUrls);
|
|
76562
|
+
if (hasCompletedLoginPage(lastSeenUrls)) {
|
|
76563
|
+
return;
|
|
76564
|
+
}
|
|
76565
|
+
}
|
|
76566
|
+
if (!browser.connected || loginPage.isClosed()) {
|
|
76567
|
+
if (hasCompletedLoginPage(lastSeenUrls)) {
|
|
76568
|
+
return;
|
|
76569
|
+
}
|
|
76570
|
+
throw new Error("Google login was not completed.");
|
|
76571
|
+
}
|
|
76572
|
+
await wait2(LOGIN_POLL_MS);
|
|
76573
|
+
}
|
|
76574
|
+
}
|
|
76482
76575
|
function isSorryPage(url) {
|
|
76483
76576
|
return url.includes("/sorry/");
|
|
76484
76577
|
}
|
|
76485
76578
|
function toErrorMessage(error) {
|
|
76486
76579
|
return error instanceof Error ? error.message : String(error);
|
|
76487
76580
|
}
|
|
76581
|
+
function isInterruptedLoginError(error, loginPage, browser) {
|
|
76582
|
+
if (!browser.connected || loginPage?.isClosed()) {
|
|
76583
|
+
return true;
|
|
76584
|
+
}
|
|
76585
|
+
const message = toErrorMessage(error);
|
|
76586
|
+
return message.includes("Navigating frame was detached") || message.includes("LifecycleWatcher disposed") || message.includes("Target closed") || message.includes("Session closed");
|
|
76587
|
+
}
|
|
76488
76588
|
async function searchQuery(options) {
|
|
76489
|
-
const page = await options.browser.newPage();
|
|
76589
|
+
const page = options.page ?? await options.browser.newPage();
|
|
76490
76590
|
try {
|
|
76491
76591
|
await preparePage(page, options.lang);
|
|
76492
76592
|
await options.blocker.enableBlockingInPage(page);
|
|
76493
|
-
await
|
|
76494
|
-
await waitForIdle(page);
|
|
76495
|
-
await submitSearch(page, options.query, options.lang, options.gl);
|
|
76593
|
+
await gotoGoogleSearchResults(page, options.query, options.lang, options.gl);
|
|
76496
76594
|
if (isSorryPage(page.url())) {
|
|
76497
76595
|
throw new Error("Google returned a /sorry/ page for this profile/IP. Re-run later or use a logged-in profile.");
|
|
76498
76596
|
}
|
|
@@ -76501,9 +76599,28 @@ async function searchQuery(options) {
|
|
|
76501
76599
|
await options.blocker.disableBlockingInPage(page).catch(() => {
|
|
76502
76600
|
return;
|
|
76503
76601
|
});
|
|
76504
|
-
|
|
76505
|
-
|
|
76602
|
+
if (!options.keepOpen) {
|
|
76603
|
+
await page.close().catch(() => {
|
|
76604
|
+
return;
|
|
76605
|
+
});
|
|
76606
|
+
}
|
|
76607
|
+
}
|
|
76608
|
+
}
|
|
76609
|
+
async function runSingleQuery(browser, options) {
|
|
76610
|
+
try {
|
|
76611
|
+
const results = await searchQuery({
|
|
76612
|
+
blocker: options.blocker,
|
|
76613
|
+
browser,
|
|
76614
|
+
gl: options.gl,
|
|
76615
|
+
keepOpen: Boolean(options.page),
|
|
76616
|
+
lang: options.lang,
|
|
76617
|
+
num: options.num,
|
|
76618
|
+
page: options.page ?? undefined,
|
|
76619
|
+
query: options.query
|
|
76506
76620
|
});
|
|
76621
|
+
return { error: null, query: options.query, results };
|
|
76622
|
+
} catch (error) {
|
|
76623
|
+
return { error: toErrorMessage(error), query: options.query, results: [] };
|
|
76507
76624
|
}
|
|
76508
76625
|
}
|
|
76509
76626
|
async function runBatchWorker(browser, options) {
|
|
@@ -76529,51 +76646,76 @@ async function runBatchWorker(browser, options) {
|
|
|
76529
76646
|
}
|
|
76530
76647
|
}
|
|
76531
76648
|
}
|
|
76532
|
-
async function searchQueriesInTabs(browser, blocker, queries, options) {
|
|
76649
|
+
async function searchQueriesInTabs(browser, blocker, queries, options, initialPage = null) {
|
|
76533
76650
|
const concurrency = Math.max(1, Math.min(options.parallel, queries.length));
|
|
76534
76651
|
const results = new Array(queries.length);
|
|
76535
76652
|
const cursor = { value: 0 };
|
|
76536
|
-
|
|
76653
|
+
const initialTask = initialPage && queries[0] ? runSingleQuery(browser, {
|
|
76537
76654
|
blocker,
|
|
76538
|
-
cursor,
|
|
76539
76655
|
gl: options.gl,
|
|
76540
76656
|
lang: options.lang,
|
|
76541
76657
|
num: options.num,
|
|
76658
|
+
page: initialPage,
|
|
76542
76659
|
parallel: options.parallel,
|
|
76543
|
-
queries
|
|
76544
|
-
|
|
76545
|
-
|
|
76660
|
+
query: queries[0]
|
|
76661
|
+
}).then((outcome) => {
|
|
76662
|
+
results[0] = outcome;
|
|
76663
|
+
}) : null;
|
|
76664
|
+
cursor.value = initialTask ? 1 : 0;
|
|
76665
|
+
await Promise.all([
|
|
76666
|
+
...initialTask ? [initialTask] : [],
|
|
76667
|
+
...Array.from({ length: Math.max(0, concurrency - (initialTask ? 1 : 0)) }, () => runBatchWorker(browser, {
|
|
76668
|
+
blocker,
|
|
76669
|
+
cursor,
|
|
76670
|
+
gl: options.gl,
|
|
76671
|
+
lang: options.lang,
|
|
76672
|
+
num: options.num,
|
|
76673
|
+
parallel: options.parallel,
|
|
76674
|
+
queries,
|
|
76675
|
+
results
|
|
76676
|
+
}))
|
|
76677
|
+
]);
|
|
76546
76678
|
return results;
|
|
76547
76679
|
}
|
|
76548
76680
|
async function runLoginSession(options) {
|
|
76549
|
-
|
|
76550
|
-
|
|
76551
|
-
|
|
76552
|
-
|
|
76553
|
-
const done = () => resolve6();
|
|
76554
|
-
options.browser.once("disconnected", done);
|
|
76555
|
-
process.once("SIGINT", async () => {
|
|
76556
|
-
await options.browser.close().catch(() => {
|
|
76557
|
-
return;
|
|
76558
|
-
});
|
|
76559
|
-
done();
|
|
76681
|
+
let loginPage = null;
|
|
76682
|
+
const handleSigint = () => {
|
|
76683
|
+
options.browser.close().catch(() => {
|
|
76684
|
+
return;
|
|
76560
76685
|
});
|
|
76561
|
-
}
|
|
76686
|
+
};
|
|
76687
|
+
process.once("SIGINT", handleSigint);
|
|
76688
|
+
try {
|
|
76689
|
+
loginPage = await options.browser.newPage();
|
|
76690
|
+
await preparePage(loginPage, options.lang);
|
|
76691
|
+
await loginPage.goto(`https://accounts.google.com/ServiceLogin?continue=${encodeURIComponent(`https://www.google.com/?hl=${options.lang}&gl=${options.gl}&pws=0`)}&hl=${encodeURIComponent(options.lang)}`, { waitUntil: "networkidle2" });
|
|
76692
|
+
await waitForCompletedLogin(loginPage, options.browser);
|
|
76693
|
+
} catch (error) {
|
|
76694
|
+
if (isInterruptedLoginError(error, loginPage, options.browser)) {
|
|
76695
|
+
throw new Error("Google login was not completed.");
|
|
76696
|
+
}
|
|
76697
|
+
throw error;
|
|
76698
|
+
} finally {
|
|
76699
|
+
process.off("SIGINT", handleSigint);
|
|
76700
|
+
await loginPage?.close().catch(() => {
|
|
76701
|
+
return;
|
|
76702
|
+
});
|
|
76703
|
+
}
|
|
76562
76704
|
}
|
|
76563
76705
|
|
|
76564
76706
|
// src/cli/profile.ts
|
|
76565
|
-
import
|
|
76707
|
+
import fs8 from "fs/promises";
|
|
76566
76708
|
import path13 from "path";
|
|
76567
76709
|
var PROFILE_READY_MARKER = ".findweb-profile-ready";
|
|
76568
76710
|
async function ensureProfileDir(dirPath) {
|
|
76569
|
-
await
|
|
76711
|
+
await fs8.mkdir(dirPath, { recursive: true });
|
|
76570
76712
|
}
|
|
76571
76713
|
function readyMarkerPath(userDataDir) {
|
|
76572
76714
|
return path13.join(userDataDir, PROFILE_READY_MARKER);
|
|
76573
76715
|
}
|
|
76574
76716
|
async function hasPreparedProfile(userDataDir) {
|
|
76575
76717
|
try {
|
|
76576
|
-
await
|
|
76718
|
+
await fs8.access(readyMarkerPath(userDataDir));
|
|
76577
76719
|
return true;
|
|
76578
76720
|
} catch {
|
|
76579
76721
|
return false;
|
|
@@ -76581,15 +76723,15 @@ async function hasPreparedProfile(userDataDir) {
|
|
|
76581
76723
|
}
|
|
76582
76724
|
async function markProfilePrepared(userDataDir) {
|
|
76583
76725
|
await ensureProfileDir(userDataDir);
|
|
76584
|
-
await
|
|
76726
|
+
await fs8.writeFile(readyMarkerPath(userDataDir), `${new Date().toISOString()}
|
|
76585
76727
|
`, "utf8");
|
|
76586
76728
|
}
|
|
76587
76729
|
|
|
76588
76730
|
// src/cli/flows/login.ts
|
|
76589
76731
|
function printLoginInstructions(userDataDir) {
|
|
76590
76732
|
console.log(`Login browser launched with profile: ${userDataDir}`);
|
|
76591
|
-
console.log("
|
|
76592
|
-
console.log("
|
|
76733
|
+
console.log("Complete Google sign-in to prepare this profile for future searches.");
|
|
76734
|
+
console.log("The session is saved automatically once sign-in is detected.");
|
|
76593
76735
|
}
|
|
76594
76736
|
async function runInteractiveLoginFlow(options) {
|
|
76595
76737
|
await ensureProfileDir(options.userDataDir);
|
|
@@ -76881,7 +77023,7 @@ __export(exports_core2, {
|
|
|
76881
77023
|
safeDecode: () => safeDecode,
|
|
76882
77024
|
registry: () => registry,
|
|
76883
77025
|
regexes: () => exports_regexes,
|
|
76884
|
-
process: () =>
|
|
77026
|
+
process: () => process4,
|
|
76885
77027
|
prettifyError: () => prettifyError,
|
|
76886
77028
|
parseAsync: () => parseAsync,
|
|
76887
77029
|
parse: () => parse,
|
|
@@ -87345,7 +87487,7 @@ function initializeContext(params) {
|
|
|
87345
87487
|
external: params?.external ?? undefined
|
|
87346
87488
|
};
|
|
87347
87489
|
}
|
|
87348
|
-
function
|
|
87490
|
+
function process4(schema, ctx, _params = { path: [], schemaPath: [] }) {
|
|
87349
87491
|
var _a5;
|
|
87350
87492
|
const def = schema._zod.def;
|
|
87351
87493
|
const seen = ctx.seen.get(schema);
|
|
@@ -87382,7 +87524,7 @@ function process3(schema, ctx, _params = { path: [], schemaPath: [] }) {
|
|
|
87382
87524
|
if (parent) {
|
|
87383
87525
|
if (!result.ref)
|
|
87384
87526
|
result.ref = parent;
|
|
87385
|
-
|
|
87527
|
+
process4(parent, ctx, params);
|
|
87386
87528
|
ctx.seen.get(parent).isParent = true;
|
|
87387
87529
|
}
|
|
87388
87530
|
}
|
|
@@ -87658,14 +87800,14 @@ function isTransforming(_schema, _ctx) {
|
|
|
87658
87800
|
}
|
|
87659
87801
|
var createToJSONSchemaMethod = (schema, processors = {}) => (params) => {
|
|
87660
87802
|
const ctx = initializeContext({ ...params, processors });
|
|
87661
|
-
|
|
87803
|
+
process4(schema, ctx);
|
|
87662
87804
|
extractDefs(ctx, schema);
|
|
87663
87805
|
return finalize(ctx, schema);
|
|
87664
87806
|
};
|
|
87665
87807
|
var createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => {
|
|
87666
87808
|
const { libraryOptions, target } = params ?? {};
|
|
87667
87809
|
const ctx = initializeContext({ ...libraryOptions ?? {}, target, io, processors });
|
|
87668
|
-
|
|
87810
|
+
process4(schema, ctx);
|
|
87669
87811
|
extractDefs(ctx, schema);
|
|
87670
87812
|
return finalize(ctx, schema);
|
|
87671
87813
|
};
|
|
@@ -87916,7 +88058,7 @@ var arrayProcessor = (schema, ctx, _json, params) => {
|
|
|
87916
88058
|
if (typeof maximum === "number")
|
|
87917
88059
|
json.maxItems = maximum;
|
|
87918
88060
|
json.type = "array";
|
|
87919
|
-
json.items =
|
|
88061
|
+
json.items = process4(def.element, ctx, { ...params, path: [...params.path, "items"] });
|
|
87920
88062
|
};
|
|
87921
88063
|
var objectProcessor = (schema, ctx, _json, params) => {
|
|
87922
88064
|
const json = _json;
|
|
@@ -87925,7 +88067,7 @@ var objectProcessor = (schema, ctx, _json, params) => {
|
|
|
87925
88067
|
json.properties = {};
|
|
87926
88068
|
const shape = def.shape;
|
|
87927
88069
|
for (const key in shape) {
|
|
87928
|
-
json.properties[key] =
|
|
88070
|
+
json.properties[key] = process4(shape[key], ctx, {
|
|
87929
88071
|
...params,
|
|
87930
88072
|
path: [...params.path, "properties", key]
|
|
87931
88073
|
});
|
|
@@ -87948,7 +88090,7 @@ var objectProcessor = (schema, ctx, _json, params) => {
|
|
|
87948
88090
|
if (ctx.io === "output")
|
|
87949
88091
|
json.additionalProperties = false;
|
|
87950
88092
|
} else if (def.catchall) {
|
|
87951
|
-
json.additionalProperties =
|
|
88093
|
+
json.additionalProperties = process4(def.catchall, ctx, {
|
|
87952
88094
|
...params,
|
|
87953
88095
|
path: [...params.path, "additionalProperties"]
|
|
87954
88096
|
});
|
|
@@ -87957,7 +88099,7 @@ var objectProcessor = (schema, ctx, _json, params) => {
|
|
|
87957
88099
|
var unionProcessor = (schema, ctx, json, params) => {
|
|
87958
88100
|
const def = schema._zod.def;
|
|
87959
88101
|
const isExclusive = def.inclusive === false;
|
|
87960
|
-
const options = def.options.map((x, i) =>
|
|
88102
|
+
const options = def.options.map((x, i) => process4(x, ctx, {
|
|
87961
88103
|
...params,
|
|
87962
88104
|
path: [...params.path, isExclusive ? "oneOf" : "anyOf", i]
|
|
87963
88105
|
}));
|
|
@@ -87969,11 +88111,11 @@ var unionProcessor = (schema, ctx, json, params) => {
|
|
|
87969
88111
|
};
|
|
87970
88112
|
var intersectionProcessor = (schema, ctx, json, params) => {
|
|
87971
88113
|
const def = schema._zod.def;
|
|
87972
|
-
const a =
|
|
88114
|
+
const a = process4(def.left, ctx, {
|
|
87973
88115
|
...params,
|
|
87974
88116
|
path: [...params.path, "allOf", 0]
|
|
87975
88117
|
});
|
|
87976
|
-
const b =
|
|
88118
|
+
const b = process4(def.right, ctx, {
|
|
87977
88119
|
...params,
|
|
87978
88120
|
path: [...params.path, "allOf", 1]
|
|
87979
88121
|
});
|
|
@@ -87990,11 +88132,11 @@ var tupleProcessor = (schema, ctx, _json, params) => {
|
|
|
87990
88132
|
json.type = "array";
|
|
87991
88133
|
const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
|
|
87992
88134
|
const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
|
|
87993
|
-
const prefixItems = def.items.map((x, i) =>
|
|
88135
|
+
const prefixItems = def.items.map((x, i) => process4(x, ctx, {
|
|
87994
88136
|
...params,
|
|
87995
88137
|
path: [...params.path, prefixPath, i]
|
|
87996
88138
|
}));
|
|
87997
|
-
const rest = def.rest ?
|
|
88139
|
+
const rest = def.rest ? process4(def.rest, ctx, {
|
|
87998
88140
|
...params,
|
|
87999
88141
|
path: [...params.path, restPath, ...ctx.target === "openapi-3.0" ? [def.items.length] : []]
|
|
88000
88142
|
}) : null;
|
|
@@ -88034,7 +88176,7 @@ var recordProcessor = (schema, ctx, _json, params) => {
|
|
|
88034
88176
|
const keyBag = keyType._zod.bag;
|
|
88035
88177
|
const patterns = keyBag?.patterns;
|
|
88036
88178
|
if (def.mode === "loose" && patterns && patterns.size > 0) {
|
|
88037
|
-
const valueSchema =
|
|
88179
|
+
const valueSchema = process4(def.valueType, ctx, {
|
|
88038
88180
|
...params,
|
|
88039
88181
|
path: [...params.path, "patternProperties", "*"]
|
|
88040
88182
|
});
|
|
@@ -88044,12 +88186,12 @@ var recordProcessor = (schema, ctx, _json, params) => {
|
|
|
88044
88186
|
}
|
|
88045
88187
|
} else {
|
|
88046
88188
|
if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
|
|
88047
|
-
json.propertyNames =
|
|
88189
|
+
json.propertyNames = process4(def.keyType, ctx, {
|
|
88048
88190
|
...params,
|
|
88049
88191
|
path: [...params.path, "propertyNames"]
|
|
88050
88192
|
});
|
|
88051
88193
|
}
|
|
88052
|
-
json.additionalProperties =
|
|
88194
|
+
json.additionalProperties = process4(def.valueType, ctx, {
|
|
88053
88195
|
...params,
|
|
88054
88196
|
path: [...params.path, "additionalProperties"]
|
|
88055
88197
|
});
|
|
@@ -88064,7 +88206,7 @@ var recordProcessor = (schema, ctx, _json, params) => {
|
|
|
88064
88206
|
};
|
|
88065
88207
|
var nullableProcessor = (schema, ctx, json, params) => {
|
|
88066
88208
|
const def = schema._zod.def;
|
|
88067
|
-
const inner =
|
|
88209
|
+
const inner = process4(def.innerType, ctx, params);
|
|
88068
88210
|
const seen = ctx.seen.get(schema);
|
|
88069
88211
|
if (ctx.target === "openapi-3.0") {
|
|
88070
88212
|
seen.ref = def.innerType;
|
|
@@ -88075,20 +88217,20 @@ var nullableProcessor = (schema, ctx, json, params) => {
|
|
|
88075
88217
|
};
|
|
88076
88218
|
var nonoptionalProcessor = (schema, ctx, _json, params) => {
|
|
88077
88219
|
const def = schema._zod.def;
|
|
88078
|
-
|
|
88220
|
+
process4(def.innerType, ctx, params);
|
|
88079
88221
|
const seen = ctx.seen.get(schema);
|
|
88080
88222
|
seen.ref = def.innerType;
|
|
88081
88223
|
};
|
|
88082
88224
|
var defaultProcessor = (schema, ctx, json, params) => {
|
|
88083
88225
|
const def = schema._zod.def;
|
|
88084
|
-
|
|
88226
|
+
process4(def.innerType, ctx, params);
|
|
88085
88227
|
const seen = ctx.seen.get(schema);
|
|
88086
88228
|
seen.ref = def.innerType;
|
|
88087
88229
|
json.default = JSON.parse(JSON.stringify(def.defaultValue));
|
|
88088
88230
|
};
|
|
88089
88231
|
var prefaultProcessor = (schema, ctx, json, params) => {
|
|
88090
88232
|
const def = schema._zod.def;
|
|
88091
|
-
|
|
88233
|
+
process4(def.innerType, ctx, params);
|
|
88092
88234
|
const seen = ctx.seen.get(schema);
|
|
88093
88235
|
seen.ref = def.innerType;
|
|
88094
88236
|
if (ctx.io === "input")
|
|
@@ -88096,7 +88238,7 @@ var prefaultProcessor = (schema, ctx, json, params) => {
|
|
|
88096
88238
|
};
|
|
88097
88239
|
var catchProcessor = (schema, ctx, json, params) => {
|
|
88098
88240
|
const def = schema._zod.def;
|
|
88099
|
-
|
|
88241
|
+
process4(def.innerType, ctx, params);
|
|
88100
88242
|
const seen = ctx.seen.get(schema);
|
|
88101
88243
|
seen.ref = def.innerType;
|
|
88102
88244
|
let catchValue;
|
|
@@ -88110,32 +88252,32 @@ var catchProcessor = (schema, ctx, json, params) => {
|
|
|
88110
88252
|
var pipeProcessor = (schema, ctx, _json, params) => {
|
|
88111
88253
|
const def = schema._zod.def;
|
|
88112
88254
|
const innerType = ctx.io === "input" ? def.in._zod.def.type === "transform" ? def.out : def.in : def.out;
|
|
88113
|
-
|
|
88255
|
+
process4(innerType, ctx, params);
|
|
88114
88256
|
const seen = ctx.seen.get(schema);
|
|
88115
88257
|
seen.ref = innerType;
|
|
88116
88258
|
};
|
|
88117
88259
|
var readonlyProcessor = (schema, ctx, json, params) => {
|
|
88118
88260
|
const def = schema._zod.def;
|
|
88119
|
-
|
|
88261
|
+
process4(def.innerType, ctx, params);
|
|
88120
88262
|
const seen = ctx.seen.get(schema);
|
|
88121
88263
|
seen.ref = def.innerType;
|
|
88122
88264
|
json.readOnly = true;
|
|
88123
88265
|
};
|
|
88124
88266
|
var promiseProcessor = (schema, ctx, _json, params) => {
|
|
88125
88267
|
const def = schema._zod.def;
|
|
88126
|
-
|
|
88268
|
+
process4(def.innerType, ctx, params);
|
|
88127
88269
|
const seen = ctx.seen.get(schema);
|
|
88128
88270
|
seen.ref = def.innerType;
|
|
88129
88271
|
};
|
|
88130
88272
|
var optionalProcessor = (schema, ctx, _json, params) => {
|
|
88131
88273
|
const def = schema._zod.def;
|
|
88132
|
-
|
|
88274
|
+
process4(def.innerType, ctx, params);
|
|
88133
88275
|
const seen = ctx.seen.get(schema);
|
|
88134
88276
|
seen.ref = def.innerType;
|
|
88135
88277
|
};
|
|
88136
88278
|
var lazyProcessor = (schema, ctx, _json, params) => {
|
|
88137
88279
|
const innerType = schema._zod.innerType;
|
|
88138
|
-
|
|
88280
|
+
process4(innerType, ctx, params);
|
|
88139
88281
|
const seen = ctx.seen.get(schema);
|
|
88140
88282
|
seen.ref = innerType;
|
|
88141
88283
|
};
|
|
@@ -88187,7 +88329,7 @@ function toJSONSchema(input2, params) {
|
|
|
88187
88329
|
const defs = {};
|
|
88188
88330
|
for (const entry of registry2._idmap.entries()) {
|
|
88189
88331
|
const [_2, schema] = entry;
|
|
88190
|
-
|
|
88332
|
+
process4(schema, ctx2);
|
|
88191
88333
|
}
|
|
88192
88334
|
const schemas = {};
|
|
88193
88335
|
const external = {
|
|
@@ -88210,7 +88352,7 @@ function toJSONSchema(input2, params) {
|
|
|
88210
88352
|
return { schemas };
|
|
88211
88353
|
}
|
|
88212
88354
|
const ctx = initializeContext({ ...params, processors: allProcessors });
|
|
88213
|
-
|
|
88355
|
+
process4(input2, ctx);
|
|
88214
88356
|
extractDefs(ctx, input2);
|
|
88215
88357
|
return finalize(ctx, input2);
|
|
88216
88358
|
}
|
|
@@ -88256,7 +88398,7 @@ class JSONSchemaGenerator {
|
|
|
88256
88398
|
});
|
|
88257
88399
|
}
|
|
88258
88400
|
process(schema, _params = { path: [], schemaPath: [] }) {
|
|
88259
|
-
return
|
|
88401
|
+
return process4(schema, this.ctx, _params);
|
|
88260
88402
|
}
|
|
88261
88403
|
emit(schema, _params) {
|
|
88262
88404
|
if (_params) {
|
|
@@ -90229,6 +90371,10 @@ function createLoginArgs() {
|
|
|
90229
90371
|
}
|
|
90230
90372
|
};
|
|
90231
90373
|
}
|
|
90374
|
+
function printCommandError(error48) {
|
|
90375
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
90376
|
+
console.error(`ERROR: ${message}`);
|
|
90377
|
+
}
|
|
90232
90378
|
async function runLogin(args) {
|
|
90233
90379
|
const options = normalizeLoginOptions({
|
|
90234
90380
|
gl: typeof args.gl === "string" ? args.gl : undefined,
|
|
@@ -90242,20 +90388,25 @@ function createLoginCommand(commandName = "findweb login") {
|
|
|
90242
90388
|
meta: { name: commandName, description: "Open a reusable Google sign-in session." },
|
|
90243
90389
|
args: createLoginArgs(),
|
|
90244
90390
|
async run({ args }) {
|
|
90245
|
-
|
|
90246
|
-
|
|
90247
|
-
|
|
90248
|
-
|
|
90249
|
-
|
|
90391
|
+
try {
|
|
90392
|
+
await runLogin({
|
|
90393
|
+
gl: args.gl,
|
|
90394
|
+
lang: args.lang,
|
|
90395
|
+
userDataDir: args.userDataDir
|
|
90396
|
+
});
|
|
90397
|
+
} catch (error48) {
|
|
90398
|
+
printCommandError(error48);
|
|
90399
|
+
process.exitCode = 1;
|
|
90400
|
+
}
|
|
90250
90401
|
}
|
|
90251
90402
|
});
|
|
90252
90403
|
}
|
|
90253
90404
|
|
|
90254
90405
|
// src/cli/commands/search.ts
|
|
90255
|
-
import
|
|
90406
|
+
import process5 from "process";
|
|
90256
90407
|
|
|
90257
90408
|
// src/search/blocker.ts
|
|
90258
|
-
import
|
|
90409
|
+
import fs9 from "fs/promises";
|
|
90259
90410
|
import os10 from "os";
|
|
90260
90411
|
import path15 from "path";
|
|
90261
90412
|
|
|
@@ -101317,17 +101468,17 @@ function defaultCacheDir() {
|
|
|
101317
101468
|
return process.env.GOOGLE_SEARCH_CACHE_DIR ?? path15.join(os10.homedir(), ".cache", "google-search");
|
|
101318
101469
|
}
|
|
101319
101470
|
async function readCache(filePath) {
|
|
101320
|
-
return
|
|
101471
|
+
return fs9.readFile(filePath);
|
|
101321
101472
|
}
|
|
101322
101473
|
async function writeCache(filePath, buffer) {
|
|
101323
|
-
await
|
|
101324
|
-
await
|
|
101474
|
+
await fs9.mkdir(path15.dirname(filePath), { recursive: true });
|
|
101475
|
+
await fs9.writeFile(filePath, buffer);
|
|
101325
101476
|
}
|
|
101326
101477
|
async function loadBlocker() {
|
|
101327
101478
|
if (!blockerPromise) {
|
|
101328
101479
|
blockerPromise = (async () => {
|
|
101329
101480
|
const cacheDir = defaultCacheDir();
|
|
101330
|
-
await
|
|
101481
|
+
await fs9.mkdir(cacheDir, { recursive: true });
|
|
101331
101482
|
return PuppeteerBlocker.fromPrebuiltAdsAndTracking(globalThis.fetch.bind(globalThis), {
|
|
101332
101483
|
path: path15.join(cacheDir, "ghostery-engine.bin"),
|
|
101333
101484
|
read: readCache,
|
|
@@ -101432,6 +101583,10 @@ var searchArgs = {
|
|
|
101432
101583
|
description: "Print JSON output"
|
|
101433
101584
|
}
|
|
101434
101585
|
};
|
|
101586
|
+
function printCommandError2(error49) {
|
|
101587
|
+
const message = error49 instanceof Error ? error49.message : String(error49);
|
|
101588
|
+
console.error(`ERROR: ${message}`);
|
|
101589
|
+
}
|
|
101435
101590
|
async function runSearch(args) {
|
|
101436
101591
|
const options = normalizeSearchOptions({
|
|
101437
101592
|
_: args._,
|
|
@@ -101465,9 +101620,9 @@ async function runSearch(args) {
|
|
|
101465
101620
|
lang: options.lang,
|
|
101466
101621
|
num: options.num,
|
|
101467
101622
|
parallel: options.parallel
|
|
101468
|
-
});
|
|
101623
|
+
}, activeBrowser.initialPage);
|
|
101469
101624
|
printResults(options.json, outcomes);
|
|
101470
|
-
|
|
101625
|
+
process5.exitCode = exitCodeForOutcomes(outcomes);
|
|
101471
101626
|
} finally {
|
|
101472
101627
|
await closeSearchBrowser(activeBrowser);
|
|
101473
101628
|
}
|
|
@@ -101480,7 +101635,12 @@ function createSearchCommand(commandName = "findweb") {
|
|
|
101480
101635
|
},
|
|
101481
101636
|
args: searchArgs,
|
|
101482
101637
|
async run({ args }) {
|
|
101483
|
-
|
|
101638
|
+
try {
|
|
101639
|
+
await runSearch(args);
|
|
101640
|
+
} catch (error49) {
|
|
101641
|
+
printCommandError2(error49);
|
|
101642
|
+
process5.exitCode = 1;
|
|
101643
|
+
}
|
|
101484
101644
|
}
|
|
101485
101645
|
});
|
|
101486
101646
|
}
|
|
@@ -101548,7 +101708,7 @@ function showRootHelp() {
|
|
|
101548
101708
|
console.log(renderRootHelp());
|
|
101549
101709
|
}
|
|
101550
101710
|
async function main() {
|
|
101551
|
-
const rawArgs =
|
|
101711
|
+
const rawArgs = process6.argv.slice(2);
|
|
101552
101712
|
const action = resolveRootAction(rawArgs);
|
|
101553
101713
|
if (action.kind === "help") {
|
|
101554
101714
|
showRootHelp();
|
|
@@ -101560,4 +101720,10 @@ async function main() {
|
|
|
101560
101720
|
}
|
|
101561
101721
|
await runMain(createSearchCommand(), { rawArgs: action.rawArgs });
|
|
101562
101722
|
}
|
|
101563
|
-
|
|
101723
|
+
try {
|
|
101724
|
+
await main();
|
|
101725
|
+
} catch (error49) {
|
|
101726
|
+
const message = error49 instanceof Error ? error49.message : String(error49);
|
|
101727
|
+
console.error(`ERROR: ${message}`);
|
|
101728
|
+
process6.exitCode = 1;
|
|
101729
|
+
}
|