@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.
- package/Dockerfile +82 -0
- package/README.md +10 -2
- package/dist/accessibility-auditor.d.ts +29 -0
- package/dist/accessibility-auditor.js +57 -0
- package/dist/accessibility-auditor.js.map +7 -0
- package/dist/accessibility-tree-crawler.d.ts +44 -0
- package/dist/accessibility-tree-crawler.js +156 -0
- package/dist/accessibility-tree-crawler.js.map +7 -0
- package/dist/advanced-ui-probes.d.ts +47 -0
- package/dist/advanced-ui-probes.js +310 -0
- package/dist/advanced-ui-probes.js.map +7 -0
- package/dist/ai-login.d.ts +32 -0
- package/dist/ai-login.js +250 -0
- package/dist/ai-login.js.map +7 -0
- package/dist/auth-token-rotator.d.ts +47 -0
- package/dist/auth-token-rotator.js +58 -0
- package/dist/auth-token-rotator.js.map +7 -0
- package/dist/auth.d.ts +20 -0
- package/dist/auth.js +348 -0
- package/dist/auth.js.map +7 -0
- package/dist/browser-extension.d.ts +37 -0
- package/dist/browser-extension.js +113 -0
- package/dist/browser-extension.js.map +7 -0
- package/dist/captcha-solver.d.ts +16 -0
- package/dist/captcha-solver.js +105 -0
- package/dist/captcha-solver.js.map +7 -0
- package/dist/color-contrast.d.ts +30 -0
- package/dist/color-contrast.js +78 -0
- package/dist/color-contrast.js.map +7 -0
- package/dist/content-chunker.d.ts +18 -0
- package/dist/content-chunker.js +152 -0
- package/dist/content-chunker.js.map +7 -0
- package/dist/content-dedup.d.ts +23 -0
- package/dist/content-dedup.js +60 -0
- package/dist/content-dedup.js.map +7 -0
- package/dist/cookie-consent.d.ts +25 -0
- package/dist/cookie-consent.js +78 -0
- package/dist/cookie-consent.js.map +7 -0
- package/dist/cookie-jar.d.ts +20 -0
- package/dist/cookie-jar.js +61 -0
- package/dist/cookie-jar.js.map +7 -0
- package/dist/crawl-session-manager.d.ts +44 -0
- package/dist/crawl-session-manager.js +145 -0
- package/dist/crawl-session-manager.js.map +7 -0
- package/dist/crawler.d.ts +233 -0
- package/dist/crawler.js +6239 -0
- package/dist/crawler.js.map +7 -0
- package/dist/crud-interaction.d.ts +31 -0
- package/dist/crud-interaction.js +264 -0
- package/dist/crud-interaction.js.map +7 -0
- package/dist/custom-js-injector.d.ts +42 -0
- package/dist/custom-js-injector.js +50 -0
- package/dist/custom-js-injector.js.map +7 -0
- package/dist/dark-mode-capture.d.ts +23 -0
- package/dist/dark-mode-capture.js +75 -0
- package/dist/dark-mode-capture.js.map +7 -0
- package/dist/dead-link-detector.d.ts +37 -0
- package/dist/dead-link-detector.js +50 -0
- package/dist/dead-link-detector.js.map +7 -0
- package/dist/dropdown-enumerator.d.ts +20 -0
- package/dist/dropdown-enumerator.js +230 -0
- package/dist/dropdown-enumerator.js.map +7 -0
- package/dist/element-hash.d.ts +9 -0
- package/dist/element-hash.js +9 -0
- package/dist/element-hash.js.map +7 -0
- package/dist/email-otp.d.ts +42 -0
- package/dist/email-otp.js +177 -0
- package/dist/email-otp.js.map +7 -0
- package/dist/engine-router.d.ts +47 -0
- package/dist/engine-router.js +94 -0
- package/dist/engine-router.js.map +7 -0
- package/dist/export/bulk-export.d.ts +26 -0
- package/dist/export/bulk-export.js +76 -0
- package/dist/export/bulk-export.js.map +7 -0
- package/dist/export/vector-export.d.ts +76 -0
- package/dist/export/vector-export.js +85 -0
- package/dist/export/vector-export.js.map +7 -0
- package/dist/extractors/advanced.d.ts +64 -0
- package/dist/extractors/advanced.js +265 -0
- package/dist/extractors/advanced.js.map +7 -0
- package/dist/extractors/artifact-envelope.d.ts +63 -0
- package/dist/extractors/artifact-envelope.js +63 -0
- package/dist/extractors/artifact-envelope.js.map +7 -0
- package/dist/extractors/branding-extractor.d.ts +46 -0
- package/dist/extractors/branding-extractor.js +104 -0
- package/dist/extractors/branding-extractor.js.map +7 -0
- package/dist/extractors/summary-extractor.d.ts +10 -0
- package/dist/extractors/summary-extractor.js +36 -0
- package/dist/extractors/summary-extractor.js.map +7 -0
- package/dist/failure-analysis-agent.d.ts +16 -0
- package/dist/failure-analysis-agent.js +42 -0
- package/dist/failure-analysis-agent.js.map +7 -0
- package/dist/feature-flag-detector.d.ts +30 -0
- package/dist/feature-flag-detector.js +55 -0
- package/dist/feature-flag-detector.js.map +7 -0
- package/dist/filter-pagination-crawler.d.ts +52 -0
- package/dist/filter-pagination-crawler.js +299 -0
- package/dist/filter-pagination-crawler.js.map +7 -0
- package/dist/form-detector.d.ts +34 -0
- package/dist/form-detector.js +58 -0
- package/dist/form-detector.js.map +7 -0
- package/dist/frontier.d.ts +40 -0
- package/dist/frontier.js +103 -0
- package/dist/frontier.js.map +7 -0
- package/dist/gap-pass.d.ts +36 -0
- package/dist/gap-pass.js +115 -0
- package/dist/gap-pass.js.map +7 -0
- package/dist/graphql-detector.d.ts +39 -0
- package/dist/graphql-detector.js +86 -0
- package/dist/graphql-detector.js.map +7 -0
- package/dist/http-engine.d.ts +80 -0
- package/dist/http-engine.js +318 -0
- package/dist/http-engine.js.map +7 -0
- package/dist/incremental-diff.d.ts +116 -0
- package/dist/incremental-diff.js +137 -0
- package/dist/incremental-diff.js.map +7 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +83 -0
- package/dist/index.js.map +7 -0
- package/dist/input-fuzzer.d.ts +30 -0
- package/dist/input-fuzzer.js +105 -0
- package/dist/input-fuzzer.js.map +7 -0
- package/dist/interactive-probe.d.ts +144 -0
- package/dist/interactive-probe.js +865 -0
- package/dist/interactive-probe.js.map +7 -0
- package/dist/job-queue.d.ts +297 -0
- package/dist/job-queue.js +3812 -0
- package/dist/job-queue.js.map +7 -0
- package/dist/js-coverage.d.ts +29 -0
- package/dist/js-coverage.js +56 -0
- package/dist/js-coverage.js.map +7 -0
- package/dist/js-router-detector.d.ts +17 -0
- package/dist/js-router-detector.js +90 -0
- package/dist/js-router-detector.js.map +7 -0
- package/dist/language-detector.d.ts +22 -0
- package/dist/language-detector.js +57 -0
- package/dist/language-detector.js.map +7 -0
- package/dist/link-classifier.d.ts +23 -0
- package/dist/link-classifier.js +40 -0
- package/dist/link-classifier.js.map +7 -0
- package/dist/live-view.d.ts +36 -0
- package/dist/live-view.js +105 -0
- package/dist/live-view.js.map +7 -0
- package/dist/locator-extractor.d.ts +46 -0
- package/dist/locator-extractor.js +220 -0
- package/dist/locator-extractor.js.map +7 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +10 -0
- package/dist/logger.js.map +7 -0
- package/dist/markdown-extract.d.ts +8 -0
- package/dist/markdown-extract.js +54 -0
- package/dist/markdown-extract.js.map +7 -0
- package/dist/multi-context-handler.d.ts +55 -0
- package/dist/multi-context-handler.js +182 -0
- package/dist/multi-context-handler.js.map +7 -0
- package/dist/native-crawler.d.ts +69 -0
- package/dist/native-crawler.js +839 -0
- package/dist/native-crawler.js.map +7 -0
- package/dist/nested-window-crawler.d.ts +41 -0
- package/dist/nested-window-crawler.js +172 -0
- package/dist/nested-window-crawler.js.map +7 -0
- package/dist/network-action-correlator.d.ts +47 -0
- package/dist/network-action-correlator.js +209 -0
- package/dist/network-action-correlator.js.map +7 -0
- package/dist/network-observer.d.ts +49 -0
- package/dist/network-observer.js +149 -0
- package/dist/network-observer.js.map +7 -0
- package/dist/network-throttle.d.ts +25 -0
- package/dist/network-throttle.js +34 -0
- package/dist/network-throttle.js.map +7 -0
- package/dist/openapi-generator.d.ts +49 -0
- package/dist/openapi-generator.js +89 -0
- package/dist/openapi-generator.js.map +7 -0
- package/dist/pdf-extractor.d.ts +28 -0
- package/dist/pdf-extractor.js +81 -0
- package/dist/pdf-extractor.js.map +7 -0
- package/dist/performance-metrics-collector.d.ts +50 -0
- package/dist/performance-metrics-collector.js +155 -0
- package/dist/performance-metrics-collector.js.map +7 -0
- package/dist/performance-metrics.d.ts +52 -0
- package/dist/performance-metrics.js +83 -0
- package/dist/performance-metrics.js.map +7 -0
- package/dist/phash.d.ts +50 -0
- package/dist/phash.js +136 -0
- package/dist/phash.js.map +7 -0
- package/dist/pii-scrubber.d.ts +21 -0
- package/dist/pii-scrubber.js +75 -0
- package/dist/pii-scrubber.js.map +7 -0
- package/dist/playwright-recorder.d.ts +39 -0
- package/dist/playwright-recorder.js +123 -0
- package/dist/playwright-recorder.js.map +7 -0
- package/dist/policies/crawl-safety.d.ts +9 -0
- package/dist/policies/crawl-safety.js +41 -0
- package/dist/policies/crawl-safety.js.map +7 -0
- package/dist/profiles/domain-profile.d.ts +19 -0
- package/dist/profiles/domain-profile.js +160 -0
- package/dist/profiles/domain-profile.js.map +7 -0
- package/dist/proxy.d.ts +50 -0
- package/dist/proxy.js +165 -0
- package/dist/proxy.js.map +7 -0
- package/dist/rate-limiter.d.ts +31 -0
- package/dist/rate-limiter.js +64 -0
- package/dist/rate-limiter.js.map +7 -0
- package/dist/redirect-tracker.d.ts +37 -0
- package/dist/redirect-tracker.js +65 -0
- package/dist/redirect-tracker.js.map +7 -0
- package/dist/redis-frontier.d.ts +48 -0
- package/dist/redis-frontier.js +126 -0
- package/dist/redis-frontier.js.map +7 -0
- package/dist/redis-queue.d.ts +48 -0
- package/dist/redis-queue.js +165 -0
- package/dist/redis-queue.js.map +7 -0
- package/dist/response-cache.d.ts +38 -0
- package/dist/response-cache.js +140 -0
- package/dist/response-cache.js.map +7 -0
- package/dist/responsive-detector.d.ts +29 -0
- package/dist/responsive-detector.js +46 -0
- package/dist/responsive-detector.js.map +7 -0
- package/dist/retry-policy.d.ts +20 -0
- package/dist/retry-policy.js +54 -0
- package/dist/retry-policy.js.map +7 -0
- package/dist/robots-txt.d.ts +9 -0
- package/dist/robots-txt.js +77 -0
- package/dist/robots-txt.js.map +7 -0
- package/dist/screen-reader.d.ts +15 -0
- package/dist/screen-reader.js +48 -0
- package/dist/screen-reader.js.map +7 -0
- package/dist/screenshot-masker.d.ts +28 -0
- package/dist/screenshot-masker.js +62 -0
- package/dist/screenshot-masker.js.map +7 -0
- package/dist/seo-checker.d.ts +33 -0
- package/dist/seo-checker.js +91 -0
- package/dist/seo-checker.js.map +7 -0
- package/dist/service-worker-interceptor.d.ts +36 -0
- package/dist/service-worker-interceptor.js +136 -0
- package/dist/service-worker-interceptor.js.map +7 -0
- package/dist/session-capture.d.ts +39 -0
- package/dist/session-capture.js +274 -0
- package/dist/session-capture.js.map +7 -0
- package/dist/session-export.d.ts +49 -0
- package/dist/session-export.js +117 -0
- package/dist/session-export.js.map +7 -0
- package/dist/shadow-dom-crawler.d.ts +35 -0
- package/dist/shadow-dom-crawler.js +132 -0
- package/dist/shadow-dom-crawler.js.map +7 -0
- package/dist/sitemap-writer.d.ts +21 -0
- package/dist/sitemap-writer.js +47 -0
- package/dist/sitemap-writer.js.map +7 -0
- package/dist/sitemap.d.ts +51 -0
- package/dist/sitemap.js +160 -0
- package/dist/sitemap.js.map +7 -0
- package/dist/skyvern.d.ts +56 -0
- package/dist/skyvern.js +129 -0
- package/dist/skyvern.js.map +7 -0
- package/dist/sqs-queue.d.ts +13 -0
- package/dist/sqs-queue.js +115 -0
- package/dist/sqs-queue.js.map +7 -0
- package/dist/sso-token.d.ts +29 -0
- package/dist/sso-token.js +76 -0
- package/dist/sso-token.js.map +7 -0
- package/dist/state-graph.d.ts +59 -0
- package/dist/state-graph.js +193 -0
- package/dist/state-graph.js.map +7 -0
- package/dist/stealth/human-behavior.d.ts +20 -0
- package/dist/stealth/human-behavior.js +202 -0
- package/dist/stealth/human-behavior.js.map +7 -0
- package/dist/telemetry.d.ts +34 -0
- package/dist/telemetry.js +77 -0
- package/dist/telemetry.js.map +7 -0
- package/dist/test-executor.d.ts +81 -0
- package/dist/test-executor.js +443 -0
- package/dist/test-executor.js.map +7 -0
- package/dist/tls-fingerprint.d.ts +50 -0
- package/dist/tls-fingerprint.js +81 -0
- package/dist/tls-fingerprint.js.map +7 -0
- package/dist/url-pattern-completer.d.ts +28 -0
- package/dist/url-pattern-completer.js +122 -0
- package/dist/url-pattern-completer.js.map +7 -0
- package/dist/visual-diff-verdict.d.ts +40 -0
- package/dist/visual-diff-verdict.js +27 -0
- package/dist/visual-diff-verdict.js.map +7 -0
- package/dist/webhook-notifier.d.ts +30 -0
- package/dist/webhook-notifier.js +76 -0
- package/dist/webhook-notifier.js.map +7 -0
- package/dist/websocket-detector.d.ts +24 -0
- package/dist/websocket-detector.js +60 -0
- package/dist/websocket-detector.js.map +7 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.js +33 -0
- package/dist/worker.js.map +7 -0
- package/package.json +49 -4
- package/src/accessibility-auditor.ts +102 -0
- package/src/accessibility-tree-crawler.ts +246 -0
- package/src/advanced-ui-probes.ts +470 -0
- package/src/ai-login.ts +298 -0
- package/src/auth-token-rotator.ts +89 -0
- package/src/auth.ts +418 -0
- package/src/browser-extension.ts +186 -0
- package/src/captcha-solver.ts +143 -0
- package/src/color-contrast.ts +116 -0
- package/src/content-chunker.ts +170 -0
- package/src/content-dedup.ts +99 -0
- package/src/cookie-consent.ts +106 -0
- package/src/cookie-jar.ts +91 -0
- package/src/crawl-session-manager.ts +231 -0
- package/src/crawler.ts +7123 -0
- package/src/crawler.ts.rej +12 -0
- package/src/crud-interaction.ts +386 -0
- package/src/custom-js-injector.ts +93 -0
- package/src/dark-mode-capture.ts +110 -0
- package/src/dead-link-detector.ts +76 -0
- package/src/dropdown-enumerator.ts +312 -0
- package/src/element-hash.ts +16 -0
- package/src/email-otp.ts +252 -0
- package/src/engine-router.ts +141 -0
- package/src/export/bulk-export.ts +85 -0
- package/src/export/vector-export.ts +160 -0
- package/src/extractors/advanced.ts +309 -0
- package/src/extractors/artifact-envelope.ts +111 -0
- package/src/extractors/branding-extractor.ts +159 -0
- package/src/extractors/summary-extractor.ts +49 -0
- package/src/failure-analysis-agent.ts +51 -0
- package/src/feature-flag-detector.ts +97 -0
- package/src/filter-pagination-crawler.ts +500 -0
- package/src/form-detector.ts +103 -0
- package/src/frontier.test.ts +64 -0
- package/src/frontier.ts +144 -0
- package/src/gap-pass.ts +165 -0
- package/src/graphql-detector.ts +129 -0
- package/src/http-engine.ts +453 -0
- package/src/incremental-diff.ts +259 -0
- package/src/index.ts +52 -0
- package/src/input-fuzzer.ts +129 -0
- package/src/interactive-probe.ts +1136 -0
- package/src/job-queue.test.ts +187 -0
- package/src/job-queue.ts +4504 -0
- package/src/js-coverage.ts +87 -0
- package/src/js-router-detector.ts +112 -0
- package/src/language-detector.ts +82 -0
- package/src/link-classifier.ts +65 -0
- package/src/live-view.ts +146 -0
- package/src/locator-extractor.ts +309 -0
- package/src/logger.ts +9 -0
- package/src/markdown-extract.test.ts +73 -0
- package/src/markdown-extract.ts +76 -0
- package/src/multi-context-handler.ts +296 -0
- package/src/native-crawler.ts +1108 -0
- package/src/nested-window-crawler.ts +310 -0
- package/src/network-action-correlator.ts +320 -0
- package/src/network-observer.ts +204 -0
- package/src/network-throttle.ts +69 -0
- package/src/openapi-generator.ts +135 -0
- package/src/pdf-extractor.ts +123 -0
- package/src/performance-metrics-collector.ts +243 -0
- package/src/performance-metrics.ts +134 -0
- package/src/phash.ts +184 -0
- package/src/pii-scrubber.ts +99 -0
- package/src/playwright-recorder.ts +170 -0
- package/src/policies/crawl-safety.ts +52 -0
- package/src/profiles/domain-profile.ts +190 -0
- package/src/proxy.ts +238 -0
- package/src/rate-limiter.ts +87 -0
- package/src/redirect-tracker.ts +97 -0
- package/src/redis-frontier.ts +143 -0
- package/src/redis-queue.ts +208 -0
- package/src/response-cache.ts +150 -0
- package/src/responsive-detector.ts +92 -0
- package/src/retry-policy.ts +87 -0
- package/src/robots-txt.ts +96 -0
- package/src/screen-reader.ts +98 -0
- package/src/screenshot-masker.ts +98 -0
- package/src/seo-checker.ts +134 -0
- package/src/service-worker-interceptor.ts +185 -0
- package/src/session-capture.ts +335 -0
- package/src/session-export.test.ts +75 -0
- package/src/session-export.ts +172 -0
- package/src/shadow-dom-crawler.ts +198 -0
- package/src/sitemap-writer.ts +65 -0
- package/src/sitemap.test.ts +127 -0
- package/src/sitemap.ts +233 -0
- package/src/skyvern.ts +199 -0
- package/src/sqs-queue.ts +129 -0
- package/src/sso-token.ts +120 -0
- package/src/state-graph.ts +280 -0
- package/src/stealth/human-behavior.ts +227 -0
- package/src/telemetry.ts +122 -0
- package/src/test-executor.test.ts +72 -0
- package/src/test-executor.ts +578 -0
- package/src/tls-fingerprint.ts +111 -0
- package/src/url-pattern-completer.ts +161 -0
- package/src/vendor.d.ts +20 -0
- package/src/visual-diff-verdict.test.ts +80 -0
- package/src/visual-diff-verdict.ts +59 -0
- package/src/webhook-notifier.ts +109 -0
- package/src/websocket-detector.ts +83 -0
- package/src/worker.ts +50 -0
- package/tsconfig.json +13 -0
- package/types/accessibility-auditor.d.ts +29 -0
- package/types/accessibility-tree-crawler.d.ts +44 -0
- package/types/advanced-ui-probes.d.ts +47 -0
- package/types/ai-login.d.ts +32 -0
- package/types/auth-token-rotator.d.ts +47 -0
- package/types/auth.d.ts +20 -0
- package/types/browser-extension.d.ts +37 -0
- package/types/bull-worker.d.ts +6 -0
- package/types/captcha-solver.d.ts +16 -0
- package/types/color-contrast.d.ts +30 -0
- package/types/content-chunker.d.ts +18 -0
- package/types/content-dedup.d.ts +23 -0
- package/types/cookie-consent.d.ts +25 -0
- package/types/cookie-jar.d.ts +20 -0
- package/types/crawl-session-manager.d.ts +44 -0
- package/types/crawler.d.ts +233 -0
- package/types/crud-interaction.d.ts +31 -0
- package/types/custom-js-injector.d.ts +42 -0
- package/types/dark-mode-capture.d.ts +23 -0
- package/types/dead-link-detector.d.ts +37 -0
- package/types/dropdown-enumerator.d.ts +20 -0
- package/types/element-hash.d.ts +9 -0
- package/types/email-otp.d.ts +42 -0
- package/types/engine-router.d.ts +47 -0
- package/types/export/bulk-export.d.ts +26 -0
- package/types/export/vector-export.d.ts +76 -0
- package/types/extractors/advanced.d.ts +64 -0
- package/types/extractors/artifact-envelope.d.ts +63 -0
- package/types/extractors/branding-extractor.d.ts +46 -0
- package/types/extractors/summary-extractor.d.ts +10 -0
- package/types/failure-analysis-agent.d.ts +16 -0
- package/types/feature-flag-detector.d.ts +30 -0
- package/types/filter-pagination-crawler.d.ts +52 -0
- package/types/form-detector.d.ts +34 -0
- package/types/frontier.d.ts +40 -0
- package/types/gap-pass.d.ts +36 -0
- package/types/graphql-detector.d.ts +39 -0
- package/types/http-engine.d.ts +80 -0
- package/types/incremental-diff.d.ts +116 -0
- package/types/index.d.ts +52 -0
- package/types/input-fuzzer.d.ts +30 -0
- package/types/interactive-probe.d.ts +144 -0
- package/types/job-queue.d.ts +308 -0
- package/types/js-coverage.d.ts +29 -0
- package/types/js-router-detector.d.ts +17 -0
- package/types/language-detector.d.ts +22 -0
- package/types/link-classifier.d.ts +23 -0
- package/types/live-view.d.ts +36 -0
- package/types/locator-extractor.d.ts +46 -0
- package/types/logger.d.ts +2 -0
- package/types/markdown-extract.d.ts +8 -0
- package/types/multi-context-handler.d.ts +55 -0
- package/types/native-crawler.d.ts +69 -0
- package/types/nested-window-crawler.d.ts +41 -0
- package/types/network-action-correlator.d.ts +47 -0
- package/types/network-observer.d.ts +49 -0
- package/types/network-throttle.d.ts +25 -0
- package/types/openapi-generator.d.ts +49 -0
- package/types/pdf-extractor.d.ts +28 -0
- package/types/performance-metrics-collector.d.ts +50 -0
- package/types/performance-metrics.d.ts +52 -0
- package/types/phash.d.ts +50 -0
- package/types/pii-scrubber.d.ts +21 -0
- package/types/playwright-recorder.d.ts +39 -0
- package/types/policies/crawl-safety.d.ts +9 -0
- package/types/profiles/domain-profile.d.ts +19 -0
- package/types/proxy.d.ts +50 -0
- package/types/rate-limiter.d.ts +31 -0
- package/types/redirect-tracker.d.ts +37 -0
- package/types/redis-frontier.d.ts +48 -0
- package/types/redis-queue.d.ts +48 -0
- package/types/response-cache.d.ts +38 -0
- package/types/responsive-detector.d.ts +29 -0
- package/types/retry-policy.d.ts +20 -0
- package/types/robots-txt.d.ts +9 -0
- package/types/screen-reader.d.ts +15 -0
- package/types/screenshot-masker.d.ts +28 -0
- package/types/seo-checker.d.ts +33 -0
- package/types/service-worker-interceptor.d.ts +36 -0
- package/types/session-capture.d.ts +39 -0
- package/types/session-export.d.ts +49 -0
- package/types/shadow-dom-crawler.d.ts +35 -0
- package/types/sitemap-writer.d.ts +21 -0
- package/types/sitemap.d.ts +51 -0
- package/types/skyvern.d.ts +56 -0
- package/types/sqs-queue.d.ts +13 -0
- package/types/sso-token.d.ts +29 -0
- package/types/state-graph.d.ts +59 -0
- package/types/stealth/human-behavior.d.ts +20 -0
- package/types/telemetry.d.ts +34 -0
- package/types/test-executor.d.ts +84 -0
- package/types/tls-fingerprint.d.ts +50 -0
- package/types/url-pattern-completer.d.ts +28 -0
- package/types/visual-diff-verdict.d.ts +40 -0
- package/types/webhook-notifier.d.ts +30 -0
- package/types/websocket-detector.d.ts +24 -0
- package/types/worker.d.ts +1 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/worker.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Standalone worker process entrypoint for a dedicated crawler/worker container,\n * separate from the API server (see infrastructure/ecs-task-definitions/crawler.json).\n *\n * index.ts is a side-effect-free library barrel imported by @detiq/api \u2014 it must NOT\n * start any background loop itself, or importing a single helper from @detiq/crawler\n * would silently spin up a second worker inside the API process too. This file is\n * the actual entrypoint that keeps a dedicated worker container's process alive and\n * consuming jobs: `node dist/worker.js`.\n */\nimport { startJobWorkerLoop, processDataRetentionPurge } from './job-queue.js';\nimport { logger } from './logger.js';\n\nasync function main() {\n logger.info('[worker] starting standalone crawler worker process');\n\n if (process.env.JOB_QUEUE_BACKEND === 'sqs') {\n // SQS mode: messages arrive via long-poll; claimSpecificJob atomically moves\n // QUEUED\u2192RUNNING before dispatch, so multiple worker replicas are safe.\n // DB poll loop also runs as a safety net for jobs whose SQS message was lost.\n const { startSqsWorker } = await import('./sqs-queue.js');\n startSqsWorker().catch((err) => {\n logger.error({ err: String(err) }, '[worker] SQS worker crashed');\n process.exit(1);\n });\n }\n\n // DB-backed poll loop \u2014 primary in non-SQS mode, safety net in SQS mode.\n // Claims all job types. Safe to run in many worker replicas (FOR UPDATE SKIP LOCKED).\n startJobWorkerLoop();\n\n // Daily data-retention purge: runs immediately on startup then every 24 h.\n // Only runs in the dedicated worker container (this file), not in the API\n // process, so there is exactly one purge sweep regardless of API replica count.\n const runPurge = () => {\n processDataRetentionPurge().catch((err) => {\n logger.error({ err: String(err) }, '[worker] data-retention purge failed');\n });\n };\n runPurge();\n setInterval(runPurge, 24 * 60 * 60 * 1000);\n}\n\nprocess.on('SIGTERM', () => { logger.info('[worker] SIGTERM received, exiting'); process.exit(0); });\nprocess.on('SIGINT', () => { logger.info('[worker] SIGINT received, exiting'); process.exit(0); });\n\nmain().catch((err) => {\n logger.error({ err: String(err) }, '[worker] fatal startup error');\n process.exit(1);\n});\n"],
|
|
5
|
+
"mappings": "AAUA,SAAS,oBAAoB,iCAAiC;AAC9D,SAAS,cAAc;AAEvB,eAAe,OAAO;AACpB,SAAO,KAAK,qDAAqD;AAEjE,MAAI,QAAQ,IAAI,sBAAsB,OAAO;AAI3C,UAAM,EAAE,eAAe,IAAI,MAAM,OAAO,gBAAgB;AACxD,mBAAe,EAAE,MAAM,CAAC,QAAQ;AAC9B,aAAO,MAAM,EAAE,KAAK,OAAO,GAAG,EAAE,GAAG,6BAA6B;AAChE,cAAQ,KAAK,CAAC;AAAA,IAChB,CAAC;AAAA,EACH;AAIA,qBAAmB;AAKnB,QAAM,WAAW,MAAM;AACrB,8BAA0B,EAAE,MAAM,CAAC,QAAQ;AACzC,aAAO,MAAM,EAAE,KAAK,OAAO,GAAG,EAAE,GAAG,sCAAsC;AAAA,IAC3E,CAAC;AAAA,EACH;AACA,WAAS;AACT,cAAY,UAAU,KAAK,KAAK,KAAK,GAAI;AAC3C;AAEA,QAAQ,GAAG,WAAW,MAAM;AAAE,SAAO,KAAK,oCAAoC;AAAG,UAAQ,KAAK,CAAC;AAAG,CAAC;AACnG,QAAQ,GAAG,UAAU,MAAM;AAAE,SAAO,KAAK,mCAAmC;AAAG,UAAQ,KAAK,CAAC;AAAG,CAAC;AAEjG,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,SAAO,MAAM,EAAE,KAAK,OAAO,GAAG,EAAE,GAAG,8BAA8B;AACjE,UAAQ,KAAK,CAAC;AAChB,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,51 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taodigital/crawler",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.2.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public",
|
|
7
|
+
"registry": "https://registry.npmjs.org/"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"types": "types/index.d.ts",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "node -e \"const {execSync}=require('child_process'),{readdirSync,statSync}=require('fs'),path=require('path');function walk(d){let f=[];for(const e of readdirSync(d)){const p=path.join(d,e);statSync(p).isDirectory()?f.push(...walk(p)):p.endsWith('.ts')&&!p.endsWith('.test.ts')&&!p.endsWith('.d.ts')&&f.push(p);}return f;}const files=walk('src').join(' ');execSync('esbuild '+files+' --format=esm --platform=node --target=node20 --outdir=dist --sourcemap',{stdio:'inherit'});\" && tsc -d --emitDeclarationOnly --outDir types",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"test": "tsx --test --test-force-exit src/**/*.test.ts"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@aws-sdk/client-sqs": "^3.1075.0",
|
|
19
|
+
"@browserbasehq/stagehand": "^3.6.0",
|
|
20
|
+
"@taodigital/agents": "*",
|
|
21
|
+
"@taodigital/app-brain": "*",
|
|
22
|
+
"@taodigital/core": "*",
|
|
23
|
+
"@taodigital/database": "*",
|
|
24
|
+
"@mozilla/readability": "^0.6.0",
|
|
25
|
+
"axe-core": "^4.12.1",
|
|
26
|
+
"camoufox": "^0.1.19",
|
|
27
|
+
"fast-xml-parser": "^5.10.1",
|
|
28
|
+
"minimatch": "^10.0.0",
|
|
29
|
+
"imapflow": "^1.4.3",
|
|
30
|
+
"lighthouse": "^13.4.0",
|
|
31
|
+
"linkedom": "^0.18.12",
|
|
32
|
+
"mailparser": "^3.9.12",
|
|
33
|
+
"pino": "^10.3.1",
|
|
34
|
+
"pino-pretty": "^13.1.3",
|
|
35
|
+
"pixelmatch": "^6.0.0",
|
|
36
|
+
"playwright": "^1.55.0",
|
|
37
|
+
"playwright-extra": "^4.3.6",
|
|
38
|
+
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
39
|
+
"rebrowser-patches": "^1.0.19",
|
|
40
|
+
"rebrowser-playwright-core": "^1.52.0",
|
|
41
|
+
"sharp": "^0.35.0",
|
|
42
|
+
"turndown": "^7.2.4",
|
|
43
|
+
"webdriverio": "^9.0.0",
|
|
44
|
+
"zod": "^3.25.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/axe-core": "^2.0.2",
|
|
48
|
+
"@types/mailparser": "^3.4.6",
|
|
49
|
+
"@types/turndown": "^5.0.5"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accessibility auditor — lightweight a11y checks using Playwright's aria snapshot
|
|
3
|
+
* and manual DOM queries. No axe-core dependency needed.
|
|
4
|
+
*
|
|
5
|
+
* Checks:
|
|
6
|
+
* 1. Images without alt text
|
|
7
|
+
* 2. Form inputs without associated labels
|
|
8
|
+
* 3. Buttons/links with no accessible name
|
|
9
|
+
* 4. Missing lang attribute on html element
|
|
10
|
+
* 5. Missing page title
|
|
11
|
+
* 6. Empty headings
|
|
12
|
+
* 7. Color contrast (limited — detects text with inline style color only)
|
|
13
|
+
* 8. Keyboard-unfocusable interactive elements (tabIndex=-1 on buttons)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { Page } from 'playwright';
|
|
17
|
+
|
|
18
|
+
export interface A11yViolation {
|
|
19
|
+
rule: string;
|
|
20
|
+
severity: 'critical' | 'serious' | 'moderate' | 'minor';
|
|
21
|
+
count: number;
|
|
22
|
+
examples: string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface A11yAuditResult {
|
|
26
|
+
url: string;
|
|
27
|
+
violations: A11yViolation[];
|
|
28
|
+
passCount: number;
|
|
29
|
+
score: number; // 0-100
|
|
30
|
+
auditedAt: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function queryAll(page: Page, selector: string): Promise<any[]> {
|
|
34
|
+
try {
|
|
35
|
+
return await page.$$eval(selector, els => els.map((el: any) => ({
|
|
36
|
+
outerHTML: el.outerHTML?.slice(0, 200) ?? '',
|
|
37
|
+
textContent: (el.textContent ?? '').trim().slice(0, 100),
|
|
38
|
+
tabIndex: el.tabIndex,
|
|
39
|
+
getAttribute: (a: string) => el.getAttribute(a),
|
|
40
|
+
})));
|
|
41
|
+
} catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function auditAccessibility(page: Page, url: string): Promise<A11yAuditResult> {
|
|
47
|
+
const violations: A11yViolation[] = [];
|
|
48
|
+
let passCount = 0;
|
|
49
|
+
const auditedAt = new Date().toISOString();
|
|
50
|
+
|
|
51
|
+
// 1. Images without alt
|
|
52
|
+
const imgs = await page.$$eval('img:not([alt])', els => els.map((e: any) => e.outerHTML?.slice(0, 120) ?? ''));
|
|
53
|
+
if (imgs.length > 0) violations.push({ rule: 'image-alt', severity: 'critical', count: imgs.length, examples: imgs.slice(0, 3) });
|
|
54
|
+
else passCount++;
|
|
55
|
+
|
|
56
|
+
// 2. Inputs without labels
|
|
57
|
+
const unlabeledInputs = await page.$$eval(
|
|
58
|
+
'input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([aria-label]):not([aria-labelledby]):not([id])',
|
|
59
|
+
els => els.map((e: any) => e.outerHTML?.slice(0, 120) ?? ''),
|
|
60
|
+
);
|
|
61
|
+
if (unlabeledInputs.length > 0) violations.push({ rule: 'label', severity: 'serious', count: unlabeledInputs.length, examples: unlabeledInputs.slice(0, 3) });
|
|
62
|
+
else passCount++;
|
|
63
|
+
|
|
64
|
+
// 3. Buttons with no text
|
|
65
|
+
const emptyButtons = await page.$$eval(
|
|
66
|
+
'button:not([aria-label]):not([aria-labelledby])',
|
|
67
|
+
els => els.filter((e: any) => !(e.textContent ?? '').trim()).map((e: any) => e.outerHTML?.slice(0, 120) ?? ''),
|
|
68
|
+
);
|
|
69
|
+
if (emptyButtons.length > 0) violations.push({ rule: 'button-name', severity: 'critical', count: emptyButtons.length, examples: emptyButtons.slice(0, 3) });
|
|
70
|
+
else passCount++;
|
|
71
|
+
|
|
72
|
+
// 4. Missing html lang
|
|
73
|
+
const htmlLang = await page.$eval('html', (el: any) => el.getAttribute('lang') ?? '').catch(() => '');
|
|
74
|
+
if (!htmlLang) violations.push({ rule: 'html-has-lang', severity: 'serious', count: 1, examples: ['<html> missing lang attribute'] });
|
|
75
|
+
else passCount++;
|
|
76
|
+
|
|
77
|
+
// 5. Missing page title
|
|
78
|
+
const title = await page.title().catch(() => '');
|
|
79
|
+
if (!title) violations.push({ rule: 'document-title', severity: 'serious', count: 1, examples: ['Page has no <title>'] });
|
|
80
|
+
else passCount++;
|
|
81
|
+
|
|
82
|
+
// 6. Empty headings
|
|
83
|
+
const emptyHeadings = await page.$$eval(
|
|
84
|
+
'h1,h2,h3,h4,h5,h6',
|
|
85
|
+
els => els.filter((e: any) => !(e.textContent ?? '').trim()).map((e: any) => e.tagName.toLowerCase()),
|
|
86
|
+
);
|
|
87
|
+
if (emptyHeadings.length > 0) violations.push({ rule: 'empty-heading', severity: 'moderate', count: emptyHeadings.length, examples: emptyHeadings.slice(0, 3) });
|
|
88
|
+
else passCount++;
|
|
89
|
+
|
|
90
|
+
// 7. Links with no accessible name
|
|
91
|
+
const emptyLinks = await page.$$eval(
|
|
92
|
+
'a[href]:not([aria-label]):not([aria-labelledby])',
|
|
93
|
+
els => els.filter((e: any) => !(e.textContent ?? '').trim() && !e.querySelector('img[alt]')).map((e: any) => e.outerHTML?.slice(0, 120) ?? ''),
|
|
94
|
+
);
|
|
95
|
+
if (emptyLinks.length > 0) violations.push({ rule: 'link-name', severity: 'serious', count: emptyLinks.length, examples: emptyLinks.slice(0, 3) });
|
|
96
|
+
else passCount++;
|
|
97
|
+
|
|
98
|
+
const totalChecks = passCount + violations.length;
|
|
99
|
+
const score = totalChecks > 0 ? Math.round((passCount / totalChecks) * 100) : 100;
|
|
100
|
+
|
|
101
|
+
return { url, violations, passCount, score, auditedAt };
|
|
102
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accessibility tree crawler — extract landmark, heading, and ARIA metadata from crawled pages.
|
|
3
|
+
*
|
|
4
|
+
* Captures: landmarks with interactive counts, heading hierarchy with violation detection,
|
|
5
|
+
* interactive elements missing accessible names, live regions, and skip-link presence.
|
|
6
|
+
*
|
|
7
|
+
* This data feeds ZeTa's accessibility test generator to surface WCAG 2.1 Level A/AA
|
|
8
|
+
* failures (missing names, heading skips, absent skip links, unlabeled live regions).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Page } from 'playwright';
|
|
12
|
+
|
|
13
|
+
export interface LandmarkInfo {
|
|
14
|
+
role: string;
|
|
15
|
+
label: string;
|
|
16
|
+
elementId: string;
|
|
17
|
+
interactiveCount: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface HeadingInfo {
|
|
21
|
+
level: number;
|
|
22
|
+
text: string;
|
|
23
|
+
elementId: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface MissingNameEl {
|
|
27
|
+
tagName: string;
|
|
28
|
+
role: string;
|
|
29
|
+
elementId: string;
|
|
30
|
+
htmlSnippet: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface LiveRegionInfo {
|
|
34
|
+
role: string;
|
|
35
|
+
ariaLive: string;
|
|
36
|
+
ariaAtomic: string;
|
|
37
|
+
currentText: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface AccessibilityTreeResult {
|
|
41
|
+
landmarkCount: number;
|
|
42
|
+
landmarks: LandmarkInfo[];
|
|
43
|
+
headings: HeadingInfo[];
|
|
44
|
+
headingHierarchyViolations: string[];
|
|
45
|
+
missingNameElements: MissingNameEl[];
|
|
46
|
+
missingNameCount: number;
|
|
47
|
+
liveRegions: LiveRegionInfo[];
|
|
48
|
+
totalInteractiveCount: number;
|
|
49
|
+
hasSkipLink: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function extractLandmarks(page: any): Promise<LandmarkInfo[]> {
|
|
53
|
+
try {
|
|
54
|
+
const raw = await page.evaluate(() => {
|
|
55
|
+
const LANDMARK_SELECTORS = [
|
|
56
|
+
{ role: 'banner', selector: 'header,[role="banner"]' },
|
|
57
|
+
{ role: 'navigation', selector: 'nav,[role="navigation"]' },
|
|
58
|
+
{ role: 'main', selector: 'main,[role="main"]' },
|
|
59
|
+
{ role: 'complementary', selector: 'aside,[role="complementary"]' },
|
|
60
|
+
{ role: 'contentinfo', selector: 'footer,[role="contentinfo"]' },
|
|
61
|
+
{ role: 'search', selector: '[role="search"]' },
|
|
62
|
+
{ role: 'form', selector: 'form[aria-label],[role="form"]' },
|
|
63
|
+
{ role: 'region', selector: '[role="region"][aria-label]' },
|
|
64
|
+
];
|
|
65
|
+
return LANDMARK_SELECTORS.flatMap(({ role, selector }) =>
|
|
66
|
+
[...document.querySelectorAll(selector)].slice(0, 10).map(el => ({
|
|
67
|
+
role,
|
|
68
|
+
label: el.getAttribute('aria-label') || el.getAttribute('aria-labelledby') || '',
|
|
69
|
+
elementId: el.id || '',
|
|
70
|
+
interactiveCount: el.querySelectorAll(
|
|
71
|
+
'button,a[href],input,select,textarea,[role="button"],[tabindex="0"]'
|
|
72
|
+
).length,
|
|
73
|
+
}))
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
return raw.slice(0, 50);
|
|
77
|
+
} catch {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function extractHeadings(page: any): Promise<HeadingInfo[]> {
|
|
83
|
+
try {
|
|
84
|
+
const raw = await page.evaluate(() => {
|
|
85
|
+
const headingEls = [...document.querySelectorAll('h1,h2,h3,h4,h5,h6,[role="heading"]')];
|
|
86
|
+
return headingEls
|
|
87
|
+
.map(el => ({
|
|
88
|
+
level:
|
|
89
|
+
parseInt(el.tagName.slice(1)) ||
|
|
90
|
+
parseInt(el.getAttribute('aria-level') || '0') ||
|
|
91
|
+
0,
|
|
92
|
+
text: el.textContent?.trim().slice(0, 100) || '',
|
|
93
|
+
elementId: el.id || '',
|
|
94
|
+
}))
|
|
95
|
+
.filter(h => h.level >= 1 && h.level <= 6);
|
|
96
|
+
});
|
|
97
|
+
return raw.slice(0, 100);
|
|
98
|
+
} catch {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function detectHeadingViolations(headings: HeadingInfo[]): string[] {
|
|
104
|
+
const violations: string[] = [];
|
|
105
|
+
if (headings.length === 0) return violations;
|
|
106
|
+
|
|
107
|
+
const h1s = headings.filter(h => h.level === 1);
|
|
108
|
+
if (h1s.length === 0) {
|
|
109
|
+
violations.push('Missing h1 landmark');
|
|
110
|
+
} else if (h1s.length > 1) {
|
|
111
|
+
violations.push('Multiple h1 elements found');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let prevLevel = 0;
|
|
115
|
+
for (const heading of headings) {
|
|
116
|
+
if (prevLevel > 0 && heading.level > prevLevel + 1) {
|
|
117
|
+
violations.push(
|
|
118
|
+
`Heading level skip: h${prevLevel} to h${heading.level}`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
prevLevel = heading.level;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return violations;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function findMissingNames(page: any): Promise<MissingNameEl[]> {
|
|
128
|
+
try {
|
|
129
|
+
return await page.evaluate(() => {
|
|
130
|
+
const INTERACTIVE_SELECTOR =
|
|
131
|
+
'button,a[href],input:not([type="hidden"]),select,textarea,' +
|
|
132
|
+
'[role="button"],[role="link"],[role="checkbox"],[role="radio"],' +
|
|
133
|
+
'[role="switch"],[role="menuitem"],[role="tab"]';
|
|
134
|
+
return [...document.querySelectorAll(INTERACTIVE_SELECTOR)]
|
|
135
|
+
.filter(el => {
|
|
136
|
+
const labelledById = el.getAttribute('aria-labelledby') || '';
|
|
137
|
+
const name =
|
|
138
|
+
(el.getAttribute('aria-label') || '').trim() ||
|
|
139
|
+
(labelledById
|
|
140
|
+
? document.getElementById(labelledById)?.textContent?.trim() ?? ''
|
|
141
|
+
: '') ||
|
|
142
|
+
(el.textContent || '').trim() ||
|
|
143
|
+
((el as HTMLInputElement).placeholder || '').trim() ||
|
|
144
|
+
((el as HTMLElement).title || '').trim() ||
|
|
145
|
+
((el as HTMLImageElement).alt || '').trim();
|
|
146
|
+
return !name || name.length === 0;
|
|
147
|
+
})
|
|
148
|
+
.slice(0, 30)
|
|
149
|
+
.map(el => ({
|
|
150
|
+
tagName: el.tagName.toLowerCase(),
|
|
151
|
+
role: el.getAttribute('role') || '',
|
|
152
|
+
elementId: el.id || '',
|
|
153
|
+
htmlSnippet: el.outerHTML.slice(0, 120),
|
|
154
|
+
}));
|
|
155
|
+
});
|
|
156
|
+
} catch {
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function extractLiveRegions(page: any): Promise<LiveRegionInfo[]> {
|
|
162
|
+
try {
|
|
163
|
+
return await page.evaluate(() => {
|
|
164
|
+
const els = [
|
|
165
|
+
...document.querySelectorAll(
|
|
166
|
+
'[aria-live],[role="alert"],[role="status"],[role="log"]'
|
|
167
|
+
),
|
|
168
|
+
];
|
|
169
|
+
return els.slice(0, 20).map(el => ({
|
|
170
|
+
role: el.getAttribute('role') || '',
|
|
171
|
+
ariaLive: el.getAttribute('aria-live') || '',
|
|
172
|
+
ariaAtomic: el.getAttribute('aria-atomic') || '',
|
|
173
|
+
currentText: (el.textContent || '').trim().slice(0, 200),
|
|
174
|
+
}));
|
|
175
|
+
});
|
|
176
|
+
} catch {
|
|
177
|
+
return [];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function checkSkipLink(page: any): Promise<boolean> {
|
|
182
|
+
try {
|
|
183
|
+
return await page.evaluate(() => {
|
|
184
|
+
const firstFocusable = document.querySelector('a[href^="#"],a:first-of-type');
|
|
185
|
+
return !!(
|
|
186
|
+
firstFocusable &&
|
|
187
|
+
/skip/i.test(
|
|
188
|
+
(firstFocusable.textContent || '') + (firstFocusable.getAttribute('href') || '')
|
|
189
|
+
)
|
|
190
|
+
);
|
|
191
|
+
});
|
|
192
|
+
} catch {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export async function crawlAccessibilityTree(page: any): Promise<AccessibilityTreeResult> {
|
|
198
|
+
const [
|
|
199
|
+
landmarksResult,
|
|
200
|
+
headingsResult,
|
|
201
|
+
missingNamesResult,
|
|
202
|
+
liveRegionsResult,
|
|
203
|
+
skipLinkResult,
|
|
204
|
+
interactiveCountResult,
|
|
205
|
+
] = await Promise.allSettled([
|
|
206
|
+
extractLandmarks(page),
|
|
207
|
+
extractHeadings(page),
|
|
208
|
+
findMissingNames(page),
|
|
209
|
+
extractLiveRegions(page),
|
|
210
|
+
checkSkipLink(page),
|
|
211
|
+
page.evaluate(() => {
|
|
212
|
+
const INTERACTIVE_SELECTOR =
|
|
213
|
+
'button,a[href],input:not([type="hidden"]),select,textarea,' +
|
|
214
|
+
'[role="button"],[role="link"],[role="checkbox"],[role="radio"],' +
|
|
215
|
+
'[role="switch"],[role="menuitem"],[role="tab"]';
|
|
216
|
+
return document.querySelectorAll(INTERACTIVE_SELECTOR).length;
|
|
217
|
+
}).catch(() => 0),
|
|
218
|
+
]);
|
|
219
|
+
|
|
220
|
+
const landmarks =
|
|
221
|
+
landmarksResult.status === 'fulfilled' ? landmarksResult.value : [];
|
|
222
|
+
const headings =
|
|
223
|
+
headingsResult.status === 'fulfilled' ? headingsResult.value : [];
|
|
224
|
+
const missingNameElements =
|
|
225
|
+
missingNamesResult.status === 'fulfilled' ? missingNamesResult.value : [];
|
|
226
|
+
const liveRegions =
|
|
227
|
+
liveRegionsResult.status === 'fulfilled' ? liveRegionsResult.value : [];
|
|
228
|
+
const hasSkipLink =
|
|
229
|
+
skipLinkResult.status === 'fulfilled' ? skipLinkResult.value : false;
|
|
230
|
+
const totalInteractiveCount =
|
|
231
|
+
interactiveCountResult.status === 'fulfilled' ? interactiveCountResult.value : 0;
|
|
232
|
+
|
|
233
|
+
const headingHierarchyViolations = detectHeadingViolations(headings);
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
landmarkCount: landmarks.length,
|
|
237
|
+
landmarks,
|
|
238
|
+
headings,
|
|
239
|
+
headingHierarchyViolations,
|
|
240
|
+
missingNameElements,
|
|
241
|
+
missingNameCount: missingNameElements.length,
|
|
242
|
+
liveRegions,
|
|
243
|
+
totalInteractiveCount,
|
|
244
|
+
hasSkipLink,
|
|
245
|
+
};
|
|
246
|
+
}
|