@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,310 @@
1
+ async function detectDragAndDrop(page) {
2
+ const detected = await page.evaluate(() => {
3
+ if (document.querySelector("[data-dnd-kit-draggable]")) {
4
+ return {
5
+ library: "dnd-kit",
6
+ draggableCount: document.querySelectorAll("[data-dnd-kit-draggable]").length,
7
+ dropZoneCount: document.querySelectorAll("[data-dnd-kit-droppable]").length
8
+ };
9
+ }
10
+ if (document.querySelector("[data-rbd-draggable-id]")) {
11
+ return {
12
+ library: "react-beautiful-dnd",
13
+ draggableCount: document.querySelectorAll("[data-rbd-draggable-id]").length,
14
+ dropZoneCount: document.querySelectorAll("[data-rbd-droppable-id]").length
15
+ };
16
+ }
17
+ if (document.querySelector(".sortable-ghost") || document.querySelector("[data-sortable]")) {
18
+ return {
19
+ library: "sortablejs",
20
+ draggableCount: document.querySelectorAll("[data-sortable], .sortable-item").length,
21
+ dropZoneCount: document.querySelectorAll("[data-sortable-list], .sortable-list").length
22
+ };
23
+ }
24
+ const html5Draggables = document.querySelectorAll('[draggable="true"]');
25
+ if (html5Draggables.length > 0) {
26
+ return {
27
+ library: "html5",
28
+ draggableCount: html5Draggables.length,
29
+ dropZoneCount: document.querySelectorAll("[data-drop-target], [ondrop], .drop-zone").length
30
+ };
31
+ }
32
+ return { library: "none", draggableCount: 0, dropZoneCount: 0 };
33
+ });
34
+ if (detected.library === "none") {
35
+ return { ...detected, testAttempted: false, testCompleted: false };
36
+ }
37
+ let testAttempted = false;
38
+ let testCompleted = false;
39
+ try {
40
+ if (detected.library === "html5" && detected.draggableCount >= 2) {
41
+ const sources = await page.$$('[draggable="true"]');
42
+ if (sources.length >= 2) {
43
+ testAttempted = true;
44
+ await page.dragAndDrop('[draggable="true"]:nth-child(1)', '[draggable="true"]:nth-child(2)');
45
+ testCompleted = true;
46
+ }
47
+ } else if (detected.draggableCount >= 2) {
48
+ const draggableSel = detected.library === "dnd-kit" ? "[data-dnd-kit-draggable]" : detected.library === "react-beautiful-dnd" ? "[data-rbd-draggable-id]" : "[data-sortable], .sortable-item";
49
+ const elements = await page.$$(draggableSel);
50
+ if (elements.length >= 2) {
51
+ testAttempted = true;
52
+ const src = elements[0];
53
+ const dst = elements[1];
54
+ const srcBox = await src.boundingBox();
55
+ const dstBox = await dst.boundingBox();
56
+ if (srcBox && dstBox) {
57
+ const srcX = srcBox.x + srcBox.width / 2;
58
+ const srcY = srcBox.y + srcBox.height / 2;
59
+ const dstX = dstBox.x + dstBox.width / 2;
60
+ const dstY = dstBox.y + dstBox.height / 2;
61
+ await page.mouse.move(srcX, srcY);
62
+ await page.mouse.down();
63
+ const steps = 10;
64
+ for (let i = 1; i <= steps; i++) {
65
+ await page.mouse.move(
66
+ srcX + (dstX - srcX) * i / steps,
67
+ srcY + (dstY - srcY) * i / steps
68
+ );
69
+ }
70
+ await page.mouse.up();
71
+ testCompleted = true;
72
+ }
73
+ }
74
+ }
75
+ } catch {
76
+ }
77
+ return { ...detected, testAttempted, testCompleted };
78
+ }
79
+ async function captureDatePickers(page) {
80
+ const results = [];
81
+ const nativeInputs = await page.$$('input[type="date"], input[type="datetime-local"]');
82
+ for (const input of nativeInputs.slice(0, 5)) {
83
+ try {
84
+ const attrs = await input.evaluate((el) => ({
85
+ type: el.type,
86
+ min: el.min || void 0,
87
+ max: el.max || void 0,
88
+ id: el.id || "",
89
+ name: el.name || ""
90
+ }));
91
+ let fieldLabel = attrs.id || attrs.name || "unknown";
92
+ if (attrs.id) {
93
+ const lblText = await page.evaluate((id) => {
94
+ const lbl = document.querySelector(`label[for="${id}"]`);
95
+ return lbl ? (lbl.textContent ?? "").trim() : null;
96
+ }, attrs.id);
97
+ if (lblText) fieldLabel = lblText;
98
+ }
99
+ let sampleSelectedValue;
100
+ try {
101
+ await input.fill("2026-09-15");
102
+ sampleSelectedValue = await input.inputValue();
103
+ if (!sampleSelectedValue) sampleSelectedValue = void 0;
104
+ } catch {
105
+ }
106
+ results.push({
107
+ fieldLabel,
108
+ pickerType: attrs.type === "datetime-local" ? "native-datetime" : "native-date",
109
+ minDate: attrs.min,
110
+ maxDate: attrs.max,
111
+ disabledDatesFound: false,
112
+ // native inputs have no visual disabled cells
113
+ sampleSelectedValue
114
+ });
115
+ } catch {
116
+ }
117
+ }
118
+ const customInputs = await page.$$('input:not([type="date"]):not([type="datetime-local"]):not([type="hidden"])');
119
+ for (const input of customInputs.slice(0, 5)) {
120
+ if (results.length >= 5) break;
121
+ try {
122
+ await input.click();
123
+ const calendarAppeared = await page.waitForSelector('[role="grid"]', { timeout: 2e3 }).then(() => true).catch(() => false);
124
+ if (!calendarAppeared) {
125
+ await page.keyboard.press("Escape");
126
+ continue;
127
+ }
128
+ const monthHeader = await page.evaluate(() => {
129
+ const header = document.querySelector('[role="grid"] caption, [role="columnheader"], .calendar-header, .rdp-caption');
130
+ return header ? (header.textContent ?? "").trim().slice(0, 60) : "";
131
+ });
132
+ const disabledCount = await page.evaluate(
133
+ () => document.querySelectorAll('[role="gridcell"][aria-disabled="true"], [role="gridcell"].disabled').length
134
+ );
135
+ const inputId = await input.evaluate((el) => el.id || el.name || "");
136
+ let fieldLabel = inputId || "datepicker";
137
+ if (inputId) {
138
+ const lblText = await page.evaluate((id) => {
139
+ const lbl = document.querySelector(`label[for="${id}"]`);
140
+ return lbl ? (lbl.textContent ?? "").trim() : null;
141
+ }, inputId);
142
+ if (lblText) fieldLabel = lblText;
143
+ }
144
+ let sampleSelectedValue;
145
+ try {
146
+ const firstEnabled = await page.$('[role="gridcell"]:not([aria-disabled="true"]):not(.disabled)');
147
+ if (firstEnabled) {
148
+ await firstEnabled.click();
149
+ sampleSelectedValue = await input.inputValue().catch(() => void 0);
150
+ }
151
+ } catch {
152
+ }
153
+ await page.keyboard.press("Escape");
154
+ results.push({
155
+ fieldLabel,
156
+ pickerType: "calendar-popup",
157
+ disabledDatesFound: disabledCount > 0,
158
+ sampleSelectedValue: sampleSelectedValue || void 0
159
+ });
160
+ } catch {
161
+ try {
162
+ await page.keyboard.press("Escape");
163
+ } catch {
164
+ }
165
+ }
166
+ }
167
+ return results;
168
+ }
169
+ async function captureSliders(page) {
170
+ const results = [];
171
+ const handles = await page.$$('input[type="range"], [role="slider"]');
172
+ for (const handle of handles.slice(0, 5)) {
173
+ try {
174
+ const attrs = await handle.evaluate((el) => {
175
+ const min = parseFloat(el.min ?? el.getAttribute("aria-valuemin") ?? "0");
176
+ const max = parseFloat(el.max ?? el.getAttribute("aria-valuemax") ?? "100");
177
+ const step = parseFloat(el.step ?? el.getAttribute("aria-valuestep") ?? "1") || 1;
178
+ const value = parseFloat(el.value ?? el.getAttribute("aria-valuenow") ?? String(min));
179
+ const id = el.id || el.name || "";
180
+ return { min, max, step, value, id };
181
+ });
182
+ let label = attrs.id || "slider";
183
+ if (attrs.id) {
184
+ const lblText = await page.evaluate((id) => {
185
+ const lbl = document.querySelector(`label[for="${id}"]`);
186
+ return lbl ? (lbl.textContent ?? "").trim() : null;
187
+ }, attrs.id);
188
+ if (lblText) label = lblText;
189
+ }
190
+ const isNative = await handle.evaluate((el) => el.tagName.toLowerCase() === "input");
191
+ if (isNative) {
192
+ try {
193
+ await handle.fill(String(attrs.min));
194
+ await handle.fill(String(attrs.max));
195
+ await handle.fill(String(attrs.value));
196
+ } catch {
197
+ }
198
+ }
199
+ results.push({
200
+ label,
201
+ min: attrs.min,
202
+ max: attrs.max,
203
+ step: attrs.step,
204
+ currentValue: attrs.value
205
+ });
206
+ } catch {
207
+ }
208
+ }
209
+ return results;
210
+ }
211
+ async function captureTypeaheads(page) {
212
+ const results = [];
213
+ const candidates = await page.$$(
214
+ '[role="combobox"][aria-autocomplete], [aria-autocomplete="list"], input.autocomplete, input[aria-autocomplete]'
215
+ );
216
+ for (const input of candidates.slice(0, 3)) {
217
+ try {
218
+ const inputId = await input.evaluate((el) => el.id || el.name || el.placeholder || "");
219
+ let label = inputId || "typeahead";
220
+ if (inputId) {
221
+ const lblText = await page.evaluate((id) => {
222
+ const lbl = document.querySelector(`label[for="${id}"]`);
223
+ return lbl ? (lbl.textContent ?? "").trim() : null;
224
+ }, inputId);
225
+ if (lblText) label = lblText;
226
+ }
227
+ await input.click();
228
+ await input.fill("");
229
+ await input.type("a", { delay: 100 });
230
+ await page.waitForTimeout(500);
231
+ let listboxVisible = await page.evaluate(() => {
232
+ const lb = document.querySelector('[role="listbox"]');
233
+ if (!lb) return false;
234
+ const style = window.getComputedStyle(lb);
235
+ return style.display !== "none" && style.visibility !== "hidden";
236
+ });
237
+ let minCharsToTrigger = listboxVisible ? 1 : 2;
238
+ if (!listboxVisible) {
239
+ await input.type("b", { delay: 100 });
240
+ await page.waitForTimeout(500);
241
+ listboxVisible = await page.evaluate(() => {
242
+ const lb = document.querySelector('[role="listbox"]');
243
+ if (!lb) return false;
244
+ const style = window.getComputedStyle(lb);
245
+ return style.display !== "none" && style.visibility !== "hidden";
246
+ });
247
+ if (listboxVisible) minCharsToTrigger = 2;
248
+ }
249
+ const sampleSuggestions = [];
250
+ if (listboxVisible) {
251
+ const suggestions = await page.evaluate(
252
+ () => Array.from(document.querySelectorAll('[role="option"]')).slice(0, 8).map((o) => (o.textContent ?? "").trim()).filter(Boolean)
253
+ );
254
+ sampleSuggestions.push(...suggestions);
255
+ }
256
+ await input.fill("ZZXQQ_NORESULT_9999");
257
+ await page.waitForTimeout(500);
258
+ const noResultsText = await page.evaluate(() => {
259
+ const selectors = [
260
+ '[role="listbox"] [role="option"]',
261
+ '[role="status"]',
262
+ ".no-results",
263
+ ".empty-message",
264
+ '[data-testid*="no-result"]'
265
+ ];
266
+ for (const sel of selectors) {
267
+ const el = document.querySelector(sel);
268
+ if (el) {
269
+ const txt = (el.textContent ?? "").trim();
270
+ if (txt) return txt.slice(0, 120);
271
+ }
272
+ }
273
+ return null;
274
+ });
275
+ await input.fill("");
276
+ results.push({
277
+ label,
278
+ minCharsToTrigger,
279
+ sampleSuggestions,
280
+ noResultsText
281
+ });
282
+ } catch {
283
+ try {
284
+ await input.fill("");
285
+ } catch {
286
+ }
287
+ }
288
+ }
289
+ return results;
290
+ }
291
+ async function probeAdvancedUI(page) {
292
+ const defaultDragDrop = {
293
+ library: "none",
294
+ draggableCount: 0,
295
+ dropZoneCount: 0,
296
+ testAttempted: false,
297
+ testCompleted: false
298
+ };
299
+ const [dragDrop, datePickers, sliders, typeaheads] = await Promise.all([
300
+ detectDragAndDrop(page).catch(() => defaultDragDrop),
301
+ captureDatePickers(page).catch(() => []),
302
+ captureSliders(page).catch(() => []),
303
+ captureTypeaheads(page).catch(() => [])
304
+ ]);
305
+ return { dragDrop, datePickers, sliders, typeaheads };
306
+ }
307
+ export {
308
+ probeAdvancedUI
309
+ };
310
+ //# sourceMappingURL=advanced-ui-probes.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/advanced-ui-probes.ts"],
4
+ "sourcesContent": ["/**\n * Advanced UI probes \u2014 detect and exercise drag-drop, date pickers, sliders,\n * and typeahead/autocomplete widgets on a crawled page.\n *\n * Results feed ZeTa's test generator so it can emit interaction-level test\n * cases for these widget families instead of falling back to generic clicks.\n *\n * Each probe is independently try/caught so a broken widget does not abort\n * the others. All browser-side code runs inside page.evaluate / page.$$eval\n * to avoid serialisation issues with DOM handles.\n */\n\nimport type { Page } from 'playwright';\n\n// ---------------------------------------------------------------------------\n// Public interfaces\n// ---------------------------------------------------------------------------\n\nexport interface DragDropCapture {\n library: 'html5' | 'dnd-kit' | 'react-beautiful-dnd' | 'sortablejs' | 'pointer-event' | 'none';\n draggableCount: number;\n dropZoneCount: number;\n testAttempted: boolean;\n testCompleted: boolean;\n}\n\nexport interface DatePickerCapture {\n fieldLabel: string;\n pickerType: 'calendar-popup' | 'native-date' | 'native-datetime' | 'none';\n minDate?: string;\n maxDate?: string;\n disabledDatesFound: boolean;\n sampleSelectedValue?: string;\n}\n\nexport interface SliderCapture {\n label: string;\n min: number;\n max: number;\n step: number;\n currentValue: number;\n}\n\nexport interface TypeaheadCapture {\n label: string;\n minCharsToTrigger: number;\n sampleSuggestions: string[];\n noResultsText: string | null;\n}\n\nexport interface AdvancedProbeResult {\n dragDrop: DragDropCapture;\n datePickers: DatePickerCapture[];\n sliders: SliderCapture[];\n typeaheads: TypeaheadCapture[];\n}\n\n// ---------------------------------------------------------------------------\n// Internal: drag-and-drop detection\n// ---------------------------------------------------------------------------\n\nasync function detectDragAndDrop(page: Page): Promise<DragDropCapture> {\n // Detect library and count elements in the browser context\n const detected = await page.evaluate((): {\n library: DragDropCapture['library'];\n draggableCount: number;\n dropZoneCount: number;\n } => {\n // dnd-kit\n if (document.querySelector('[data-dnd-kit-draggable]')) {\n return {\n library: 'dnd-kit',\n draggableCount: document.querySelectorAll('[data-dnd-kit-draggable]').length,\n dropZoneCount: document.querySelectorAll('[data-dnd-kit-droppable]').length,\n };\n }\n // react-beautiful-dnd\n if (document.querySelector('[data-rbd-draggable-id]')) {\n return {\n library: 'react-beautiful-dnd',\n draggableCount: document.querySelectorAll('[data-rbd-draggable-id]').length,\n dropZoneCount: document.querySelectorAll('[data-rbd-droppable-id]').length,\n };\n }\n // SortableJS\n if (document.querySelector('.sortable-ghost') || document.querySelector('[data-sortable]')) {\n return {\n library: 'sortablejs',\n draggableCount: document.querySelectorAll('[data-sortable], .sortable-item').length,\n dropZoneCount: document.querySelectorAll('[data-sortable-list], .sortable-list').length,\n };\n }\n // Native HTML5 draggable\n const html5Draggables = document.querySelectorAll('[draggable=\"true\"]');\n if (html5Draggables.length > 0) {\n return {\n library: 'html5',\n draggableCount: html5Draggables.length,\n dropZoneCount: document.querySelectorAll('[data-drop-target], [ondrop], .drop-zone').length,\n };\n }\n return { library: 'none', draggableCount: 0, dropZoneCount: 0 };\n });\n\n if (detected.library === 'none') {\n return { ...detected, testAttempted: false, testCompleted: false };\n }\n\n let testAttempted = false;\n let testCompleted = false;\n\n try {\n if (detected.library === 'html5' && detected.draggableCount >= 2) {\n // Attempt a real dragAndDrop between the first two draggable elements\n const sources = await page.$$('[draggable=\"true\"]');\n if (sources.length >= 2) {\n testAttempted = true;\n await page.dragAndDrop('[draggable=\"true\"]:nth-child(1)', '[draggable=\"true\"]:nth-child(2)');\n testCompleted = true;\n }\n } else if (detected.draggableCount >= 2) {\n // Pointer-event simulation for library-managed drag\n const draggableSel =\n detected.library === 'dnd-kit' ? '[data-dnd-kit-draggable]' :\n detected.library === 'react-beautiful-dnd' ? '[data-rbd-draggable-id]' :\n '[data-sortable], .sortable-item';\n\n const elements = await page.$$(draggableSel);\n if (elements.length >= 2) {\n testAttempted = true;\n const src = elements[0];\n const dst = elements[1];\n const srcBox = await src.boundingBox();\n const dstBox = await dst.boundingBox();\n\n if (srcBox && dstBox) {\n const srcX = srcBox.x + srcBox.width / 2;\n const srcY = srcBox.y + srcBox.height / 2;\n const dstX = dstBox.x + dstBox.width / 2;\n const dstY = dstBox.y + dstBox.height / 2;\n\n await page.mouse.move(srcX, srcY);\n await page.mouse.down();\n // Move in small steps to allow drag handlers to fire\n const steps = 10;\n for (let i = 1; i <= steps; i++) {\n await page.mouse.move(\n srcX + ((dstX - srcX) * i) / steps,\n srcY + ((dstY - srcY) * i) / steps,\n );\n }\n await page.mouse.up();\n testCompleted = true;\n }\n }\n }\n } catch {\n // testCompleted remains false \u2014 that is the signal to the caller\n }\n\n return { ...detected, testAttempted, testCompleted };\n}\n\n// ---------------------------------------------------------------------------\n// Internal: date pickers\n// ---------------------------------------------------------------------------\n\nasync function captureDatePickers(page: Page): Promise<DatePickerCapture[]> {\n const results: DatePickerCapture[] = [];\n\n // Native date / datetime-local inputs\n const nativeInputs = await page.$$('input[type=\"date\"], input[type=\"datetime-local\"]');\n for (const input of nativeInputs.slice(0, 5)) {\n try {\n const attrs = await input.evaluate((el: any) => ({\n type: el.type as string,\n min: el.min || undefined,\n max: el.max || undefined,\n id: el.id || '',\n name: el.name || '',\n }));\n\n // Resolve label text\n let fieldLabel = attrs.id || attrs.name || 'unknown';\n if (attrs.id) {\n const lblText = await page.evaluate((id: string) => {\n const lbl = document.querySelector(`label[for=\"${id}\"]`);\n return lbl ? (lbl.textContent ?? '').trim() : null;\n }, attrs.id);\n if (lblText) fieldLabel = lblText;\n }\n\n // Try filling a known date and reading it back\n let sampleSelectedValue: string | undefined;\n try {\n await input.fill('2026-09-15');\n sampleSelectedValue = await input.inputValue();\n if (!sampleSelectedValue) sampleSelectedValue = undefined;\n } catch {\n // ignore fill errors\n }\n\n results.push({\n fieldLabel,\n pickerType: attrs.type === 'datetime-local' ? 'native-datetime' : 'native-date',\n minDate: attrs.min,\n maxDate: attrs.max,\n disabledDatesFound: false, // native inputs have no visual disabled cells\n sampleSelectedValue,\n });\n } catch {\n // skip this element\n }\n }\n\n // Calendar-popup pickers (custom widgets triggered by click)\n // Only look for inputs not already classified as native date inputs\n const customInputs = await page.$$('input:not([type=\"date\"]):not([type=\"datetime-local\"]):not([type=\"hidden\"])');\n for (const input of customInputs.slice(0, 5)) {\n if (results.length >= 5) break;\n\n try {\n await input.click();\n // Wait up to 2 s for a calendar grid to appear\n const calendarAppeared = await page.waitForSelector('[role=\"grid\"]', { timeout: 2000 })\n .then(() => true)\n .catch(() => false);\n\n if (!calendarAppeared) {\n await page.keyboard.press('Escape');\n continue;\n }\n\n // Capture month/year header\n const monthHeader = await page.evaluate(() => {\n const header = document.querySelector('[role=\"grid\"] caption, [role=\"columnheader\"], .calendar-header, .rdp-caption');\n return header ? (header.textContent ?? '').trim().slice(0, 60) : '';\n });\n\n // Count disabled cells\n const disabledCount = await page.evaluate(() =>\n document.querySelectorAll('[role=\"gridcell\"][aria-disabled=\"true\"], [role=\"gridcell\"].disabled').length\n );\n\n // Resolve label for this input\n const inputId = await input.evaluate((el: any) => el.id || el.name || '');\n let fieldLabel = inputId || 'datepicker';\n if (inputId) {\n const lblText = await page.evaluate((id: string) => {\n const lbl = document.querySelector(`label[for=\"${id}\"]`);\n return lbl ? (lbl.textContent ?? '').trim() : null;\n }, inputId);\n if (lblText) fieldLabel = lblText;\n }\n\n // Click the first enabled cell and read value\n let sampleSelectedValue: string | undefined;\n try {\n const firstEnabled = await page.$('[role=\"gridcell\"]:not([aria-disabled=\"true\"]):not(.disabled)');\n if (firstEnabled) {\n await firstEnabled.click();\n sampleSelectedValue = await input.inputValue().catch(() => undefined);\n }\n } catch {\n // ignore\n }\n\n await page.keyboard.press('Escape');\n\n results.push({\n fieldLabel,\n pickerType: 'calendar-popup',\n disabledDatesFound: disabledCount > 0,\n sampleSelectedValue: sampleSelectedValue || undefined,\n });\n } catch {\n try { await page.keyboard.press('Escape'); } catch { /* ignore */ }\n }\n }\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Internal: sliders\n// ---------------------------------------------------------------------------\n\nasync function captureSliders(page: Page): Promise<SliderCapture[]> {\n const results: SliderCapture[] = [];\n\n // Collect both native range inputs and ARIA sliders\n const handles = await page.$$('input[type=\"range\"], [role=\"slider\"]');\n\n for (const handle of handles.slice(0, 5)) {\n try {\n const attrs = await handle.evaluate((el: any) => {\n const min = parseFloat(el.min ?? el.getAttribute('aria-valuemin') ?? '0');\n const max = parseFloat(el.max ?? el.getAttribute('aria-valuemax') ?? '100');\n const step = parseFloat(el.step ?? el.getAttribute('aria-valuestep') ?? '1') || 1;\n const value = parseFloat(el.value ?? el.getAttribute('aria-valuenow') ?? String(min));\n const id = el.id || el.name || '';\n return { min, max, step, value, id };\n });\n\n // Resolve label\n let label = attrs.id || 'slider';\n if (attrs.id) {\n const lblText = await page.evaluate((id: string) => {\n const lbl = document.querySelector(`label[for=\"${id}\"]`);\n return lbl ? (lbl.textContent ?? '').trim() : null;\n }, attrs.id);\n if (lblText) label = lblText;\n }\n\n // Exercise fill to min then max then restore (native range only)\n const isNative = await handle.evaluate((el: any) => el.tagName.toLowerCase() === 'input');\n if (isNative) {\n try {\n await handle.fill(String(attrs.min));\n await handle.fill(String(attrs.max));\n await handle.fill(String(attrs.value));\n } catch {\n // ignore \u2014 read-only or detached\n }\n }\n\n results.push({\n label,\n min: attrs.min,\n max: attrs.max,\n step: attrs.step,\n currentValue: attrs.value,\n });\n } catch {\n // skip this element\n }\n }\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Internal: typeahead / autocomplete\n// ---------------------------------------------------------------------------\n\nasync function captureTypeaheads(page: Page): Promise<TypeaheadCapture[]> {\n const results: TypeaheadCapture[] = [];\n\n // Candidate selectors for typeahead inputs\n const candidates = await page.$$(\n '[role=\"combobox\"][aria-autocomplete], [aria-autocomplete=\"list\"], input.autocomplete, input[aria-autocomplete]'\n );\n\n for (const input of candidates.slice(0, 3)) {\n try {\n const inputId = await input.evaluate((el: any) => el.id || el.name || el.placeholder || '');\n\n // Resolve label\n let label = inputId || 'typeahead';\n if (inputId) {\n const lblText = await page.evaluate((id: string) => {\n const lbl = document.querySelector(`label[for=\"${id}\"]`);\n return lbl ? (lbl.textContent ?? '').trim() : null;\n }, inputId);\n if (lblText) label = lblText;\n }\n\n await input.click();\n await input.fill('');\n\n // Type 'a' and check whether a listbox appears\n await input.type('a', { delay: 100 });\n await page.waitForTimeout(500);\n\n let listboxVisible = await page.evaluate(() => {\n const lb = document.querySelector('[role=\"listbox\"]');\n if (!lb) return false;\n const style = window.getComputedStyle(lb);\n return style.display !== 'none' && style.visibility !== 'hidden';\n });\n\n let minCharsToTrigger = listboxVisible ? 1 : 2;\n\n if (!listboxVisible) {\n // Try a second character\n await input.type('b', { delay: 100 });\n await page.waitForTimeout(500);\n listboxVisible = await page.evaluate(() => {\n const lb = document.querySelector('[role=\"listbox\"]');\n if (!lb) return false;\n const style = window.getComputedStyle(lb);\n return style.display !== 'none' && style.visibility !== 'hidden';\n });\n if (listboxVisible) minCharsToTrigger = 2;\n }\n\n // Collect suggestion text from visible options\n const sampleSuggestions: string[] = [];\n if (listboxVisible) {\n const suggestions = await page.evaluate(() =>\n Array.from(document.querySelectorAll('[role=\"option\"]'))\n .slice(0, 8)\n .map(o => (o.textContent ?? '').trim())\n .filter(Boolean)\n );\n sampleSuggestions.push(...suggestions);\n }\n\n // Type a nonsense string to capture the \"no results\" message\n await input.fill('ZZXQQ_NORESULT_9999');\n await page.waitForTimeout(500);\n\n const noResultsText = await page.evaluate(() => {\n // Common no-results patterns\n const selectors = [\n '[role=\"listbox\"] [role=\"option\"]',\n '[role=\"status\"]',\n '.no-results',\n '.empty-message',\n '[data-testid*=\"no-result\"]',\n ];\n for (const sel of selectors) {\n const el = document.querySelector(sel);\n if (el) {\n const txt = (el.textContent ?? '').trim();\n if (txt) return txt.slice(0, 120);\n }\n }\n return null;\n });\n\n // Clear the input to leave the page in a clean state\n await input.fill('');\n\n results.push({\n label,\n minCharsToTrigger,\n sampleSuggestions,\n noResultsText,\n });\n } catch {\n try { await input.fill(''); } catch { /* ignore */ }\n }\n }\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Public orchestrator\n// ---------------------------------------------------------------------------\n\nexport async function probeAdvancedUI(page: Page): Promise<AdvancedProbeResult> {\n const defaultDragDrop: DragDropCapture = {\n library: 'none',\n draggableCount: 0,\n dropZoneCount: 0,\n testAttempted: false,\n testCompleted: false,\n };\n\n const [dragDrop, datePickers, sliders, typeaheads] = await Promise.all([\n detectDragAndDrop(page).catch((): DragDropCapture => defaultDragDrop),\n captureDatePickers(page).catch((): DatePickerCapture[] => []),\n captureSliders(page).catch((): SliderCapture[] => []),\n captureTypeaheads(page).catch((): TypeaheadCapture[] => []),\n ]);\n\n return { dragDrop, datePickers, sliders, typeaheads };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,32 @@
1
+ import type { Stagehand } from '@browserbasehq/stagehand';
2
+ import type { Credentials } from './auth.js';
3
+ /**
4
+ * Recorded login step from the Chrome extension's step recorder.
5
+ * {username} and {password} in `value` are substituted at replay time.
6
+ */
7
+ export interface LoginStep {
8
+ action: 'fill' | 'click' | 'wait';
9
+ selector: string;
10
+ value?: string;
11
+ ms?: number;
12
+ }
13
+ /**
14
+ * AI-guided login using Stagehand act/extract.
15
+ *
16
+ * @param loginInstructions - Optional natural language description of the login flow.
17
+ * When provided, an initial stagehand.act() is called with these instructions to
18
+ * navigate the UI (e.g. "click Sign In in the nav, fill email, click Continue").
19
+ * The standard 3-step credential fill follows immediately after.
20
+ * @param opts - Optional tenant/project/job IDs for writing AUTH_STEP CrawlEvidence.
21
+ */
22
+ export declare function loginWithStagehand(stagehand: Stagehand, creds: Credentials, startUrl: string, captchaOpts?: {
23
+ apiKey?: string;
24
+ provider?: '2captcha' | 'capsolver';
25
+ }, emailOtpOpts?: {
26
+ apiKey?: string;
27
+ inboxId?: string;
28
+ }, loginInstructions?: string, opts?: {
29
+ tenantId?: string;
30
+ projectId?: string;
31
+ jobId?: string;
32
+ }): Promise<boolean>;
@@ -0,0 +1,250 @@
1
+ import { z } from "zod";
2
+ import { AppBrain } from "@taodigital/app-brain";
3
+ import { solveCaptcha } from "./captcha-solver.js";
4
+ import { waitForEmailContent } from "./email-otp.js";
5
+ import { logger } from "./logger.js";
6
+ import { simulateMouseMovement } from "./stealth/human-behavior.js";
7
+ const CLICK_INTENT = /\b(click|tap|press|submit|select|choose|toggle)\b/i;
8
+ function isNoObjectGeneratedError(err) {
9
+ const name = String(err?.name ?? "");
10
+ const msg = String(err?.message ?? "");
11
+ return name.includes("NoObjectGenerated") || msg.includes("NoObjectGenerated") || msg.includes("No object generated");
12
+ }
13
+ async function actWithMouseSim(stagehand, instruction) {
14
+ if (CLICK_INTENT.test(instruction)) {
15
+ try {
16
+ const pg = await stagehand.resolvePage();
17
+ const viewport = pg.viewportSize() ?? { width: 1280, height: 720 };
18
+ const targetX = viewport.width * 0.3 + Math.random() * viewport.width * 0.4;
19
+ const targetY = viewport.height * 0.2 + Math.random() * viewport.height * 0.5;
20
+ await simulateMouseMovement(pg, targetX, targetY);
21
+ } catch {
22
+ }
23
+ }
24
+ return stagehand.act(instruction);
25
+ }
26
+ const TwoFASchema = z.object({
27
+ has2FA: z.boolean(),
28
+ fieldLabel: z.string().optional()
29
+ });
30
+ const CAPTCHA_SELECTORS = [
31
+ 'iframe[src*="recaptcha"]',
32
+ 'iframe[src*="hcaptcha"]',
33
+ 'iframe[src*="challenges.cloudflare.com"]',
34
+ ".cf-turnstile",
35
+ "[data-sitekey]",
36
+ "#captcha",
37
+ ".captcha",
38
+ '[id*="captcha"]',
39
+ '[class*="captcha"]'
40
+ ];
41
+ async function loginWithStagehand(stagehand, creds, startUrl, captchaOpts, emailOtpOpts, loginInstructions, opts) {
42
+ async function logStep(step, fn) {
43
+ const t0 = Date.now();
44
+ try {
45
+ const r = await fn();
46
+ const result = { success: true, detail: r?.description ?? r?.message ?? step };
47
+ if (opts?.tenantId && opts?.projectId) {
48
+ AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {
49
+ jobId: opts?.jobId,
50
+ type: "AUTH_STEP",
51
+ payload: { step, ...result, ms: Date.now() - t0 }
52
+ }).catch(() => {
53
+ });
54
+ }
55
+ return result;
56
+ } catch (e) {
57
+ const result = { success: false, detail: e.message ?? "failed" };
58
+ if (opts?.tenantId && opts?.projectId) {
59
+ AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {
60
+ jobId: opts?.jobId,
61
+ type: "AUTH_STEP",
62
+ payload: { step, ...result, ms: Date.now() - t0 }
63
+ }).catch(() => {
64
+ });
65
+ }
66
+ throw e;
67
+ }
68
+ }
69
+ try {
70
+ const pg = await stagehand.resolvePage();
71
+ for (const sel of CAPTCHA_SELECTORS) {
72
+ const count = await pg.locator(sel).count().catch(() => 0);
73
+ if (count > 0) {
74
+ logger.warn({ selector: sel }, "[crawler] CAPTCHA detected on login page");
75
+ if (captchaOpts?.apiKey) {
76
+ logger.info({ provider: captchaOpts.provider ?? "2captcha" }, "[crawler] Attempting auto-solve");
77
+ try {
78
+ const result = await solveCaptcha(pg, startUrl, captchaOpts.apiKey, captchaOpts.provider ?? "2captcha");
79
+ if (result) {
80
+ logger.info({ provider: result.provider }, "[crawler] CAPTCHA solved \u2014 proceeding with login");
81
+ break;
82
+ }
83
+ } catch (solveErr) {
84
+ logger.warn({ err: solveErr }, "[crawler] CAPTCHA solve failed \u2014 falling back to manual error");
85
+ throw new Error(`CAPTCHA_DETECTED: Auto-solve failed (${String(solveErr)}). Use session capture instead.`);
86
+ }
87
+ } else {
88
+ throw new Error(
89
+ 'CAPTCHA_DETECTED: Login page has a CAPTCHA. Use "Session Capture \u2192 Launch Browser" to log in manually, then capture the session. Alternatively, disable CAPTCHA for the ZeTa crawler IP.'
90
+ );
91
+ }
92
+ break;
93
+ }
94
+ }
95
+ const MAX_LOGIN_INSTRUCTIONS = 2e3;
96
+ if (loginInstructions && loginInstructions.length > MAX_LOGIN_INSTRUCTIONS) {
97
+ throw new Error(`loginInstructions exceeds ${MAX_LOGIN_INSTRUCTIONS} character limit`);
98
+ }
99
+ if (loginInstructions) {
100
+ await logStep("custom_recipe", async () => {
101
+ try {
102
+ return await actWithMouseSim(stagehand, loginInstructions);
103
+ } catch (err) {
104
+ if (!isNoObjectGeneratedError(err)) throw err;
105
+ logger.warn("[crawler] custom_recipe act() failed \u2014 Stagehand V3 elementId schema error, skipping to standard fill");
106
+ return { description: "custom_recipe skipped (schema error)" };
107
+ }
108
+ });
109
+ await pg.waitForLoadState("networkidle").catch(() => pg.waitForTimeout(1500));
110
+ }
111
+ await logStep("fill_username", async () => {
112
+ try {
113
+ return await actWithMouseSim(stagehand, `Type "${creds.username}" into the username or email input field`);
114
+ } catch (err) {
115
+ if (!isNoObjectGeneratedError(err)) throw err;
116
+ logger.warn("[crawler] fill_username act() failed \u2014 falling back to DOM");
117
+ const sel = 'input[type="email"], input[autocomplete="email"], input[autocomplete="username"], input[name*="email" i], input[name*="user" i], input[placeholder*="email" i], input[placeholder*="user" i], input[id*="email" i], input[id*="user" i]';
118
+ await pg.locator(sel).first().fill(creds.username);
119
+ return { description: "fill_username via DOM fallback" };
120
+ }
121
+ });
122
+ await logStep("fill_password", async () => {
123
+ const observations = await stagehand.observe("Find the password input field");
124
+ const selector = observations[0]?.selector || 'input[type="password"]';
125
+ try {
126
+ await pg.locator(selector).fill(creds.password);
127
+ } catch {
128
+ await pg.evaluate((pwd) => {
129
+ const input = document.querySelector('input[type="password"]');
130
+ if (!input) throw new Error("No password field found on page");
131
+ const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set;
132
+ setter?.call(input, pwd);
133
+ input.dispatchEvent(new Event("input", { bubbles: true }));
134
+ input.dispatchEvent(new Event("change", { bubbles: true }));
135
+ }, creds.password);
136
+ }
137
+ });
138
+ await logStep("click_submit", async () => {
139
+ try {
140
+ return await actWithMouseSim(stagehand, "Click the sign in, log in, login, or continue button to submit credentials");
141
+ } catch (err) {
142
+ if (!isNoObjectGeneratedError(err)) throw err;
143
+ logger.warn("[crawler] click_submit act() failed \u2014 falling back to DOM");
144
+ const sel = 'button[type="submit"], input[type="submit"], button:has-text("Sign in"), button:has-text("Log in"), button:has-text("Login"), button:has-text("Continue"), button:has-text("Next"), button:has-text("Sign In"), [role="button"]:has-text("Sign in"), [role="button"]:has-text("Login")';
145
+ await pg.locator(sel).first().click();
146
+ await pg.waitForTimeout(500);
147
+ return { description: "click_submit via DOM fallback" };
148
+ }
149
+ });
150
+ await pg.waitForLoadState("networkidle").catch(() => pg.waitForTimeout(2e3));
151
+ const twoFA = await stagehand.extract(
152
+ "Is there a two-factor authentication, OTP, or verification code input visible right now?",
153
+ TwoFASchema
154
+ );
155
+ if (twoFA.has2FA) {
156
+ if (opts?.tenantId && opts?.projectId) {
157
+ AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {
158
+ jobId: opts?.jobId,
159
+ type: "AUTH_STEP",
160
+ payload: { step: "2fa_detect", success: true, detail: twoFA.fieldLabel ?? "2FA detected", ms: 0 }
161
+ }).catch(() => {
162
+ });
163
+ }
164
+ let code = creds.oneTimeCode ?? await creds.getOneTimeCode?.();
165
+ if (!code && emailOtpOpts?.apiKey && emailOtpOpts?.inboxId) {
166
+ const since = (/* @__PURE__ */ new Date()).toISOString();
167
+ logger.info("[crawler] 2FA detected \u2014 waiting for email OTP or magic link via MailSlurp");
168
+ const emailContent = await waitForEmailContent(
169
+ { provider: "mailslurp", apiKey: emailOtpOpts.apiKey, inboxId: emailOtpOpts.inboxId },
170
+ since
171
+ );
172
+ if (emailContent?.magicLink) {
173
+ logger.info({ url: emailContent.magicLink }, "[crawler] Magic link received \u2014 navigating");
174
+ await pg.goto(emailContent.magicLink, { waitUntil: "domcontentloaded" });
175
+ await pg.waitForLoadState("networkidle").catch(() => {
176
+ });
177
+ return true;
178
+ }
179
+ code = emailContent?.otp ?? void 0;
180
+ if (code) {
181
+ logger.info("[crawler] Email OTP received");
182
+ } else {
183
+ logger.warn("[crawler] Email OTP timed out after 60s");
184
+ }
185
+ }
186
+ if (!code) {
187
+ console.warn("[crawler] 2FA detected but no oneTimeCode provided");
188
+ return false;
189
+ }
190
+ await logStep("2fa_inject", async () => {
191
+ try {
192
+ return await actWithMouseSim(stagehand, `Enter "${code}" into the ${twoFA.fieldLabel ?? "verification code"} field`);
193
+ } catch (err) {
194
+ if (!isNoObjectGeneratedError(err)) throw err;
195
+ logger.warn("[crawler] 2fa_inject act() failed \u2014 falling back to DOM");
196
+ const sel = 'input[autocomplete="one-time-code"], input[name*="otp" i], input[name*="code" i], input[name*="token" i], input[inputmode="numeric"], input[type="number"]';
197
+ await pg.locator(sel).first().fill(code);
198
+ return { description: "2fa_inject via DOM fallback" };
199
+ }
200
+ });
201
+ await logStep("2fa_submit", async () => {
202
+ try {
203
+ return await actWithMouseSim(stagehand, "Click verify or confirm to submit the verification code");
204
+ } catch (err) {
205
+ if (!isNoObjectGeneratedError(err)) throw err;
206
+ logger.warn("[crawler] 2fa_submit act() failed \u2014 falling back to DOM");
207
+ const sel = 'button[type="submit"], button:has-text("Verify"), button:has-text("Confirm"), button:has-text("Submit"), button:has-text("Continue")';
208
+ await pg.locator(sel).first().click();
209
+ return { description: "2fa_submit via DOM fallback" };
210
+ }
211
+ });
212
+ await pg.waitForLoadState("networkidle").catch(() => pg.waitForTimeout(2e3));
213
+ }
214
+ const currentUrl = pg.url();
215
+ const loginPathPattern = /\/(login|signin|sign-in|auth|authenticate|log-in|account\/login)(\?|$|\/)/i;
216
+ try {
217
+ const { pathname } = new URL(currentUrl);
218
+ const wasRedirected = currentUrl !== startUrl;
219
+ const stillOnLoginPath = loginPathPattern.test(pathname);
220
+ if (wasRedirected && !stillOnLoginPath) {
221
+ logger.info({ url: currentUrl }, "Login confirmed via URL change");
222
+ return true;
223
+ }
224
+ } catch {
225
+ }
226
+ const passwordCount = await pg.locator('input[type="password"]').count().catch(() => 1);
227
+ const bodyText = await pg.evaluate(() => document.body?.innerText?.trim()?.length ?? 0).catch(() => 0);
228
+ if (passwordCount === 0 && bodyText > 30) {
229
+ logger.info("Login confirmed: password field no longer visible");
230
+ return true;
231
+ }
232
+ logger.warn({ url: currentUrl }, "Login appears failed");
233
+ try {
234
+ const screenshotPath = `/tmp/zeta-auth-failure-${Date.now()}.jpg`;
235
+ await pg.screenshot({ path: screenshotPath, type: "jpeg", quality: 70, fullPage: false });
236
+ logger.warn({ screenshotPath }, "[crawler] Auth failure screenshot saved");
237
+ } catch {
238
+ }
239
+ return false;
240
+ } catch (err) {
241
+ const msg = String(err.message ?? err);
242
+ if (msg.includes("CAPTCHA_DETECTED")) throw err;
243
+ logger.error({ err }, "Login error");
244
+ return false;
245
+ }
246
+ }
247
+ export {
248
+ loginWithStagehand
249
+ };
250
+ //# sourceMappingURL=ai-login.js.map