recker 1.0.43 → 1.0.44-next.084c2ef

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 (464) hide show
  1. package/README.md +47 -0
  2. package/dist/bin/recker-linux-x64 +0 -0
  3. package/dist/bin/recker-macos-x64 +0 -0
  4. package/dist/bin/recker-win-x64.exe +0 -0
  5. package/dist/bin/rek.cjs +85617 -99560
  6. package/dist/browser/ai/adaptive-timeout.d.ts +50 -0
  7. package/dist/browser/ai/adaptive-timeout.js +208 -0
  8. package/dist/browser/ai/client.d.ts +22 -0
  9. package/dist/browser/ai/client.js +294 -0
  10. package/dist/browser/ai/index.d.ts +14 -0
  11. package/dist/browser/ai/index.js +11 -0
  12. package/dist/browser/ai/providers/anthropic.d.ts +63 -0
  13. package/dist/browser/ai/providers/anthropic.js +370 -0
  14. package/dist/browser/ai/providers/base.d.ts +48 -0
  15. package/dist/browser/ai/providers/base.js +150 -0
  16. package/dist/browser/ai/providers/google.d.ts +59 -0
  17. package/dist/browser/ai/providers/google.js +305 -0
  18. package/dist/browser/ai/providers/ollama.d.ts +44 -0
  19. package/dist/browser/ai/providers/ollama.js +240 -0
  20. package/dist/browser/ai/providers/openai.d.ts +64 -0
  21. package/dist/browser/ai/providers/openai.js +298 -0
  22. package/dist/browser/ai/rate-limiter.d.ts +43 -0
  23. package/dist/browser/ai/rate-limiter.js +215 -0
  24. package/dist/browser/ai/vector/index.d.ts +2 -0
  25. package/dist/browser/ai/vector/index.js +2 -0
  26. package/dist/browser/ai/vector/similarity.d.ts +2 -0
  27. package/dist/browser/ai/vector/similarity.js +27 -0
  28. package/dist/browser/ai/vector/store.d.ts +27 -0
  29. package/dist/browser/ai/vector/store.js +82 -0
  30. package/dist/browser/browser/cache.d.ts +2 -40
  31. package/dist/browser/browser/cache.js +2 -199
  32. package/dist/browser/browser/index.d.ts +8 -0
  33. package/dist/browser/browser/index.js +8 -0
  34. package/dist/browser/browser/recker.d.ts +8 -1
  35. package/dist/browser/browser/recker.js +8 -2
  36. package/dist/browser/cache/indexed-db.d.ts +10 -0
  37. package/dist/browser/cache/indexed-db.js +88 -0
  38. package/dist/browser/cache/service-worker-cache.d.ts +18 -0
  39. package/dist/browser/cache/service-worker-cache.js +103 -0
  40. package/dist/browser/cache.d.ts +2 -40
  41. package/dist/browser/cache.js +2 -199
  42. package/dist/browser/constants/user-agents.d.ts +7 -0
  43. package/dist/browser/constants/user-agents.js +7 -0
  44. package/dist/browser/core/client.d.ts +2 -0
  45. package/dist/browser/core/client.js +19 -1
  46. package/dist/browser/index.d.ts +8 -0
  47. package/dist/browser/index.js +8 -0
  48. package/dist/browser/plugins/har-recorder.d.ts +40 -0
  49. package/dist/browser/plugins/har-recorder.js +120 -0
  50. package/dist/browser/plugins/network-simulation.d.ts +7 -0
  51. package/dist/browser/plugins/network-simulation.js +13 -0
  52. package/dist/browser/presets/android.d.ts +2 -0
  53. package/dist/browser/presets/android.js +16 -0
  54. package/dist/browser/presets/anthropic.d.ts +8 -0
  55. package/dist/browser/presets/anthropic.js +27 -0
  56. package/dist/browser/presets/aws.d.ts +19 -0
  57. package/dist/browser/presets/aws.js +68 -0
  58. package/dist/browser/presets/azure-openai.d.ts +10 -0
  59. package/dist/browser/presets/azure-openai.js +35 -0
  60. package/dist/browser/presets/azure.d.ts +41 -0
  61. package/dist/browser/presets/azure.js +104 -0
  62. package/dist/browser/presets/chaturbate.d.ts +2 -0
  63. package/dist/browser/presets/chaturbate.js +17 -0
  64. package/dist/browser/presets/cloudflare.d.ts +12 -0
  65. package/dist/browser/presets/cloudflare.js +39 -0
  66. package/dist/browser/presets/cohere.d.ts +7 -0
  67. package/dist/browser/presets/cohere.js +22 -0
  68. package/dist/browser/presets/deepseek.d.ts +7 -0
  69. package/dist/browser/presets/deepseek.js +22 -0
  70. package/dist/browser/presets/digitalocean.d.ts +5 -0
  71. package/dist/browser/presets/digitalocean.js +16 -0
  72. package/dist/browser/presets/discord.d.ts +6 -0
  73. package/dist/browser/presets/discord.js +17 -0
  74. package/dist/browser/presets/elevenlabs.d.ts +6 -0
  75. package/dist/browser/presets/elevenlabs.js +20 -0
  76. package/dist/browser/presets/enhancers.d.ts +20 -0
  77. package/dist/browser/presets/enhancers.js +85 -0
  78. package/dist/browser/presets/fireworks.d.ts +7 -0
  79. package/dist/browser/presets/fireworks.js +22 -0
  80. package/dist/browser/presets/gcp.d.ts +34 -0
  81. package/dist/browser/presets/gcp.js +91 -0
  82. package/dist/browser/presets/gemini.d.ts +7 -0
  83. package/dist/browser/presets/gemini.js +23 -0
  84. package/dist/browser/presets/github.d.ts +6 -0
  85. package/dist/browser/presets/github.js +17 -0
  86. package/dist/browser/presets/gitlab.d.ts +6 -0
  87. package/dist/browser/presets/gitlab.js +16 -0
  88. package/dist/browser/presets/groq.d.ts +7 -0
  89. package/dist/browser/presets/groq.js +22 -0
  90. package/dist/browser/presets/hubspot.d.ts +9 -0
  91. package/dist/browser/presets/hubspot.js +28 -0
  92. package/dist/browser/presets/huggingface.d.ts +7 -0
  93. package/dist/browser/presets/huggingface.js +23 -0
  94. package/dist/browser/presets/index.d.ts +47 -0
  95. package/dist/browser/presets/index.js +47 -0
  96. package/dist/browser/presets/ios.d.ts +2 -0
  97. package/dist/browser/presets/ios.js +13 -0
  98. package/dist/browser/presets/linear.d.ts +5 -0
  99. package/dist/browser/presets/linear.js +16 -0
  100. package/dist/browser/presets/mailgun.d.ts +7 -0
  101. package/dist/browser/presets/mailgun.js +20 -0
  102. package/dist/browser/presets/meta.d.ts +10 -0
  103. package/dist/browser/presets/meta.js +33 -0
  104. package/dist/browser/presets/mistral.d.ts +7 -0
  105. package/dist/browser/presets/mistral.js +22 -0
  106. package/dist/browser/presets/notion.d.ts +6 -0
  107. package/dist/browser/presets/notion.js +17 -0
  108. package/dist/browser/presets/openai.d.ts +9 -0
  109. package/dist/browser/presets/openai.js +30 -0
  110. package/dist/browser/presets/oracle.d.ts +19 -0
  111. package/dist/browser/presets/oracle.js +117 -0
  112. package/dist/browser/presets/perplexity.d.ts +7 -0
  113. package/dist/browser/presets/perplexity.js +22 -0
  114. package/dist/browser/presets/pinecone.d.ts +8 -0
  115. package/dist/browser/presets/pinecone.js +42 -0
  116. package/dist/browser/presets/registry.d.ts +23 -0
  117. package/dist/browser/presets/registry.js +519 -0
  118. package/dist/browser/presets/replicate.d.ts +7 -0
  119. package/dist/browser/presets/replicate.js +23 -0
  120. package/dist/browser/presets/sendgrid.d.ts +6 -0
  121. package/dist/browser/presets/sendgrid.js +20 -0
  122. package/dist/browser/presets/sentry.d.ts +11 -0
  123. package/dist/browser/presets/sentry.js +48 -0
  124. package/dist/browser/presets/sinch.d.ts +9 -0
  125. package/dist/browser/presets/sinch.js +39 -0
  126. package/dist/browser/presets/slack.d.ts +5 -0
  127. package/dist/browser/presets/slack.js +16 -0
  128. package/dist/browser/presets/square.d.ts +10 -0
  129. package/dist/browser/presets/square.js +33 -0
  130. package/dist/browser/presets/stripe.d.ts +7 -0
  131. package/dist/browser/presets/stripe.js +23 -0
  132. package/dist/browser/presets/supabase.d.ts +6 -0
  133. package/dist/browser/presets/supabase.js +18 -0
  134. package/dist/browser/presets/tiktok.d.ts +10 -0
  135. package/dist/browser/presets/tiktok.js +38 -0
  136. package/dist/browser/presets/together.d.ts +7 -0
  137. package/dist/browser/presets/together.js +22 -0
  138. package/dist/browser/presets/twilio.d.ts +6 -0
  139. package/dist/browser/presets/twilio.js +17 -0
  140. package/dist/browser/presets/vercel.d.ts +6 -0
  141. package/dist/browser/presets/vercel.js +23 -0
  142. package/dist/browser/presets/vultr.d.ts +5 -0
  143. package/dist/browser/presets/vultr.js +16 -0
  144. package/dist/browser/presets/xai.d.ts +8 -0
  145. package/dist/browser/presets/xai.js +23 -0
  146. package/dist/browser/presets/youtube.d.ts +5 -0
  147. package/dist/browser/presets/youtube.js +20 -0
  148. package/dist/browser/recker.d.ts +8 -1
  149. package/dist/browser/recker.js +8 -2
  150. package/dist/browser/scrape/document.d.ts +5 -4
  151. package/dist/browser/scrape/document.js +89 -76
  152. package/dist/browser/scrape/element.d.ts +10 -8
  153. package/dist/browser/scrape/element.js +295 -81
  154. package/dist/browser/scrape/extractors.d.ts +11 -11
  155. package/dist/browser/scrape/extractors.js +145 -113
  156. package/dist/browser/scrape/parser/back.d.ts +1 -0
  157. package/dist/browser/scrape/parser/back.js +3 -0
  158. package/dist/browser/scrape/parser/index.d.ts +20 -0
  159. package/dist/browser/scrape/parser/index.js +19 -0
  160. package/dist/browser/scrape/parser/matcher.d.ts +30 -0
  161. package/dist/browser/scrape/parser/matcher.js +99 -0
  162. package/dist/browser/scrape/parser/nodes/comment.d.ts +12 -0
  163. package/dist/browser/scrape/parser/nodes/comment.js +21 -0
  164. package/dist/browser/scrape/parser/nodes/html.d.ts +110 -0
  165. package/dist/browser/scrape/parser/nodes/html.js +978 -0
  166. package/dist/browser/scrape/parser/nodes/node.d.ts +18 -0
  167. package/dist/browser/scrape/parser/nodes/node.js +31 -0
  168. package/dist/browser/scrape/parser/nodes/text.d.ts +14 -0
  169. package/dist/browser/scrape/parser/nodes/text.js +30 -0
  170. package/dist/browser/scrape/parser/nodes/type.d.ts +6 -0
  171. package/dist/browser/scrape/parser/nodes/type.js +7 -0
  172. package/dist/browser/scrape/parser/parse.d.ts +1 -0
  173. package/dist/browser/scrape/parser/parse.js +1 -0
  174. package/dist/browser/scrape/parser/valid.d.ts +2 -0
  175. package/dist/browser/scrape/parser/valid.js +5 -0
  176. package/dist/browser/scrape/parser/void-tag.d.ts +7 -0
  177. package/dist/browser/scrape/parser/void-tag.js +43 -0
  178. package/dist/browser/scrape/types.d.ts +7 -0
  179. package/dist/browser/seo/analyzer.d.ts +59 -0
  180. package/dist/browser/seo/analyzer.js +1399 -0
  181. package/dist/browser/seo/keywords.d.ts +16 -0
  182. package/dist/browser/seo/keywords.js +55 -0
  183. package/dist/browser/seo/rules/accessibility.d.ts +2 -0
  184. package/dist/browser/seo/rules/accessibility.js +733 -0
  185. package/dist/browser/seo/rules/ai-search.d.ts +2 -0
  186. package/dist/browser/seo/rules/ai-search.js +436 -0
  187. package/dist/browser/seo/rules/analytics.d.ts +2 -0
  188. package/dist/browser/seo/rules/analytics.js +306 -0
  189. package/dist/browser/seo/rules/best-practices.d.ts +2 -0
  190. package/dist/browser/seo/rules/best-practices.js +195 -0
  191. package/dist/browser/seo/rules/canonical.d.ts +12 -0
  192. package/dist/browser/seo/rules/canonical.js +270 -0
  193. package/dist/browser/seo/rules/content.d.ts +2 -0
  194. package/dist/browser/seo/rules/content.js +522 -0
  195. package/dist/browser/seo/rules/crawl.d.ts +2 -0
  196. package/dist/browser/seo/rules/crawl.js +435 -0
  197. package/dist/browser/seo/rules/cwv.d.ts +2 -0
  198. package/dist/browser/seo/rules/cwv.js +248 -0
  199. package/dist/browser/seo/rules/ecommerce.d.ts +2 -0
  200. package/dist/browser/seo/rules/ecommerce.js +312 -0
  201. package/dist/browser/seo/rules/i18n.d.ts +2 -0
  202. package/dist/browser/seo/rules/i18n.js +288 -0
  203. package/dist/browser/seo/rules/images.d.ts +2 -0
  204. package/dist/browser/seo/rules/images.js +255 -0
  205. package/dist/browser/seo/rules/index.d.ts +52 -0
  206. package/dist/browser/seo/rules/index.js +163 -0
  207. package/dist/browser/seo/rules/internal-linking.d.ts +2 -0
  208. package/dist/browser/seo/rules/internal-linking.js +394 -0
  209. package/dist/browser/seo/rules/links.d.ts +2 -0
  210. package/dist/browser/seo/rules/links.js +498 -0
  211. package/dist/browser/seo/rules/local.d.ts +2 -0
  212. package/dist/browser/seo/rules/local.js +289 -0
  213. package/dist/browser/seo/rules/manifest.d.ts +2 -0
  214. package/dist/browser/seo/rules/manifest.js +621 -0
  215. package/dist/browser/seo/rules/meta.d.ts +2 -0
  216. package/dist/browser/seo/rules/meta.js +805 -0
  217. package/dist/browser/seo/rules/mobile.d.ts +2 -0
  218. package/dist/browser/seo/rules/mobile.js +161 -0
  219. package/dist/browser/seo/rules/performance.d.ts +2 -0
  220. package/dist/browser/seo/rules/performance.js +738 -0
  221. package/dist/browser/seo/rules/pwa.d.ts +2 -0
  222. package/dist/browser/seo/rules/pwa.js +299 -0
  223. package/dist/browser/seo/rules/readability.d.ts +2 -0
  224. package/dist/browser/seo/rules/readability.js +264 -0
  225. package/dist/browser/seo/rules/redirects.d.ts +16 -0
  226. package/dist/browser/seo/rules/redirects.js +199 -0
  227. package/dist/browser/seo/rules/resources.d.ts +2 -0
  228. package/dist/browser/seo/rules/resources.js +390 -0
  229. package/dist/browser/seo/rules/schema.d.ts +2 -0
  230. package/dist/browser/seo/rules/schema.js +379 -0
  231. package/dist/browser/seo/rules/security.d.ts +2 -0
  232. package/dist/browser/seo/rules/security.js +877 -0
  233. package/dist/browser/seo/rules/social.d.ts +2 -0
  234. package/dist/browser/seo/rules/social.js +603 -0
  235. package/dist/browser/seo/rules/structural.d.ts +2 -0
  236. package/dist/browser/seo/rules/structural.js +223 -0
  237. package/dist/browser/seo/rules/technical-advanced.d.ts +10 -0
  238. package/dist/browser/seo/rules/technical-advanced.js +289 -0
  239. package/dist/browser/seo/rules/technical.d.ts +3 -0
  240. package/dist/browser/seo/rules/technical.js +509 -0
  241. package/dist/browser/seo/rules/thresholds.d.ts +196 -0
  242. package/dist/browser/seo/rules/thresholds.js +118 -0
  243. package/dist/browser/seo/rules/types.d.ts +518 -0
  244. package/dist/browser/seo/rules/types.js +11 -0
  245. package/dist/browser/seo/types.d.ts +211 -0
  246. package/dist/browser/seo/types.js +1 -0
  247. package/dist/browser/transport/curl.d.ts +4 -0
  248. package/dist/browser/transport/curl.js +101 -0
  249. package/dist/browser/transport/undici.js +1 -2
  250. package/dist/browser/transport/worker.d.ts +18 -0
  251. package/dist/browser/transport/worker.js +278 -0
  252. package/dist/browser/types/index.d.ts +4 -1
  253. package/dist/browser/utils/binary-manager.d.ts +4 -0
  254. package/dist/browser/utils/binary-manager.js +72 -0
  255. package/dist/browser/utils/user-agent.js +2 -13
  256. package/dist/cache/indexed-db.d.ts +10 -0
  257. package/dist/cache/indexed-db.js +88 -0
  258. package/dist/cache/service-worker-cache.d.ts +18 -0
  259. package/dist/cache/service-worker-cache.js +103 -0
  260. package/dist/cli/commands/ai.d.ts +2 -0
  261. package/dist/cli/commands/ai.js +162 -0
  262. package/dist/cli/commands/bench.d.ts +2 -0
  263. package/dist/cli/commands/bench.js +51 -0
  264. package/dist/cli/commands/dns.d.ts +2 -0
  265. package/dist/cli/commands/dns.js +295 -0
  266. package/dist/cli/commands/har.d.ts +2 -0
  267. package/dist/cli/commands/har.js +171 -0
  268. package/dist/cli/commands/hls.d.ts +2 -0
  269. package/dist/cli/commands/hls.js +192 -0
  270. package/dist/cli/commands/network.d.ts +2 -0
  271. package/dist/cli/commands/network.js +288 -0
  272. package/dist/cli/commands/protocols.d.ts +2 -0
  273. package/dist/cli/commands/protocols.js +344 -0
  274. package/dist/cli/commands/scrape.d.ts +2 -0
  275. package/dist/cli/commands/scrape.js +176 -0
  276. package/dist/cli/commands/security.d.ts +2 -0
  277. package/dist/cli/commands/security.js +57 -0
  278. package/dist/cli/commands/seo.d.ts +2 -0
  279. package/dist/cli/commands/seo.js +125 -0
  280. package/dist/cli/commands/serve.d.ts +2 -0
  281. package/dist/cli/commands/serve.js +531 -0
  282. package/dist/cli/commands/spider.d.ts +3 -0
  283. package/dist/cli/commands/spider.js +478 -0
  284. package/dist/cli/commands/utils.d.ts +2 -0
  285. package/dist/cli/commands/utils.js +176 -0
  286. package/dist/cli/commands/vector.d.ts +2 -0
  287. package/dist/cli/commands/vector.js +158 -0
  288. package/dist/cli/handler.d.ts +2 -2
  289. package/dist/cli/handler.js +6 -6
  290. package/dist/cli/helpers.d.ts +7 -0
  291. package/dist/cli/helpers.js +128 -0
  292. package/dist/cli/index.js +96 -5228
  293. package/dist/cli/parser/help.d.ts +2 -0
  294. package/dist/cli/parser/help.js +52 -0
  295. package/dist/cli/parser/index.d.ts +3 -0
  296. package/dist/cli/parser/index.js +3 -0
  297. package/dist/cli/parser/parser.d.ts +4 -0
  298. package/dist/cli/parser/parser.js +146 -0
  299. package/dist/cli/parser/types.d.ts +41 -0
  300. package/dist/cli/parser/types.js +1 -0
  301. package/dist/cli/presets.d.ts +1 -1
  302. package/dist/cli/presets.js +1 -1
  303. package/dist/cli/router.d.ts +36 -0
  304. package/dist/cli/router.js +195 -0
  305. package/dist/cli/tui/ai-chat.js +1 -1
  306. package/dist/cli/tui/commands/context.d.ts +9 -0
  307. package/dist/cli/tui/commands/context.js +1 -0
  308. package/dist/cli/tui/commands/dns.d.ts +10 -0
  309. package/dist/cli/tui/commands/dns.js +461 -0
  310. package/dist/cli/tui/commands/hls.d.ts +2 -0
  311. package/dist/cli/tui/commands/hls.js +162 -0
  312. package/dist/cli/tui/commands/ip.d.ts +2 -0
  313. package/dist/cli/tui/commands/ip.js +45 -0
  314. package/dist/cli/tui/commands/network.d.ts +3 -0
  315. package/dist/cli/tui/commands/network.js +81 -0
  316. package/dist/cli/tui/commands/protocols.d.ts +6 -0
  317. package/dist/cli/tui/commands/protocols.js +531 -0
  318. package/dist/cli/tui/commands/security.d.ts +2 -0
  319. package/dist/cli/tui/commands/security.js +48 -0
  320. package/dist/cli/tui/commands/seo.d.ts +2 -0
  321. package/dist/cli/tui/commands/seo.js +74 -0
  322. package/dist/cli/tui/context.d.ts +12 -0
  323. package/dist/cli/tui/context.js +1 -0
  324. package/dist/cli/tui/shell.d.ts +11 -20
  325. package/dist/cli/tui/shell.js +216 -1873
  326. package/dist/constants/user-agents.d.ts +7 -0
  327. package/dist/constants/user-agents.js +7 -0
  328. package/dist/core/client.d.ts +2 -0
  329. package/dist/core/client.js +19 -1
  330. package/dist/index.d.ts +1 -0
  331. package/dist/index.js +1 -0
  332. package/dist/mcp/cli.js +2 -3
  333. package/dist/mcp/data/embeddings.json +1 -1
  334. package/dist/mcp/tools/network.js +298 -158
  335. package/dist/plugins/har-player.d.ts +23 -0
  336. package/dist/plugins/har-player.js +49 -0
  337. package/dist/plugins/har-recorder.d.ts +37 -3
  338. package/dist/plugins/har-recorder.js +116 -63
  339. package/dist/plugins/network-simulation.d.ts +7 -0
  340. package/dist/plugins/network-simulation.js +13 -0
  341. package/dist/presets/android.d.ts +2 -0
  342. package/dist/presets/android.js +16 -0
  343. package/dist/presets/chaturbate.d.ts +2 -0
  344. package/dist/presets/chaturbate.js +17 -0
  345. package/dist/presets/elevenlabs.d.ts +6 -0
  346. package/dist/presets/elevenlabs.js +20 -0
  347. package/dist/presets/enhancers.d.ts +20 -0
  348. package/dist/presets/enhancers.js +85 -0
  349. package/dist/presets/hubspot.d.ts +9 -0
  350. package/dist/presets/hubspot.js +28 -0
  351. package/dist/presets/index.d.ts +10 -0
  352. package/dist/presets/index.js +10 -0
  353. package/dist/presets/ios.d.ts +2 -0
  354. package/dist/presets/ios.js +13 -0
  355. package/dist/presets/pinecone.d.ts +8 -0
  356. package/dist/presets/pinecone.js +42 -0
  357. package/dist/presets/registry.js +60 -0
  358. package/dist/presets/sendgrid.d.ts +6 -0
  359. package/dist/presets/sendgrid.js +20 -0
  360. package/dist/presets/sentry.d.ts +11 -0
  361. package/dist/presets/sentry.js +48 -0
  362. package/dist/presets/square.d.ts +10 -0
  363. package/dist/presets/square.js +33 -0
  364. package/dist/recker.d.ts +3 -0
  365. package/dist/recker.js +4 -0
  366. package/dist/scrape/document.d.ts +5 -4
  367. package/dist/scrape/document.js +89 -76
  368. package/dist/scrape/element.d.ts +10 -8
  369. package/dist/scrape/element.js +295 -81
  370. package/dist/scrape/extractors.d.ts +11 -11
  371. package/dist/scrape/extractors.js +145 -113
  372. package/dist/scrape/index.d.ts +2 -0
  373. package/dist/scrape/index.js +1 -0
  374. package/dist/scrape/parser/back.d.ts +1 -0
  375. package/dist/scrape/parser/back.js +3 -0
  376. package/dist/scrape/parser/index.d.ts +20 -0
  377. package/dist/scrape/parser/index.js +19 -0
  378. package/dist/scrape/parser/matcher.d.ts +30 -0
  379. package/dist/scrape/parser/matcher.js +99 -0
  380. package/dist/scrape/parser/nodes/comment.d.ts +12 -0
  381. package/dist/scrape/parser/nodes/comment.js +21 -0
  382. package/dist/scrape/parser/nodes/html.d.ts +110 -0
  383. package/dist/scrape/parser/nodes/html.js +978 -0
  384. package/dist/scrape/parser/nodes/node.d.ts +18 -0
  385. package/dist/scrape/parser/nodes/node.js +31 -0
  386. package/dist/scrape/parser/nodes/text.d.ts +14 -0
  387. package/dist/scrape/parser/nodes/text.js +30 -0
  388. package/dist/scrape/parser/nodes/type.d.ts +6 -0
  389. package/dist/scrape/parser/nodes/type.js +7 -0
  390. package/dist/scrape/parser/parse.d.ts +1 -0
  391. package/dist/scrape/parser/parse.js +1 -0
  392. package/dist/scrape/parser/valid.d.ts +2 -0
  393. package/dist/scrape/parser/valid.js +5 -0
  394. package/dist/scrape/parser/void-tag.d.ts +7 -0
  395. package/dist/scrape/parser/void-tag.js +43 -0
  396. package/dist/scrape/spider.d.ts +19 -0
  397. package/dist/scrape/spider.js +28 -3
  398. package/dist/scrape/types.d.ts +7 -0
  399. package/dist/seo/analyzer.d.ts +15 -5
  400. package/dist/seo/analyzer.js +636 -175
  401. package/dist/seo/formatter.d.ts +16 -0
  402. package/dist/seo/formatter.js +228 -0
  403. package/dist/seo/index.d.ts +2 -0
  404. package/dist/seo/index.js +1 -0
  405. package/dist/seo/keywords.d.ts +16 -0
  406. package/dist/seo/keywords.js +55 -0
  407. package/dist/seo/rules/accessibility.js +96 -57
  408. package/dist/seo/rules/ai-search.js +44 -31
  409. package/dist/seo/rules/analytics.d.ts +2 -0
  410. package/dist/seo/rules/analytics.js +306 -0
  411. package/dist/seo/rules/best-practices.js +21 -14
  412. package/dist/seo/rules/canonical.js +53 -32
  413. package/dist/seo/rules/content.js +317 -31
  414. package/dist/seo/rules/crawl.js +55 -40
  415. package/dist/seo/rules/cwv.js +21 -15
  416. package/dist/seo/rules/ecommerce.js +82 -22
  417. package/dist/seo/rules/i18n.js +75 -36
  418. package/dist/seo/rules/images.js +109 -30
  419. package/dist/seo/rules/index.js +7 -1
  420. package/dist/seo/rules/internal-linking.js +58 -39
  421. package/dist/seo/rules/links.js +79 -52
  422. package/dist/seo/rules/local.js +49 -25
  423. package/dist/seo/rules/manifest.d.ts +2 -0
  424. package/dist/seo/rules/manifest.js +621 -0
  425. package/dist/seo/rules/meta.js +339 -81
  426. package/dist/seo/rules/mobile.js +112 -2
  427. package/dist/seo/rules/performance.js +434 -66
  428. package/dist/seo/rules/pwa.js +36 -39
  429. package/dist/seo/rules/readability.js +31 -22
  430. package/dist/seo/rules/redirects.js +21 -15
  431. package/dist/seo/rules/resources.js +59 -42
  432. package/dist/seo/rules/schema.js +333 -8
  433. package/dist/seo/rules/security.js +142 -80
  434. package/dist/seo/rules/social.js +277 -47
  435. package/dist/seo/rules/structural.js +87 -19
  436. package/dist/seo/rules/technical-advanced.js +30 -24
  437. package/dist/seo/rules/technical.d.ts +1 -0
  438. package/dist/seo/rules/technical.js +272 -42
  439. package/dist/seo/rules/types.d.ts +74 -2
  440. package/dist/seo/seo-spider.d.ts +35 -0
  441. package/dist/seo/seo-spider.js +152 -13
  442. package/dist/seo/types.d.ts +8 -1
  443. package/dist/seo/validators/llms-txt.js +19 -0
  444. package/dist/seo/validators/rss.d.ts +11 -0
  445. package/dist/seo/validators/rss.js +93 -0
  446. package/dist/seo/validators/sitemap.js +36 -26
  447. package/dist/transport/curl.d.ts +4 -0
  448. package/dist/transport/curl.js +101 -0
  449. package/dist/transport/udp.js +0 -1
  450. package/dist/transport/undici.js +1 -2
  451. package/dist/transport/worker.d.ts +18 -0
  452. package/dist/transport/worker.js +278 -0
  453. package/dist/types/index.d.ts +4 -1
  454. package/dist/utils/binary-manager.d.ts +4 -0
  455. package/dist/utils/binary-manager.js +72 -0
  456. package/dist/utils/optional-require.d.ts +7 -8
  457. package/dist/utils/optional-require.js +2 -21
  458. package/dist/utils/upload.d.ts +6 -0
  459. package/dist/utils/upload.js +11 -0
  460. package/dist/utils/user-agent.js +2 -13
  461. package/dist/version.js +1 -1
  462. package/package.json +12 -6
  463. package/dist/browser/utils/optional-require.d.ts +0 -19
  464. package/dist/browser/utils/optional-require.js +0 -105
