@taodigital/crawler 0.0.0-stage → 1.2.0

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,60 @@
1
+ function extractFingerprints(markdown) {
2
+ const lines = markdown.split("\n").filter((l) => l.trim().length > 0);
3
+ const fps = [];
4
+ const headings = lines.filter((l) => /^#{1,6} /.test(l));
5
+ const hCounts = [0, 0, 0, 0, 0, 0];
6
+ for (const h of headings) {
7
+ const lvl = h.match(/^(#{1,6}) /)?.[1].length ?? 1;
8
+ hCounts[lvl - 1]++;
9
+ }
10
+ fps.push("h:" + hCounts.join(","));
11
+ const linkCount = (markdown.match(/\[.+?\]\(.+?\)/g) ?? []).length;
12
+ fps.push("lk:" + Math.floor(linkCount / 5));
13
+ const listCount = lines.filter((l) => /^[\-\*\+] |^\d+\. /.test(l)).length;
14
+ fps.push("li:" + Math.floor(listCount / 3));
15
+ fps.push("code:" + (markdown.includes("```") ? "1" : "0"));
16
+ fps.push("tbl:" + (markdown.includes("|") ? "1" : "0"));
17
+ const paraCount = markdown.split(/\n{2,}/).filter((p) => p.trim().length > 30).length;
18
+ fps.push("p:" + Math.floor(paraCount / 2));
19
+ const firstH = headings[0]?.replace(/^#{1,6} /, "").toLowerCase().replace(/[^a-z0-9]/g, "") ?? "";
20
+ fps.push("fh:" + firstH.slice(0, 20));
21
+ const wordCount = markdown.split(/\s+/).length;
22
+ fps.push("wc:" + Math.floor(wordCount / 50));
23
+ return fps;
24
+ }
25
+ function similarity(a, b) {
26
+ if (a.length !== b.length) return 0;
27
+ let matches = 0;
28
+ for (let i = 0; i < a.length; i++) {
29
+ if (a[i] === b[i]) matches++;
30
+ }
31
+ return matches / a.length;
32
+ }
33
+ class ContentDeduplicator {
34
+ seen = /* @__PURE__ */ new Map();
35
+ threshold;
36
+ constructor(threshold = 0.85) {
37
+ this.threshold = threshold;
38
+ }
39
+ check(url, markdown) {
40
+ const fps = extractFingerprints(markdown);
41
+ for (const [key, entry] of this.seen) {
42
+ const score = similarity(fps, entry.fps);
43
+ if (score >= this.threshold) {
44
+ return { isDuplicate: true, similarUrl: entry.url, similarityScore: score };
45
+ }
46
+ }
47
+ this.seen.set(url, { fps, url });
48
+ return { isDuplicate: false, similarityScore: 1 };
49
+ }
50
+ size() {
51
+ return this.seen.size;
52
+ }
53
+ reset() {
54
+ this.seen.clear();
55
+ }
56
+ }
57
+ export {
58
+ ContentDeduplicator
59
+ };
60
+ //# sourceMappingURL=content-dedup.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/content-dedup.ts"],
4
+ "sourcesContent": ["/**\n * Content deduplication \u2014 detect near-duplicate pages during crawl.\n *\n * Uses MinHash-inspired approach: instead of full MinHash (needs many hash functions),\n * we use 8 structural fingerprints extracted from the markdown to detect pages that\n * share the same layout/template even if the data differs.\n *\n * Typical duplicates: /products?page=1 vs /products?page=2 (same template, different data).\n * These waste crawl budget and generate redundant test cases.\n */\n\n/** Extract structural fingerprints from markdown \u2014 layout-sensitive, data-insensitive */\nfunction extractFingerprints(markdown: string): string[] {\n const lines = markdown.split('\\n').filter(l => l.trim().length > 0);\n const fps: string[] = [];\n\n // FP1: heading structure (H1-H6 count distribution)\n const headings = lines.filter(l => /^#{1,6} /.test(l));\n const hCounts = [0, 0, 0, 0, 0, 0];\n for (const h of headings) {\n const lvl = h.match(/^(#{1,6}) /)?.[1].length ?? 1;\n hCounts[lvl - 1]++;\n }\n fps.push('h:' + hCounts.join(','));\n\n // FP2: link count (grouped into buckets)\n const linkCount = (markdown.match(/\\[.+?\\]\\(.+?\\)/g) ?? []).length;\n fps.push('lk:' + Math.floor(linkCount / 5));\n\n // FP3: list item count (grouped)\n const listCount = lines.filter(l => /^[\\-\\*\\+] |^\\d+\\. /.test(l)).length;\n fps.push('li:' + Math.floor(listCount / 3));\n\n // FP4: code block presence\n fps.push('code:' + (markdown.includes('```') ? '1' : '0'));\n\n // FP5: table presence\n fps.push('tbl:' + (markdown.includes('|') ? '1' : '0'));\n\n // FP6: approximate paragraph count\n const paraCount = markdown.split(/\\n{2,}/).filter(p => p.trim().length > 30).length;\n fps.push('p:' + Math.floor(paraCount / 2));\n\n // FP7: first heading text (normalized)\n const firstH = headings[0]?.replace(/^#{1,6} /, '').toLowerCase().replace(/[^a-z0-9]/g, '') ?? '';\n fps.push('fh:' + firstH.slice(0, 20));\n\n // FP8: word count bucket\n const wordCount = markdown.split(/\\s+/).length;\n fps.push('wc:' + Math.floor(wordCount / 50));\n\n return fps;\n}\n\nfunction similarity(a: string[], b: string[]): number {\n if (a.length !== b.length) return 0;\n let matches = 0;\n for (let i = 0; i < a.length; i++) {\n if (a[i] === b[i]) matches++;\n }\n return matches / a.length;\n}\n\nexport interface DedupResult {\n isDuplicate: boolean;\n similarUrl?: string;\n similarityScore: number;\n}\n\nexport class ContentDeduplicator {\n private seen = new Map<string, { fps: string[]; url: string }>();\n private readonly threshold: number;\n\n constructor(threshold = 0.85) {\n this.threshold = threshold;\n }\n\n check(url: string, markdown: string): DedupResult {\n const fps = extractFingerprints(markdown);\n\n for (const [key, entry] of this.seen) {\n const score = similarity(fps, entry.fps);\n if (score >= this.threshold) {\n return { isDuplicate: true, similarUrl: entry.url, similarityScore: score };\n }\n }\n\n this.seen.set(url, { fps, url });\n return { isDuplicate: false, similarityScore: 1.0 };\n }\n\n size(): number {\n return this.seen.size;\n }\n\n reset(): void {\n this.seen.clear();\n }\n}\n"],
5
+ "mappings": "AAYA,SAAS,oBAAoB,UAA4B;AACvD,QAAM,QAAQ,SAAS,MAAM,IAAI,EAAE,OAAO,OAAK,EAAE,KAAK,EAAE,SAAS,CAAC;AAClE,QAAM,MAAgB,CAAC;AAGvB,QAAM,WAAW,MAAM,OAAO,OAAK,WAAW,KAAK,CAAC,CAAC;AACrD,QAAM,UAAU,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AACjC,aAAW,KAAK,UAAU;AACxB,UAAM,MAAM,EAAE,MAAM,YAAY,IAAI,CAAC,EAAE,UAAU;AACjD,YAAQ,MAAM,CAAC;AAAA,EACjB;AACA,MAAI,KAAK,OAAO,QAAQ,KAAK,GAAG,CAAC;AAGjC,QAAM,aAAa,SAAS,MAAM,iBAAiB,KAAK,CAAC,GAAG;AAC5D,MAAI,KAAK,QAAQ,KAAK,MAAM,YAAY,CAAC,CAAC;AAG1C,QAAM,YAAY,MAAM,OAAO,OAAK,qBAAqB,KAAK,CAAC,CAAC,EAAE;AAClE,MAAI,KAAK,QAAQ,KAAK,MAAM,YAAY,CAAC,CAAC;AAG1C,MAAI,KAAK,WAAW,SAAS,SAAS,KAAK,IAAI,MAAM,IAAI;AAGzD,MAAI,KAAK,UAAU,SAAS,SAAS,GAAG,IAAI,MAAM,IAAI;AAGtD,QAAM,YAAY,SAAS,MAAM,QAAQ,EAAE,OAAO,OAAK,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;AAC7E,MAAI,KAAK,OAAO,KAAK,MAAM,YAAY,CAAC,CAAC;AAGzC,QAAM,SAAS,SAAS,CAAC,GAAG,QAAQ,YAAY,EAAE,EAAE,YAAY,EAAE,QAAQ,cAAc,EAAE,KAAK;AAC/F,MAAI,KAAK,QAAQ,OAAO,MAAM,GAAG,EAAE,CAAC;AAGpC,QAAM,YAAY,SAAS,MAAM,KAAK,EAAE;AACxC,MAAI,KAAK,QAAQ,KAAK,MAAM,YAAY,EAAE,CAAC;AAE3C,SAAO;AACT;AAEA,SAAS,WAAW,GAAa,GAAqB;AACpD,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,UAAU;AACd,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,QAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAG;AAAA,EACrB;AACA,SAAO,UAAU,EAAE;AACrB;AAQO,MAAM,oBAAoB;AAAA,EACvB,OAAO,oBAAI,IAA4C;AAAA,EAC9C;AAAA,EAEjB,YAAY,YAAY,MAAM;AAC5B,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,KAAa,UAA+B;AAChD,UAAM,MAAM,oBAAoB,QAAQ;AAExC,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,MAAM;AACpC,YAAM,QAAQ,WAAW,KAAK,MAAM,GAAG;AACvC,UAAI,SAAS,KAAK,WAAW;AAC3B,eAAO,EAAE,aAAa,MAAM,YAAY,MAAM,KAAK,iBAAiB,MAAM;AAAA,MAC5E;AAAA,IACF;AAEA,SAAK,KAAK,IAAI,KAAK,EAAE,KAAK,IAAI,CAAC;AAC/B,WAAO,EAAE,aAAa,OAAO,iBAAiB,EAAI;AAAA,EACpD;AAAA,EAEA,OAAe;AACb,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA,EAEA,QAAc;AACZ,SAAK,KAAK,MAAM;AAAA,EAClB;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Cookie consent auto-acceptor.
3
+ *
4
+ * Detects and clicks "Accept" on common cookie consent banners before the
5
+ * crawler proceeds. Without this, many EU sites show a consent wall that
6
+ * blocks content or shows a different layout, making crawl results unreliable.
7
+ *
8
+ * Supports: Cookiebot, OneTrust, TrustArc, Usercentrics, GDPR Cookie Compliance,
9
+ * generic "Accept All" / "Accept Cookies" buttons.
10
+ *
11
+ * Strategy: try known selectors first, then fall back to text-based button search.
12
+ * Non-blocking — if no banner is found or click fails, crawl proceeds normally.
13
+ */
14
+ import type { Page } from 'playwright';
15
+ export interface ConsentResult {
16
+ found: boolean;
17
+ clicked: boolean;
18
+ method?: string;
19
+ error?: string;
20
+ }
21
+ export declare function acceptCookieConsent(page: Page, opts?: {
22
+ waitMs?: number;
23
+ }): Promise<ConsentResult>;
24
+ /** Check if a consent banner is still visible after attempted dismissal */
25
+ export declare function isConsentBannerVisible(page: Page): Promise<boolean>;
@@ -0,0 +1,78 @@
1
+ const CONSENT_SELECTORS = [
2
+ // Cookiebot
3
+ "#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll",
4
+ "#CybotCookiebotDialogBodyButtonAccept",
5
+ // OneTrust
6
+ "#onetrust-accept-btn-handler",
7
+ ".ot-sdk-accept-btn",
8
+ // TrustArc
9
+ '.truste_popframe [title*="Accept"]',
10
+ "#truste-consent-button",
11
+ // Usercentrics
12
+ '[data-testid="uc-accept-all-button"]',
13
+ // Generic high-confidence
14
+ '[id*="accept"][id*="cookie"]',
15
+ '[class*="accept"][class*="cookie"]',
16
+ '[class*="cookie"][class*="accept"]',
17
+ // GDPR Cookie Compliance
18
+ ".gdpr-cookie-notice-accept",
19
+ // Quantcast
20
+ ".qc-cmp2-summary-buttons button:first-child"
21
+ ];
22
+ const ACCEPT_TEXT_PATTERNS = [
23
+ /^accept all$/i,
24
+ /^accept all cookies$/i,
25
+ /^allow all$/i,
26
+ /^i accept$/i,
27
+ /^agree$/i,
28
+ /^ok$/i,
29
+ /^got it$/i,
30
+ /^allow cookies$/i
31
+ ];
32
+ async function acceptCookieConsent(page, opts = {}) {
33
+ const { waitMs = 1500 } = opts;
34
+ await page.waitForTimeout(waitMs).catch(() => {
35
+ });
36
+ for (const selector of CONSENT_SELECTORS) {
37
+ try {
38
+ const el = await page.$(selector);
39
+ if (el && await el.isVisible()) {
40
+ await el.click({ timeout: 2e3 });
41
+ await page.waitForTimeout(500);
42
+ return { found: true, clicked: true, method: `selector: ${selector}` };
43
+ }
44
+ } catch {
45
+ }
46
+ }
47
+ try {
48
+ const buttons = await page.$$('button, [role="button"], a[class*="cookie"]');
49
+ for (const btn of buttons) {
50
+ const text = (await btn.textContent() ?? "").trim();
51
+ if (ACCEPT_TEXT_PATTERNS.some((re) => re.test(text))) {
52
+ if (await btn.isVisible()) {
53
+ await btn.click({ timeout: 2e3 });
54
+ await page.waitForTimeout(500);
55
+ return { found: true, clicked: true, method: `text: "${text}"` };
56
+ }
57
+ }
58
+ }
59
+ } catch {
60
+ }
61
+ return { found: false, clicked: false };
62
+ }
63
+ async function isConsentBannerVisible(page) {
64
+ try {
65
+ for (const sel of CONSENT_SELECTORS.slice(0, 5)) {
66
+ const el = await page.$(sel);
67
+ if (el && await el.isVisible()) return true;
68
+ }
69
+ return false;
70
+ } catch {
71
+ return false;
72
+ }
73
+ }
74
+ export {
75
+ acceptCookieConsent,
76
+ isConsentBannerVisible
77
+ };
78
+ //# sourceMappingURL=cookie-consent.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/cookie-consent.ts"],
4
+ "sourcesContent": ["/**\n * Cookie consent auto-acceptor.\n *\n * Detects and clicks \"Accept\" on common cookie consent banners before the\n * crawler proceeds. Without this, many EU sites show a consent wall that\n * blocks content or shows a different layout, making crawl results unreliable.\n *\n * Supports: Cookiebot, OneTrust, TrustArc, Usercentrics, GDPR Cookie Compliance,\n * generic \"Accept All\" / \"Accept Cookies\" buttons.\n *\n * Strategy: try known selectors first, then fall back to text-based button search.\n * Non-blocking \u2014 if no banner is found or click fails, crawl proceeds normally.\n */\n\nimport type { Page } from 'playwright';\n\nexport interface ConsentResult {\n found: boolean;\n clicked: boolean;\n method?: string; // which selector/strategy matched\n error?: string;\n}\n\n// Known consent platform selectors\nconst CONSENT_SELECTORS = [\n // Cookiebot\n '#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll',\n '#CybotCookiebotDialogBodyButtonAccept',\n // OneTrust\n '#onetrust-accept-btn-handler',\n '.ot-sdk-accept-btn',\n // TrustArc\n '.truste_popframe [title*=\"Accept\"]',\n '#truste-consent-button',\n // Usercentrics\n '[data-testid=\"uc-accept-all-button\"]',\n // Generic high-confidence\n '[id*=\"accept\"][id*=\"cookie\"]',\n '[class*=\"accept\"][class*=\"cookie\"]',\n '[class*=\"cookie\"][class*=\"accept\"]',\n // GDPR Cookie Compliance\n '.gdpr-cookie-notice-accept',\n // Quantcast\n '.qc-cmp2-summary-buttons button:first-child',\n];\n\n// Fallback: button text matching\nconst ACCEPT_TEXT_PATTERNS = [\n /^accept all$/i,\n /^accept all cookies$/i,\n /^allow all$/i,\n /^i accept$/i,\n /^agree$/i,\n /^ok$/i,\n /^got it$/i,\n /^allow cookies$/i,\n];\n\nexport async function acceptCookieConsent(page: Page, opts: { waitMs?: number } = {}): Promise<ConsentResult> {\n const { waitMs = 1_500 } = opts;\n\n // Wait briefly for consent banners to appear\n await page.waitForTimeout(waitMs).catch(() => {});\n\n // Try known selectors first\n for (const selector of CONSENT_SELECTORS) {\n try {\n const el = await page.$(selector);\n if (el && await el.isVisible()) {\n await el.click({ timeout: 2_000 });\n await page.waitForTimeout(500);\n return { found: true, clicked: true, method: `selector: ${selector}` };\n }\n } catch { /* try next */ }\n }\n\n // Fallback: find buttons with accept-like text\n try {\n const buttons = await page.$$('button, [role=\"button\"], a[class*=\"cookie\"]');\n for (const btn of buttons) {\n const text = ((await btn.textContent()) ?? '').trim();\n if (ACCEPT_TEXT_PATTERNS.some(re => re.test(text))) {\n if (await btn.isVisible()) {\n await btn.click({ timeout: 2_000 });\n await page.waitForTimeout(500);\n return { found: true, clicked: true, method: `text: \"${text}\"` };\n }\n }\n }\n } catch { /* non-fatal */ }\n\n return { found: false, clicked: false };\n}\n\n/** Check if a consent banner is still visible after attempted dismissal */\nexport async function isConsentBannerVisible(page: Page): Promise<boolean> {\n try {\n for (const sel of CONSENT_SELECTORS.slice(0, 5)) {\n const el = await page.$(sel);\n if (el && await el.isVisible()) return true;\n }\n return false;\n } catch {\n return false;\n }\n}\n"],
5
+ "mappings": "AAwBA,MAAM,oBAAoB;AAAA;AAAA,EAExB;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AACF;AAGA,MAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,eAAsB,oBAAoB,MAAY,OAA4B,CAAC,GAA2B;AAC5G,QAAM,EAAE,SAAS,KAAM,IAAI;AAG3B,QAAM,KAAK,eAAe,MAAM,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AAGhD,aAAW,YAAY,mBAAmB;AACxC,QAAI;AACF,YAAM,KAAK,MAAM,KAAK,EAAE,QAAQ;AAChC,UAAI,MAAM,MAAM,GAAG,UAAU,GAAG;AAC9B,cAAM,GAAG,MAAM,EAAE,SAAS,IAAM,CAAC;AACjC,cAAM,KAAK,eAAe,GAAG;AAC7B,eAAO,EAAE,OAAO,MAAM,SAAS,MAAM,QAAQ,aAAa,QAAQ,GAAG;AAAA,MACvE;AAAA,IACF,QAAQ;AAAA,IAAiB;AAAA,EAC3B;AAGA,MAAI;AACF,UAAM,UAAU,MAAM,KAAK,GAAG,6CAA6C;AAC3E,eAAW,OAAO,SAAS;AACzB,YAAM,QAAS,MAAM,IAAI,YAAY,KAAM,IAAI,KAAK;AACpD,UAAI,qBAAqB,KAAK,QAAM,GAAG,KAAK,IAAI,CAAC,GAAG;AAClD,YAAI,MAAM,IAAI,UAAU,GAAG;AACzB,gBAAM,IAAI,MAAM,EAAE,SAAS,IAAM,CAAC;AAClC,gBAAM,KAAK,eAAe,GAAG;AAC7B,iBAAO,EAAE,OAAO,MAAM,SAAS,MAAM,QAAQ,UAAU,IAAI,IAAI;AAAA,QACjE;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAAkB;AAE1B,SAAO,EAAE,OAAO,OAAO,SAAS,MAAM;AACxC;AAGA,eAAsB,uBAAuB,MAA8B;AACzE,MAAI;AACF,eAAW,OAAO,kBAAkB,MAAM,GAAG,CAAC,GAAG;AAC/C,YAAM,KAAK,MAAM,KAAK,EAAE,GAAG;AAC3B,UAAI,MAAM,MAAM,GAAG,UAAU,EAAG,QAAO;AAAA,IACzC;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Cookie jar — persist and restore Playwright storageState cookies between
3
+ * crawl segments and restarts. Enables continuous auth across session boundaries
4
+ * (e.g. segment 1 logs in, segment 2–N inherit the session without re-login).
5
+ *
6
+ * Storage: JSON file per project in the crawl cache dir.
7
+ * Format: Playwright's storageState shape (cookies + origins).
8
+ */
9
+ export interface CookieJarEntry {
10
+ projectId: string;
11
+ tenantId: string;
12
+ storageState: string;
13
+ savedAt: string;
14
+ domain: string;
15
+ }
16
+ export declare function saveCookieJar(cacheDir: string, projectId: string, tenantId: string, storageState: string, domain: string): Promise<void>;
17
+ export declare function loadCookieJar(cacheDir: string, projectId: string, maxAgeMs?: number): Promise<string | null>;
18
+ export declare function clearCookieJar(cacheDir: string, projectId: string): Promise<void>;
19
+ /** Merge two storageState JSON strings — second takes priority for same-domain cookies. */
20
+ export declare function mergeStorageStates(base: string, overlay: string): string;
@@ -0,0 +1,61 @@
1
+ import * as fs from "fs/promises";
2
+ import * as path from "path";
3
+ function jarPath(cacheDir, projectId) {
4
+ return path.join(cacheDir, `cookie-jar-${projectId}.json`);
5
+ }
6
+ async function saveCookieJar(cacheDir, projectId, tenantId, storageState, domain) {
7
+ await fs.mkdir(cacheDir, { recursive: true });
8
+ const entry = {
9
+ projectId,
10
+ tenantId,
11
+ storageState,
12
+ savedAt: (/* @__PURE__ */ new Date()).toISOString(),
13
+ domain
14
+ };
15
+ await fs.writeFile(jarPath(cacheDir, projectId), JSON.stringify(entry, null, 2), "utf8");
16
+ }
17
+ async function loadCookieJar(cacheDir, projectId, maxAgeMs = 8 * 60 * 60 * 1e3) {
18
+ try {
19
+ const raw = await fs.readFile(jarPath(cacheDir, projectId), "utf8");
20
+ const entry = JSON.parse(raw);
21
+ const age = Date.now() - new Date(entry.savedAt).getTime();
22
+ if (age > maxAgeMs) return null;
23
+ return entry.storageState;
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+ async function clearCookieJar(cacheDir, projectId) {
29
+ try {
30
+ await fs.unlink(jarPath(cacheDir, projectId));
31
+ } catch {
32
+ }
33
+ }
34
+ function mergeStorageStates(base, overlay) {
35
+ try {
36
+ const a = JSON.parse(base);
37
+ const b = JSON.parse(overlay);
38
+ const cookies = [...a.cookies ?? []];
39
+ for (const ck of b.cookies ?? []) {
40
+ const idx = cookies.findIndex(
41
+ (c) => c.name === ck.name && c.domain === ck.domain && c.path === ck.path
42
+ );
43
+ if (idx >= 0) cookies[idx] = ck;
44
+ else cookies.push(ck);
45
+ }
46
+ const originsMap = /* @__PURE__ */ new Map();
47
+ for (const o of [...a.origins ?? [], ...b.origins ?? []]) {
48
+ originsMap.set(o.origin, o);
49
+ }
50
+ return JSON.stringify({ cookies, origins: [...originsMap.values()] });
51
+ } catch {
52
+ return overlay || base;
53
+ }
54
+ }
55
+ export {
56
+ clearCookieJar,
57
+ loadCookieJar,
58
+ mergeStorageStates,
59
+ saveCookieJar
60
+ };
61
+ //# sourceMappingURL=cookie-jar.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/cookie-jar.ts"],
4
+ "sourcesContent": ["/**\n * Cookie jar \u2014 persist and restore Playwright storageState cookies between\n * crawl segments and restarts. Enables continuous auth across session boundaries\n * (e.g. segment 1 logs in, segment 2\u2013N inherit the session without re-login).\n *\n * Storage: JSON file per project in the crawl cache dir.\n * Format: Playwright's storageState shape (cookies + origins).\n */\n\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\n\nexport interface CookieJarEntry {\n projectId: string;\n tenantId: string;\n storageState: string; // JSON-stringified Playwright StorageState\n savedAt: string; // ISO timestamp\n domain: string; // hostname for quick lookup\n}\n\nfunction jarPath(cacheDir: string, projectId: string): string {\n return path.join(cacheDir, `cookie-jar-${projectId}.json`);\n}\n\nexport async function saveCookieJar(\n cacheDir: string,\n projectId: string,\n tenantId: string,\n storageState: string,\n domain: string,\n): Promise<void> {\n await fs.mkdir(cacheDir, { recursive: true });\n const entry: CookieJarEntry = {\n projectId,\n tenantId,\n storageState,\n savedAt: new Date().toISOString(),\n domain,\n };\n await fs.writeFile(jarPath(cacheDir, projectId), JSON.stringify(entry, null, 2), 'utf8');\n}\n\nexport async function loadCookieJar(\n cacheDir: string,\n projectId: string,\n maxAgeMs = 8 * 60 * 60 * 1000, // 8 hours\n): Promise<string | null> {\n try {\n const raw = await fs.readFile(jarPath(cacheDir, projectId), 'utf8');\n const entry: CookieJarEntry = JSON.parse(raw);\n const age = Date.now() - new Date(entry.savedAt).getTime();\n if (age > maxAgeMs) return null; // expired\n return entry.storageState;\n } catch {\n return null;\n }\n}\n\nexport async function clearCookieJar(cacheDir: string, projectId: string): Promise<void> {\n try {\n await fs.unlink(jarPath(cacheDir, projectId));\n } catch { /* already gone */ }\n}\n\n/** Merge two storageState JSON strings \u2014 second takes priority for same-domain cookies. */\nexport function mergeStorageStates(base: string, overlay: string): string {\n try {\n const a = JSON.parse(base);\n const b = JSON.parse(overlay);\n\n // Cookies: overlay replaces same-name+domain+path cookies from base\n const cookies = [...(a.cookies ?? [])];\n for (const ck of (b.cookies ?? [])) {\n const idx = cookies.findIndex(\n (c: any) => c.name === ck.name && c.domain === ck.domain && c.path === ck.path,\n );\n if (idx >= 0) cookies[idx] = ck;\n else cookies.push(ck);\n }\n\n // Origins: merge origins, overlay wins on same-origin\n const originsMap = new Map<string, any>();\n for (const o of [...(a.origins ?? []), ...(b.origins ?? [])]) {\n originsMap.set(o.origin, o);\n }\n\n return JSON.stringify({ cookies, origins: [...originsMap.values()] });\n } catch {\n return overlay || base;\n }\n}\n"],
5
+ "mappings": "AASA,YAAY,QAAQ;AACpB,YAAY,UAAU;AAUtB,SAAS,QAAQ,UAAkB,WAA2B;AAC5D,SAAO,KAAK,KAAK,UAAU,cAAc,SAAS,OAAO;AAC3D;AAEA,eAAsB,cACpB,UACA,WACA,UACA,cACA,QACe;AACf,QAAM,GAAG,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAC5C,QAAM,QAAwB;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAS,oBAAI,KAAK,GAAE,YAAY;AAAA,IAChC;AAAA,EACF;AACA,QAAM,GAAG,UAAU,QAAQ,UAAU,SAAS,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,MAAM;AACzF;AAEA,eAAsB,cACpB,UACA,WACA,WAAW,IAAI,KAAK,KAAK,KACD;AACxB,MAAI;AACF,UAAM,MAAM,MAAM,GAAG,SAAS,QAAQ,UAAU,SAAS,GAAG,MAAM;AAClE,UAAM,QAAwB,KAAK,MAAM,GAAG;AAC5C,UAAM,MAAM,KAAK,IAAI,IAAI,IAAI,KAAK,MAAM,OAAO,EAAE,QAAQ;AACzD,QAAI,MAAM,SAAU,QAAO;AAC3B,WAAO,MAAM;AAAA,EACf,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,eAAe,UAAkB,WAAkC;AACvF,MAAI;AACF,UAAM,GAAG,OAAO,QAAQ,UAAU,SAAS,CAAC;AAAA,EAC9C,QAAQ;AAAA,EAAqB;AAC/B;AAGO,SAAS,mBAAmB,MAAc,SAAyB;AACxE,MAAI;AACF,UAAM,IAAI,KAAK,MAAM,IAAI;AACzB,UAAM,IAAI,KAAK,MAAM,OAAO;AAG5B,UAAM,UAAU,CAAC,GAAI,EAAE,WAAW,CAAC,CAAE;AACrC,eAAW,MAAO,EAAE,WAAW,CAAC,GAAI;AAClC,YAAM,MAAM,QAAQ;AAAA,QAClB,CAAC,MAAW,EAAE,SAAS,GAAG,QAAQ,EAAE,WAAW,GAAG,UAAU,EAAE,SAAS,GAAG;AAAA,MAC5E;AACA,UAAI,OAAO,EAAG,SAAQ,GAAG,IAAI;AAAA,UACxB,SAAQ,KAAK,EAAE;AAAA,IACtB;AAGA,UAAM,aAAa,oBAAI,IAAiB;AACxC,eAAW,KAAK,CAAC,GAAI,EAAE,WAAW,CAAC,GAAI,GAAI,EAAE,WAAW,CAAC,CAAE,GAAG;AAC5D,iBAAW,IAAI,EAAE,QAAQ,CAAC;AAAA,IAC5B;AAEA,WAAO,KAAK,UAAU,EAAE,SAAS,SAAS,CAAC,GAAG,WAAW,OAAO,CAAC,EAAE,CAAC;AAAA,EACtE,QAAQ;AACN,WAAO,WAAW;AAAA,EACpB;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Session management for authenticated crawl sessions.
3
+ * Detects auth expiry via HTTP status codes and login-page redirects,
4
+ * then attempts recovery via a token refresh endpoint or re-login flow.
5
+ * Designed to keep long-running crawls alive without manual intervention.
6
+ */
7
+ import type { Page } from 'playwright';
8
+ export interface SessionConfig {
9
+ loginUrl?: string;
10
+ email?: string;
11
+ password?: string;
12
+ healthCheckUrl?: string;
13
+ refreshEndpoint?: string;
14
+ tokenLocalStorageKey?: string;
15
+ maxRefreshAttempts?: number;
16
+ }
17
+ export type SessionEventType = 'HEALTHY' | 'EXPIRY_DETECTED' | 'REFRESH_ATTEMPT' | 'REFRESH_SUCCESS' | 'REFRESH_FAILED' | 'AUTH_FAILURE';
18
+ export interface SessionEvent {
19
+ type: SessionEventType;
20
+ isoTimestamp: string;
21
+ url?: string;
22
+ strategy?: string;
23
+ attemptCount?: number;
24
+ }
25
+ export interface SessionManager {
26
+ onResponse(url: string, status: number): void;
27
+ onNavigation(url: string): void;
28
+ isHealthy(): boolean;
29
+ needsRefresh(): boolean;
30
+ markHealthy(isoTimestamp: string): void;
31
+ refresh(page: Page, isoTimestamp: string): Promise<boolean>;
32
+ getEvents(): SessionEvent[];
33
+ getStats(): {
34
+ healthy: boolean;
35
+ refreshAttempts: number;
36
+ authFailure: boolean;
37
+ };
38
+ }
39
+ export declare function createSessionManager(config: SessionConfig): SessionManager;
40
+ /**
41
+ * Attaches a Playwright response listener to feed HTTP status codes into the
42
+ * session manager. Returns a cleanup function to remove the listener.
43
+ */
44
+ export declare function attachSessionWatcher(page: Page, manager: SessionManager): () => void;
@@ -0,0 +1,145 @@
1
+ const LOGIN_PATH_PATTERNS = [
2
+ "/login",
3
+ "/sign-in",
4
+ "/signin",
5
+ "/auth/login",
6
+ "/auth/sign-in"
7
+ ];
8
+ function createSessionManager(config) {
9
+ let healthy = true;
10
+ let refreshAttempts = 0;
11
+ let authFailure = false;
12
+ const events = [];
13
+ const maxAttempts = config.maxRefreshAttempts ?? 3;
14
+ function onResponse(url, status) {
15
+ if ((status === 401 || status === 403) && healthy) {
16
+ healthy = false;
17
+ events.push({ type: "EXPIRY_DETECTED", isoTimestamp: (/* @__PURE__ */ new Date()).toISOString(), url });
18
+ }
19
+ }
20
+ function onNavigation(url) {
21
+ const isLoginPage = LOGIN_PATH_PATTERNS.some((pattern) => url.includes(pattern));
22
+ if (isLoginPage && healthy) {
23
+ healthy = false;
24
+ events.push({ type: "EXPIRY_DETECTED", isoTimestamp: (/* @__PURE__ */ new Date()).toISOString(), url });
25
+ }
26
+ }
27
+ function isHealthy() {
28
+ return healthy;
29
+ }
30
+ function needsRefresh() {
31
+ return !healthy && !authFailure && refreshAttempts < maxAttempts;
32
+ }
33
+ function markHealthy(isoTimestamp) {
34
+ healthy = true;
35
+ events.push({ type: "HEALTHY", isoTimestamp });
36
+ }
37
+ async function tryRefreshEndpoint(page, isoTimestamp) {
38
+ if (!config.refreshEndpoint) return false;
39
+ events.push({
40
+ type: "REFRESH_ATTEMPT",
41
+ isoTimestamp,
42
+ strategy: "refreshEndpoint",
43
+ attemptCount: refreshAttempts + 1
44
+ });
45
+ try {
46
+ const result = await page.evaluate(async (endpoint) => {
47
+ try {
48
+ const res = await fetch(endpoint, { method: "POST", credentials: "include" });
49
+ if (res.ok) {
50
+ const data = await res.json().catch(() => ({}));
51
+ return { ok: true, token: data.access_token || data.token || null };
52
+ }
53
+ return { ok: false, token: null };
54
+ } catch {
55
+ return { ok: false, token: null };
56
+ }
57
+ }, config.refreshEndpoint);
58
+ if (result.ok) {
59
+ if (result.token && config.tokenLocalStorageKey) {
60
+ await page.evaluate(
61
+ ([key, val]) => localStorage.setItem(key, val),
62
+ [config.tokenLocalStorageKey, result.token]
63
+ );
64
+ }
65
+ refreshAttempts++;
66
+ events.push({ type: "REFRESH_SUCCESS", isoTimestamp, strategy: "refreshEndpoint" });
67
+ return true;
68
+ }
69
+ } catch {
70
+ }
71
+ return false;
72
+ }
73
+ async function tryReLogin(page, isoTimestamp) {
74
+ if (!config.loginUrl || !config.email || !config.password) return false;
75
+ events.push({
76
+ type: "REFRESH_ATTEMPT",
77
+ isoTimestamp,
78
+ strategy: "reLogin",
79
+ attemptCount: refreshAttempts + 1
80
+ });
81
+ try {
82
+ await page.goto(config.loginUrl, { waitUntil: "domcontentloaded" });
83
+ await page.locator('input[type="email"], input[name="email"], input[name="username"]').first().fill(config.email);
84
+ await page.locator('input[type="password"]').first().fill(config.password);
85
+ await page.locator(
86
+ 'button[type="submit"], button:has-text("Sign In"), button:has-text("Log In"), button:has-text("Login")'
87
+ ).first().click();
88
+ await page.waitForFunction(
89
+ (loginUrl) => !location.href.includes(loginUrl),
90
+ config.loginUrl,
91
+ { timeout: 1e4 }
92
+ );
93
+ events.push({ type: "REFRESH_SUCCESS", isoTimestamp, strategy: "reLogin" });
94
+ return true;
95
+ } catch {
96
+ events.push({ type: "REFRESH_FAILED", isoTimestamp, strategy: "reLogin" });
97
+ return false;
98
+ }
99
+ }
100
+ async function refresh(page, isoTimestamp) {
101
+ if (config.refreshEndpoint) {
102
+ const ok = await tryRefreshEndpoint(page, isoTimestamp);
103
+ if (ok) return true;
104
+ }
105
+ if (config.loginUrl && config.email && config.password) {
106
+ const ok = await tryReLogin(page, isoTimestamp);
107
+ if (ok) return true;
108
+ }
109
+ refreshAttempts++;
110
+ events.push({ type: "REFRESH_FAILED", isoTimestamp, attemptCount: refreshAttempts });
111
+ if (refreshAttempts >= maxAttempts) {
112
+ authFailure = true;
113
+ events.push({ type: "AUTH_FAILURE", isoTimestamp, attemptCount: refreshAttempts });
114
+ }
115
+ return false;
116
+ }
117
+ function getEvents() {
118
+ return [...events];
119
+ }
120
+ function getStats() {
121
+ return { healthy, refreshAttempts, authFailure };
122
+ }
123
+ return {
124
+ onResponse,
125
+ onNavigation,
126
+ isHealthy,
127
+ needsRefresh,
128
+ markHealthy,
129
+ refresh,
130
+ getEvents,
131
+ getStats
132
+ };
133
+ }
134
+ function attachSessionWatcher(page, manager) {
135
+ const onResponse = (res) => {
136
+ manager.onResponse(res.url(), res.status());
137
+ };
138
+ page.on("response", onResponse);
139
+ return () => page.off("response", onResponse);
140
+ }
141
+ export {
142
+ attachSessionWatcher,
143
+ createSessionManager
144
+ };
145
+ //# sourceMappingURL=crawl-session-manager.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/crawl-session-manager.ts"],
4
+ "sourcesContent": ["/**\n * Session management for authenticated crawl sessions.\n * Detects auth expiry via HTTP status codes and login-page redirects,\n * then attempts recovery via a token refresh endpoint or re-login flow.\n * Designed to keep long-running crawls alive without manual intervention.\n */\n\nimport type { Page } from 'playwright';\n\nexport interface SessionConfig {\n loginUrl?: string;\n email?: string;\n password?: string;\n healthCheckUrl?: string;\n refreshEndpoint?: string;\n tokenLocalStorageKey?: string;\n maxRefreshAttempts?: number;\n}\n\nexport type SessionEventType =\n | 'HEALTHY'\n | 'EXPIRY_DETECTED'\n | 'REFRESH_ATTEMPT'\n | 'REFRESH_SUCCESS'\n | 'REFRESH_FAILED'\n | 'AUTH_FAILURE';\n\nexport interface SessionEvent {\n type: SessionEventType;\n isoTimestamp: string;\n url?: string;\n strategy?: string;\n attemptCount?: number;\n}\n\nexport interface SessionManager {\n onResponse(url: string, status: number): void;\n onNavigation(url: string): void;\n isHealthy(): boolean;\n needsRefresh(): boolean;\n markHealthy(isoTimestamp: string): void;\n refresh(page: Page, isoTimestamp: string): Promise<boolean>;\n getEvents(): SessionEvent[];\n getStats(): { healthy: boolean; refreshAttempts: number; authFailure: boolean };\n}\n\nconst LOGIN_PATH_PATTERNS = [\n '/login',\n '/sign-in',\n '/signin',\n '/auth/login',\n '/auth/sign-in',\n];\n\nexport function createSessionManager(config: SessionConfig): SessionManager {\n let healthy = true;\n let refreshAttempts = 0;\n let authFailure = false;\n const events: SessionEvent[] = [];\n const maxAttempts = config.maxRefreshAttempts ?? 3;\n\n function onResponse(url: string, status: number): void {\n if ((status === 401 || status === 403) && healthy) {\n healthy = false;\n events.push({ type: 'EXPIRY_DETECTED', isoTimestamp: new Date().toISOString(), url });\n }\n }\n\n function onNavigation(url: string): void {\n const isLoginPage = LOGIN_PATH_PATTERNS.some((pattern) => url.includes(pattern));\n if (isLoginPage && healthy) {\n healthy = false;\n events.push({ type: 'EXPIRY_DETECTED', isoTimestamp: new Date().toISOString(), url });\n }\n }\n\n function isHealthy(): boolean {\n return healthy;\n }\n\n function needsRefresh(): boolean {\n return !healthy && !authFailure && refreshAttempts < maxAttempts;\n }\n\n function markHealthy(isoTimestamp: string): void {\n healthy = true;\n events.push({ type: 'HEALTHY', isoTimestamp });\n }\n\n async function tryRefreshEndpoint(page: Page, isoTimestamp: string): Promise<boolean> {\n if (!config.refreshEndpoint) return false;\n\n events.push({\n type: 'REFRESH_ATTEMPT',\n isoTimestamp,\n strategy: 'refreshEndpoint',\n attemptCount: refreshAttempts + 1,\n });\n\n try {\n const result = await page.evaluate(async (endpoint) => {\n try {\n const res = await fetch(endpoint, { method: 'POST', credentials: 'include' });\n if (res.ok) {\n const data = await res.json().catch(() => ({}));\n return { ok: true, token: (data as any).access_token || (data as any).token || null };\n }\n return { ok: false, token: null };\n } catch {\n return { ok: false, token: null };\n }\n }, config.refreshEndpoint);\n\n if (result.ok) {\n if (result.token && config.tokenLocalStorageKey) {\n await page.evaluate(\n ([key, val]) => localStorage.setItem(key, val),\n [config.tokenLocalStorageKey, result.token] as [string, string],\n );\n }\n refreshAttempts++;\n events.push({ type: 'REFRESH_SUCCESS', isoTimestamp, strategy: 'refreshEndpoint' });\n return true;\n }\n } catch {\n // page.evaluate or localStorage.setItem failed \u2014 fall through\n }\n\n return false;\n }\n\n async function tryReLogin(page: Page, isoTimestamp: string): Promise<boolean> {\n if (!config.loginUrl || !config.email || !config.password) return false;\n\n events.push({\n type: 'REFRESH_ATTEMPT',\n isoTimestamp,\n strategy: 'reLogin',\n attemptCount: refreshAttempts + 1,\n });\n\n try {\n await page.goto(config.loginUrl, { waitUntil: 'domcontentloaded' });\n\n await page\n .locator('input[type=\"email\"], input[name=\"email\"], input[name=\"username\"]')\n .first()\n .fill(config.email);\n\n await page\n .locator('input[type=\"password\"]')\n .first()\n .fill(config.password);\n\n await page\n .locator(\n 'button[type=\"submit\"], button:has-text(\"Sign In\"), button:has-text(\"Log In\"), button:has-text(\"Login\")',\n )\n .first()\n .click();\n\n await page.waitForFunction(\n (loginUrl) => !location.href.includes(loginUrl),\n config.loginUrl,\n { timeout: 10000 },\n );\n\n events.push({ type: 'REFRESH_SUCCESS', isoTimestamp, strategy: 'reLogin' });\n return true;\n } catch {\n events.push({ type: 'REFRESH_FAILED', isoTimestamp, strategy: 'reLogin' });\n return false;\n }\n }\n\n async function refresh(page: Page, isoTimestamp: string): Promise<boolean> {\n // Strategy 1: token refresh endpoint\n if (config.refreshEndpoint) {\n const ok = await tryRefreshEndpoint(page, isoTimestamp);\n if (ok) return true;\n }\n\n // Strategy 2: re-login\n if (config.loginUrl && config.email && config.password) {\n const ok = await tryReLogin(page, isoTimestamp);\n if (ok) return true;\n }\n\n // All strategies exhausted\n refreshAttempts++;\n events.push({ type: 'REFRESH_FAILED', isoTimestamp, attemptCount: refreshAttempts });\n\n if (refreshAttempts >= maxAttempts) {\n authFailure = true;\n events.push({ type: 'AUTH_FAILURE', isoTimestamp, attemptCount: refreshAttempts });\n }\n\n return false;\n }\n\n function getEvents(): SessionEvent[] {\n return [...events];\n }\n\n function getStats(): { healthy: boolean; refreshAttempts: number; authFailure: boolean } {\n return { healthy, refreshAttempts, authFailure };\n }\n\n return {\n onResponse,\n onNavigation,\n isHealthy,\n needsRefresh,\n markHealthy,\n refresh,\n getEvents,\n getStats,\n };\n}\n\n/**\n * Attaches a Playwright response listener to feed HTTP status codes into the\n * session manager. Returns a cleanup function to remove the listener.\n */\nexport function attachSessionWatcher(page: Page, manager: SessionManager): () => void {\n const onResponse = (res: import('playwright').Response) => {\n manager.onResponse(res.url(), res.status());\n };\n page.on('response', onResponse);\n return () => page.off('response', onResponse);\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }