webcrawl 1.3.4 → 1.3.6
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/cli.d.ts +3 -1
- package/dist/cli.js +36 -16
- package/package.json +3 -3
package/dist/cli.d.ts
CHANGED
|
@@ -10,10 +10,12 @@ export interface Deps {
|
|
|
10
10
|
fetch?: typeof fetch;
|
|
11
11
|
/** Config file path override (tests). */
|
|
12
12
|
configFile?: string;
|
|
13
|
+
/** Browser opener override (tests). */
|
|
14
|
+
openUrl?: (url: string) => void;
|
|
13
15
|
/** Home directory override for `webcrawl setup` tests. */
|
|
14
16
|
homeDir?: string;
|
|
15
17
|
/** Working directory override for `webcrawl setup` tests. */
|
|
16
18
|
cwd?: string;
|
|
17
19
|
}
|
|
18
|
-
export declare const HELP = "Webcrawl Anything: search, scrape, parse and crawl any target on the internet\n\nUsage: webcrawl <command> [options]\n\nCommands\n search <query> Search the web or verticals. -c category, --sub, -n limit, --site <domain>\n scrape <url> Inspect a URL (website, SPA, PDF, Office, YouTube, GitHub, ArXiv, llms.txt)\n map <url> List a site's URLs. --filter <text>, -n limit\n crawl <url> Read several pages. -n max pages (default 5, max 25)\n extract <url> Structured JSON. --prompt <text> or --schema <file.json>\n rerank <query> Rank documents. --doc <text> (repeatable), --file <path>, or lines on stdin. -n top\n targets List all supported crawl & search targets and their requirements\n categories List search categories and vertical filters\n setup Register Webcrawl MCP server and Agent Skill (Claude, Cursor, Codex, Gemini, Windsurf)\n doctor Check local crawl engine, parsers, stealth browser, and cloud configuration\n login / signup Create an account or sign in (--email <addr> [--code <6-digit>],
|
|
20
|
+
export declare const HELP = "Webcrawl Anything: search, scrape, parse and crawl any target on the internet\n\nUsage: webcrawl <command> [options]\n\nCommands\n search <query> Search the web or verticals. -c category, --sub, -n limit, --site <domain>\n scrape <url> Inspect a URL (website, SPA, PDF, Office, YouTube, GitHub, ArXiv, llms.txt)\n map <url> List a site's URLs. --filter <text>, -n limit\n crawl <url> Read several pages. -n max pages (default 5, max 25)\n extract <url> Structured JSON. --prompt <text> or --schema <file.json>\n rerank <query> Rank documents. --doc <text> (repeatable), --file <path>, or lines on stdin. -n top\n targets List all supported crawl & search targets and their requirements\n categories List search categories and vertical filters\n setup Register Webcrawl MCP server and Agent Skill (Claude, Cursor, Codex, Gemini, Windsurf)\n doctor Check local crawl engine, parsers, stealth browser, and cloud configuration\n login / signup Create an account or sign in in your browser (default), or --email <addr> [--code <6-digit>], or --key <key>\n whoami Show execution mode (local vs cloud), account email, key source, and credit balance\n\nOptions\n --mode <m> Execution mode: auto (default: local without key, cloud with key), local, or cloud\n --email <addr> Email address for CLI account creation / OTP sign-in (assigns 1,000 free credits)\n --code <6-digit> 6-digit email verification code from `webcrawl login --email <addr>`\n --name <name> Optional display name when creating an account with `--email`\n --web Sign in via browser OAuth (default for login; no need to pass it)\n --json Print the raw JSON response\n --api-key <key> Override WEBCRAWL_API_KEY\n --url <base> Override WEBCRAWL_URL (default https://webcrawl.app)\n --country, --city Where to search from (default: this machine's timezone)\n --no-cache Skip cached pages (scrape)\n --agent <name> Target agent for setup: claude, cursor, codex, gemini, windsurf, or all (repeatable)\n --schema-profile MCP schema profile for setup: compact (default) or full\n -h, --help\n\nConfig order: flags, then WEBCRAWL_API_KEY / WEBCRAWL_URL / WEBCRAWL_MODE, then ~/.config/webcrawl/config.json";
|
|
19
21
|
export declare function main(argv: string[], io: Io, deps?: Deps): Promise<number>;
|
package/dist/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ Commands
|
|
|
22
22
|
categories List search categories and vertical filters
|
|
23
23
|
setup Register Webcrawl MCP server and Agent Skill (Claude, Cursor, Codex, Gemini, Windsurf)
|
|
24
24
|
doctor Check local crawl engine, parsers, stealth browser, and cloud configuration
|
|
25
|
-
login / signup Create an account or sign in (--email <addr> [--code <6-digit>],
|
|
25
|
+
login / signup Create an account or sign in in your browser (default), or --email <addr> [--code <6-digit>], or --key <key>
|
|
26
26
|
whoami Show execution mode (local vs cloud), account email, key source, and credit balance
|
|
27
27
|
|
|
28
28
|
Options
|
|
@@ -30,7 +30,7 @@ Options
|
|
|
30
30
|
--email <addr> Email address for CLI account creation / OTP sign-in (assigns 1,000 free credits)
|
|
31
31
|
--code <6-digit> 6-digit email verification code from \`webcrawl login --email <addr>\`
|
|
32
32
|
--name <name> Optional display name when creating an account with \`--email\`
|
|
33
|
-
--web Sign in
|
|
33
|
+
--web Sign in via browser OAuth (default for login; no need to pass it)
|
|
34
34
|
--json Print the raw JSON response
|
|
35
35
|
--api-key <key> Override WEBCRAWL_API_KEY
|
|
36
36
|
--url <base> Override WEBCRAWL_URL (default https://webcrawl.app)
|
|
@@ -112,7 +112,7 @@ function openBrowserUrl(url) {
|
|
|
112
112
|
// ignore
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
async function runWebOAuthLogin(baseUrl, fetchImpl, io) {
|
|
115
|
+
async function runWebOAuthLogin(baseUrl, fetchImpl, io, openUrl = openBrowserUrl) {
|
|
116
116
|
const verifier = crypto.randomBytes(32).toString("base64url");
|
|
117
117
|
const challenge = crypto.createHash("sha256").update(verifier).digest("base64url");
|
|
118
118
|
const state = crypto.randomBytes(16).toString("base64url");
|
|
@@ -153,7 +153,8 @@ async function runWebOAuthLogin(baseUrl, fetchImpl, io) {
|
|
|
153
153
|
"",
|
|
154
154
|
"Waiting for browser authorization...",
|
|
155
155
|
].join("\n") + "\n");
|
|
156
|
-
|
|
156
|
+
openUrl(authUrl);
|
|
157
|
+
let handled = false;
|
|
157
158
|
server.on("request", async (req, res) => {
|
|
158
159
|
try {
|
|
159
160
|
const u = new URL(req.url || "/", redirectUri);
|
|
@@ -163,14 +164,29 @@ async function runWebOAuthLogin(baseUrl, fetchImpl, io) {
|
|
|
163
164
|
}
|
|
164
165
|
const code = u.searchParams.get("code");
|
|
165
166
|
const returnedState = u.searchParams.get("state");
|
|
166
|
-
if (
|
|
167
|
+
if (handled) {
|
|
168
|
+
// Browser retry / prefetch of the same callback: the code is single-use, so never exchange it twice.
|
|
169
|
+
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
170
|
+
res.end("<h3>Already received. You can close this tab and return to your terminal.</h3>");
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const oauthError = u.searchParams.get("error");
|
|
174
|
+
if (oauthError && returnedState === state) {
|
|
175
|
+
handled = true;
|
|
167
176
|
res.writeHead(400, { "content-type": "text/html; charset=utf-8" });
|
|
168
|
-
res.end("<h3>Authorization
|
|
177
|
+
res.end("<h3>Authorization was cancelled. You can close this tab.</h3>");
|
|
169
178
|
clearTimeout(timeout);
|
|
170
179
|
server.close();
|
|
171
|
-
reject(new Error(
|
|
180
|
+
reject(new Error(`OAuth authorization failed: ${oauthError}.`));
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (!code || returnedState !== state) {
|
|
184
|
+
// Stray or forged request: reject it but keep waiting for the real callback.
|
|
185
|
+
res.writeHead(400, { "content-type": "text/html; charset=utf-8" });
|
|
186
|
+
res.end("<h3>Authorization failed or state mismatch.</h3>");
|
|
172
187
|
return;
|
|
173
188
|
}
|
|
189
|
+
handled = true;
|
|
174
190
|
const tokenRes = await fetchImpl(`${baseUrl}/oauth/token`, {
|
|
175
191
|
method: "POST",
|
|
176
192
|
headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json" },
|
|
@@ -183,7 +199,11 @@ async function runWebOAuthLogin(baseUrl, fetchImpl, io) {
|
|
|
183
199
|
}).toString(),
|
|
184
200
|
});
|
|
185
201
|
if (!tokenRes.ok) {
|
|
186
|
-
|
|
202
|
+
const detail = (await tokenRes.json().catch(() => ({})));
|
|
203
|
+
const reason = detail.error_description || detail.error;
|
|
204
|
+
res.writeHead(400, { "content-type": "text/html; charset=utf-8" });
|
|
205
|
+
res.end("<h3>Webcrawl sign-in failed. Return to your terminal for details.</h3>");
|
|
206
|
+
throw new Error(`OAuth token exchange failed (HTTP ${tokenRes.status}${reason ? `: ${reason}` : ""}). Run \`webcrawl login\` again, or use \`webcrawl login --email <you@domain.com>\`.`);
|
|
187
207
|
}
|
|
188
208
|
const tokenData = (await tokenRes.json());
|
|
189
209
|
let finalKey = tokenData.access_token;
|
|
@@ -302,7 +322,7 @@ export async function main(argv, io, deps = {}) {
|
|
|
302
322
|
" webcrawl login --email <you@domain.com>",
|
|
303
323
|
" webcrawl login --email <you@domain.com> --code <6-digit-code>",
|
|
304
324
|
" 2. Browser OAuth redirect:",
|
|
305
|
-
" webcrawl login
|
|
325
|
+
" webcrawl login",
|
|
306
326
|
" 3. Or run in zero-key local mode:",
|
|
307
327
|
` webcrawl --mode local ${cmd} ${rest.join(" ")}`,
|
|
308
328
|
].join("\n");
|
|
@@ -314,7 +334,7 @@ export async function main(argv, io, deps = {}) {
|
|
|
314
334
|
loginCommands: {
|
|
315
335
|
sendOtp: "webcrawl login --email <you@domain.com>",
|
|
316
336
|
verifyOtp: "webcrawl login --email <you@domain.com> --code <6-digit-code>",
|
|
317
|
-
browserRedirect: "webcrawl login
|
|
337
|
+
browserRedirect: "webcrawl login",
|
|
318
338
|
signupUrl: `${cfg.baseUrl}/?signup=cli`,
|
|
319
339
|
},
|
|
320
340
|
}, null, 2)}\n`);
|
|
@@ -447,9 +467,9 @@ export async function main(argv, io, deps = {}) {
|
|
|
447
467
|
fetch: deps.fetch,
|
|
448
468
|
userAgent: "webcrawl-cli/1.2",
|
|
449
469
|
});
|
|
450
|
-
// 1. Browser OAuth PKCE redirect (`webcrawl login
|
|
451
|
-
if (v.web) {
|
|
452
|
-
const webRes = await runWebOAuthLogin(cfg.baseUrl, deps.fetch ?? globalThis.fetch, io);
|
|
470
|
+
// 1. Browser OAuth PKCE redirect (default for `webcrawl login`; `--web` kept for compatibility)
|
|
471
|
+
if (v.web || (!v.email && !v.key)) {
|
|
472
|
+
const webRes = await runWebOAuthLogin(cfg.baseUrl, deps.fetch ?? globalThis.fetch, io, deps.openUrl);
|
|
453
473
|
const existing = readConfigFile(file);
|
|
454
474
|
writeConfigFile({ ...existing, apiKey: webRes.apiKey, ...(v.url ? { baseUrl: v.url } : {}) }, file);
|
|
455
475
|
const payload = {
|
|
@@ -524,9 +544,9 @@ export async function main(argv, io, deps = {}) {
|
|
|
524
544
|
return 0;
|
|
525
545
|
}
|
|
526
546
|
// 3. Direct API key (`webcrawl login --key wc_live_...` or interactive paste)
|
|
527
|
-
const key =
|
|
547
|
+
const key = v.key?.trim() ?? (await readKeyInteractively(io)).trim();
|
|
528
548
|
if (!key) {
|
|
529
|
-
throw new UsageError("No key provided. Pass --key <wc_live_
|
|
549
|
+
throw new UsageError("No key provided. Pass --key <wc_live_...> or --email <you@domain.com>, or run `webcrawl login` to sign in via your browser.");
|
|
530
550
|
}
|
|
531
551
|
const existing = readConfigFile(file);
|
|
532
552
|
writeConfigFile({ ...existing, apiKey: key, ...(v.url ? { baseUrl: v.url } : {}) }, file);
|
|
@@ -538,7 +558,7 @@ export async function main(argv, io, deps = {}) {
|
|
|
538
558
|
const lines = [
|
|
539
559
|
`endpoint: ${cfg.baseUrl} (${cfg.source.baseUrl})`,
|
|
540
560
|
`mode: ${cfg.effectiveMode} (${cfg.source.mode})`,
|
|
541
|
-
`key: ${masked}${cfg.apiKey ? ` (${cfg.source.apiKey})` : ". Run `webcrawl login` (`--email <you@domain.com>`
|
|
561
|
+
`key: ${masked}${cfg.apiKey ? ` (${cfg.source.apiKey})` : ". Run `webcrawl login` to sign in via your browser (or `--email <you@domain.com>`), or set WEBCRAWL_API_KEY (local mode works with zero key)."}`,
|
|
542
562
|
];
|
|
543
563
|
if (cfg.apiKey) {
|
|
544
564
|
const u = await client.usage();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcrawl",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.6",
|
|
4
4
|
"description": "Webcrawl Anything CLI & Core Engine — crawl, search, and extract structured evidence from any website, SPA, PDF, Office file, YouTube video, GitHub repo, ArXiv paper, or CVE",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -127,8 +127,8 @@
|
|
|
127
127
|
"@ai-sdk/gateway": "^4.0.123",
|
|
128
128
|
"@firecrawl/pdf-inspector": "^1.25.2",
|
|
129
129
|
"@vercel/sandbox": "^1.0.0",
|
|
130
|
-
"@webcrawl/client": "^1.3.
|
|
131
|
-
"@webcrawl/curl-impersonate": "^1.3.
|
|
130
|
+
"@webcrawl/client": "^1.3.6",
|
|
131
|
+
"@webcrawl/curl-impersonate": "^1.3.6",
|
|
132
132
|
"ai": "^7.0.150",
|
|
133
133
|
"impit": "^0.14.7",
|
|
134
134
|
"mammoth": "^1.13.0",
|