@@ -0,0 +1,478 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import colors from '../../utils/colors.js';
3
+ import { summarizeErrors, formatErrorSummary } from '../helpers.js';
4
+ import { RekArgs, generateHelp } from '../parser/index.js';
5
+ const schema = {
6
+ name: 'spider',
7
+ description: 'Crawl a website and analyze all pages.\nThe crawler respects robots.txt, handles JavaScript-rendered content, and provides detailed reports on site structure, broken links, and SEO issues.',
8
+ params: {
9
+ depth: { type: 'number', default: 5, description: 'Max link depth to follow' },
10
+ limit: { type: 'number', default: 100, description: 'Max pages to crawl' },
11
+ concurrency: { type: 'number', default: 5, description: 'Parallel requests' },
12
+ output: { type: 'string', description: 'Save JSON report to file' },
13
+ focus: { type: 'string', default: 'all', choices: ['all', 'links', 'duplicates', 'security', 'ai', 'resources'], description: 'Focus analysis on specific area (requires seo)' }
14
+ },
15
+ keywords: {
16
+ seo: { description: 'Enable SEO analysis mode' }
17
+ },
18
+ flags: {
19
+ json: { description: 'Output JSON to stdout', alias: 'j' },
20
+ robots: { description: 'Respect robots.txt rules', default: false }
21
+ },
22
+ examples: [
23
+ { cmd: 'rek spider example.com', desc: 'Crawl (ignores robots.txt)' },
24
+ { cmd: 'rek spider example.com --robots', desc: 'Crawl respecting robots.txt' },
25
+ { cmd: 'rek spider example.com depth=3 limit=50', desc: 'Depth 3, max 50 pages' },
26
+ { cmd: 'rek spider example.com seo focus=security', desc: 'Focus on security issues' },
27
+ { cmd: 'rek spider example.com seo output=report.json', desc: 'SEO with JSON export' }
28
+ ]
29
+ };
30
+ export async function runSpider(rawArgs, defaultUrl) {
31
+ const { data, options, args } = RekArgs.parse(rawArgs, schema);
32
+ let url = args[0];
33
+ if (!url && defaultUrl) {
34
+ url = defaultUrl;
35
+ }
36
+ const formatJson = options.json || data.format === 'json';
37
+ const outputFile = data.output;
38
+ const seoEnabled = data.seo;
39
+ const focusMode = data.focus;
40
+ const respectRobotsTxt = !!options.robots;
41
+ const focusCategories = {
42
+ links: ['links'],
43
+ duplicates: ['title', 'meta', 'content'],
44
+ security: ['security'],
45
+ ai: ['ai-search'],
46
+ resources: ['resources', 'performance'],
47
+ all: [],
48
+ };
49
+ if (!url) {
50
+ if (!formatJson) {
51
+ console.log(colors.yellow('Usage: spider <url> [options]'));
52
+ console.log(generateHelp(schema));
53
+ }
54
+ return;
55
+ }
56
+ if (!url.startsWith('http'))
57
+ url = `https://${url}`;
58
+ if (!formatJson) {
59
+ const modeLabel = seoEnabled ? colors.magenta(' + SEO') : '';
60
+ const focusLabel = focusMode !== 'all' ? colors.cyan(` [focus: ${focusMode}]`) : '';
61
+ console.log(colors.cyan(`
62
+ Spider starting: ${url}`));
63
+ console.log(colors.gray(` Depth: ${data.depth} | Limit: ${data.limit} | Concurrency: ${data.concurrency}${modeLabel}${focusLabel}`));
64
+ if (outputFile) {
65
+ console.log(colors.gray(` Output: ${outputFile}`));
66
+ }
67
+ console.log('');
68
+ }
69
+ try {
70
+ if (seoEnabled) {
71
+ const { SeoSpider } = await import('../../seo/index.js');
72
+ const seoSpider = new SeoSpider({
73
+ maxDepth: data.depth,
74
+ maxPages: data.limit,
75
+ concurrency: data.concurrency,
76
+ sameDomain: true,
77
+ delay: 100,
78
+ seo: true,
79
+ respectRobotsTxt,
80
+ output: outputFile || undefined,
81
+ focusCategories: focusCategories[focusMode],
82
+ focusMode: focusMode,
83
+ onProgress: formatJson ? undefined : (progress) => {
84
+ process.stdout.write(`\r${colors.gray(' Crawling:')} ${colors.cyan(progress.crawled.toString())} pages | ${colors.gray('Queue:')} ${progress.queued} | ${colors.gray('Depth:')} ${progress.depth} `);
85
+ },
86
+ });
87
+ const result = await seoSpider.crawl(url);
88
+ if (formatJson) {
89
+ const responseTimes = result.pages.filter(p => p.duration > 0).map(p => p.duration);
90
+ const avgResponseTime = responseTimes.length > 0
91
+ ? Math.round(responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length)
92
+ : 0;
93
+ const statusCounts = {};
94
+ for (const page of result.pages) {
95
+ const key = page.status?.toString() || 'error';
96
+ statusCounts[key] = (statusCounts[key] || 0) + 1;
97
+ }
98
+ let totalInternalLinks = 0;
99
+ let totalExternalLinks = 0;
100
+ let totalImages = 0;
101
+ let imagesWithoutAlt = 0;
102
+ for (const page of result.pages) {
103
+ if (page.seoReport) {
104
+ totalInternalLinks += page.seoReport.links?.internal || 0;
105
+ totalExternalLinks += page.seoReport.links?.external || 0;
106
+ totalImages += page.seoReport.images?.total || 0;
107
+ imagesWithoutAlt += page.seoReport.images?.withoutAlt || 0;
108
+ }
109
+ }
110
+ const jsonOutput = {
111
+ startUrl: url,
112
+ crawledAt: new Date().toISOString(),
113
+ duration: result.duration,
114
+ config: {
115
+ maxDepth: data.depth,
116
+ maxPages: data.limit,
117
+ concurrency: data.concurrency,
118
+ focusMode,
119
+ },
120
+ summary: {
121
+ totalPages: result.pages.length,
122
+ uniqueUrls: result.visited.size,
123
+ avgSeoScore: result.summary.avgScore,
124
+ avgResponseTime,
125
+ pagesWithErrors: result.summary.pagesWithErrors,
126
+ pagesWithWarnings: result.summary.pagesWithWarnings,
127
+ duplicateTitles: result.summary.duplicateTitles,
128
+ duplicateDescriptions: result.summary.duplicateDescriptions,
129
+ duplicateH1s: result.summary.duplicateH1s,
130
+ orphanPages: result.summary.orphanPages,
131
+ },
132
+ discovery: result.discovery ? {
133
+ humans: result.discovery.humans.found,
134
+ llms: result.discovery.llms.found,
135
+ sitemap: result.discovery.sitemap.found,
136
+ manifest: result.discovery.manifest.found ? {
137
+ valid: result.discovery.manifest.valid,
138
+ issues: result.discovery.manifest.issues,
139
+ } : undefined,
140
+ } : undefined,
141
+ rssFeeds: result.rssFeeds,
142
+ content: {
143
+ totalInternalLinks,
144
+ totalExternalLinks,
145
+ totalImages,
146
+ imagesWithoutAlt,
147
+ },
148
+ httpStatus: statusCounts,
149
+ siteWideIssues: result.siteWideIssues.map(issue => ({
150
+ type: issue.type,
151
+ severity: issue.severity,
152
+ message: issue.message,
153
+ value: issue.value,
154
+ affectedUrls: issue.affectedUrls,
155
+ })),
156
+ pages: result.pages.map(page => ({
157
+ url: page.url,
158
+ status: page.status,
159
+ depth: page.depth,
160
+ duration: page.duration,
161
+ title: page.title,
162
+ error: page.error,
163
+ seo: page.seoReport ? {
164
+ score: page.seoReport.score,
165
+ grade: page.seoReport.grade,
166
+ title: page.seoReport.title,
167
+ metaDescription: page.seoReport.metaDescription,
168
+ headings: page.seoReport.headings,
169
+ links: page.seoReport.links,
170
+ images: page.seoReport.images,
171
+ checks: page.seoReport.checks,
172
+ } : null,
173
+ })),
174
+ errors: result.pages.filter(p => p.error).map(p => ({
175
+ url: p.url,
176
+ status: p.status,
177
+ error: p.error
178
+ })),
179
+ };
180
+ console.log(JSON.stringify(jsonOutput, null, 2));
181
+ return;
182
+ }
183
+ process.stdout.write('\r' + ' '.repeat(80) + '\r');
184
+ console.log(colors.green(`\n✔ SEO Spider complete`) + colors.gray(` (${(result.duration / 1000).toFixed(1)}s)`));
185
+ console.log(` ${colors.cyan('Pages crawled')}: ${result.pages.length}`);
186
+ console.log(` ${colors.cyan('Unique URLs')}: ${result.visited.size}`);
187
+ console.log(` ${colors.cyan('Avg SEO Score')}: ${result.summary.avgScore}/100`);
188
+ const responseTimes = result.pages.filter(p => p.duration > 0).map(p => p.duration);
189
+ const avgResponseTime = responseTimes.length > 0
190
+ ? Math.round(responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length)
191
+ : 0;
192
+ const minResponseTime = responseTimes.length > 0 ? Math.min(...responseTimes) : 0;
193
+ const maxResponseTime = responseTimes.length > 0 ? Math.max(...responseTimes) : 0;
194
+ const reqPerSec = result.duration > 0 ? (result.pages.length / (result.duration / 1000)).toFixed(1) : '0';
195
+ const statusCounts = new Map();
196
+ for (const page of result.pages) {
197
+ const key = page.status ? page.status.toString() : 'error';
198
+ statusCounts.set(key, (statusCounts.get(key) || 0) + 1);
199
+ }
200
+ let totalInternalLinks = 0;
201
+ let totalExternalLinks = 0;
202
+ let totalImages = 0;
203
+ let imagesWithoutAlt = 0;
204
+ let pagesWithoutTitle = 0;
205
+ let pagesWithoutDescription = 0;
206
+ for (const page of result.pages) {
207
+ if (page.seoReport) {
208
+ totalInternalLinks += page.seoReport.links?.internal || 0;
209
+ totalExternalLinks += page.seoReport.links?.external || 0;
210
+ totalImages += page.seoReport.images?.total || 0;
211
+ imagesWithoutAlt += page.seoReport.images?.withoutAlt || 0;
212
+ if (!page.seoReport.title?.text)
213
+ pagesWithoutTitle++;
214
+ if (!page.seoReport.metaDescription?.text)
215
+ pagesWithoutDescription++;
216
+ }
217
+ }
218
+ console.log(colors.bold('\n Performance:'));
219
+ console.log(` ${colors.gray('Avg Response:')} ${avgResponseTime}ms`);
220
+ console.log(` ${colors.gray('Min/Max:')} ${minResponseTime}ms / ${maxResponseTime}ms`);
221
+ console.log(` ${colors.gray('Throughput:')} ${reqPerSec} req/s`);
222
+ console.log(colors.bold('\n HTTP Status:'));
223
+ const sortedStatuses = Array.from(statusCounts.entries()).sort((a, b) => b[1] - a[1]);
224
+ for (const [statusKey, count] of sortedStatuses.slice(0, 5)) {
225
+ const statusNum = parseInt(statusKey);
226
+ const statusColor = statusNum >= 400 ? colors.red :
227
+ statusNum >= 300 ? colors.yellow :
228
+ statusKey === 'error' ? colors.red : colors.green;
229
+ const pct = ((count / result.pages.length) * 100).toFixed(0);
230
+ console.log(` ${statusColor(statusKey.padEnd(5))} ${count.toString().padStart(3)} (${pct}%)`);
231
+ }
232
+ console.log(colors.bold('\n Content:'));
233
+ console.log(` ${colors.gray('Internal links:')} ${totalInternalLinks.toLocaleString()}`);
234
+ console.log(` ${colors.gray('External links:')} ${totalExternalLinks.toLocaleString()}`);
235
+ console.log(` ${colors.gray('Images:')} ${totalImages.toLocaleString()} (${imagesWithoutAlt} missing alt)`);
236
+ console.log(` ${colors.gray('Missing title:')} ${pagesWithoutTitle}`);
237
+ console.log(` ${colors.gray('Missing desc:')} ${pagesWithoutDescription}`);
238
+ console.log(colors.bold('\n SEO Summary:'));
239
+ const { summary } = result;
240
+ console.log(` ${colors.red('✗')} Pages with errors: ${summary.pagesWithErrors}`);
241
+ console.log(` ${colors.yellow('⚠')} Pages with warnings: ${summary.pagesWithWarnings}`);
242
+ console.log(` ${colors.magenta('⚐')} Duplicate titles: ${summary.duplicateTitles}`);
243
+ console.log(` ${colors.magenta('⚐')} Duplicate descriptions:${summary.duplicateDescriptions}`);
244
+ console.log(` ${colors.magenta('⚐')} Duplicate H1s: ${summary.duplicateH1s}`);
245
+ console.log(` ${colors.gray('○')} Orphan pages: ${summary.orphanPages}`);
246
+ if (result.discovery) {
247
+ console.log(colors.bold('\n Discovery:'));
248
+ const { humans, llms, sitemap, manifest } = result.discovery;
249
+ if (humans.found)
250
+ console.log(` ${colors.green('✔')} humans.txt found`);
251
+ if (llms.found)
252
+ console.log(` ${colors.green('✔')} llms.txt found`);
253
+ if (sitemap.found) {
254
+ const urlCount = sitemap.urlCount ? ` (${sitemap.urlCount} URLs)` : '';
255
+ console.log(` ${colors.green('✔')} sitemap.xml found${urlCount}`);
256
+ }
257
+ if (manifest.found) {
258
+ const status = manifest.valid ? colors.green('valid') : colors.yellow('invalid');
259
+ console.log(` ${colors.green('✔')} manifest.json found (${status})`);
260
+ if (manifest.issues && manifest.issues.length > 0) {
261
+ manifest.issues.slice(0, 3).forEach(issue => {
262
+ console.log(` ${colors.yellow('⚠')} ${issue}`);
263
+ });
264
+ if (manifest.issues.length > 3) {
265
+ console.log(` ${colors.gray(`...and ${manifest.issues.length - 3} more issues`)}`);
266
+ }
267
+ }
268
+ }
269
+ if (!humans.found && !llms.found && !sitemap.found && !manifest.found) {
270
+ console.log(` ${colors.gray('○')} No discovery files found`);
271
+ }
272
+ }
273
+ if (result.rssFeeds && result.rssFeeds.length > 0) {
274
+ console.log(colors.bold('\n RSS/Atom Feeds:'));
275
+ result.rssFeeds.forEach(feed => {
276
+ const typeLabel = feed.type === 'rss' ? 'RSS' : 'Atom';
277
+ const title = feed.title ? `"${feed.title}"` : 'Untitled';
278
+ const count = feed.itemCount > 0 ? `(${feed.itemCount} items)` : '';
279
+ console.log(` ${colors.green('✔')} ${colors.cyan(typeLabel)} ${title} ${colors.gray(count)}`);
280
+ console.log(` ${colors.gray(feed.url)}`);
281
+ });
282
+ }
283
+ if (result.siteWideIssues.length > 0) {
284
+ console.log(colors.bold('\n Site-Wide Issues:'));
285
+ const sortedIssues = [...result.siteWideIssues].sort((a, b) => {
286
+ const priority = { error: 0, warning: 1, info: 2 };
287
+ return priority[a.severity] - priority[b.severity];
288
+ });
289
+ for (const issue of sortedIssues.slice(0, 10)) {
290
+ const icon = issue.severity === 'error' ? colors.red('✗') :
291
+ issue.severity === 'warning' ? colors.yellow('⚠') : colors.gray('○');
292
+ const colorFn = issue.severity === 'error' ? colors.red :
293
+ issue.severity === 'warning' ? colors.yellow : colors.gray;
294
+ console.log(` ${icon} ${colorFn(issue.message)}`);
295
+ if (issue.value) {
296
+ const truncatedValue = issue.value.length > 50 ? issue.value.slice(0, 47) + '...' : issue.value;
297
+ console.log(` ${colors.gray(`"${truncatedValue}"`)}`);
298
+ }
299
+ const uniquePaths = [...new Set(issue.affectedUrls.map(u => {
300
+ try {
301
+ return new URL(u).pathname;
302
+ }
303
+ catch {
304
+ return u;
305
+ }
306
+ }))];
307
+ if (uniquePaths.length <= 3) {
308
+ for (const path of uniquePaths) {
309
+ console.log(` ${colors.gray('→')} ${path}`);
310
+ }
311
+ }
312
+ else {
313
+ console.log(` ${colors.gray(`→ ${uniquePaths.length} pages affected`)}`);
314
+ }
315
+ }
316
+ if (result.siteWideIssues.length > 10) {
317
+ console.log(colors.gray(` ... and ${result.siteWideIssues.length - 10} more issues`));
318
+ }
319
+ }
320
+ const pagesWithScores = result.pages
321
+ .filter(p => p.seoReport)
322
+ .sort((a, b) => (a.seoReport?.score || 0) - (b.seoReport?.score || 0));
323
+ const seenPaths = new Set();
324
+ const uniquePages = pagesWithScores.filter(page => {
325
+ const path = new URL(page.url).pathname;
326
+ if (seenPaths.has(path))
327
+ return false;
328
+ seenPaths.add(path);
329
+ return true;
330
+ });
331
+ if (uniquePages.length > 0) {
332
+ console.log(colors.bold('\n Pages by SEO Score:'));
333
+ const worstPages = uniquePages.slice(0, 5);
334
+ for (const page of worstPages) {
335
+ const score = page.seoReport?.score || 0;
336
+ const grade = page.seoReport?.grade || '?';
337
+ const path = new URL(page.url).pathname;
338
+ const scoreColor = score >= 80 ? colors.green : score >= 60 ? colors.yellow : colors.red;
339
+ console.log(` ${scoreColor(`${score.toString().padStart(3)}`)} ${colors.gray(`[${grade}]`)} ${path.slice(0, 50)}`);
340
+ }
341
+ if (uniquePages.length > 5) {
342
+ console.log(colors.gray(` ... and ${uniquePages.length - 5} more pages`));
343
+ }
344
+ }
345
+ if (outputFile) {
346
+ console.log(colors.green(`\n Report saved to: ${outputFile}`));
347
+ }
348
+ }
349
+ else {
350
+ const { Spider } = await import('../../scrape/spider.js');
351
+ const spider = new Spider({
352
+ maxDepth: data.depth,
353
+ maxPages: data.limit,
354
+ concurrency: data.concurrency,
355
+ sameDomain: true,
356
+ delay: 100,
357
+ respectRobotsTxt,
358
+ onProgress: formatJson ? undefined : (progress) => {
359
+ process.stdout.write(`\r${colors.gray(' Crawling:')} ${colors.cyan(progress.crawled.toString())} pages | ${colors.gray('Queue:')} ${progress.queued} | ${colors.gray('Depth:')} ${progress.depth} `);
360
+ },
361
+ });
362
+ const result = await spider.crawl(url);
363
+ if (formatJson) {
364
+ const jsonOutput = {
365
+ startUrl: result.startUrl,
366
+ crawledAt: new Date().toISOString(),
367
+ duration: result.duration,
368
+ config: {
369
+ maxDepth: data.depth,
370
+ maxPages: data.limit,
371
+ concurrency: data.concurrency,
372
+ },
373
+ summary: {
374
+ totalPages: result.pages.length,
375
+ successCount: result.pages.filter(p => !p.error).length,
376
+ errorCount: result.errors.length,
377
+ uniqueUrls: result.visited.size,
378
+ },
379
+ pages: result.pages.map(p => ({
380
+ url: p.url,
381
+ status: p.status,
382
+ title: p.title,
383
+ depth: p.depth,
384
+ linksCount: p.links.length,
385
+ duration: p.duration,
386
+ error: p.error,
387
+ meta: p.meta,
388
+ metrics: p.metrics,
389
+ social: p.social,
390
+ })), errors: result.pages.filter(p => p.error).map(p => ({
391
+ url: p.url,
392
+ status: p.status,
393
+ error: p.error
394
+ })),
395
+ };
396
+ console.log(JSON.stringify(jsonOutput, null, 2));
397
+ return;
398
+ }
399
+ process.stdout.write('\r' + ' '.repeat(80) + '\r');
400
+ console.log(colors.green(`\n✔ Spider complete`) + colors.gray(` (${(result.duration / 1000).toFixed(1)}s)`));
401
+ console.log(` ${colors.cyan('Pages crawled')}: ${result.pages.length}`);
402
+ console.log(` ${colors.cyan('Unique URLs')}: ${result.visited.size}`);
403
+ console.log(` ${colors.cyan('Errors')}: ${result.errors.length}`);
404
+ const byDepth = new Map();
405
+ for (const page of result.pages) {
406
+ byDepth.set(page.depth, (byDepth.get(page.depth) || 0) + 1);
407
+ }
408
+ console.log(colors.bold('\n Pages by depth:'));
409
+ for (const [depth, count] of Array.from(byDepth.entries()).sort((a, b) => a[0] - b[0])) {
410
+ const bar = '█'.repeat(Math.min(count, 40));
411
+ console.log(` ${colors.gray(`d${depth}:`)} ${bar} ${count}`);
412
+ }
413
+ const topPages = [...result.pages]
414
+ .filter(p => !p.error)
415
+ .sort((a, b) => b.links.length - a.links.length)
416
+ .slice(0, 10);
417
+ if (topPages.length > 0) {
418
+ console.log(colors.bold('\n Top pages by outgoing links:'));
419
+ for (const page of topPages) {
420
+ const title = page.title.slice(0, 40) || new URL(page.url).pathname;
421
+ console.log(` ${colors.cyan(page.links.length.toString().padStart(3))} ${title}`);
422
+ }
423
+ }
424
+ if (result.errors.length > 0) {
425
+ const errorSummary = summarizeErrors(result.errors);
426
+ console.log(formatErrorSummary(errorSummary));
427
+ }
428
+ if (outputFile) {
429
+ const jsonOutput = {
430
+ startUrl: result.startUrl,
431
+ crawledAt: new Date().toISOString(),
432
+ duration: result.duration,
433
+ summary: {
434
+ totalPages: result.pages.length,
435
+ successCount: result.pages.filter(p => !p.error).length,
436
+ errorCount: result.errors.length,
437
+ uniqueUrls: result.visited.size,
438
+ },
439
+ pages: result.pages.map(p => ({
440
+ url: p.url,
441
+ status: p.status,
442
+ title: p.title,
443
+ depth: p.depth,
444
+ linksCount: p.links.length,
445
+ duration: p.duration,
446
+ error: p.error,
447
+ meta: p.meta,
448
+ metrics: p.metrics,
449
+ social: p.social,
450
+ })), errors: result.pages.filter(p => p.error).map(p => ({
451
+ url: p.url,
452
+ status: p.status,
453
+ error: p.error
454
+ })),
455
+ };
456
+ await fs.writeFile(outputFile, JSON.stringify(jsonOutput, null, 2));
457
+ console.log(colors.green(`\n Report saved to: ${outputFile}`));
458
+ }
459
+ }
460
+ console.log('');
461
+ }
462
+ catch (error) {
463
+ console.error(colors.red(`\nSpider failed: ${error.message}`));
464
+ process.exit(1);
465
+ }
466
+ }
467
+ export function registerSpiderCommand(program) {
468
+ program
469
+ .command('spider')
470
+ .alias('crawl')
471
+ .description('Crawl a website and analyze all pages')
472
+ .argument('<url>', 'Starting URL to crawl')
473
+ .argument('[args...]', 'Options: depth=N limit=N concurrency=N seo focus=MODE...')
474
+ .addHelpText('after', generateHelp(schema))
475
+ .action(async (url, rawArgs) => {
476
+ await runSpider([url, ...rawArgs]);
477
+ });
478
+ }
@@ -0,0 +1,2 @@
1
+ import { RekCommand as Command } from '../router.js';
2
+ export declare function registerUtilsCommands(program: Command): void;
@@ -0,0 +1,176 @@
1
+ import colors from '../../utils/colors.js';
2
+ import { RekArgs, generateHelp } from '../parser/index.js';
3
+ import { promises as fs } from 'node:fs';
4
+ import pathMod from 'node:path';
5
+ import { installCurlImpersonate, hasImpersonate, getCurlPath } from '../../utils/binary-manager.js';
6
+ const uploadSchema = {
7
+ name: 'upload',
8
+ description: 'Upload a file to a URL',
9
+ params: {
10
+ field: { type: 'string', default: 'file', description: 'Form field name' },
11
+ },
12
+ flags: {
13
+ progress: { description: 'Show upload progress', default: true },
14
+ 'no-progress': { description: 'Disable progress bar' }
15
+ },
16
+ examples: [
17
+ { cmd: 'rek upload api.com/files ./image.png', desc: 'Simple upload' },
18
+ { cmd: 'rek upload api.com/files data.json field=doc', desc: 'Custom field' }
19
+ ]
20
+ };
21
+ const downloadSchema = {
22
+ name: 'download',
23
+ description: 'Download a file from a URL',
24
+ flags: {
25
+ resume: { description: 'Resume partial download', default: false },
26
+ progress: { description: 'Show progress', default: true },
27
+ 'no-progress': { description: 'Disable progress' }
28
+ },
29
+ examples: [
30
+ { cmd: 'rek download example.com/file.zip', desc: 'Download' },
31
+ { cmd: 'rek download example.com/large.iso resume', desc: 'Resume download' }
32
+ ]
33
+ };
34
+ const proxySchema = {
35
+ name: 'proxy',
36
+ description: 'Route requests through a proxy',
37
+ params: {
38
+ method: { type: 'string', default: 'GET', description: 'HTTP Method' },
39
+ },
40
+ examples: [
41
+ { cmd: 'rek proxy http://127.0.0.1:8080 api.com/get', desc: 'Proxy GET' },
42
+ { cmd: 'rek proxy socks5://127.0.0.1:9050 api.com/post method=POST', desc: 'SOCKS5 POST' }
43
+ ]
44
+ };
45
+ export function registerUtilsCommands(program) {
46
+ program.command('upload')
47
+ .description(uploadSchema.description)
48
+ .argument('<url>', 'Target URL')
49
+ .argument('<file>', 'File path')
50
+ .argument('[args...]', 'Options')
51
+ .addHelpText('after', generateHelp(uploadSchema))
52
+ .action(async (url, file, rawArgs) => {
53
+ const { data, options, headers } = RekArgs.parse(rawArgs, uploadSchema);
54
+ const showProgress = options['no-progress'] ? false : (options.progress !== false);
55
+ if (!url.startsWith('http'))
56
+ url = `https://${url}`;
57
+ const { createClient } = await import('../../core/client.js');
58
+ try {
59
+ await fs.access(file);
60
+ const stats = await fs.stat(file);
61
+ console.log(colors.gray(`Uploading ${pathMod.basename(file)} (${(stats.size / 1024).toFixed(1)} KB)...`));
62
+ const client = createClient();
63
+ const fileContent = await fs.readFile(file);
64
+ const boundary = `----ReckerBoundary${Date.now()}`;
65
+ const filename = pathMod.basename(file);
66
+ const bodyParts = [
67
+ `--${boundary}`,
68
+ `Content-Disposition: form-data; name="${data.field}"; filename="${filename}"`,
69
+ 'Content-Type: application/octet-stream',
70
+ '',
71
+ ''
72
+ ];
73
+ const header = Buffer.from(bodyParts.join('\r\n'));
74
+ const footer = Buffer.from(`\r\n--${boundary}--\r\n`);
75
+ const body = Buffer.concat([header, fileContent, footer]);
76
+ const response = await client.post(url, body, {
77
+ headers: {
78
+ ...headers,
79
+ 'Content-Type': `multipart/form-data; boundary=${boundary}`,
80
+ },
81
+ });
82
+ console.log(colors.green(`✔ Upload complete: ${response.status} ${response.statusText}`));
83
+ const text = await response.text();
84
+ if (text)
85
+ console.log(text);
86
+ }
87
+ catch (err) {
88
+ console.error(colors.red(`Upload Error: ${err.message}`));
89
+ process.exit(1);
90
+ }
91
+ });
92
+ program.command('download')
93
+ .description(downloadSchema.description)
94
+ .argument('<url>', 'Source URL')
95
+ .argument('[args...]', 'Output path and options')
96
+ .addHelpText('after', generateHelp(downloadSchema))
97
+ .action(async (url, rawArgs) => {
98
+ const { options, headers, args } = RekArgs.parse(rawArgs, downloadSchema);
99
+ const output = args[0];
100
+ const showProgress = options['no-progress'] ? false : (options.progress !== false);
101
+ const resume = !!options.resume;
102
+ if (!url.startsWith('http'))
103
+ url = `https://${url}`;
104
+ const { downloadToFile } = await import('../../utils/download.js');
105
+ const { createClient } = await import('../../core/client.js');
106
+ const urlPath = new URL(url).pathname;
107
+ const filename = output || pathMod.basename(urlPath) || 'download';
108
+ console.log(colors.gray(`Downloading to ${filename}...`));
109
+ try {
110
+ const client = createClient();
111
+ await downloadToFile(client, url, filename, {
112
+ resume,
113
+ headers,
114
+ onProgress: showProgress ? (p) => {
115
+ const total = p.total || 0;
116
+ const pct = total > 0 ? Math.round((p.loaded / total) * 100) : 0;
117
+ const mb = (p.loaded / 1024 / 1024).toFixed(1);
118
+ process.stdout.write(`\r ${pct}% (${mb} MB)`);
119
+ } : undefined
120
+ });
121
+ if (showProgress)
122
+ process.stdout.write('\n');
123
+ console.log(colors.green(`✔ Download complete`));
124
+ }
125
+ catch (err) {
126
+ console.error(colors.red(`Download Error: ${err.message}`));
127
+ process.exit(1);
128
+ }
129
+ });
130
+ program.command('proxy')
131
+ .description(proxySchema.description)
132
+ .argument('<proxy>', 'Proxy URL')
133
+ .argument('<target>', 'Target URL')
134
+ .argument('[args...]', 'Request options')
135
+ .addHelpText('after', generateHelp(proxySchema))
136
+ .action(async (proxy, target, rawArgs) => {
137
+ const { data, headers } = RekArgs.parse(rawArgs, proxySchema);
138
+ if (!target.startsWith('http'))
139
+ target = `https://${target}`;
140
+ console.log(colors.gray(`Proxy: ${proxy}`));
141
+ console.log(colors.gray(`Target: ${target}`));
142
+ const { createClient } = await import('../../core/client.js');
143
+ try {
144
+ const client = createClient({ proxy: { url: proxy } });
145
+ const method = data.method.toLowerCase();
146
+ const body = { ...data };
147
+ delete body.method;
148
+ const hasBody = Object.keys(body).length > 0;
149
+ const options = hasBody ? { json: body, headers } : { headers };
150
+ const response = await client[method](target, options);
151
+ console.log(colors.green(`✔ ${response.status} ${response.statusText}`));
152
+ console.log(await response.text());
153
+ }
154
+ catch (err) {
155
+ console.error(colors.red(`Proxy Error: ${err.message}`));
156
+ process.exit(1);
157
+ }
158
+ });
159
+ program.command('setup')
160
+ .description('Install external dependencies (curl-impersonate) for advanced features')
161
+ .action(async () => {
162
+ if (await hasImpersonate()) {
163
+ console.log(colors.green(`✔ curl-impersonate is already installed at:`));
164
+ console.log(colors.gray(getCurlPath()));
165
+ return;
166
+ }
167
+ try {
168
+ console.log(colors.cyan('Installing curl-impersonate...'));
169
+ await installCurlImpersonate(console);
170
+ }
171
+ catch (e) {
172
+ console.error(colors.red(`Installation failed: ${e.message}`));
173
+ process.exit(1);
174
+ }
175
+ });
176
+ }
@@ -0,0 +1,2 @@
1
+ import { RekCommand as Command } from '../router.js';
2
+ export declare function registerVectorCommand(program: Command): void;