@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,132 @@
1
+ async function enumerateShadowHosts(page) {
2
+ const raw = await page.evaluate(() => {
3
+ if (typeof globalThis.__name === "undefined") globalThis.__name = (fn) => fn;
4
+ function collectHosts(root, depth) {
5
+ if (depth > 8) return [];
6
+ const hosts = [];
7
+ const els = root.querySelectorAll("*");
8
+ for (const el of Array.from(els)) {
9
+ const htmlEl = el;
10
+ if (htmlEl.shadowRoot) {
11
+ const interactive = htmlEl.shadowRoot.querySelectorAll(
12
+ 'button,input,select,textarea,a[href],[role="button"],[role="link"],[role="checkbox"],[role="menuitem"],[role="tab"],[role="switch"]'
13
+ );
14
+ const slots = Array.from(htmlEl.shadowRoot.querySelectorAll("slot")).map(
15
+ (s) => s.name || "default"
16
+ );
17
+ const nestedHosts = Array.from(htmlEl.shadowRoot.querySelectorAll("*")).filter(
18
+ (c) => c.shadowRoot
19
+ ).length;
20
+ hosts.push({
21
+ tagName: htmlEl.tagName.toLowerCase(),
22
+ hostId: htmlEl.id || htmlEl.className?.toString()?.split(" ")[0] || "",
23
+ shadowMode: "open",
24
+ depth,
25
+ interactiveCount: interactive.length,
26
+ interactiveDetails: Array.from(interactive).slice(0, 8).map((i) => {
27
+ const iEl = i;
28
+ return {
29
+ role: iEl.getAttribute("role") || iEl.tagName.toLowerCase(),
30
+ label: (iEl.getAttribute("aria-label") || iEl.getAttribute("placeholder") || iEl.textContent?.trim() || "").slice(0, 40),
31
+ type: iEl.getAttribute("type") || "",
32
+ tagName: iEl.tagName.toLowerCase()
33
+ };
34
+ }),
35
+ slotNames: slots,
36
+ childShadowHosts: nestedHosts
37
+ });
38
+ const nested = collectHosts(htmlEl.shadowRoot, depth + 1);
39
+ hosts.push(...nested);
40
+ } else if (el.tagName.includes("-") && !el.shadowRoot) {
41
+ hosts.push({
42
+ tagName: el.tagName.toLowerCase(),
43
+ hostId: el.id || "",
44
+ shadowMode: "closed",
45
+ depth,
46
+ interactiveCount: 0,
47
+ interactiveDetails: [],
48
+ slotNames: [],
49
+ childShadowHosts: 0
50
+ });
51
+ }
52
+ }
53
+ return hosts;
54
+ }
55
+ return collectHosts(document, 0);
56
+ });
57
+ return raw.slice(0, 100).map((h) => ({
58
+ tagName: h.tagName,
59
+ hostId: h.hostId,
60
+ shadowMode: h.shadowMode,
61
+ depth: h.depth,
62
+ interactiveCount: h.interactiveCount,
63
+ interactiveElements: h.interactiveDetails,
64
+ slotNames: h.slotNames,
65
+ childShadowHosts: h.childShadowHosts
66
+ }));
67
+ }
68
+ async function detectWebComponentLibrary(page) {
69
+ return page.evaluate(() => {
70
+ const checks = [
71
+ ["sl-button", "Shoelace"],
72
+ ["fast-button", "Microsoft FAST"],
73
+ ["mwc-button", "Material Web Components"],
74
+ ["ion-button", "Ionic"],
75
+ ["vaadin-button", "Vaadin"],
76
+ ["fluent-button", "Fluent UI Web Components"],
77
+ ["hy-icon", "Hydra"]
78
+ ];
79
+ const detected = [];
80
+ for (const [tag, name] of checks) {
81
+ if (customElements.get(tag)) detected.push(name);
82
+ }
83
+ const allTags = Array.from(document.querySelectorAll("*")).map((e) => e.tagName.toLowerCase()).filter((t) => t.includes("-"));
84
+ const uniqueTags = Array.from(new Set(allTags));
85
+ if (uniqueTags.some((t) => t.startsWith("sl-")) && !detected.includes("Shoelace"))
86
+ detected.push("Shoelace");
87
+ if (uniqueTags.some((t) => t.startsWith("fast-")) && !detected.includes("Microsoft FAST"))
88
+ detected.push("Microsoft FAST");
89
+ if (uniqueTags.some((t) => t.startsWith("ion-")) && !detected.includes("Ionic"))
90
+ detected.push("Ionic");
91
+ return detected;
92
+ });
93
+ }
94
+ async function crawlShadowDom(page) {
95
+ const empty = {
96
+ shadowHostCount: 0,
97
+ openShadowCount: 0,
98
+ closedShadowCount: 0,
99
+ maxNestingDepth: 0,
100
+ hosts: [],
101
+ totalInteractiveInShadow: 0,
102
+ detectedLibraries: [],
103
+ blindSpots: []
104
+ };
105
+ try {
106
+ const [hosts, detectedLibraries] = await Promise.all([
107
+ enumerateShadowHosts(page),
108
+ detectWebComponentLibrary(page)
109
+ ]);
110
+ const openHosts = hosts.filter((h) => h.shadowMode === "open");
111
+ const closedHosts = hosts.filter((h) => h.shadowMode === "closed");
112
+ const maxNestingDepth = hosts.reduce((max, h) => Math.max(max, h.depth), 0);
113
+ const totalInteractiveInShadow = openHosts.reduce((sum, h) => sum + h.interactiveCount, 0);
114
+ const blindSpots = [...new Set(closedHosts.map((h) => h.tagName))];
115
+ return {
116
+ shadowHostCount: hosts.length,
117
+ openShadowCount: openHosts.length,
118
+ closedShadowCount: closedHosts.length,
119
+ maxNestingDepth,
120
+ hosts,
121
+ totalInteractiveInShadow,
122
+ detectedLibraries,
123
+ blindSpots
124
+ };
125
+ } catch {
126
+ return empty;
127
+ }
128
+ }
129
+ export {
130
+ crawlShadowDom
131
+ };
132
+ //# sourceMappingURL=shadow-dom-crawler.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/shadow-dom-crawler.ts"],
4
+ "sourcesContent": ["/**\n * Shadow DOM crawler \u2014 enumerate shadow hosts and detect web component libraries.\n *\n * Walks the live DOM recursively (up to depth 8) to find all open shadow roots\n * and custom elements with closed shadow roots, then classifies the component\n * framework in use. Results feed ZeTa's test generator so it can account for\n * elements that are invisible to standard Playwright locators.\n */\n\nimport type { Page } from 'playwright';\n\nexport interface ShadowInteractiveEl {\n role: string;\n label: string;\n type: string;\n tagName: string;\n}\n\nexport interface ShadowHostInfo {\n tagName: string;\n hostId: string;\n shadowMode: 'open' | 'closed';\n depth: number;\n interactiveCount: number;\n interactiveElements: ShadowInteractiveEl[];\n slotNames: string[];\n childShadowHosts: number;\n}\n\nexport interface ShadowDomCrawlResult {\n shadowHostCount: number;\n openShadowCount: number;\n closedShadowCount: number;\n maxNestingDepth: number;\n hosts: ShadowHostInfo[];\n totalInteractiveInShadow: number;\n detectedLibraries: string[];\n blindSpots: string[];\n}\n\ninterface RawShadowHost {\n tagName: string;\n hostId: string;\n shadowMode: 'open' | 'closed';\n depth: number;\n interactiveCount: number;\n interactiveDetails: Array<{ role: string; label: string; type: string; tagName: string }>;\n slotNames: string[];\n childShadowHosts: number;\n}\n\nasync function enumerateShadowHosts(page: any): Promise<ShadowHostInfo[]> {\n const raw: RawShadowHost[] = await page.evaluate(() => {\n // esbuild injects __name() for named function declarations; polyfill prevents ReferenceError in browser.\n if (typeof (globalThis as any).__name === 'undefined') (globalThis as any).__name = (fn: any) => fn;\n function collectHosts(root: Document | ShadowRoot, depth: number): RawShadowHost[] {\n if (depth > 8) return [];\n const hosts: RawShadowHost[] = [];\n const els = root.querySelectorAll('*');\n for (const el of Array.from(els)) {\n const htmlEl = el as HTMLElement & { shadowRoot: ShadowRoot | null };\n if (htmlEl.shadowRoot) {\n const interactive = htmlEl.shadowRoot.querySelectorAll(\n 'button,input,select,textarea,a[href],[role=\"button\"],[role=\"link\"],[role=\"checkbox\"],[role=\"menuitem\"],[role=\"tab\"],[role=\"switch\"]'\n );\n const slots = Array.from(htmlEl.shadowRoot.querySelectorAll('slot')).map(\n (s) => (s as HTMLSlotElement).name || 'default'\n );\n const nestedHosts = Array.from(htmlEl.shadowRoot.querySelectorAll('*')).filter(\n (c) => (c as HTMLElement & { shadowRoot: ShadowRoot | null }).shadowRoot\n ).length;\n hosts.push({\n tagName: htmlEl.tagName.toLowerCase(),\n hostId:\n htmlEl.id ||\n (htmlEl.className?.toString()?.split(' ')[0]) ||\n '',\n shadowMode: 'open',\n depth,\n interactiveCount: interactive.length,\n interactiveDetails: Array.from(interactive)\n .slice(0, 8)\n .map((i) => {\n const iEl = i as HTMLElement;\n return {\n role: iEl.getAttribute('role') || iEl.tagName.toLowerCase(),\n label: (\n iEl.getAttribute('aria-label') ||\n iEl.getAttribute('placeholder') ||\n iEl.textContent?.trim() ||\n ''\n ).slice(0, 40),\n type: iEl.getAttribute('type') || '',\n tagName: iEl.tagName.toLowerCase(),\n };\n }),\n slotNames: slots,\n childShadowHosts: nestedHosts,\n });\n const nested = collectHosts(htmlEl.shadowRoot, depth + 1);\n hosts.push(...nested);\n } else if (el.tagName.includes('-') && !(el as HTMLElement & { shadowRoot: ShadowRoot | null }).shadowRoot) {\n hosts.push({\n tagName: el.tagName.toLowerCase(),\n hostId: (el as HTMLElement).id || '',\n shadowMode: 'closed',\n depth,\n interactiveCount: 0,\n interactiveDetails: [],\n slotNames: [],\n childShadowHosts: 0,\n });\n }\n }\n return hosts;\n }\n return collectHosts(document, 0);\n });\n\n return raw.slice(0, 100).map((h) => ({\n tagName: h.tagName,\n hostId: h.hostId,\n shadowMode: h.shadowMode,\n depth: h.depth,\n interactiveCount: h.interactiveCount,\n interactiveElements: h.interactiveDetails,\n slotNames: h.slotNames,\n childShadowHosts: h.childShadowHosts,\n }));\n}\n\nasync function detectWebComponentLibrary(page: any): Promise<string[]> {\n return page.evaluate(() => {\n const checks: [string, string][] = [\n ['sl-button', 'Shoelace'],\n ['fast-button', 'Microsoft FAST'],\n ['mwc-button', 'Material Web Components'],\n ['ion-button', 'Ionic'],\n ['vaadin-button', 'Vaadin'],\n ['fluent-button', 'Fluent UI Web Components'],\n ['hy-icon', 'Hydra'],\n ];\n const detected: string[] = [];\n for (const [tag, name] of checks) {\n if (customElements.get(tag)) detected.push(name);\n }\n const allTags = Array.from(document.querySelectorAll('*'))\n .map((e) => e.tagName.toLowerCase())\n .filter((t) => t.includes('-'));\n const uniqueTags = Array.from(new Set(allTags));\n if (uniqueTags.some((t) => t.startsWith('sl-')) && !detected.includes('Shoelace'))\n detected.push('Shoelace');\n if (uniqueTags.some((t) => t.startsWith('fast-')) && !detected.includes('Microsoft FAST'))\n detected.push('Microsoft FAST');\n if (uniqueTags.some((t) => t.startsWith('ion-')) && !detected.includes('Ionic'))\n detected.push('Ionic');\n return detected;\n });\n}\n\nexport async function crawlShadowDom(page: any): Promise<ShadowDomCrawlResult> {\n const empty: ShadowDomCrawlResult = {\n shadowHostCount: 0,\n openShadowCount: 0,\n closedShadowCount: 0,\n maxNestingDepth: 0,\n hosts: [],\n totalInteractiveInShadow: 0,\n detectedLibraries: [],\n blindSpots: [],\n };\n\n try {\n const [hosts, detectedLibraries] = await Promise.all([\n enumerateShadowHosts(page),\n detectWebComponentLibrary(page),\n ]);\n\n const openHosts = hosts.filter((h) => h.shadowMode === 'open');\n const closedHosts = hosts.filter((h) => h.shadowMode === 'closed');\n const maxNestingDepth = hosts.reduce((max, h) => Math.max(max, h.depth), 0);\n const totalInteractiveInShadow = openHosts.reduce((sum, h) => sum + h.interactiveCount, 0);\n const blindSpots = [...new Set(closedHosts.map((h) => h.tagName))];\n\n return {\n shadowHostCount: hosts.length,\n openShadowCount: openHosts.length,\n closedShadowCount: closedHosts.length,\n maxNestingDepth,\n hosts,\n totalInteractiveInShadow,\n detectedLibraries,\n blindSpots,\n };\n } catch {\n return empty;\n }\n}\n"],
5
+ "mappings": "AAmDA,eAAe,qBAAqB,MAAsC;AACxE,QAAM,MAAuB,MAAM,KAAK,SAAS,MAAM;AAErD,QAAI,OAAQ,WAAmB,WAAW,YAAa,CAAC,WAAmB,SAAS,CAAC,OAAY;AACjG,aAAS,aAAa,MAA6B,OAAgC;AACjF,UAAI,QAAQ,EAAG,QAAO,CAAC;AACvB,YAAM,QAAyB,CAAC;AAChC,YAAM,MAAM,KAAK,iBAAiB,GAAG;AACrC,iBAAW,MAAM,MAAM,KAAK,GAAG,GAAG;AAChC,cAAM,SAAS;AACf,YAAI,OAAO,YAAY;AACrB,gBAAM,cAAc,OAAO,WAAW;AAAA,YACpC;AAAA,UACF;AACA,gBAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,iBAAiB,MAAM,CAAC,EAAE;AAAA,YACnE,CAAC,MAAO,EAAsB,QAAQ;AAAA,UACxC;AACA,gBAAM,cAAc,MAAM,KAAK,OAAO,WAAW,iBAAiB,GAAG,CAAC,EAAE;AAAA,YACtE,CAAC,MAAO,EAAsD;AAAA,UAChE,EAAE;AACF,gBAAM,KAAK;AAAA,YACT,SAAS,OAAO,QAAQ,YAAY;AAAA,YACpC,QACE,OAAO,MACN,OAAO,WAAW,SAAS,GAAG,MAAM,GAAG,EAAE,CAAC,KAC3C;AAAA,YACF,YAAY;AAAA,YACZ;AAAA,YACA,kBAAkB,YAAY;AAAA,YAC9B,oBAAoB,MAAM,KAAK,WAAW,EACvC,MAAM,GAAG,CAAC,EACV,IAAI,CAAC,MAAM;AACV,oBAAM,MAAM;AACZ,qBAAO;AAAA,gBACL,MAAM,IAAI,aAAa,MAAM,KAAK,IAAI,QAAQ,YAAY;AAAA,gBAC1D,QACE,IAAI,aAAa,YAAY,KAC7B,IAAI,aAAa,aAAa,KAC9B,IAAI,aAAa,KAAK,KACtB,IACA,MAAM,GAAG,EAAE;AAAA,gBACb,MAAM,IAAI,aAAa,MAAM,KAAK;AAAA,gBAClC,SAAS,IAAI,QAAQ,YAAY;AAAA,cACnC;AAAA,YACF,CAAC;AAAA,YACH,WAAW;AAAA,YACX,kBAAkB;AAAA,UACpB,CAAC;AACD,gBAAM,SAAS,aAAa,OAAO,YAAY,QAAQ,CAAC;AACxD,gBAAM,KAAK,GAAG,MAAM;AAAA,QACtB,WAAW,GAAG,QAAQ,SAAS,GAAG,KAAK,CAAE,GAAuD,YAAY;AAC1G,gBAAM,KAAK;AAAA,YACT,SAAS,GAAG,QAAQ,YAAY;AAAA,YAChC,QAAS,GAAmB,MAAM;AAAA,YAClC,YAAY;AAAA,YACZ;AAAA,YACA,kBAAkB;AAAA,YAClB,oBAAoB,CAAC;AAAA,YACrB,WAAW,CAAC;AAAA,YACZ,kBAAkB;AAAA,UACpB,CAAC;AAAA,QACH;AAAA,MACF;AACA,aAAO;AAAA,IACT;AACA,WAAO,aAAa,UAAU,CAAC;AAAA,EACjC,CAAC;AAED,SAAO,IAAI,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,OAAO;AAAA,IACnC,SAAS,EAAE;AAAA,IACX,QAAQ,EAAE;AAAA,IACV,YAAY,EAAE;AAAA,IACd,OAAO,EAAE;AAAA,IACT,kBAAkB,EAAE;AAAA,IACpB,qBAAqB,EAAE;AAAA,IACvB,WAAW,EAAE;AAAA,IACb,kBAAkB,EAAE;AAAA,EACtB,EAAE;AACJ;AAEA,eAAe,0BAA0B,MAA8B;AACrE,SAAO,KAAK,SAAS,MAAM;AACzB,UAAM,SAA6B;AAAA,MACjC,CAAC,aAAa,UAAU;AAAA,MACxB,CAAC,eAAe,gBAAgB;AAAA,MAChC,CAAC,cAAc,yBAAyB;AAAA,MACxC,CAAC,cAAc,OAAO;AAAA,MACtB,CAAC,iBAAiB,QAAQ;AAAA,MAC1B,CAAC,iBAAiB,0BAA0B;AAAA,MAC5C,CAAC,WAAW,OAAO;AAAA,IACrB;AACA,UAAM,WAAqB,CAAC;AAC5B,eAAW,CAAC,KAAK,IAAI,KAAK,QAAQ;AAChC,UAAI,eAAe,IAAI,GAAG,EAAG,UAAS,KAAK,IAAI;AAAA,IACjD;AACA,UAAM,UAAU,MAAM,KAAK,SAAS,iBAAiB,GAAG,CAAC,EACtD,IAAI,CAAC,MAAM,EAAE,QAAQ,YAAY,CAAC,EAClC,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,CAAC;AAChC,UAAM,aAAa,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC;AAC9C,QAAI,WAAW,KAAK,CAAC,MAAM,EAAE,WAAW,KAAK,CAAC,KAAK,CAAC,SAAS,SAAS,UAAU;AAC9E,eAAS,KAAK,UAAU;AAC1B,QAAI,WAAW,KAAK,CAAC,MAAM,EAAE,WAAW,OAAO,CAAC,KAAK,CAAC,SAAS,SAAS,gBAAgB;AACtF,eAAS,KAAK,gBAAgB;AAChC,QAAI,WAAW,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM,CAAC,KAAK,CAAC,SAAS,SAAS,OAAO;AAC5E,eAAS,KAAK,OAAO;AACvB,WAAO;AAAA,EACT,CAAC;AACH;AAEA,eAAsB,eAAe,MAA0C;AAC7E,QAAM,QAA8B;AAAA,IAClC,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,OAAO,CAAC;AAAA,IACR,0BAA0B;AAAA,IAC1B,mBAAmB,CAAC;AAAA,IACpB,YAAY,CAAC;AAAA,EACf;AAEA,MAAI;AACF,UAAM,CAAC,OAAO,iBAAiB,IAAI,MAAM,QAAQ,IAAI;AAAA,MACnD,qBAAqB,IAAI;AAAA,MACzB,0BAA0B,IAAI;AAAA,IAChC,CAAC;AAED,UAAM,YAAY,MAAM,OAAO,CAAC,MAAM,EAAE,eAAe,MAAM;AAC7D,UAAM,cAAc,MAAM,OAAO,CAAC,MAAM,EAAE,eAAe,QAAQ;AACjE,UAAM,kBAAkB,MAAM,OAAO,CAAC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,KAAK,GAAG,CAAC;AAC1E,UAAM,2BAA2B,UAAU,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,kBAAkB,CAAC;AACzF,UAAM,aAAa,CAAC,GAAG,IAAI,IAAI,YAAY,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjE,WAAO;AAAA,MACL,iBAAiB,MAAM;AAAA,MACvB,iBAAiB,UAAU;AAAA,MAC3B,mBAAmB,YAAY;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Sitemap writer — generate XML sitemap from crawled screens.
3
+ *
4
+ * Compliant with sitemaps.org protocol (sitemap index + individual sitemap files).
5
+ * Splits into 50k-URL files per the spec when needed.
6
+ * Used for: SEO audit export, future crawl seed, and crawler/robots.txt comparison.
7
+ */
8
+ export interface SitemapUrl {
9
+ loc: string;
10
+ lastmod?: string;
11
+ changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
12
+ priority?: number;
13
+ }
14
+ export declare function writeSitemap(urls: SitemapUrl[], outputPath: string): Promise<void>;
15
+ /** Convert crawled screen records to SitemapUrl objects */
16
+ export declare function screensToSitemapUrls(screens: Array<{
17
+ url: string;
18
+ updatedAt?: Date;
19
+ depth?: number;
20
+ }>): SitemapUrl[];
21
+ export declare function buildSitemapString(urls: SitemapUrl[]): string;
@@ -0,0 +1,47 @@
1
+ import * as fs from "fs/promises";
2
+ import * as path from "path";
3
+ const XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>\n';
4
+ const SITEMAP_NS = 'xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"';
5
+ function escape(s) {
6
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
7
+ }
8
+ function buildSitemapXml(urls) {
9
+ const entries = urls.map((u) => [
10
+ " <url>",
11
+ ` <loc>${escape(u.loc)}</loc>`,
12
+ u.lastmod ? ` <lastmod>${u.lastmod}</lastmod>` : "",
13
+ u.changefreq ? ` <changefreq>${u.changefreq}</changefreq>` : "",
14
+ u.priority !== void 0 ? ` <priority>${u.priority.toFixed(1)}</priority>` : "",
15
+ " </url>"
16
+ ].filter(Boolean).join("\n")).join("\n");
17
+ return `${XML_HEADER}<urlset ${SITEMAP_NS}>
18
+ ${entries}
19
+ </urlset>`;
20
+ }
21
+ async function writeSitemap(urls, outputPath) {
22
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
23
+ await fs.writeFile(outputPath, buildSitemapXml(urls), "utf8");
24
+ }
25
+ function screensToSitemapUrls(screens) {
26
+ return screens.filter((s) => {
27
+ try {
28
+ return new URL(s.url).protocol.startsWith("http");
29
+ } catch {
30
+ return false;
31
+ }
32
+ }).map((s) => ({
33
+ loc: s.url,
34
+ lastmod: s.updatedAt ? s.updatedAt.toISOString().split("T")[0] : void 0,
35
+ changefreq: "weekly",
36
+ priority: s.depth === 0 ? 1 : s.depth === 1 ? 0.8 : 0.6
37
+ }));
38
+ }
39
+ function buildSitemapString(urls) {
40
+ return buildSitemapXml(urls);
41
+ }
42
+ export {
43
+ buildSitemapString,
44
+ screensToSitemapUrls,
45
+ writeSitemap
46
+ };
47
+ //# sourceMappingURL=sitemap-writer.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/sitemap-writer.ts"],
4
+ "sourcesContent": ["/**\n * Sitemap writer \u2014 generate XML sitemap from crawled screens.\n *\n * Compliant with sitemaps.org protocol (sitemap index + individual sitemap files).\n * Splits into 50k-URL files per the spec when needed.\n * Used for: SEO audit export, future crawl seed, and crawler/robots.txt comparison.\n */\n\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\n\nexport interface SitemapUrl {\n loc: string;\n lastmod?: string;\n changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';\n priority?: number; // 0.0\u20131.0\n}\n\nconst XML_HEADER = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n';\nconst SITEMAP_NS = 'xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"';\n\nfunction escape(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;').replace(/'/g, '&apos;');\n}\n\nfunction buildSitemapXml(urls: SitemapUrl[]): string {\n const entries = urls.map(u => [\n ' <url>',\n ` <loc>${escape(u.loc)}</loc>`,\n u.lastmod ? ` <lastmod>${u.lastmod}</lastmod>` : '',\n u.changefreq ? ` <changefreq>${u.changefreq}</changefreq>` : '',\n u.priority !== undefined ? ` <priority>${u.priority.toFixed(1)}</priority>` : '',\n ' </url>',\n ].filter(Boolean).join('\\n')).join('\\n');\n\n return `${XML_HEADER}<urlset ${SITEMAP_NS}>\\n${entries}\\n</urlset>`;\n}\n\nexport async function writeSitemap(\n urls: SitemapUrl[],\n outputPath: string,\n): Promise<void> {\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, buildSitemapXml(urls), 'utf8');\n}\n\n/** Convert crawled screen records to SitemapUrl objects */\nexport function screensToSitemapUrls(\n screens: Array<{ url: string; updatedAt?: Date; depth?: number }>,\n): SitemapUrl[] {\n return screens\n .filter(s => {\n try { return new URL(s.url).protocol.startsWith('http'); } catch { return false; }\n })\n .map(s => ({\n loc: s.url,\n lastmod: s.updatedAt ? s.updatedAt.toISOString().split('T')[0] : undefined,\n changefreq: 'weekly' as const,\n priority: s.depth === 0 ? 1.0 : s.depth === 1 ? 0.8 : 0.6,\n }));\n}\n\nexport function buildSitemapString(urls: SitemapUrl[]): string {\n return buildSitemapXml(urls);\n}\n"],
5
+ "mappings": "AAQA,YAAY,QAAQ;AACpB,YAAY,UAAU;AAStB,MAAM,aAAa;AACnB,MAAM,aAAa;AAEnB,SAAS,OAAO,GAAmB;AACjC,SAAO,EAAE,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,QAAQ,EAAE,QAAQ,MAAM,QAAQ;AAC5H;AAEA,SAAS,gBAAgB,MAA4B;AACnD,QAAM,UAAU,KAAK,IAAI,OAAK;AAAA,IAC5B;AAAA,IACA,YAAY,OAAO,EAAE,GAAG,CAAC;AAAA,IACzB,EAAE,UAAU,gBAAgB,EAAE,OAAO,eAAe;AAAA,IACpD,EAAE,aAAa,mBAAmB,EAAE,UAAU,kBAAkB;AAAA,IAChE,EAAE,aAAa,SAAY,iBAAiB,EAAE,SAAS,QAAQ,CAAC,CAAC,gBAAgB;AAAA,IACjF;AAAA,EACF,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI;AAEvC,SAAO,GAAG,UAAU,WAAW,UAAU;AAAA,EAAM,OAAO;AAAA;AACxD;AAEA,eAAsB,aACpB,MACA,YACe;AACf,QAAM,GAAG,MAAM,KAAK,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5D,QAAM,GAAG,UAAU,YAAY,gBAAgB,IAAI,GAAG,MAAM;AAC9D;AAGO,SAAS,qBACd,SACc;AACd,SAAO,QACJ,OAAO,OAAK;AACX,QAAI;AAAE,aAAO,IAAI,IAAI,EAAE,GAAG,EAAE,SAAS,WAAW,MAAM;AAAA,IAAG,QAAQ;AAAE,aAAO;AAAA,IAAO;AAAA,EACnF,CAAC,EACA,IAAI,QAAM;AAAA,IACT,KAAK,EAAE;AAAA,IACP,SAAS,EAAE,YAAY,EAAE,UAAU,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,IAAI;AAAA,IACjE,YAAY;AAAA,IACZ,UAAU,EAAE,UAAU,IAAI,IAAM,EAAE,UAAU,IAAI,MAAM;AAAA,EACxD,EAAE;AACN;AAEO,SAAS,mBAAmB,MAA4B;AAC7D,SAAO,gBAAgB,IAAI;AAC7B;",
6
+ "names": []
7
+ }
@@ -0,0 +1,51 @@
1
+ import { ProxyAgent } from 'undici';
2
+ /**
3
+ * Same-site check that tolerates www/non-www and http/https differences — a sitemap on
4
+ * `vercel.com` is valid for a project pointed at `www.vercel.com` (and vice versa).
5
+ */
6
+ export declare function sameSite(candidateUrl: string, siteOrigin: string): boolean;
7
+ /**
8
+ * Pulls page URLs and sub-sitemap URLs out of an already-XML-parsed sitemap
9
+ * document (either a <urlset> or a <sitemapindex>), filtered to same-origin
10
+ * and deduped. Pure function — no I/O — for direct unit testing without a
11
+ * real HTTP fetch.
12
+ */
13
+ export declare function extractUrlsFromParsedSitemap(parsed: any, origin: string, maxUrls?: number): {
14
+ pageUrls: string[];
15
+ subSitemapUrls: string[];
16
+ };
17
+ /**
18
+ * Fetches and parses a sitemap (or sitemap index, recursed up to a small
19
+ * depth) into a flat, deduped list of same-origin URLs.
20
+ */
21
+ export declare function fetchSitemapUrls(sitemapUrl: string, origin: string, depth?: number, dispatcher?: any, maxUrls?: number): Promise<string[]>;
22
+ /**
23
+ * Discovers a project's sitemap (default `${origin}/sitemap.xml`, or an
24
+ * explicit override) and returns the URLs it lists. Never throws.
25
+ */
26
+ export declare function discoverSitemapUrls(appUrl: string, sitemapUrl?: string): Promise<string[]>;
27
+ /**
28
+ * Build an undici ProxyAgent from a proxy URL. Parses credentials manually because
29
+ * DataImpulse-style usernames contain commas (country codes) that break new URL().
30
+ * Returns undefined for no/auto proxy — the caller then fetches directly.
31
+ */
32
+ export declare function buildProxyDispatcher(proxyUrl?: string): ProxyAgent | undefined;
33
+ /** Extract same-origin `Sitemap:` directives from a robots.txt body. */
34
+ export declare function parseRobotsSitemaps(robotsTxt: string, origin: string): string[];
35
+ export interface UrlCandidate {
36
+ url: string;
37
+ source: 'sitemap' | 'robots' | 'link';
38
+ }
39
+ /**
40
+ * Pre-crawl URL discovery for the review-before-crawl flow: reads robots.txt Sitemap
41
+ * directives and sitemap.xml (recursed, same-origin), proxy-aware. Returns a deduped
42
+ * candidate list the user can review and seed before launching the Playwright crawl.
43
+ * Never throws — bot-protected sites (Akamai/Cloudflare) simply yield an empty list.
44
+ */
45
+ export declare function discoverProjectUrls(appUrl: string, opts?: {
46
+ sitemapUrl?: string;
47
+ proxyUrl?: string;
48
+ }): Promise<{
49
+ candidates: UrlCandidate[];
50
+ sitemapFound: boolean;
51
+ }>;
@@ -0,0 +1,160 @@
1
+ import { XMLParser } from "fast-xml-parser";
2
+ import { ProxyAgent } from "undici";
3
+ import { assertCrawlUrlSafe } from "@taodigital/core/dist/ssrf-guard.js";
4
+ import { logger } from "./logger.js";
5
+ const FETCH_TIMEOUT_MS = 1e4;
6
+ const MAX_SITEMAP_INDEX_DEPTH = 3;
7
+ const MAX_SUB_SITEMAPS = 50;
8
+ async function getSitemapMaxUrls() {
9
+ const { getSystemConfig } = await import("@taodigital/core");
10
+ const cfg = await getSystemConfig("crawl_tuning");
11
+ return parseInt(String(cfg?.sitemapMaxUrls ?? "5000"), 10);
12
+ }
13
+ function toArray(x) {
14
+ if (x == null) return [];
15
+ return Array.isArray(x) ? x : [x];
16
+ }
17
+ function hostKey(hostname) {
18
+ return hostname.replace(/^www\./i, "").toLowerCase();
19
+ }
20
+ function sameSite(candidateUrl, siteOrigin) {
21
+ try {
22
+ const originHost = /^https?:\/\//i.test(siteOrigin) ? new URL(siteOrigin).hostname : siteOrigin;
23
+ return hostKey(new URL(candidateUrl).hostname) === hostKey(originHost);
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
28
+ function extractUrlsFromParsedSitemap(parsed, origin, maxUrls = 5e3) {
29
+ const rawPageUrls = [];
30
+ let subSitemapUrls = [];
31
+ if (parsed?.sitemapindex) {
32
+ subSitemapUrls = toArray(parsed.sitemapindex.sitemap).map((s) => s?.loc).filter((loc) => typeof loc === "string").slice(0, MAX_SUB_SITEMAPS);
33
+ }
34
+ if (parsed?.urlset) {
35
+ rawPageUrls.push(
36
+ ...toArray(parsed.urlset.url).map((u) => u?.loc).filter((loc) => typeof loc === "string")
37
+ );
38
+ }
39
+ const sameOrigin = rawPageUrls.filter((u) => sameSite(u, origin));
40
+ return { pageUrls: [...new Set(sameOrigin)].slice(0, maxUrls), subSitemapUrls };
41
+ }
42
+ async function fetchAndParseXml(url, dispatcher) {
43
+ try {
44
+ assertCrawlUrlSafe(url);
45
+ } catch {
46
+ return null;
47
+ }
48
+ try {
49
+ const res = await fetch(url, {
50
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
51
+ headers: { "User-Agent": "ZeTa-AI-Crawler/1.0 (+sitemap-discovery)" },
52
+ ...dispatcher ? { dispatcher } : {}
53
+ });
54
+ if (!res.ok) return null;
55
+ const text = await res.text();
56
+ return new XMLParser().parse(text);
57
+ } catch {
58
+ return null;
59
+ }
60
+ }
61
+ async function fetchSitemapUrls(sitemapUrl, origin, depth = 0, dispatcher, maxUrls) {
62
+ if (depth > MAX_SITEMAP_INDEX_DEPTH) return [];
63
+ if (maxUrls === void 0) maxUrls = await getSitemapMaxUrls();
64
+ const parsed = await fetchAndParseXml(sitemapUrl, dispatcher);
65
+ if (!parsed) return [];
66
+ const { pageUrls, subSitemapUrls } = extractUrlsFromParsedSitemap(parsed, origin, maxUrls);
67
+ const collected = [...pageUrls];
68
+ if (subSitemapUrls.length > 0 && collected.length < maxUrls) {
69
+ const subResults = await Promise.all(
70
+ subSitemapUrls.slice(0, 10).map((subUrl) => fetchSitemapUrls(subUrl, origin, depth + 1, dispatcher, maxUrls))
71
+ );
72
+ for (const sub of subResults) collected.push(...sub);
73
+ }
74
+ return [...new Set(collected)].slice(0, maxUrls);
75
+ }
76
+ async function discoverSitemapUrls(appUrl, sitemapUrl) {
77
+ let origin;
78
+ try {
79
+ origin = new URL(appUrl).origin;
80
+ } catch {
81
+ return [];
82
+ }
83
+ const target = sitemapUrl || `${origin}/sitemap.xml`;
84
+ try {
85
+ return await fetchSitemapUrls(target, origin);
86
+ } catch (err) {
87
+ logger.warn({ err: String(err), target }, "[sitemap] discovery failed, continuing without it");
88
+ return [];
89
+ }
90
+ }
91
+ function buildProxyDispatcher(proxyUrl) {
92
+ if (!proxyUrl || proxyUrl === "auto") return void 0;
93
+ try {
94
+ const m = proxyUrl.match(/^(https?):\/\/(?:([^:@]*)(?::([^@]*))?@)?(.+)$/);
95
+ if (!m) return new ProxyAgent(proxyUrl);
96
+ const [, scheme, user, pass, hostPort] = m;
97
+ const uri = `${scheme}://${hostPort}`;
98
+ if (user) {
99
+ const token = "Basic " + Buffer.from(`${decodeURIComponent(user)}:${decodeURIComponent(pass ?? "")}`).toString("base64");
100
+ return new ProxyAgent({ uri, token });
101
+ }
102
+ return new ProxyAgent({ uri });
103
+ } catch {
104
+ return void 0;
105
+ }
106
+ }
107
+ function parseRobotsSitemaps(robotsTxt, origin) {
108
+ const out = [];
109
+ for (const line of robotsTxt.split(/\r?\n/)) {
110
+ const m = line.match(/^\s*sitemap:\s*(\S+)/i);
111
+ if (m && sameSite(m[1], origin)) out.push(m[1]);
112
+ }
113
+ return [...new Set(out)];
114
+ }
115
+ async function discoverProjectUrls(appUrl, opts) {
116
+ let origin;
117
+ try {
118
+ origin = new URL(appUrl).origin;
119
+ } catch {
120
+ return { candidates: [], sitemapFound: false };
121
+ }
122
+ const dispatcher = buildProxyDispatcher(opts?.proxyUrl);
123
+ const maxUrls = await getSitemapMaxUrls();
124
+ let robotsSitemaps = [];
125
+ try {
126
+ assertCrawlUrlSafe(`${origin}/robots.txt`);
127
+ const res = await fetch(`${origin}/robots.txt`, {
128
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
129
+ headers: { "User-Agent": "ZeTa-AI-Crawler/1.0 (+url-discovery)" },
130
+ ...dispatcher ? { dispatcher } : {}
131
+ });
132
+ if (res.ok) robotsSitemaps = parseRobotsSitemaps(await res.text(), origin);
133
+ } catch {
134
+ }
135
+ const robotsSet = new Set(robotsSitemaps);
136
+ const sitemapTargets = [.../* @__PURE__ */ new Set([
137
+ ...opts?.sitemapUrl ? [opts.sitemapUrl] : [],
138
+ ...robotsSitemaps,
139
+ `${origin}/sitemap.xml`
140
+ ])];
141
+ const seen = /* @__PURE__ */ new Map();
142
+ let sitemapFound = false;
143
+ for (const sm of sitemapTargets) {
144
+ const urls = await fetchSitemapUrls(sm, origin, 0, dispatcher, maxUrls);
145
+ if (urls.length) sitemapFound = true;
146
+ const source = robotsSet.has(sm) ? "robots" : "sitemap";
147
+ for (const u of urls) if (!seen.has(u)) seen.set(u, { url: u, source });
148
+ }
149
+ return { candidates: [...seen.values()].slice(0, maxUrls), sitemapFound };
150
+ }
151
+ export {
152
+ buildProxyDispatcher,
153
+ discoverProjectUrls,
154
+ discoverSitemapUrls,
155
+ extractUrlsFromParsedSitemap,
156
+ fetchSitemapUrls,
157
+ parseRobotsSitemaps,
158
+ sameSite
159
+ };
160
+ //# sourceMappingURL=sitemap.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/sitemap.ts"],
4
+ "sourcesContent": ["/**\n * Sitemap.xml discovery \u2014 seeds the crawl queue from a project's sitemap\n * instead of (or alongside) plain link-following, matching crawl4AI's\n * sitemap-seeding capability. Best-effort throughout: most sites don't have\n * a sitemap, or it 404s, or it's malformed \u2014 none of that should ever fail\n * a crawl, it just means sitemap seeding contributes nothing this run.\n */\nimport { XMLParser } from 'fast-xml-parser';\nimport { ProxyAgent } from 'undici';\nimport { assertCrawlUrlSafe } from '@detiq/core/dist/ssrf-guard.js';\nimport { logger } from './logger.js';\n\nconst FETCH_TIMEOUT_MS = 10_000;\nconst MAX_SITEMAP_INDEX_DEPTH = 3; // sitemap index -> sub-sitemaps -> (no deeper nesting expected)\nconst MAX_SUB_SITEMAPS = 50; // bound fan-out from a single sitemap index\n\nasync function getSitemapMaxUrls(): Promise<number> {\n const { getSystemConfig } = await import('@detiq/core');\n const cfg = await getSystemConfig('crawl_tuning');\n return parseInt(String(cfg?.sitemapMaxUrls ?? '5000'), 10);\n}\n\nfunction toArray<T>(x: T | T[] | undefined | null): T[] {\n if (x == null) return [];\n return Array.isArray(x) ? x : [x];\n}\n\n/** Registrable-host key: lowercased hostname with a leading `www.` stripped. */\nfunction hostKey(hostname: string): string {\n return hostname.replace(/^www\\./i, '').toLowerCase();\n}\n\n/**\n * Same-site check that tolerates www/non-www and http/https differences \u2014 a sitemap on\n * `vercel.com` is valid for a project pointed at `www.vercel.com` (and vice versa).\n */\nexport function sameSite(candidateUrl: string, siteOrigin: string): boolean {\n try {\n const originHost = /^https?:\\/\\//i.test(siteOrigin) ? new URL(siteOrigin).hostname : siteOrigin;\n return hostKey(new URL(candidateUrl).hostname) === hostKey(originHost);\n } catch {\n return false;\n }\n}\n\n/**\n * Pulls page URLs and sub-sitemap URLs out of an already-XML-parsed sitemap\n * document (either a <urlset> or a <sitemapindex>), filtered to same-origin\n * and deduped. Pure function \u2014 no I/O \u2014 for direct unit testing without a\n * real HTTP fetch.\n */\nexport function extractUrlsFromParsedSitemap(parsed: any, origin: string, maxUrls = 5000): { pageUrls: string[]; subSitemapUrls: string[] } {\n const rawPageUrls: string[] = [];\n let subSitemapUrls: string[] = [];\n\n if (parsed?.sitemapindex) {\n subSitemapUrls = toArray(parsed.sitemapindex.sitemap)\n .map((s: any) => s?.loc)\n .filter((loc: any): loc is string => typeof loc === 'string')\n .slice(0, MAX_SUB_SITEMAPS);\n }\n\n if (parsed?.urlset) {\n rawPageUrls.push(\n ...toArray(parsed.urlset.url)\n .map((u: any) => u?.loc)\n .filter((loc: any): loc is string => typeof loc === 'string'),\n );\n }\n\n // Same-site only (www/protocol-tolerant) \u2014 a sitemap listing external URLs shouldn't seed this project's queue.\n const sameOrigin = rawPageUrls.filter((u) => sameSite(u, origin));\n\n return { pageUrls: [...new Set(sameOrigin)].slice(0, maxUrls), subSitemapUrls };\n}\n\nasync function fetchAndParseXml(url: string, dispatcher?: any): Promise<any | null> {\n // Same SSRF posture as the crawl itself (assertCrawlUrlSafe, not the\n // stricter webhook-oriented assertResolvesToPublicAddress) \u2014 a sitemap\n // living on a tenant's internal/VPN-only staging server is a legitimate\n // crawl target, not an attack; only loopback/cloud-metadata are blocked.\n try {\n assertCrawlUrlSafe(url);\n } catch {\n return null;\n }\n try {\n // Redirects followed normally here (unlike the webhook-dispatch.ts\n // 'manual' pattern) \u2014 an http\u2192https or bare\u2192www redirect on the\n // sitemap is completely ordinary, and Playwright's actual page\n // navigation later in the crawl already follows redirects to whatever\n // this same site sends it to; a sitemap fetch isn't a more sensitive\n // operation than that.\n const res = await fetch(url, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n headers: { 'User-Agent': 'ZeTa-AI-Crawler/1.0 (+sitemap-discovery)' },\n ...(dispatcher ? { dispatcher } : {}),\n });\n if (!res.ok) return null;\n const text = await res.text();\n return new XMLParser().parse(text);\n } catch {\n return null;\n }\n}\n\n/**\n * Fetches and parses a sitemap (or sitemap index, recursed up to a small\n * depth) into a flat, deduped list of same-origin URLs.\n */\nexport async function fetchSitemapUrls(sitemapUrl: string, origin: string, depth = 0, dispatcher?: any, maxUrls?: number): Promise<string[]> {\n if (depth > MAX_SITEMAP_INDEX_DEPTH) return [];\n if (maxUrls === undefined) maxUrls = await getSitemapMaxUrls();\n const parsed = await fetchAndParseXml(sitemapUrl, dispatcher);\n if (!parsed) return [];\n\n const { pageUrls, subSitemapUrls } = extractUrlsFromParsedSitemap(parsed, origin, maxUrls);\n const collected = [...pageUrls];\n\n if (subSitemapUrls.length > 0 && collected.length < maxUrls) {\n const subResults = await Promise.all(\n subSitemapUrls.slice(0, 10).map(subUrl => fetchSitemapUrls(subUrl, origin, depth + 1, dispatcher, maxUrls))\n );\n for (const sub of subResults) collected.push(...sub);\n }\n\n return [...new Set(collected)].slice(0, maxUrls);\n}\n\n/**\n * Discovers a project's sitemap (default `${origin}/sitemap.xml`, or an\n * explicit override) and returns the URLs it lists. Never throws.\n */\nexport async function discoverSitemapUrls(appUrl: string, sitemapUrl?: string): Promise<string[]> {\n let origin: string;\n try {\n origin = new URL(appUrl).origin;\n } catch {\n return [];\n }\n const target = sitemapUrl || `${origin}/sitemap.xml`;\n try {\n return await fetchSitemapUrls(target, origin);\n } catch (err) {\n logger.warn({ err: String(err), target }, '[sitemap] discovery failed, continuing without it');\n return [];\n }\n}\n\n/**\n * Build an undici ProxyAgent from a proxy URL. Parses credentials manually because\n * DataImpulse-style usernames contain commas (country codes) that break new URL().\n * Returns undefined for no/auto proxy \u2014 the caller then fetches directly.\n */\nexport function buildProxyDispatcher(proxyUrl?: string): ProxyAgent | undefined {\n if (!proxyUrl || proxyUrl === 'auto') return undefined;\n try {\n const m = proxyUrl.match(/^(https?):\\/\\/(?:([^:@]*)(?::([^@]*))?@)?(.+)$/);\n if (!m) return new ProxyAgent(proxyUrl);\n const [, scheme, user, pass, hostPort] = m;\n const uri = `${scheme}://${hostPort}`;\n if (user) {\n const token = 'Basic ' + Buffer.from(`${decodeURIComponent(user)}:${decodeURIComponent(pass ?? '')}`).toString('base64');\n return new ProxyAgent({ uri, token });\n }\n return new ProxyAgent({ uri });\n } catch {\n return undefined;\n }\n}\n\n/** Extract same-origin `Sitemap:` directives from a robots.txt body. */\nexport function parseRobotsSitemaps(robotsTxt: string, origin: string): string[] {\n const out: string[] = [];\n for (const line of robotsTxt.split(/\\r?\\n/)) {\n const m = line.match(/^\\s*sitemap:\\s*(\\S+)/i);\n if (m && sameSite(m[1], origin)) out.push(m[1]);\n }\n return [...new Set(out)];\n}\n\nexport interface UrlCandidate {\n url: string;\n source: 'sitemap' | 'robots' | 'link';\n}\n\n/**\n * Pre-crawl URL discovery for the review-before-crawl flow: reads robots.txt Sitemap\n * directives and sitemap.xml (recursed, same-origin), proxy-aware. Returns a deduped\n * candidate list the user can review and seed before launching the Playwright crawl.\n * Never throws \u2014 bot-protected sites (Akamai/Cloudflare) simply yield an empty list.\n */\nexport async function discoverProjectUrls(\n appUrl: string,\n opts?: { sitemapUrl?: string; proxyUrl?: string },\n): Promise<{ candidates: UrlCandidate[]; sitemapFound: boolean }> {\n let origin: string;\n try { origin = new URL(appUrl).origin; } catch { return { candidates: [], sitemapFound: false }; }\n\n const dispatcher = buildProxyDispatcher(opts?.proxyUrl);\n const maxUrls = await getSitemapMaxUrls();\n\n // 1. robots.txt \u2192 declared sitemaps\n let robotsSitemaps: string[] = [];\n try {\n assertCrawlUrlSafe(`${origin}/robots.txt`);\n const res = await fetch(`${origin}/robots.txt`, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n headers: { 'User-Agent': 'ZeTa-AI-Crawler/1.0 (+url-discovery)' },\n ...(dispatcher ? { dispatcher } : {}),\n });\n if (res.ok) robotsSitemaps = parseRobotsSitemaps(await res.text(), origin);\n } catch { /* best-effort */ }\n\n // 2. sitemap targets: explicit override + robots-declared + conventional default\n const robotsSet = new Set(robotsSitemaps);\n const sitemapTargets = [...new Set([\n ...(opts?.sitemapUrl ? [opts.sitemapUrl] : []),\n ...robotsSitemaps,\n `${origin}/sitemap.xml`,\n ])];\n\n const seen = new Map<string, UrlCandidate>();\n let sitemapFound = false;\n for (const sm of sitemapTargets) {\n const urls = await fetchSitemapUrls(sm, origin, 0, dispatcher, maxUrls);\n if (urls.length) sitemapFound = true;\n const source: UrlCandidate['source'] = robotsSet.has(sm) ? 'robots' : 'sitemap';\n for (const u of urls) if (!seen.has(u)) seen.set(u, { url: u, source });\n }\n\n return { candidates: [...seen.values()].slice(0, maxUrls), sitemapFound };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Skyvern Vision Fallback
3
+ *
4
+ * Skyvern combines computer vision + LLM reasoning to navigate sites that
5
+ * defeat DOM-based approaches: CAPTCHAs, legacy apps, visual-only login flows,
6
+ * government portals. It's the "break glass" option when Stagehand fails.
7
+ *
8
+ * Production setup (Phase 4+):
9
+ * 1. Self-host: https://github.com/Skyvern-AI/skyvern
10
+ * 2. Or use cloud: https://app.skyvern.com
11
+ * 3. Set SKYVERN_API_URL + SKYVERN_API_KEY in .env
12
+ *
13
+ * Pricing note: vision tasks cost more per step than DOM-based Stagehand.
14
+ * Use only when the fast path fails.
15
+ */
16
+ export interface SkyvernTask {
17
+ taskDescription: string;
18
+ url: string;
19
+ credentials?: {
20
+ username: string;
21
+ password: string;
22
+ oneTimeCode?: string;
23
+ };
24
+ }
25
+ export interface SkyvernConfig {
26
+ apiUrl: string;
27
+ apiKey: string;
28
+ llmKey?: string;
29
+ llmApiKey?: string;
30
+ }
31
+ export interface SkyvernStep {
32
+ order: number;
33
+ action_type: string;
34
+ element_description?: string;
35
+ reasoning?: string;
36
+ success: boolean;
37
+ screenshot_url?: string;
38
+ duration_ms?: number;
39
+ error?: string;
40
+ }
41
+ export interface SkyvernNavigateResult {
42
+ screenshotUrls: string[];
43
+ visitedUrls: string[];
44
+ status: 'success' | 'failed' | 'partial';
45
+ steps?: SkyvernStep[];
46
+ taskId?: string;
47
+ durationMs?: number;
48
+ triggerReason?: string;
49
+ }
50
+ /**
51
+ * Gap 5: Post-login navigation via Skyvern vision for apps where DOM analysis
52
+ * cannot discover screens (canvas, WebGL, legacy Flash-replacement stacks).
53
+ * Skyvern drives the browser via screenshot + LLM, returning visited page list.
54
+ */
55
+ export declare function skyvernNavigate(startUrl: string, navigationGoals: string[], tenantConfig?: SkyvernConfig, triggerReason?: string): Promise<SkyvernNavigateResult>;
56
+ export declare function skyvernFallback(task: SkyvernTask, tenantConfig?: SkyvernConfig): Promise<'success' | 'failed'>;