recker 1.0.79 → 1.0.80-next.70ea84d
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/browser/browser/mini.d.ts +2 -2
- package/dist/browser/browser/recker-mini.d.ts +8 -8
- package/dist/browser/browser/recker.d.ts +11 -8
- package/dist/browser/browser/recker.js +54 -6
- package/dist/browser/core/client.d.ts +15 -10
- package/dist/browser/core/client.js +54 -38
- package/dist/browser/index.iife.min.js +129 -130
- package/dist/browser/index.min.js +129 -130
- package/dist/browser/index.mini.iife.js +5697 -636
- package/dist/browser/index.mini.iife.min.js +47 -48
- package/dist/browser/index.mini.min.js +47 -48
- package/dist/browser/index.mini.umd.js +5697 -636
- package/dist/browser/index.mini.umd.min.js +47 -48
- package/dist/browser/index.umd.min.js +129 -130
- package/dist/browser/mini.d.ts +2 -2
- package/dist/browser/plugins/proxy-rotator.d.ts +2 -2
- package/dist/browser/plugins/proxy-rotator.js +6 -28
- package/dist/browser/recker-mini.d.ts +8 -8
- package/dist/browser/recker.d.ts +11 -8
- package/dist/browser/recker.js +54 -6
- package/dist/browser/scrape/document.js +2 -2
- package/dist/browser/scrape/element.js +7 -1
- package/dist/browser/scrape/parser/nodes/html.js +1 -1
- package/dist/browser/scrape/spider.d.ts +52 -0
- package/dist/browser/scrape/spider.js +620 -38
- package/dist/browser/scrape/types.d.ts +2 -0
- package/dist/browser/search/google.d.ts +26 -1
- package/dist/browser/search/google.js +427 -45
- package/dist/browser/seo/analyzer.d.ts +1 -0
- package/dist/browser/seo/analyzer.js +144 -1
- package/dist/browser/seo/index.d.ts +1 -1
- package/dist/browser/seo/keyword-campaign-analyzer.d.ts +2 -0
- package/dist/browser/seo/keyword-campaign-analyzer.js +538 -0
- package/dist/browser/seo/keyword-campaign-seed-advanced.d.ts +17 -0
- package/dist/browser/seo/keyword-campaign-seed-advanced.js +269 -0
- package/dist/browser/seo/keyword-campaign-seed-core.d.ts +29 -0
- package/dist/browser/seo/keyword-campaign-seed-core.js +525 -0
- package/dist/browser/seo/keyword-campaign-shared.d.ts +165 -0
- package/dist/browser/seo/keyword-campaign-shared.js +59 -0
- package/dist/browser/seo/keyword-campaign.d.ts +4 -107
- package/dist/browser/seo/keyword-campaign.js +2 -380
- package/dist/browser/seo/keywords.js +5 -22
- package/dist/browser/seo/types.d.ts +19 -0
- package/dist/browser/transport/curl.d.ts +5 -1
- package/dist/browser/transport/curl.js +207 -50
- package/dist/browser/transport/undici.d.ts +4 -3
- package/dist/browser/transport/undici.js +123 -49
- package/dist/browser/types/index.d.ts +9 -3
- package/dist/browser/utils/binary-manager.js +26 -3
- package/dist/browser/utils/block-detector.d.ts +8 -0
- package/dist/browser/utils/block-detector.js +542 -7
- package/dist/cli/commands/hls-runner.js +5 -4
- package/dist/cli/commands/live-runner.js +5 -4
- package/dist/cli/commands/loadtest-runner.js +3 -2
- package/dist/cli/commands/search.d.ts +2 -0
- package/dist/cli/commands/search.js +105 -0
- package/dist/cli/commands/seo-runner.js +9 -7
- package/dist/cli/commands/seo.js +140 -1
- package/dist/cli/commands/serve.js +75 -131
- package/dist/cli/commands/server-runner.js +59 -82
- package/dist/cli/commands/spider-runner.d.ts +37 -1
- package/dist/cli/commands/spider-runner.js +134 -10
- package/dist/cli/commands/spider.d.ts +18 -1
- package/dist/cli/commands/spider.js +457 -27
- package/dist/cli/events/handlers/cli.js +30 -1
- package/dist/cli/events/handlers/tui.js +26 -0
- package/dist/cli/events/types.d.ts +27 -0
- package/dist/cli/handler.d.ts +2 -12
- package/dist/cli/handler.js +20 -15
- package/dist/cli/handlers/protocols.js +39 -12
- package/dist/cli/handlers/search.d.ts +2 -0
- package/dist/cli/handlers/search.js +171 -0
- package/dist/cli/handlers/seo-analyze.d.ts +1 -0
- package/dist/cli/handlers/seo-analyze.js +666 -0
- package/dist/cli/handlers/seo-robots.d.ts +1 -0
- package/dist/cli/handlers/seo-robots.js +76 -0
- package/dist/cli/handlers/seo-serp.d.ts +54 -0
- package/dist/cli/handlers/seo-serp.js +243 -0
- package/dist/cli/handlers/seo-sitemap.d.ts +1 -0
- package/dist/cli/handlers/seo-sitemap.js +55 -0
- package/dist/cli/handlers/seo-spider.d.ts +1 -0
- package/dist/cli/handlers/seo-spider.js +334 -0
- package/dist/cli/handlers/seo.d.ts +8 -4
- package/dist/cli/handlers/seo.js +294 -442
- package/dist/cli/handlers/spider.js +94 -17
- package/dist/cli/handlers/streaming.js +5 -1
- package/dist/cli/index.js +11 -2
- package/dist/cli/presets.d.ts +1 -1
- package/dist/cli/presets.js +15 -4
- package/dist/cli/tui/app.js +6 -1
- package/dist/cli/tui/components/rich-response.d.ts +72 -0
- package/dist/cli/tui/components/rich-response.js +117 -0
- package/dist/cli/tui/executor-commands/background.js +30 -24
- package/dist/cli/tui/executor-commands/testing.js +3 -2
- package/dist/cli/tui/hooks/useDomains.d.ts +17 -0
- package/dist/cli/tui/hooks/useHelp.js +15 -2
- package/dist/cli/tui/job-manager.d.ts +4 -4
- package/dist/cli/tui/job-manager.js +5 -1
- package/dist/cli/tui/spider-tui.d.ts +63 -0
- package/dist/cli/tui/spider-tui.js +120 -2
- package/dist/cli/types.d.ts +12 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utils/option-helpers.d.ts +10 -0
- package/dist/cli/utils/option-helpers.js +63 -0
- package/dist/cli/utils/score-color.d.ts +11 -0
- package/dist/cli/utils/score-color.js +11 -0
- package/dist/cli/utils/serp-campaign.d.ts +53 -0
- package/dist/cli/utils/serp-campaign.js +53 -0
- package/dist/cli/utils/serp-config.d.ts +26 -0
- package/dist/cli/utils/serp-config.js +125 -0
- package/dist/core/client.d.ts +15 -10
- package/dist/core/client.js +54 -38
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/cli.js +35 -34
- package/dist/mcp/client.d.ts +2 -2
- package/dist/mcp/client.js +20 -2
- package/dist/mcp/contract.d.ts +1 -1
- package/dist/mcp/profiles.js +5 -1
- package/dist/mcp/prompts/index.js +8 -4
- package/dist/mcp/resources/index.js +46 -23
- package/dist/mcp/server.js +9 -6
- package/dist/mcp/tools/protocols.js +9 -2
- package/dist/mcp/tools/registry.js +13 -3
- package/dist/mcp/tools/seo.js +427 -2
- package/dist/mcp/types.d.ts +5 -1
- package/dist/plugins/proxy-rotator.d.ts +2 -2
- package/dist/plugins/proxy-rotator.js +6 -28
- package/dist/raffel/client.d.ts +38 -0
- package/dist/raffel/client.js +282 -0
- package/dist/raffel/index.d.ts +2 -0
- package/dist/raffel/index.js +2 -0
- package/dist/raffel/types.d.ts +40 -0
- package/dist/raffel/types.js +14 -0
- package/dist/recker.d.ts +13 -7
- package/dist/recker.js +58 -6
- package/dist/scrape/document.js +2 -2
- package/dist/scrape/element.js +7 -1
- package/dist/scrape/parser/nodes/html.js +1 -1
- package/dist/scrape/spider.d.ts +52 -0
- package/dist/scrape/spider.js +620 -38
- package/dist/scrape/types.d.ts +2 -0
- package/dist/search/google.d.ts +26 -1
- package/dist/search/google.js +427 -45
- package/dist/search/index.d.ts +1 -1
- package/dist/seo/analyzer.d.ts +1 -0
- package/dist/seo/analyzer.js +144 -1
- package/dist/seo/index.d.ts +1 -1
- package/dist/seo/keyword-campaign-analyzer.d.ts +2 -0
- package/dist/seo/keyword-campaign-analyzer.js +538 -0
- package/dist/seo/keyword-campaign-seed-advanced.d.ts +17 -0
- package/dist/seo/keyword-campaign-seed-advanced.js +269 -0
- package/dist/seo/keyword-campaign-seed-core.d.ts +29 -0
- package/dist/seo/keyword-campaign-seed-core.js +525 -0
- package/dist/seo/keyword-campaign-shared.d.ts +165 -0
- package/dist/seo/keyword-campaign-shared.js +59 -0
- package/dist/seo/keyword-campaign.d.ts +4 -107
- package/dist/seo/keyword-campaign.js +2 -380
- package/dist/seo/keywords.js +5 -22
- package/dist/seo/types.d.ts +19 -0
- package/dist/template/index.d.ts +1 -1
- package/dist/template/types.d.ts +0 -2
- package/dist/testing/index.d.ts +1 -22
- package/dist/testing/index.js +1 -11
- package/dist/transport/curl.d.ts +5 -1
- package/dist/transport/curl.js +207 -50
- package/dist/transport/undici.d.ts +4 -3
- package/dist/transport/undici.js +123 -49
- package/dist/types/index.d.ts +9 -3
- package/dist/utils/binary-manager.js +26 -3
- package/dist/utils/block-detector.d.ts +8 -0
- package/dist/utils/block-detector.js +542 -7
- package/dist/version.js +1 -1
- package/package.json +12 -1
- package/dist/testing/mock-dns-server.d.ts +0 -69
- package/dist/testing/mock-dns-server.js +0 -269
- package/dist/testing/mock-ftp-server.d.ts +0 -89
- package/dist/testing/mock-ftp-server.js +0 -562
- package/dist/testing/mock-hls-server.d.ts +0 -80
- package/dist/testing/mock-hls-server.js +0 -381
- package/dist/testing/mock-http-server.d.ts +0 -124
- package/dist/testing/mock-http-server.js +0 -343
- package/dist/testing/mock-proxy-server.d.ts +0 -108
- package/dist/testing/mock-proxy-server.js +0 -615
- package/dist/testing/mock-sse-server.d.ts +0 -76
- package/dist/testing/mock-sse-server.js +0 -291
- package/dist/testing/mock-telnet-server.d.ts +0 -59
- package/dist/testing/mock-telnet-server.js +0 -274
- package/dist/testing/mock-udp-server.d.ts +0 -43
- package/dist/testing/mock-udp-server.js +0 -188
- package/dist/testing/mock-websocket-server.d.ts +0 -76
- package/dist/testing/mock-websocket-server.js +0 -334
- package/dist/testing/mock-whois-server.d.ts +0 -56
- package/dist/testing/mock-whois-server.js +0 -234
- package/dist/testing/proxy-certs.d.ts +0 -19
- package/dist/testing/proxy-certs.js +0 -208
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createClient } from '../../core/client.js';
|
|
2
2
|
import { CommandEmitter } from '../events/emitter.js';
|
|
3
|
+
import { AbortError } from '../../core/errors.js';
|
|
3
4
|
export class LiveRunner extends CommandEmitter {
|
|
4
5
|
client;
|
|
5
6
|
constructor(client) {
|
|
@@ -14,7 +15,7 @@ export class LiveRunner extends CommandEmitter {
|
|
|
14
15
|
this.emitStart(url, { action: 'info' });
|
|
15
16
|
try {
|
|
16
17
|
if (signal?.aborted) {
|
|
17
|
-
throw new
|
|
18
|
+
throw new AbortError('Live info aborted');
|
|
18
19
|
}
|
|
19
20
|
const { createVideoBuilder } = await import('../../video/builder.js');
|
|
20
21
|
const videoBuilder = createVideoBuilder(url, options.client ?? this.client);
|
|
@@ -37,7 +38,7 @@ export class LiveRunner extends CommandEmitter {
|
|
|
37
38
|
return result;
|
|
38
39
|
}
|
|
39
40
|
catch (err) {
|
|
40
|
-
if (signal?.aborted || err
|
|
41
|
+
if (signal?.aborted || err instanceof AbortError) {
|
|
41
42
|
this.emitError('Live info stopped by user', { code: 'ABORT' });
|
|
42
43
|
}
|
|
43
44
|
else {
|
|
@@ -59,7 +60,7 @@ export class LiveRunner extends CommandEmitter {
|
|
|
59
60
|
let streamInfo = {};
|
|
60
61
|
try {
|
|
61
62
|
if (signal?.aborted) {
|
|
62
|
-
throw new
|
|
63
|
+
throw new AbortError('Live download aborted');
|
|
63
64
|
}
|
|
64
65
|
this.emitProgress({
|
|
65
66
|
current: 0,
|
|
@@ -152,7 +153,7 @@ export class LiveRunner extends CommandEmitter {
|
|
|
152
153
|
return result;
|
|
153
154
|
}
|
|
154
155
|
catch (err) {
|
|
155
|
-
if (signal?.aborted || err
|
|
156
|
+
if (signal?.aborted || err instanceof AbortError) {
|
|
156
157
|
this.emitError('Live recording stopped by user', { code: 'ABORT' });
|
|
157
158
|
return {
|
|
158
159
|
url,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CommandEmitter } from '../events/emitter.js';
|
|
2
2
|
import { LoadGenerator } from '../../bench/generator.js';
|
|
3
|
+
import { AbortError } from '../../core/errors.js';
|
|
3
4
|
export class LoadTestRunner extends CommandEmitter {
|
|
4
5
|
generator = null;
|
|
5
6
|
updateInterval = null;
|
|
@@ -34,7 +35,7 @@ export class LoadTestRunner extends CommandEmitter {
|
|
|
34
35
|
this.aborted = false;
|
|
35
36
|
try {
|
|
36
37
|
if (signal?.aborted) {
|
|
37
|
-
throw new
|
|
38
|
+
throw new AbortError('Load test aborted');
|
|
38
39
|
}
|
|
39
40
|
const abortHandler = () => {
|
|
40
41
|
this.aborted = true;
|
|
@@ -88,7 +89,7 @@ export class LoadTestRunner extends CommandEmitter {
|
|
|
88
89
|
}
|
|
89
90
|
catch (err) {
|
|
90
91
|
this.stopStatsPolling();
|
|
91
|
-
if (signal?.aborted || this.aborted || err
|
|
92
|
+
if (signal?.aborted || this.aborted || err instanceof AbortError) {
|
|
92
93
|
this.emitError('Load test stopped by user', { code: 'ABORT' });
|
|
93
94
|
const stats = this.generator?.stats;
|
|
94
95
|
const actualDuration = Math.round((Date.now() - this.startTime) / 1000);
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { createCliActionWithOptions } from '../cli-adapter.js';
|
|
2
|
+
import { searchHandler } from '../handlers/search.js';
|
|
3
|
+
export function registerSearchCommand(program) {
|
|
4
|
+
program
|
|
5
|
+
.command('search')
|
|
6
|
+
.description('Run a single Google search query and show top results')
|
|
7
|
+
.argument('<query>', {
|
|
8
|
+
type: 'string',
|
|
9
|
+
description: 'Search query',
|
|
10
|
+
example: 'stone',
|
|
11
|
+
})
|
|
12
|
+
.option('site', {
|
|
13
|
+
type: 'string',
|
|
14
|
+
description: 'Limit results to a site/domain (as_sitesearch)',
|
|
15
|
+
example: 'stone.com.br',
|
|
16
|
+
})
|
|
17
|
+
.option('country', {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'Country code or country name for locale inference',
|
|
20
|
+
example: 'br',
|
|
21
|
+
})
|
|
22
|
+
.option('gl', {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'Override country code for Google locale',
|
|
25
|
+
example: 'br',
|
|
26
|
+
})
|
|
27
|
+
.option('hl', {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: 'Interface language code',
|
|
30
|
+
example: 'pt-BR',
|
|
31
|
+
})
|
|
32
|
+
.option('num', {
|
|
33
|
+
type: 'number',
|
|
34
|
+
default: 10,
|
|
35
|
+
description: 'Number of results',
|
|
36
|
+
example: '10',
|
|
37
|
+
})
|
|
38
|
+
.option('start', {
|
|
39
|
+
type: 'number',
|
|
40
|
+
default: 0,
|
|
41
|
+
description: 'Start offset for paginated results',
|
|
42
|
+
})
|
|
43
|
+
.option('human-profile', {
|
|
44
|
+
type: 'string',
|
|
45
|
+
default: 'chrome',
|
|
46
|
+
description: 'human-search signature (chrome|off)',
|
|
47
|
+
})
|
|
48
|
+
.option('as-site-search', {
|
|
49
|
+
type: 'string',
|
|
50
|
+
description: 'Site filter alias (same as --site)',
|
|
51
|
+
})
|
|
52
|
+
.option('exact-phrase', {
|
|
53
|
+
type: 'string',
|
|
54
|
+
description: 'Exact phrase query (as_epq)',
|
|
55
|
+
})
|
|
56
|
+
.option('source', {
|
|
57
|
+
type: 'string',
|
|
58
|
+
default: 'google',
|
|
59
|
+
description: 'Search source/provider. Current options: google',
|
|
60
|
+
example: 'google',
|
|
61
|
+
})
|
|
62
|
+
.option('transport', {
|
|
63
|
+
type: 'string',
|
|
64
|
+
default: 'curl',
|
|
65
|
+
description: 'Search transport (auto | undici | curl)',
|
|
66
|
+
example: 'curl',
|
|
67
|
+
})
|
|
68
|
+
.option('timeout', {
|
|
69
|
+
type: 'number',
|
|
70
|
+
description: 'Search request timeout (ms)',
|
|
71
|
+
example: '15000',
|
|
72
|
+
})
|
|
73
|
+
.option('include-raw-html', {
|
|
74
|
+
type: 'boolean',
|
|
75
|
+
description: 'Include raw HTML in JSON output',
|
|
76
|
+
})
|
|
77
|
+
.example('rek search "stone" --country br', 'Search query in Google BR')
|
|
78
|
+
.example('rek search "stone" --site stone.com.br --num 5 --transport curl', 'Limit to domain + use curl')
|
|
79
|
+
.example('rek search "como ativar pix" --country br --as-site-search stone.com.br', 'Search exact phrase on domain')
|
|
80
|
+
.action(createCliActionWithOptions(searchHandler, {
|
|
81
|
+
positional: ['query'],
|
|
82
|
+
options: [
|
|
83
|
+
'site',
|
|
84
|
+
'country',
|
|
85
|
+
'gl',
|
|
86
|
+
'hl',
|
|
87
|
+
'num',
|
|
88
|
+
'start',
|
|
89
|
+
'exact-phrase',
|
|
90
|
+
'human-profile',
|
|
91
|
+
'as-site-search',
|
|
92
|
+
'source',
|
|
93
|
+
'transport',
|
|
94
|
+
'timeout',
|
|
95
|
+
'include-raw-html',
|
|
96
|
+
'json',
|
|
97
|
+
],
|
|
98
|
+
optionMapping: {
|
|
99
|
+
'exact-phrase': 'exactPhrase',
|
|
100
|
+
'human-profile': 'humanProfile',
|
|
101
|
+
'as-site-search': 'asSiteSearch',
|
|
102
|
+
'include-raw-html': 'includeRawHtml',
|
|
103
|
+
},
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createClient } from '../../core/client.js';
|
|
2
2
|
import { CommandEmitter } from '../events/emitter.js';
|
|
3
|
+
import { AbortError } from '../../core/errors.js';
|
|
3
4
|
export class SEORunner extends CommandEmitter {
|
|
4
5
|
client;
|
|
5
6
|
constructor(client) {
|
|
6
7
|
super('seo');
|
|
7
8
|
this.client = client ?? createClient({
|
|
8
9
|
timeout: 30000,
|
|
9
|
-
checkHooks: false,
|
|
10
10
|
});
|
|
11
11
|
}
|
|
12
12
|
async run(url, options = {}) {
|
|
@@ -19,7 +19,7 @@ export class SEORunner extends CommandEmitter {
|
|
|
19
19
|
const startTime = performance.now();
|
|
20
20
|
try {
|
|
21
21
|
if (signal?.aborted) {
|
|
22
|
-
throw new
|
|
22
|
+
throw new AbortError('SEO run aborted');
|
|
23
23
|
}
|
|
24
24
|
this.emitProgress({
|
|
25
25
|
current: 1,
|
|
@@ -27,7 +27,8 @@ export class SEORunner extends CommandEmitter {
|
|
|
27
27
|
currentItem: `Fetching ${targetUrl}...`,
|
|
28
28
|
percent: 10,
|
|
29
29
|
});
|
|
30
|
-
const
|
|
30
|
+
const requestOptions = signal ? { signal } : undefined;
|
|
31
|
+
const response = await this.client.get(targetUrl, requestOptions);
|
|
31
32
|
const html = await response.text();
|
|
32
33
|
this.emit('data', {
|
|
33
34
|
type: 'data',
|
|
@@ -43,7 +44,7 @@ export class SEORunner extends CommandEmitter {
|
|
|
43
44
|
},
|
|
44
45
|
});
|
|
45
46
|
if (signal?.aborted) {
|
|
46
|
-
throw new
|
|
47
|
+
throw new AbortError('SEO run aborted');
|
|
47
48
|
}
|
|
48
49
|
this.emitProgress({
|
|
49
50
|
current: 2,
|
|
@@ -153,12 +154,13 @@ export class SEORunner extends CommandEmitter {
|
|
|
153
154
|
return result;
|
|
154
155
|
}
|
|
155
156
|
catch (err) {
|
|
156
|
-
if (signal?.aborted || err
|
|
157
|
+
if (signal?.aborted || err instanceof AbortError) {
|
|
157
158
|
this.emitError('SEO analysis stopped by user', { code: 'ABORT' });
|
|
158
159
|
}
|
|
159
160
|
else {
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
const error = err instanceof Error ? err : new Error('SEO analysis failed');
|
|
162
|
+
this.emitError(error.message || 'SEO analysis failed', {
|
|
163
|
+
stack: error.stack,
|
|
162
164
|
context: targetUrl,
|
|
163
165
|
});
|
|
164
166
|
}
|
package/dist/cli/commands/seo.js
CHANGED
|
@@ -30,15 +30,154 @@ export function registerSeoCommand(program) {
|
|
|
30
30
|
short: 'O',
|
|
31
31
|
description: 'Save report to directory (auto-generates filename)',
|
|
32
32
|
example: '~/reports/',
|
|
33
|
+
})
|
|
34
|
+
.option('json', {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Output report in JSON',
|
|
37
|
+
})
|
|
38
|
+
.option('serp', {
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
description: 'Run SERP checks for extracted top keywords',
|
|
41
|
+
})
|
|
42
|
+
.option('serp-top-keywords', {
|
|
43
|
+
type: 'number',
|
|
44
|
+
description: 'Top keywords per page used to seed SERP',
|
|
45
|
+
example: '20',
|
|
46
|
+
})
|
|
47
|
+
.option('serp-query-limit', {
|
|
48
|
+
type: 'number',
|
|
49
|
+
description: 'Number of queries to run in SERP',
|
|
50
|
+
example: '10',
|
|
51
|
+
})
|
|
52
|
+
.option('serp-results-per-query', {
|
|
53
|
+
type: 'number',
|
|
54
|
+
description: 'Results fetched per SERP query',
|
|
55
|
+
example: '10',
|
|
56
|
+
})
|
|
57
|
+
.option('serp-concurrency', {
|
|
58
|
+
type: 'number',
|
|
59
|
+
description: 'Number of parallel SERP queries',
|
|
60
|
+
example: '4',
|
|
61
|
+
})
|
|
62
|
+
.option('serp-delay-ms', {
|
|
63
|
+
type: 'number',
|
|
64
|
+
description: 'Base delay in ms between SERP queries',
|
|
65
|
+
example: '450',
|
|
66
|
+
})
|
|
67
|
+
.option('serp-delay-jitter-ms', {
|
|
68
|
+
type: 'number',
|
|
69
|
+
description: 'Random delay jitter in ms between SERP queries',
|
|
70
|
+
example: '250',
|
|
71
|
+
})
|
|
72
|
+
.option('serp-max-consecutive-blocks', {
|
|
73
|
+
type: 'number',
|
|
74
|
+
description: 'Stop campaign after this many consecutive blocked/captcha responses (0 = never)',
|
|
75
|
+
example: '5',
|
|
76
|
+
})
|
|
77
|
+
.option('serp-captcha-cooldown-ms', {
|
|
78
|
+
type: 'number',
|
|
79
|
+
description: 'Cooldown in ms after captcha before continuing SERP queries',
|
|
80
|
+
example: '1200',
|
|
81
|
+
})
|
|
82
|
+
.option('serp-retry-count', {
|
|
83
|
+
type: 'number',
|
|
84
|
+
description: 'Retry count per SERP query',
|
|
85
|
+
example: '1',
|
|
86
|
+
})
|
|
87
|
+
.option('serp-retry-delay-ms', {
|
|
88
|
+
type: 'number',
|
|
89
|
+
description: 'Base delay in ms for SERP query retries',
|
|
90
|
+
example: '900',
|
|
91
|
+
})
|
|
92
|
+
.option('serp-transport', {
|
|
93
|
+
type: 'string',
|
|
94
|
+
default: 'curl',
|
|
95
|
+
description: 'Search transport (auto | undici | curl)',
|
|
96
|
+
example: 'curl',
|
|
97
|
+
})
|
|
98
|
+
.option('serp-source', {
|
|
99
|
+
type: 'string',
|
|
100
|
+
default: 'google',
|
|
101
|
+
description: 'Search source/provider. Current options: google',
|
|
102
|
+
example: 'google',
|
|
103
|
+
})
|
|
104
|
+
.option('serp-timeout', {
|
|
105
|
+
type: 'number',
|
|
106
|
+
description: 'Search timeout (ms)',
|
|
107
|
+
example: '15000',
|
|
108
|
+
})
|
|
109
|
+
.option('serp-country', {
|
|
110
|
+
type: 'string',
|
|
111
|
+
description: 'Country/region for SERP results',
|
|
112
|
+
example: 'br',
|
|
113
|
+
})
|
|
114
|
+
.option('serp-gl', {
|
|
115
|
+
type: 'string',
|
|
116
|
+
description: 'Google GL parameter',
|
|
117
|
+
})
|
|
118
|
+
.option('serp-hl', {
|
|
119
|
+
type: 'string',
|
|
120
|
+
description: 'Google HL parameter',
|
|
121
|
+
})
|
|
122
|
+
.option('serp-human-profile', {
|
|
123
|
+
type: 'string',
|
|
124
|
+
description: 'Human-like SERP query profile: chrome or off',
|
|
125
|
+
default: 'chrome',
|
|
33
126
|
})
|
|
34
127
|
.example('rek seo example.com', 'Run SEO audit')
|
|
35
128
|
.example('rek seo example.com -o report.json', 'Save to file')
|
|
36
129
|
.example('rek seo example.com -O ~/reports/', 'Save with auto-filename')
|
|
37
130
|
.example('rek seo example.com --json', 'Get JSON report')
|
|
131
|
+
.example('rek seo example.com --serp', 'Run SERP check')
|
|
132
|
+
.example('rek seo example.com --serp --serp-top-keywords 12 --serp-query-limit 10', 'Run SERP with tuned limits')
|
|
38
133
|
.example('rek seo example.com -a', 'Show all checks')
|
|
39
134
|
.example('rek seo example.com -C performance', 'Only performance checks')
|
|
40
135
|
.action(createCliActionWithOptions(seoAnalyzeHandler, {
|
|
41
136
|
positional: ['url'],
|
|
42
|
-
options: [
|
|
137
|
+
options: [
|
|
138
|
+
'all',
|
|
139
|
+
'category',
|
|
140
|
+
'output',
|
|
141
|
+
'outputDir',
|
|
142
|
+
'json',
|
|
143
|
+
'serp',
|
|
144
|
+
'serp-top-keywords',
|
|
145
|
+
'serp-query-limit',
|
|
146
|
+
'serp-results-per-query',
|
|
147
|
+
'serp-concurrency',
|
|
148
|
+
'serp-delay-ms',
|
|
149
|
+
'serp-delay-jitter-ms',
|
|
150
|
+
'serp-max-consecutive-blocks',
|
|
151
|
+
'serp-captcha-cooldown-ms',
|
|
152
|
+
'serp-retry-count',
|
|
153
|
+
'serp-retry-delay-ms',
|
|
154
|
+
'serp-transport',
|
|
155
|
+
'serp-source',
|
|
156
|
+
'serp-timeout',
|
|
157
|
+
'serp-country',
|
|
158
|
+
'serp-gl',
|
|
159
|
+
'serp-hl',
|
|
160
|
+
'serp-human-profile',
|
|
161
|
+
],
|
|
162
|
+
optionMapping: {
|
|
163
|
+
'output-dir': 'outputDir',
|
|
164
|
+
'serp-top-keywords': 'serpTopKeywords',
|
|
165
|
+
'serp-query-limit': 'serpQueryLimit',
|
|
166
|
+
'serp-results-per-query': 'serpResultsPerQuery',
|
|
167
|
+
'serp-concurrency': 'serpConcurrency',
|
|
168
|
+
'serp-delay-ms': 'serpDelayMs',
|
|
169
|
+
'serp-delay-jitter-ms': 'serpDelayJitterMs',
|
|
170
|
+
'serp-max-consecutive-blocks': 'serpMaxConsecutiveBlocks',
|
|
171
|
+
'serp-captcha-cooldown-ms': 'serpCaptchaCooldownMs',
|
|
172
|
+
'serp-retry-count': 'serpRetryCount',
|
|
173
|
+
'serp-retry-delay-ms': 'serpRetryDelayMs',
|
|
174
|
+
'serp-transport': 'serpTransport',
|
|
175
|
+
'serp-source': 'serpSource',
|
|
176
|
+
'serp-timeout': 'serpTimeout',
|
|
177
|
+
'serp-country': 'serpCountry',
|
|
178
|
+
'serp-gl': 'serpGl',
|
|
179
|
+
'serp-hl': 'serpHl',
|
|
180
|
+
'serp-human-profile': 'serpHumanProfile',
|
|
181
|
+
},
|
|
43
182
|
}));
|
|
44
183
|
}
|