@detiq/crawler 1.1.7 → 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.
Files changed (92) hide show
  1. package/dist/accessibility-auditor.js +74 -54
  2. package/dist/ai-login.js +249 -227
  3. package/dist/auth-token-rotator.js +67 -57
  4. package/dist/auth.js +336 -299
  5. package/dist/browser-extension.js +142 -104
  6. package/dist/captcha-solver.js +125 -98
  7. package/dist/color-contrast.js +89 -77
  8. package/dist/content-chunker.js +126 -126
  9. package/dist/content-dedup.js +71 -54
  10. package/dist/cookie-consent.js +83 -68
  11. package/dist/cookie-jar.js +60 -53
  12. package/dist/crawler.js +5345 -4486
  13. package/dist/custom-js-injector.js +61 -45
  14. package/dist/dark-mode-capture.js +81 -67
  15. package/dist/dead-link-detector.js +55 -47
  16. package/dist/element-hash.js +12 -8
  17. package/dist/email-otp.js +195 -154
  18. package/dist/engine-router.js +98 -87
  19. package/dist/export/bulk-export.js +55 -70
  20. package/dist/export/vector-export.js +105 -77
  21. package/dist/extractors/advanced.d.ts +10 -0
  22. package/dist/extractors/advanced.js +266 -249
  23. package/dist/extractors/artifact-envelope.js +58 -59
  24. package/dist/failure-analysis-agent.js +33 -37
  25. package/dist/feature-flag-detector.js +66 -51
  26. package/dist/form-detector.js +75 -55
  27. package/dist/frontier.js +101 -76
  28. package/dist/gap-pass.js +89 -68
  29. package/dist/graphql-detector.js +72 -62
  30. package/dist/http-engine.js +330 -282
  31. package/dist/incremental-diff.js +87 -54
  32. package/dist/index.d.ts +2 -0
  33. package/dist/index.js +28 -63
  34. package/dist/index.js.map +2 -2
  35. package/dist/input-fuzzer.js +97 -93
  36. package/dist/interactive-probe.d.ts +36 -0
  37. package/dist/interactive-probe.js +827 -715
  38. package/dist/job-queue.js +2169 -2151
  39. package/dist/js-coverage.js +56 -52
  40. package/dist/js-router-detector.js +117 -86
  41. package/dist/language-detector.js +63 -51
  42. package/dist/link-classifier.js +50 -32
  43. package/dist/live-view.js +108 -91
  44. package/dist/locator-extractor.d.ts +37 -0
  45. package/dist/locator-extractor.js +199 -0
  46. package/dist/locator-extractor.js.map +7 -0
  47. package/dist/logger.js +7 -9
  48. package/dist/markdown-extract.js +61 -48
  49. package/dist/native-crawler.js +946 -780
  50. package/dist/network-observer.js +156 -135
  51. package/dist/network-throttle.js +40 -29
  52. package/dist/openapi-generator.js +92 -77
  53. package/dist/pdf-extractor.js +90 -72
  54. package/dist/performance-metrics.js +102 -80
  55. package/dist/phash.js +144 -125
  56. package/dist/pii-scrubber.js +68 -65
  57. package/dist/playwright-recorder.js +58 -70
  58. package/dist/policies/crawl-safety.js +34 -31
  59. package/dist/profiles/domain-profile.js +125 -130
  60. package/dist/proxy.js +172 -146
  61. package/dist/rate-limiter.js +65 -58
  62. package/dist/redirect-tracker.js +64 -60
  63. package/dist/redis-frontier.js +136 -116
  64. package/dist/redis-queue.js +144 -157
  65. package/dist/response-cache.js +140 -127
  66. package/dist/responsive-detector.js +46 -42
  67. package/dist/retry-policy.js +50 -46
  68. package/dist/robots-txt.js +83 -69
  69. package/dist/screen-reader.js +70 -45
  70. package/dist/screenshot-masker.js +77 -59
  71. package/dist/seo-checker.js +107 -88
  72. package/dist/session-capture.js +212 -192
  73. package/dist/session-export.js +133 -107
  74. package/dist/sitemap-writer.js +41 -38
  75. package/dist/sitemap.js +202 -141
  76. package/dist/skyvern.js +148 -123
  77. package/dist/sqs-queue.js +42 -42
  78. package/dist/sso-token.js +90 -74
  79. package/dist/stealth/human-behavior.js +173 -156
  80. package/dist/telemetry.js +82 -68
  81. package/dist/test-executor.js +335 -309
  82. package/dist/tls-fingerprint.js +88 -77
  83. package/dist/url-pattern-completer.js +90 -71
  84. package/dist/visual-diff-verdict.js +38 -23
  85. package/dist/webhook-notifier.js +69 -71
  86. package/dist/websocket-detector.js +68 -56
  87. package/dist/worker.js +38 -29
  88. package/package.json +1 -1
  89. package/src/index.ts +2 -0
  90. package/src/locator-extractor.ts +226 -0
  91. package/types/index.d.ts +2 -0
  92. package/types/locator-extractor.d.ts +37 -0
@@ -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
- 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
- }
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
- 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 };
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