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.
Files changed (196) hide show
  1. package/dist/browser/browser/mini.d.ts +2 -2
  2. package/dist/browser/browser/recker-mini.d.ts +8 -8
  3. package/dist/browser/browser/recker.d.ts +11 -8
  4. package/dist/browser/browser/recker.js +54 -6
  5. package/dist/browser/core/client.d.ts +15 -10
  6. package/dist/browser/core/client.js +54 -38
  7. package/dist/browser/index.iife.min.js +129 -130
  8. package/dist/browser/index.min.js +129 -130
  9. package/dist/browser/index.mini.iife.js +5697 -636
  10. package/dist/browser/index.mini.iife.min.js +47 -48
  11. package/dist/browser/index.mini.min.js +47 -48
  12. package/dist/browser/index.mini.umd.js +5697 -636
  13. package/dist/browser/index.mini.umd.min.js +47 -48
  14. package/dist/browser/index.umd.min.js +129 -130
  15. package/dist/browser/mini.d.ts +2 -2
  16. package/dist/browser/plugins/proxy-rotator.d.ts +2 -2
  17. package/dist/browser/plugins/proxy-rotator.js +6 -28
  18. package/dist/browser/recker-mini.d.ts +8 -8
  19. package/dist/browser/recker.d.ts +11 -8
  20. package/dist/browser/recker.js +54 -6
  21. package/dist/browser/scrape/document.js +2 -2
  22. package/dist/browser/scrape/element.js +7 -1
  23. package/dist/browser/scrape/parser/nodes/html.js +1 -1
  24. package/dist/browser/scrape/spider.d.ts +52 -0
  25. package/dist/browser/scrape/spider.js +620 -38
  26. package/dist/browser/scrape/types.d.ts +2 -0
  27. package/dist/browser/search/google.d.ts +26 -1
  28. package/dist/browser/search/google.js +427 -45
  29. package/dist/browser/seo/analyzer.d.ts +1 -0
  30. package/dist/browser/seo/analyzer.js +144 -1
  31. package/dist/browser/seo/index.d.ts +1 -1
  32. package/dist/browser/seo/keyword-campaign-analyzer.d.ts +2 -0
  33. package/dist/browser/seo/keyword-campaign-analyzer.js +538 -0
  34. package/dist/browser/seo/keyword-campaign-seed-advanced.d.ts +17 -0
  35. package/dist/browser/seo/keyword-campaign-seed-advanced.js +269 -0
  36. package/dist/browser/seo/keyword-campaign-seed-core.d.ts +29 -0
  37. package/dist/browser/seo/keyword-campaign-seed-core.js +525 -0
  38. package/dist/browser/seo/keyword-campaign-shared.d.ts +165 -0
  39. package/dist/browser/seo/keyword-campaign-shared.js +59 -0
  40. package/dist/browser/seo/keyword-campaign.d.ts +4 -107
  41. package/dist/browser/seo/keyword-campaign.js +2 -380
  42. package/dist/browser/seo/keywords.js +5 -22
  43. package/dist/browser/seo/types.d.ts +19 -0
  44. package/dist/browser/transport/curl.d.ts +5 -1
  45. package/dist/browser/transport/curl.js +207 -50
  46. package/dist/browser/transport/undici.d.ts +4 -3
  47. package/dist/browser/transport/undici.js +123 -49
  48. package/dist/browser/types/index.d.ts +9 -3
  49. package/dist/browser/utils/binary-manager.js +26 -3
  50. package/dist/browser/utils/block-detector.d.ts +8 -0
  51. package/dist/browser/utils/block-detector.js +542 -7
  52. package/dist/cli/commands/hls-runner.js +5 -4
  53. package/dist/cli/commands/live-runner.js +5 -4
  54. package/dist/cli/commands/loadtest-runner.js +3 -2
  55. package/dist/cli/commands/search.d.ts +2 -0
  56. package/dist/cli/commands/search.js +105 -0
  57. package/dist/cli/commands/seo-runner.js +9 -7
  58. package/dist/cli/commands/seo.js +140 -1
  59. package/dist/cli/commands/serve.js +75 -131
  60. package/dist/cli/commands/server-runner.js +59 -82
  61. package/dist/cli/commands/spider-runner.d.ts +37 -1
  62. package/dist/cli/commands/spider-runner.js +134 -10
  63. package/dist/cli/commands/spider.d.ts +18 -1
  64. package/dist/cli/commands/spider.js +457 -27
  65. package/dist/cli/events/handlers/cli.js +30 -1
  66. package/dist/cli/events/handlers/tui.js +26 -0
  67. package/dist/cli/events/types.d.ts +27 -0
  68. package/dist/cli/handler.d.ts +2 -12
  69. package/dist/cli/handler.js +20 -15
  70. package/dist/cli/handlers/protocols.js +39 -12
  71. package/dist/cli/handlers/search.d.ts +2 -0
  72. package/dist/cli/handlers/search.js +171 -0
  73. package/dist/cli/handlers/seo-analyze.d.ts +1 -0
  74. package/dist/cli/handlers/seo-analyze.js +666 -0
  75. package/dist/cli/handlers/seo-robots.d.ts +1 -0
  76. package/dist/cli/handlers/seo-robots.js +76 -0
  77. package/dist/cli/handlers/seo-serp.d.ts +54 -0
  78. package/dist/cli/handlers/seo-serp.js +243 -0
  79. package/dist/cli/handlers/seo-sitemap.d.ts +1 -0
  80. package/dist/cli/handlers/seo-sitemap.js +55 -0
  81. package/dist/cli/handlers/seo-spider.d.ts +1 -0
  82. package/dist/cli/handlers/seo-spider.js +334 -0
  83. package/dist/cli/handlers/seo.d.ts +8 -4
  84. package/dist/cli/handlers/seo.js +294 -442
  85. package/dist/cli/handlers/spider.js +94 -17
  86. package/dist/cli/handlers/streaming.js +5 -1
  87. package/dist/cli/index.js +11 -2
  88. package/dist/cli/presets.d.ts +1 -1
  89. package/dist/cli/presets.js +15 -4
  90. package/dist/cli/tui/app.js +6 -1
  91. package/dist/cli/tui/components/rich-response.d.ts +72 -0
  92. package/dist/cli/tui/components/rich-response.js +117 -0
  93. package/dist/cli/tui/executor-commands/background.js +30 -24
  94. package/dist/cli/tui/executor-commands/testing.js +3 -2
  95. package/dist/cli/tui/hooks/useDomains.d.ts +17 -0
  96. package/dist/cli/tui/hooks/useHelp.js +15 -2
  97. package/dist/cli/tui/job-manager.d.ts +4 -4
  98. package/dist/cli/tui/job-manager.js +5 -1
  99. package/dist/cli/tui/spider-tui.d.ts +63 -0
  100. package/dist/cli/tui/spider-tui.js +120 -2
  101. package/dist/cli/types.d.ts +12 -0
  102. package/dist/cli/types.js +1 -0
  103. package/dist/cli/utils/option-helpers.d.ts +10 -0
  104. package/dist/cli/utils/option-helpers.js +63 -0
  105. package/dist/cli/utils/score-color.d.ts +11 -0
  106. package/dist/cli/utils/score-color.js +11 -0
  107. package/dist/cli/utils/serp-campaign.d.ts +53 -0
  108. package/dist/cli/utils/serp-campaign.js +53 -0
  109. package/dist/cli/utils/serp-config.d.ts +26 -0
  110. package/dist/cli/utils/serp-config.js +125 -0
  111. package/dist/core/client.d.ts +15 -10
  112. package/dist/core/client.js +54 -38
  113. package/dist/index.d.ts +1 -0
  114. package/dist/index.js +1 -0
  115. package/dist/mcp/cli.js +35 -34
  116. package/dist/mcp/client.d.ts +2 -2
  117. package/dist/mcp/client.js +20 -2
  118. package/dist/mcp/contract.d.ts +1 -1
  119. package/dist/mcp/profiles.js +5 -1
  120. package/dist/mcp/prompts/index.js +8 -4
  121. package/dist/mcp/resources/index.js +46 -23
  122. package/dist/mcp/server.js +9 -6
  123. package/dist/mcp/tools/protocols.js +9 -2
  124. package/dist/mcp/tools/registry.js +13 -3
  125. package/dist/mcp/tools/seo.js +427 -2
  126. package/dist/mcp/types.d.ts +5 -1
  127. package/dist/plugins/proxy-rotator.d.ts +2 -2
  128. package/dist/plugins/proxy-rotator.js +6 -28
  129. package/dist/raffel/client.d.ts +38 -0
  130. package/dist/raffel/client.js +282 -0
  131. package/dist/raffel/index.d.ts +2 -0
  132. package/dist/raffel/index.js +2 -0
  133. package/dist/raffel/types.d.ts +40 -0
  134. package/dist/raffel/types.js +14 -0
  135. package/dist/recker.d.ts +13 -7
  136. package/dist/recker.js +58 -6
  137. package/dist/scrape/document.js +2 -2
  138. package/dist/scrape/element.js +7 -1
  139. package/dist/scrape/parser/nodes/html.js +1 -1
  140. package/dist/scrape/spider.d.ts +52 -0
  141. package/dist/scrape/spider.js +620 -38
  142. package/dist/scrape/types.d.ts +2 -0
  143. package/dist/search/google.d.ts +26 -1
  144. package/dist/search/google.js +427 -45
  145. package/dist/search/index.d.ts +1 -1
  146. package/dist/seo/analyzer.d.ts +1 -0
  147. package/dist/seo/analyzer.js +144 -1
  148. package/dist/seo/index.d.ts +1 -1
  149. package/dist/seo/keyword-campaign-analyzer.d.ts +2 -0
  150. package/dist/seo/keyword-campaign-analyzer.js +538 -0
  151. package/dist/seo/keyword-campaign-seed-advanced.d.ts +17 -0
  152. package/dist/seo/keyword-campaign-seed-advanced.js +269 -0
  153. package/dist/seo/keyword-campaign-seed-core.d.ts +29 -0
  154. package/dist/seo/keyword-campaign-seed-core.js +525 -0
  155. package/dist/seo/keyword-campaign-shared.d.ts +165 -0
  156. package/dist/seo/keyword-campaign-shared.js +59 -0
  157. package/dist/seo/keyword-campaign.d.ts +4 -107
  158. package/dist/seo/keyword-campaign.js +2 -380
  159. package/dist/seo/keywords.js +5 -22
  160. package/dist/seo/types.d.ts +19 -0
  161. package/dist/template/index.d.ts +1 -1
  162. package/dist/template/types.d.ts +0 -2
  163. package/dist/testing/index.d.ts +1 -22
  164. package/dist/testing/index.js +1 -11
  165. package/dist/transport/curl.d.ts +5 -1
  166. package/dist/transport/curl.js +207 -50
  167. package/dist/transport/undici.d.ts +4 -3
  168. package/dist/transport/undici.js +123 -49
  169. package/dist/types/index.d.ts +9 -3
  170. package/dist/utils/binary-manager.js +26 -3
  171. package/dist/utils/block-detector.d.ts +8 -0
  172. package/dist/utils/block-detector.js +542 -7
  173. package/dist/version.js +1 -1
  174. package/package.json +12 -1
  175. package/dist/testing/mock-dns-server.d.ts +0 -69
  176. package/dist/testing/mock-dns-server.js +0 -269
  177. package/dist/testing/mock-ftp-server.d.ts +0 -89
  178. package/dist/testing/mock-ftp-server.js +0 -562
  179. package/dist/testing/mock-hls-server.d.ts +0 -80
  180. package/dist/testing/mock-hls-server.js +0 -381
  181. package/dist/testing/mock-http-server.d.ts +0 -124
  182. package/dist/testing/mock-http-server.js +0 -343
  183. package/dist/testing/mock-proxy-server.d.ts +0 -108
  184. package/dist/testing/mock-proxy-server.js +0 -615
  185. package/dist/testing/mock-sse-server.d.ts +0 -76
  186. package/dist/testing/mock-sse-server.js +0 -291
  187. package/dist/testing/mock-telnet-server.d.ts +0 -59
  188. package/dist/testing/mock-telnet-server.js +0 -274
  189. package/dist/testing/mock-udp-server.d.ts +0 -43
  190. package/dist/testing/mock-udp-server.js +0 -188
  191. package/dist/testing/mock-websocket-server.d.ts +0 -76
  192. package/dist/testing/mock-websocket-server.js +0 -334
  193. package/dist/testing/mock-whois-server.d.ts +0 -56
  194. package/dist/testing/mock-whois-server.js +0 -234
  195. package/dist/testing/proxy-certs.d.ts +0 -19
  196. package/dist/testing/proxy-certs.js +0 -208
