recker 1.0.43 → 1.0.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -0
- package/dist/bin/recker-linux-x64 +0 -0
- package/dist/bin/recker-macos-x64 +0 -0
- package/dist/bin/recker-win-x64.exe +0 -0
- package/dist/bin/rek.cjs +85152 -100207
- package/dist/browser/ai/adaptive-timeout.d.ts +50 -0
- package/dist/browser/ai/adaptive-timeout.js +208 -0
- package/dist/browser/ai/client.d.ts +22 -0
- package/dist/browser/ai/client.js +294 -0
- package/dist/browser/ai/index.d.ts +14 -0
- package/dist/browser/ai/index.js +11 -0
- package/dist/browser/ai/providers/anthropic.d.ts +63 -0
- package/dist/browser/ai/providers/anthropic.js +370 -0
- package/dist/browser/ai/providers/base.d.ts +48 -0
- package/dist/browser/ai/providers/base.js +150 -0
- package/dist/browser/ai/providers/google.d.ts +59 -0
- package/dist/browser/ai/providers/google.js +305 -0
- package/dist/browser/ai/providers/ollama.d.ts +44 -0
- package/dist/browser/ai/providers/ollama.js +240 -0
- package/dist/browser/ai/providers/openai.d.ts +64 -0
- package/dist/browser/ai/providers/openai.js +298 -0
- package/dist/browser/ai/rate-limiter.d.ts +43 -0
- package/dist/browser/ai/rate-limiter.js +215 -0
- package/dist/browser/ai/vector/index.d.ts +2 -0
- package/dist/browser/ai/vector/index.js +2 -0
- package/dist/browser/ai/vector/similarity.d.ts +2 -0
- package/dist/browser/ai/vector/similarity.js +27 -0
- package/dist/browser/ai/vector/store.d.ts +27 -0
- package/dist/browser/ai/vector/store.js +82 -0
- package/dist/browser/browser/cache.d.ts +2 -40
- package/dist/browser/browser/cache.js +2 -199
- package/dist/browser/browser/index.d.ts +8 -0
- package/dist/browser/browser/index.js +8 -0
- package/dist/browser/browser/recker.d.ts +8 -1
- package/dist/browser/browser/recker.js +8 -2
- package/dist/browser/cache/indexed-db.d.ts +10 -0
- package/dist/browser/cache/indexed-db.js +88 -0
- package/dist/browser/cache/service-worker-cache.d.ts +18 -0
- package/dist/browser/cache/service-worker-cache.js +103 -0
- package/dist/browser/cache.d.ts +2 -40
- package/dist/browser/cache.js +2 -199
- package/dist/browser/constants/user-agents.d.ts +7 -0
- package/dist/browser/constants/user-agents.js +7 -0
- package/dist/browser/core/client.d.ts +2 -0
- package/dist/browser/core/client.js +19 -1
- package/dist/browser/index.d.ts +8 -0
- package/dist/browser/index.js +8 -0
- package/dist/browser/plugins/har-recorder.d.ts +40 -0
- package/dist/browser/plugins/har-recorder.js +120 -0
- package/dist/browser/plugins/network-simulation.d.ts +7 -0
- package/dist/browser/plugins/network-simulation.js +13 -0
- package/dist/browser/presets/android.d.ts +2 -0
- package/dist/browser/presets/android.js +16 -0
- package/dist/browser/presets/anthropic.d.ts +8 -0
- package/dist/browser/presets/anthropic.js +27 -0
- package/dist/browser/presets/aws.d.ts +19 -0
- package/dist/browser/presets/aws.js +68 -0
- package/dist/browser/presets/azure-openai.d.ts +10 -0
- package/dist/browser/presets/azure-openai.js +35 -0
- package/dist/browser/presets/azure.d.ts +41 -0
- package/dist/browser/presets/azure.js +104 -0
- package/dist/browser/presets/chaturbate.d.ts +2 -0
- package/dist/browser/presets/chaturbate.js +17 -0
- package/dist/browser/presets/cloudflare.d.ts +12 -0
- package/dist/browser/presets/cloudflare.js +39 -0
- package/dist/browser/presets/cohere.d.ts +7 -0
- package/dist/browser/presets/cohere.js +22 -0
- package/dist/browser/presets/deepseek.d.ts +7 -0
- package/dist/browser/presets/deepseek.js +22 -0
- package/dist/browser/presets/digitalocean.d.ts +5 -0
- package/dist/browser/presets/digitalocean.js +16 -0
- package/dist/browser/presets/discord.d.ts +6 -0
- package/dist/browser/presets/discord.js +17 -0
- package/dist/browser/presets/elevenlabs.d.ts +6 -0
- package/dist/browser/presets/elevenlabs.js +20 -0
- package/dist/browser/presets/enhancers.d.ts +20 -0
- package/dist/browser/presets/enhancers.js +85 -0
- package/dist/browser/presets/fireworks.d.ts +7 -0
- package/dist/browser/presets/fireworks.js +22 -0
- package/dist/browser/presets/gcp.d.ts +34 -0
- package/dist/browser/presets/gcp.js +91 -0
- package/dist/browser/presets/gemini.d.ts +7 -0
- package/dist/browser/presets/gemini.js +23 -0
- package/dist/browser/presets/github.d.ts +6 -0
- package/dist/browser/presets/github.js +17 -0
- package/dist/browser/presets/gitlab.d.ts +6 -0
- package/dist/browser/presets/gitlab.js +16 -0
- package/dist/browser/presets/groq.d.ts +7 -0
- package/dist/browser/presets/groq.js +22 -0
- package/dist/browser/presets/hubspot.d.ts +9 -0
- package/dist/browser/presets/hubspot.js +28 -0
- package/dist/browser/presets/huggingface.d.ts +7 -0
- package/dist/browser/presets/huggingface.js +23 -0
- package/dist/browser/presets/index.d.ts +47 -0
- package/dist/browser/presets/index.js +47 -0
- package/dist/browser/presets/ios.d.ts +2 -0
- package/dist/browser/presets/ios.js +13 -0
- package/dist/browser/presets/linear.d.ts +5 -0
- package/dist/browser/presets/linear.js +16 -0
- package/dist/browser/presets/mailgun.d.ts +7 -0
- package/dist/browser/presets/mailgun.js +20 -0
- package/dist/browser/presets/meta.d.ts +10 -0
- package/dist/browser/presets/meta.js +33 -0
- package/dist/browser/presets/mistral.d.ts +7 -0
- package/dist/browser/presets/mistral.js +22 -0
- package/dist/browser/presets/notion.d.ts +6 -0
- package/dist/browser/presets/notion.js +17 -0
- package/dist/browser/presets/openai.d.ts +9 -0
- package/dist/browser/presets/openai.js +30 -0
- package/dist/browser/presets/oracle.d.ts +19 -0
- package/dist/browser/presets/oracle.js +117 -0
- package/dist/browser/presets/perplexity.d.ts +7 -0
- package/dist/browser/presets/perplexity.js +22 -0
- package/dist/browser/presets/pinecone.d.ts +8 -0
- package/dist/browser/presets/pinecone.js +42 -0
- package/dist/browser/presets/registry.d.ts +23 -0
- package/dist/browser/presets/registry.js +519 -0
- package/dist/browser/presets/replicate.d.ts +7 -0
- package/dist/browser/presets/replicate.js +23 -0
- package/dist/browser/presets/sendgrid.d.ts +6 -0
- package/dist/browser/presets/sendgrid.js +20 -0
- package/dist/browser/presets/sentry.d.ts +11 -0
- package/dist/browser/presets/sentry.js +48 -0
- package/dist/browser/presets/sinch.d.ts +9 -0
- package/dist/browser/presets/sinch.js +39 -0
- package/dist/browser/presets/slack.d.ts +5 -0
- package/dist/browser/presets/slack.js +16 -0
- package/dist/browser/presets/square.d.ts +10 -0
- package/dist/browser/presets/square.js +33 -0
- package/dist/browser/presets/stripe.d.ts +7 -0
- package/dist/browser/presets/stripe.js +23 -0
- package/dist/browser/presets/supabase.d.ts +6 -0
- package/dist/browser/presets/supabase.js +18 -0
- package/dist/browser/presets/tiktok.d.ts +10 -0
- package/dist/browser/presets/tiktok.js +38 -0
- package/dist/browser/presets/together.d.ts +7 -0
- package/dist/browser/presets/together.js +22 -0
- package/dist/browser/presets/twilio.d.ts +6 -0
- package/dist/browser/presets/twilio.js +17 -0
- package/dist/browser/presets/vercel.d.ts +6 -0
- package/dist/browser/presets/vercel.js +23 -0
- package/dist/browser/presets/vultr.d.ts +5 -0
- package/dist/browser/presets/vultr.js +16 -0
- package/dist/browser/presets/xai.d.ts +8 -0
- package/dist/browser/presets/xai.js +23 -0
- package/dist/browser/presets/youtube.d.ts +5 -0
- package/dist/browser/presets/youtube.js +20 -0
- package/dist/browser/recker.d.ts +8 -1
- package/dist/browser/recker.js +8 -2
- package/dist/browser/scrape/document.d.ts +5 -4
- package/dist/browser/scrape/document.js +89 -76
- package/dist/browser/scrape/element.d.ts +10 -8
- package/dist/browser/scrape/element.js +295 -81
- package/dist/browser/scrape/extractors.d.ts +11 -11
- package/dist/browser/scrape/extractors.js +145 -113
- package/dist/browser/scrape/parser/back.d.ts +1 -0
- package/dist/browser/scrape/parser/back.js +3 -0
- package/dist/browser/scrape/parser/index.d.ts +20 -0
- package/dist/browser/scrape/parser/index.js +19 -0
- package/dist/browser/scrape/parser/matcher.d.ts +30 -0
- package/dist/browser/scrape/parser/matcher.js +99 -0
- package/dist/browser/scrape/parser/nodes/comment.d.ts +12 -0
- package/dist/browser/scrape/parser/nodes/comment.js +21 -0
- package/dist/browser/scrape/parser/nodes/html.d.ts +110 -0
- package/dist/browser/scrape/parser/nodes/html.js +978 -0
- package/dist/browser/scrape/parser/nodes/node.d.ts +18 -0
- package/dist/browser/scrape/parser/nodes/node.js +31 -0
- package/dist/browser/scrape/parser/nodes/text.d.ts +14 -0
- package/dist/browser/scrape/parser/nodes/text.js +30 -0
- package/dist/browser/scrape/parser/nodes/type.d.ts +6 -0
- package/dist/browser/scrape/parser/nodes/type.js +7 -0
- package/dist/browser/scrape/parser/parse.d.ts +1 -0
- package/dist/browser/scrape/parser/parse.js +1 -0
- package/dist/browser/scrape/parser/valid.d.ts +2 -0
- package/dist/browser/scrape/parser/valid.js +5 -0
- package/dist/browser/scrape/parser/void-tag.d.ts +7 -0
- package/dist/browser/scrape/parser/void-tag.js +43 -0
- package/dist/browser/scrape/types.d.ts +7 -0
- package/dist/browser/seo/analyzer.d.ts +59 -0
- package/dist/browser/seo/analyzer.js +1399 -0
- package/dist/browser/seo/keywords.d.ts +16 -0
- package/dist/browser/seo/keywords.js +55 -0
- package/dist/browser/seo/rules/accessibility.d.ts +2 -0
- package/dist/browser/seo/rules/accessibility.js +733 -0
- package/dist/browser/seo/rules/ai-search.d.ts +2 -0
- package/dist/browser/seo/rules/ai-search.js +436 -0
- package/dist/browser/seo/rules/analytics.d.ts +2 -0
- package/dist/browser/seo/rules/analytics.js +306 -0
- package/dist/browser/seo/rules/best-practices.d.ts +2 -0
- package/dist/browser/seo/rules/best-practices.js +195 -0
- package/dist/browser/seo/rules/canonical.d.ts +12 -0
- package/dist/browser/seo/rules/canonical.js +270 -0
- package/dist/browser/seo/rules/content.d.ts +2 -0
- package/dist/browser/seo/rules/content.js +522 -0
- package/dist/browser/seo/rules/crawl.d.ts +2 -0
- package/dist/browser/seo/rules/crawl.js +435 -0
- package/dist/browser/seo/rules/cwv.d.ts +2 -0
- package/dist/browser/seo/rules/cwv.js +248 -0
- package/dist/browser/seo/rules/ecommerce.d.ts +2 -0
- package/dist/browser/seo/rules/ecommerce.js +312 -0
- package/dist/browser/seo/rules/i18n.d.ts +2 -0
- package/dist/browser/seo/rules/i18n.js +288 -0
- package/dist/browser/seo/rules/images.d.ts +2 -0
- package/dist/browser/seo/rules/images.js +255 -0
- package/dist/browser/seo/rules/index.d.ts +52 -0
- package/dist/browser/seo/rules/index.js +159 -0
- package/dist/browser/seo/rules/internal-linking.d.ts +2 -0
- package/dist/browser/seo/rules/internal-linking.js +394 -0
- package/dist/browser/seo/rules/links.d.ts +2 -0
- package/dist/browser/seo/rules/links.js +498 -0
- package/dist/browser/seo/rules/local.d.ts +2 -0
- package/dist/browser/seo/rules/local.js +289 -0
- package/dist/browser/seo/rules/meta.d.ts +2 -0
- package/dist/browser/seo/rules/meta.js +805 -0
- package/dist/browser/seo/rules/mobile.d.ts +2 -0
- package/dist/browser/seo/rules/mobile.js +161 -0
- package/dist/browser/seo/rules/performance.d.ts +2 -0
- package/dist/browser/seo/rules/performance.js +738 -0
- package/dist/browser/seo/rules/pwa.d.ts +2 -0
- package/dist/browser/seo/rules/pwa.js +299 -0
- package/dist/browser/seo/rules/readability.d.ts +2 -0
- package/dist/browser/seo/rules/readability.js +264 -0
- package/dist/browser/seo/rules/redirects.d.ts +16 -0
- package/dist/browser/seo/rules/redirects.js +199 -0
- package/dist/browser/seo/rules/resources.d.ts +2 -0
- package/dist/browser/seo/rules/resources.js +390 -0
- package/dist/browser/seo/rules/schema.d.ts +2 -0
- package/dist/browser/seo/rules/schema.js +379 -0
- package/dist/browser/seo/rules/security.d.ts +2 -0
- package/dist/browser/seo/rules/security.js +877 -0
- package/dist/browser/seo/rules/social.d.ts +2 -0
- package/dist/browser/seo/rules/social.js +603 -0
- package/dist/browser/seo/rules/structural.d.ts +2 -0
- package/dist/browser/seo/rules/structural.js +223 -0
- package/dist/browser/seo/rules/technical-advanced.d.ts +10 -0
- package/dist/browser/seo/rules/technical-advanced.js +289 -0
- package/dist/browser/seo/rules/technical.d.ts +2 -0
- package/dist/browser/seo/rules/technical.js +480 -0
- package/dist/browser/seo/rules/thresholds.d.ts +196 -0
- package/dist/browser/seo/rules/thresholds.js +118 -0
- package/dist/browser/seo/rules/types.d.ts +498 -0
- package/dist/browser/seo/rules/types.js +11 -0
- package/dist/browser/seo/types.d.ts +211 -0
- package/dist/browser/seo/types.js +1 -0
- package/dist/browser/transport/curl.d.ts +4 -0
- package/dist/browser/transport/curl.js +101 -0
- package/dist/browser/transport/undici.js +1 -2
- package/dist/browser/transport/worker.d.ts +18 -0
- package/dist/browser/transport/worker.js +278 -0
- package/dist/browser/types/index.d.ts +4 -1
- package/dist/browser/utils/binary-manager.d.ts +4 -0
- package/dist/browser/utils/binary-manager.js +72 -0
- package/dist/browser/utils/user-agent.js +2 -13
- package/dist/cache/indexed-db.d.ts +10 -0
- package/dist/cache/indexed-db.js +88 -0
- package/dist/cache/service-worker-cache.d.ts +18 -0
- package/dist/cache/service-worker-cache.js +103 -0
- package/dist/cli/commands/ai.d.ts +2 -0
- package/dist/cli/commands/ai.js +162 -0
- package/dist/cli/commands/bench.d.ts +2 -0
- package/dist/cli/commands/bench.js +51 -0
- package/dist/cli/commands/dns.d.ts +2 -0
- package/dist/cli/commands/dns.js +295 -0
- package/dist/cli/commands/har.d.ts +2 -0
- package/dist/cli/commands/har.js +171 -0
- package/dist/cli/commands/hls.d.ts +2 -0
- package/dist/cli/commands/hls.js +192 -0
- package/dist/cli/commands/network.d.ts +2 -0
- package/dist/cli/commands/network.js +288 -0
- package/dist/cli/commands/protocols.d.ts +2 -0
- package/dist/cli/commands/protocols.js +344 -0
- package/dist/cli/commands/scrape.d.ts +2 -0
- package/dist/cli/commands/scrape.js +176 -0
- package/dist/cli/commands/security.d.ts +2 -0
- package/dist/cli/commands/security.js +57 -0
- package/dist/cli/commands/seo.d.ts +2 -0
- package/dist/cli/commands/seo.js +125 -0
- package/dist/cli/commands/serve.d.ts +2 -0
- package/dist/cli/commands/serve.js +531 -0
- package/dist/cli/commands/spider.d.ts +3 -0
- package/dist/cli/commands/spider.js +456 -0
- package/dist/cli/commands/utils.d.ts +2 -0
- package/dist/cli/commands/utils.js +176 -0
- package/dist/cli/commands/vector.d.ts +2 -0
- package/dist/cli/commands/vector.js +158 -0
- package/dist/cli/handler.d.ts +2 -2
- package/dist/cli/handler.js +6 -6
- package/dist/cli/helpers.d.ts +7 -0
- package/dist/cli/helpers.js +128 -0
- package/dist/cli/index.js +96 -5228
- package/dist/cli/parser/help.d.ts +2 -0
- package/dist/cli/parser/help.js +52 -0
- package/dist/cli/parser/index.d.ts +3 -0
- package/dist/cli/parser/index.js +3 -0
- package/dist/cli/parser/parser.d.ts +4 -0
- package/dist/cli/parser/parser.js +146 -0
- package/dist/cli/parser/types.d.ts +41 -0
- package/dist/cli/parser/types.js +1 -0
- package/dist/cli/presets.d.ts +1 -1
- package/dist/cli/presets.js +1 -1
- package/dist/cli/router.d.ts +36 -0
- package/dist/cli/router.js +195 -0
- package/dist/cli/tui/ai-chat.js +1 -1
- package/dist/cli/tui/commands/context.d.ts +9 -0
- package/dist/cli/tui/commands/context.js +1 -0
- package/dist/cli/tui/commands/dns.d.ts +10 -0
- package/dist/cli/tui/commands/dns.js +461 -0
- package/dist/cli/tui/commands/hls.d.ts +2 -0
- package/dist/cli/tui/commands/hls.js +162 -0
- package/dist/cli/tui/commands/ip.d.ts +2 -0
- package/dist/cli/tui/commands/ip.js +45 -0
- package/dist/cli/tui/commands/network.d.ts +3 -0
- package/dist/cli/tui/commands/network.js +81 -0
- package/dist/cli/tui/commands/protocols.d.ts +6 -0
- package/dist/cli/tui/commands/protocols.js +531 -0
- package/dist/cli/tui/commands/security.d.ts +2 -0
- package/dist/cli/tui/commands/security.js +48 -0
- package/dist/cli/tui/commands/seo.d.ts +2 -0
- package/dist/cli/tui/commands/seo.js +74 -0
- package/dist/cli/tui/context.d.ts +12 -0
- package/dist/cli/tui/context.js +1 -0
- package/dist/cli/tui/shell.d.ts +11 -20
- package/dist/cli/tui/shell.js +216 -1873
- package/dist/constants/user-agents.d.ts +7 -0
- package/dist/constants/user-agents.js +7 -0
- package/dist/core/client.d.ts +2 -0
- package/dist/core/client.js +19 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/cli.js +2 -3
- package/dist/mcp/data/embeddings.json +1 -1
- package/dist/mcp/tools/network.js +298 -158
- package/dist/plugins/har-player.d.ts +23 -0
- package/dist/plugins/har-player.js +49 -0
- package/dist/plugins/har-recorder.d.ts +37 -3
- package/dist/plugins/har-recorder.js +116 -63
- package/dist/plugins/network-simulation.d.ts +7 -0
- package/dist/plugins/network-simulation.js +13 -0
- package/dist/presets/android.d.ts +2 -0
- package/dist/presets/android.js +16 -0
- package/dist/presets/chaturbate.d.ts +2 -0
- package/dist/presets/chaturbate.js +17 -0
- package/dist/presets/elevenlabs.d.ts +6 -0
- package/dist/presets/elevenlabs.js +20 -0
- package/dist/presets/enhancers.d.ts +20 -0
- package/dist/presets/enhancers.js +85 -0
- package/dist/presets/hubspot.d.ts +9 -0
- package/dist/presets/hubspot.js +28 -0
- package/dist/presets/index.d.ts +10 -0
- package/dist/presets/index.js +10 -0
- package/dist/presets/ios.d.ts +2 -0
- package/dist/presets/ios.js +13 -0
- package/dist/presets/pinecone.d.ts +8 -0
- package/dist/presets/pinecone.js +42 -0
- package/dist/presets/registry.js +60 -0
- package/dist/presets/sendgrid.d.ts +6 -0
- package/dist/presets/sendgrid.js +20 -0
- package/dist/presets/sentry.d.ts +11 -0
- package/dist/presets/sentry.js +48 -0
- package/dist/presets/square.d.ts +10 -0
- package/dist/presets/square.js +33 -0
- package/dist/recker.d.ts +3 -0
- package/dist/recker.js +4 -0
- package/dist/scrape/document.d.ts +5 -4
- package/dist/scrape/document.js +89 -76
- package/dist/scrape/element.d.ts +10 -8
- package/dist/scrape/element.js +295 -81
- package/dist/scrape/extractors.d.ts +11 -11
- package/dist/scrape/extractors.js +145 -113
- package/dist/scrape/index.d.ts +2 -0
- package/dist/scrape/index.js +1 -0
- package/dist/scrape/parser/back.d.ts +1 -0
- package/dist/scrape/parser/back.js +3 -0
- package/dist/scrape/parser/index.d.ts +20 -0
- package/dist/scrape/parser/index.js +19 -0
- package/dist/scrape/parser/matcher.d.ts +30 -0
- package/dist/scrape/parser/matcher.js +99 -0
- package/dist/scrape/parser/nodes/comment.d.ts +12 -0
- package/dist/scrape/parser/nodes/comment.js +21 -0
- package/dist/scrape/parser/nodes/html.d.ts +110 -0
- package/dist/scrape/parser/nodes/html.js +978 -0
- package/dist/scrape/parser/nodes/node.d.ts +18 -0
- package/dist/scrape/parser/nodes/node.js +31 -0
- package/dist/scrape/parser/nodes/text.d.ts +14 -0
- package/dist/scrape/parser/nodes/text.js +30 -0
- package/dist/scrape/parser/nodes/type.d.ts +6 -0
- package/dist/scrape/parser/nodes/type.js +7 -0
- package/dist/scrape/parser/parse.d.ts +1 -0
- package/dist/scrape/parser/parse.js +1 -0
- package/dist/scrape/parser/valid.d.ts +2 -0
- package/dist/scrape/parser/valid.js +5 -0
- package/dist/scrape/parser/void-tag.d.ts +7 -0
- package/dist/scrape/parser/void-tag.js +43 -0
- package/dist/scrape/spider.d.ts +19 -0
- package/dist/scrape/spider.js +28 -3
- package/dist/scrape/types.d.ts +7 -0
- package/dist/seo/analyzer.d.ts +15 -5
- package/dist/seo/analyzer.js +636 -175
- package/dist/seo/formatter.d.ts +16 -0
- package/dist/seo/formatter.js +228 -0
- package/dist/seo/index.d.ts +2 -0
- package/dist/seo/index.js +1 -0
- package/dist/seo/keywords.d.ts +16 -0
- package/dist/seo/keywords.js +55 -0
- package/dist/seo/rules/accessibility.js +96 -57
- package/dist/seo/rules/ai-search.js +44 -31
- package/dist/seo/rules/analytics.d.ts +2 -0
- package/dist/seo/rules/analytics.js +306 -0
- package/dist/seo/rules/best-practices.js +21 -14
- package/dist/seo/rules/canonical.js +53 -32
- package/dist/seo/rules/content.js +317 -31
- package/dist/seo/rules/crawl.js +55 -40
- package/dist/seo/rules/cwv.js +21 -15
- package/dist/seo/rules/ecommerce.js +82 -22
- package/dist/seo/rules/i18n.js +75 -36
- package/dist/seo/rules/images.js +109 -30
- package/dist/seo/rules/index.js +2 -0
- package/dist/seo/rules/internal-linking.js +58 -39
- package/dist/seo/rules/links.js +79 -52
- package/dist/seo/rules/local.js +49 -25
- package/dist/seo/rules/meta.js +339 -81
- package/dist/seo/rules/mobile.js +112 -2
- package/dist/seo/rules/performance.js +434 -66
- package/dist/seo/rules/pwa.js +36 -39
- package/dist/seo/rules/readability.js +31 -22
- package/dist/seo/rules/redirects.js +21 -15
- package/dist/seo/rules/resources.js +59 -42
- package/dist/seo/rules/schema.js +333 -8
- package/dist/seo/rules/security.js +142 -80
- package/dist/seo/rules/social.js +277 -47
- package/dist/seo/rules/structural.js +87 -19
- package/dist/seo/rules/technical-advanced.js +30 -24
- package/dist/seo/rules/technical.js +243 -42
- package/dist/seo/rules/types.d.ts +53 -1
- package/dist/seo/seo-spider.d.ts +22 -0
- package/dist/seo/seo-spider.js +77 -13
- package/dist/seo/types.d.ts +8 -1
- package/dist/seo/validators/llms-txt.js +19 -0
- package/dist/seo/validators/rss.d.ts +11 -0
- package/dist/seo/validators/rss.js +93 -0
- package/dist/seo/validators/sitemap.js +36 -26
- package/dist/transport/curl.d.ts +4 -0
- package/dist/transport/curl.js +101 -0
- package/dist/transport/udp.js +0 -1
- package/dist/transport/undici.js +1 -2
- package/dist/transport/worker.d.ts +18 -0
- package/dist/transport/worker.js +278 -0
- package/dist/types/index.d.ts +4 -1
- package/dist/utils/binary-manager.d.ts +4 -0
- package/dist/utils/binary-manager.js +72 -0
- package/dist/utils/optional-require.d.ts +7 -8
- package/dist/utils/optional-require.js +2 -21
- package/dist/utils/upload.d.ts +6 -0
- package/dist/utils/upload.js +11 -0
- package/dist/utils/user-agent.js +2 -13
- package/dist/version.js +1 -1
- package/package.json +12 -6
- package/dist/browser/utils/optional-require.d.ts +0 -19
- package/dist/browser/utils/optional-require.js +0 -105
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import colors from '../../utils/colors.js';
|
|
2
|
+
import { generateHelp } from '../parser/index.js';
|
|
3
|
+
import { promises as fs } from 'node:fs';
|
|
4
|
+
const harSchema = {
|
|
5
|
+
name: 'har',
|
|
6
|
+
description: 'HAR recording and playback',
|
|
7
|
+
flags: {
|
|
8
|
+
append: { description: 'Append to existing HAR file', alias: 'a' },
|
|
9
|
+
strict: { description: 'Fail if request not found in HAR', alias: 's' },
|
|
10
|
+
verbose: { description: 'Show detailed output', alias: 'v' },
|
|
11
|
+
json: { description: 'Output as JSON' }
|
|
12
|
+
},
|
|
13
|
+
params: {
|
|
14
|
+
delay: { type: 'number', default: 0, description: 'Delay between requests' }
|
|
15
|
+
},
|
|
16
|
+
examples: [
|
|
17
|
+
{ cmd: 'rek har record session.har', desc: 'Record requests' },
|
|
18
|
+
{ cmd: 'rek har play session.har', desc: 'Replay requests' },
|
|
19
|
+
{ cmd: 'rek har info session.har', desc: 'Inspect HAR' }
|
|
20
|
+
]
|
|
21
|
+
};
|
|
22
|
+
export function registerHarCommand(program) {
|
|
23
|
+
const har = program.command('har')
|
|
24
|
+
.description(harSchema.description)
|
|
25
|
+
.addHelpText('after', generateHelp(harSchema));
|
|
26
|
+
har.command('record')
|
|
27
|
+
.description('Record HTTP requests to HAR file')
|
|
28
|
+
.argument('<file>', 'Output HAR file path')
|
|
29
|
+
.argument('[url]', 'Optional URL to start recording with')
|
|
30
|
+
.option('-a, --append', 'Append to existing HAR file')
|
|
31
|
+
.action(async (file, url, options) => {
|
|
32
|
+
const { createClient } = await import('../../core/client.js');
|
|
33
|
+
const { harRecorderPlugin } = await import('../../plugins/har-recorder.js');
|
|
34
|
+
let existingEntries = [];
|
|
35
|
+
if (options.append) {
|
|
36
|
+
try {
|
|
37
|
+
const existing = await fs.readFile(file, 'utf-8');
|
|
38
|
+
const har = JSON.parse(existing);
|
|
39
|
+
existingEntries = har.log?.entries || [];
|
|
40
|
+
console.log(colors.gray(`Appending to existing HAR with ${existingEntries.length} entries`));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const client = createClient();
|
|
46
|
+
const plugin = harRecorderPlugin({
|
|
47
|
+
path: file,
|
|
48
|
+
onEntry: (entry) => {
|
|
49
|
+
console.log(colors.green('✔') + colors.gray(` Recorded: ${entry.request.method} ${entry.request.url}`));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
plugin(client);
|
|
53
|
+
if (url) {
|
|
54
|
+
if (!url.startsWith('http'))
|
|
55
|
+
url = `https://${url}`;
|
|
56
|
+
console.log(colors.gray(`Recording request to ${url}...`));
|
|
57
|
+
try {
|
|
58
|
+
const response = await client.get(url);
|
|
59
|
+
console.log(colors.green(`✔ Response: ${response.status} ${response.statusText}`));
|
|
60
|
+
console.log(colors.gray(`Saved to ${file}`));
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error(colors.red(`Request failed: ${error.message}`));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
console.log(colors.cyan('HAR Recording Session'));
|
|
69
|
+
console.log(colors.gray(`Recording to: ${file}`));
|
|
70
|
+
console.log(colors.gray('Enter URLs to record, or "exit" to quit'));
|
|
71
|
+
console.log('');
|
|
72
|
+
const readline = await import('node:readline');
|
|
73
|
+
const rl = readline.createInterface({
|
|
74
|
+
input: process.stdin,
|
|
75
|
+
output: process.stdout,
|
|
76
|
+
});
|
|
77
|
+
const prompt = () => {
|
|
78
|
+
rl.question(colors.cyan('har> '), async (input) => {
|
|
79
|
+
const line = input.trim();
|
|
80
|
+
if (line === 'exit' || line === 'quit') {
|
|
81
|
+
console.log(colors.gray(`\nSession ended. HAR saved to ${file}`));
|
|
82
|
+
rl.close();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (!line) {
|
|
86
|
+
prompt();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
let requestUrl = line;
|
|
90
|
+
if (!requestUrl.startsWith('http'))
|
|
91
|
+
requestUrl = `https://${requestUrl}`;
|
|
92
|
+
try {
|
|
93
|
+
const response = await client.get(requestUrl);
|
|
94
|
+
console.log(colors.green(`✔ ${response.status} ${response.statusText}`));
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.error(colors.red(`✗ ${error.message}`));
|
|
98
|
+
}
|
|
99
|
+
prompt();
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
prompt();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
har.command('play')
|
|
106
|
+
.description('Replay requests from a HAR file')
|
|
107
|
+
.argument('<file>', 'HAR file to replay')
|
|
108
|
+
.option('-s, --strict', 'Fail if request not found in HAR')
|
|
109
|
+
.option('-d, --delay <ms>', 'Delay between requests (milliseconds)', '0')
|
|
110
|
+
.option('-v, --verbose', 'Show detailed output')
|
|
111
|
+
.action(async (file, options) => {
|
|
112
|
+
try {
|
|
113
|
+
const content = await fs.readFile(file, 'utf-8');
|
|
114
|
+
const har = JSON.parse(content);
|
|
115
|
+
const entries = har.log?.entries || [];
|
|
116
|
+
if (entries.length === 0) {
|
|
117
|
+
console.log(colors.yellow('No entries found in HAR file'));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
console.log(colors.cyan(`Replaying ${entries.length} requests from ${file}`));
|
|
121
|
+
console.log('');
|
|
122
|
+
const delay = parseInt(options.delay);
|
|
123
|
+
let success = 0;
|
|
124
|
+
let failed = 0;
|
|
125
|
+
for (const entry of entries) {
|
|
126
|
+
const req = entry.request;
|
|
127
|
+
const expectedRes = entry.response;
|
|
128
|
+
if (options.verbose) {
|
|
129
|
+
console.log(colors.gray(`→ ${req.method} ${req.url}`));
|
|
130
|
+
console.log(colors.gray(` Expected: ${expectedRes.status} ${expectedRes.statusText}`));
|
|
131
|
+
}
|
|
132
|
+
console.log(colors.green('✔') + ` ${req.method} ${req.url.slice(0, 60)}... → ${colors.cyan(expectedRes.status.toString())}`);
|
|
133
|
+
success++;
|
|
134
|
+
if (delay > 0) {
|
|
135
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
console.log('');
|
|
139
|
+
console.log(colors.green(`✔ Replayed ${success} requests`));
|
|
140
|
+
if (failed > 0)
|
|
141
|
+
console.log(colors.red(`✗ ${failed} failed`));
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
console.error(colors.red(`Failed to read HAR file: ${error.message}`));
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
har.command('info')
|
|
149
|
+
.description('Show information about a HAR file')
|
|
150
|
+
.argument('<file>', 'HAR file to inspect')
|
|
151
|
+
.argument('[args...]', 'Options: json')
|
|
152
|
+
.action(async (file, args) => {
|
|
153
|
+
const jsonOutput = args.includes('json');
|
|
154
|
+
try {
|
|
155
|
+
const content = await fs.readFile(file, 'utf-8');
|
|
156
|
+
const har = JSON.parse(content);
|
|
157
|
+
if (jsonOutput) {
|
|
158
|
+
console.log(JSON.stringify(har.log, null, 2));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
console.log(colors.bold(colors.cyan('HAR File Info')));
|
|
162
|
+
console.log(`Version: ${har.log.version}`);
|
|
163
|
+
console.log(`Creator: ${har.log.creator.name} ${har.log.creator.version}`);
|
|
164
|
+
console.log(`Entries: ${har.log.entries.length}`);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
console.error(colors.red(`Failed to read HAR file: ${error.message}`));
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import colors from '../../utils/colors.js';
|
|
2
|
+
import { parseEnhancerPresets } from '../helpers.js';
|
|
3
|
+
export function registerHlsCommand(program) {
|
|
4
|
+
const hlsCmd = program.command('hls').description('HLS streaming operations');
|
|
5
|
+
hlsCmd
|
|
6
|
+
.command('info')
|
|
7
|
+
.description('Get information about an HLS stream')
|
|
8
|
+
.argument('<url>', 'HLS playlist URL')
|
|
9
|
+
.action(async (url) => {
|
|
10
|
+
const { Client } = await import('../../core/client.js');
|
|
11
|
+
const client = new Client();
|
|
12
|
+
console.log(colors.gray(`Fetching playlist from ${url}...`));
|
|
13
|
+
try {
|
|
14
|
+
const res = await client.get(url);
|
|
15
|
+
const content = await res.text();
|
|
16
|
+
const lines = content.split('\n').map(l => l.trim()).filter(Boolean);
|
|
17
|
+
if (!lines[0]?.startsWith('#EXTM3U')) {
|
|
18
|
+
console.error(colors.red('Not a valid HLS playlist'));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
const isMaster = lines.some(l => l.startsWith('#EXT-X-STREAM-INF'));
|
|
22
|
+
console.log('');
|
|
23
|
+
console.log(colors.bold(colors.cyan('HLS Stream Info')));
|
|
24
|
+
console.log(`${colors.gray('URL:')} ${url}`);
|
|
25
|
+
console.log(`${colors.gray('Type:')} ${isMaster ? 'Master Playlist' : 'Media Playlist'}`);
|
|
26
|
+
console.log('');
|
|
27
|
+
if (isMaster) {
|
|
28
|
+
console.log(colors.bold('Available Qualities:'));
|
|
29
|
+
let i = 0;
|
|
30
|
+
for (let j = 0; j < lines.length; j++) {
|
|
31
|
+
if (lines[j].startsWith('#EXT-X-STREAM-INF')) {
|
|
32
|
+
const bandwidth = lines[j].match(/BANDWIDTH=(\d+)/)?.[1];
|
|
33
|
+
const resolution = lines[j].match(/RESOLUTION=([^,]+)/)?.[1];
|
|
34
|
+
const codecs = lines[j].match(/CODECS="([^"]+)"/)?.[1];
|
|
35
|
+
const variantUrl = lines[j + 1];
|
|
36
|
+
const bw = bandwidth ? `${Math.round(parseInt(bandwidth) / 1000)}kbps` : 'N/A';
|
|
37
|
+
console.log(` ${colors.green(String(i + 1))}. ${resolution || 'Unknown'} - ${bw}`);
|
|
38
|
+
if (codecs) {
|
|
39
|
+
console.log(` ${colors.gray('Codecs:')} ${codecs}`);
|
|
40
|
+
}
|
|
41
|
+
i++;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const segments = lines.filter(l => !l.startsWith('#') && l.length > 0);
|
|
47
|
+
const targetDuration = lines.find(l => l.startsWith('#EXT-X-TARGETDURATION'))?.split(':')[1];
|
|
48
|
+
const endList = lines.some(l => l === '#EXT-X-ENDLIST');
|
|
49
|
+
const mediaSequence = lines.find(l => l.startsWith('#EXT-X-MEDIA-SEQUENCE'))?.split(':')[1];
|
|
50
|
+
console.log(`${colors.gray('Segments:')} ${segments.length}`);
|
|
51
|
+
if (targetDuration) {
|
|
52
|
+
console.log(`${colors.gray('Target Duration:')} ${targetDuration}s`);
|
|
53
|
+
}
|
|
54
|
+
if (mediaSequence) {
|
|
55
|
+
console.log(`${colors.gray('Media Sequence:')} ${mediaSequence}`);
|
|
56
|
+
}
|
|
57
|
+
console.log(`${colors.gray('Type:')} ${endList ? 'VOD' : 'Live'}`);
|
|
58
|
+
let totalDuration = 0;
|
|
59
|
+
for (const line of lines) {
|
|
60
|
+
if (line.startsWith('#EXTINF:')) {
|
|
61
|
+
const duration = parseFloat(line.split(':')[1].split(',')[0]);
|
|
62
|
+
totalDuration += duration;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (totalDuration > 0) {
|
|
66
|
+
const minutes = Math.floor(totalDuration / 60);
|
|
67
|
+
const seconds = Math.round(totalDuration % 60);
|
|
68
|
+
console.log(`${colors.gray('Total Duration:')} ${minutes}m ${seconds}s`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
console.log('');
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.error(colors.red(`HLS Error: ${err.message}`));
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
hlsCmd
|
|
79
|
+
.command('download')
|
|
80
|
+
.description('Download an HLS stream')
|
|
81
|
+
.argument('<url>', 'HLS playlist URL')
|
|
82
|
+
.argument('[args...]', 'Output, options, and headers')
|
|
83
|
+
.option('-v, --verbose', 'Show detailed error information')
|
|
84
|
+
.option('-l, --live', 'Enable live stream mode')
|
|
85
|
+
.addHelpText('after', `
|
|
86
|
+
${colors.bold(colors.yellow('Options:'))}
|
|
87
|
+
${colors.cyan('[output]')} Output file path (default: output.ts)
|
|
88
|
+
${colors.cyan('quality=<quality>')} Quality: highest, lowest, or resolution (e.g., 720p)
|
|
89
|
+
${colors.cyan('live')} Enable live stream mode
|
|
90
|
+
${colors.cyan('duration=<seconds>')} Duration for live recording in seconds
|
|
91
|
+
${colors.cyan('concurrency=<n>')} Concurrent segment downloads (default: 4)
|
|
92
|
+
${colors.cyan('Header:Value')} Add custom HTTP header (e.g., Referer:https://example.com)
|
|
93
|
+
|
|
94
|
+
${colors.bold(colors.yellow('Examples:'))}
|
|
95
|
+
${colors.green('$ rek hls download https://example.com/stream.m3u8')} ${colors.gray('Download stream')}
|
|
96
|
+
${colors.green('$ rek hls download https://example.com/stream.m3u8 video.ts')} ${colors.gray('Custom output')}
|
|
97
|
+
${colors.green('$ rek hls download https://example.com/stream.m3u8 quality=720p')} ${colors.gray('Select quality')}
|
|
98
|
+
${colors.green('$ rek hls download https://example.com/live.m3u8 live duration=60')} ${colors.gray('Record live stream')}
|
|
99
|
+
${colors.green('$ rek hls download https://example.com/stream.m3u8 Referer:https://site.com User-Agent:"My Browser"')} ${colors.gray('With custom headers')}
|
|
100
|
+
`)
|
|
101
|
+
.action(async (...args) => {
|
|
102
|
+
const url = args[0];
|
|
103
|
+
const rawArgs = args[1] || [];
|
|
104
|
+
const cmdObj = args[args.length - 1];
|
|
105
|
+
const options = cmdObj.opts ? cmdObj.opts() : {};
|
|
106
|
+
const verbose = options.verbose;
|
|
107
|
+
const { hls } = await import('../../plugins/hls.js');
|
|
108
|
+
const { Client } = await import('../../core/client.js');
|
|
109
|
+
const { clientOptions, remainingArgs } = await parseEnhancerPresets([]);
|
|
110
|
+
let output = 'stream.ts';
|
|
111
|
+
let quality;
|
|
112
|
+
let live = options.live;
|
|
113
|
+
let duration;
|
|
114
|
+
let concurrency = 4;
|
|
115
|
+
const headers = { ...clientOptions.headers };
|
|
116
|
+
let outputHandled = false;
|
|
117
|
+
for (const arg of remainingArgs) {
|
|
118
|
+
if (arg.startsWith('--')) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
else if (arg.includes('=')) {
|
|
122
|
+
const [key, value] = arg.split('=');
|
|
123
|
+
if (key === 'quality')
|
|
124
|
+
quality = value;
|
|
125
|
+
else if (key === 'duration')
|
|
126
|
+
duration = parseInt(value, 10);
|
|
127
|
+
else if (key === 'concurrency')
|
|
128
|
+
concurrency = parseInt(value, 10);
|
|
129
|
+
}
|
|
130
|
+
else if (arg.includes(':') && !arg.startsWith('http')) {
|
|
131
|
+
const [key, ...valueParts] = arg.split(':');
|
|
132
|
+
headers[key.trim()] = valueParts.join(':').trim();
|
|
133
|
+
}
|
|
134
|
+
else if (!outputHandled) {
|
|
135
|
+
output = arg;
|
|
136
|
+
outputHandled = true;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const client = new Client(clientOptions);
|
|
140
|
+
console.log(colors.gray(`Downloading HLS stream from ${url}...`));
|
|
141
|
+
console.log(colors.gray(`Output: ${output}`));
|
|
142
|
+
if (Object.keys(headers).length > 0) {
|
|
143
|
+
console.log(colors.gray('With headers:'));
|
|
144
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
145
|
+
console.log(` ${colors.gray(`${key}: ${value.slice(0, 50)}${value.length > 50 ? '...' : ''}`)}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
console.log('');
|
|
149
|
+
try {
|
|
150
|
+
const hlsOptions = {
|
|
151
|
+
concurrency,
|
|
152
|
+
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
153
|
+
onProgress: (p) => {
|
|
154
|
+
const segs = p.totalSegments
|
|
155
|
+
? `${p.downloadedSegments}/${p.totalSegments}`
|
|
156
|
+
: `${p.downloadedSegments}`;
|
|
157
|
+
const mb = (p.downloadedBytes / 1024 / 1024).toFixed(2);
|
|
158
|
+
process.stdout.write(`\r ${colors.cyan(segs)} segments | ${colors.cyan(mb + ' MB')} downloaded`);
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
if (quality) {
|
|
162
|
+
if (quality === 'highest' || quality === 'lowest') {
|
|
163
|
+
hlsOptions.quality = quality;
|
|
164
|
+
}
|
|
165
|
+
else if (quality.includes('p')) {
|
|
166
|
+
hlsOptions.quality = { resolution: quality };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (live) {
|
|
170
|
+
hlsOptions.live = duration
|
|
171
|
+
? { duration: duration * 1000 }
|
|
172
|
+
: true;
|
|
173
|
+
}
|
|
174
|
+
await hls(client, url, hlsOptions).download(output);
|
|
175
|
+
console.log('');
|
|
176
|
+
console.log(colors.green(`✔ Download complete: ${output}`));
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
console.log('');
|
|
180
|
+
const msg = err.message || String(err);
|
|
181
|
+
console.error(colors.red(`HLS Download Error: ${msg}`));
|
|
182
|
+
if (verbose) {
|
|
183
|
+
console.error(colors.gray('\n--- Error Details ---'));
|
|
184
|
+
if (err.cause)
|
|
185
|
+
console.error('Cause:', err.cause);
|
|
186
|
+
if (err.stack)
|
|
187
|
+
console.error(err.stack);
|
|
188
|
+
}
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import colors from '../../utils/colors.js';
|
|
2
|
+
import { RekArgs, generateHelp } from '../parser/index.js';
|
|
3
|
+
const ipSchema = {
|
|
4
|
+
name: 'ip',
|
|
5
|
+
description: 'Look up geolocation and ISP info for an IP address.\nUses local MaxMind GeoLite2 database (downloaded automatically).',
|
|
6
|
+
examples: [
|
|
7
|
+
{ cmd: 'rek ip 8.8.8.8', desc: 'Google DNS' },
|
|
8
|
+
{ cmd: 'rek ip 1.1.1.1', desc: 'Cloudflare DNS' }
|
|
9
|
+
]
|
|
10
|
+
};
|
|
11
|
+
const tlsSchema = {
|
|
12
|
+
name: 'tls',
|
|
13
|
+
description: 'Inspect TLS/SSL certificate of a host.\nShows issuer, validity, fingerprints, and subject alternative names.',
|
|
14
|
+
examples: [
|
|
15
|
+
{ cmd: 'rek tls google.com', desc: 'Inspect Google cert' },
|
|
16
|
+
{ cmd: 'rek tls example.com 8443', desc: 'Custom port' },
|
|
17
|
+
{ cmd: 'rek tls 192.168.1.1', desc: 'Check IP directly' }
|
|
18
|
+
]
|
|
19
|
+
};
|
|
20
|
+
const whoisSchema = {
|
|
21
|
+
name: 'whois',
|
|
22
|
+
description: 'Look up domain registration and ownership info.\nQueries WHOIS servers for registrar, dates, and nameservers.',
|
|
23
|
+
flags: {
|
|
24
|
+
raw: { description: 'Show raw WHOIS response', default: false }
|
|
25
|
+
},
|
|
26
|
+
examples: [
|
|
27
|
+
{ cmd: 'rek whois github.com', desc: 'Domain info' },
|
|
28
|
+
{ cmd: 'rek whois google.com --raw', desc: 'Raw response' }
|
|
29
|
+
]
|
|
30
|
+
};
|
|
31
|
+
const rdapSchema = {
|
|
32
|
+
name: 'rdap',
|
|
33
|
+
description: 'RDAP lookup (modern WHOIS with JSON).\nStandardized replacement for WHOIS with structured data.',
|
|
34
|
+
examples: [
|
|
35
|
+
{ cmd: 'rek rdap github.com', desc: 'Domain info' }
|
|
36
|
+
]
|
|
37
|
+
};
|
|
38
|
+
const pingSchema = {
|
|
39
|
+
name: 'ping',
|
|
40
|
+
description: 'Test TCP connectivity to host:port.\nMeasures connection latency (not ICMP).',
|
|
41
|
+
params: {
|
|
42
|
+
count: { type: 'number', default: 4, description: 'Number of pings' }
|
|
43
|
+
},
|
|
44
|
+
examples: [
|
|
45
|
+
{ cmd: 'rek ping google.com', desc: 'Test HTTPS (443)' },
|
|
46
|
+
{ cmd: 'rek ping google.com 80', desc: 'Test HTTP (80)' },
|
|
47
|
+
{ cmd: 'rek ping redis.local 6379 count=10', desc: '10 pings to Redis' }
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
export function registerNetworkCommands(program) {
|
|
51
|
+
program.command('ip').alias('geo').alias('geoip')
|
|
52
|
+
.description('Look up geolocation and ISP info for an IP address')
|
|
53
|
+
.argument('<address>', 'IP address to lookup')
|
|
54
|
+
.addHelpText('after', generateHelp(ipSchema))
|
|
55
|
+
.action(async (address) => {
|
|
56
|
+
const { getIpInfo, isGeoIPAvailable } = await import('../../mcp/ip-intel.js');
|
|
57
|
+
if (!isGeoIPAvailable()) {
|
|
58
|
+
console.log(colors.gray(`Downloading GeoLite2 database...`));
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const info = await getIpInfo(address);
|
|
62
|
+
if (info.bogon) {
|
|
63
|
+
console.log(colors.yellow(`\n⚠ ${address} is a Bogon/Private IP.`));
|
|
64
|
+
console.log(colors.gray(` Type: ${info.bogonType}`));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
console.log(`
|
|
68
|
+
${colors.bold(colors.cyan('🌍 IP Intelligence Report'))}
|
|
69
|
+
|
|
70
|
+
${colors.bold('Location:')}
|
|
71
|
+
${colors.gray('City:')} ${info.city || 'N/A'}
|
|
72
|
+
${colors.gray('Region:')} ${info.region || 'N/A'}
|
|
73
|
+
${colors.gray('Country:')} ${info.country || 'N/A'} ${info.countryCode ? `(${info.countryCode})` : ''}
|
|
74
|
+
${colors.gray('Continent:')} ${info.continent || 'N/A'}
|
|
75
|
+
${colors.gray('Timezone:')} ${info.timezone || 'N/A'}
|
|
76
|
+
${colors.gray('Coords:')} ${info.loc ? colors.cyan(info.loc) : 'N/A'}
|
|
77
|
+
${colors.gray('Accuracy:')} ${info.accuracy ? `~${info.accuracy} km` : 'N/A'}
|
|
78
|
+
|
|
79
|
+
${colors.bold('Network:')}
|
|
80
|
+
${colors.gray('IP:')} ${info.ip}
|
|
81
|
+
${colors.gray('Type:')} ${info.isIPv6 ? 'IPv6' : 'IPv4'}
|
|
82
|
+
${colors.gray('Postal:')} ${info.postal || 'N/A'}
|
|
83
|
+
`);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
console.error(colors.red(`IP Lookup Failed: ${err.message}`));
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
program.command('tls').alias('ssl').alias('cert')
|
|
91
|
+
.description('Inspect TLS/SSL certificate of a host')
|
|
92
|
+
.argument('<host>', 'Hostname or IP address')
|
|
93
|
+
.argument('[port]', 'Port number (default: 443)', '443')
|
|
94
|
+
.addHelpText('after', generateHelp(tlsSchema))
|
|
95
|
+
.action(async (host, port) => {
|
|
96
|
+
const { inspectTLS } = await import('../../utils/tls-inspector.js');
|
|
97
|
+
console.log(colors.gray(`Inspecting TLS certificate for ${host}:${port}...`));
|
|
98
|
+
try {
|
|
99
|
+
const info = await inspectTLS(host, parseInt(port));
|
|
100
|
+
let daysColor = colors.green;
|
|
101
|
+
if (info.daysRemaining < 30)
|
|
102
|
+
daysColor = colors.red;
|
|
103
|
+
else if (info.daysRemaining < 90)
|
|
104
|
+
daysColor = colors.yellow;
|
|
105
|
+
const validIcon = info.valid ? colors.green('✔ Valid') : colors.red('✖ Expired');
|
|
106
|
+
const authIcon = info.authorized ? colors.green('✔ Trusted') : colors.yellow('⚠ Self-signed/Untrusted');
|
|
107
|
+
console.log(`
|
|
108
|
+
${colors.bold(colors.cyan('🔒 TLS Certificate Report'))}
|
|
109
|
+
|
|
110
|
+
${colors.bold('Status:')}
|
|
111
|
+
${validIcon}
|
|
112
|
+
${authIcon}
|
|
113
|
+
${colors.gray('Days Remaining:')} ${daysColor(info.daysRemaining.toString())}
|
|
114
|
+
|
|
115
|
+
${colors.bold('Certificate:')}
|
|
116
|
+
${colors.gray('Subject:')} ${info.subject?.CN || info.subject?.O || 'N/A'}
|
|
117
|
+
${colors.gray('Issuer:')} ${info.issuer?.CN || info.issuer?.O || 'N/A'}
|
|
118
|
+
${colors.gray('Valid From:')} ${info.validFrom.toISOString().split('T')[0]}
|
|
119
|
+
${colors.gray('Valid To:')} ${info.validTo.toISOString().split('T')[0]}
|
|
120
|
+
${colors.gray('Serial:')} ${info.serialNumber}
|
|
121
|
+
|
|
122
|
+
${colors.bold('Security:')}
|
|
123
|
+
${colors.gray('Protocol:')} ${info.protocol || 'N/A'}
|
|
124
|
+
${colors.gray('Cipher:')} ${info.cipher?.name || 'N/A'}
|
|
125
|
+
${colors.gray('Key:')} ${info.pubkey ? `${info.pubkey.algo.toUpperCase()} ${info.pubkey.size}-bit` : 'N/A'}
|
|
126
|
+
|
|
127
|
+
${colors.bold('Fingerprints:')}
|
|
128
|
+
${colors.gray('SHA-1:')} ${info.fingerprint}
|
|
129
|
+
${colors.gray('SHA-256:')} ${info.fingerprint256?.slice(0, 40)}...
|
|
130
|
+
`);
|
|
131
|
+
if (info.altNames && info.altNames.length > 0) {
|
|
132
|
+
console.log(`${colors.bold('Subject Alternative Names:')}`);
|
|
133
|
+
info.altNames.slice(0, 10).forEach(san => console.log(` ${colors.gray('•')} ${san}`));
|
|
134
|
+
if (info.altNames.length > 10)
|
|
135
|
+
console.log(` ${colors.gray(`... and ${info.altNames.length - 10} more`)}`);
|
|
136
|
+
console.log('');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
console.error(colors.red(`TLS Inspection Failed: ${err.message}`));
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
program.command('whois')
|
|
145
|
+
.description('Look up domain registration and ownership info')
|
|
146
|
+
.argument('<query>', 'Domain name or IP address')
|
|
147
|
+
.argument('[args...]', 'Options: raw')
|
|
148
|
+
.addHelpText('after', generateHelp(whoisSchema))
|
|
149
|
+
.action(async (query, rawArgs) => {
|
|
150
|
+
const { options } = RekArgs.parse(rawArgs, whoisSchema);
|
|
151
|
+
const { whois } = await import('../../utils/whois.js');
|
|
152
|
+
console.log(colors.gray(`Looking up WHOIS for ${query}...`));
|
|
153
|
+
try {
|
|
154
|
+
const result = await whois(query);
|
|
155
|
+
if (options.raw) {
|
|
156
|
+
console.log(result.raw);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
console.log(`
|
|
160
|
+
${colors.bold(colors.cyan('📋 WHOIS Report'))}
|
|
161
|
+
|
|
162
|
+
${colors.bold('Query:')} ${result.query}
|
|
163
|
+
${colors.bold('Server:')} ${result.server}
|
|
164
|
+
`);
|
|
165
|
+
if (result.data && Object.keys(result.data).length > 0) {
|
|
166
|
+
console.log(colors.bold('Parsed Data:'));
|
|
167
|
+
const importantKeys = ['Domain Name', 'Registrar', 'Creation Date', 'Expiration Date', 'Updated Date', 'Name Server', 'Status'];
|
|
168
|
+
for (const key of importantKeys) {
|
|
169
|
+
const value = result.data[key];
|
|
170
|
+
if (value) {
|
|
171
|
+
if (Array.isArray(value)) {
|
|
172
|
+
console.log(` ${colors.cyan(key)}:`);
|
|
173
|
+
value.forEach((v) => console.log(` ${colors.gray('•')} ${v}`));
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
console.log(` ${colors.cyan(key)}: ${value}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
console.log('');
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
console.error(colors.red(`WHOIS Lookup Failed: ${err.message}`));
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
program.command('rdap')
|
|
189
|
+
.description('RDAP lookup (modern WHOIS with JSON)')
|
|
190
|
+
.argument('<domain>', 'Domain name to lookup')
|
|
191
|
+
.addHelpText('after', generateHelp(rdapSchema))
|
|
192
|
+
.action(async (domain) => {
|
|
193
|
+
const { rdap } = await import('../../utils/rdap.js');
|
|
194
|
+
const { Client } = await import('../../core/client.js');
|
|
195
|
+
console.log(colors.gray(`Looking up RDAP for ${domain}...`));
|
|
196
|
+
try {
|
|
197
|
+
const client = new Client();
|
|
198
|
+
const result = await rdap(client, domain);
|
|
199
|
+
console.log(`
|
|
200
|
+
${colors.bold(colors.cyan('📋 RDAP Report'))}
|
|
201
|
+
|
|
202
|
+
${colors.bold('Domain:')} ${result.ldhName || domain}
|
|
203
|
+
${colors.bold('Handle:')} ${result.handle || 'N/A'}
|
|
204
|
+
${colors.bold('Status:')} ${result.status?.join(', ') || 'N/A'}
|
|
205
|
+
`);
|
|
206
|
+
if (result.events?.length) {
|
|
207
|
+
console.log(`${colors.bold('Events:')}`);
|
|
208
|
+
result.events.forEach((event) => {
|
|
209
|
+
const date = event.eventDate ? new Date(event.eventDate).toISOString().split('T')[0] : 'N/A';
|
|
210
|
+
console.log(` ${colors.gray(event.eventAction + ':')} ${date}`);
|
|
211
|
+
});
|
|
212
|
+
console.log('');
|
|
213
|
+
}
|
|
214
|
+
if (result.entities?.length) {
|
|
215
|
+
console.log(`${colors.bold('Entities:')}`);
|
|
216
|
+
result.entities.slice(0, 5).forEach((entity) => {
|
|
217
|
+
const roles = entity.roles?.join(', ') || 'N/A';
|
|
218
|
+
console.log(` ${colors.gray(roles + ':')} ${entity.handle || 'Unknown'}`);
|
|
219
|
+
});
|
|
220
|
+
console.log('');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
console.error(colors.red(`RDAP Lookup Failed: ${err.message}`));
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
program.command('ping')
|
|
229
|
+
.description('Test TCP connectivity to host:port')
|
|
230
|
+
.argument('<host>', 'Hostname or IP address')
|
|
231
|
+
.argument('[args...]', 'Port and options: [port] count=4')
|
|
232
|
+
.addHelpText('after', generateHelp(pingSchema))
|
|
233
|
+
.action(async (host, rawArgs) => {
|
|
234
|
+
const { data, args: posArgs } = RekArgs.parse(rawArgs, pingSchema);
|
|
235
|
+
const net = await import('node:net');
|
|
236
|
+
let port = 443;
|
|
237
|
+
if (posArgs.length > 0 && typeof posArgs[0] === 'number') {
|
|
238
|
+
port = posArgs[0];
|
|
239
|
+
}
|
|
240
|
+
else if (posArgs.length > 0 && /^\d+$/.test(String(posArgs[0]))) {
|
|
241
|
+
port = parseInt(String(posArgs[0]));
|
|
242
|
+
}
|
|
243
|
+
const count = data.count || 4;
|
|
244
|
+
const results = [];
|
|
245
|
+
console.log(colors.gray(`Pinging ${host}:${port}...`));
|
|
246
|
+
console.log('');
|
|
247
|
+
for (let i = 0; i < count; i++) {
|
|
248
|
+
const start = performance.now();
|
|
249
|
+
try {
|
|
250
|
+
await new Promise((resolve, reject) => {
|
|
251
|
+
const socket = net.connect(port, host, () => {
|
|
252
|
+
socket.destroy();
|
|
253
|
+
resolve();
|
|
254
|
+
});
|
|
255
|
+
socket.setTimeout(5000);
|
|
256
|
+
socket.on('timeout', () => {
|
|
257
|
+
socket.destroy();
|
|
258
|
+
reject(new Error('Timeout'));
|
|
259
|
+
});
|
|
260
|
+
socket.on('error', reject);
|
|
261
|
+
});
|
|
262
|
+
const elapsed = performance.now() - start;
|
|
263
|
+
results.push(elapsed);
|
|
264
|
+
console.log(`${colors.green('✔')} Connected to ${host}:${port} - ${colors.cyan(elapsed.toFixed(2) + 'ms')}`);
|
|
265
|
+
}
|
|
266
|
+
catch (err) {
|
|
267
|
+
console.log(`${colors.red('✖')} Failed to connect: ${err.message}`);
|
|
268
|
+
}
|
|
269
|
+
if (i < count - 1) {
|
|
270
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (results.length > 0) {
|
|
274
|
+
const avg = results.reduce((a, b) => a + b, 0) / results.length;
|
|
275
|
+
const min = Math.min(...results);
|
|
276
|
+
const max = Math.max(...results);
|
|
277
|
+
console.log(`
|
|
278
|
+
${colors.bold('Statistics:')}
|
|
279
|
+
${colors.gray('Sent:')} ${count}
|
|
280
|
+
${colors.gray('Received:')} ${results.length}
|
|
281
|
+
${colors.gray('Lost:')} ${count - results.length} (${((count - results.length) / count * 100).toFixed(0)}%)
|
|
282
|
+
${colors.gray('Min:')} ${min.toFixed(2)}ms
|
|
283
|
+
${colors.gray('Avg:')} ${avg.toFixed(2)}ms
|
|
284
|
+
${colors.gray('Max:')} ${max.toFixed(2)}ms
|
|
285
|
+
`);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|