recker 1.0.43 → 1.0.44-next.084c2ef

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. package/README.md +47 -0
  2. package/dist/bin/recker-linux-x64 +0 -0
  3. package/dist/bin/recker-macos-x64 +0 -0
  4. package/dist/bin/recker-win-x64.exe +0 -0
  5. package/dist/bin/rek.cjs +85617 -99560
  6. package/dist/browser/ai/adaptive-timeout.d.ts +50 -0
  7. package/dist/browser/ai/adaptive-timeout.js +208 -0
  8. package/dist/browser/ai/client.d.ts +22 -0
  9. package/dist/browser/ai/client.js +294 -0
  10. package/dist/browser/ai/index.d.ts +14 -0
  11. package/dist/browser/ai/index.js +11 -0
  12. package/dist/browser/ai/providers/anthropic.d.ts +63 -0
  13. package/dist/browser/ai/providers/anthropic.js +370 -0
  14. package/dist/browser/ai/providers/base.d.ts +48 -0
  15. package/dist/browser/ai/providers/base.js +150 -0
  16. package/dist/browser/ai/providers/google.d.ts +59 -0
  17. package/dist/browser/ai/providers/google.js +305 -0
  18. package/dist/browser/ai/providers/ollama.d.ts +44 -0
  19. package/dist/browser/ai/providers/ollama.js +240 -0
  20. package/dist/browser/ai/providers/openai.d.ts +64 -0
  21. package/dist/browser/ai/providers/openai.js +298 -0
  22. package/dist/browser/ai/rate-limiter.d.ts +43 -0
  23. package/dist/browser/ai/rate-limiter.js +215 -0
  24. package/dist/browser/ai/vector/index.d.ts +2 -0
  25. package/dist/browser/ai/vector/index.js +2 -0
  26. package/dist/browser/ai/vector/similarity.d.ts +2 -0
  27. package/dist/browser/ai/vector/similarity.js +27 -0
  28. package/dist/browser/ai/vector/store.d.ts +27 -0
  29. package/dist/browser/ai/vector/store.js +82 -0
  30. package/dist/browser/browser/cache.d.ts +2 -40
  31. package/dist/browser/browser/cache.js +2 -199
  32. package/dist/browser/browser/index.d.ts +8 -0
  33. package/dist/browser/browser/index.js +8 -0
  34. package/dist/browser/browser/recker.d.ts +8 -1
  35. package/dist/browser/browser/recker.js +8 -2
  36. package/dist/browser/cache/indexed-db.d.ts +10 -0
  37. package/dist/browser/cache/indexed-db.js +88 -0
  38. package/dist/browser/cache/service-worker-cache.d.ts +18 -0
  39. package/dist/browser/cache/service-worker-cache.js +103 -0
  40. package/dist/browser/cache.d.ts +2 -40
  41. package/dist/browser/cache.js +2 -199
  42. package/dist/browser/constants/user-agents.d.ts +7 -0
  43. package/dist/browser/constants/user-agents.js +7 -0
  44. package/dist/browser/core/client.d.ts +2 -0
  45. package/dist/browser/core/client.js +19 -1
  46. package/dist/browser/index.d.ts +8 -0
  47. package/dist/browser/index.js +8 -0
  48. package/dist/browser/plugins/har-recorder.d.ts +40 -0
  49. package/dist/browser/plugins/har-recorder.js +120 -0
  50. package/dist/browser/plugins/network-simulation.d.ts +7 -0
  51. package/dist/browser/plugins/network-simulation.js +13 -0
  52. package/dist/browser/presets/android.d.ts +2 -0
  53. package/dist/browser/presets/android.js +16 -0
  54. package/dist/browser/presets/anthropic.d.ts +8 -0
  55. package/dist/browser/presets/anthropic.js +27 -0
  56. package/dist/browser/presets/aws.d.ts +19 -0
  57. package/dist/browser/presets/aws.js +68 -0
  58. package/dist/browser/presets/azure-openai.d.ts +10 -0
  59. package/dist/browser/presets/azure-openai.js +35 -0
  60. package/dist/browser/presets/azure.d.ts +41 -0
  61. package/dist/browser/presets/azure.js +104 -0
  62. package/dist/browser/presets/chaturbate.d.ts +2 -0
  63. package/dist/browser/presets/chaturbate.js +17 -0
  64. package/dist/browser/presets/cloudflare.d.ts +12 -0
  65. package/dist/browser/presets/cloudflare.js +39 -0
  66. package/dist/browser/presets/cohere.d.ts +7 -0
  67. package/dist/browser/presets/cohere.js +22 -0
  68. package/dist/browser/presets/deepseek.d.ts +7 -0
  69. package/dist/browser/presets/deepseek.js +22 -0
  70. package/dist/browser/presets/digitalocean.d.ts +5 -0
  71. package/dist/browser/presets/digitalocean.js +16 -0
  72. package/dist/browser/presets/discord.d.ts +6 -0
  73. package/dist/browser/presets/discord.js +17 -0
  74. package/dist/browser/presets/elevenlabs.d.ts +6 -0
  75. package/dist/browser/presets/elevenlabs.js +20 -0
  76. package/dist/browser/presets/enhancers.d.ts +20 -0
  77. package/dist/browser/presets/enhancers.js +85 -0
  78. package/dist/browser/presets/fireworks.d.ts +7 -0
  79. package/dist/browser/presets/fireworks.js +22 -0
  80. package/dist/browser/presets/gcp.d.ts +34 -0
  81. package/dist/browser/presets/gcp.js +91 -0
  82. package/dist/browser/presets/gemini.d.ts +7 -0
  83. package/dist/browser/presets/gemini.js +23 -0
  84. package/dist/browser/presets/github.d.ts +6 -0
  85. package/dist/browser/presets/github.js +17 -0
  86. package/dist/browser/presets/gitlab.d.ts +6 -0
  87. package/dist/browser/presets/gitlab.js +16 -0
  88. package/dist/browser/presets/groq.d.ts +7 -0
  89. package/dist/browser/presets/groq.js +22 -0
  90. package/dist/browser/presets/hubspot.d.ts +9 -0
  91. package/dist/browser/presets/hubspot.js +28 -0
  92. package/dist/browser/presets/huggingface.d.ts +7 -0
  93. package/dist/browser/presets/huggingface.js +23 -0
  94. package/dist/browser/presets/index.d.ts +47 -0
  95. package/dist/browser/presets/index.js +47 -0
  96. package/dist/browser/presets/ios.d.ts +2 -0
  97. package/dist/browser/presets/ios.js +13 -0
  98. package/dist/browser/presets/linear.d.ts +5 -0
  99. package/dist/browser/presets/linear.js +16 -0
  100. package/dist/browser/presets/mailgun.d.ts +7 -0
  101. package/dist/browser/presets/mailgun.js +20 -0
  102. package/dist/browser/presets/meta.d.ts +10 -0
  103. package/dist/browser/presets/meta.js +33 -0
  104. package/dist/browser/presets/mistral.d.ts +7 -0
  105. package/dist/browser/presets/mistral.js +22 -0
  106. package/dist/browser/presets/notion.d.ts +6 -0
  107. package/dist/browser/presets/notion.js +17 -0
  108. package/dist/browser/presets/openai.d.ts +9 -0
  109. package/dist/browser/presets/openai.js +30 -0
  110. package/dist/browser/presets/oracle.d.ts +19 -0
  111. package/dist/browser/presets/oracle.js +117 -0
  112. package/dist/browser/presets/perplexity.d.ts +7 -0
  113. package/dist/browser/presets/perplexity.js +22 -0
  114. package/dist/browser/presets/pinecone.d.ts +8 -0
  115. package/dist/browser/presets/pinecone.js +42 -0
  116. package/dist/browser/presets/registry.d.ts +23 -0
  117. package/dist/browser/presets/registry.js +519 -0
  118. package/dist/browser/presets/replicate.d.ts +7 -0
  119. package/dist/browser/presets/replicate.js +23 -0
  120. package/dist/browser/presets/sendgrid.d.ts +6 -0
  121. package/dist/browser/presets/sendgrid.js +20 -0
  122. package/dist/browser/presets/sentry.d.ts +11 -0
  123. package/dist/browser/presets/sentry.js +48 -0
  124. package/dist/browser/presets/sinch.d.ts +9 -0
  125. package/dist/browser/presets/sinch.js +39 -0
  126. package/dist/browser/presets/slack.d.ts +5 -0
  127. package/dist/browser/presets/slack.js +16 -0
  128. package/dist/browser/presets/square.d.ts +10 -0
  129. package/dist/browser/presets/square.js +33 -0
  130. package/dist/browser/presets/stripe.d.ts +7 -0
  131. package/dist/browser/presets/stripe.js +23 -0
  132. package/dist/browser/presets/supabase.d.ts +6 -0
  133. package/dist/browser/presets/supabase.js +18 -0
  134. package/dist/browser/presets/tiktok.d.ts +10 -0
  135. package/dist/browser/presets/tiktok.js +38 -0
  136. package/dist/browser/presets/together.d.ts +7 -0
  137. package/dist/browser/presets/together.js +22 -0
  138. package/dist/browser/presets/twilio.d.ts +6 -0
  139. package/dist/browser/presets/twilio.js +17 -0
  140. package/dist/browser/presets/vercel.d.ts +6 -0
  141. package/dist/browser/presets/vercel.js +23 -0
  142. package/dist/browser/presets/vultr.d.ts +5 -0
  143. package/dist/browser/presets/vultr.js +16 -0
  144. package/dist/browser/presets/xai.d.ts +8 -0
  145. package/dist/browser/presets/xai.js +23 -0
  146. package/dist/browser/presets/youtube.d.ts +5 -0
  147. package/dist/browser/presets/youtube.js +20 -0
  148. package/dist/browser/recker.d.ts +8 -1
  149. package/dist/browser/recker.js +8 -2
  150. package/dist/browser/scrape/document.d.ts +5 -4
  151. package/dist/browser/scrape/document.js +89 -76
  152. package/dist/browser/scrape/element.d.ts +10 -8
  153. package/dist/browser/scrape/element.js +295 -81
  154. package/dist/browser/scrape/extractors.d.ts +11 -11
  155. package/dist/browser/scrape/extractors.js +145 -113
  156. package/dist/browser/scrape/parser/back.d.ts +1 -0
  157. package/dist/browser/scrape/parser/back.js +3 -0
  158. package/dist/browser/scrape/parser/index.d.ts +20 -0
  159. package/dist/browser/scrape/parser/index.js +19 -0
  160. package/dist/browser/scrape/parser/matcher.d.ts +30 -0
  161. package/dist/browser/scrape/parser/matcher.js +99 -0
  162. package/dist/browser/scrape/parser/nodes/comment.d.ts +12 -0
  163. package/dist/browser/scrape/parser/nodes/comment.js +21 -0
  164. package/dist/browser/scrape/parser/nodes/html.d.ts +110 -0
  165. package/dist/browser/scrape/parser/nodes/html.js +978 -0
  166. package/dist/browser/scrape/parser/nodes/node.d.ts +18 -0
  167. package/dist/browser/scrape/parser/nodes/node.js +31 -0
  168. package/dist/browser/scrape/parser/nodes/text.d.ts +14 -0
  169. package/dist/browser/scrape/parser/nodes/text.js +30 -0
  170. package/dist/browser/scrape/parser/nodes/type.d.ts +6 -0
  171. package/dist/browser/scrape/parser/nodes/type.js +7 -0
  172. package/dist/browser/scrape/parser/parse.d.ts +1 -0
  173. package/dist/browser/scrape/parser/parse.js +1 -0
  174. package/dist/browser/scrape/parser/valid.d.ts +2 -0
  175. package/dist/browser/scrape/parser/valid.js +5 -0
  176. package/dist/browser/scrape/parser/void-tag.d.ts +7 -0
  177. package/dist/browser/scrape/parser/void-tag.js +43 -0
  178. package/dist/browser/scrape/types.d.ts +7 -0
  179. package/dist/browser/seo/analyzer.d.ts +59 -0
  180. package/dist/browser/seo/analyzer.js +1399 -0
  181. package/dist/browser/seo/keywords.d.ts +16 -0
  182. package/dist/browser/seo/keywords.js +55 -0
  183. package/dist/browser/seo/rules/accessibility.d.ts +2 -0
  184. package/dist/browser/seo/rules/accessibility.js +733 -0
  185. package/dist/browser/seo/rules/ai-search.d.ts +2 -0
  186. package/dist/browser/seo/rules/ai-search.js +436 -0
  187. package/dist/browser/seo/rules/analytics.d.ts +2 -0
  188. package/dist/browser/seo/rules/analytics.js +306 -0
  189. package/dist/browser/seo/rules/best-practices.d.ts +2 -0
  190. package/dist/browser/seo/rules/best-practices.js +195 -0
  191. package/dist/browser/seo/rules/canonical.d.ts +12 -0
  192. package/dist/browser/seo/rules/canonical.js +270 -0
  193. package/dist/browser/seo/rules/content.d.ts +2 -0
  194. package/dist/browser/seo/rules/content.js +522 -0
  195. package/dist/browser/seo/rules/crawl.d.ts +2 -0
  196. package/dist/browser/seo/rules/crawl.js +435 -0
  197. package/dist/browser/seo/rules/cwv.d.ts +2 -0
  198. package/dist/browser/seo/rules/cwv.js +248 -0
  199. package/dist/browser/seo/rules/ecommerce.d.ts +2 -0
  200. package/dist/browser/seo/rules/ecommerce.js +312 -0
  201. package/dist/browser/seo/rules/i18n.d.ts +2 -0
  202. package/dist/browser/seo/rules/i18n.js +288 -0
  203. package/dist/browser/seo/rules/images.d.ts +2 -0
  204. package/dist/browser/seo/rules/images.js +255 -0
  205. package/dist/browser/seo/rules/index.d.ts +52 -0
  206. package/dist/browser/seo/rules/index.js +163 -0
  207. package/dist/browser/seo/rules/internal-linking.d.ts +2 -0
  208. package/dist/browser/seo/rules/internal-linking.js +394 -0
  209. package/dist/browser/seo/rules/links.d.ts +2 -0
  210. package/dist/browser/seo/rules/links.js +498 -0
  211. package/dist/browser/seo/rules/local.d.ts +2 -0
  212. package/dist/browser/seo/rules/local.js +289 -0
  213. package/dist/browser/seo/rules/manifest.d.ts +2 -0
  214. package/dist/browser/seo/rules/manifest.js +621 -0
  215. package/dist/browser/seo/rules/meta.d.ts +2 -0
  216. package/dist/browser/seo/rules/meta.js +805 -0
  217. package/dist/browser/seo/rules/mobile.d.ts +2 -0
  218. package/dist/browser/seo/rules/mobile.js +161 -0
  219. package/dist/browser/seo/rules/performance.d.ts +2 -0
  220. package/dist/browser/seo/rules/performance.js +738 -0
  221. package/dist/browser/seo/rules/pwa.d.ts +2 -0
  222. package/dist/browser/seo/rules/pwa.js +299 -0
  223. package/dist/browser/seo/rules/readability.d.ts +2 -0
  224. package/dist/browser/seo/rules/readability.js +264 -0
  225. package/dist/browser/seo/rules/redirects.d.ts +16 -0
  226. package/dist/browser/seo/rules/redirects.js +199 -0
  227. package/dist/browser/seo/rules/resources.d.ts +2 -0
  228. package/dist/browser/seo/rules/resources.js +390 -0
  229. package/dist/browser/seo/rules/schema.d.ts +2 -0
  230. package/dist/browser/seo/rules/schema.js +379 -0
  231. package/dist/browser/seo/rules/security.d.ts +2 -0
  232. package/dist/browser/seo/rules/security.js +877 -0
  233. package/dist/browser/seo/rules/social.d.ts +2 -0
  234. package/dist/browser/seo/rules/social.js +603 -0
  235. package/dist/browser/seo/rules/structural.d.ts +2 -0
  236. package/dist/browser/seo/rules/structural.js +223 -0
  237. package/dist/browser/seo/rules/technical-advanced.d.ts +10 -0
  238. package/dist/browser/seo/rules/technical-advanced.js +289 -0
  239. package/dist/browser/seo/rules/technical.d.ts +3 -0
  240. package/dist/browser/seo/rules/technical.js +509 -0
  241. package/dist/browser/seo/rules/thresholds.d.ts +196 -0
  242. package/dist/browser/seo/rules/thresholds.js +118 -0
  243. package/dist/browser/seo/rules/types.d.ts +518 -0
  244. package/dist/browser/seo/rules/types.js +11 -0
  245. package/dist/browser/seo/types.d.ts +211 -0
  246. package/dist/browser/seo/types.js +1 -0
  247. package/dist/browser/transport/curl.d.ts +4 -0
  248. package/dist/browser/transport/curl.js +101 -0
  249. package/dist/browser/transport/undici.js +1 -2
  250. package/dist/browser/transport/worker.d.ts +18 -0
  251. package/dist/browser/transport/worker.js +278 -0
  252. package/dist/browser/types/index.d.ts +4 -1
  253. package/dist/browser/utils/binary-manager.d.ts +4 -0
  254. package/dist/browser/utils/binary-manager.js +72 -0
  255. package/dist/browser/utils/user-agent.js +2 -13
  256. package/dist/cache/indexed-db.d.ts +10 -0
  257. package/dist/cache/indexed-db.js +88 -0
  258. package/dist/cache/service-worker-cache.d.ts +18 -0
  259. package/dist/cache/service-worker-cache.js +103 -0
  260. package/dist/cli/commands/ai.d.ts +2 -0
  261. package/dist/cli/commands/ai.js +162 -0
  262. package/dist/cli/commands/bench.d.ts +2 -0
  263. package/dist/cli/commands/bench.js +51 -0
  264. package/dist/cli/commands/dns.d.ts +2 -0
  265. package/dist/cli/commands/dns.js +295 -0
  266. package/dist/cli/commands/har.d.ts +2 -0
  267. package/dist/cli/commands/har.js +171 -0
  268. package/dist/cli/commands/hls.d.ts +2 -0
  269. package/dist/cli/commands/hls.js +192 -0
  270. package/dist/cli/commands/network.d.ts +2 -0
  271. package/dist/cli/commands/network.js +288 -0
  272. package/dist/cli/commands/protocols.d.ts +2 -0
  273. package/dist/cli/commands/protocols.js +344 -0
  274. package/dist/cli/commands/scrape.d.ts +2 -0
  275. package/dist/cli/commands/scrape.js +176 -0
  276. package/dist/cli/commands/security.d.ts +2 -0
  277. package/dist/cli/commands/security.js +57 -0
  278. package/dist/cli/commands/seo.d.ts +2 -0
  279. package/dist/cli/commands/seo.js +125 -0
  280. package/dist/cli/commands/serve.d.ts +2 -0
  281. package/dist/cli/commands/serve.js +531 -0
  282. package/dist/cli/commands/spider.d.ts +3 -0
  283. package/dist/cli/commands/spider.js +478 -0
  284. package/dist/cli/commands/utils.d.ts +2 -0
  285. package/dist/cli/commands/utils.js +176 -0
  286. package/dist/cli/commands/vector.d.ts +2 -0
  287. package/dist/cli/commands/vector.js +158 -0
  288. package/dist/cli/handler.d.ts +2 -2
  289. package/dist/cli/handler.js +6 -6
  290. package/dist/cli/helpers.d.ts +7 -0
  291. package/dist/cli/helpers.js +128 -0
  292. package/dist/cli/index.js +96 -5228
  293. package/dist/cli/parser/help.d.ts +2 -0
  294. package/dist/cli/parser/help.js +52 -0
  295. package/dist/cli/parser/index.d.ts +3 -0
  296. package/dist/cli/parser/index.js +3 -0
  297. package/dist/cli/parser/parser.d.ts +4 -0
  298. package/dist/cli/parser/parser.js +146 -0
  299. package/dist/cli/parser/types.d.ts +41 -0
  300. package/dist/cli/parser/types.js +1 -0
  301. package/dist/cli/presets.d.ts +1 -1
  302. package/dist/cli/presets.js +1 -1
  303. package/dist/cli/router.d.ts +36 -0
  304. package/dist/cli/router.js +195 -0
  305. package/dist/cli/tui/ai-chat.js +1 -1
  306. package/dist/cli/tui/commands/context.d.ts +9 -0
  307. package/dist/cli/tui/commands/context.js +1 -0
  308. package/dist/cli/tui/commands/dns.d.ts +10 -0
  309. package/dist/cli/tui/commands/dns.js +461 -0
  310. package/dist/cli/tui/commands/hls.d.ts +2 -0
  311. package/dist/cli/tui/commands/hls.js +162 -0
  312. package/dist/cli/tui/commands/ip.d.ts +2 -0
  313. package/dist/cli/tui/commands/ip.js +45 -0
  314. package/dist/cli/tui/commands/network.d.ts +3 -0
  315. package/dist/cli/tui/commands/network.js +81 -0
  316. package/dist/cli/tui/commands/protocols.d.ts +6 -0
  317. package/dist/cli/tui/commands/protocols.js +531 -0
  318. package/dist/cli/tui/commands/security.d.ts +2 -0
  319. package/dist/cli/tui/commands/security.js +48 -0
  320. package/dist/cli/tui/commands/seo.d.ts +2 -0
  321. package/dist/cli/tui/commands/seo.js +74 -0
  322. package/dist/cli/tui/context.d.ts +12 -0
  323. package/dist/cli/tui/context.js +1 -0
  324. package/dist/cli/tui/shell.d.ts +11 -20
  325. package/dist/cli/tui/shell.js +216 -1873
  326. package/dist/constants/user-agents.d.ts +7 -0
  327. package/dist/constants/user-agents.js +7 -0
  328. package/dist/core/client.d.ts +2 -0
  329. package/dist/core/client.js +19 -1
  330. package/dist/index.d.ts +1 -0
  331. package/dist/index.js +1 -0
  332. package/dist/mcp/cli.js +2 -3
  333. package/dist/mcp/data/embeddings.json +1 -1
  334. package/dist/mcp/tools/network.js +298 -158
  335. package/dist/plugins/har-player.d.ts +23 -0
  336. package/dist/plugins/har-player.js +49 -0
  337. package/dist/plugins/har-recorder.d.ts +37 -3
  338. package/dist/plugins/har-recorder.js +116 -63
  339. package/dist/plugins/network-simulation.d.ts +7 -0
  340. package/dist/plugins/network-simulation.js +13 -0
  341. package/dist/presets/android.d.ts +2 -0
  342. package/dist/presets/android.js +16 -0
  343. package/dist/presets/chaturbate.d.ts +2 -0
  344. package/dist/presets/chaturbate.js +17 -0
  345. package/dist/presets/elevenlabs.d.ts +6 -0
  346. package/dist/presets/elevenlabs.js +20 -0
  347. package/dist/presets/enhancers.d.ts +20 -0
  348. package/dist/presets/enhancers.js +85 -0
  349. package/dist/presets/hubspot.d.ts +9 -0
  350. package/dist/presets/hubspot.js +28 -0
  351. package/dist/presets/index.d.ts +10 -0
  352. package/dist/presets/index.js +10 -0
  353. package/dist/presets/ios.d.ts +2 -0
  354. package/dist/presets/ios.js +13 -0
  355. package/dist/presets/pinecone.d.ts +8 -0
  356. package/dist/presets/pinecone.js +42 -0
  357. package/dist/presets/registry.js +60 -0
  358. package/dist/presets/sendgrid.d.ts +6 -0
  359. package/dist/presets/sendgrid.js +20 -0
  360. package/dist/presets/sentry.d.ts +11 -0
  361. package/dist/presets/sentry.js +48 -0
  362. package/dist/presets/square.d.ts +10 -0
  363. package/dist/presets/square.js +33 -0
  364. package/dist/recker.d.ts +3 -0
  365. package/dist/recker.js +4 -0
  366. package/dist/scrape/document.d.ts +5 -4
  367. package/dist/scrape/document.js +89 -76
  368. package/dist/scrape/element.d.ts +10 -8
  369. package/dist/scrape/element.js +295 -81
  370. package/dist/scrape/extractors.d.ts +11 -11
  371. package/dist/scrape/extractors.js +145 -113
  372. package/dist/scrape/index.d.ts +2 -0
  373. package/dist/scrape/index.js +1 -0
  374. package/dist/scrape/parser/back.d.ts +1 -0
  375. package/dist/scrape/parser/back.js +3 -0
  376. package/dist/scrape/parser/index.d.ts +20 -0
  377. package/dist/scrape/parser/index.js +19 -0
  378. package/dist/scrape/parser/matcher.d.ts +30 -0
  379. package/dist/scrape/parser/matcher.js +99 -0
  380. package/dist/scrape/parser/nodes/comment.d.ts +12 -0
  381. package/dist/scrape/parser/nodes/comment.js +21 -0
  382. package/dist/scrape/parser/nodes/html.d.ts +110 -0
  383. package/dist/scrape/parser/nodes/html.js +978 -0
  384. package/dist/scrape/parser/nodes/node.d.ts +18 -0
  385. package/dist/scrape/parser/nodes/node.js +31 -0
  386. package/dist/scrape/parser/nodes/text.d.ts +14 -0
  387. package/dist/scrape/parser/nodes/text.js +30 -0
  388. package/dist/scrape/parser/nodes/type.d.ts +6 -0
  389. package/dist/scrape/parser/nodes/type.js +7 -0
  390. package/dist/scrape/parser/parse.d.ts +1 -0
  391. package/dist/scrape/parser/parse.js +1 -0
  392. package/dist/scrape/parser/valid.d.ts +2 -0
  393. package/dist/scrape/parser/valid.js +5 -0
  394. package/dist/scrape/parser/void-tag.d.ts +7 -0
  395. package/dist/scrape/parser/void-tag.js +43 -0
  396. package/dist/scrape/spider.d.ts +19 -0
  397. package/dist/scrape/spider.js +28 -3
  398. package/dist/scrape/types.d.ts +7 -0
  399. package/dist/seo/analyzer.d.ts +15 -5
  400. package/dist/seo/analyzer.js +636 -175
  401. package/dist/seo/formatter.d.ts +16 -0
  402. package/dist/seo/formatter.js +228 -0
  403. package/dist/seo/index.d.ts +2 -0
  404. package/dist/seo/index.js +1 -0
  405. package/dist/seo/keywords.d.ts +16 -0
  406. package/dist/seo/keywords.js +55 -0
  407. package/dist/seo/rules/accessibility.js +96 -57
  408. package/dist/seo/rules/ai-search.js +44 -31
  409. package/dist/seo/rules/analytics.d.ts +2 -0
  410. package/dist/seo/rules/analytics.js +306 -0
  411. package/dist/seo/rules/best-practices.js +21 -14
  412. package/dist/seo/rules/canonical.js +53 -32
  413. package/dist/seo/rules/content.js +317 -31
  414. package/dist/seo/rules/crawl.js +55 -40
  415. package/dist/seo/rules/cwv.js +21 -15
  416. package/dist/seo/rules/ecommerce.js +82 -22
  417. package/dist/seo/rules/i18n.js +75 -36
  418. package/dist/seo/rules/images.js +109 -30
  419. package/dist/seo/rules/index.js +7 -1
  420. package/dist/seo/rules/internal-linking.js +58 -39
  421. package/dist/seo/rules/links.js +79 -52
  422. package/dist/seo/rules/local.js +49 -25
  423. package/dist/seo/rules/manifest.d.ts +2 -0
  424. package/dist/seo/rules/manifest.js +621 -0
  425. package/dist/seo/rules/meta.js +339 -81
  426. package/dist/seo/rules/mobile.js +112 -2
  427. package/dist/seo/rules/performance.js +434 -66
  428. package/dist/seo/rules/pwa.js +36 -39
  429. package/dist/seo/rules/readability.js +31 -22
  430. package/dist/seo/rules/redirects.js +21 -15
  431. package/dist/seo/rules/resources.js +59 -42
  432. package/dist/seo/rules/schema.js +333 -8
  433. package/dist/seo/rules/security.js +142 -80
  434. package/dist/seo/rules/social.js +277 -47
  435. package/dist/seo/rules/structural.js +87 -19
  436. package/dist/seo/rules/technical-advanced.js +30 -24
  437. package/dist/seo/rules/technical.d.ts +1 -0
  438. package/dist/seo/rules/technical.js +272 -42
  439. package/dist/seo/rules/types.d.ts +74 -2
  440. package/dist/seo/seo-spider.d.ts +35 -0
  441. package/dist/seo/seo-spider.js +152 -13
  442. package/dist/seo/types.d.ts +8 -1
  443. package/dist/seo/validators/llms-txt.js +19 -0
  444. package/dist/seo/validators/rss.d.ts +11 -0
  445. package/dist/seo/validators/rss.js +93 -0
  446. package/dist/seo/validators/sitemap.js +36 -26
  447. package/dist/transport/curl.d.ts +4 -0
  448. package/dist/transport/curl.js +101 -0
  449. package/dist/transport/udp.js +0 -1
  450. package/dist/transport/undici.js +1 -2
  451. package/dist/transport/worker.d.ts +18 -0
  452. package/dist/transport/worker.js +278 -0
  453. package/dist/types/index.d.ts +4 -1
  454. package/dist/utils/binary-manager.d.ts +4 -0
  455. package/dist/utils/binary-manager.js +72 -0
  456. package/dist/utils/optional-require.d.ts +7 -8
  457. package/dist/utils/optional-require.js +2 -21
  458. package/dist/utils/upload.d.ts +6 -0
  459. package/dist/utils/upload.js +11 -0
  460. package/dist/utils/user-agent.js +2 -13
  461. package/dist/version.js +1 -1
  462. package/package.json +12 -6
  463. package/dist/browser/utils/optional-require.d.ts +0 -19
  464. package/dist/browser/utils/optional-require.js +0 -105
