@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.
Files changed (82) 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.js +266 -249
  22. package/dist/extractors/artifact-envelope.js +58 -59
  23. package/dist/failure-analysis-agent.js +33 -37
  24. package/dist/feature-flag-detector.js +66 -51
  25. package/dist/form-detector.js +75 -55
  26. package/dist/frontier.js +101 -76
  27. package/dist/gap-pass.js +89 -68
  28. package/dist/graphql-detector.js +72 -62
  29. package/dist/http-engine.js +330 -282
  30. package/dist/incremental-diff.js +87 -54
  31. package/dist/index.js +28 -67
  32. package/dist/input-fuzzer.js +97 -93
  33. package/dist/interactive-probe.js +827 -715
  34. package/dist/job-queue.js +2169 -2151
  35. package/dist/js-coverage.js +56 -52
  36. package/dist/js-router-detector.js +117 -86
  37. package/dist/language-detector.js +63 -51
  38. package/dist/link-classifier.js +50 -32
  39. package/dist/live-view.js +108 -91
  40. package/dist/locator-extractor.js +187 -151
  41. package/dist/logger.js +7 -9
  42. package/dist/markdown-extract.js +61 -48
  43. package/dist/native-crawler.js +946 -780
  44. package/dist/network-observer.js +156 -135
  45. package/dist/network-throttle.js +40 -29
  46. package/dist/openapi-generator.js +92 -77
  47. package/dist/pdf-extractor.js +90 -72
  48. package/dist/performance-metrics.js +102 -80
  49. package/dist/phash.js +144 -125
  50. package/dist/pii-scrubber.js +68 -65
  51. package/dist/playwright-recorder.js +58 -70
  52. package/dist/policies/crawl-safety.js +34 -31
  53. package/dist/profiles/domain-profile.js +125 -130
  54. package/dist/proxy.js +172 -146
  55. package/dist/rate-limiter.js +65 -58
  56. package/dist/redirect-tracker.js +64 -60
  57. package/dist/redis-frontier.js +136 -116
  58. package/dist/redis-queue.js +144 -157
  59. package/dist/response-cache.js +140 -127
  60. package/dist/responsive-detector.js +46 -42
  61. package/dist/retry-policy.js +50 -46
  62. package/dist/robots-txt.js +83 -69
  63. package/dist/screen-reader.js +70 -45
  64. package/dist/screenshot-masker.js +77 -59
  65. package/dist/seo-checker.js +107 -88
  66. package/dist/session-capture.js +212 -192
  67. package/dist/session-export.js +133 -107
  68. package/dist/sitemap-writer.js +41 -38
  69. package/dist/sitemap.js +202 -141
  70. package/dist/skyvern.js +148 -123
  71. package/dist/sqs-queue.js +42 -42
  72. package/dist/sso-token.js +90 -74
  73. package/dist/stealth/human-behavior.js +173 -156
  74. package/dist/telemetry.js +82 -68
  75. package/dist/test-executor.js +335 -309
  76. package/dist/tls-fingerprint.js +88 -77
  77. package/dist/url-pattern-completer.js +90 -71
  78. package/dist/visual-diff-verdict.js +38 -23
  79. package/dist/webhook-notifier.js +69 -71
  80. package/dist/websocket-detector.js +68 -56
  81. package/dist/worker.js +38 -29
  82. package/package.json +1 -1
@@ -1,78 +1,93 @@
1
+ /**
2
+ * Cookie consent auto-acceptor.
3
+ *
4
+ * Detects and clicks "Accept" on common cookie consent banners before the
5
+ * crawler proceeds. Without this, many EU sites show a consent wall that
6
+ * blocks content or shows a different layout, making crawl results unreliable.
7
+ *
8
+ * Supports: Cookiebot, OneTrust, TrustArc, Usercentrics, GDPR Cookie Compliance,
9
+ * generic "Accept All" / "Accept Cookies" buttons.
10
+ *
11
+ * Strategy: try known selectors first, then fall back to text-based button search.
12
+ * Non-blocking — if no banner is found or click fails, crawl proceeds normally.
13
+ */
14
+ // Known consent platform selectors
1
15
  const CONSENT_SELECTORS = [
2
- // Cookiebot
3
- "#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll",
4
- "#CybotCookiebotDialogBodyButtonAccept",
5
- // OneTrust
6
- "#onetrust-accept-btn-handler",
7
- ".ot-sdk-accept-btn",
8
- // TrustArc
9
- '.truste_popframe [title*="Accept"]',
10
- "#truste-consent-button",
11
- // Usercentrics
12
- '[data-testid="uc-accept-all-button"]',
13
- // Generic high-confidence
14
- '[id*="accept"][id*="cookie"]',
15
- '[class*="accept"][class*="cookie"]',
16
- '[class*="cookie"][class*="accept"]',
17
- // GDPR Cookie Compliance
18
- ".gdpr-cookie-notice-accept",
19
- // Quantcast
20
- ".qc-cmp2-summary-buttons button:first-child"
16
+ // Cookiebot
17
+ '#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll',
18
+ '#CybotCookiebotDialogBodyButtonAccept',
19
+ // OneTrust
20
+ '#onetrust-accept-btn-handler',
21
+ '.ot-sdk-accept-btn',
22
+ // TrustArc
23
+ '.truste_popframe [title*="Accept"]',
24
+ '#truste-consent-button',
25
+ // Usercentrics
26
+ '[data-testid="uc-accept-all-button"]',
27
+ // Generic high-confidence
28
+ '[id*="accept"][id*="cookie"]',
29
+ '[class*="accept"][class*="cookie"]',
30
+ '[class*="cookie"][class*="accept"]',
31
+ // GDPR Cookie Compliance
32
+ '.gdpr-cookie-notice-accept',
33
+ // Quantcast
34
+ '.qc-cmp2-summary-buttons button:first-child',
21
35
  ];
36
+ // Fallback: button text matching
22
37
  const ACCEPT_TEXT_PATTERNS = [
23
- /^accept all$/i,
24
- /^accept all cookies$/i,
25
- /^allow all$/i,
26
- /^i accept$/i,
27
- /^agree$/i,
28
- /^ok$/i,
29
- /^got it$/i,
30
- /^allow cookies$/i
38
+ /^accept all$/i,
39
+ /^accept all cookies$/i,
40
+ /^allow all$/i,
41
+ /^i accept$/i,
42
+ /^agree$/i,
43
+ /^ok$/i,
44
+ /^got it$/i,
45
+ /^allow cookies$/i,
31
46
  ];
