findweb 0.1.2 → 0.1.3
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 +3 -3
- package/dist/index.js +102 -21
- 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
|
|
@@ -98,7 +98,7 @@ You can trigger that ahead of time with:
|
|
|
98
98
|
findweb login
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
This opens a visible Chrome window with the Google sign-in page. After
|
|
101
|
+
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
102
|
|
|
103
103
|
## Output
|
|
104
104
|
|
package/dist/index.js
CHANGED
|
@@ -76479,12 +76479,59 @@ async function waitForIdle(page) {
|
|
|
76479
76479
|
}
|
|
76480
76480
|
|
|
76481
76481
|
// src/search/search.ts
|
|
76482
|
+
var LOGIN_POLL_MS = 250;
|
|
76483
|
+
function wait2(delayMs) {
|
|
76484
|
+
return new Promise((resolve6) => setTimeout(resolve6, delayMs));
|
|
76485
|
+
}
|
|
76486
|
+
function hostnameFromUrl(url) {
|
|
76487
|
+
try {
|
|
76488
|
+
return new URL(url).hostname.toLowerCase();
|
|
76489
|
+
} catch {
|
|
76490
|
+
return null;
|
|
76491
|
+
}
|
|
76492
|
+
}
|
|
76493
|
+
function isCompletedLoginUrl(url) {
|
|
76494
|
+
const hostname = hostnameFromUrl(url);
|
|
76495
|
+
return hostname !== null && hostname !== "accounts.google.com" && (hostname === "google.com" || hostname.endsWith(".google.com"));
|
|
76496
|
+
}
|
|
76497
|
+
function hasCompletedLoginPage(urls) {
|
|
76498
|
+
return urls.some((url) => isCompletedLoginUrl(url));
|
|
76499
|
+
}
|
|
76500
|
+
async function pageUrls(browser) {
|
|
76501
|
+
const pages = await browser.pages();
|
|
76502
|
+
return pages.map((page) => page.url());
|
|
76503
|
+
}
|
|
76504
|
+
async function waitForCompletedLogin(loginPage, browser) {
|
|
76505
|
+
let lastSeenUrls = [loginPage.url()];
|
|
76506
|
+
while (true) {
|
|
76507
|
+
if (browser.connected) {
|
|
76508
|
+
lastSeenUrls = await pageUrls(browser).catch(() => lastSeenUrls);
|
|
76509
|
+
if (hasCompletedLoginPage(lastSeenUrls)) {
|
|
76510
|
+
return;
|
|
76511
|
+
}
|
|
76512
|
+
}
|
|
76513
|
+
if (!browser.connected || loginPage.isClosed()) {
|
|
76514
|
+
if (hasCompletedLoginPage(lastSeenUrls)) {
|
|
76515
|
+
return;
|
|
76516
|
+
}
|
|
76517
|
+
throw new Error("Google login was not completed.");
|
|
76518
|
+
}
|
|
76519
|
+
await wait2(LOGIN_POLL_MS);
|
|
76520
|
+
}
|
|
76521
|
+
}
|
|
76482
76522
|
function isSorryPage(url) {
|
|
76483
76523
|
return url.includes("/sorry/");
|
|
76484
76524
|
}
|
|
76485
76525
|
function toErrorMessage(error) {
|
|
76486
76526
|
return error instanceof Error ? error.message : String(error);
|
|
76487
76527
|
}
|
|
76528
|
+
function isInterruptedLoginError(error, loginPage, browser) {
|
|
76529
|
+
if (!browser.connected || loginPage?.isClosed()) {
|
|
76530
|
+
return true;
|
|
76531
|
+
}
|
|
76532
|
+
const message = toErrorMessage(error);
|
|
76533
|
+
return message.includes("Navigating frame was detached") || message.includes("LifecycleWatcher disposed") || message.includes("Target closed") || message.includes("Session closed");
|
|
76534
|
+
}
|
|
76488
76535
|
async function searchQuery(options) {
|
|
76489
76536
|
const page = await options.browser.newPage();
|
|
76490
76537
|
try {
|
|
@@ -76546,19 +76593,29 @@ async function searchQueriesInTabs(browser, blocker, queries, options) {
|
|
|
76546
76593
|
return results;
|
|
76547
76594
|
}
|
|
76548
76595
|
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();
|
|
76596
|
+
let loginPage = null;
|
|
76597
|
+
const handleSigint = () => {
|
|
76598
|
+
options.browser.close().catch(() => {
|
|
76599
|
+
return;
|
|
76560
76600
|
});
|
|
76561
|
-
}
|
|
76601
|
+
};
|
|
76602
|
+
process.once("SIGINT", handleSigint);
|
|
76603
|
+
try {
|
|
76604
|
+
loginPage = await options.browser.newPage();
|
|
76605
|
+
await preparePage(loginPage, options.lang);
|
|
76606
|
+
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" });
|
|
76607
|
+
await waitForCompletedLogin(loginPage, options.browser);
|
|
76608
|
+
} catch (error) {
|
|
76609
|
+
if (isInterruptedLoginError(error, loginPage, options.browser)) {
|
|
76610
|
+
throw new Error("Google login was not completed.");
|
|
76611
|
+
}
|
|
76612
|
+
throw error;
|
|
76613
|
+
} finally {
|
|
76614
|
+
process.off("SIGINT", handleSigint);
|
|
76615
|
+
await loginPage?.close().catch(() => {
|
|
76616
|
+
return;
|
|
76617
|
+
});
|
|
76618
|
+
}
|
|
76562
76619
|
}
|
|
76563
76620
|
|
|
76564
76621
|
// src/cli/profile.ts
|
|
@@ -76588,8 +76645,8 @@ async function markProfilePrepared(userDataDir) {
|
|
|
76588
76645
|
// src/cli/flows/login.ts
|
|
76589
76646
|
function printLoginInstructions(userDataDir) {
|
|
76590
76647
|
console.log(`Login browser launched with profile: ${userDataDir}`);
|
|
76591
|
-
console.log("
|
|
76592
|
-
console.log("
|
|
76648
|
+
console.log("Complete Google sign-in to prepare this profile for future searches.");
|
|
76649
|
+
console.log("The session is saved automatically once sign-in is detected.");
|
|
76593
76650
|
}
|
|
76594
76651
|
async function runInteractiveLoginFlow(options) {
|
|
76595
76652
|
await ensureProfileDir(options.userDataDir);
|
|
@@ -90229,6 +90286,10 @@ function createLoginArgs() {
|
|
|
90229
90286
|
}
|
|
90230
90287
|
};
|
|
90231
90288
|
}
|
|
90289
|
+
function printCommandError(error48) {
|
|
90290
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
90291
|
+
console.error(`ERROR: ${message}`);
|
|
90292
|
+
}
|
|
90232
90293
|
async function runLogin(args) {
|
|
90233
90294
|
const options = normalizeLoginOptions({
|
|
90234
90295
|
gl: typeof args.gl === "string" ? args.gl : undefined,
|
|
@@ -90242,11 +90303,16 @@ function createLoginCommand(commandName = "findweb login") {
|
|
|
90242
90303
|
meta: { name: commandName, description: "Open a reusable Google sign-in session." },
|
|
90243
90304
|
args: createLoginArgs(),
|
|
90244
90305
|
async run({ args }) {
|
|
90245
|
-
|
|
90246
|
-
|
|
90247
|
-
|
|
90248
|
-
|
|
90249
|
-
|
|
90306
|
+
try {
|
|
90307
|
+
await runLogin({
|
|
90308
|
+
gl: args.gl,
|
|
90309
|
+
lang: args.lang,
|
|
90310
|
+
userDataDir: args.userDataDir
|
|
90311
|
+
});
|
|
90312
|
+
} catch (error48) {
|
|
90313
|
+
printCommandError(error48);
|
|
90314
|
+
process.exitCode = 1;
|
|
90315
|
+
}
|
|
90250
90316
|
}
|
|
90251
90317
|
});
|
|
90252
90318
|
}
|
|
@@ -101432,6 +101498,10 @@ var searchArgs = {
|
|
|
101432
101498
|
description: "Print JSON output"
|
|
101433
101499
|
}
|
|
101434
101500
|
};
|
|
101501
|
+
function printCommandError2(error49) {
|
|
101502
|
+
const message = error49 instanceof Error ? error49.message : String(error49);
|
|
101503
|
+
console.error(`ERROR: ${message}`);
|
|
101504
|
+
}
|
|
101435
101505
|
async function runSearch(args) {
|
|
101436
101506
|
const options = normalizeSearchOptions({
|
|
101437
101507
|
_: args._,
|
|
@@ -101480,7 +101550,12 @@ function createSearchCommand(commandName = "findweb") {
|
|
|
101480
101550
|
},
|
|
101481
101551
|
args: searchArgs,
|
|
101482
101552
|
async run({ args }) {
|
|
101483
|
-
|
|
101553
|
+
try {
|
|
101554
|
+
await runSearch(args);
|
|
101555
|
+
} catch (error49) {
|
|
101556
|
+
printCommandError2(error49);
|
|
101557
|
+
process4.exitCode = 1;
|
|
101558
|
+
}
|
|
101484
101559
|
}
|
|
101485
101560
|
});
|
|
101486
101561
|
}
|
|
@@ -101560,4 +101635,10 @@ async function main() {
|
|
|
101560
101635
|
}
|
|
101561
101636
|
await runMain(createSearchCommand(), { rawArgs: action.rawArgs });
|
|
101562
101637
|
}
|
|
101563
|
-
|
|
101638
|
+
try {
|
|
101639
|
+
await main();
|
|
101640
|
+
} catch (error49) {
|
|
101641
|
+
const message = error49 instanceof Error ? error49.message : String(error49);
|
|
101642
|
+
console.error(`ERROR: ${message}`);
|
|
101643
|
+
process5.exitCode = 1;
|
|
101644
|
+
}
|