@@ -0,0 +1,53 @@
1
+ import { runCrawlerSerpCampaign } from '../handlers/seo.js';
2
+ export async function runSpiderKeywordCampaign(targetUrl, pages, config) {
3
+ const normalizedPages = pages.map((page) => ({
4
+ url: page.url,
5
+ seoReport: page.seoReport,
6
+ }));
7
+ return runCrawlerSerpCampaign(targetUrl, normalizedPages, config);
8
+ }
9
+ function toKeywordCampaignResult(item) {
10
+ return {
11
+ keyword: item.keyword,
12
+ found: Boolean(item.found),
13
+ position: item.bestPosition,
14
+ targetUrl: item.matchedUrl,
15
+ searchUrl: item.searchUrl,
16
+ };
17
+ }
18
+ function toSerpSeedMap(plan) {
19
+ return plan.map((seed) => ({
20
+ keyword: seed.keyword,
21
+ sourcePage: seed.sourcePage,
22
+ sourceWeight: seed.sourceWeight,
23
+ }));
24
+ }
25
+ export function toSerpPayload(campaign) {
26
+ return {
27
+ summary: {
28
+ queriesRequested: campaign.campaign.summary.queriesRequested,
29
+ queriesExecuted: campaign.campaign.summary.queriesExecuted,
30
+ queriesFound: campaign.campaign.summary.queriesFound,
31
+ avgTopPosition: campaign.campaign.summary.avgTopPosition,
32
+ top3Count: campaign.campaign.summary.top3Count,
33
+ top10Count: campaign.campaign.summary.top10Count,
34
+ topOrganicCompetitors: campaign.campaign.summary.topOrganicCompetitors,
35
+ },
36
+ campaign: campaign.campaign.campaign,
37
+ results: campaign.campaign.results.slice(0, 12).map((item) => toKeywordCampaignResult(item)),
38
+ pageComparison: campaign.campaign.pageComparison.map((item) => ({
39
+ pageUrl: item.pageUrl,
40
+ tracked: item.tracked,
41
+ found: item.found,
42
+ appearanceRate: `${item.appearanceRate.toFixed(1)}%`,
43
+ avgPosition: item.avgPosition === null ? 'n/a' : String(item.avgPosition),
44
+ top3: item.top3,
45
+ top10: item.top10,
46
+ })),
47
+ seedPlan: {
48
+ short: toSerpSeedMap(campaign.plan.short),
49
+ longTail: toSerpSeedMap(campaign.plan.longTail),
50
+ ordered: toSerpSeedMap(campaign.plan.ordered),
51
+ },
52
+ };
53
+ }
@@ -0,0 +1,26 @@
1
+ import type { GoogleSearchAdvancedOptions } from '../../search/google.js';
2
+ export declare const DEFAULT_SERP_KEYWORD_LIMIT = 5;
3
+ export declare const DEFAULT_SERP_MAX_RESULTS = 10;
4
+ export declare const DEFAULT_SERP_CONCURRENCY = 1;
5
+ export declare const DEFAULT_SERP_DELAY_MS = 1200;
6
+ export declare const DEFAULT_SERP_JITTER_MS = 450;
7
+ export declare const DEFAULT_SERP_CAPTCHA_COOLDOWN_MS = 2400;
8
+ export declare const DEFAULT_SERP_MAX_CONSECUTIVE_BLOCKS = 3;
9
+ export declare const DEFAULT_SERP_RETRY_COUNT = 1;
10
+ export declare const DEFAULT_SERP_RETRY_DELAY_MS = 1200;
11
+ export declare const DEFAULT_SERP_HUMAN_PROFILE: 'chrome' | 'off';
12
+ export interface SpiderSerpOptionConfig {
13
+ enabled: boolean;
14
+ topKeywordsLimit: number;
15
+ queriesLimit: number;
16
+ resultsPerQuery: number;
17
+ searchConcurrency: number;
18
+ searchDelayMs: number;
19
+ searchDelayJitterMs: number;
20
+ searchCaptchaCooldownMs: number;
21
+ searchMaxConsecutiveBlocks?: number;
22
+ searchRetryCount: number;
23
+ searchRetryDelayMs: number;
24
+ searchOptions: GoogleSearchAdvancedOptions;
25
+ }
26
+ export declare function parseSpiderSerpConfig(options: Record<string, unknown>): SpiderSerpOptionConfig;
@@ -0,0 +1,125 @@
1
+ import { getOptionValue, toOptionString, toNonNegativeInt, } from './option-helpers.js';
2
+ export const DEFAULT_SERP_KEYWORD_LIMIT = 5;
3
+ export const DEFAULT_SERP_MAX_RESULTS = 10;
4
+ export const DEFAULT_SERP_CONCURRENCY = 1;
5
+ export const DEFAULT_SERP_DELAY_MS = 1200;
6
+ export const DEFAULT_SERP_JITTER_MS = 450;
7
+ export const DEFAULT_SERP_CAPTCHA_COOLDOWN_MS = 2400;
8
+ export const DEFAULT_SERP_MAX_CONSECUTIVE_BLOCKS = 3;
9
+ export const DEFAULT_SERP_RETRY_COUNT = 1;
10
+ export const DEFAULT_SERP_RETRY_DELAY_MS = 1_200;
11
+ export const DEFAULT_SERP_HUMAN_PROFILE = 'chrome';
12
+ function toSearchTransport(value) {
13
+ const raw = toOptionString(value)?.toLowerCase();
14
+ if (raw === 'auto' || raw === 'undici' || raw === 'curl')
15
+ return raw;
16
+ return 'curl';
17
+ }
18
+ function toSerpSearchSource(value) {
19
+ const raw = toOptionString(value)?.toLowerCase();
20
+ return raw === 'google' ? 'google' : 'google';
21
+ }
22
+ function parseSerpExtraParams(value) {
23
+ const raw = toOptionString(value);
24
+ if (!raw)
25
+ return undefined;
26
+ const params = {};
27
+ const chunks = raw.includes('&')
28
+ ? raw.split('&')
29
+ : raw.includes(';')
30
+ ? raw.split(';')
31
+ : raw.split(',');
32
+ for (const chunk of chunks) {
33
+ const pair = chunk.trim();
34
+ if (!pair)
35
+ continue;
36
+ const idx = pair.indexOf('=');
37
+ if (idx <= 0)
38
+ continue;
39
+ const key = pair.slice(0, idx).trim();
40
+ const value = pair.slice(idx + 1).trim();
41
+ if (!key || !value)
42
+ continue;
43
+ if (/^(true|false)$/i.test(value)) {
44
+ params[key] = value.toLowerCase() === 'true';
45
+ continue;
46
+ }
47
+ const numberValue = Number(value);
48
+ if (Number.isFinite(numberValue)) {
49
+ params[key] = numberValue;
50
+ continue;
51
+ }
52
+ params[key] = value;
53
+ }
54
+ return Object.keys(params).length > 0 ? params : undefined;
55
+ }
56
+ function parseSerpHumanProfile(value) {
57
+ if (typeof value !== 'string') {
58
+ return DEFAULT_SERP_HUMAN_PROFILE;
59
+ }
60
+ const normalized = value.trim().toLowerCase();
61
+ if (!normalized || normalized === 'off' || normalized === 'false' || normalized === 'none' || normalized === '0') {
62
+ return 'off';
63
+ }
64
+ if (normalized === 'chrome' || normalized === 'browser' || normalized === 'human') {
65
+ return 'chrome';
66
+ }
67
+ if (normalized === 'default' || normalized === 'on' || normalized === 'true' || normalized === '1') {
68
+ return 'chrome';
69
+ }
70
+ return DEFAULT_SERP_HUMAN_PROFILE;
71
+ }
72
+ export function parseSpiderSerpConfig(options) {
73
+ const enabled = Boolean(getOptionValue(options, 'serp', 'serpEnabled'));
74
+ const topKeywordsLimit = toNonNegativeInt(getOptionValue(options, 'serpTopKeywords', 'serp-top-keywords'), DEFAULT_SERP_KEYWORD_LIMIT);
75
+ const queriesLimit = toNonNegativeInt(getOptionValue(options, 'serpQueryLimit', 'serp-query-limit'), DEFAULT_SERP_MAX_RESULTS);
76
+ const resultsPerQuery = toNonNegativeInt(getOptionValue(options, 'serpResultsPerQuery', 'serp-results-per-query'), DEFAULT_SERP_MAX_RESULTS);
77
+ const searchConcurrency = toNonNegativeInt(getOptionValue(options, 'serpConcurrency', 'serp-concurrency'), DEFAULT_SERP_CONCURRENCY);
78
+ const searchDelayMs = toNonNegativeInt(getOptionValue(options, 'serpDelayMs', 'serp-delay-ms', 'serpDelay'), DEFAULT_SERP_DELAY_MS);
79
+ const searchDelayJitterMs = toNonNegativeInt(getOptionValue(options, 'serpDelayJitterMs', 'serp-delay-jitter-ms', 'serpJitterMs'), DEFAULT_SERP_JITTER_MS);
80
+ const searchCaptchaCooldownMs = toNonNegativeInt(getOptionValue(options, 'serpCaptchaCooldownMs', 'serp-captcha-cooldown-ms', 'serpCaptchaCooldown'), DEFAULT_SERP_CAPTCHA_COOLDOWN_MS);
81
+ const searchMaxConsecutiveBlocks = toNonNegativeInt(getOptionValue(options, 'serpMaxConsecutiveBlocks', 'serp-max-consecutive-blocks'), DEFAULT_SERP_MAX_CONSECUTIVE_BLOCKS);
82
+ const searchRetryCount = toNonNegativeInt(getOptionValue(options, 'serpRetryCount', 'serp-retry-count', 'serpRetries'), DEFAULT_SERP_RETRY_COUNT);
83
+ const searchRetryDelayMs = toNonNegativeInt(getOptionValue(options, 'serpRetryDelayMs', 'serp-retry-delay-ms', 'serpRetryDelay'), DEFAULT_SERP_RETRY_DELAY_MS);
84
+ const searchSource = toSerpSearchSource(getOptionValue(options, 'serpSource', 'serp-source'));
85
+ const country = getOptionValue(options, 'serpCountry', 'serp-country', 'serpRegion', 'serp-region');
86
+ return {
87
+ enabled,
88
+ topKeywordsLimit: topKeywordsLimit > 0 ? topKeywordsLimit : DEFAULT_SERP_KEYWORD_LIMIT,
89
+ queriesLimit: queriesLimit > 0 ? queriesLimit : DEFAULT_SERP_MAX_RESULTS,
90
+ resultsPerQuery: resultsPerQuery > 0 ? resultsPerQuery : DEFAULT_SERP_MAX_RESULTS,
91
+ searchConcurrency: searchConcurrency > 0 ? searchConcurrency : DEFAULT_SERP_CONCURRENCY,
92
+ searchDelayMs: searchDelayMs > 0 ? searchDelayMs : DEFAULT_SERP_DELAY_MS,
93
+ searchDelayJitterMs: searchDelayJitterMs > 0 ? searchDelayJitterMs : DEFAULT_SERP_JITTER_MS,
94
+ searchCaptchaCooldownMs: searchCaptchaCooldownMs > 0 ? searchCaptchaCooldownMs : DEFAULT_SERP_CAPTCHA_COOLDOWN_MS,
95
+ searchMaxConsecutiveBlocks: searchMaxConsecutiveBlocks >= 0
96
+ ? searchMaxConsecutiveBlocks
97
+ : DEFAULT_SERP_MAX_CONSECUTIVE_BLOCKS,
98
+ searchRetryCount: searchRetryCount >= 0 ? searchRetryCount : DEFAULT_SERP_RETRY_COUNT,
99
+ searchRetryDelayMs: searchRetryDelayMs > 0 ? searchRetryDelayMs : DEFAULT_SERP_RETRY_DELAY_MS,
100
+ searchOptions: {
101
+ transport: toSearchTransport(getOptionValue(options, 'serpTransport', 'serp-transport')),
102
+ source: searchSource,
103
+ timeout: toNonNegativeInt(getOptionValue(options, 'serpTimeout', 'serp-timeout'), 0) || undefined,
104
+ country: toOptionString(country),
105
+ gl: toOptionString(getOptionValue(options, 'serpGl', 'serp-gl')),
106
+ hl: toOptionString(getOptionValue(options, 'serpHl', 'serp-hl')),
107
+ safe: toOptionString(getOptionValue(options, 'serpSafe', 'serp-safe')),
108
+ as_q: toOptionString(getOptionValue(options, 'serpAsQ', 'serp-as-q')),
109
+ as_epq: toOptionString(getOptionValue(options, 'serpAsEpq', 'serp-as-epq', 'serpAsEpq')),
110
+ as_oq: toOptionString(getOptionValue(options, 'serpAsOq', 'serp-as-oq')),
111
+ as_eq: toOptionString(getOptionValue(options, 'serpAsEq', 'serp-as-eq')),
112
+ as_sitesearch: toOptionString(getOptionValue(options, 'serpAsSitesearch', 'serp-as-sitesearch', 'serpAsSitesearch')),
113
+ as_filetype: toOptionString(getOptionValue(options, 'serpAsFiletype', 'serp-as-filetype', 'serpAsFiletype')),
114
+ as_rights: toOptionString(getOptionValue(options, 'serpAsRights', 'serp-as-rights', 'serpAsRights')),
115
+ as_nlo: toOptionString(getOptionValue(options, 'serpAsNlo', 'serp-as-nlo', 'serpNlo')),
116
+ as_nhi: toOptionString(getOptionValue(options, 'serpAsNhi', 'serp-as-nhi', 'serpNhi')),
117
+ humanProfile: parseSerpHumanProfile(getOptionValue(options, 'serpHumanProfile', 'serp-human-profile')),
118
+ lr: toOptionString(getOptionValue(options, 'serpLr', 'serp-lr')),
119
+ cr: toOptionString(getOptionValue(options, 'serpCr', 'serp-cr')),
120
+ tbs: toOptionString(getOptionValue(options, 'serpTbs', 'serp-tbs')),
121
+ tbm: toOptionString(getOptionValue(options, 'serpTbm', 'serp-tbm')),
122
+ extraParams: parseSerpExtraParams(getOptionValue(options, 'serpExtra', 'serp-extra')),
123
+ },
124
+ };
125
+ }
@@ -22,6 +22,7 @@ interface BatchRequestOptions<T = ReckerResponse> {
22
22
  signal?: AbortSignal;
23
23
  deadlineMs?: number;
24
24
  }