@@ -0,0 +1,621 @@
1
+ import { createResult } from './types.js';
2
+ function isValidColor(color) {
3
+ if (!color)
4
+ return false;
5
+ if (/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(color))
6
+ return true;
7
+ if (/^(rgb|rgba|hsl|hsla)\(/.test(color))
8
+ return true;
9
+ const namedColors = [
10
+ 'black', 'white', 'red', 'green', 'blue', 'yellow', 'cyan', 'magenta',
11
+ 'gray', 'grey', 'orange', 'purple', 'pink', 'brown', 'transparent'
12
+ ];
13
+ return namedColors.includes(color.toLowerCase());
14
+ }
15
+ export const manifestRules = [
16
+ {
17
+ id: 'manifest-exists',
18
+ name: 'Manifest File',
19
+ category: 'technical',
20
+ severity: 'warning',
21
+ description: 'A web app manifest file is required for PWA installability and better SEO',
22
+ check: (ctx) => {
23
+ if (!ctx.hasManifest) {
24
+ return createResult({ id: 'manifest-exists', name: 'Manifest File', category: 'technical', severity: 'warning' }, 'warn', 'No web app manifest found', {
25
+ recommendation: 'Create a manifest.json or site.webmanifest file and link it in your HTML.',
26
+ evidence: {
27
+ expected: '<link rel="manifest" href="/manifest.json">',
28
+ impact: 'Without a manifest, your site cannot be installed as a PWA. Google uses manifest data for app indexing and rich results. It also enables "Add to Home Screen" on mobile devices.',
29
+ example: `{
30
+ "name": "My App",
31
+ "short_name": "App",
32
+ "start_url": "/",
33
+ "display": "standalone",
34
+ "background_color": "#ffffff",
35
+ "theme_color": "#4285f4",
36
+ "icons": [
37
+ { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
38
+ { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
39
+ ]
40
+ }`,
41
+ learnMore: 'https://web.dev/articles/add-manifest'
42
+ }
43
+ });
44
+ }
45
+ return createResult({ id: 'manifest-exists', name: 'Manifest File', category: 'technical', severity: 'warning' }, 'pass', 'Web app manifest is linked', { value: ctx.manifestUrl });
46
+ },
47
+ },
48
+ {
49
+ id: 'manifest-name',
50
+ name: 'Manifest Name',
51
+ category: 'technical',
52
+ severity: 'warning',
53
+ description: 'Manifest must have a name field for proper identification',
54
+ check: (ctx) => {
55
+ if (!ctx.hasManifest) {
56
+ return createResult({ id: 'manifest-name', name: 'Manifest Name', category: 'technical', severity: 'warning' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
57
+ }
58
+ if (!ctx.manifestName) {
59
+ return createResult({ id: 'manifest-name', name: 'Manifest Name', category: 'technical', severity: 'warning' }, 'warn', 'Manifest missing name field', {
60
+ recommendation: 'Add a name field to your manifest.',
61
+ evidence: {
62
+ expected: '"name": "Your Application Name"',
63
+ impact: 'The name is displayed in app stores, install prompts, and splash screens. Without it, browsers may use the page title or leave it blank.',
64
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/name'
65
+ }
66
+ });
67
+ }
68
+ if (ctx.manifestName.length > 45) {
69
+ return createResult({ id: 'manifest-name', name: 'Manifest Name', category: 'technical', severity: 'warning' }, 'warn', `Manifest name too long: ${ctx.manifestName.length} characters`, {
70
+ value: ctx.manifestName,
71
+ recommendation: 'Keep the name under 45 characters.',
72
+ evidence: {
73
+ found: `${ctx.manifestName.length} characters`,
74
+ expected: 'Maximum 45 characters',
75
+ impact: 'Long names may be truncated in install prompts and app launchers.'
76
+ }
77
+ });
78
+ }
79
+ return createResult({ id: 'manifest-name', name: 'Manifest Name', category: 'technical', severity: 'warning' }, 'pass', `Manifest name: ${ctx.manifestName}`);
80
+ },
81
+ },
82
+ {
83
+ id: 'manifest-short-name',
84
+ name: 'Manifest Short Name',
85
+ category: 'technical',
86
+ severity: 'info',
87
+ description: 'short_name is used when name is too long for the display context',
88
+ check: (ctx) => {
89
+ if (!ctx.hasManifest) {
90
+ return createResult({ id: 'manifest-short-name', name: 'Manifest Short Name', category: 'technical', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
91
+ }
92
+ if (!ctx.manifestShortName && !ctx.manifestName) {
93
+ return createResult({ id: 'manifest-short-name', name: 'Manifest Short Name', category: 'technical', severity: 'info' }, 'warn', 'Manifest missing both name and short_name', {
94
+ recommendation: 'Add at least a name field, preferably also short_name.',
95
+ evidence: {
96
+ expected: '"short_name": "App" (max 12 chars)',
97
+ impact: 'Without any name, your app will appear unnamed in launchers and install prompts.'
98
+ }
99
+ });
100
+ }
101
+ if (ctx.manifestShortName && ctx.manifestShortName.length > 12) {
102
+ return createResult({ id: 'manifest-short-name', name: 'Manifest Short Name', category: 'technical', severity: 'info' }, 'info', `Short name exceeds 12 characters: "${ctx.manifestShortName}"`, {
103
+ value: ctx.manifestShortName,
104
+ recommendation: 'Keep short_name under 12 characters to avoid truncation.',
105
+ evidence: {
106
+ found: `${ctx.manifestShortName.length} characters`,
107
+ expected: 'Maximum 12 characters',
108
+ impact: 'Home screen labels are limited to about 12 characters. Longer names will be cut off.'
109
+ }
110
+ });
111
+ }
112
+ return createResult({ id: 'manifest-short-name', name: 'Manifest Short Name', category: 'technical', severity: 'info' }, 'pass', ctx.manifestShortName ? `Short name: ${ctx.manifestShortName}` : 'Using full name (no short_name defined)');
113
+ },
114
+ },
115
+ {
116
+ id: 'manifest-description',
117
+ name: 'Manifest Description',
118
+ category: 'technical',
119
+ severity: 'info',
120
+ description: 'Adding a description helps with app store listings and discoverability',
121
+ check: (ctx) => {
122
+ if (!ctx.hasManifest) {
123
+ return createResult({ id: 'manifest-description', name: 'Manifest Description', category: 'technical', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
124
+ }
125
+ if (!ctx.manifestDescription) {
126
+ return createResult({ id: 'manifest-description', name: 'Manifest Description', category: 'technical', severity: 'info' }, 'info', 'Manifest missing description field', {
127
+ recommendation: 'Add a description to improve app store presence.',
128
+ evidence: {
129
+ expected: '"description": "A brief description of your application"',
130
+ impact: 'The description may appear in app stores, search results, and install prompts. It helps users understand what your app does.',
131
+ example: '"description": "Track your daily tasks and stay productive with our simple to-do app."',
132
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/description'
133
+ }
134
+ });
135
+ }
136
+ return createResult({ id: 'manifest-description', name: 'Manifest Description', category: 'technical', severity: 'info' }, 'pass', 'Manifest has description', { value: ctx.manifestDescription });
137
+ },
138
+ },
139
+ {
140
+ id: 'manifest-icons-required',
141
+ name: 'Required Icons',
142
+ category: 'mobile',
143
+ severity: 'warning',
144
+ description: 'Manifest must include 192x192 and 512x512 icons for PWA installability',
145
+ check: (ctx) => {
146
+ if (!ctx.hasManifest) {
147
+ return createResult({ id: 'manifest-icons-required', name: 'Required Icons', category: 'mobile', severity: 'warning' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
148
+ }
149
+ const sizes = ctx.manifestIconSizes || [];
150
+ const missing = [];
151
+ if (!sizes.includes(192))
152
+ missing.push(192);
153
+ if (!sizes.includes(512))
154
+ missing.push(512);
155
+ if (missing.length > 0) {
156
+ return createResult({ id: 'manifest-icons-required', name: 'Required Icons', category: 'mobile', severity: 'warning' }, 'warn', `Missing required icon sizes: ${missing.map(s => `${s}x${s}`).join(', ')}`, {
157
+ recommendation: 'Add icons in 192x192 and 512x512 sizes.',
158
+ evidence: {
159
+ found: sizes.length > 0 ? sizes.map(s => `${s}x${s}`).join(', ') : 'No icons',
160
+ expected: '192x192 and 512x512 (minimum)',
161
+ impact: 'Chrome requires 192x192 and 512x512 icons to show the "Add to Home Screen" prompt. Without these, your PWA cannot be installed.',
162
+ example: `"icons": [
163
+ { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
164
+ { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" }
165
+ ]`,
166
+ learnMore: 'https://web.dev/articles/install-criteria'
167
+ }
168
+ });
169
+ }
170
+ return createResult({ id: 'manifest-icons-required', name: 'Required Icons', category: 'mobile', severity: 'warning' }, 'pass', `Icons present: ${sizes.map(s => `${s}x${s}`).join(', ')}`);
171
+ },
172
+ },
173
+ {
174
+ id: 'manifest-maskable-icon',
175
+ name: 'Maskable Icon',
176
+ category: 'mobile',
177
+ severity: 'info',
178
+ description: 'Maskable icons adapt to different icon shapes on Android',
179
+ check: (ctx) => {
180
+ if (!ctx.hasManifest) {
181
+ return createResult({ id: 'manifest-maskable-icon', name: 'Maskable Icon', category: 'mobile', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
182
+ }
183
+ if (!ctx.hasMaskableIcon) {
184
+ return createResult({ id: 'manifest-maskable-icon', name: 'Maskable Icon', category: 'mobile', severity: 'info' }, 'info', 'No maskable icon defined', {
185
+ recommendation: 'Add a maskable icon for better Android integration.',
186
+ evidence: {
187
+ expected: 'An icon with "purpose": "maskable" or "purpose": "any maskable"',
188
+ impact: 'Android devices use different icon shapes (circle, rounded square, squircle). Maskable icons ensure your icon looks good in all shapes without being cropped badly.',
189
+ example: `{
190
+ "src": "/icons/icon-maskable.png",
191
+ "sizes": "512x512",
192
+ "type": "image/png",
193
+ "purpose": "maskable"
194
+ }`,
195
+ learnMore: 'https://web.dev/articles/maskable-icon'
196
+ }
197
+ });
198
+ }
199
+ return createResult({ id: 'manifest-maskable-icon', name: 'Maskable Icon', category: 'mobile', severity: 'info' }, 'pass', 'Maskable icon is defined');
200
+ },
201
+ },
202
+ {
203
+ id: 'manifest-display',
204
+ name: 'Display Mode',
205
+ category: 'technical',
206
+ severity: 'warning',
207
+ description: 'Display mode determines how the app UI is presented',
208
+ check: (ctx) => {
209
+ if (!ctx.hasManifest) {
210
+ return createResult({ id: 'manifest-display', name: 'Display Mode', category: 'technical', severity: 'warning' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
211
+ }
212
+ const display = ctx.manifestDisplay;
213
+ if (!display) {
214
+ return createResult({ id: 'manifest-display', name: 'Display Mode', category: 'technical', severity: 'warning' }, 'warn', 'Manifest missing display mode', {
215
+ recommendation: 'Set display mode for app-like experience.',
216
+ evidence: {
217
+ expected: '"display": "standalone"',
218
+ impact: 'Without display mode, the app opens in a regular browser tab. "standalone" removes browser UI for an app-like experience.',
219
+ example: 'Options: fullscreen, standalone, minimal-ui, browser',
220
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/display'
221
+ }
222
+ });
223
+ }
224
+ const validModes = ['fullscreen', 'standalone', 'minimal-ui', 'browser'];
225
+ if (!validModes.includes(display)) {
226
+ return createResult({ id: 'manifest-display', name: 'Display Mode', category: 'technical', severity: 'warning' }, 'warn', `Invalid display mode: ${display}`, {
227
+ value: display,
228
+ recommendation: 'Use a valid display mode.',
229
+ evidence: {
230
+ found: display,
231
+ expected: 'One of: fullscreen, standalone, minimal-ui, browser'
232
+ }
233
+ });
234
+ }
235
+ if (display === 'browser') {
236
+ return createResult({ id: 'manifest-display', name: 'Display Mode', category: 'technical', severity: 'warning' }, 'info', 'Display mode is "browser" (no app-like experience)', {
237
+ recommendation: 'Consider using "standalone" for a more app-like experience.'
238
+ });
239
+ }
240
+ return createResult({ id: 'manifest-display', name: 'Display Mode', category: 'technical', severity: 'warning' }, 'pass', `Display mode: ${display}`);
241
+ },
242
+ },
243
+ {
244
+ id: 'manifest-orientation',
245
+ name: 'Orientation',
246
+ category: 'mobile',
247
+ severity: 'info',
248
+ description: 'Define preferred screen orientation for your app',
249
+ check: (ctx) => {
250
+ if (!ctx.hasManifest) {
251
+ return createResult({ id: 'manifest-orientation', name: 'Orientation', category: 'mobile', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
252
+ }
253
+ if (!ctx.manifestOrientation) {
254
+ return createResult({ id: 'manifest-orientation', name: 'Orientation', category: 'mobile', severity: 'info' }, 'info', 'No orientation preference set', {
255
+ recommendation: 'Set orientation if your app has specific requirements.',
256
+ evidence: {
257
+ expected: '"orientation": "portrait" or "any"',
258
+ impact: 'Useful for games (landscape) or reading apps (portrait). Most apps should use "any" or not specify.',
259
+ example: 'Options: any, natural, landscape, portrait, portrait-primary, portrait-secondary, landscape-primary, landscape-secondary',
260
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/orientation'
261
+ }
262
+ });
263
+ }
264
+ return createResult({ id: 'manifest-orientation', name: 'Orientation', category: 'mobile', severity: 'info' }, 'pass', `Orientation: ${ctx.manifestOrientation}`);
265
+ },
266
+ },
267
+ {
268
+ id: 'manifest-theme-color',
269
+ name: 'Theme Color',
270
+ category: 'mobile',
271
+ severity: 'warning',
272
+ description: 'Theme color customizes browser UI and title bar color',
273
+ check: (ctx) => {
274
+ if (!ctx.hasManifest) {
275
+ return createResult({ id: 'manifest-theme-color', name: 'Theme Color', category: 'mobile', severity: 'warning' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
276
+ }
277
+ const themeColor = ctx.manifestThemeColor || ctx.themeColor;
278
+ if (!themeColor) {
279
+ return createResult({ id: 'manifest-theme-color', name: 'Theme Color', category: 'mobile', severity: 'warning' }, 'warn', 'No theme color defined', {
280
+ recommendation: 'Set theme_color in manifest and meta tag.',
281
+ evidence: {
282
+ expected: '"theme_color": "#4285f4"',
283
+ impact: 'Theme color sets the browser toolbar color on mobile and the title bar in standalone mode. It should match your brand colors.',
284
+ example: '<meta name="theme-color" content="#4285f4">\n// In manifest.json:\n"theme_color": "#4285f4"',
285
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/theme_color'
286
+ }
287
+ });
288
+ }
289
+ if (!isValidColor(themeColor)) {
290
+ return createResult({ id: 'manifest-theme-color', name: 'Theme Color', category: 'mobile', severity: 'warning' }, 'warn', `Invalid theme color format: ${themeColor}`, {
291
+ value: themeColor,
292
+ recommendation: 'Use a valid CSS color format.',
293
+ evidence: {
294
+ found: themeColor,
295
+ expected: 'Hex (#4285f4), rgb, rgba, hsl, or named color'
296
+ }
297
+ });
298
+ }
299
+ return createResult({ id: 'manifest-theme-color', name: 'Theme Color', category: 'mobile', severity: 'warning' }, 'pass', `Theme color: ${themeColor}`);
300
+ },
301
+ },
302
+ {
303
+ id: 'manifest-background-color',
304
+ name: 'Background Color',
305
+ category: 'mobile',
306
+ severity: 'info',
307
+ description: 'Background color is used for the splash screen during app launch',
308
+ check: (ctx) => {
309
+ if (!ctx.hasManifest) {
310
+ return createResult({ id: 'manifest-background-color', name: 'Background Color', category: 'mobile', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
311
+ }
312
+ if (!ctx.manifestBackgroundColor) {
313
+ return createResult({ id: 'manifest-background-color', name: 'Background Color', category: 'mobile', severity: 'info' }, 'info', 'No background color defined', {
314
+ recommendation: 'Set background_color for a smoother launch experience.',
315
+ evidence: {
316
+ expected: '"background_color": "#ffffff"',
317
+ impact: 'The background_color is shown as the splash screen background while your app loads. It should match your app\'s primary background color to avoid a jarring transition.',
318
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/background_color'
319
+ }
320
+ });
321
+ }
322
+ if (!isValidColor(ctx.manifestBackgroundColor)) {
323
+ return createResult({ id: 'manifest-background-color', name: 'Background Color', category: 'mobile', severity: 'info' }, 'info', `Invalid background color format: ${ctx.manifestBackgroundColor}`, {
324
+ value: ctx.manifestBackgroundColor,
325
+ recommendation: 'Use a valid CSS color format.',
326
+ evidence: {
327
+ found: ctx.manifestBackgroundColor,
328
+ expected: 'Hex (#ffffff), rgb, rgba, hsl, or named color'
329
+ }
330
+ });
331
+ }
332
+ return createResult({ id: 'manifest-background-color', name: 'Background Color', category: 'mobile', severity: 'info' }, 'pass', `Background color: ${ctx.manifestBackgroundColor}`);
333
+ },
334
+ },
335
+ {
336
+ id: 'manifest-start-url',
337
+ name: 'Start URL',
338
+ category: 'technical',
339
+ severity: 'warning',
340
+ description: 'start_url defines the entry point when the app is launched',
341
+ check: (ctx) => {
342
+ if (!ctx.hasManifest) {
343
+ return createResult({ id: 'manifest-start-url', name: 'Start URL', category: 'technical', severity: 'warning' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
344
+ }
345
+ if (!ctx.manifestStartUrl) {
346
+ return createResult({ id: 'manifest-start-url', name: 'Start URL', category: 'technical', severity: 'warning' }, 'warn', 'Manifest missing start_url', {
347
+ recommendation: 'Define start_url for consistent app launch behavior.',
348
+ evidence: {
349
+ expected: '"start_url": "/"',
350
+ impact: 'Without start_url, the browser uses the manifest URL as the start page. Using a start_url with a query parameter (e.g., "/?source=pwa") helps track PWA usage in analytics.',
351
+ example: '"start_url": "/?utm_source=pwa&utm_medium=homescreen"',
352
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/start_url'
353
+ }
354
+ });
355
+ }
356
+ return createResult({ id: 'manifest-start-url', name: 'Start URL', category: 'technical', severity: 'warning' }, 'pass', `Start URL: ${ctx.manifestStartUrl}`);
357
+ },
358
+ },
359
+ {
360
+ id: 'manifest-scope',
361
+ name: 'Navigation Scope',
362
+ category: 'technical',
363
+ severity: 'info',
364
+ description: 'scope restricts which URLs are part of the app context',
365
+ check: (ctx) => {
366
+ if (!ctx.hasManifest) {
367
+ return createResult({ id: 'manifest-scope', name: 'Navigation Scope', category: 'technical', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
368
+ }
369
+ if (!ctx.manifestScope) {
370
+ return createResult({ id: 'manifest-scope', name: 'Navigation Scope', category: 'technical', severity: 'info' }, 'info', 'No scope defined (defaults to manifest directory)', {
371
+ recommendation: 'Consider setting scope to control navigation boundaries.',
372
+ evidence: {
373
+ expected: '"scope": "/"',
374
+ impact: 'URLs outside the scope will open in a browser tab instead of the PWA. Default scope is the directory containing the manifest.',
375
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/scope'
376
+ }
377
+ });
378
+ }
379
+ return createResult({ id: 'manifest-scope', name: 'Navigation Scope', category: 'technical', severity: 'info' }, 'pass', `Scope: ${ctx.manifestScope}`);
380
+ },
381
+ },
382
+ {
383
+ id: 'manifest-lang',
384
+ name: 'Manifest Language',
385
+ category: 'i18n',
386
+ severity: 'info',
387
+ description: 'Specify the primary language of the app',
388
+ check: (ctx) => {
389
+ if (!ctx.hasManifest) {
390
+ return createResult({ id: 'manifest-lang', name: 'Manifest Language', category: 'i18n', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
391
+ }
392
+ if (!ctx.manifestLang) {
393
+ return createResult({ id: 'manifest-lang', name: 'Manifest Language', category: 'i18n', severity: 'info' }, 'info', 'No language specified in manifest', {
394
+ recommendation: 'Add lang field for internationalization.',
395
+ evidence: {
396
+ expected: '"lang": "en"',
397
+ impact: 'Helps browsers and assistive technologies understand the app\'s primary language. Important for multilingual apps.',
398
+ example: '"lang": "en-US"\n"lang": "pt-BR"\n"lang": "zh-Hans"',
399
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/lang'
400
+ }
401
+ });
402
+ }
403
+ return createResult({ id: 'manifest-lang', name: 'Manifest Language', category: 'i18n', severity: 'info' }, 'pass', `Language: ${ctx.manifestLang}`);
404
+ },
405
+ },
406
+ {
407
+ id: 'manifest-dir',
408
+ name: 'Text Direction',
409
+ category: 'i18n',
410
+ severity: 'info',
411
+ description: 'Specify text direction for RTL languages',
412
+ check: (ctx) => {
413
+ if (!ctx.hasManifest) {
414
+ return createResult({ id: 'manifest-dir', name: 'Text Direction', category: 'i18n', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
415
+ }
416
+ const rtlLanguages = ['ar', 'he', 'fa', 'ur', 'yi', 'ku', 'ps', 'sd', 'ug'];
417
+ const lang = ctx.manifestLang?.split('-')[0]?.toLowerCase();
418
+ const isRtlLang = lang && rtlLanguages.includes(lang);
419
+ if (isRtlLang && ctx.manifestDir !== 'rtl') {
420
+ return createResult({ id: 'manifest-dir', name: 'Text Direction', category: 'i18n', severity: 'info' }, 'warn', `RTL language detected (${ctx.manifestLang}) but dir is not "rtl"`, {
421
+ recommendation: 'Add dir: "rtl" for right-to-left languages.',
422
+ evidence: {
423
+ found: ctx.manifestDir || 'Not specified',
424
+ expected: '"dir": "rtl"',
425
+ impact: 'Text and UI elements should be right-aligned for RTL languages.'
426
+ }
427
+ });
428
+ }
429
+ if (!ctx.manifestDir) {
430
+ return createResult({ id: 'manifest-dir', name: 'Text Direction', category: 'i18n', severity: 'info' }, 'info', 'No text direction specified (defaults to "auto")', {
431
+ recommendation: 'Consider setting dir for explicit text direction.',
432
+ evidence: {
433
+ expected: '"dir": "ltr" or "rtl" or "auto"',
434
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/dir'
435
+ }
436
+ });
437
+ }
438
+ return createResult({ id: 'manifest-dir', name: 'Text Direction', category: 'i18n', severity: 'info' }, 'pass', `Text direction: ${ctx.manifestDir}`);
439
+ },
440
+ },
441
+ {
442
+ id: 'manifest-categories',
443
+ name: 'App Categories',
444
+ category: 'technical',
445
+ severity: 'info',
446
+ description: 'Categories help with app store discovery',
447
+ check: (ctx) => {
448
+ if (!ctx.hasManifest) {
449
+ return createResult({ id: 'manifest-categories', name: 'App Categories', category: 'technical', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
450
+ }
451
+ if (!ctx.manifestCategories || ctx.manifestCategories.length === 0) {
452
+ return createResult({ id: 'manifest-categories', name: 'App Categories', category: 'technical', severity: 'info' }, 'info', 'No categories defined', {
453
+ recommendation: 'Add categories to improve app store discoverability.',
454
+ evidence: {
455
+ expected: '"categories": ["productivity", "utilities"]',
456
+ impact: 'Categories help users find your app in app stores and browsers that support PWA catalogs.',
457
+ example: 'Common categories: books, business, education, entertainment, finance, fitness, food, games, graphics, health, kids, lifestyle, magazines, medical, music, navigation, news, personalization, photo, politics, productivity, security, shopping, social, sports, travel, utilities, weather',
458
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/categories'
459
+ }
460
+ });
461
+ }
462
+ return createResult({ id: 'manifest-categories', name: 'App Categories', category: 'technical', severity: 'info' }, 'pass', `Categories: ${ctx.manifestCategories.join(', ')}`);
463
+ },
464
+ },
465
+ {
466
+ id: 'manifest-id',
467
+ name: 'App ID',
468
+ category: 'technical',
469
+ severity: 'info',
470
+ description: 'Unique identifier helps with app store listings',
471
+ check: (ctx) => {
472
+ if (!ctx.hasManifest) {
473
+ return createResult({ id: 'manifest-id', name: 'App ID', category: 'technical', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
474
+ }
475
+ if (!ctx.manifestId) {
476
+ return createResult({ id: 'manifest-id', name: 'App ID', category: 'technical', severity: 'info' }, 'info', 'No id field defined', {
477
+ recommendation: 'Add a unique id to identify your app across stores.',
478
+ evidence: {
479
+ expected: '"id": "/?homescreen=1" or "/app/"',
480
+ impact: 'The id field provides a unique identifier for your app. It should remain stable even if start_url changes. App stores use this to identify your app.',
481
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/id'
482
+ }
483
+ });
484
+ }
485
+ return createResult({ id: 'manifest-id', name: 'App ID', category: 'technical', severity: 'info' }, 'pass', `App ID: ${ctx.manifestId}`);
486
+ },
487
+ },
488
+ {
489
+ id: 'manifest-screenshots',
490
+ name: 'App Screenshots',
491
+ category: 'technical',
492
+ severity: 'info',
493
+ description: 'Screenshots enhance the install prompt and app store presence',
494
+ check: (ctx) => {
495
+ if (!ctx.hasManifest) {
496
+ return createResult({ id: 'manifest-screenshots', name: 'App Screenshots', category: 'technical', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
497
+ }
498
+ if (!ctx.manifestScreenshots || ctx.manifestScreenshots.length === 0) {
499
+ return createResult({ id: 'manifest-screenshots', name: 'App Screenshots', category: 'technical', severity: 'info' }, 'info', 'No screenshots defined', {
500
+ recommendation: 'Add screenshots to showcase your app.',
501
+ evidence: {
502
+ expected: '"screenshots": [{ "src": "/screenshots/home.png", "type": "image/png", "sizes": "1280x720" }]',
503
+ impact: 'Screenshots appear in the enhanced install prompt on desktop Chrome and in app stores. They help users understand what your app does before installing.',
504
+ example: `"screenshots": [
505
+ {
506
+ "src": "/screenshots/home.png",
507
+ "type": "image/png",
508
+ "sizes": "1280x720",
509
+ "form_factor": "wide",
510
+ "label": "Home screen"
511
+ }
512
+ ]`,
513
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/screenshots'
514
+ }
515
+ });
516
+ }
517
+ return createResult({ id: 'manifest-screenshots', name: 'App Screenshots', category: 'technical', severity: 'info' }, 'pass', `${ctx.manifestScreenshots.length} screenshot(s) defined`);
518
+ },
519
+ },
520
+ {
521
+ id: 'manifest-shortcuts',
522
+ name: 'App Shortcuts',
523
+ category: 'technical',
524
+ severity: 'info',
525
+ description: 'Shortcuts provide quick access to key features from app icon context menu',
526
+ check: (ctx) => {
527
+ if (!ctx.hasManifest) {
528
+ return createResult({ id: 'manifest-shortcuts', name: 'App Shortcuts', category: 'technical', severity: 'info' }, 'info', 'Not applicable (no manifest)', { recommendation: 'First add a web app manifest' });
529
+ }
530
+ if (!ctx.manifestShortcuts || ctx.manifestShortcuts.length === 0) {
531
+ return createResult({ id: 'manifest-shortcuts', name: 'App Shortcuts', category: 'technical', severity: 'info' }, 'info', 'No shortcuts defined', {
532
+ recommendation: 'Add shortcuts for common user tasks.',
533
+ evidence: {
534
+ expected: '"shortcuts": [{ "name": "New Task", "url": "/new" }]',
535
+ impact: 'Shortcuts appear when users long-press or right-click the app icon. They provide quick access to key app features.',
536
+ example: `"shortcuts": [
537
+ {
538
+ "name": "New Task",
539
+ "short_name": "New",
540
+ "description": "Create a new task",
541
+ "url": "/new?source=shortcut",
542
+ "icons": [{ "src": "/icons/new-task.png", "sizes": "96x96" }]
543
+ }
544
+ ]`,
545
+ learnMore: 'https://developer.mozilla.org/en-US/docs/Web/Manifest/shortcuts'
546
+ }
547
+ });
548
+ }
549
+ return createResult({ id: 'manifest-shortcuts', name: 'App Shortcuts', category: 'technical', severity: 'info' }, 'pass', `${ctx.manifestShortcuts.length} shortcut(s) defined`);
550
+ },
551
+ },
552
+ {
553
+ id: 'manifest-service-worker',
554
+ name: 'Service Worker',
555
+ category: 'technical',
556
+ severity: 'warning',
557
+ description: 'A service worker is required for PWA installability',
558
+ check: (ctx) => {
559
+ if (!ctx.hasServiceWorker) {
560
+ return createResult({ id: 'manifest-service-worker', name: 'Service Worker', category: 'technical', severity: 'warning' }, 'warn', 'No service worker detected', {
561
+ recommendation: 'Register a service worker for PWA installability.',
562
+ evidence: {
563
+ expected: 'A registered service worker',
564
+ impact: 'Service workers are required for PWA installation. They enable offline functionality, push notifications, and background sync. Without one, Chrome won\'t show the install prompt.',
565
+ example: `// In your main JavaScript:
566
+ if ('serviceWorker' in navigator) {
567
+ navigator.serviceWorker.register('/sw.js');
568
+ }`,
569
+ learnMore: 'https://web.dev/articles/service-workers-registration'
570
+ }
571
+ });
572
+ }
573
+ return createResult({ id: 'manifest-service-worker', name: 'Service Worker', category: 'technical', severity: 'warning' }, 'pass', 'Service worker is registered');
574
+ },
575
+ },
576
+ {
577
+ id: 'manifest-installable',
578
+ name: 'PWA Installability',
579
+ category: 'technical',
580
+ severity: 'warning',
581
+ description: 'Check if the app meets minimum PWA installability requirements',
582
+ check: (ctx) => {
583
+ if (!ctx.hasManifest) {
584
+ return createResult({ id: 'manifest-installable', name: 'PWA Installability', category: 'technical', severity: 'warning' }, 'warn', 'Not installable: no manifest', {
585
+ recommendation: 'Add a web app manifest to enable PWA installation.',
586
+ evidence: {
587
+ impact: 'PWA installability requires: manifest, HTTPS, service worker, 192x192 and 512x512 icons, name/short_name, start_url, display (standalone/fullscreen/minimal-ui).',
588
+ learnMore: 'https://web.dev/articles/install-criteria'
589
+ }
590
+ });
591
+ }
592
+ const issues = [];
593
+ if (!ctx.manifestName && !ctx.manifestShortName)
594
+ issues.push('name or short_name');
595
+ if (!ctx.manifestStartUrl)
596
+ issues.push('start_url');
597
+ if (!ctx.manifestDisplay || !['standalone', 'fullscreen', 'minimal-ui'].includes(ctx.manifestDisplay)) {
598
+ issues.push('display (standalone/fullscreen/minimal-ui)');
599
+ }
600
+ const sizes = ctx.manifestIconSizes || [];
601
+ if (!sizes.includes(192))
602
+ issues.push('192x192 icon');
603
+ if (!sizes.includes(512))
604
+ issues.push('512x512 icon');
605
+ if (!ctx.hasServiceWorker)
606
+ issues.push('service worker');
607
+ if (issues.length > 0) {
608
+ return createResult({ id: 'manifest-installable', name: 'PWA Installability', category: 'technical', severity: 'warning' }, 'warn', `Missing requirements for installability: ${issues.join(', ')}`, {
609
+ recommendation: 'Address the missing requirements to make your app installable.',
610
+ evidence: {
611
+ found: `Missing: ${issues.join(', ')}`,
612
+ expected: 'All PWA installability requirements met',
613
+ impact: 'Users cannot install your app to their home screen without meeting these requirements.',
614
+ learnMore: 'https://web.dev/articles/install-criteria'
615
+ }
616
+ });
617
+ }
618
+ return createResult({ id: 'manifest-installable', name: 'PWA Installability', category: 'technical', severity: 'warning' }, 'pass', 'App meets PWA installability requirements');
619
+ },
620
+ },
621
+ ];