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
package/dist/seo/rules/pwa.js
CHANGED
|
@@ -7,8 +7,6 @@ export const pwaRules = [
|
|
|
7
7
|
severity: 'info',
|
|
8
8
|
description: 'Pages should link to a web app manifest for PWA support',
|
|
9
9
|
check: (ctx) => {
|
|
10
|
-
if (ctx.hasManifest === undefined)
|
|
11
|
-
return null;
|
|
12
10
|
if (!ctx.hasManifest) {
|
|
13
11
|
return createResult({ id: 'pwa-manifest-link', name: 'Web App Manifest', category: 'technical', severity: 'info' }, 'info', 'No web app manifest linked', {
|
|
14
12
|
recommendation: 'Add a manifest.json for PWA installability',
|
|
@@ -29,8 +27,6 @@ export const pwaRules = [
|
|
|
29
27
|
severity: 'info',
|
|
30
28
|
description: 'Pages should define a theme color for browser UI',
|
|
31
29
|
check: (ctx) => {
|
|
32
|
-
if (ctx.themeColor === undefined)
|
|
33
|
-
return null;
|
|
34
30
|
if (!ctx.themeColor) {
|
|
35
31
|
return createResult({ id: 'pwa-theme-color', name: 'Theme Color', category: 'mobile', severity: 'info' }, 'info', 'No theme-color meta tag', {
|
|
36
32
|
recommendation: 'Add theme-color for browser UI customization',
|
|
@@ -50,8 +46,6 @@ export const pwaRules = [
|
|
|
50
46
|
severity: 'info',
|
|
51
47
|
description: 'iOS devices need apple-touch-icon for home screen',
|
|
52
48
|
check: (ctx) => {
|
|
53
|
-
if (ctx.hasAppleTouchIcon === undefined)
|
|
54
|
-
return null;
|
|
55
49
|
if (!ctx.hasAppleTouchIcon) {
|
|
56
50
|
return createResult({ id: 'pwa-apple-touch-icon', name: 'Apple Touch Icon', category: 'mobile', severity: 'info' }, 'info', 'No apple-touch-icon found', {
|
|
57
51
|
recommendation: 'Add apple-touch-icon for iOS home screen',
|
|
@@ -72,8 +66,6 @@ export const pwaRules = [
|
|
|
72
66
|
severity: 'info',
|
|
73
67
|
description: 'Enable standalone mode on iOS devices',
|
|
74
68
|
check: (ctx) => {
|
|
75
|
-
if (ctx.hasAppleMobileWebAppCapable === undefined)
|
|
76
|
-
return null;
|
|
77
69
|
if (!ctx.hasAppleMobileWebAppCapable) {
|
|
78
70
|
return createResult({ id: 'pwa-apple-mobile-capable', name: 'Apple Mobile Web App', category: 'mobile', severity: 'info' }, 'info', 'No apple-mobile-web-app-capable meta tag', {
|
|
79
71
|
recommendation: 'Add for full-screen iOS experience',
|
|
@@ -93,10 +85,11 @@ export const pwaRules = [
|
|
|
93
85
|
severity: 'info',
|
|
94
86
|
description: 'Configure iOS status bar appearance',
|
|
95
87
|
check: (ctx) => {
|
|
96
|
-
if (!ctx.hasAppleMobileWebAppCapable)
|
|
97
|
-
return
|
|
98
|
-
|
|
99
|
-
|
|
88
|
+
if (!ctx.hasAppleMobileWebAppCapable) {
|
|
89
|
+
return createResult({ id: 'pwa-apple-status-bar', name: 'Apple Status Bar Style', category: 'mobile', severity: 'info' }, 'info', 'Not applicable (apple-mobile-web-app-capable not set)', {
|
|
90
|
+
recommendation: 'First enable apple-mobile-web-app-capable, then configure status bar',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
100
93
|
if (!ctx.appleStatusBarStyle) {
|
|
101
94
|
return createResult({ id: 'pwa-apple-status-bar', name: 'Apple Status Bar Style', category: 'mobile', severity: 'info' }, 'info', 'No apple-mobile-web-app-status-bar-style defined', {
|
|
102
95
|
recommendation: 'Define status bar style for iOS',
|
|
@@ -116,8 +109,6 @@ export const pwaRules = [
|
|
|
116
109
|
severity: 'info',
|
|
117
110
|
description: 'Manifest should include maskable icons for Android',
|
|
118
111
|
check: (ctx) => {
|
|
119
|
-
if (ctx.hasMaskableIcon === undefined)
|
|
120
|
-
return null;
|
|
121
112
|
if (!ctx.hasMaskableIcon) {
|
|
122
113
|
return createResult({ id: 'pwa-maskable-icon', name: 'Maskable Icon', category: 'mobile', severity: 'info' }, 'info', 'No maskable icon in manifest', {
|
|
123
114
|
recommendation: 'Add maskable icon for adaptive icons on Android',
|
|
@@ -145,10 +136,11 @@ export const pwaRules = [
|
|
|
145
136
|
severity: 'info',
|
|
146
137
|
description: 'Manifest should define a start_url',
|
|
147
138
|
check: (ctx) => {
|
|
148
|
-
if (!ctx.hasManifest)
|
|
149
|
-
return
|
|
150
|
-
|
|
151
|
-
|
|
139
|
+
if (!ctx.hasManifest) {
|
|
140
|
+
return createResult({ id: 'pwa-start-url', name: 'Start URL', category: 'technical', severity: 'info' }, 'info', 'Not applicable (no manifest)', {
|
|
141
|
+
recommendation: 'First add a web app manifest, then define start_url',
|
|
142
|
+
});
|
|
143
|
+
}
|
|
152
144
|
if (!ctx.manifestStartUrl) {
|
|
153
145
|
return createResult({ id: 'pwa-start-url', name: 'Start URL', category: 'technical', severity: 'info' }, 'info', 'Manifest missing start_url', {
|
|
154
146
|
recommendation: 'Define start_url in manifest for PWA launch',
|
|
@@ -168,10 +160,11 @@ export const pwaRules = [
|
|
|
168
160
|
severity: 'info',
|
|
169
161
|
description: 'Manifest should define display mode',
|
|
170
162
|
check: (ctx) => {
|
|
171
|
-
if (!ctx.hasManifest)
|
|
172
|
-
return
|
|
173
|
-
|
|
174
|
-
|
|
163
|
+
if (!ctx.hasManifest) {
|
|
164
|
+
return createResult({ id: 'pwa-display-mode', name: 'Display Mode', category: 'technical', severity: 'info' }, 'info', 'Not applicable (no manifest)', {
|
|
165
|
+
recommendation: 'First add a web app manifest, then define display mode',
|
|
166
|
+
});
|
|
167
|
+
}
|
|
175
168
|
const display = ctx.manifestDisplay;
|
|
176
169
|
if (!display) {
|
|
177
170
|
return createResult({ id: 'pwa-display-mode', name: 'Display Mode', category: 'technical', severity: 'info' }, 'info', 'Manifest missing display mode', {
|
|
@@ -198,10 +191,11 @@ export const pwaRules = [
|
|
|
198
191
|
severity: 'info',
|
|
199
192
|
description: 'Manifest should define navigation scope',
|
|
200
193
|
check: (ctx) => {
|
|
201
|
-
if (!ctx.hasManifest)
|
|
202
|
-
return
|
|
203
|
-
|
|
204
|
-
|
|
194
|
+
if (!ctx.hasManifest) {
|
|
195
|
+
return createResult({ id: 'pwa-scope', name: 'Navigation Scope', category: 'technical', severity: 'info' }, 'info', 'Not applicable (no manifest)', {
|
|
196
|
+
recommendation: 'First add a web app manifest, then define scope',
|
|
197
|
+
});
|
|
198
|
+
}
|
|
205
199
|
if (!ctx.manifestScope) {
|
|
206
200
|
return createResult({ id: 'pwa-scope', name: 'Navigation Scope', category: 'technical', severity: 'info' }, 'info', 'Manifest missing scope', {
|
|
207
201
|
recommendation: 'Define scope to control PWA navigation boundaries',
|
|
@@ -221,11 +215,12 @@ export const pwaRules = [
|
|
|
221
215
|
severity: 'info',
|
|
222
216
|
description: 'Manifest should include multiple icon sizes',
|
|
223
217
|
check: (ctx) => {
|
|
224
|
-
if (!ctx.hasManifest)
|
|
225
|
-
return
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
218
|
+
if (!ctx.hasManifest) {
|
|
219
|
+
return createResult({ id: 'pwa-icons-sizes', name: 'Icon Sizes', category: 'mobile', severity: 'info' }, 'info', 'Not applicable (no manifest)', {
|
|
220
|
+
recommendation: 'First add a web app manifest with icons',
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
const sizes = ctx.manifestIconSizes || [];
|
|
229
224
|
const requiredSizes = [192, 512];
|
|
230
225
|
const missingSizes = requiredSizes.filter(s => !sizes.includes(s));
|
|
231
226
|
if (missingSizes.length > 0) {
|
|
@@ -248,10 +243,11 @@ export const pwaRules = [
|
|
|
248
243
|
severity: 'info',
|
|
249
244
|
description: 'Manifest should have a short_name for home screen',
|
|
250
245
|
check: (ctx) => {
|
|
251
|
-
if (!ctx.hasManifest)
|
|
252
|
-
return
|
|
253
|
-
|
|
254
|
-
|
|
246
|
+
if (!ctx.hasManifest) {
|
|
247
|
+
return createResult({ id: 'pwa-short-name', name: 'Short Name', category: 'technical', severity: 'info' }, 'info', 'Not applicable (no manifest)', {
|
|
248
|
+
recommendation: 'First add a web app manifest with name/short_name',
|
|
249
|
+
});
|
|
250
|
+
}
|
|
255
251
|
const shortName = ctx.manifestShortName;
|
|
256
252
|
const name = ctx.manifestName;
|
|
257
253
|
if (!shortName && !name) {
|
|
@@ -283,10 +279,11 @@ export const pwaRules = [
|
|
|
283
279
|
severity: 'info',
|
|
284
280
|
description: 'Manifest should define background_color for splash screen',
|
|
285
281
|
check: (ctx) => {
|
|
286
|
-
if (!ctx.hasManifest)
|
|
287
|
-
return
|
|
288
|
-
|
|
289
|
-
|
|
282
|
+
if (!ctx.hasManifest) {
|
|
283
|
+
return createResult({ id: 'pwa-background-color', name: 'Background Color', category: 'mobile', severity: 'info' }, 'info', 'Not applicable (no manifest)', {
|
|
284
|
+
recommendation: 'First add a web app manifest, then define background_color',
|
|
285
|
+
});
|
|
286
|
+
}
|
|
290
287
|
if (!ctx.manifestBackgroundColor) {
|
|
291
288
|
return createResult({ id: 'pwa-background-color', name: 'Background Color', category: 'mobile', severity: 'info' }, 'info', 'Manifest missing background_color', {
|
|
292
289
|
recommendation: 'Define background_color for splash screen',
|
|
@@ -7,8 +7,9 @@ export const readabilityRules = [
|
|
|
7
7
|
severity: 'info',
|
|
8
8
|
description: 'Content should be easy to read for the target audience',
|
|
9
9
|
check: (ctx) => {
|
|
10
|
-
if (ctx.fleschReadingEase === undefined)
|
|
11
|
-
return
|
|
10
|
+
if (ctx.fleschReadingEase === undefined) {
|
|
11
|
+
return createResult({ id: 'readability-flesch-score', name: 'Flesch Reading Ease', category: 'content', severity: 'info' }, 'info', 'Not applicable (Flesch Reading Ease data unavailable)', { recommendation: 'This rule analyzes content readability using the Flesch Reading Ease formula' });
|
|
12
|
+
}
|
|
12
13
|
const score = ctx.fleschReadingEase;
|
|
13
14
|
let level;
|
|
14
15
|
let status;
|
|
@@ -49,8 +50,9 @@ export const readabilityRules = [
|
|
|
49
50
|
severity: 'info',
|
|
50
51
|
description: 'Sentences should be concise for better readability',
|
|
51
52
|
check: (ctx) => {
|
|
52
|
-
if (ctx.avgSentenceLength === undefined)
|
|
53
|
-
return
|
|
53
|
+
if (ctx.avgSentenceLength === undefined) {
|
|
54
|
+
return createResult({ id: 'readability-sentence-length', name: 'Sentence Length', category: 'content', severity: 'info' }, 'info', 'Not applicable (sentence length data unavailable)', { recommendation: 'This rule checks average sentence length for optimal readability' });
|
|
55
|
+
}
|
|
54
56
|
const avgLength = ctx.avgSentenceLength;
|
|
55
57
|
if (avgLength > 30) {
|
|
56
58
|
return createResult({ id: 'readability-sentence-length', name: 'Sentence Length', category: 'content', severity: 'info' }, 'warn', `Average sentence length: ${Math.round(avgLength)} words (too long)`, {
|
|
@@ -81,8 +83,9 @@ export const readabilityRules = [
|
|
|
81
83
|
severity: 'info',
|
|
82
84
|
description: 'Paragraphs should be short for web readability',
|
|
83
85
|
check: (ctx) => {
|
|
84
|
-
if (ctx.avgParagraphLength === undefined)
|
|
85
|
-
return
|
|
86
|
+
if (ctx.avgParagraphLength === undefined) {
|
|
87
|
+
return createResult({ id: 'readability-paragraph-length', name: 'Paragraph Length', category: 'content', severity: 'info' }, 'info', 'Not applicable (paragraph length data unavailable)', { recommendation: 'This rule checks average paragraph length for web readability' });
|
|
88
|
+
}
|
|
86
89
|
const avgLength = ctx.avgParagraphLength;
|
|
87
90
|
if (avgLength > 150) {
|
|
88
91
|
return createResult({ id: 'readability-paragraph-length', name: 'Paragraph Length', category: 'content', severity: 'info' }, 'warn', `Average paragraph length: ${Math.round(avgLength)} words (too long)`, {
|
|
@@ -109,8 +112,9 @@ export const readabilityRules = [
|
|
|
109
112
|
severity: 'info',
|
|
110
113
|
description: 'Limit passive voice for clearer writing',
|
|
111
114
|
check: (ctx) => {
|
|
112
|
-
if (ctx.passiveVoicePercentage === undefined)
|
|
113
|
-
return
|
|
115
|
+
if (ctx.passiveVoicePercentage === undefined) {
|
|
116
|
+
return createResult({ id: 'readability-passive-voice', name: 'Passive Voice', category: 'content', severity: 'info' }, 'info', 'Not applicable (passive voice data unavailable)', { recommendation: 'This rule checks passive voice usage for clearer writing' });
|
|
117
|
+
}
|
|
114
118
|
const percentage = ctx.passiveVoicePercentage;
|
|
115
119
|
if (percentage > 20) {
|
|
116
120
|
return createResult({ id: 'readability-passive-voice', name: 'Passive Voice', category: 'content', severity: 'info' }, 'warn', `Passive voice: ${Math.round(percentage)}% of sentences`, {
|
|
@@ -127,7 +131,7 @@ export const readabilityRules = [
|
|
|
127
131
|
recommendation: 'Consider reducing passive voice usage',
|
|
128
132
|
});
|
|
129
133
|
}
|
|
130
|
-
return
|
|
134
|
+
return createResult({ id: 'readability-passive-voice', name: 'Passive Voice', category: 'content', severity: 'info' }, 'pass', `Passive voice usage acceptable (${Math.round(percentage)}%)`);
|
|
131
135
|
},
|
|
132
136
|
},
|
|
133
137
|
{
|
|
@@ -137,8 +141,9 @@ export const readabilityRules = [
|
|
|
137
141
|
severity: 'info',
|
|
138
142
|
description: 'Use transition words for better flow',
|
|
139
143
|
check: (ctx) => {
|
|
140
|
-
if (ctx.transitionWordPercentage === undefined)
|
|
141
|
-
return
|
|
144
|
+
if (ctx.transitionWordPercentage === undefined) {
|
|
145
|
+
return createResult({ id: 'readability-transition-words', name: 'Transition Words', category: 'content', severity: 'info' }, 'info', 'Not applicable (transition word data unavailable)', { recommendation: 'This rule checks for transition words that improve content flow' });
|
|
146
|
+
}
|
|
142
147
|
const percentage = ctx.transitionWordPercentage;
|
|
143
148
|
if (percentage < 20) {
|
|
144
149
|
return createResult({ id: 'readability-transition-words', name: 'Transition Words', category: 'content', severity: 'info' }, 'info', `Transition words: ${Math.round(percentage)}% of sentences`, {
|
|
@@ -161,8 +166,9 @@ export const readabilityRules = [
|
|
|
161
166
|
severity: 'info',
|
|
162
167
|
description: 'Break content with subheadings every 300 words',
|
|
163
168
|
check: (ctx) => {
|
|
164
|
-
if (!ctx.wordCount || !ctx.h2Count)
|
|
165
|
-
return
|
|
169
|
+
if (!ctx.wordCount || !ctx.h2Count) {
|
|
170
|
+
return createResult({ id: 'readability-subheading-distribution', name: 'Subheading Distribution', category: 'content', severity: 'info' }, 'info', 'Not applicable (word count or heading data unavailable)', { recommendation: 'This rule checks for proper subheading distribution to break up content' });
|
|
171
|
+
}
|
|
166
172
|
const wordsPerSubheading = ctx.wordCount / (ctx.h2Count + 1);
|
|
167
173
|
if (ctx.wordCount > 500 && wordsPerSubheading > 400) {
|
|
168
174
|
return createResult({ id: 'readability-subheading-distribution', name: 'Subheading Distribution', category: 'content', severity: 'info' }, 'warn', `${Math.round(wordsPerSubheading)} words between subheadings (too many)`, {
|
|
@@ -189,8 +195,9 @@ export const readabilityRules = [
|
|
|
189
195
|
severity: 'info',
|
|
190
196
|
description: 'Use varied sentence structures and word choices',
|
|
191
197
|
check: (ctx) => {
|
|
192
|
-
if (ctx.consecutiveSentenceStarts === undefined)
|
|
193
|
-
return
|
|
198
|
+
if (ctx.consecutiveSentenceStarts === undefined) {
|
|
199
|
+
return createResult({ id: 'readability-text-variety', name: 'Text Variety', category: 'content', severity: 'info' }, 'info', 'Not applicable (sentence variety data unavailable)', { recommendation: 'This rule checks for varied sentence structures and beginnings' });
|
|
200
|
+
}
|
|
194
201
|
if (ctx.consecutiveSentenceStarts > 3) {
|
|
195
202
|
return createResult({ id: 'readability-text-variety', name: 'Text Variety', category: 'content', severity: 'info' }, 'info', `${ctx.consecutiveSentenceStarts} consecutive sentences start similarly`, {
|
|
196
203
|
recommendation: 'Vary sentence beginnings for better flow',
|
|
@@ -199,7 +206,7 @@ export const readabilityRules = [
|
|
|
199
206
|
},
|
|
200
207
|
});
|
|
201
208
|
}
|
|
202
|
-
return
|
|
209
|
+
return createResult({ id: 'readability-text-variety', name: 'Text Variety', category: 'content', severity: 'info' }, 'pass', 'Good sentence variety');
|
|
203
210
|
},
|
|
204
211
|
},
|
|
205
212
|
{
|
|
@@ -209,8 +216,9 @@ export const readabilityRules = [
|
|
|
209
216
|
severity: 'info',
|
|
210
217
|
description: 'Avoid overly complex vocabulary',
|
|
211
218
|
check: (ctx) => {
|
|
212
|
-
if (ctx.complexWordPercentage === undefined)
|
|
213
|
-
return
|
|
219
|
+
if (ctx.complexWordPercentage === undefined) {
|
|
220
|
+
return createResult({ id: 'readability-word-complexity', name: 'Word Complexity', category: 'content', severity: 'info' }, 'info', 'Not applicable (word complexity data unavailable)', { recommendation: 'This rule checks for complex vocabulary that may reduce readability' });
|
|
221
|
+
}
|
|
214
222
|
if (ctx.complexWordPercentage > 15) {
|
|
215
223
|
return createResult({ id: 'readability-word-complexity', name: 'Word Complexity', category: 'content', severity: 'info' }, 'warn', `Complex words: ${Math.round(ctx.complexWordPercentage)}%`, {
|
|
216
224
|
recommendation: 'Use simpler vocabulary where possible',
|
|
@@ -224,7 +232,7 @@ export const readabilityRules = [
|
|
|
224
232
|
if (ctx.complexWordPercentage > 10) {
|
|
225
233
|
return createResult({ id: 'readability-word-complexity', name: 'Word Complexity', category: 'content', severity: 'info' }, 'info', `Complex words: ${Math.round(ctx.complexWordPercentage)}%`);
|
|
226
234
|
}
|
|
227
|
-
return
|
|
235
|
+
return createResult({ id: 'readability-word-complexity', name: 'Word Complexity', category: 'content', severity: 'info' }, 'pass', `Word complexity acceptable (${Math.round(ctx.complexWordPercentage)}%)`);
|
|
228
236
|
},
|
|
229
237
|
},
|
|
230
238
|
{
|
|
@@ -234,8 +242,9 @@ export const readabilityRules = [
|
|
|
234
242
|
severity: 'info',
|
|
235
243
|
description: 'Use lists to improve scannability',
|
|
236
244
|
check: (ctx) => {
|
|
237
|
-
if (!ctx.wordCount || ctx.listCount === undefined)
|
|
238
|
-
return
|
|
245
|
+
if (!ctx.wordCount || ctx.listCount === undefined) {
|
|
246
|
+
return createResult({ id: 'readability-list-usage', name: 'List Usage', category: 'content', severity: 'info' }, 'info', 'Not applicable (word count or list data unavailable)', { recommendation: 'This rule checks for proper use of lists to improve scannability' });
|
|
247
|
+
}
|
|
239
248
|
if (ctx.wordCount > 500 && ctx.listCount === 0) {
|
|
240
249
|
return createResult({ id: 'readability-list-usage', name: 'List Usage', category: 'content', severity: 'info' }, 'info', 'No lists found in long-form content', {
|
|
241
250
|
recommendation: 'Consider using bullet points or numbered lists',
|
|
@@ -249,7 +258,7 @@ export const readabilityRules = [
|
|
|
249
258
|
if (ctx.listCount > 0) {
|
|
250
259
|
return createResult({ id: 'readability-list-usage', name: 'List Usage', category: 'content', severity: 'info' }, 'pass', `${ctx.listCount} list(s) found`);
|
|
251
260
|
}
|
|
252
|
-
return
|
|
261
|
+
return createResult({ id: 'readability-list-usage', name: 'List Usage', category: 'content', severity: 'info' }, 'pass', 'Content length does not require lists');
|
|
253
262
|
},
|
|
254
263
|
},
|
|
255
264
|
];
|
|
@@ -7,8 +7,9 @@ export const redirectRules = [
|
|
|
7
7
|
severity: 'warning',
|
|
8
8
|
description: 'Redirect chains should not exceed 3 hops',
|
|
9
9
|
check: (ctx) => {
|
|
10
|
-
if (ctx.redirectChain === undefined)
|
|
11
|
-
return
|
|
10
|
+
if (ctx.redirectChain === undefined) {
|
|
11
|
+
return createResult({ id: 'redirect-chain-length', name: 'Redirect Chain Length', category: 'technical', severity: 'warning' }, 'info', 'Unable to check redirect chain (data unavailable)', { recommendation: 'Ensure redirect analysis completed' });
|
|
12
|
+
}
|
|
12
13
|
const chainLength = ctx.redirectChain.length;
|
|
13
14
|
if (chainLength === 0) {
|
|
14
15
|
return createResult({ id: 'redirect-chain-length', name: 'Redirect Chain Length', category: 'technical', severity: 'warning' }, 'pass', 'No redirects detected');
|
|
@@ -50,8 +51,9 @@ export const redirectRules = [
|
|
|
50
51
|
severity: 'error',
|
|
51
52
|
description: 'Pages should not create redirect loops',
|
|
52
53
|
check: (ctx) => {
|
|
53
|
-
if (!ctx.redirectChain || ctx.redirectChain.length === 0)
|
|
54
|
-
return
|
|
54
|
+
if (!ctx.redirectChain || ctx.redirectChain.length === 0) {
|
|
55
|
+
return createResult({ id: 'redirect-loop', name: 'Redirect Loop', category: 'technical', severity: 'error' }, 'pass', 'No redirect chain to check for loops');
|
|
56
|
+
}
|
|
55
57
|
const urls = ctx.redirectChain.map(r => r.from);
|
|
56
58
|
urls.push(ctx.redirectChain[ctx.redirectChain.length - 1].to);
|
|
57
59
|
const seen = new Set();
|
|
@@ -74,7 +76,7 @@ export const redirectRules = [
|
|
|
74
76
|
}
|
|
75
77
|
});
|
|
76
78
|
}
|
|
77
|
-
return
|
|
79
|
+
return createResult({ id: 'redirect-loop', name: 'Redirect Loop', category: 'technical', severity: 'error' }, 'pass', 'No redirect loop detected');
|
|
78
80
|
},
|
|
79
81
|
},
|
|
80
82
|
{
|
|
@@ -84,8 +86,9 @@ export const redirectRules = [
|
|
|
84
86
|
severity: 'info',
|
|
85
87
|
description: 'Permanent content moves should use 301 redirects',
|
|
86
88
|
check: (ctx) => {
|
|
87
|
-
if (!ctx.redirectChain || ctx.redirectChain.length === 0)
|
|
88
|
-
return
|
|
89
|
+
if (!ctx.redirectChain || ctx.redirectChain.length === 0) {
|
|
90
|
+
return createResult({ id: 'redirect-type', name: 'Redirect Type', category: 'technical', severity: 'info' }, 'info', 'No redirects to analyze', { recommendation: 'Page loaded without redirects' });
|
|
91
|
+
}
|
|
89
92
|
const temporary = ctx.redirectChain.filter(r => r.status === 302 || r.status === 307);
|
|
90
93
|
const permanent = ctx.redirectChain.filter(r => r.status === 301 || r.status === 308);
|
|
91
94
|
if (temporary.length > 0 && permanent.length === 0) {
|
|
@@ -101,7 +104,7 @@ export const redirectRules = [
|
|
|
101
104
|
if (permanent.length > 0) {
|
|
102
105
|
return createResult({ id: 'redirect-type', name: 'Redirect Type', category: 'technical', severity: 'info' }, 'pass', 'Using permanent redirect (301)');
|
|
103
106
|
}
|
|
104
|
-
return
|
|
107
|
+
return createResult({ id: 'redirect-type', name: 'Redirect Type', category: 'technical', severity: 'info' }, 'info', 'Unknown redirect type', { recommendation: 'Check redirect status codes' });
|
|
105
108
|
},
|
|
106
109
|
},
|
|
107
110
|
{
|
|
@@ -111,8 +114,9 @@ export const redirectRules = [
|
|
|
111
114
|
severity: 'warning',
|
|
112
115
|
description: 'Site should redirect consistently to either WWW or non-WWW version',
|
|
113
116
|
check: (ctx) => {
|
|
114
|
-
if (ctx.wwwConsistency === undefined)
|
|
115
|
-
return
|
|
117
|
+
if (ctx.wwwConsistency === undefined) {
|
|
118
|
+
return createResult({ id: 'www-consistency', name: 'WWW vs Non-WWW', category: 'canonicalization', severity: 'warning' }, 'info', 'Unable to check WWW consistency (data unavailable)', { recommendation: 'Ensure WWW/non-WWW analysis completed' });
|
|
119
|
+
}
|
|
116
120
|
const { canonicalHasWww, urlHasWww, redirectsToCanonical } = ctx.wwwConsistency;
|
|
117
121
|
if (canonicalHasWww !== urlHasWww && !redirectsToCanonical) {
|
|
118
122
|
return createResult({ id: 'www-consistency', name: 'WWW vs Non-WWW', category: 'canonicalization', severity: 'warning' }, 'warn', 'WWW/non-WWW version accessible without redirect', {
|
|
@@ -134,8 +138,9 @@ export const redirectRules = [
|
|
|
134
138
|
severity: 'warning',
|
|
135
139
|
description: 'HTTP version should redirect to HTTPS',
|
|
136
140
|
check: (ctx) => {
|
|
137
|
-
if (ctx.httpRedirectsToHttps === undefined)
|
|
138
|
-
return
|
|
141
|
+
if (ctx.httpRedirectsToHttps === undefined) {
|
|
142
|
+
return createResult({ id: 'http-to-https-redirect', name: 'HTTP to HTTPS Redirect', category: 'security', severity: 'warning' }, 'info', 'Unable to check HTTP to HTTPS redirect (data unavailable)', { recommendation: 'Ensure HTTPS redirect analysis completed' });
|
|
143
|
+
}
|
|
139
144
|
if (!ctx.httpRedirectsToHttps) {
|
|
140
145
|
return createResult({ id: 'http-to-https-redirect', name: 'HTTP to HTTPS Redirect', category: 'security', severity: 'warning' }, 'warn', 'HTTP version does not redirect to HTTPS', {
|
|
141
146
|
recommendation: 'Configure server to redirect HTTP traffic to HTTPS',
|
|
@@ -157,8 +162,9 @@ export const redirectRules = [
|
|
|
157
162
|
severity: 'info',
|
|
158
163
|
description: 'Detects redirects to different domains',
|
|
159
164
|
check: (ctx) => {
|
|
160
|
-
if (!ctx.redirectChain || ctx.redirectChain.length === 0)
|
|
161
|
-
return
|
|
165
|
+
if (!ctx.redirectChain || ctx.redirectChain.length === 0) {
|
|
166
|
+
return createResult({ id: 'cross-domain-redirect', name: 'Cross-Domain Redirect', category: 'technical', severity: 'info' }, 'info', 'No redirect chain to check', { recommendation: 'Page loaded without redirects' });
|
|
167
|
+
}
|
|
162
168
|
const crossDomainRedirects = ctx.redirectChain.filter(r => {
|
|
163
169
|
try {
|
|
164
170
|
const fromHost = new URL(r.from).hostname;
|
|
@@ -178,7 +184,7 @@ export const redirectRules = [
|
|
|
178
184
|
}
|
|
179
185
|
});
|
|
180
186
|
}
|
|
181
|
-
return
|
|
187
|
+
return createResult({ id: 'cross-domain-redirect', name: 'Cross-Domain Redirect', category: 'technical', severity: 'info' }, 'pass', 'No cross-domain redirects');
|
|
182
188
|
},
|
|
183
189
|
},
|
|
184
190
|
];
|