25
+ type RequestWithBodyOptions = Omit<RequestOptions, 'method'>;
25
26
  export interface ExtendedClientOptions extends ClientOptions {
26
27
  retry?: RetryOptions;
27
28
  cache?: ClientCacheConfig;
@@ -36,6 +37,7 @@ export declare class Client {
36
37
  private hooks;
37
38
  private transport;
38
39
  private curlTransport?;
40
+ private proxyConfig?;
39
41
  private defaultHeaders;
40
42
  private defaultHeadersObj;
41
43
  private defaultParams;
@@ -104,28 +106,31 @@ export declare class Client {
104
106
  };
105
107
  }>;
106
108
  private requestWithBody;
107
- post<T = unknown>(path: string, body?: any, options?: Omit<RequestOptions, 'method' | 'body'>): RequestPromise<T>;
108
- put<T = unknown>(path: string, body?: any, options?: Omit<RequestOptions, 'method' | 'body'>): RequestPromise<T>;
109
- patch<T = unknown>(path: string, body?: any, options?: Omit<RequestOptions, 'method' | 'body'>): RequestPromise<T>;
109
+ post<T = unknown>(path: string, options?: RequestWithBodyOptions): RequestPromise<T>;
110
+ post<T = unknown>(path: string, body?: unknown, options?: RequestWithBodyOptions): RequestPromise<T>;
111
+ put<T = unknown>(path: string, options?: RequestWithBodyOptions): RequestPromise<T>;
112
+ put<T = unknown>(path: string, body?: unknown, options?: RequestWithBodyOptions): RequestPromise<T>;
113
+ patch<T = unknown>(path: string, options?: RequestWithBodyOptions): RequestPromise<T>;
114
+ patch<T = unknown>(path: string, body?: unknown, options?: RequestWithBodyOptions): RequestPromise<T>;
110
115
  delete<T = unknown>(path: string, options?: Omit<RequestOptions, 'method'>): RequestPromise<T>;
111
116
  head<T = unknown>(path: string, options?: Omit<RequestOptions, 'method'>): RequestPromise<T>;
112
117
  options<T = unknown>(path: string, options?: Omit<RequestOptions, 'method'>): RequestPromise<T>;
113
118
  trace<T = unknown>(path: string, options?: Omit<RequestOptions, 'method'>): RequestPromise<T>;
114
119
  connect<T = unknown>(path: string, options?: Omit<RequestOptions, 'method'>): RequestPromise<T>;
115
120
  purge<T = unknown>(path: string, options?: Omit<RequestOptions, 'method'>): RequestPromise<T>;
116
- propfind<T = unknown>(path: string, body?: any, options?: Omit<RequestOptions, 'method' | 'body'>): RequestPromise<T>;
117
- proppatch<T = unknown>(path: string, body?: any, options?: Omit<RequestOptions, 'method' | 'body'>): RequestPromise<T>;
121
+ propfind<T = unknown>(path: string, body?: unknown, options?: RequestWithBodyOptions): RequestPromise<T>;
122
+ proppatch<T = unknown>(path: string, body?: unknown, options?: RequestWithBodyOptions): RequestPromise<T>;
118
123
  mkcol<T = unknown>(path: string, options?: Omit<RequestOptions, 'method'>): RequestPromise<T>;
119
124
  copy<T = unknown>(path: string, options?: Omit<RequestOptions, 'method'>): RequestPromise<T>;
120
125
  move<T = unknown>(path: string, options?: Omit<RequestOptions, 'method'>): RequestPromise<T>;
121
- lock<T = unknown>(path: string, body?: any, options?: Omit<RequestOptions, 'method' | 'body'>): RequestPromise<T>;
126
+ lock<T = unknown>(path: string, body?: unknown, options?: RequestWithBodyOptions): RequestPromise<T>;
122
127
  unlock<T = unknown>(path: string, options?: Omit<RequestOptions, 'method'>): RequestPromise<T>;
123
- link<T = unknown>(path: string, body?: any, options?: Omit<RequestOptions, 'method' | 'body'>): RequestPromise<T>;
124
- unlink<T = unknown>(path: string, body?: any, options?: Omit<RequestOptions, 'method' | 'body'>): RequestPromise<T>;
128
+ link<T = unknown>(path: string, body?: unknown, options?: RequestWithBodyOptions): RequestPromise<T>;
129
+ unlink<T = unknown>(path: string, body?: unknown, options?: RequestWithBodyOptions): RequestPromise<T>;
125
130
  scrape(path: string, options?: RequestOptions): ScrapePromise<ReckerResponse>;
126
131
  paginate<T>(path: string, options?: RequestOptions & PaginationOptions<T>): AsyncGenerator<T>;
127
- pages<T = any>(path: string, options?: RequestOptions & PaginationOptions): AsyncGenerator<PageResult<T>>;
128
- page<T = any>(path: string, pageNumber: number, options?: RequestOptions & {
132
+ pages<T = unknown>(path: string, options?: RequestOptions & PaginationOptions): AsyncGenerator<PageResult<T>>;
133
+ page<T = unknown>(path: string, pageNumber: number, options?: RequestOptions & {
129
134
  pageParam?: string;
130
135
  }): RequestPromise<T>;
131
136
  getAll<T>(path: string, options?: RequestOptions & PaginationOptions<T>): Promise<T[]>;
@@ -28,8 +28,34 @@ import { ReckerWebSocket } from '../websocket/client.js';
28
28
  import { whois as performWhois, isDomainAvailable } from '../utils/whois.js';
29
29
  import { MemoryCookieJar } from '../cookies/memory-cookie-jar.js';
30
30
  import { scrape as scrapeHelper } from '../plugins/scrape.js';
31
+ const toError = (error) => error instanceof Error ? error : new Error(String(error));
32
+ const BODY_OPTION_HINTS = [
33
+ 'json',
34
+ 'form',
35
+ 'xml',
36
+ 'yaml',
37
+ 'csv',
38
+ 'body',
39
+ 'headers',
40
+ 'timeout',
41
+ 'retry',
42
+ 'hooks',
43
+ 'searchParams',
44
+ 'params',
45
+ 'beforeRedirect',
46
+ 'maxRedirects',
47
+ 'followRedirects',
48
+ 'http2',
49
+ 'useCurl',
50
+ ];
31
51
  function isNodeRuntime() {
32
- return typeof globalThis !== 'undefined' && Boolean(globalThis.process?.versions?.node);
52
+ const maybeNodeGlobal = globalThis;
53
+ return typeof globalThis !== 'undefined' && Boolean(maybeNodeGlobal.process?.versions?.node);
54
+ }
55
+ function isRequestWithBodyOptions(value) {
56
+ if (!isPlainObject(value))
57
+ return false;
58
+ return BODY_OPTION_HINTS.some((key) => Object.prototype.hasOwnProperty.call(value, key));
33
59
  }
34
60
  class LazyTransport {
35
61
  factory;
@@ -67,7 +93,7 @@ class LazyTransport {
67
93
  await this.resolving;
68
94
  }
69
95
  }
70
- function createLazyCurlTransport() {
96
+ function createLazyCurlTransport(proxy) {
71
97
  if (!isNodeRuntime()) {
72
98
  return {
73
99
  async dispatch(req) {
@@ -77,7 +103,7 @@ function createLazyCurlTransport() {
77
103
  }
78
104
  return new LazyTransport(async () => {
79
105
  const { CurlTransport } = await import('../transport/curl.js');
80
- return new CurlTransport();
106
+ return new CurlTransport(proxy);
81
107
  });
82
108
  }
83
109
  class LazyCacheStorage {
@@ -179,6 +205,7 @@ export class Client {
179
205
  hooks;
180
206
  transport;
181
207
  curlTransport;
208
+ proxyConfig;
182
209
  defaultHeaders;
183
210
  defaultHeadersObj;
184
211
  defaultParams;
@@ -222,6 +249,7 @@ export class Client {
222
249
  this.defaultParams = options.defaults?.params || {};
223
250
  this.paginationConfig = options.pagination;
224
251
  this.maxResponseSize = options.maxResponseSize;
252
+ this.proxyConfig = options.proxy;
225
253
  const runtimeEventBus = options.runtimeEventBus;
226
254
  if (runtimeEventBus) {
227
255
  this.runtimeEventBus = {
@@ -254,7 +282,7 @@ export class Client {
254
282
  else if (options.useCurl) {
255
283
  if (this.debugEnabled)
256
284
  console.log('[DEBUG] Using Curl Transport');
257
- this.transport = createLazyCurlTransport();
285
+ this.transport = createLazyCurlTransport(options.proxy);
258
286
  this.transportKind = 'curl';
259
287
  }
260
288
  else if (isNodeRuntime()) {
@@ -290,8 +318,9 @@ export class Client {
290
318
  this.transportKind = 'undici';
291
319
  }
292
320
  else {
293
- if (this.debugEnabled)
294
- console.log('[DEBUG] Using Fetch Transport');
321
+ if (this.debugEnabled && this.logger) {
322
+ this.logger.debug('Using Fetch Transport');
323
+ }
295
324
  this.transport = new FetchTransport();
296
325
  this.transportKind = 'fetch';
297
326
  }
@@ -317,7 +346,8 @@ export class Client {
317
346
  interval: this.concurrencyConfig.interval
318
347
  });
319
348
  registerPlugin((client) => {
320
- client.middlewares.unshift(this.requestPool.asMiddleware());
349
+ const pluginClient = client;
350
+ pluginClient.middlewares?.unshift(this.requestPool.asMiddleware());
321
351
  }, {
322
352
  name: 'recker:request-pool',
323
353
  priority: 130,
@@ -525,7 +555,7 @@ export class Client {
525
555
  try {
526
556
  if (req.useCurl && this.transportKind !== 'curl') {
527
557
  if (!this.curlTransport) {
528
- this.curlTransport = createLazyCurlTransport();
558
+ this.curlTransport = createLazyCurlTransport(this.proxyConfig);
529
559
  }
530
560
  const response = await this.curlTransport.dispatch(req);
531
561
  if (context) {
@@ -552,7 +582,7 @@ export class Client {
552
582
  this.runtimeEventBus.emit('transport:error', {
553
583
  context,
554
584
  req,
555
- error: error instanceof Error ? error : new Error(String(error))
585
+ error: toError(error)
556
586
  });
557
587
  }
558
588
  throw error;
@@ -768,7 +798,7 @@ export class Client {
768
798
  });
769
799
  return response;
770
800
  }, (error) => {
771
- const requestError = error instanceof Error ? error : new Error(String(error));
801
+ const requestError = toError(error);
772
802
  this.runtimeEventBus.emit('request:failed', {
773
803
  context: requestContext,
774
804
  req,
@@ -849,7 +879,7 @@ export class Client {
849
879
  });
850
880
  return response;
851
881
  }, (error) => {
852
- const requestError = error instanceof Error ? error : new Error(String(error));
882
+ const requestError = toError(error);
853
883
  this.runtimeEventBus.emit('request:failed', {
854
884
  context: requestContext,
855
885
  req,
@@ -873,8 +903,9 @@ export class Client {
873
903
  return this.request(path, { ...options, method: 'GET' });
874
904
  }
875
905
  async warmup() {
876
- if (this.transport && 'warmup' in this.transport && typeof this.transport.warmup === 'function') {
877
- await this.transport.warmup();
906
+ const transport = this.transport;
907
+ if (transport?.warmup) {
908
+ await transport.warmup();
878
909
  }
879
910
  }
880
911
  async batch(requests, options = {}) {
@@ -899,29 +930,14 @@ export class Client {
899
930
  }
900
931
  requestWithBody(method, path, bodyOrOptions, options) {
901
932
  let actualBody = bodyOrOptions;
902
- let actualOptions = options;
903
- const isOptionsEmpty = actualOptions === undefined ||
904
- (typeof actualOptions === 'object' && actualOptions !== null && Object.keys(actualOptions).length === 0);
905
- if (isOptionsEmpty && isPlainObject(bodyOrOptions)) {
906
- const potentialOptions = bodyOrOptions;
907
- if (potentialOptions.json !== undefined ||
908
- potentialOptions.form !== undefined ||
909
- potentialOptions.xml !== undefined ||
910
- potentialOptions.yaml !== undefined ||
911
- potentialOptions.csv !== undefined ||
912
- potentialOptions.body !== undefined ||
913
- potentialOptions.headers !== undefined ||
914
- potentialOptions.timeout !== undefined ||
915
- potentialOptions.retry !== undefined ||
916
- potentialOptions.hooks !== undefined ||
917
- potentialOptions.searchParams !== undefined ||
918
- potentialOptions.params !== undefined) {
919
- actualOptions = bodyOrOptions;
920
- actualBody = undefined;
921
- }
922
- }
923
- actualOptions = actualOptions || {};
924
- const { json, form, xml, yaml, csv, ...restOptions } = actualOptions;
933
+ let actualOptions = options || {};
934
+ const isOptionsEmpty = options === undefined
935
+ || (isPlainObject(options) && Object.keys(options).length === 0);
936
+ if (isOptionsEmpty && isRequestWithBodyOptions(bodyOrOptions)) {
937
+ actualOptions = bodyOrOptions;
938
+ actualBody = undefined;
939
+ }
940
+ const { json, form, xml, yaml, csv, body: explicitBody, ...restOptions } = actualOptions;
925
941
  let finalBody = actualBody;
926
942
  let explicitContentType;
927
943
  if (form !== undefined) {
@@ -944,8 +960,8 @@ export class Client {
944
960
  finalBody = serializeCsv(csv);
945
961
  explicitContentType = 'text/csv';
946
962
  }
947
- else if (restOptions.body !== undefined) {
948
- finalBody = restOptions.body;
963
+ else if (explicitBody !== undefined) {
964
+ finalBody = explicitBody;
949
965
  }
950
966
  const { body: processedBody, contentType } = processBody(finalBody);
951
967
  const headers = new Headers(restOptions.headers);
package/dist/index.d.ts CHANGED
@@ -74,6 +74,7 @@ export * from './utils/concurrency.js';
74
74
  export * as presets from './presets/index.js';
75
75
  export * as testing from './testing/index.js';
76
76
  export * as protocols from './protocols/index.js';
77
+ export * from './raffel/index.js';
77
78
  export * from './mcp/client.js';
78
79
  export * from './mcp/contract.js';
79
80
  export * as template from './template/index.js';
package/dist/index.js CHANGED
@@ -74,6 +74,7 @@ export * from './utils/concurrency.js';
74
74
  export * as presets from './presets/index.js';
75
75
  export * as testing from './testing/index.js';
76
76
  export * as protocols from './protocols/index.js';
77
+ export * from './raffel/index.js';
77
78
  export * from './mcp/client.js';
78
79
  export * from './mcp/contract.js';
79
80
  export * as template from './template/index.js';
package/dist/mcp/cli.js CHANGED
@@ -3,6 +3,7 @@ import { RekCommand as Command } from '../cli/router.js';
3
3
  import { MCPServer } from './server.js';
4
4
  import { listCategories, DEFAULT_CATEGORY, validateCategories, estimateCategoryTokens, } from './profiles.js';
5
5
  import { LEGACY_TOOL_GROUPS } from './legacy-tool-groups.js';
6
+ import { consoleLogger } from '../types/logger.js';
6
7
  const program = new Command('recker-mcp');
7
8
  program
8
9
  .description('Start the Recker MCP server for AI agent integration')
@@ -29,25 +30,25 @@ program
29
30
  opts.transport = opts.transport || 'stdio';
30
31
  opts.port = opts.port || '3100';
31
32
  if (opts.listCategories) {
32
- console.log('╔═══════════════════════════════════════════════════════════════════╗');
33
- console.log('║ Recker MCP Categories ║');
34
- console.log('╚═══════════════════════════════════════════════════════════════════╝');
35
- console.log('');
36
- console.log('Available categories:');
37
- console.log('');
33
+ consoleLogger.info('╔═══════════════════════════════════════════════════════════════════╗');
34
+ consoleLogger.info('║ Recker MCP Categories ║');
35
+ consoleLogger.info('╚═══════════════════════════════════════════════════════════════════╝');
36
+ consoleLogger.info('');
37
+ consoleLogger.info('Available categories:');
38
+ consoleLogger.info('');
38
39
  for (const category of listCategories()) {
39
40
  const toolCount = category.toolCount === -1 ? 'all' : category.toolCount;
40
41
  const icon = category.icon || '📦';
41
- console.log(` ${icon} ${category.name.padEnd(12)} ${category.description}`);
42
- console.log(` Tools: ${toolCount}, ~${category.estimatedTokens} tokens`);
43
- console.log('');
42
+ consoleLogger.info(` ${icon} ${category.name.padEnd(12)} ${category.description}`);
43
+ consoleLogger.info(` Tools: ${toolCount}, ~${category.estimatedTokens} tokens`);
44
+ consoleLogger.info('');
44
45
  }
45
- console.log('Usage examples:');
46
- console.log(' recker-mcp # Default: minimal category');
47
- console.log(' recker-mcp --category=minimal,seo # Combine categories');
48
- console.log(' recker-mcp -c seo,security # Short form');
49
- console.log(' recker-mcp --category=full # All tools (high context)');
50
- console.log('');
46
+ consoleLogger.info('Usage examples:');
47
+ consoleLogger.info(' recker-mcp # Default: minimal category');
48
+ consoleLogger.info(' recker-mcp --category=minimal,seo # Combine categories');
49
+ consoleLogger.info(' recker-mcp -c seo,security # Short form');
50
+ consoleLogger.info(' recker-mcp --category=full # All tools (high context)');
51
+ consoleLogger.info('');
51
52
  process.exit(0);
52
53
  }
53
54
  const useExplicitCategory = Boolean(opts.category);
@@ -55,8 +56,8 @@ program
55
56
  const categoryNames = opts.category.split(',').map((p) => p.trim());
56
57
  const validation = validateCategories(categoryNames);
57
58
  if (!validation.valid) {
58
- console.error(`Invalid category(s): ${validation.invalid.join(', ')}`);
59
- console.error('Use --list-categories to see available categories');
59
+ consoleLogger.error(`Invalid category(s): ${validation.invalid.join(', ')}`);
60
+ consoleLogger.error('Use --list-categories to see available categories');
60
61
  process.exit(1);
61
62
  }
62
63
  }
@@ -97,7 +98,7 @@ program
97
98
  const transport = opts.transport;
98
99
  const port = parseInt(opts.port, 10);
99
100
  if (!['stdio', 'http', 'sse'].includes(transport)) {
100
- console.error(`Invalid transport mode: ${transport}. Use: stdio, http, or sse`);
101
+ consoleLogger.error(`Invalid transport mode: ${transport}. Use: stdio, http, or sse`);
101
102
  process.exit(1);
102
103
  }
103
104
  const effectiveCategory = useExplicitCategory ? opts.category : (!opts.only && !opts.filter ? DEFAULT_CATEGORY : undefined);
@@ -112,25 +113,25 @@ program
112
113
  toolsFilter: !effectiveCategory && toolsFilter.length > 0 ? toolsFilter : undefined,
113
114
  });
114
115
  if (transport !== 'stdio') {
115
- console.log('╔═══════════════════════════════════════════════════════════════════╗');
116
- console.log('║ Recker MCP Server ║');
117
- console.log('╚═══════════════════════════════════════════════════════════════════╝');
118
- console.log('');
119
- console.log(` Transport: ${transport}`);
120
- console.log(` Port: ${port}`);
121
- console.log(` Debug: ${opts.debug ? 'enabled' : 'disabled'}`);
116
+ consoleLogger.info('╔═══════════════════════════════════════════════════════════════════╗');
117
+ consoleLogger.info('║ Recker MCP Server ║');
118
+ consoleLogger.info('╚═══════════════════════════════════════════════════════════════════╝');
119
+ consoleLogger.info('');
120
+ consoleLogger.info(` Transport: ${transport}`);
121
+ consoleLogger.info(` Port: ${port}`);
122
+ consoleLogger.info(` Debug: ${opts.debug ? 'enabled' : 'disabled'}`);
122
123
  if (effectiveCategory) {
123
124
  const tokens = estimateCategoryTokens(effectiveCategory);
124
- console.log(` Category: ${effectiveCategory} (~${tokens} tokens)`);
125
+ consoleLogger.info(` Category: ${effectiveCategory} (~${tokens} tokens)`);
125
126
  }
126
127
  else if (toolsFilter.length > 0) {
127
- console.log(` Filters: ${toolsFilter.join(', ')}`);
128
+ consoleLogger.info(` Filters: ${toolsFilter.join(', ')}`);
128
129
  }
129
130
  else {
130
- console.log(` Category: minimal (default)`);
131
+ consoleLogger.info(' Category: minimal (default)');
131
132
  }
132
- console.log('');
133
- console.log(' Available tools:');
133
+ consoleLogger.info('');
134
+ consoleLogger.info(' Available tools:');
134
135
  const allTools = [
135
136
  ...LEGACY_TOOL_GROUPS.docs,
136
137
  ...LEGACY_TOOL_GROUPS.network,
@@ -148,15 +149,15 @@ program
148
149
  return positive.includes(tool);
149
150
  });
150
151
  enabledTools.forEach(tool => {
151
- console.log(` ✓ ${tool}`);
152
+ consoleLogger.info(` ✓ ${tool}`);
152
153
  });
153
154
  const disabledTools = allTools.filter(t => !enabledTools.includes(t));
154
155
  if (disabledTools.length > 0) {
155
- disabledTools.forEach(tool => {
156
- console.log(` ✗ ${tool} (disabled)`);
156
+ disabledTools.forEach((tool) => {
157
+ consoleLogger.info(` ✗ ${tool} (disabled)`);
157
158
  });
158
159
  }
159
- console.log('');
160
+ consoleLogger.info('');
160
161
  }
161
162
  await server.start();
162
163
  });
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from 'events';
2
- import type { MCPServerInfo, MCPTool, MCPToolResult, MCPResource, MCPResourceContent, MCPPrompt, MCPPromptMessage } from './types.js';
2
+ import type { MCPServerInfo, MCPTool, MCPToolResult, MCPResource, MCPResourceContent, MCPPrompt, MCPPromptMessage, MCPTransportOptions } from './types.js';
3
3
  export interface MCPClientOptions {
4
4
  endpoint: string;
5
5
  clientName?: string;
@@ -9,7 +9,7 @@ export interface MCPClientOptions {
9
9
  timeout?: number;
10
10
  retries?: number;
11
11
  debug?: boolean;
12
- transport?: any;
12
+ transport?: MCPTransportOptions['transport'];
13
13
  }
14
14
  interface ResolvedMCPClientOptions {
15
15
  endpoint: string;