@detiq/crawler 1.1.9 → 1.1.11
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 +54 -74
- package/dist/ai-login.js +227 -249
- package/dist/auth-token-rotator.js +57 -67
- package/dist/auth.js +299 -336
- package/dist/browser-extension.js +104 -142
- package/dist/captcha-solver.js +98 -125
- package/dist/color-contrast.js +77 -89
- package/dist/content-chunker.js +126 -126
- package/dist/content-dedup.js +54 -71
- package/dist/cookie-consent.js +68 -83
- package/dist/cookie-jar.js +53 -60
- package/dist/crawler.js +4494 -5353
- package/dist/custom-js-injector.js +45 -61
- package/dist/dark-mode-capture.js +67 -81
- package/dist/dead-link-detector.js +47 -55
- package/dist/element-hash.js +8 -12
- package/dist/email-otp.js +154 -195
- package/dist/engine-router.js +87 -98
- package/dist/export/bulk-export.js +70 -55
- package/dist/export/vector-export.js +77 -105
- package/dist/extractors/advanced.js +249 -266
- package/dist/extractors/artifact-envelope.js +59 -58
- package/dist/failure-analysis-agent.js +37 -33
- package/dist/feature-flag-detector.js +51 -66
- package/dist/form-detector.js +55 -75
- package/dist/frontier.js +76 -101
- package/dist/gap-pass.js +68 -89
- package/dist/graphql-detector.js +62 -72
- package/dist/http-engine.js +282 -330
- package/dist/incremental-diff.js +54 -87
- package/dist/index.js +67 -28
- package/dist/input-fuzzer.js +93 -97
- package/dist/interactive-probe.js +715 -827
- package/dist/job-queue.js +2151 -2169
- package/dist/js-coverage.js +52 -56
- package/dist/js-router-detector.js +86 -117
- package/dist/language-detector.js +51 -63
- package/dist/link-classifier.js +32 -50
- package/dist/live-view.js +91 -108
- package/dist/locator-extractor.js +151 -187
- package/dist/logger.js +9 -7
- package/dist/markdown-extract.js +48 -61
- package/dist/native-crawler.js +780 -946
- package/dist/network-observer.js +135 -156
- package/dist/network-throttle.js +29 -40
- package/dist/openapi-generator.js +77 -92
- package/dist/pdf-extractor.js +72 -90
- package/dist/performance-metrics.js +80 -102
- package/dist/phash.js +125 -144
- package/dist/pii-scrubber.js +65 -68
- package/dist/playwright-recorder.js +70 -58
- package/dist/policies/crawl-safety.js +31 -34
- package/dist/profiles/domain-profile.js +130 -125
- package/dist/proxy.js +146 -172
- package/dist/rate-limiter.js +58 -65
- package/dist/redirect-tracker.js +60 -64
- package/dist/redis-frontier.js +116 -136
- package/dist/redis-queue.js +157 -144
- package/dist/response-cache.js +127 -140
- package/dist/responsive-detector.js +42 -46
- package/dist/retry-policy.js +46 -50
- package/dist/robots-txt.js +69 -83
- package/dist/screen-reader.js +45 -70
- package/dist/screenshot-masker.js +59 -77
- package/dist/seo-checker.js +88 -107
- package/dist/session-capture.js +192 -212
- package/dist/session-export.js +107 -133
- package/dist/sitemap-writer.js +38 -41
- package/dist/sitemap.js +141 -202
- package/dist/skyvern.js +123 -148
- package/dist/sqs-queue.js +42 -42
- package/dist/sso-token.js +74 -90
- package/dist/stealth/human-behavior.js +156 -173
- package/dist/telemetry.js +68 -82
- package/dist/test-executor.js +309 -335
- package/dist/tls-fingerprint.js +77 -88
- package/dist/url-pattern-completer.js +71 -90
- package/dist/visual-diff-verdict.js +23 -38
- package/dist/webhook-notifier.js +71 -69
- package/dist/websocket-detector.js +56 -68
- package/dist/worker.js +29 -38
- package/package.json +1 -1
- package/src/job-queue.ts +136 -0
package/dist/cookie-consent.js
CHANGED
|
@@ -1,93 +1,78 @@
|
|
|
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
|
|
15
1
|
const CONSENT_SELECTORS = [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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"
|
|
35
21
|
];
|
|
36
|
-
// Fallback: button text matching
|
|
37
22
|
const ACCEPT_TEXT_PATTERNS = [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
46
31
|
];
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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 */ }
|
|
62
|
-
}
|
|
63
|
-
// Fallback: find buttons with accept-like text
|
|
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) {
|
|
64
37
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return { found: true, clicked: true, method: `text: "${text}"` };
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
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 {
|
|
76
45
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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}"` };
|
|
87
56
|
}
|
|
88
|
-
|
|
57
|
+
}
|
|
89
58
|
}
|
|
90
|
-
|
|
91
|
-
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
return { found: false, clicked: false };
|
|
62
|
+
}
|
|
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;
|
|
92
68
|
}
|
|
69
|
+
return false;
|
|
70
|
+
} catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
93
73
|
}
|
|
74
|
+
export {
|
|
75
|
+
acceptCookieConsent,
|
|
76
|
+
isConsentBannerVisible
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=cookie-consent.js.map
|
package/dist/cookie-jar.js
CHANGED
|
@@ -1,68 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
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';
|
|
1
|
+
import * as fs from "fs/promises";
|
|
2
|
+
import * as path from "path";
|
|
11
3
|
function jarPath(cacheDir, projectId) {
|
|
12
|
-
|
|
4
|
+
return path.join(cacheDir, `cookie-jar-${projectId}.json`);
|
|
13
5
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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");
|
|
24
16
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
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
|
+
}
|
|
37
27
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
async function clearCookieJar(cacheDir, projectId) {
|
|
29
|
+
try {
|
|
30
|
+
await fs.unlink(jarPath(cacheDir, projectId));
|
|
31
|
+
} catch {
|
|
32
|
+
}
|
|
43
33
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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()] });
|
|
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);
|
|
64
45
|
}
|
|
65
|
-
|
|
66
|
-
|
|
46
|
+
const originsMap = /* @__PURE__ */ new Map();
|
|
47
|
+
for (const o of [...a.origins ?? [], ...b.origins ?? []]) {
|
|
48
|
+
originsMap.set(o.origin, o);
|
|
67
49
|
}
|
|
50
|
+
return JSON.stringify({ cookies, origins: [...originsMap.values()] });
|
|
51
|
+
} catch {
|
|
52
|
+
return overlay || base;
|
|
53
|
+
}
|
|
68
54
|
}
|
|
55
|
+
export {
|
|
56
|
+
clearCookieJar,
|
|
57
|
+
loadCookieJar,
|
|
58
|
+
mergeStorageStates,
|
|
59
|
+
saveCookieJar
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=cookie-jar.js.map
|