@detiq/crawler 1.1.8 → 1.1.9
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/dist/accessibility-auditor.js +74 -54
- package/dist/ai-login.js +249 -227
- package/dist/auth-token-rotator.js +67 -57
- package/dist/auth.js +336 -299
- package/dist/browser-extension.js +142 -104
- package/dist/captcha-solver.js +125 -98
- package/dist/color-contrast.js +89 -77
- package/dist/content-chunker.js +126 -126
- package/dist/content-dedup.js +71 -54
- package/dist/cookie-consent.js +83 -68
- package/dist/cookie-jar.js +60 -53
- package/dist/crawler.js +5345 -4486
- package/dist/custom-js-injector.js +61 -45
- package/dist/dark-mode-capture.js +81 -67
- package/dist/dead-link-detector.js +55 -47
- package/dist/element-hash.js +12 -8
- package/dist/email-otp.js +195 -154
- package/dist/engine-router.js +98 -87
- package/dist/export/bulk-export.js +55 -70
- package/dist/export/vector-export.js +105 -77
- package/dist/extractors/advanced.js +266 -249
- package/dist/extractors/artifact-envelope.js +58 -59
- package/dist/failure-analysis-agent.js +33 -37
- package/dist/feature-flag-detector.js +66 -51
- package/dist/form-detector.js +75 -55
- package/dist/frontier.js +101 -76
- package/dist/gap-pass.js +89 -68
- package/dist/graphql-detector.js +72 -62
- package/dist/http-engine.js +330 -282
- package/dist/incremental-diff.js +87 -54
- package/dist/index.js +28 -67
- package/dist/input-fuzzer.js +97 -93
- package/dist/interactive-probe.js +827 -715
- package/dist/job-queue.js +2169 -2151
- package/dist/js-coverage.js +56 -52
- package/dist/js-router-detector.js +117 -86
- package/dist/language-detector.js +63 -51
- package/dist/link-classifier.js +50 -32
- package/dist/live-view.js +108 -91
- package/dist/locator-extractor.js +187 -151
- package/dist/logger.js +7 -9
- package/dist/markdown-extract.js +61 -48
- package/dist/native-crawler.js +946 -780
- package/dist/network-observer.js +156 -135
- package/dist/network-throttle.js +40 -29
- package/dist/openapi-generator.js +92 -77
- package/dist/pdf-extractor.js +90 -72
- package/dist/performance-metrics.js +102 -80
- package/dist/phash.js +144 -125
- package/dist/pii-scrubber.js +68 -65
- package/dist/playwright-recorder.js +58 -70
- package/dist/policies/crawl-safety.js +34 -31
- package/dist/profiles/domain-profile.js +125 -130
- package/dist/proxy.js +172 -146
- package/dist/rate-limiter.js +65 -58
- package/dist/redirect-tracker.js +64 -60
- package/dist/redis-frontier.js +136 -116
- package/dist/redis-queue.js +144 -157
- package/dist/response-cache.js +140 -127
- package/dist/responsive-detector.js +46 -42
- package/dist/retry-policy.js +50 -46
- package/dist/robots-txt.js +83 -69
- package/dist/screen-reader.js +70 -45
- package/dist/screenshot-masker.js +77 -59
- package/dist/seo-checker.js +107 -88
- package/dist/session-capture.js +212 -192
- package/dist/session-export.js +133 -107
- package/dist/sitemap-writer.js +41 -38
- package/dist/sitemap.js +202 -141
- package/dist/skyvern.js +148 -123
- package/dist/sqs-queue.js +42 -42
- package/dist/sso-token.js +90 -74
- package/dist/stealth/human-behavior.js +173 -156
- package/dist/telemetry.js +82 -68
- package/dist/test-executor.js +335 -309
- package/dist/tls-fingerprint.js +88 -77
- package/dist/url-pattern-completer.js +90 -71
- package/dist/visual-diff-verdict.js +38 -23
- package/dist/webhook-notifier.js +69 -71
- package/dist/websocket-detector.js +68 -56
- package/dist/worker.js +38 -29
- package/package.json +1 -1
|
@@ -1,57 +1,77 @@
|
|
|
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
|
+
*/
|
|
1
15
|
async function queryAll(page, selector) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
16
|
+
try {
|
|
17
|
+
return await page.$$eval(selector, els => els.map((el) => ({
|
|
18
|
+
outerHTML: el.outerHTML?.slice(0, 200) ?? '',
|
|
19
|
+
textContent: (el.textContent ?? '').trim().slice(0, 100),
|
|
20
|
+
tabIndex: el.tabIndex,
|
|
21
|
+
getAttribute: (a) => el.getAttribute(a),
|
|
22
|
+
})));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
12
27
|
}
|
|
13
|
-
async function auditAccessibility(page, url) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
28
|
+
export async function auditAccessibility(page, url) {
|
|
29
|
+
const violations = [];
|
|
30
|
+
let passCount = 0;
|
|
31
|
+
const auditedAt = new Date().toISOString();
|
|
32
|
+
// 1. Images without alt
|
|
33
|
+
const imgs = await page.$$eval('img:not([alt])', els => els.map((e) => e.outerHTML?.slice(0, 120) ?? ''));
|
|
34
|
+
if (imgs.length > 0)
|
|
35
|
+
violations.push({ rule: 'image-alt', severity: 'critical', count: imgs.length, examples: imgs.slice(0, 3) });
|
|
36
|
+
else
|
|
37
|
+
passCount++;
|
|
38
|
+
// 2. Inputs without labels
|
|
39
|
+
const unlabeledInputs = await page.$$eval('input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([aria-label]):not([aria-labelledby]):not([id])', els => els.map((e) => e.outerHTML?.slice(0, 120) ?? ''));
|
|
40
|
+
if (unlabeledInputs.length > 0)
|
|
41
|
+
violations.push({ rule: 'label', severity: 'serious', count: unlabeledInputs.length, examples: unlabeledInputs.slice(0, 3) });
|
|
42
|
+
else
|
|
43
|
+
passCount++;
|
|
44
|
+
// 3. Buttons with no text
|
|
45
|
+
const emptyButtons = await page.$$eval('button:not([aria-label]):not([aria-labelledby])', els => els.filter((e) => !(e.textContent ?? '').trim()).map((e) => e.outerHTML?.slice(0, 120) ?? ''));
|
|
46
|
+
if (emptyButtons.length > 0)
|
|
47
|
+
violations.push({ rule: 'button-name', severity: 'critical', count: emptyButtons.length, examples: emptyButtons.slice(0, 3) });
|
|
48
|
+
else
|
|
49
|
+
passCount++;
|
|
50
|
+
// 4. Missing html lang
|
|
51
|
+
const htmlLang = await page.$eval('html', (el) => el.getAttribute('lang') ?? '').catch(() => '');
|
|
52
|
+
if (!htmlLang)
|
|
53
|
+
violations.push({ rule: 'html-has-lang', severity: 'serious', count: 1, examples: ['<html> missing lang attribute'] });
|
|
54
|
+
else
|
|
55
|
+
passCount++;
|
|
56
|
+
// 5. Missing page title
|
|
57
|
+
const title = await page.title().catch(() => '');
|
|
58
|
+
if (!title)
|
|
59
|
+
violations.push({ rule: 'document-title', severity: 'serious', count: 1, examples: ['Page has no <title>'] });
|
|
60
|
+
else
|
|
61
|
+
passCount++;
|
|
62
|
+
// 6. Empty headings
|
|
63
|
+
const emptyHeadings = await page.$$eval('h1,h2,h3,h4,h5,h6', els => els.filter((e) => !(e.textContent ?? '').trim()).map((e) => e.tagName.toLowerCase()));
|
|
64
|
+
if (emptyHeadings.length > 0)
|
|
65
|
+
violations.push({ rule: 'empty-heading', severity: 'moderate', count: emptyHeadings.length, examples: emptyHeadings.slice(0, 3) });
|
|
66
|
+
else
|
|
67
|
+
passCount++;
|
|
68
|
+
// 7. Links with no accessible name
|
|
69
|
+
const emptyLinks = await page.$$eval('a[href]:not([aria-label]):not([aria-labelledby])', els => els.filter((e) => !(e.textContent ?? '').trim() && !e.querySelector('img[alt]')).map((e) => e.outerHTML?.slice(0, 120) ?? ''));
|
|
70
|
+
if (emptyLinks.length > 0)
|
|
71
|
+
violations.push({ rule: 'link-name', severity: 'serious', count: emptyLinks.length, examples: emptyLinks.slice(0, 3) });
|
|
72
|
+
else
|
|
73
|
+
passCount++;
|
|
74
|
+
const totalChecks = passCount + violations.length;
|
|
75
|
+
const score = totalChecks > 0 ? Math.round((passCount / totalChecks) * 100) : 100;
|
|
76
|
+
return { url, violations, passCount, score, auditedAt };
|
|
53
77
|
}
|
|
54
|
-
export {
|
|
55
|
-
auditAccessibility
|
|
56
|
-
};
|
|
57
|
-
//# sourceMappingURL=accessibility-auditor.js.map
|