32
- async function acceptCookieConsent(page, opts = {}) {
33
- const { waitMs = 1500 } = opts;
34
- await page.waitForTimeout(waitMs).catch(() => {
35
- });
36
- for (const selector of CONSENT_SELECTORS) {
37
- try {
38
- const el = await page.$(selector);
39
- if (el && await el.isVisible()) {
40
- await el.click({ timeout: 2e3 });
41
- await page.waitForTimeout(500);
42
- return { found: true, clicked: true, method: `selector: ${selector}` };
43
- }
44
- } catch {
47
+ export async function acceptCookieConsent(page, opts = {}) {
48
+ const { waitMs = 1_500 } = opts;
49
+ // Wait briefly for consent banners to appear
50
+ await page.waitForTimeout(waitMs).catch(() => { });
51
+ // Try known selectors first
52
+ for (const selector of CONSENT_SELECTORS) {
53
+ try {
54
+ const el = await page.$(selector);
55
+ if (el && await el.isVisible()) {
56
+ await el.click({ timeout: 2_000 });
57
+ await page.waitForTimeout(500);
58
+ return { found: true, clicked: true, method: `selector: ${selector}` };
59
+ }
60
+ }
61
+ catch { /* try next */ }
45
62
  }
46
- }
47
- try {
48
- const buttons = await page.$$('button, [role="button"], a[class*="cookie"]');
49
- for (const btn of buttons) {
50
- const text = (await btn.textContent() ?? "").trim();
51
- if (ACCEPT_TEXT_PATTERNS.some((re) => re.test(text))) {
52
- if (await btn.isVisible()) {
53
- await btn.click({ timeout: 2e3 });
54
- await page.waitForTimeout(500);
55
- return { found: true, clicked: true, method: `text: "${text}"` };
63
+ // Fallback: find buttons with accept-like text
64
+ try {
65
+ const buttons = await page.$$('button, [role="button"], a[class*="cookie"]');
66
+ for (const btn of buttons) {
67
+ const text = ((await btn.textContent()) ?? '').trim();
68
+ if (ACCEPT_TEXT_PATTERNS.some(re => re.test(text))) {
69
+ if (await btn.isVisible()) {
70
+ await btn.click({ timeout: 2_000 });
71
+ await page.waitForTimeout(500);
72
+ return { found: true, clicked: true, method: `text: "${text}"` };
73
+ }
74
+ }
56
75
  }
57
- }
58
76
  }
59
- } catch {
60
- }
61
- return { found: false, clicked: false };
77
+ catch { /* non-fatal */ }
78
+ return { found: false, clicked: false };
62
79
  }
63
- async function isConsentBannerVisible(page) {
64
- try {
65
- for (const sel of CONSENT_SELECTORS.slice(0, 5)) {
66
- const el = await page.$(sel);
67
- if (el && await el.isVisible()) return true;
80
+ /** Check if a consent banner is still visible after attempted dismissal */
81
+ export async function isConsentBannerVisible(page) {
82
+ try {
83
+ for (const sel of CONSENT_SELECTORS.slice(0, 5)) {
84
+ const el = await page.$(sel);
85
+ if (el && await el.isVisible())
86
+ return true;
87
+ }
88
+ return false;
89
+ }
90
+ catch {
91
+ return false;
68
92
  }
69
- return false;
70
- } catch {
71
- return false;
72
- }
73
93
  }
74
- export {
75
- acceptCookieConsent,
76
- isConsentBannerVisible
77
- };
78
- //# sourceMappingURL=cookie-consent.js.map
@@ -1,61 +1,68 @@
1
- import * as fs from "fs/promises";
2
- import * as path from "path";
1
+ /**
2
+ * Cookie jar — persist and restore Playwright storageState cookies between
3
+ * crawl segments and restarts. Enables continuous auth across session boundaries
4
+ * (e.g. segment 1 logs in, segment 2–N inherit the session without re-login).
5
+ *
6
+ * Storage: JSON file per project in the crawl cache dir.
7
+ * Format: Playwright's storageState shape (cookies + origins).
8
+ */
9
+ import * as fs from 'fs/promises';
10
+ import * as path from 'path';
3
11
  function jarPath(cacheDir, projectId) {
4
- return path.join(cacheDir, `cookie-jar-${projectId}.json`);
12
+ return path.join(cacheDir, `cookie-jar-${projectId}.json`);
5
13
  }
6
- async function saveCookieJar(cacheDir, projectId, tenantId, storageState, domain) {
7
- await fs.mkdir(cacheDir, { recursive: true });
8
- const entry = {
9
- projectId,
10
- tenantId,
11
- storageState,
12
- savedAt: (/* @__PURE__ */ new Date()).toISOString(),
13
- domain
14
- };
15
- await fs.writeFile(jarPath(cacheDir, projectId), JSON.stringify(entry, null, 2), "utf8");
14
+ export async function saveCookieJar(cacheDir, projectId, tenantId, storageState, domain) {
15
+ await fs.mkdir(cacheDir, { recursive: true });
16
+ const entry = {
17
+ projectId,
18
+ tenantId,
19
+ storageState,
20
+ savedAt: new Date().toISOString(),
21
+ domain,
22
+ };
23
+ await fs.writeFile(jarPath(cacheDir, projectId), JSON.stringify(entry, null, 2), 'utf8');
16
24
  }
17
- async function loadCookieJar(cacheDir, projectId, maxAgeMs = 8 * 60 * 60 * 1e3) {
18
- try {
19
- const raw = await fs.readFile(jarPath(cacheDir, projectId), "utf8");
20
- const entry = JSON.parse(raw);
21
- const age = Date.now() - new Date(entry.savedAt).getTime();
22
- if (age > maxAgeMs) return null;
23
- return entry.storageState;
24
- } catch {
25
- return null;
26
- }
25
+ export async function loadCookieJar(cacheDir, projectId, maxAgeMs = 8 * 60 * 60 * 1000) {
26
+ try {
27
+ const raw = await fs.readFile(jarPath(cacheDir, projectId), 'utf8');
28
+ const entry = JSON.parse(raw);
29
+ const age = Date.now() - new Date(entry.savedAt).getTime();
30
+ if (age > maxAgeMs)
31
+ return null; // expired
32
+ return entry.storageState;
33
+ }
34
+ catch {
35
+ return null;
36
+ }
27
37
  }
28
- async function clearCookieJar(cacheDir, projectId) {
29
- try {
30
- await fs.unlink(jarPath(cacheDir, projectId));
31
- } catch {
32
- }
38
+ export async function clearCookieJar(cacheDir, projectId) {
39
+ try {
40
+ await fs.unlink(jarPath(cacheDir, projectId));
41
+ }
42
+ catch { /* already gone */ }
33
43
  }
34
- function mergeStorageStates(base, overlay) {
35
- try {
36
- const a = JSON.parse(base);
37
- const b = JSON.parse(overlay);
38
- const cookies = [...a.cookies ?? []];
39
- for (const ck of b.cookies ?? []) {
40
- const idx = cookies.findIndex(
41
- (c) => c.name === ck.name && c.domain === ck.domain && c.path === ck.path
42
- );
43
- if (idx >= 0) cookies[idx] = ck;
44
- else cookies.push(ck);
44
+ /** Merge two storageState JSON strings — second takes priority for same-domain cookies. */
45
+ export function mergeStorageStates(base, overlay) {
46
+ try {
47
+ const a = JSON.parse(base);
48
+ const b = JSON.parse(overlay);
49
+ // Cookies: overlay replaces same-name+domain+path cookies from base
50
+ const cookies = [...(a.cookies ?? [])];
51
+ for (const ck of (b.cookies ?? [])) {
52
+ const idx = cookies.findIndex((c) => c.name === ck.name && c.domain === ck.domain && c.path === ck.path);
53
+ if (idx >= 0)
54
+ cookies[idx] = ck;
55
+ else
56
+ cookies.push(ck);
57
+ }
58
+ // Origins: merge origins, overlay wins on same-origin
59
+ const originsMap = new Map();
60
+ for (const o of [...(a.origins ?? []), ...(b.origins ?? [])]) {
61
+ originsMap.set(o.origin, o);
62
+ }
63
+ return JSON.stringify({ cookies, origins: [...originsMap.values()] });
45
64
  }
46
- const originsMap = /* @__PURE__ */ new Map();
47
- for (const o of [...a.origins ?? [], ...b.origins ?? []]) {
48
- originsMap.set(o.origin, o);
65
+ catch {
66
+ return overlay || base;
49
67
  }
50
- return JSON.stringify({ cookies, origins: [...originsMap.values()] });
51
- } catch {
52
- return overlay || base;
53
- }
54
68
  }
55
- export {
56
- clearCookieJar,
57
- loadCookieJar,
58
- mergeStorageStates,
59
- saveCookieJar
60
- };
61
- //# sourceMappingURL=cookie-jar.js.map