@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.
- 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
package/Dockerfile
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# ZeTa-AI Crawler — includes Playwright + Chromium
|
|
2
|
+
# Playwright needs a real Linux environment with system deps.
|
|
3
|
+
# This service CANNOT run on Vercel serverless — use Railway/Render.
|
|
4
|
+
# IMPORTANT: ECS Fargate task definition must set sharedMemorySize: 2048 (MB) for Chromium stability
|
|
5
|
+
FROM mcr.microsoft.com/playwright:v1.55.0-jammy AS runner
|
|
6
|
+
WORKDIR /app
|
|
7
|
+
ENV NODE_ENV=production
|
|
8
|
+
# Install browsers to a fixed path — base image ships browsers here and
|
|
9
|
+
# we override after npm ci to match the exact installed playwright revision.
|
|
10
|
+
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
|
|
11
|
+
|
|
12
|
+
# Install Node.js 20 (Playwright base image ships with 18)
|
|
13
|
+
RUN apt-get update && apt-get install -y curl build-essential python3 && \
|
|
14
|
+
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
|
|
15
|
+
apt-get install -y nodejs && \
|
|
16
|
+
apt-get clean && rm -rf /var/lib/apt/lists/*
|
|
17
|
+
|
|
18
|
+
# Workspace manifests (layer cache)
|
|
19
|
+
# Copy all workspace package.json files so npm ci can resolve the full lockfile.
|
|
20
|
+
# Packages not used by the crawler (api, web, etc.) are stubs; their source is not copied later.
|
|
21
|
+
COPY package.json package-lock.json ./
|
|
22
|
+
COPY packages/agent-cli/package.json packages/agent-cli/
|
|
23
|
+
COPY packages/agents/package.json packages/agents/
|
|
24
|
+
COPY packages/api/package.json packages/api/
|
|
25
|
+
COPY packages/app-brain/package.json packages/app-brain/
|
|
26
|
+
COPY packages/chrome-extension/package.json packages/chrome-extension/
|
|
27
|
+
COPY packages/connectors/package.json packages/connectors/
|
|
28
|
+
COPY packages/core/package.json packages/core/
|
|
29
|
+
COPY packages/crawler/package.json packages/crawler/
|
|
30
|
+
COPY packages/database/package.json packages/database/
|
|
31
|
+
COPY packages/github-action/package.json packages/github-action/
|
|
32
|
+
COPY packages/reranker/package.json packages/reranker/
|
|
33
|
+
COPY packages/sdk/package.json packages/sdk/
|
|
34
|
+
COPY packages/session-receiver/package.json packages/session-receiver/
|
|
35
|
+
COPY packages/vscode-extension/package.json packages/vscode-extension/
|
|
36
|
+
COPY packages/web/package.json packages/web/
|
|
37
|
+
RUN npm ci --include=dev
|
|
38
|
+
|
|
39
|
+
# Patch Stagehand's act() schema to add `additionalProperties: false` on the
|
|
40
|
+
# inner anyOf[0] object. OpenAI strict mode (v1/responses) requires it on every
|
|
41
|
+
# nested object; Stagehand ≤3.6 omits it, causing a 400 "invalid_json_schema".
|
|
42
|
+
RUN node -e "const fs=require('fs');['packages/crawler/node_modules/@browserbasehq/stagehand/dist/cjs/lib/inference.js','packages/crawler/node_modules/@browserbasehq/stagehand/dist/esm/lib/inference.js'].forEach(f=>{if(!fs.existsSync(f)){console.log('skip',f);return;}let c=fs.readFileSync(f,'utf8');if(c.includes('.strict()')){console.log('already patched',f);return;}c=c.replace(/\\.nullable\\(\\)\\n(\\s+)\\.describe\\(\"The element to act on/g,'\.strict()\n\$1.nullable()\n\$1.describe(\"The element to act on');fs.writeFileSync(f,c);console.log('patched',f);});"
|
|
43
|
+
|
|
44
|
+
# Re-install chromium after npm ci so the browser revision matches the
|
|
45
|
+
# exact playwright version resolved by the lockfile (not the base image's
|
|
46
|
+
# bundled version, which may differ if the lockfile was updated).
|
|
47
|
+
RUN npx playwright install chromium
|
|
48
|
+
|
|
49
|
+
# Source
|
|
50
|
+
COPY tsconfig.base.json ./
|
|
51
|
+
COPY packages/database packages/database
|
|
52
|
+
COPY packages/reranker packages/reranker
|
|
53
|
+
COPY packages/core packages/core
|
|
54
|
+
COPY packages/connectors packages/connectors
|
|
55
|
+
COPY packages/app-brain packages/app-brain
|
|
56
|
+
COPY packages/agents packages/agents
|
|
57
|
+
COPY packages/crawler packages/crawler
|
|
58
|
+
|
|
59
|
+
# Build order: database → reranker → core → connectors → app-brain → agents → crawler
|
|
60
|
+
RUN npx prisma generate --schema packages/database/prisma/schema.prisma && \
|
|
61
|
+
npm run -w @detiq/database build && \
|
|
62
|
+
npm run -w @detiq/reranker build && \
|
|
63
|
+
npm run -w @detiq/core build && \
|
|
64
|
+
npm run -w @detiq/connectors build && \
|
|
65
|
+
npm run -w @detiq/app-brain build && \
|
|
66
|
+
npm run -w @detiq/agents build && \
|
|
67
|
+
npm run -w @detiq/crawler build
|
|
68
|
+
|
|
69
|
+
# Screenshot cache dir
|
|
70
|
+
RUN mkdir -p /app/.screenshots-cache
|
|
71
|
+
|
|
72
|
+
RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser
|
|
73
|
+
RUN chown -R appuser:appgroup /app
|
|
74
|
+
USER appuser
|
|
75
|
+
|
|
76
|
+
EXPOSE 4001
|
|
77
|
+
# index.js is a side-effect-free library barrel (also imported by @detiq/api) — it holds
|
|
78
|
+
# no listener/timer, so running it directly starts the process, finishes its imports,
|
|
79
|
+
# and exits immediately with nothing ever consuming the job queue. worker.js is the
|
|
80
|
+
# actual long-running entrypoint: it starts the durable job-poll loop (and the SQS
|
|
81
|
+
# consumer when JOB_QUEUE_BACKEND=sqs) and keeps the process alive.
|
|
82
|
+
CMD ["node", "packages/crawler/dist/worker.js"]
|
package/README.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @detiq/crawler — The Explorer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Crawls an app, **gets past the login** (the star of Phase 1), discovers
|
|
4
|
+
screens, captures screenshots, and reads each page's elements into the App
|
|
5
|
+
Brain.
|
|
6
|
+
|
|
7
|
+
- `auth.ts` — login handling. **Invest here**; it's the competitive edge.
|
|
8
|
+
- `screen-reader.ts` — reads pages as a cheap structured outline (accessibility
|
|
9
|
+
tree), not pixels. Vision is a later fallback.
|
|
10
|
+
- `crawler.ts` — the discovery loop. Swap in an AI navigation library
|
|
11
|
+
(Stagehand / Browser Use) to explore more intelligently.
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
import type { Page } from 'playwright';
|
|
16
|
+
export interface A11yViolation {
|
|
17
|
+
rule: string;
|
|
18
|
+
severity: 'critical' | 'serious' | 'moderate' | 'minor';
|
|
19
|
+
count: number;
|
|
20
|
+
examples: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface A11yAuditResult {
|
|
23
|
+
url: string;
|
|
24
|
+
violations: A11yViolation[];
|
|
25
|
+
passCount: number;
|
|
26
|
+
score: number;
|
|
27
|
+
auditedAt: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function auditAccessibility(page: Page, url: string): Promise<A11yAuditResult>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
async function queryAll(page, selector) {
|
|
2
|
+
try {
|
|
3
|
+
return await page.$$eval(selector, (els) => els.map((el) => ({
|
|
4
|
+
outerHTML: el.outerHTML?.slice(0, 200) ?? "",
|
|
5
|
+
textContent: (el.textContent ?? "").trim().slice(0, 100),
|
|
6
|
+
tabIndex: el.tabIndex,
|
|
7
|
+
getAttribute: (a) => el.getAttribute(a)
|
|
8
|
+
})));
|
|
9
|
+
} catch {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
async function auditAccessibility(page, url) {
|
|
14
|
+
const violations = [];
|
|
15
|
+
let passCount = 0;
|
|
16
|
+
const auditedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
17
|
+
const imgs = await page.$$eval("img:not([alt])", (els) => els.map((e) => e.outerHTML?.slice(0, 120) ?? ""));
|
|
18
|
+
if (imgs.length > 0) violations.push({ rule: "image-alt", severity: "critical", count: imgs.length, examples: imgs.slice(0, 3) });
|
|
19
|
+
else passCount++;
|
|
20
|
+
const unlabeledInputs = await page.$$eval(
|
|
21
|
+
'input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([aria-label]):not([aria-labelledby]):not([id])',
|
|
22
|
+
(els) => els.map((e) => e.outerHTML?.slice(0, 120) ?? "")
|
|
23
|
+
);
|
|
24
|
+
if (unlabeledInputs.length > 0) violations.push({ rule: "label", severity: "serious", count: unlabeledInputs.length, examples: unlabeledInputs.slice(0, 3) });
|
|
25
|
+
else passCount++;
|
|
26
|
+
const emptyButtons = await page.$$eval(
|
|
27
|
+
"button:not([aria-label]):not([aria-labelledby])",
|
|
28
|
+
(els) => els.filter((e) => !(e.textContent ?? "").trim()).map((e) => e.outerHTML?.slice(0, 120) ?? "")
|
|
29
|
+
);
|
|
30
|
+
if (emptyButtons.length > 0) violations.push({ rule: "button-name", severity: "critical", count: emptyButtons.length, examples: emptyButtons.slice(0, 3) });
|
|
31
|
+
else passCount++;
|
|
32
|
+
const htmlLang = await page.$eval("html", (el) => el.getAttribute("lang") ?? "").catch(() => "");
|
|
33
|
+
if (!htmlLang) violations.push({ rule: "html-has-lang", severity: "serious", count: 1, examples: ["<html> missing lang attribute"] });
|
|
34
|
+
else passCount++;
|
|
35
|
+
const title = await page.title().catch(() => "");
|
|
36
|
+
if (!title) violations.push({ rule: "document-title", severity: "serious", count: 1, examples: ["Page has no <title>"] });
|
|
37
|
+
else passCount++;
|
|
38
|
+
const emptyHeadings = await page.$$eval(
|
|
39
|
+
"h1,h2,h3,h4,h5,h6",
|
|
40
|
+
(els) => els.filter((e) => !(e.textContent ?? "").trim()).map((e) => e.tagName.toLowerCase())
|
|
41
|
+
);
|
|
42
|
+
if (emptyHeadings.length > 0) violations.push({ rule: "empty-heading", severity: "moderate", count: emptyHeadings.length, examples: emptyHeadings.slice(0, 3) });
|
|
43
|
+
else passCount++;
|
|
44
|
+
const emptyLinks = await page.$$eval(
|
|
45
|
+
"a[href]:not([aria-label]):not([aria-labelledby])",
|
|
46
|
+
(els) => els.filter((e) => !(e.textContent ?? "").trim() && !e.querySelector("img[alt]")).map((e) => e.outerHTML?.slice(0, 120) ?? "")
|
|
47
|
+
);
|
|
48
|
+
if (emptyLinks.length > 0) violations.push({ rule: "link-name", severity: "serious", count: emptyLinks.length, examples: emptyLinks.slice(0, 3) });
|
|
49
|
+
else passCount++;
|
|
50
|
+
const totalChecks = passCount + violations.length;
|
|
51
|
+
const score = totalChecks > 0 ? Math.round(passCount / totalChecks * 100) : 100;
|
|
52
|
+
return { url, violations, passCount, score, auditedAt };
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
auditAccessibility
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=accessibility-auditor.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/accessibility-auditor.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Accessibility auditor \u2014 lightweight a11y checks using Playwright's aria snapshot\n * and manual DOM queries. No axe-core dependency needed.\n *\n * Checks:\n * 1. Images without alt text\n * 2. Form inputs without associated labels\n * 3. Buttons/links with no accessible name\n * 4. Missing lang attribute on html element\n * 5. Missing page title\n * 6. Empty headings\n * 7. Color contrast (limited \u2014 detects text with inline style color only)\n * 8. Keyboard-unfocusable interactive elements (tabIndex=-1 on buttons)\n */\n\nimport type { Page } from 'playwright';\n\nexport interface A11yViolation {\n rule: string;\n severity: 'critical' | 'serious' | 'moderate' | 'minor';\n count: number;\n examples: string[];\n}\n\nexport interface A11yAuditResult {\n url: string;\n violations: A11yViolation[];\n passCount: number;\n score: number; // 0-100\n auditedAt: string;\n}\n\nasync function queryAll(page: Page, selector: string): Promise<any[]> {\n try {\n return await page.$$eval(selector, els => els.map((el: any) => ({\n outerHTML: el.outerHTML?.slice(0, 200) ?? '',\n textContent: (el.textContent ?? '').trim().slice(0, 100),\n tabIndex: el.tabIndex,\n getAttribute: (a: string) => el.getAttribute(a),\n })));\n } catch {\n return [];\n }\n}\n\nexport async function auditAccessibility(page: Page, url: string): Promise<A11yAuditResult> {\n const violations: A11yViolation[] = [];\n let passCount = 0;\n const auditedAt = new Date().toISOString();\n\n // 1. Images without alt\n const imgs = await page.$$eval('img:not([alt])', els => els.map((e: any) => e.outerHTML?.slice(0, 120) ?? ''));\n if (imgs.length > 0) violations.push({ rule: 'image-alt', severity: 'critical', count: imgs.length, examples: imgs.slice(0, 3) });\n else passCount++;\n\n // 2. Inputs without labels\n const unlabeledInputs = await page.$$eval(\n 'input:not([type=\"hidden\"]):not([type=\"submit\"]):not([type=\"button\"]):not([aria-label]):not([aria-labelledby]):not([id])',\n els => els.map((e: any) => e.outerHTML?.slice(0, 120) ?? ''),\n );\n if (unlabeledInputs.length > 0) violations.push({ rule: 'label', severity: 'serious', count: unlabeledInputs.length, examples: unlabeledInputs.slice(0, 3) });\n else passCount++;\n\n // 3. Buttons with no text\n const emptyButtons = await page.$$eval(\n 'button:not([aria-label]):not([aria-labelledby])',\n els => els.filter((e: any) => !(e.textContent ?? '').trim()).map((e: any) => e.outerHTML?.slice(0, 120) ?? ''),\n );\n if (emptyButtons.length > 0) violations.push({ rule: 'button-name', severity: 'critical', count: emptyButtons.length, examples: emptyButtons.slice(0, 3) });\n else passCount++;\n\n // 4. Missing html lang\n const htmlLang = await page.$eval('html', (el: any) => el.getAttribute('lang') ?? '').catch(() => '');\n if (!htmlLang) violations.push({ rule: 'html-has-lang', severity: 'serious', count: 1, examples: ['<html> missing lang attribute'] });\n else passCount++;\n\n // 5. Missing page title\n const title = await page.title().catch(() => '');\n if (!title) violations.push({ rule: 'document-title', severity: 'serious', count: 1, examples: ['Page has no <title>'] });\n else passCount++;\n\n // 6. Empty headings\n const emptyHeadings = await page.$$eval(\n 'h1,h2,h3,h4,h5,h6',\n els => els.filter((e: any) => !(e.textContent ?? '').trim()).map((e: any) => e.tagName.toLowerCase()),\n );\n if (emptyHeadings.length > 0) violations.push({ rule: 'empty-heading', severity: 'moderate', count: emptyHeadings.length, examples: emptyHeadings.slice(0, 3) });\n else passCount++;\n\n // 7. Links with no accessible name\n const emptyLinks = await page.$$eval(\n 'a[href]:not([aria-label]):not([aria-labelledby])',\n els => els.filter((e: any) => !(e.textContent ?? '').trim() && !e.querySelector('img[alt]')).map((e: any) => e.outerHTML?.slice(0, 120) ?? ''),\n );\n if (emptyLinks.length > 0) violations.push({ rule: 'link-name', severity: 'serious', count: emptyLinks.length, examples: emptyLinks.slice(0, 3) });\n else passCount++;\n\n const totalChecks = passCount + violations.length;\n const score = totalChecks > 0 ? Math.round((passCount / totalChecks) * 100) : 100;\n\n return { url, violations, passCount, score, auditedAt };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
export interface LandmarkInfo {
|
|
11
|
+
role: string;
|
|
12
|
+
label: string;
|
|
13
|
+
elementId: string;
|
|
14
|
+
interactiveCount: number;
|
|
15
|
+
}
|
|
16
|
+
export interface HeadingInfo {
|
|
17
|
+
level: number;
|
|
18
|
+
text: string;
|
|
19
|
+
elementId: string;
|
|
20
|
+
}
|
|
21
|
+
export interface MissingNameEl {
|
|
22
|
+
tagName: string;
|
|
23
|
+
role: string;
|
|
24
|
+
elementId: string;
|
|
25
|
+
htmlSnippet: string;
|
|
26
|
+
}
|
|
27
|
+
export interface LiveRegionInfo {
|
|
28
|
+
role: string;
|
|
29
|
+
ariaLive: string;
|
|
30
|
+
ariaAtomic: string;
|
|
31
|
+
currentText: string;
|
|
32
|
+
}
|
|
33
|
+
export interface AccessibilityTreeResult {
|
|
34
|
+
landmarkCount: number;
|
|
35
|
+
landmarks: LandmarkInfo[];
|
|
36
|
+
headings: HeadingInfo[];
|
|
37
|
+
headingHierarchyViolations: string[];
|
|
38
|
+
missingNameElements: MissingNameEl[];
|
|
39
|
+
missingNameCount: number;
|
|
40
|
+
liveRegions: LiveRegionInfo[];
|
|
41
|
+
totalInteractiveCount: number;
|
|
42
|
+
hasSkipLink: boolean;
|
|
43
|
+
}
|
|
44
|
+
export declare function crawlAccessibilityTree(page: any): Promise<AccessibilityTreeResult>;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
async function extractLandmarks(page) {
|
|
2
|
+
try {
|
|
3
|
+
const raw = await page.evaluate(() => {
|
|
4
|
+
const LANDMARK_SELECTORS = [
|
|
5
|
+
{ role: "banner", selector: 'header,[role="banner"]' },
|
|
6
|
+
{ role: "navigation", selector: 'nav,[role="navigation"]' },
|
|
7
|
+
{ role: "main", selector: 'main,[role="main"]' },
|
|
8
|
+
{ role: "complementary", selector: 'aside,[role="complementary"]' },
|
|
9
|
+
{ role: "contentinfo", selector: 'footer,[role="contentinfo"]' },
|
|
10
|
+
{ role: "search", selector: '[role="search"]' },
|
|
11
|
+
{ role: "form", selector: 'form[aria-label],[role="form"]' },
|
|
12
|
+
{ role: "region", selector: '[role="region"][aria-label]' }
|
|
13
|
+
];
|
|
14
|
+
return LANDMARK_SELECTORS.flatMap(
|
|
15
|
+
({ role, selector }) => [...document.querySelectorAll(selector)].slice(0, 10).map((el) => ({
|
|
16
|
+
role,
|
|
17
|
+
label: el.getAttribute("aria-label") || el.getAttribute("aria-labelledby") || "",
|
|
18
|
+
elementId: el.id || "",
|
|
19
|
+
interactiveCount: el.querySelectorAll(
|
|
20
|
+
'button,a[href],input,select,textarea,[role="button"],[tabindex="0"]'
|
|
21
|
+
).length
|
|
22
|
+
}))
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
return raw.slice(0, 50);
|
|
26
|
+
} catch {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function extractHeadings(page) {
|
|
31
|
+
try {
|
|
32
|
+
const raw = await page.evaluate(() => {
|
|
33
|
+
const headingEls = [...document.querySelectorAll('h1,h2,h3,h4,h5,h6,[role="heading"]')];
|
|
34
|
+
return headingEls.map((el) => ({
|
|
35
|
+
level: parseInt(el.tagName.slice(1)) || parseInt(el.getAttribute("aria-level") || "0") || 0,
|
|
36
|
+
text: el.textContent?.trim().slice(0, 100) || "",
|
|
37
|
+
elementId: el.id || ""
|
|
38
|
+
})).filter((h) => h.level >= 1 && h.level <= 6);
|
|
39
|
+
});
|
|
40
|
+
return raw.slice(0, 100);
|
|
41
|
+
} catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function detectHeadingViolations(headings) {
|
|
46
|
+
const violations = [];
|
|
47
|
+
if (headings.length === 0) return violations;
|
|
48
|
+
const h1s = headings.filter((h) => h.level === 1);
|
|
49
|
+
if (h1s.length === 0) {
|
|
50
|
+
violations.push("Missing h1 landmark");
|
|
51
|
+
} else if (h1s.length > 1) {
|
|
52
|
+
violations.push("Multiple h1 elements found");
|
|
53
|
+
}
|
|
54
|
+
let prevLevel = 0;
|
|
55
|
+
for (const heading of headings) {
|
|
56
|
+
if (prevLevel > 0 && heading.level > prevLevel + 1) {
|
|
57
|
+
violations.push(
|
|
58
|
+
`Heading level skip: h${prevLevel} to h${heading.level}`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
prevLevel = heading.level;
|
|
62
|
+
}
|
|
63
|
+
return violations;
|
|
64
|
+
}
|
|
65
|
+
async function findMissingNames(page) {
|
|
66
|
+
try {
|
|
67
|
+
return await page.evaluate(() => {
|
|
68
|
+
const INTERACTIVE_SELECTOR = 'button,a[href],input:not([type="hidden"]),select,textarea,[role="button"],[role="link"],[role="checkbox"],[role="radio"],[role="switch"],[role="menuitem"],[role="tab"]';
|
|
69
|
+
return [...document.querySelectorAll(INTERACTIVE_SELECTOR)].filter((el) => {
|
|
70
|
+
const labelledById = el.getAttribute("aria-labelledby") || "";
|
|
71
|
+
const name = (el.getAttribute("aria-label") || "").trim() || (labelledById ? document.getElementById(labelledById)?.textContent?.trim() ?? "" : "") || (el.textContent || "").trim() || (el.placeholder || "").trim() || (el.title || "").trim() || (el.alt || "").trim();
|
|
72
|
+
return !name || name.length === 0;
|
|
73
|
+
}).slice(0, 30).map((el) => ({
|
|
74
|
+
tagName: el.tagName.toLowerCase(),
|
|
75
|
+
role: el.getAttribute("role") || "",
|
|
76
|
+
elementId: el.id || "",
|
|
77
|
+
htmlSnippet: el.outerHTML.slice(0, 120)
|
|
78
|
+
}));
|
|
79
|
+
});
|
|
80
|
+
} catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function extractLiveRegions(page) {
|
|
85
|
+
try {
|
|
86
|
+
return await page.evaluate(() => {
|
|
87
|
+
const els = [
|
|
88
|
+
...document.querySelectorAll(
|
|
89
|
+
'[aria-live],[role="alert"],[role="status"],[role="log"]'
|
|
90
|
+
)
|
|
91
|
+
];
|
|
92
|
+
return els.slice(0, 20).map((el) => ({
|
|
93
|
+
role: el.getAttribute("role") || "",
|
|
94
|
+
ariaLive: el.getAttribute("aria-live") || "",
|
|
95
|
+
ariaAtomic: el.getAttribute("aria-atomic") || "",
|
|
96
|
+
currentText: (el.textContent || "").trim().slice(0, 200)
|
|
97
|
+
}));
|
|
98
|
+
});
|
|
99
|
+
} catch {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async function checkSkipLink(page) {
|
|
104
|
+
try {
|
|
105
|
+
return await page.evaluate(() => {
|
|
106
|
+
const firstFocusable = document.querySelector('a[href^="#"],a:first-of-type');
|
|
107
|
+
return !!(firstFocusable && /skip/i.test(
|
|
108
|
+
(firstFocusable.textContent || "") + (firstFocusable.getAttribute("href") || "")
|
|
109
|
+
));
|
|
110
|
+
});
|
|
111
|
+
} catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async function crawlAccessibilityTree(page) {
|
|
116
|
+
const [
|
|
117
|
+
landmarksResult,
|
|
118
|
+
headingsResult,
|
|
119
|
+
missingNamesResult,
|
|
120
|
+
liveRegionsResult,
|
|
121
|
+
skipLinkResult,
|
|
122
|
+
interactiveCountResult
|
|
123
|
+
] = await Promise.allSettled([
|
|
124
|
+
extractLandmarks(page),
|
|
125
|
+
extractHeadings(page),
|
|
126
|
+
findMissingNames(page),
|
|
127
|
+
extractLiveRegions(page),
|
|
128
|
+
checkSkipLink(page),
|
|
129
|
+
page.evaluate(() => {
|
|
130
|
+
const INTERACTIVE_SELECTOR = 'button,a[href],input:not([type="hidden"]),select,textarea,[role="button"],[role="link"],[role="checkbox"],[role="radio"],[role="switch"],[role="menuitem"],[role="tab"]';
|
|
131
|
+
return document.querySelectorAll(INTERACTIVE_SELECTOR).length;
|
|
132
|
+
}).catch(() => 0)
|
|
133
|
+
]);
|
|
134
|
+
const landmarks = landmarksResult.status === "fulfilled" ? landmarksResult.value : [];
|
|
135
|
+
const headings = headingsResult.status === "fulfilled" ? headingsResult.value : [];
|
|
136
|
+
const missingNameElements = missingNamesResult.status === "fulfilled" ? missingNamesResult.value : [];
|
|
137
|
+
const liveRegions = liveRegionsResult.status === "fulfilled" ? liveRegionsResult.value : [];
|
|
138
|
+
const hasSkipLink = skipLinkResult.status === "fulfilled" ? skipLinkResult.value : false;
|
|
139
|
+
const totalInteractiveCount = interactiveCountResult.status === "fulfilled" ? interactiveCountResult.value : 0;
|
|
140
|
+
const headingHierarchyViolations = detectHeadingViolations(headings);
|
|
141
|
+
return {
|
|
142
|
+
landmarkCount: landmarks.length,
|
|
143
|
+
landmarks,
|
|
144
|
+
headings,
|
|
145
|
+
headingHierarchyViolations,
|
|
146
|
+
missingNameElements,
|
|
147
|
+
missingNameCount: missingNameElements.length,
|
|
148
|
+
liveRegions,
|
|
149
|
+
totalInteractiveCount,
|
|
150
|
+
hasSkipLink
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
export {
|
|
154
|
+
crawlAccessibilityTree
|
|
155
|
+
};
|
|
156
|
+
//# sourceMappingURL=accessibility-tree-crawler.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/accessibility-tree-crawler.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Accessibility tree crawler \u2014 extract landmark, heading, and ARIA metadata from crawled pages.\n *\n * Captures: landmarks with interactive counts, heading hierarchy with violation detection,\n * interactive elements missing accessible names, live regions, and skip-link presence.\n *\n * This data feeds ZeTa's accessibility test generator to surface WCAG 2.1 Level A/AA\n * failures (missing names, heading skips, absent skip links, unlabeled live regions).\n */\n\nimport type { Page } from 'playwright';\n\nexport interface LandmarkInfo {\n role: string;\n label: string;\n elementId: string;\n interactiveCount: number;\n}\n\nexport interface HeadingInfo {\n level: number;\n text: string;\n elementId: string;\n}\n\nexport interface MissingNameEl {\n tagName: string;\n role: string;\n elementId: string;\n htmlSnippet: string;\n}\n\nexport interface LiveRegionInfo {\n role: string;\n ariaLive: string;\n ariaAtomic: string;\n currentText: string;\n}\n\nexport interface AccessibilityTreeResult {\n landmarkCount: number;\n landmarks: LandmarkInfo[];\n headings: HeadingInfo[];\n headingHierarchyViolations: string[];\n missingNameElements: MissingNameEl[];\n missingNameCount: number;\n liveRegions: LiveRegionInfo[];\n totalInteractiveCount: number;\n hasSkipLink: boolean;\n}\n\nasync function extractLandmarks(page: any): Promise<LandmarkInfo[]> {\n try {\n const raw = await page.evaluate(() => {\n const LANDMARK_SELECTORS = [\n { role: 'banner', selector: 'header,[role=\"banner\"]' },\n { role: 'navigation', selector: 'nav,[role=\"navigation\"]' },\n { role: 'main', selector: 'main,[role=\"main\"]' },\n { role: 'complementary', selector: 'aside,[role=\"complementary\"]' },\n { role: 'contentinfo', selector: 'footer,[role=\"contentinfo\"]' },\n { role: 'search', selector: '[role=\"search\"]' },\n { role: 'form', selector: 'form[aria-label],[role=\"form\"]' },\n { role: 'region', selector: '[role=\"region\"][aria-label]' },\n ];\n return LANDMARK_SELECTORS.flatMap(({ role, selector }) =>\n [...document.querySelectorAll(selector)].slice(0, 10).map(el => ({\n role,\n label: el.getAttribute('aria-label') || el.getAttribute('aria-labelledby') || '',\n elementId: el.id || '',\n interactiveCount: el.querySelectorAll(\n 'button,a[href],input,select,textarea,[role=\"button\"],[tabindex=\"0\"]'\n ).length,\n }))\n );\n });\n return raw.slice(0, 50);\n } catch {\n return [];\n }\n}\n\nasync function extractHeadings(page: any): Promise<HeadingInfo[]> {\n try {\n const raw = await page.evaluate(() => {\n const headingEls = [...document.querySelectorAll('h1,h2,h3,h4,h5,h6,[role=\"heading\"]')];\n return headingEls\n .map(el => ({\n level:\n parseInt(el.tagName.slice(1)) ||\n parseInt(el.getAttribute('aria-level') || '0') ||\n 0,\n text: el.textContent?.trim().slice(0, 100) || '',\n elementId: el.id || '',\n }))\n .filter(h => h.level >= 1 && h.level <= 6);\n });\n return raw.slice(0, 100);\n } catch {\n return [];\n }\n}\n\nfunction detectHeadingViolations(headings: HeadingInfo[]): string[] {\n const violations: string[] = [];\n if (headings.length === 0) return violations;\n\n const h1s = headings.filter(h => h.level === 1);\n if (h1s.length === 0) {\n violations.push('Missing h1 landmark');\n } else if (h1s.length > 1) {\n violations.push('Multiple h1 elements found');\n }\n\n let prevLevel = 0;\n for (const heading of headings) {\n if (prevLevel > 0 && heading.level > prevLevel + 1) {\n violations.push(\n `Heading level skip: h${prevLevel} to h${heading.level}`\n );\n }\n prevLevel = heading.level;\n }\n\n return violations;\n}\n\nasync function findMissingNames(page: any): Promise<MissingNameEl[]> {\n try {\n return await page.evaluate(() => {\n const INTERACTIVE_SELECTOR =\n 'button,a[href],input:not([type=\"hidden\"]),select,textarea,' +\n '[role=\"button\"],[role=\"link\"],[role=\"checkbox\"],[role=\"radio\"],' +\n '[role=\"switch\"],[role=\"menuitem\"],[role=\"tab\"]';\n return [...document.querySelectorAll(INTERACTIVE_SELECTOR)]\n .filter(el => {\n const labelledById = el.getAttribute('aria-labelledby') || '';\n const name =\n (el.getAttribute('aria-label') || '').trim() ||\n (labelledById\n ? document.getElementById(labelledById)?.textContent?.trim() ?? ''\n : '') ||\n (el.textContent || '').trim() ||\n ((el as HTMLInputElement).placeholder || '').trim() ||\n ((el as HTMLElement).title || '').trim() ||\n ((el as HTMLImageElement).alt || '').trim();\n return !name || name.length === 0;\n })\n .slice(0, 30)\n .map(el => ({\n tagName: el.tagName.toLowerCase(),\n role: el.getAttribute('role') || '',\n elementId: el.id || '',\n htmlSnippet: el.outerHTML.slice(0, 120),\n }));\n });\n } catch {\n return [];\n }\n}\n\nasync function extractLiveRegions(page: any): Promise<LiveRegionInfo[]> {\n try {\n return await page.evaluate(() => {\n const els = [\n ...document.querySelectorAll(\n '[aria-live],[role=\"alert\"],[role=\"status\"],[role=\"log\"]'\n ),\n ];\n return els.slice(0, 20).map(el => ({\n role: el.getAttribute('role') || '',\n ariaLive: el.getAttribute('aria-live') || '',\n ariaAtomic: el.getAttribute('aria-atomic') || '',\n currentText: (el.textContent || '').trim().slice(0, 200),\n }));\n });\n } catch {\n return [];\n }\n}\n\nasync function checkSkipLink(page: any): Promise<boolean> {\n try {\n return await page.evaluate(() => {\n const firstFocusable = document.querySelector('a[href^=\"#\"],a:first-of-type');\n return !!(\n firstFocusable &&\n /skip/i.test(\n (firstFocusable.textContent || '') + (firstFocusable.getAttribute('href') || '')\n )\n );\n });\n } catch {\n return false;\n }\n}\n\nexport async function crawlAccessibilityTree(page: any): Promise<AccessibilityTreeResult> {\n const [\n landmarksResult,\n headingsResult,\n missingNamesResult,\n liveRegionsResult,\n skipLinkResult,\n interactiveCountResult,\n ] = await Promise.allSettled([\n extractLandmarks(page),\n extractHeadings(page),\n findMissingNames(page),\n extractLiveRegions(page),\n checkSkipLink(page),\n page.evaluate(() => {\n const INTERACTIVE_SELECTOR =\n 'button,a[href],input:not([type=\"hidden\"]),select,textarea,' +\n '[role=\"button\"],[role=\"link\"],[role=\"checkbox\"],[role=\"radio\"],' +\n '[role=\"switch\"],[role=\"menuitem\"],[role=\"tab\"]';\n return document.querySelectorAll(INTERACTIVE_SELECTOR).length;\n }).catch(() => 0),\n ]);\n\n const landmarks =\n landmarksResult.status === 'fulfilled' ? landmarksResult.value : [];\n const headings =\n headingsResult.status === 'fulfilled' ? headingsResult.value : [];\n const missingNameElements =\n missingNamesResult.status === 'fulfilled' ? missingNamesResult.value : [];\n const liveRegions =\n liveRegionsResult.status === 'fulfilled' ? liveRegionsResult.value : [];\n const hasSkipLink =\n skipLinkResult.status === 'fulfilled' ? skipLinkResult.value : false;\n const totalInteractiveCount =\n interactiveCountResult.status === 'fulfilled' ? interactiveCountResult.value : 0;\n\n const headingHierarchyViolations = detectHeadingViolations(headings);\n\n return {\n landmarkCount: landmarks.length,\n landmarks,\n headings,\n headingHierarchyViolations,\n missingNameElements,\n missingNameCount: missingNameElements.length,\n liveRegions,\n totalInteractiveCount,\n hasSkipLink,\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced UI probes — detect and exercise drag-drop, date pickers, sliders,
|
|
3
|
+
* and typeahead/autocomplete widgets on a crawled page.
|
|
4
|
+
*
|
|
5
|
+
* Results feed ZeTa's test generator so it can emit interaction-level test
|
|
6
|
+
* cases for these widget families instead of falling back to generic clicks.
|
|
7
|
+
*
|
|
8
|
+
* Each probe is independently try/caught so a broken widget does not abort
|
|
9
|
+
* the others. All browser-side code runs inside page.evaluate / page.$$eval
|
|
10
|
+
* to avoid serialisation issues with DOM handles.
|
|
11
|
+
*/
|
|
12
|
+
import type { Page } from 'playwright';
|
|
13
|
+
export interface DragDropCapture {
|
|
14
|
+
library: 'html5' | 'dnd-kit' | 'react-beautiful-dnd' | 'sortablejs' | 'pointer-event' | 'none';
|
|
15
|
+
draggableCount: number;
|
|
16
|
+
dropZoneCount: number;
|
|
17
|
+
testAttempted: boolean;
|
|
18
|
+
testCompleted: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface DatePickerCapture {
|
|
21
|
+
fieldLabel: string;
|
|
22
|
+
pickerType: 'calendar-popup' | 'native-date' | 'native-datetime' | 'none';
|
|
23
|
+
minDate?: string;
|
|
24
|
+
maxDate?: string;
|
|
25
|
+
disabledDatesFound: boolean;
|
|
26
|
+
sampleSelectedValue?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface SliderCapture {
|
|
29
|
+
label: string;
|
|
30
|
+
min: number;
|
|
31
|
+
max: number;
|
|
32
|
+
step: number;
|
|
33
|
+
currentValue: number;
|
|
34
|
+
}
|
|
35
|
+
export interface TypeaheadCapture {
|
|
36
|
+
label: string;
|
|
37
|
+
minCharsToTrigger: number;
|
|
38
|
+
sampleSuggestions: string[];
|
|
39
|
+
noResultsText: string | null;
|
|
40
|
+
}
|
|
41
|
+
export interface AdvancedProbeResult {
|
|
42
|
+
dragDrop: DragDropCapture;
|
|
43
|
+
datePickers: DatePickerCapture[];
|
|
44
|
+
sliders: SliderCapture[];
|
|
45
|
+
typeaheads: TypeaheadCapture[];
|
|
46
|
+
}
|
|
47
|
+
export declare function probeAdvancedUI(page: Page): Promise<AdvancedProbeResult>;
|