@taodigital/crawler 0.0.0-stage → 1.2.1

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 (494) hide show
  1. package/Dockerfile +82 -0
  2. package/README.md +10 -2
  3. package/dist/accessibility-auditor.d.ts +29 -0
  4. package/dist/accessibility-auditor.js +57 -0
  5. package/dist/accessibility-auditor.js.map +7 -0
  6. package/dist/accessibility-tree-crawler.d.ts +44 -0
  7. package/dist/accessibility-tree-crawler.js +156 -0
  8. package/dist/accessibility-tree-crawler.js.map +7 -0
  9. package/dist/advanced-ui-probes.d.ts +47 -0
  10. package/dist/advanced-ui-probes.js +310 -0
  11. package/dist/advanced-ui-probes.js.map +7 -0
  12. package/dist/ai-login.d.ts +32 -0
  13. package/dist/ai-login.js +250 -0
  14. package/dist/ai-login.js.map +7 -0
  15. package/dist/auth-token-rotator.d.ts +47 -0
  16. package/dist/auth-token-rotator.js +58 -0
  17. package/dist/auth-token-rotator.js.map +7 -0
  18. package/dist/auth.d.ts +20 -0
  19. package/dist/auth.js +348 -0
  20. package/dist/auth.js.map +7 -0
  21. package/dist/browser-extension.d.ts +37 -0
  22. package/dist/browser-extension.js +113 -0
  23. package/dist/browser-extension.js.map +7 -0
  24. package/dist/captcha-solver.d.ts +16 -0
  25. package/dist/captcha-solver.js +105 -0
  26. package/dist/captcha-solver.js.map +7 -0
  27. package/dist/color-contrast.d.ts +30 -0
  28. package/dist/color-contrast.js +78 -0
  29. package/dist/color-contrast.js.map +7 -0
  30. package/dist/content-chunker.d.ts +18 -0
  31. package/dist/content-chunker.js +152 -0
  32. package/dist/content-chunker.js.map +7 -0
  33. package/dist/content-dedup.d.ts +23 -0
  34. package/dist/content-dedup.js +60 -0
  35. package/dist/content-dedup.js.map +7 -0
  36. package/dist/cookie-consent.d.ts +25 -0
  37. package/dist/cookie-consent.js +78 -0
  38. package/dist/cookie-consent.js.map +7 -0
  39. package/dist/cookie-jar.d.ts +20 -0
  40. package/dist/cookie-jar.js +61 -0
  41. package/dist/cookie-jar.js.map +7 -0
  42. package/dist/crawl-session-manager.d.ts +44 -0
  43. package/dist/crawl-session-manager.js +145 -0
  44. package/dist/crawl-session-manager.js.map +7 -0
  45. package/dist/crawler.d.ts +233 -0
  46. package/dist/crawler.js +6239 -0
  47. package/dist/crawler.js.map +7 -0
  48. package/dist/crud-interaction.d.ts +31 -0
  49. package/dist/crud-interaction.js +264 -0
  50. package/dist/crud-interaction.js.map +7 -0
  51. package/dist/custom-js-injector.d.ts +42 -0
  52. package/dist/custom-js-injector.js +50 -0
  53. package/dist/custom-js-injector.js.map +7 -0
  54. package/dist/dark-mode-capture.d.ts +23 -0
  55. package/dist/dark-mode-capture.js +75 -0
  56. package/dist/dark-mode-capture.js.map +7 -0
  57. package/dist/dead-link-detector.d.ts +37 -0
  58. package/dist/dead-link-detector.js +50 -0
  59. package/dist/dead-link-detector.js.map +7 -0
  60. package/dist/dropdown-enumerator.d.ts +20 -0
  61. package/dist/dropdown-enumerator.js +230 -0
  62. package/dist/dropdown-enumerator.js.map +7 -0
  63. package/dist/element-hash.d.ts +9 -0
  64. package/dist/element-hash.js +9 -0
  65. package/dist/element-hash.js.map +7 -0
  66. package/dist/email-otp.d.ts +42 -0
  67. package/dist/email-otp.js +177 -0
  68. package/dist/email-otp.js.map +7 -0
  69. package/dist/engine-router.d.ts +47 -0
  70. package/dist/engine-router.js +94 -0
  71. package/dist/engine-router.js.map +7 -0
  72. package/dist/export/bulk-export.d.ts +26 -0
  73. package/dist/export/bulk-export.js +76 -0
  74. package/dist/export/bulk-export.js.map +7 -0
  75. package/dist/export/vector-export.d.ts +76 -0
  76. package/dist/export/vector-export.js +85 -0
  77. package/dist/export/vector-export.js.map +7 -0
  78. package/dist/extractors/advanced.d.ts +64 -0
  79. package/dist/extractors/advanced.js +265 -0
  80. package/dist/extractors/advanced.js.map +7 -0
  81. package/dist/extractors/artifact-envelope.d.ts +63 -0
  82. package/dist/extractors/artifact-envelope.js +63 -0
  83. package/dist/extractors/artifact-envelope.js.map +7 -0
  84. package/dist/extractors/branding-extractor.d.ts +46 -0
  85. package/dist/extractors/branding-extractor.js +104 -0
  86. package/dist/extractors/branding-extractor.js.map +7 -0
  87. package/dist/extractors/summary-extractor.d.ts +10 -0
  88. package/dist/extractors/summary-extractor.js +36 -0
  89. package/dist/extractors/summary-extractor.js.map +7 -0
  90. package/dist/failure-analysis-agent.d.ts +16 -0
  91. package/dist/failure-analysis-agent.js +42 -0
  92. package/dist/failure-analysis-agent.js.map +7 -0
  93. package/dist/feature-flag-detector.d.ts +30 -0
  94. package/dist/feature-flag-detector.js +55 -0
  95. package/dist/feature-flag-detector.js.map +7 -0
  96. package/dist/filter-pagination-crawler.d.ts +52 -0
  97. package/dist/filter-pagination-crawler.js +299 -0
  98. package/dist/filter-pagination-crawler.js.map +7 -0
  99. package/dist/form-detector.d.ts +34 -0
  100. package/dist/form-detector.js +58 -0
  101. package/dist/form-detector.js.map +7 -0
  102. package/dist/frontier.d.ts +40 -0
  103. package/dist/frontier.js +103 -0
  104. package/dist/frontier.js.map +7 -0
  105. package/dist/gap-pass.d.ts +36 -0
  106. package/dist/gap-pass.js +115 -0
  107. package/dist/gap-pass.js.map +7 -0
  108. package/dist/graphql-detector.d.ts +39 -0
  109. package/dist/graphql-detector.js +86 -0
  110. package/dist/graphql-detector.js.map +7 -0
  111. package/dist/http-engine.d.ts +80 -0
  112. package/dist/http-engine.js +318 -0
  113. package/dist/http-engine.js.map +7 -0
  114. package/dist/incremental-diff.d.ts +116 -0
  115. package/dist/incremental-diff.js +137 -0
  116. package/dist/incremental-diff.js.map +7 -0
  117. package/dist/index.d.ts +52 -0
  118. package/dist/index.js +83 -0
  119. package/dist/index.js.map +7 -0
  120. package/dist/input-fuzzer.d.ts +30 -0
  121. package/dist/input-fuzzer.js +105 -0
  122. package/dist/input-fuzzer.js.map +7 -0
  123. package/dist/interactive-probe.d.ts +144 -0
  124. package/dist/interactive-probe.js +865 -0
  125. package/dist/interactive-probe.js.map +7 -0
  126. package/dist/job-queue.d.ts +297 -0
  127. package/dist/job-queue.js +3812 -0
  128. package/dist/job-queue.js.map +7 -0
  129. package/dist/js-coverage.d.ts +29 -0
  130. package/dist/js-coverage.js +56 -0
  131. package/dist/js-coverage.js.map +7 -0
  132. package/dist/js-router-detector.d.ts +17 -0
  133. package/dist/js-router-detector.js +90 -0
  134. package/dist/js-router-detector.js.map +7 -0
  135. package/dist/language-detector.d.ts +22 -0
  136. package/dist/language-detector.js +57 -0
  137. package/dist/language-detector.js.map +7 -0
  138. package/dist/link-classifier.d.ts +23 -0
  139. package/dist/link-classifier.js +40 -0
  140. package/dist/link-classifier.js.map +7 -0
  141. package/dist/live-view.d.ts +36 -0
  142. package/dist/live-view.js +105 -0
  143. package/dist/live-view.js.map +7 -0
  144. package/dist/locator-extractor.d.ts +46 -0
  145. package/dist/locator-extractor.js +220 -0
  146. package/dist/locator-extractor.js.map +7 -0
  147. package/dist/logger.d.ts +2 -0
  148. package/dist/logger.js +10 -0
  149. package/dist/logger.js.map +7 -0
  150. package/dist/markdown-extract.d.ts +8 -0
  151. package/dist/markdown-extract.js +54 -0
  152. package/dist/markdown-extract.js.map +7 -0
  153. package/dist/multi-context-handler.d.ts +55 -0
  154. package/dist/multi-context-handler.js +182 -0
  155. package/dist/multi-context-handler.js.map +7 -0
  156. package/dist/native-crawler.d.ts +69 -0
  157. package/dist/native-crawler.js +839 -0
  158. package/dist/native-crawler.js.map +7 -0
  159. package/dist/nested-window-crawler.d.ts +41 -0
  160. package/dist/nested-window-crawler.js +172 -0
  161. package/dist/nested-window-crawler.js.map +7 -0
  162. package/dist/network-action-correlator.d.ts +47 -0
  163. package/dist/network-action-correlator.js +209 -0
  164. package/dist/network-action-correlator.js.map +7 -0
  165. package/dist/network-observer.d.ts +49 -0
  166. package/dist/network-observer.js +149 -0
  167. package/dist/network-observer.js.map +7 -0
  168. package/dist/network-throttle.d.ts +25 -0
  169. package/dist/network-throttle.js +34 -0
  170. package/dist/network-throttle.js.map +7 -0
  171. package/dist/openapi-generator.d.ts +49 -0
  172. package/dist/openapi-generator.js +89 -0
  173. package/dist/openapi-generator.js.map +7 -0
  174. package/dist/pdf-extractor.d.ts +28 -0
  175. package/dist/pdf-extractor.js +81 -0
  176. package/dist/pdf-extractor.js.map +7 -0
  177. package/dist/performance-metrics-collector.d.ts +50 -0
  178. package/dist/performance-metrics-collector.js +155 -0
  179. package/dist/performance-metrics-collector.js.map +7 -0
  180. package/dist/performance-metrics.d.ts +52 -0
  181. package/dist/performance-metrics.js +83 -0
  182. package/dist/performance-metrics.js.map +7 -0
  183. package/dist/phash.d.ts +50 -0
  184. package/dist/phash.js +136 -0
  185. package/dist/phash.js.map +7 -0
  186. package/dist/pii-scrubber.d.ts +21 -0
  187. package/dist/pii-scrubber.js +75 -0
  188. package/dist/pii-scrubber.js.map +7 -0
  189. package/dist/playwright-recorder.d.ts +39 -0
  190. package/dist/playwright-recorder.js +123 -0
  191. package/dist/playwright-recorder.js.map +7 -0
  192. package/dist/policies/crawl-safety.d.ts +9 -0
  193. package/dist/policies/crawl-safety.js +41 -0
  194. package/dist/policies/crawl-safety.js.map +7 -0
  195. package/dist/profiles/domain-profile.d.ts +19 -0
  196. package/dist/profiles/domain-profile.js +160 -0
  197. package/dist/profiles/domain-profile.js.map +7 -0
  198. package/dist/proxy.d.ts +50 -0
  199. package/dist/proxy.js +165 -0
  200. package/dist/proxy.js.map +7 -0
  201. package/dist/rate-limiter.d.ts +31 -0
  202. package/dist/rate-limiter.js +64 -0
  203. package/dist/rate-limiter.js.map +7 -0
  204. package/dist/redirect-tracker.d.ts +37 -0
  205. package/dist/redirect-tracker.js +65 -0
  206. package/dist/redirect-tracker.js.map +7 -0
  207. package/dist/redis-frontier.d.ts +48 -0
  208. package/dist/redis-frontier.js +126 -0
  209. package/dist/redis-frontier.js.map +7 -0
  210. package/dist/redis-queue.d.ts +48 -0
  211. package/dist/redis-queue.js +165 -0
  212. package/dist/redis-queue.js.map +7 -0
  213. package/dist/response-cache.d.ts +38 -0
  214. package/dist/response-cache.js +140 -0
  215. package/dist/response-cache.js.map +7 -0
  216. package/dist/responsive-detector.d.ts +29 -0
  217. package/dist/responsive-detector.js +46 -0
  218. package/dist/responsive-detector.js.map +7 -0
  219. package/dist/retry-policy.d.ts +20 -0
  220. package/dist/retry-policy.js +54 -0
  221. package/dist/retry-policy.js.map +7 -0
  222. package/dist/robots-txt.d.ts +9 -0
  223. package/dist/robots-txt.js +77 -0
  224. package/dist/robots-txt.js.map +7 -0
  225. package/dist/screen-reader.d.ts +15 -0
  226. package/dist/screen-reader.js +48 -0
  227. package/dist/screen-reader.js.map +7 -0
  228. package/dist/screenshot-masker.d.ts +28 -0
  229. package/dist/screenshot-masker.js +62 -0
  230. package/dist/screenshot-masker.js.map +7 -0
  231. package/dist/seo-checker.d.ts +33 -0
  232. package/dist/seo-checker.js +91 -0
  233. package/dist/seo-checker.js.map +7 -0
  234. package/dist/service-worker-interceptor.d.ts +36 -0
  235. package/dist/service-worker-interceptor.js +136 -0
  236. package/dist/service-worker-interceptor.js.map +7 -0
  237. package/dist/session-capture.d.ts +39 -0
  238. package/dist/session-capture.js +274 -0
  239. package/dist/session-capture.js.map +7 -0
  240. package/dist/session-export.d.ts +49 -0
  241. package/dist/session-export.js +117 -0
  242. package/dist/session-export.js.map +7 -0
  243. package/dist/shadow-dom-crawler.d.ts +35 -0
  244. package/dist/shadow-dom-crawler.js +132 -0
  245. package/dist/shadow-dom-crawler.js.map +7 -0
  246. package/dist/sitemap-writer.d.ts +21 -0
  247. package/dist/sitemap-writer.js +47 -0
  248. package/dist/sitemap-writer.js.map +7 -0
  249. package/dist/sitemap.d.ts +51 -0
  250. package/dist/sitemap.js +160 -0
  251. package/dist/sitemap.js.map +7 -0
  252. package/dist/skyvern.d.ts +56 -0
  253. package/dist/skyvern.js +129 -0
  254. package/dist/skyvern.js.map +7 -0
  255. package/dist/sqs-queue.d.ts +13 -0
  256. package/dist/sqs-queue.js +115 -0
  257. package/dist/sqs-queue.js.map +7 -0
  258. package/dist/sso-token.d.ts +29 -0
  259. package/dist/sso-token.js +76 -0
  260. package/dist/sso-token.js.map +7 -0
  261. package/dist/state-graph.d.ts +59 -0
  262. package/dist/state-graph.js +193 -0
  263. package/dist/state-graph.js.map +7 -0
  264. package/dist/stealth/human-behavior.d.ts +20 -0
  265. package/dist/stealth/human-behavior.js +202 -0
  266. package/dist/stealth/human-behavior.js.map +7 -0
  267. package/dist/telemetry.d.ts +34 -0
  268. package/dist/telemetry.js +77 -0
  269. package/dist/telemetry.js.map +7 -0
  270. package/dist/test-executor.d.ts +81 -0
  271. package/dist/test-executor.js +443 -0
  272. package/dist/test-executor.js.map +7 -0
  273. package/dist/tls-fingerprint.d.ts +50 -0
  274. package/dist/tls-fingerprint.js +81 -0
  275. package/dist/tls-fingerprint.js.map +7 -0
  276. package/dist/url-pattern-completer.d.ts +28 -0
  277. package/dist/url-pattern-completer.js +122 -0
  278. package/dist/url-pattern-completer.js.map +7 -0
  279. package/dist/visual-diff-verdict.d.ts +40 -0
  280. package/dist/visual-diff-verdict.js +27 -0
  281. package/dist/visual-diff-verdict.js.map +7 -0
  282. package/dist/webhook-notifier.d.ts +30 -0
  283. package/dist/webhook-notifier.js +76 -0
  284. package/dist/webhook-notifier.js.map +7 -0
  285. package/dist/websocket-detector.d.ts +24 -0
  286. package/dist/websocket-detector.js +60 -0
  287. package/dist/websocket-detector.js.map +7 -0
  288. package/dist/worker.d.ts +1 -0
  289. package/dist/worker.js +33 -0
  290. package/dist/worker.js.map +7 -0
  291. package/package.json +49 -4
  292. package/src/accessibility-auditor.ts +102 -0
  293. package/src/accessibility-tree-crawler.ts +246 -0
  294. package/src/advanced-ui-probes.ts +470 -0
  295. package/src/ai-login.ts +298 -0
  296. package/src/auth-token-rotator.ts +89 -0
  297. package/src/auth.ts +418 -0
  298. package/src/browser-extension.ts +186 -0
  299. package/src/captcha-solver.ts +143 -0
  300. package/src/color-contrast.ts +116 -0
  301. package/src/content-chunker.ts +170 -0
  302. package/src/content-dedup.ts +99 -0
  303. package/src/cookie-consent.ts +106 -0
  304. package/src/cookie-jar.ts +91 -0
  305. package/src/crawl-session-manager.ts +231 -0
  306. package/src/crawler.ts +7123 -0
  307. package/src/crawler.ts.rej +12 -0
  308. package/src/crud-interaction.ts +386 -0
  309. package/src/custom-js-injector.ts +93 -0
  310. package/src/dark-mode-capture.ts +110 -0
  311. package/src/dead-link-detector.ts +76 -0
  312. package/src/dropdown-enumerator.ts +312 -0
  313. package/src/element-hash.ts +16 -0
  314. package/src/email-otp.ts +252 -0
  315. package/src/engine-router.ts +141 -0
  316. package/src/export/bulk-export.ts +85 -0
  317. package/src/export/vector-export.ts +160 -0
  318. package/src/extractors/advanced.ts +309 -0
  319. package/src/extractors/artifact-envelope.ts +111 -0
  320. package/src/extractors/branding-extractor.ts +159 -0
  321. package/src/extractors/summary-extractor.ts +49 -0
  322. package/src/failure-analysis-agent.ts +51 -0
  323. package/src/feature-flag-detector.ts +97 -0
  324. package/src/filter-pagination-crawler.ts +500 -0
  325. package/src/form-detector.ts +103 -0
  326. package/src/frontier.test.ts +64 -0
  327. package/src/frontier.ts +144 -0
  328. package/src/gap-pass.ts +165 -0
  329. package/src/graphql-detector.ts +129 -0
  330. package/src/http-engine.ts +453 -0
  331. package/src/incremental-diff.ts +259 -0
  332. package/src/index.ts +52 -0
  333. package/src/input-fuzzer.ts +129 -0
  334. package/src/interactive-probe.ts +1136 -0
  335. package/src/job-queue.test.ts +187 -0
  336. package/src/job-queue.ts +4504 -0
  337. package/src/js-coverage.ts +87 -0
  338. package/src/js-router-detector.ts +112 -0
  339. package/src/language-detector.ts +82 -0
  340. package/src/link-classifier.ts +65 -0
  341. package/src/live-view.ts +146 -0
  342. package/src/locator-extractor.ts +309 -0
  343. package/src/logger.ts +9 -0
  344. package/src/markdown-extract.test.ts +73 -0
  345. package/src/markdown-extract.ts +76 -0
  346. package/src/multi-context-handler.ts +296 -0
  347. package/src/native-crawler.ts +1108 -0
  348. package/src/nested-window-crawler.ts +310 -0
  349. package/src/network-action-correlator.ts +320 -0
  350. package/src/network-observer.ts +204 -0
  351. package/src/network-throttle.ts +69 -0
  352. package/src/openapi-generator.ts +135 -0
  353. package/src/pdf-extractor.ts +123 -0
  354. package/src/performance-metrics-collector.ts +243 -0
  355. package/src/performance-metrics.ts +134 -0
  356. package/src/phash.ts +184 -0
  357. package/src/pii-scrubber.ts +99 -0
  358. package/src/playwright-recorder.ts +170 -0
  359. package/src/policies/crawl-safety.ts +52 -0
  360. package/src/profiles/domain-profile.ts +190 -0
  361. package/src/proxy.ts +238 -0
  362. package/src/rate-limiter.ts +87 -0
  363. package/src/redirect-tracker.ts +97 -0
  364. package/src/redis-frontier.ts +143 -0
  365. package/src/redis-queue.ts +208 -0
  366. package/src/response-cache.ts +150 -0
  367. package/src/responsive-detector.ts +92 -0
  368. package/src/retry-policy.ts +87 -0
  369. package/src/robots-txt.ts +96 -0
  370. package/src/screen-reader.ts +98 -0
  371. package/src/screenshot-masker.ts +98 -0
  372. package/src/seo-checker.ts +134 -0
  373. package/src/service-worker-interceptor.ts +185 -0
  374. package/src/session-capture.ts +335 -0
  375. package/src/session-export.test.ts +75 -0
  376. package/src/session-export.ts +172 -0
  377. package/src/shadow-dom-crawler.ts +198 -0
  378. package/src/sitemap-writer.ts +65 -0
  379. package/src/sitemap.test.ts +127 -0
  380. package/src/sitemap.ts +233 -0
  381. package/src/skyvern.ts +199 -0
  382. package/src/sqs-queue.ts +129 -0
  383. package/src/sso-token.ts +120 -0
  384. package/src/state-graph.ts +280 -0
  385. package/src/stealth/human-behavior.ts +227 -0
  386. package/src/telemetry.ts +122 -0
  387. package/src/test-executor.test.ts +72 -0
  388. package/src/test-executor.ts +578 -0
  389. package/src/tls-fingerprint.ts +111 -0
  390. package/src/url-pattern-completer.ts +161 -0
  391. package/src/vendor.d.ts +20 -0
  392. package/src/visual-diff-verdict.test.ts +80 -0
  393. package/src/visual-diff-verdict.ts +59 -0
  394. package/src/webhook-notifier.ts +109 -0
  395. package/src/websocket-detector.ts +83 -0
  396. package/src/worker.ts +50 -0
  397. package/tsconfig.json +13 -0
  398. package/types/accessibility-auditor.d.ts +29 -0
  399. package/types/accessibility-tree-crawler.d.ts +44 -0
  400. package/types/advanced-ui-probes.d.ts +47 -0
  401. package/types/ai-login.d.ts +32 -0
  402. package/types/auth-token-rotator.d.ts +47 -0
  403. package/types/auth.d.ts +20 -0
  404. package/types/browser-extension.d.ts +37 -0
  405. package/types/bull-worker.d.ts +6 -0
  406. package/types/captcha-solver.d.ts +16 -0
  407. package/types/color-contrast.d.ts +30 -0
  408. package/types/content-chunker.d.ts +18 -0
  409. package/types/content-dedup.d.ts +23 -0
  410. package/types/cookie-consent.d.ts +25 -0
  411. package/types/cookie-jar.d.ts +20 -0
  412. package/types/crawl-session-manager.d.ts +44 -0
  413. package/types/crawler.d.ts +233 -0
  414. package/types/crud-interaction.d.ts +31 -0
  415. package/types/custom-js-injector.d.ts +42 -0
  416. package/types/dark-mode-capture.d.ts +23 -0
  417. package/types/dead-link-detector.d.ts +37 -0
  418. package/types/dropdown-enumerator.d.ts +20 -0
  419. package/types/element-hash.d.ts +9 -0
  420. package/types/email-otp.d.ts +42 -0
  421. package/types/engine-router.d.ts +47 -0
  422. package/types/export/bulk-export.d.ts +26 -0
  423. package/types/export/vector-export.d.ts +76 -0
  424. package/types/extractors/advanced.d.ts +64 -0
  425. package/types/extractors/artifact-envelope.d.ts +63 -0
  426. package/types/extractors/branding-extractor.d.ts +46 -0
  427. package/types/extractors/summary-extractor.d.ts +10 -0
  428. package/types/failure-analysis-agent.d.ts +16 -0
  429. package/types/feature-flag-detector.d.ts +30 -0
  430. package/types/filter-pagination-crawler.d.ts +52 -0
  431. package/types/form-detector.d.ts +34 -0
  432. package/types/frontier.d.ts +40 -0
  433. package/types/gap-pass.d.ts +36 -0
  434. package/types/graphql-detector.d.ts +39 -0
  435. package/types/http-engine.d.ts +80 -0
  436. package/types/incremental-diff.d.ts +116 -0
  437. package/types/index.d.ts +52 -0
  438. package/types/input-fuzzer.d.ts +30 -0
  439. package/types/interactive-probe.d.ts +144 -0
  440. package/types/job-queue.d.ts +308 -0
  441. package/types/js-coverage.d.ts +29 -0
  442. package/types/js-router-detector.d.ts +17 -0
  443. package/types/language-detector.d.ts +22 -0
  444. package/types/link-classifier.d.ts +23 -0
  445. package/types/live-view.d.ts +36 -0
  446. package/types/locator-extractor.d.ts +46 -0
  447. package/types/logger.d.ts +2 -0
  448. package/types/markdown-extract.d.ts +8 -0
  449. package/types/multi-context-handler.d.ts +55 -0
  450. package/types/native-crawler.d.ts +69 -0
  451. package/types/nested-window-crawler.d.ts +41 -0
  452. package/types/network-action-correlator.d.ts +47 -0
  453. package/types/network-observer.d.ts +49 -0
  454. package/types/network-throttle.d.ts +25 -0
  455. package/types/openapi-generator.d.ts +49 -0
  456. package/types/pdf-extractor.d.ts +28 -0
  457. package/types/performance-metrics-collector.d.ts +50 -0
  458. package/types/performance-metrics.d.ts +52 -0
  459. package/types/phash.d.ts +50 -0
  460. package/types/pii-scrubber.d.ts +21 -0
  461. package/types/playwright-recorder.d.ts +39 -0
  462. package/types/policies/crawl-safety.d.ts +9 -0
  463. package/types/profiles/domain-profile.d.ts +19 -0
  464. package/types/proxy.d.ts +50 -0
  465. package/types/rate-limiter.d.ts +31 -0
  466. package/types/redirect-tracker.d.ts +37 -0
  467. package/types/redis-frontier.d.ts +48 -0
  468. package/types/redis-queue.d.ts +48 -0
  469. package/types/response-cache.d.ts +38 -0
  470. package/types/responsive-detector.d.ts +29 -0
  471. package/types/retry-policy.d.ts +20 -0
  472. package/types/robots-txt.d.ts +9 -0
  473. package/types/screen-reader.d.ts +15 -0
  474. package/types/screenshot-masker.d.ts +28 -0
  475. package/types/seo-checker.d.ts +33 -0
  476. package/types/service-worker-interceptor.d.ts +36 -0
  477. package/types/session-capture.d.ts +39 -0
  478. package/types/session-export.d.ts +49 -0
  479. package/types/shadow-dom-crawler.d.ts +35 -0
  480. package/types/sitemap-writer.d.ts +21 -0
  481. package/types/sitemap.d.ts +51 -0
  482. package/types/skyvern.d.ts +56 -0
  483. package/types/sqs-queue.d.ts +13 -0
  484. package/types/sso-token.d.ts +29 -0
  485. package/types/state-graph.d.ts +59 -0
  486. package/types/stealth/human-behavior.d.ts +20 -0
  487. package/types/telemetry.d.ts +34 -0
  488. package/types/test-executor.d.ts +84 -0
  489. package/types/tls-fingerprint.d.ts +50 -0
  490. package/types/url-pattern-completer.d.ts +28 -0
  491. package/types/visual-diff-verdict.d.ts +40 -0
  492. package/types/webhook-notifier.d.ts +30 -0
  493. package/types/websocket-detector.d.ts +24 -0
  494. package/types/worker.d.ts +1 -0
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Playwright test recorder — generate Playwright test code from crawl data.
3
+ *
4
+ * Given a list of crawled screens, generates a minimal Playwright test file that:
5
+ * 1. Navigates to each screen URL
6
+ * 2. Verifies the page title
7
+ * 3. Checks key elements visible on the page
8
+ * 4. Verifies no console errors (optional)
9
+ *
10
+ * This is a "smoke test" generator — not a full interaction recorder.
11
+ * Output: valid TypeScript Playwright test file ready to run with npx playwright test.
12
+ */
13
+
14
+ export interface RecorderScreen {
15
+ id: string;
16
+ name: string;
17
+ url: string;
18
+ title?: string;
19
+ heading?: string;
20
+ markdownWordCount?: number;
21
+ smartLocator?: {
22
+ tag: string; // e.g. 'button', 'a', 'input'
23
+ text?: string; // visible text content
24
+ role?: string; // ARIA role
25
+ placeholder?: string; // for inputs
26
+ nearText?: string; // nearby label text
27
+ };
28
+ }
29
+
30
+ export interface RecorderOpts {
31
+ baseUrl?: string;
32
+ includeConsoleCheck?: boolean;
33
+ testTimeout?: number; // ms, default 30000
34
+ projectName?: string;
35
+ useSmartLocators?: boolean; // default true
36
+ }
37
+
38
+ function buildSmartLocatorHelper(): string {
39
+ return `
40
+ // smartLocator — falls back to similarity search when primary selector fails.
41
+ // Generated by ZeTa Crawler. Do not edit manually.
42
+ async function smartLocator(page: any, primary: string, ref: { tag?: string; text?: string; role?: string; placeholder?: string }) {
43
+ try {
44
+ const el = page.locator(primary);
45
+ if (await el.count() > 0) return el;
46
+ } catch { /* fall through */ }
47
+ // Fallback: find by ARIA role + text
48
+ if (ref.role && ref.text) {
49
+ const byRole = page.getByRole(ref.role as any, { name: ref.text, exact: false });
50
+ if (await byRole.count() > 0) return byRole;
51
+ }
52
+ // Fallback: find by text content
53
+ if (ref.text) {
54
+ const byText = page.getByText(ref.text, { exact: false });
55
+ if (await byText.count() > 0) return byText;
56
+ }
57
+ // Fallback: find by placeholder
58
+ if (ref.placeholder) {
59
+ const byPlaceholder = page.getByPlaceholder(ref.placeholder, { exact: false });
60
+ if (await byPlaceholder.count() > 0) return byPlaceholder;
61
+ }
62
+ // Last resort: return the primary (will fail with original error)
63
+ return page.locator(primary);
64
+ }`.trim();
65
+ }
66
+
67
+ function sanitizeTestName(name: string): string {
68
+ return name.replace(/[^a-zA-Z0-9 _-]/g, '').trim().slice(0, 80) || 'Screen';
69
+ }
70
+
71
+ function escapeString(s: string): string {
72
+ return s.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/`/g, '\\`');
73
+ }
74
+
75
+ export function generatePlaywrightTest(screens: RecorderScreen[], opts: RecorderOpts = {}): string {
76
+ const {
77
+ includeConsoleCheck = false,
78
+ testTimeout = 30_000,
79
+ projectName = 'ZeTa Crawl',
80
+ useSmartLocators = true,
81
+ } = opts;
82
+
83
+ const needsSmartLocator = useSmartLocators && screens.some(s => s.smartLocator != null);
84
+
85
+ const lines: string[] = [
86
+ `// Generated by ZeTa Crawler — ${new Date().toISOString()}`,
87
+ `// Project: ${escapeString(projectName)}`,
88
+ `// Screens: ${screens.length}`,
89
+ `// Run: npx playwright test`,
90
+ '',
91
+ "import { test, expect } from '@playwright/test';",
92
+ '',
93
+ ];
94
+
95
+ if (needsSmartLocator) {
96
+ lines.push(buildSmartLocatorHelper(), '');
97
+ }
98
+
99
+ lines.push(`test.setTimeout(${testTimeout});`, '');
100
+
101
+ if (includeConsoleCheck) {
102
+ lines.push(
103
+ `test.beforeEach(async ({ page }) => {`,
104
+ ` const errors: string[] = [];`,
105
+ ` page.on('console', msg => { if (msg.type() === 'error') errors.push(msg.text()); });`,
106
+ ` page.on('pageerror', err => errors.push(err.message));`,
107
+ ` (page as any).__consoleErrors = errors;`,
108
+ `});`,
109
+ '',
110
+ );
111
+ }
112
+
113
+ for (const screen of screens) {
114
+ const testName = sanitizeTestName(screen.name);
115
+ lines.push(
116
+ `test('${escapeString(testName)}', async ({ page }) => {`,
117
+ ` await page.goto('${escapeString(screen.url)}');`,
118
+ ` await expect(page).toHaveURL(/${escapeString(screen.url.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))}/);`,
119
+ );
120
+
121
+ if (screen.title) {
122
+ lines.push(` await expect(page).toHaveTitle(/${escapeString(screen.title.slice(0, 40).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))}/i);`);
123
+ }
124
+
125
+ if (screen.heading) {
126
+ const h = escapeString(screen.heading.slice(0, 60));
127
+ if (needsSmartLocator && screen.smartLocator) {
128
+ const tag = escapeString(screen.smartLocator.tag);
129
+ const text = escapeString(screen.smartLocator.text ?? '');
130
+ lines.push(
131
+ ` const headingEl = await smartLocator(page, 'h1, h2, h3', { tag: '${tag}', text: '${text}' });`,
132
+ ` await expect(headingEl.first()).toContainText('${h}', { ignoreCase: true });`,
133
+ );
134
+ } else {
135
+ lines.push(` await expect(page.locator('h1, h2, h3').first()).toContainText('${h}', { ignoreCase: true });`);
136
+ }
137
+ }
138
+
139
+ if (includeConsoleCheck) {
140
+ lines.push(` expect((page as any).__consoleErrors ?? []).toHaveLength(0);`);
141
+ }
142
+
143
+ lines.push(`});`, '');
144
+ }
145
+
146
+ return lines.join('\n');
147
+ }
148
+
149
+ export function generatePlaywrightConfig(opts: { baseUrl?: string; reportDir?: string } = {}): string {
150
+ const { baseUrl = 'http://localhost:3000', reportDir = 'playwright-report' } = opts;
151
+ return `// playwright.config.ts — generated by ZeTa Crawler
152
+ import { defineConfig } from '@playwright/test';
153
+
154
+ export default defineConfig({
155
+ testDir: './tests',
156
+ reporter: [['html', { outputFolder: '${reportDir}' }]],
157
+ use: {
158
+ baseURL: '${baseUrl}',
159
+ headless: true,
160
+ screenshot: 'only-on-failure',
161
+ video: 'retain-on-failure',
162
+ },
163
+ projects: [
164
+ { name: 'chromium', use: { browserName: 'chromium' } },
165
+ { name: 'firefox', use: { browserName: 'firefox' } },
166
+ { name: 'webkit', use: { browserName: 'webkit' } },
167
+ ],
168
+ });
169
+ `;
170
+ }
@@ -0,0 +1,52 @@
1
+ import type { DomainProfile } from '../profiles/domain-profile.js';
2
+
3
+ export interface CrawlSafetyDecision {
4
+ allowed: boolean;
5
+ reason?: string;
6
+ severity: 'info' | 'warn' | 'block';
7
+ }
8
+
9
+ const _extraDestructive = process.env.CRAWL_EXTRA_DESTRUCTIVE_PATTERNS
10
+ ? process.env.CRAWL_EXTRA_DESTRUCTIVE_PATTERNS.split(',').map((p) => p.trim()).filter(Boolean)
11
+ : [];
12
+ const DESTRUCTIVE_ACTION = new RegExp(
13
+ `\\b(delete|remove|destroy|deactivate|disable|cancel|refund|void|transfer|withdraw|pay now|place order|submit order|confirm payment|send money|publish|approve|reject|bulk update|drop${_extraDestructive.length ? `|${_extraDestructive.join('|')}` : ''})\\b`,
14
+ 'i',
15
+ );
16
+ const SECRET_LIKE = /\b(api[_ -]?key|secret|token|password|authorization|cookie|set-cookie)\b/i;
17
+
18
+ export function assessActionSafety(label: string, profile: DomainProfile): CrawlSafetyDecision {
19
+ const riskyByProfile = profile.riskyActions.some((risk) => label.toLowerCase().includes(risk.toLowerCase()));
20
+ if (DESTRUCTIVE_ACTION.test(label) || riskyByProfile) {
21
+ return {
22
+ allowed: false,
23
+ severity: 'block',
24
+ reason: `Blocked risky action "${label}" for ${profile.industry} profile.`,
25
+ };
26
+ }
27
+ return { allowed: true, severity: 'info' };
28
+ }
29
+
30
+ export function redactSensitiveValue(value: string): string {
31
+ let redacted = value
32
+ .replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, '[email]')
33
+ .replace(/\b(?:\+?\d[\d -]{8,}\d)\b/g, '[phone-or-id]')
34
+ .replace(/\b(?:\d[ -]*?){13,19}\b/g, '[card-like-number]')
35
+ .replace(/\b[A-Za-z0-9_-]{24,}\b/g, '[token-like-value]');
36
+ if (SECRET_LIKE.test(redacted)) redacted = redacted.replace(/:\s*[^,\s}]+/g, ': [redacted]');
37
+ return redacted;
38
+ }
39
+
40
+ export function redactJson(value: unknown): unknown {
41
+ if (typeof value === 'string') return redactSensitiveValue(value);
42
+ if (Array.isArray(value)) return value.map(redactJson);
43
+ if (value && typeof value === 'object') {
44
+ const out: Record<string, unknown> = {};
45
+ for (const [key, item] of Object.entries(value)) {
46
+ if (SECRET_LIKE.test(key)) out[key] = '[redacted]';
47
+ else out[key] = redactJson(item);
48
+ }
49
+ return out;
50
+ }
51
+ return value;
52
+ }
@@ -0,0 +1,190 @@
1
+ export type Industry =
2
+ | 'ecommerce'
3
+ | 'banking'
4
+ | 'fintech'
5
+ | 'healthcare'
6
+ | 'pharma'
7
+ | 'agriculture'
8
+ | 'legacy-enterprise'
9
+ | 'saas'
10
+ | 'unknown';
11
+
12
+ export interface DomainProfile {
13
+ industry: Industry;
14
+ confidence: number;
15
+ importantScreenPatterns: string[];
16
+ workflowGoals: string[];
17
+ piiRules: string[];
18
+ riskyActions: string[];
19
+ safeProbeRules: string[];
20
+ requiredArtifacts: string[];
21
+ evidence: string[];
22
+ }
23
+
24
+ const COMMON_REQUIRED_ARTIFACTS = [
25
+ 'screenshot',
26
+ 'dom',
27
+ 'markdown',
28
+ 'accessibility',
29
+ 'network',
30
+ 'performance',
31
+ ];
32
+
33
+ const PROFILES: Record<Industry, Omit<DomainProfile, 'confidence' | 'evidence'>> = {
34
+ ecommerce: {
35
+ industry: 'ecommerce',
36
+ importantScreenPatterns: ['catalog', 'product', 'search', 'filter', 'cart', 'checkout', 'payment', 'order', 'returns'],
37
+ workflowGoals: ['discover product catalogue', 'map cart and checkout', 'capture order confirmation and failure states', 'map search/filter/sort'],
38
+ piiRules: ['mask email', 'mask phone', 'mask address', 'mask card-like numbers'],
39
+ riskyActions: ['place order', 'submit payment', 'save card', 'apply real coupon'],
40
+ safeProbeRules: ['do not click final payment/order buttons', 'use invalid test card data only', 'stop before irreversible purchase'],
41
+ requiredArtifacts: COMMON_REQUIRED_ARTIFACTS,
42
+ },
43
+ banking: {
44
+ industry: 'banking',
45
+ importantScreenPatterns: ['login', 'mfa', 'dashboard', 'accounts', 'transactions', 'transfer', 'beneficiary', 'statement', 'dispute'],
46
+ workflowGoals: ['map account overview', 'map transactions and statements', 'map transfer setup without submitting', 'map MFA/session timeout states'],
47
+ piiRules: ['mask account numbers', 'mask balances', 'mask names', 'mask addresses', 'mask tax identifiers'],
48
+ riskyActions: ['transfer money', 'add beneficiary', 'submit dispute', 'download sensitive statement'],
49
+ safeProbeRules: ['read-only by default', 'never submit transfer confirmation', 'never alter beneficiary data'],
50
+ requiredArtifacts: COMMON_REQUIRED_ARTIFACTS,
51
+ },
52
+ fintech: {
53
+ industry: 'fintech',
54
+ importantScreenPatterns: ['kyc', 'wallet', 'transactions', 'cards', 'payments', 'payouts', 'risk', 'compliance', 'disputes'],
55
+ workflowGoals: ['map KYC onboarding', 'map wallet/payment states', 'map failed payment and dispute flows', 'capture compliance screens'],
56
+ piiRules: ['mask card numbers', 'mask bank accounts', 'mask identity documents', 'mask balances'],
57
+ riskyActions: ['send payment', 'withdraw funds', 'change card status', 'submit KYC with real data'],
58
+ safeProbeRules: ['sandbox data only', 'stop before money movement', 'never upload real identity documents'],
59
+ requiredArtifacts: COMMON_REQUIRED_ARTIFACTS,
60
+ },
61
+ healthcare: {
62
+ industry: 'healthcare',
63
+ importantScreenPatterns: ['patient', 'appointment', 'claims', 'provider', 'prescription', 'records', 'lab', 'consent'],
64
+ workflowGoals: ['map patient lookup safely', 'map appointment booking before final submit', 'map claims and prescription screens', 'capture consent and records UX'],
65
+ piiRules: ['mask PHI', 'mask patient names', 'mask MRN', 'mask DOB', 'mask diagnosis', 'mask prescriptions'],
66
+ riskyActions: ['schedule real appointment', 'submit claim', 'change medication', 'message provider with PHI'],
67
+ safeProbeRules: ['use synthetic patients only', 'do not submit clinical changes', 'avoid external notifications'],
68
+ requiredArtifacts: COMMON_REQUIRED_ARTIFACTS,
69
+ },
70
+ pharma: {
71
+ industry: 'pharma',
72
+ importantScreenPatterns: ['product', 'dosage', 'safety', 'batch', 'adverse-event', 'regulatory', 'trial', 'label'],
73
+ workflowGoals: ['map product and safety content', 'map adverse event intake before submit', 'capture regulatory and batch workflows'],
74
+ piiRules: ['mask patient reports', 'mask reporter contact', 'mask trial participant identifiers'],
75
+ riskyActions: ['submit adverse event', 'change safety record', 'publish regulatory content'],
76
+ safeProbeRules: ['stop before regulatory or safety submission', 'use synthetic reports only'],
77
+ requiredArtifacts: COMMON_REQUIRED_ARTIFACTS,
78
+ },
79
+ agriculture: {
80
+ industry: 'agriculture',
81
+ importantScreenPatterns: ['crop', 'field', 'weather', 'inventory', 'marketplace', 'logistics', 'sensor', 'subsidy'],
82
+ workflowGoals: ['map crop and field planning', 'map inventory/marketplace flows', 'capture logistics and sensor dashboards'],
83
+ piiRules: ['mask farmer identity', 'mask location precision', 'mask subsidy identifiers'],
84
+ riskyActions: ['place market order', 'submit subsidy application', 'change sensor/device control'],
85
+ safeProbeRules: ['avoid irreversible orders', 'avoid device actuation', 'use test farm data'],
86
+ requiredArtifacts: COMMON_REQUIRED_ARTIFACTS,
87
+ },
88
+ 'legacy-enterprise': {
89
+ industry: 'legacy-enterprise',
90
+ importantScreenPatterns: ['frameset', 'iframe', 'popup', 'table', 'search', 'admin', 'report', 'export'],
91
+ workflowGoals: ['map menu trees', 'capture iframe and popup states', 'map table filters and reports', 'detect session timeout'],
92
+ piiRules: ['mask table cells that look like PII', 'mask exported identifiers'],
93
+ riskyActions: ['bulk update', 'delete record', 'export production data', 'submit admin change'],
94
+ safeProbeRules: ['read-only table probing', 'never click delete/bulk actions', 'capture popups without committing'],
95
+ requiredArtifacts: COMMON_REQUIRED_ARTIFACTS,
96
+ },
97
+ saas: {
98
+ industry: 'saas',
99
+ importantScreenPatterns: ['dashboard', 'settings', 'users', 'billing', 'integrations', 'reports', 'admin', 'workspace'],
100
+ workflowGoals: ['map workspace navigation', 'map settings and integrations', 'map role/user management without changing state', 'capture dashboards and reports'],
101
+ piiRules: ['mask emails', 'mask tokens', 'mask API keys', 'mask billing data'],
102
+ riskyActions: ['delete workspace', 'invite real user', 'rotate key', 'change billing plan'],
103
+ safeProbeRules: ['never submit destructive settings', 'redact secrets immediately', 'use sandbox users'],
104
+ requiredArtifacts: COMMON_REQUIRED_ARTIFACTS,
105
+ },
106
+ unknown: {
107
+ industry: 'unknown',
108
+ importantScreenPatterns: ['login', 'dashboard', 'settings', 'search', 'detail', 'report', 'form'],
109
+ workflowGoals: ['map top-level navigation', 'capture forms and validation states', 'discover hidden menus', 'classify domain after first pages'],
110
+ piiRules: ['mask emails', 'mask phone numbers', 'mask long identifiers', 'mask card-like numbers'],
111
+ riskyActions: ['delete', 'submit payment', 'transfer', 'publish', 'send notification'],
112
+ safeProbeRules: ['read-only by default', 'stop before irreversible actions', 'use synthetic data only'],
113
+ requiredArtifacts: COMMON_REQUIRED_ARTIFACTS,
114
+ },
115
+ };
116
+
117
+ const BASE_INDUSTRY_HINTS: Array<{ industry: Industry; terms: RegExp[] }> = [
118
+ { industry: 'ecommerce', terms: [/cart/i, /checkout/i, /product/i, /catalog/i, /sku/i, /wishlist/i, /order/i] },
119
+ { industry: 'banking', terms: [/account/i, /statement/i, /beneficiar/i, /transfer/i, /iban/i, /routing/i, /balance/i] },
120
+ { industry: 'fintech', terms: [/wallet/i, /kyc/i, /payout/i, /card/i, /payment/i, /risk/i, /dispute/i] },
121
+ { industry: 'healthcare', terms: [/patient/i, /provider/i, /appointment/i, /claim/i, /prescription/i, /medical/i, /lab result/i] },
122
+ { industry: 'pharma', terms: [/pharma/i, /dosage/i, /adverse/i, /batch/i, /regulatory/i, /clinical trial/i, /label/i] },
123
+ { industry: 'agriculture', terms: [/crop/i, /field/i, /farm/i, /harvest/i, /sensor/i, /weather/i, /subsidy/i] },
124
+ { industry: 'legacy-enterprise', terms: [/frameset/i, /iframe/i, /popup/i, /legacy/i, /report export/i, /mainframe/i] },
125
+ { industry: 'saas', terms: [/workspace/i, /tenant/i, /integration/i, /billing/i, /api key/i, /admin/i, /dashboard/i] },
126
+ ];
127
+
128
+ // Allow additional industry hint keywords via ENV without replacing the baseline.
129
+ // Format: JSON array of { industry: string; terms: string[] } — terms are treated as case-insensitive regex.
130
+ // Example: EXTRA_INDUSTRY_HINTS_JSON='[{"industry":"saas","terms":["platform","multitenant"]}]'
131
+ const _extraHints: Array<{ industry: Industry; terms: RegExp[] }> = (() => {
132
+ const raw = process.env.EXTRA_INDUSTRY_HINTS_JSON;
133
+ if (!raw) return [];
134
+ try {
135
+ const parsed: Array<{ industry: string; terms: string[] }> = JSON.parse(raw);
136
+ return parsed.map(h => ({ industry: h.industry as Industry, terms: h.terms.map(t => new RegExp(t, 'i')) }));
137
+ } catch { return []; }
138
+ })();
139
+
140
+ const INDUSTRY_HINTS = [...BASE_INDUSTRY_HINTS, ..._extraHints];
141
+
142
+ // Allow patching profile fields (riskyActions, piiRules, etc.) per industry via ENV.
143
+ // Format: JSON object keyed by industry, value is partial DomainProfile fields to merge.
144
+ // Example: DOMAIN_PROFILE_OVERRIDES_JSON='{"saas":{"riskyActions":["delete workspace","export all data"]}}'
145
+ const _profileOverrides: Partial<Record<Industry, Partial<Omit<DomainProfile, 'confidence' | 'evidence'>>>> = (() => {
146
+ const raw = process.env.DOMAIN_PROFILE_OVERRIDES_JSON;
147
+ if (!raw) return {};
148
+ try { return JSON.parse(raw); } catch { return {}; }
149
+ })();
150
+
151
+ export function classifyDomainProfile(input: {
152
+ appUrl: string;
153
+ projectName?: string | null;
154
+ appType?: string | null;
155
+ seedText?: string;
156
+ }): DomainProfile {
157
+ const haystack = [input.appUrl, input.projectName ?? '', input.appType ?? '', input.seedText ?? ''].join(' ');
158
+ const scores = new Map<Industry, { score: number; evidence: string[] }>();
159
+ for (const { industry, terms } of INDUSTRY_HINTS) {
160
+ for (const term of terms) {
161
+ if (term.test(haystack)) {
162
+ const prev = scores.get(industry) ?? { score: 0, evidence: [] };
163
+ prev.score += 1;
164
+ prev.evidence.push(term.source);
165
+ scores.set(industry, prev);
166
+ }
167
+ }
168
+ }
169
+ let selected: Industry = 'unknown';
170
+ let best = 0;
171
+ let evidence: string[] = [];
172
+ for (const [industry, result] of scores) {
173
+ if (result.score > best) {
174
+ selected = industry;
175
+ best = result.score;
176
+ evidence = result.evidence;
177
+ }
178
+ }
179
+ const base = PROFILES[selected];
180
+ return {
181
+ ...base,
182
+ confidence: best === 0 ? 0.25 : Math.min(0.95, 0.35 + best * 0.15),
183
+ evidence,
184
+ };
185
+ }
186
+
187
+ export function getProfile(industry: Industry): DomainProfile {
188
+ const base = PROFILES[industry] ?? PROFILES.unknown;
189
+ return { ...base, confidence: 1, evidence: ['explicit'] };
190
+ }
package/src/proxy.ts ADDED
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Free proxy auto-selection for bot-protection bypass.
3
+ *
4
+ * Source: proxifly/free-proxy-list (MIT) via jsDelivr CDN.
5
+ * These are datacenter proxies — they bypass simple IP blocks but NOT
6
+ * full Cloudflare Bot Manager / Akamai. For Cloudflare-protected sites,
7
+ * users need a residential proxy (Bright Data, Oxylabs, etc.).
8
+ */
9
+
10
+ import { createConnection } from 'net';
11
+
12
+ const PROXY_LIST_URL =
13
+ 'https://cdn.jsdelivr.net/gh/proxifly/free-proxy-list@main/proxies/all/data.json';
14
+
15
+ interface ProxyEntry {
16
+ ip: string;
17
+ port: number;
18
+ protocols: string[];
19
+ upTime?: number;
20
+ speed?: number;
21
+ }
22
+
23
+ /** Fetch and filter proxy list. Returns http proxies sorted by speed (fastest first). */
24
+ async function fetchCandidates(): Promise<ProxyEntry[]> {
25
+ const res = await fetch(PROXY_LIST_URL, {
26
+ signal: AbortSignal.timeout(10_000),
27
+ headers: { 'Accept': 'application/json' },
28
+ });
29
+ if (!res.ok) throw new Error(`proxy list fetch failed: ${res.status}`);
30
+ const raw: ProxyEntry[] = await res.json();
31
+ return raw
32
+ .filter((p) => p.protocols?.includes('http') && p.port > 0 && (p.upTime ?? 0) >= 30)
33
+ .sort((a, b) => (a.speed ?? 99999) - (b.speed ?? 99999))
34
+ .slice(0, 50); // test at most 50 candidates
35
+ }
36
+
37
+ /** TCP-level proxy liveness check via HTTP CONNECT tunnel. No extra dependencies. */
38
+ function testProxy(ip: string, port: number, timeoutMs: number): Promise<boolean> {
39
+ return new Promise((resolve) => {
40
+ let settled = false;
41
+ const settle = (ok: boolean) => {
42
+ if (settled) return;
43
+ settled = true;
44
+ resolve(ok);
45
+ try { sock.destroy(); } catch { /* ignore */ }
46
+ };
47
+
48
+ const timer = setTimeout(() => settle(false), timeoutMs);
49
+ const sock = createConnection({ host: ip, port, timeout: timeoutMs });
50
+
51
+ sock.on('connect', () => {
52
+ sock.write('CONNECT example.com:80 HTTP/1.1\r\nHost: example.com:80\r\n\r\n');
53
+ sock.once('data', (data) => {
54
+ clearTimeout(timer);
55
+ const ok = /^HTTP\/1\.[01] 200/.test(data.toString());
56
+ settle(ok);
57
+ });
58
+ });
59
+ sock.on('error', () => { clearTimeout(timer); settle(false); });
60
+ sock.on('timeout', () => { clearTimeout(timer); settle(false); });
61
+ });
62
+ }
63
+
64
+ /** Test `batchSize` proxies concurrently and return first working one. */
65
+ async function testBatch(
66
+ candidates: ProxyEntry[],
67
+ start: number,
68
+ batchSize: number,
69
+ timeoutMs: number,
70
+ ): Promise<string | null> {
71
+ const batch = candidates.slice(start, start + batchSize);
72
+ if (batch.length === 0) return null;
73
+
74
+ const results = await Promise.all(
75
+ batch.map(async (p) => {
76
+ const ok = await testProxy(p.ip, p.port, timeoutMs);
77
+ return ok ? `http://${p.ip}:${p.port}` : null;
78
+ }),
79
+ );
80
+
81
+ return results.find((r) => r !== null) ?? null;
82
+ }
83
+
84
+ /**
85
+ * Pick a working free proxy. Tests in parallel batches of 10 with a 4s timeout.
86
+ * Returns null if no working proxy found (not an error — crawl can proceed without proxy).
87
+ */
88
+ export async function pickFreeProxy(): Promise<string | null> {
89
+ let candidates: ProxyEntry[];
90
+ try {
91
+ candidates = await fetchCandidates();
92
+ } catch (err: any) {
93
+ console.warn('[proxy] failed to fetch proxy list:', err?.message ?? err);
94
+ return null;
95
+ }
96
+
97
+ const BATCH = 10;
98
+ const TIMEOUT = 4_000;
99
+
100
+ for (let i = 0; i < candidates.length; i += BATCH) {
101
+ const found = await testBatch(candidates, i, BATCH, TIMEOUT);
102
+ if (found) {
103
+ console.info(`[proxy] selected free proxy: ${found} (tested ${i + BATCH} candidates)`);
104
+ return found;
105
+ }
106
+ }
107
+
108
+ console.warn('[proxy] no working free proxy found in list');
109
+ return null;
110
+ }
111
+
112
+ // ── Tiered Proxy Rotation ─────────────────────────────────────────────────────
113
+
114
+ export type ProxyTier = 'free' | 'datacenter' | 'residential' | 'premium';
115
+
116
+ export interface ProxyTierConfig {
117
+ /** List of proxy URLs for this tier. E.g. ['http://user:pass@dc1.proxy:8080'] */
118
+ urls: string[];
119
+ tier: ProxyTier;
120
+ }
121
+
122
+ interface DomainHistory {
123
+ tier: ProxyTier;
124
+ consecutiveFailures: number;
125
+ lastEscalatedAt: number;
126
+ totalRequests: number;
127
+ successRate: number;
128
+ }
129
+
130
+ const TIER_ORDER: ProxyTier[] = ['free', 'datacenter', 'residential', 'premium'];
131
+
132
+ function nextTier(current: ProxyTier): ProxyTier {
133
+ const idx = TIER_ORDER.indexOf(current);
134
+ return TIER_ORDER[Math.min(idx + 1, TIER_ORDER.length - 1)];
135
+ }
136
+
137
+ /**
138
+ * Tiered proxy manager with per-domain error histograms.
139
+ *
140
+ * Tracks success/failure per domain and automatically escalates to higher proxy tiers
141
+ * on consecutive failures. Applies time-decay to probe returning to lower tiers.
142
+ *
143
+ * Usage:
144
+ * const mgr = new TieredProxyManager([{ tier: 'datacenter', urls: [...] }]);
145
+ * const proxy = await mgr.selectProxy('api.salesforce.com');
146
+ * // ... make request ...
147
+ * mgr.recordResult('api.salesforce.com', success);
148
+ */
149
+ export class TieredProxyManager {
150
+ private tiers: Map<ProxyTier, string[]> = new Map();
151
+ private domainHistory: Map<string, DomainHistory> = new Map();
152
+ private readonly ESCALATE_AFTER = 3; // consecutive failures before escalation
153
+ private readonly DECAY_AFTER_MS = 30 * 60 * 1000; // 30 min: probe tier downgrade
154
+
155
+ constructor(configs: ProxyTierConfig[]) {
156
+ for (const cfg of configs) {
157
+ if (cfg.urls.length > 0) this.tiers.set(cfg.tier, cfg.urls);
158
+ }
159
+ }
160
+
161
+ private getHistory(domain: string): DomainHistory {
162
+ if (!this.domainHistory.has(domain)) {
163
+ this.domainHistory.set(domain, {
164
+ tier: this.lowestAvailableTier(),
165
+ consecutiveFailures: 0,
166
+ lastEscalatedAt: 0,
167
+ totalRequests: 0,
168
+ successRate: 1,
169
+ });
170
+ }
171
+ return this.domainHistory.get(domain)!;
172
+ }
173
+
174
+ private lowestAvailableTier(): ProxyTier {
175
+ for (const t of TIER_ORDER) {
176
+ if (this.tiers.has(t)) return t;
177
+ }
178
+ return 'free';
179
+ }
180
+
181
+ /** Pick a proxy URL for this domain, based on its tier history. */
182
+ selectProxy(domain: string): string | null {
183
+ const history = this.getHistory(domain);
184
+
185
+ // Time-decay: if we've been on elevated tier for DECAY_AFTER_MS, try stepping down
186
+ if (history.consecutiveFailures === 0 && history.lastEscalatedAt > 0) {
187
+ const elapsed = Date.now() - history.lastEscalatedAt;
188
+ if (elapsed > this.DECAY_AFTER_MS) {
189
+ const currentIdx = TIER_ORDER.indexOf(history.tier);
190
+ if (currentIdx > 0) {
191
+ const lowerTier = TIER_ORDER[currentIdx - 1];
192
+ if (this.tiers.has(lowerTier)) {
193
+ history.tier = lowerTier;
194
+ history.lastEscalatedAt = 0;
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ const urls = this.tiers.get(history.tier);
201
+ if (!urls || urls.length === 0) return null;
202
+ // Round-robin within tier
203
+ const idx = history.totalRequests % urls.length;
204
+ return urls[idx];
205
+ }
206
+
207
+ /** Record a request result for a domain. Triggers tier escalation on repeated failures. */
208
+ recordResult(domain: string, success: boolean): void {
209
+ const history = this.getHistory(domain);
210
+ history.totalRequests++;
211
+ if (success) {
212
+ history.consecutiveFailures = 0;
213
+ // Update EMA success rate
214
+ history.successRate = history.successRate * 0.9 + 0.1;
215
+ } else {
216
+ history.consecutiveFailures++;
217
+ history.successRate = history.successRate * 0.9;
218
+ if (history.consecutiveFailures >= this.ESCALATE_AFTER) {
219
+ const elevated = nextTier(history.tier);
220
+ if (elevated !== history.tier && this.tiers.has(elevated)) {
221
+ console.warn(`[proxy-tier] domain=${domain} escalating ${history.tier}→${elevated} after ${history.consecutiveFailures} failures`);
222
+ history.tier = elevated;
223
+ history.lastEscalatedAt = Date.now();
224
+ history.consecutiveFailures = 0;
225
+ }
226
+ }
227
+ }
228
+ }
229
+
230
+ stats(): Array<{ domain: string; tier: ProxyTier; successRate: number; totalRequests: number }> {
231
+ return Array.from(this.domainHistory.entries()).map(([domain, h]) => ({
232
+ domain,
233
+ tier: h.tier,
234
+ successRate: Math.round(h.successRate * 100) / 100,
235
+ totalRequests: h.totalRequests,
236
+ }));
237
+ }
238
+ }