@detiq/crawler 1.1.28 → 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/dist/crawler.js +9 -0
- package/dist/crawler.js.map +2 -2
- package/dist/failure-analysis-agent.js +2 -1
- package/dist/failure-analysis-agent.js.map +2 -2
- package/dist/job-queue.js +177 -195
- package/dist/job-queue.js.map +2 -2
- package/package.json +1 -1
- package/src/job-queue.test.ts +69 -2
- package/src/job-queue.ts +202 -160
- package/types/job-queue.d.ts +12 -0
package/dist/crawler.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/crawler.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * ZeTa-AI Crawler \u2014 Stagehand hybrid architecture\n *\n * Three-layer stack:\n * Layer 1 \u2014 Playwright (deterministic): navigation, screenshots, DOM fallbacks\n * Layer 2 \u2014 Stagehand act/extract (AI): login, element understanding, smart link discovery\n * Layer 3 \u2014 Skyvern (vision): fallback for CAPTCHAs, legacy apps, visual-only flows\n *\n * enableCaching: true \u2192 repeat crawls of the same site cost ~zero AI tokens after first run.\n */\n\nimport { Stagehand } from '@browserbasehq/stagehand';\n// Option 2: rebrowser-playwright-core patches the CDP Runtime.enable leak at protocol level \u2014\n// the deepest possible stealth, defeats detection methods that JS init scripts cannot touch.\n// @ts-ignore\nimport { chromium } from 'rebrowser-playwright-core';\nimport { chromium as stealthChromium } from 'playwright-extra';\n// @ts-ignore\nimport StealthPlugin from 'puppeteer-extra-plugin-stealth';\n// Option 3: Camoufox \u2014 Firefox-based browser with built-in fingerprint randomisation.\n// Loaded dynamically (not at startup) to avoid ESM/CJS conflict when API imports crawler.\nimport { spawn, execSync, type ChildProcess } from 'node:child_process';\nimport { existsSync as existsSyncFs, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\n\nstealthChromium.use(StealthPlugin());\nimport { z } from 'zod';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { AppBrain, recordLLMCall } from '@detiq/app-brain';\nimport { aiVisualCompare, askTracked, deterministicSeed, estimateCost, getTaskAgentLLMConfig } from '@detiq/agents';\nimport { config } from '@detiq/core';\nimport { pHashVerdict, mergeAiVisualVerdict } from './visual-diff-verdict.js';\nimport type { Credentials } from './auth.js';\nimport { skyvernFallback, skyvernNavigate, type SkyvernConfig } from './skyvern.js';\nimport { loginWithStagehand } from './ai-login.js';\nimport { readScreen } from './screen-reader.js';\nimport { probeAllScreens, probeKeyboardNav } from './interactive-probe.js';\nimport { computeElementHash } from './element-hash.js';\nimport { logger } from './logger.js';\nimport { solveCaptcha } from './captcha-solver.js';\nimport { waitForEmailOTP } from './email-otp.js';\nimport { getSsoToken } from './sso-token.js';\nimport { discoverSitemapUrls, sameSite } from './sitemap.js';\nimport { extractMarkdown } from './markdown-extract.js';\nimport { CrawlFrontier, type TraversalStrategy } from './frontier.js';\nimport { RobotsCache } from './robots-txt.js';\nimport { classifyDomainProfile } from './profiles/domain-profile.js';\nimport { chooseCrawlEngines } from './engine-router.js';\nimport { assessActionSafety } from './policies/crawl-safety.js';\nimport { attachNetworkObserver, type ApiEndpointObservationInput } from './network-observer.js';\nimport { scrubPii } from './pii-scrubber.js';\nimport { computeContentHash } from './incremental-diff.js';\nimport { isPdfUrl, extractPdfFromUrl } from './pdf-extractor.js';\nimport { attachWebSocketDetector } from './websocket-detector.js';\nimport { ContentDeduplicator } from './content-dedup.js';\nimport { guessGraphQLEndpoints, introspectGraphQL } from './graphql-detector.js';\nimport { acceptCookieConsent } from './cookie-consent.js';\nimport { detectJsRoutes } from './js-router-detector.js';\nimport { runGapAnalysis } from './gap-pass.js';\nimport { buildCrawlArtifactEnvelope, buildFitMarkdown, sha256, summarizeStructuredElements } from './extractors/artifact-envelope.js';\nimport { pickFreeProxy, TieredProxyManager } from './proxy.js';\nimport type { ProxyTierConfig } from './proxy.js';\nimport { infiniteScrollToBottom, extractIframeContent, pierceShadowDom, injectFingerprintOverrides } from './stealth/human-behavior.js';\nimport { checkSeo } from './seo-checker.js';\nimport { auditColorContrast } from './color-contrast.js';\nimport { detectFeatureFlags } from './feature-flag-detector.js';\nimport { detectLanguage } from './language-detector.js';\nimport { detectForms } from './form-detector.js';\nimport { auditAccessibility } from './accessibility-auditor.js';\nimport { RedirectRegistry } from './redirect-tracker.js';\nimport { DeadLinkTracker } from './dead-link-detector.js';\nimport { screensToSitemapUrls, writeSitemap } from './sitemap-writer.js';\nimport { generateOpenApiSpec, specToYaml } from './openapi-generator.js';\nimport { WebhookNotifier } from './webhook-notifier.js';\nimport { generatePlaywrightTest } from './playwright-recorder.js';\nimport { enumerateDropdowns } from './dropdown-enumerator.js';\nimport { probeCrudFlows } from './crud-interaction.js';\nimport { crawlFiltersAndPagination } from './filter-pagination-crawler.js';\nimport { probeMultiContext } from './multi-context-handler.js';\nimport { probeAdvancedUI } from './advanced-ui-probes.js';\nimport { ScreenTransitionGraph, simHash32 } from './state-graph.js';\nimport { crawlNestedContexts } from './nested-window-crawler.js';\nimport { crawlShadowDom } from './shadow-dom-crawler.js';\nimport { crawlAccessibilityTree } from './accessibility-tree-crawler.js';\nimport { collectPerfMetrics } from './performance-metrics.js';\nimport { inspectServiceWorker } from './service-worker-interceptor.js';\n\nasync function getCrawlTuning() {\n const { getSystemConfig } = await import('@detiq/core');\n const cfg = await getSystemConfig('crawl_tuning');\n return {\n navTimeoutMs: parseInt(String(cfg?.navTimeoutMs ?? '15000'), 10),\n defaultTimeoutMs: parseInt(String(cfg?.defaultTimeoutMs ?? '2000'), 10),\n userAgent: String(cfg?.userAgent ?? 'ZeTa-Crawler/1.0 (+https://zeta.taodigitalsolutions.com/crawler)'),\n };\n}\n\n// Module-level cache for per-crawl LLM config \u2014 avoids redundant DB round-trips inside per-page loops.\n// Keyed by tenantId so multi-tenant workers don't share configs across tenants.\nconst _crawlLLMCache = new Map<string, any>();\nasync function getCachedCrawlLLM(tenantId: string): Promise<any> {\n if (_crawlLLMCache.has(tenantId)) return _crawlLLMCache.get(tenantId);\n const cfg = await getTaskAgentLLMConfig(tenantId, 'crawl').catch(() => null);\n if (cfg) _crawlLLMCache.set(tenantId, cfg);\n return cfg;\n}\n\nfunction getGitInfo(): { branch: string; commit: string } {\n try {\n const branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8', timeout: 3000 }).trim();\n const commit = execSync('git rev-parse HEAD', { encoding: 'utf8', timeout: 3000 }).trim().slice(0, 12);\n return { branch: branch || 'main', commit };\n } catch {\n return { branch: 'main', commit: '' };\n }\n}\n\ninterface PerformanceMetric {\n url: string;\n screenName: string;\n lcp?: number;\n fcp?: number;\n ttfb?: number;\n cls?: number;\n}\n\nexport interface DiscoveredLinkMeta {\n url: string;\n text?: string;\n landmark?: string;\n source: 'DOM' | 'AI' | 'INTERACTIVE';\n}\n\nconst ALLOWED_NUMERIC_PATHS = new Set(['/2fa', '/404', '/500', '/403', '/401']);\n\n// Seed path patterns compiled for the active crawl. Set by crawlProject() at the\n// start of each run. All isUsefulNavigationUrl() calls share this for the duration.\nlet _activeSeedPatterns: RegExp[] = [];\nconst UUID_PATH_SEGMENT_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst CUID_PATH_SEGMENT_RE = /^c[a-z0-9]{20,}$/i;\n// Match 4+ digit pure numeric IDs only \u2014 aligns with canonicalize()'s /\\d{4,}/ threshold.\n// 1-3 digit segments (page/2/, /tag/books/page/3/) are valid pagination \u2014 do NOT skip them.\nconst NUMERIC_ID_PATH_SEGMENT_RE = /^\\d{4,}$/;\nconst COMPOUND_NUMERIC_ID_PATH_SEGMENT_RE = /^\\d+-\\d+$/;\n\nfunction normalizePathForNumericGuard(pathname: string): string {\n const normalized = pathname.replace(/\\/+$/, '') || '/';\n return normalized;\n}\n\nfunction isGeneratedPathSegment(segment: string): boolean {\n return UUID_PATH_SEGMENT_RE.test(segment)\n || CUID_PATH_SEGMENT_RE.test(segment)\n || COMPOUND_NUMERIC_ID_PATH_SEGMENT_RE.test(segment)\n || NUMERIC_ID_PATH_SEGMENT_RE.test(segment);\n}\n\nfunction isGeneratedDynamicPath(pathname: string): boolean {\n const normalized = normalizePathForNumericGuard(pathname);\n if (ALLOWED_NUMERIC_PATHS.has(normalized)) return false;\n\n // Parent-route agnostic: any generated ID-like segment can create hundreds of\n // duplicate detail/fallback screens under different sections of the app.\n return normalized.split('/').filter(Boolean).some(isGeneratedPathSegment);\n}\n\n// File extensions that trigger browser downloads rather than page renders.\n// URLs ending with these are skipped from the BFS queue entirely.\nconst DOWNLOAD_EXT_RE = /\\.(pdf|zip|gz|tar|rar|7z|exe|dmg|pkg|deb|rpm|msi|apk|ipa|doc|docx|xls|xlsx|ppt|pptx|csv|json|xml|yaml|yml|txt|log|sql|db|sqlite|mp4|mp3|avi|mov|mkv|webm|wav|ogg|flac|jpg|jpeg|png|gif|bmp|svg|webp|ico|woff|woff2|ttf|eot|otf|bin|iso|img|vhd|vmdk)(\\?.*)?$/i;\n\n// API endpoint path patterns \u2014 these return data (JSON/CSV/binary), not rendered pages.\n// Crawling them triggers file downloads and wastes BFS slots.\nconst API_PATH_RE = /^\\/api\\//i;\n\n// Export/download path segments that appear in apps \u2014 these return file data even without\n// a file extension in the URL (e.g. /admin/exports/report, /download/invoice/123).\nconst EXPORT_PATH_RE = /\\/(exports?|downloads?|export-csv|export-pdf|export-excel|download-report|generate-report|report-download)(\\/|$|\\?)/i;\n\nfunction isUsefulNavigationUrl(href: string, siteOrigin: string): boolean {\n try {\n const u = new URL(href);\n if (!sameSite(u.toString(), siteOrigin)) return false;\n if (/\\/(logout|logged-out|signout|sign-out)(\\/|$|\\?)/i.test(u.pathname)) return false;\n // Bypass CUID/UUID guard for seed path patterns declared by the caller.\n // _activeSeedPatterns is set per-crawl by crawlProject.\n if (isGeneratedDynamicPath(u.pathname) && !_activeSeedPatterns.some(re => re.test(u.pathname))) return false;\n if (DOWNLOAD_EXT_RE.test(u.pathname)) return false;\n if (API_PATH_RE.test(u.pathname)) return false;\n if (EXPORT_PATH_RE.test(u.pathname)) return false;\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Compile seedPathPatterns (e.g., ['/projects/{id}/tests']) into RegExp matchers.\n * {id} matches any single path segment (CUID, UUID, numeric, slug, etc.).\n * Example: '/projects/{id}/tests' \u2192 /^\\/projects\\/[^/]+\\/tests(\\/.*)?$/i\n */\nfunction buildSeedPatternRegexes(patterns: string[]): RegExp[] {\n return patterns.map((p) => {\n const parts = p.split('{id}').map(part => part.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&'));\n const body = parts.join('[^/]+');\n return new RegExp(`^${body}(/.*)?$`, 'i');\n });\n}\n\ntype AuthFlowType = 'public' | 'login' | 'register' | 'password_reset' | 'verification' | 'invite' | 'session_recovery';\ntype AuthDiscoverySource = 'entry' | 'seed_path' | 'page_link' | 'auth_click';\ntype AuthDiscoveryProgress = (pct: number, step: string) => void | Promise<void>;\ntype AuthDiscoveryOptions = {\n appUrl: string;\n tenantId: string;\n projectId: string;\n jobId?: string;\n screenshotDir?: string;\n storageConfig?: any;\n};\n\nconst AUTH_DISCOVERY_MAX_SCREENS = parseInt(process.env.CRAWLER_AUTH_DISCOVERY_MAX_SCREENS ?? '') || 36;\nconst AUTH_DISCOVERY_MAX_QUEUE = parseInt(process.env.CRAWLER_AUTH_DISCOVERY_MAX_QUEUE ?? '') || 48;\nconst AUTH_DISCOVERY_MAX_CLICKS_PER_PAGE = parseInt(process.env.CRAWLER_AUTH_DISCOVERY_MAX_CLICKS_PER_PAGE ?? '') || 6;\nconst AUTH_DISCOVERY_PATHS = [\n '/',\n '/login', '/log-in', '/signin', '/sign-in', '/auth', '/auth/login', '/account/login', '/user/login', '/app/login',\n '/register', '/signup', '/sign-up', '/create-account', '/join',\n '/forgot-password', '/forgot', '/password/forgot', '/reset-password', '/password/reset',\n '/verify-email', '/invite',\n '/pricing', '/contact', '/about', '/help', '/docs',\n];\nconst AUTH_PATH_RE = /\\/(login|log-in|signin|sign-in|auth|oauth|sso|account\\/login|user\\/login|app\\/login|register|signup|sign-up|create-account|forgot|reset|password|verify-email|invite)(\\/|$|\\?)/i;\nconst PUBLIC_PATH_RE = /\\/($|pricing|contact|about|help|docs|features|security|privacy|terms)(\\/|$|\\?)/i;\n\nfunction compactSlug(input: string, fallback = 'state'): string {\n const slug = input.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 48);\n return slug || fallback;\n}\n\nfunction titleFromUrl(url: string, fallback = 'Page'): string {\n try {\n const u = new URL(url);\n const parts = u.pathname.split('/').filter(Boolean);\n if (parts.length === 0) return 'Home';\n return parts\n .slice(-2)\n .join(' ')\n .replace(/[-_]+/g, ' ')\n .replace(/\\b\\w/g, (m) => m.toUpperCase());\n } catch {\n return fallback;\n }\n}\n\nfunction flowTypeForUrlOrText(value: string): AuthFlowType {\n const v = value.toLowerCase();\n if (/(forgot|reset|password)/.test(v)) return 'password_reset';\n if (/(register|signup|sign up|create account|join)/.test(v)) return 'register';\n if (/(verify|verification|otp|mfa|2fa|invite)/.test(v)) return v.includes('invite') ? 'invite' : 'verification';\n if (/(session-expired|expired|unauthorized|forbidden|401|403|logout|logged-out)/.test(v)) return 'session_recovery';\n if (/(login|log in|signin|sign in|auth|sso|oauth)/.test(v)) return 'login';\n return 'public';\n}\n\nfunction shouldSeedAuthDiscoveryUrl(url: string, origin: string): boolean {\n try {\n const u = new URL(url);\n if (!sameSite(u.toString(), origin)) return false;\n if (/\\/(logout|logged-out|signout|sign-out|delete|remove|destroy)(\\/|$|\\?)/i.test(u.pathname)) return false;\n return AUTH_PATH_RE.test(u.pathname) || PUBLIC_PATH_RE.test(u.pathname);\n } catch {\n return false;\n }\n}\n\nfunction normalizeAuthUrl(url: string): string {\n try {\n const u = new URL(url);\n u.hash = '';\n return `${u.origin}${u.pathname.replace(/\\/$/, '') || '/'}${u.search}`;\n } catch {\n return url;\n }\n}\n\nasync function capturePageHtml(page: any): Promise<string | null> {\n let html: string | null = null;\n\n try {\n if (typeof page.content === 'function') {\n const raw = await page.content();\n if (typeof raw === 'string' && raw.trim()) html = raw;\n }\n } catch (err: any) {\n logger.warn({ err: String(err?.message ?? err) }, '[crawler] page.content() failed; trying DOM evaluate fallback');\n }\n\n if (!html) {\n try {\n html = await page.evaluate(() => {\n const type = document.doctype;\n const doctype = type\n ? '<!DOCTYPE ' + type.name +\n (type.publicId ? ' PUBLIC \"' + type.publicId + '\"' : '') +\n (type.systemId ? ' \"' + type.systemId + '\"' : '') +\n '>'\n : '<!DOCTYPE html>';\n return doctype + '\\n' + (document.documentElement?.outerHTML ?? document.body?.outerHTML ?? '');\n });\n if (typeof html !== 'string' || !html.trim()) html = null;\n } catch (err: any) {\n logger.warn({ err: String(err?.message ?? err) }, '[crawler] DOM snapshot capture failed');\n return null;\n }\n }\n\n if (!html) return null;\n\n // Inline all accessible stylesheets so the snapshot renders correctly offline\n // (srcDoc iframes have a null origin \u2014 external CSS loads fail cross-origin).\n try {\n html = await page.evaluate(() => {\n // Strip script tags \u2014 execution is blocked by CSP/sandbox anyway; removing reduces size and avoids leaking inline tokens.\n document.querySelectorAll('script').forEach((s: any) => s.remove());\n for (const sheet of Array.from(document.styleSheets)) {\n try {\n // cssRules throws SecurityError for cross-origin sheets \u2014 skip those\n const cssText = Array.from(sheet.cssRules).map((r: any) => r.cssText).join('\\n');\n const style = document.createElement('style');\n style.textContent = cssText;\n const owner = sheet.ownerNode as Element | null;\n owner?.replaceWith(style);\n } catch { /* cross-origin CDN sheet \u2014 leave <link> in place */ }\n }\n const doctype = (() => {\n const dt = document.doctype;\n return dt ? `<!DOCTYPE ${dt.name}>` : '<!DOCTYPE html>';\n })();\n return doctype + '\\n' + (document.documentElement?.outerHTML ?? '');\n });\n if (typeof html !== 'string' || !html.trim()) html = null;\n } catch (err: any) {\n logger.warn({ err: String(err?.message ?? err) }, '[crawler] CSS inlining failed; using raw HTML');\n // html already has the raw value from page.content() \u2014 usable as-is\n }\n\n return html;\n}\n\n/** Launch Chrome on a random CDP port and return its WebSocket debugger URL. */\nasync function launchChromeCDP(\n execPath: string,\n extraArgs: string[],\n proxy?: { server: string; username?: string; password?: string },\n useStealthPlugin = true,\n): Promise<{ wsUrl: string; proc: any }> {\n // Use a random port in 9200-9900 range to avoid clashes between concurrent crawls.\n const port = 9200 + Math.floor(Math.random() * 700);\n\n // Use stealthChromium (playwright-extra + puppeteer-extra-plugin-stealth) by default.\n // Pass useStealthPlugin=false to opt out for a specific crawl job (opts.stealth === false).\n const launcher = useStealthPlugin ? stealthChromium : chromium;\n const browserServer = await launcher.launchServer({\n headless: true,\n executablePath: execPath,\n // Use Playwright's native proxy option \u2014 it handles 407 auth challenges automatically.\n // The --proxy-server Chrome flag does NOT support credentials with special chars (commas).\n ...(proxy ? { proxy } : {}),\n args: [\n ...extraArgs,\n `--remote-debugging-port=${port}`,\n '--remote-allow-origins=*',\n '--no-first-run',\n '--no-default-browser-check',\n ],\n });\n\n // Poll until Chrome's debug port is ready (up to 10 s).\n const deadline = Date.now() + 10_000;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, 300));\n try {\n const res = await fetch(`http://127.0.0.1:${port}/json/version`);\n if (res.ok) {\n const { webSocketDebuggerUrl } = await res.json() as { webSocketDebuggerUrl: string };\n return { wsUrl: webSocketDebuggerUrl, proc: browserServer };\n }\n } catch { /* not ready */ }\n }\n await browserServer.close();\n throw new Error(`Chrome failed to open CDP port ${port} within 10 s`);\n}\n\n/**\n * Lightweight pre-crawl link discovery: loads the app URL in a headless (proxy-aware) browser\n * and returns same-site `<a href>` links. Complements sitemap discovery for SPA/app sites that\n * have no sitemap.xml. Best-effort \u2014 returns [] on any failure (bot wall, timeout, etc.).\n * chromium.launch({ proxy }) handles proxy 407 auth itself (same client), so no CDP handler needed.\n */\nexport async function discoverLinksViaBrowser(\n appUrl: string,\n opts?: { proxyUrl?: string; maxLinks?: number },\n): Promise<string[]> {\n let proxy: { server: string; username?: string; password?: string } | undefined;\n const purl = opts?.proxyUrl;\n if (purl && purl !== 'auto') {\n const m = purl.match(/^(https?|socks5?):\\/\\/(?:([^:@]*)(?::([^@]*))?@)?(.+)$/);\n if (m) {\n const [, scheme, user, pass, hostPort] = m;\n proxy = user\n ? { server: `${scheme}://${hostPort}`, username: decodeURIComponent(user), password: decodeURIComponent(pass ?? '') }\n : { server: `${scheme}://${hostPort}` };\n } else {\n proxy = { server: purl };\n }\n }\n let executablePath: string | undefined;\n try { executablePath = chromium.executablePath(); } catch { /* fall back to CHROME_PATH */ }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let browser: any = null;\n try {\n browser = await chromium.launch({\n headless: true,\n ...(executablePath ? { executablePath } : {}),\n ...(proxy ? { proxy } : {}),\n args: ['--no-sandbox', '--disable-dev-shm-usage'],\n });\n const page = await browser.newPage();\n await page.goto(appUrl, { waitUntil: 'networkidle', timeout: 30_000 }).catch(() => { });\n await page.waitForTimeout(2_500); // let SPA / Web Components hydrate before scraping links\n const hrefs: string[] = await page.evaluate((origin: string) => {\n const found = new Set<string>();\n const walk = (root: Document | ShadowRoot | Element) => {\n (root as any).querySelectorAll('a[href]').forEach((a: any) => {\n const h: string = a.href || a.getAttribute('href') || '';\n if (h && (h.startsWith(origin) || h.startsWith('/'))) found.add(h);\n });\n (root as any).querySelectorAll('*').forEach((el: any) => {\n if (el.shadowRoot) walk(el.shadowRoot);\n });\n };\n walk(document);\n return [...found];\n }, new URL(appUrl).origin).catch(() => [] as string[]);\n return [...new Set(hrefs.filter((h) => sameSite(h, appUrl)))].slice(0, opts?.maxLinks ?? 500);\n } catch {\n return [];\n } finally {\n if (browser) await browser.close().catch(() => { });\n }\n}\n\n/**\n * Run a Lighthouse audit against a URL and return category scores (0-100 integers).\n * Requires ENABLE_LIGHTHOUSE=true env var \u2014 disabled by default to avoid slowing crawls.\n * Returns null on any error or when disabled.\n */\nasync function runLighthouse(url: string): Promise<{\n perf: number; a11y: number; seo: number; bp: number; report: object;\n} | null> {\n if (!process.env.ENABLE_LIGHTHOUSE) return null;\n try {\n const { default: lighthouse } = await import('lighthouse');\n const chromeLauncher = await import('chrome-launcher');\n const chrome = await chromeLauncher.launch({\n chromeFlags: ['--headless', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage'],\n });\n try {\n const result = await lighthouse(url, {\n port: chrome.port,\n output: 'json',\n logLevel: 'error',\n onlyCategories: ['performance', 'accessibility', 'seo', 'best-practices'],\n } as any);\n if (!result?.lhr?.categories) return null;\n const cats = result.lhr.categories as Record<string, { score: number | null }>;\n const score = (key: string) => Math.round((cats[key]?.score ?? 0) * 100);\n return {\n perf: score('performance'),\n a11y: score('accessibility'),\n seo: score('seo'),\n bp: score('best-practices'),\n report: result.lhr as object,\n };\n } finally {\n await chrome.kill();\n }\n } catch (err) {\n console.warn('[crawler] Lighthouse run failed (non-fatal):', err);\n return null;\n }\n}\n\nconst ElementSchema = z.object({\n elements: z.array(z.object({\n meaning: z.string(),\n role: z.string(),\n expectedData: z.string().optional(),\n })),\n});\n\nconst LinksSchema = z.object({\n links: z.array(z.string()),\n});\n\nconst TwoFASchema = z.object({\n has2FA: z.boolean(),\n fieldLabel: z.string().optional(),\n});\n\n// Shared across all crawl phases (lite-worker, main BFS, P3a, P6).\n// PHP/legacy apps render session-expired content inline without URL redirect.\nconst INLINE_AUTH_WALL_RE = /your login session (was|has been) expired|session (has )?expired[^.]*click|please (log ?in|sign ?in) to continue|you (are|were) logged out|your session has timed out/i;\n\nexport async function crawlProject(opts: {\n tenantId: string;\n projectId: string;\n appUrl: string;\n /** The viewport used for this crawl pass */\n viewport?: 'DESKTOP' | 'MOBILE_PORTRAIT' | 'TABLET';\n credentials?: Credentials;\n /** Playwright storageState JSON string \u2014 if present, session is restored and AI login is skipped. */\n storageState?: string;\n screenshotDir?: string;\n /** Cloud storage config for immediate screenshot upload. If set, screenshots are uploaded to cloud immediately after capture and cloudUrl is persisted. */\n storageConfig?: { provider: string; bucket: string; region?: string; accountId?: string; endpointUrl?: string; accessKeyId?: string; secretAccessKey?: string; prefix?: string; publicUrl?: string } | null;\n /** When true, run a fast URL-only discovery crawl \u2014 skips screenshots, DB saves, and AI element extraction. Returns discoveredUrls in the result object. */\n discoveryMode?: boolean;\n maxScreens?: number;\n /** Seed URLs added to the initial crawl queue \u2014 link discovery still runs from each page. */\n startUrls?: string[];\n /** When provided, crawl ONLY these exact URLs (no link-following, no full screen clear). Used for selected-screen recrawl. */\n selectiveUrls?: string[];\n /**\n * URL path patterns that bypass the CUID/UUID generated-ID filter during BFS link discovery.\n * Use {id} as a placeholder for any generated path segment (CUID, UUID, numeric ID, etc.).\n * Example: ['/projects/{id}/tests', '/workspaces/{id}/settings']\n * Without this, all URLs containing generated IDs are silently skipped by the BFS.\n */\n seedPathPatterns?: string[];\n /** When true, run the interactive probe after static crawl to capture real validation errors, toasts, and modals. */\n interactive?: boolean;\n /** Optional abort signal \u2014 abort() cancels the crawl between page navigations. */\n abortSignal?: AbortSignal;\n /** Platform job ID \u2014 stored on screens so we can diff which were found in each crawl. */\n jobId?: string;\n /** Device profiles to capture screenshots for after the main DESKTOP crawl.\n * Values: 'MOBILE_PORTRAIT' | 'TABLET'\n * The main crawl always runs as DESKTOP. Extra profiles trigger a screenshot-only pass.\n */\n deviceProfiles?: string[];\n /** HTTP Basic Auth credentials \u2014 injected as Authorization header on same-origin requests. */\n httpBasicUsername?: string;\n httpBasicPassword?: string;\n /** Bearer/API token \u2014 injected as a request header and into localStorage. Skips AI login. */\n authToken?: string;\n /** Header name for authToken (default: 'Authorization'). */\n authTokenHeader?: string;\n /** Prefix for authToken value (default: 'Bearer '). */\n authTokenPrefix?: string;\n /** CAPTCHA solving API key (2captcha or CapSolver). */\n captchaSolverApiKey?: string;\n /** CAPTCHA solving service provider (default: '2captcha'). */\n captchaSolverProvider?: '2captcha' | 'capsolver';\n /**\n * Path to a Chrome user data directory for profile inheritance.\n * When set, the crawler exports the existing session from this profile and injects it,\n * so the agent is already logged in. Works for local/self-hosted deployments only.\n * Ignored on cloud/Docker (headless env cannot open another Chrome instance safely).\n */\n chromeProfilePath?: string;\n /** MailSlurp API key for email OTP auto-retrieval (GAP 5). */\n mailslurpApiKey?: string;\n /** MailSlurp inbox ID to poll for OTP emails (GAP 5). */\n mailslurpInboxId?: string;\n /** SSO provider for ROPC token flow \u2014 'okta' | 'azure_ad' | 'generic_oidc' (GAP 18). */\n ssoProvider?: string;\n /** SSO domain or Azure tenant ID (GAP 18). */\n ssoDomain?: string;\n /** SSO OAuth2 client ID (GAP 18). */\n ssoClientId?: string;\n /** SSO OAuth2 client secret (GAP 18). */\n ssoClientSecret?: string;\n /** SSO scopes (space-separated, default: 'openid profile') (GAP 18). */\n ssoScope?: string;\n /** HTTP/HTTPS/SOCKS5 proxy URL \u2014 e.g. 'http://user:pass@proxy.example.com:8080' or 'socks5://proxy:1080'.\n * Useful for sites that block datacenter IPs (Akamai, Cloudflare Bot Manager). */\n proxyUrl?: string;\n /** Tiered proxy configuration for automatic per-domain escalation (free \u2192 datacenter \u2192 residential \u2192 premium). */\n proxyTiers?: ProxyTierConfig[];\n /** Use Camoufox (Firefox) as a cookie bootstrapper before the main Chromium crawl.\n * Camoufox visits the URL first to solve Cloudflare JS challenges and extract session\n * cookies, which are then injected into the Chromium crawl as storageState.\n * Enable via Project Settings \u2192 Crawl Config \u2192 useFirefox: true. */\n useFirefox?: boolean;\n /** Natural language login instructions for Stagehand AI login. E.g. \"Click Sign In in the nav, fill email, click Continue\". */\n loginInstructions?: string;\n /** Skyvern vision fallback config from workspace settings (overrides SKYVERN_API_URL/KEY env vars). */\n skyvernConfig?: SkyvernConfig;\n /**\n * Max screens to crawl per segment (default 50).\n * After this limit the crawl pauses and remaining URLs are saved so the\n * next job can continue. Total crawl is unlimited \u2014 just runs in multiple jobs.\n */\n segmentSize?: number;\n /** URLs still queued from a previous segment \u2014 injected by the job-queue auto-continuation. */\n resumeUrls?: string[];\n /** Segment number (1-based) \u2014 used for progress display only. */\n segmentIndex?: number;\n /** Seed the crawl queue from the project's sitemap.xml, in addition to link-following. */\n useSitemap?: boolean;\n /** Explicit sitemap URL override \u2014 defaults to `${origin}/sitemap.xml` when useSitemap is set. */\n sitemapUrl?: string;\n /** Crawl queue traversal order. Default BFS \u2014 unchanged behavior from before this option existed. */\n traversalStrategy?: TraversalStrategy;\n /** BEST_FIRST only: URLs containing any of these (case-insensitive) are prioritized. */\n bestFirstKeywords?: string[];\n /** When true, skip URLs disallowed by the site's robots.txt. Default false. */\n respectRobotsTxt?: boolean;\n /** When true, dynamically slow crawl speed when server response latency is high (Scrapy-style AutoThrottle). Default false. */\n autoThrottle?: boolean;\n /** Regex pattern \u2014 only crawl URLs whose path+query match this pattern. */\n urlFilter?: string;\n /** Glob patterns \u2014 only enqueue URLs whose pathname matches at least one (supports * and **). */\n includePatterns?: string[];\n /** Glob patterns \u2014 skip URLs whose pathname matches any of these (supports * and **). */\n excludePatterns?: string[];\n /** Already-captured URLs from a previous failed job \u2014 pre-seeded into visited map so they're never re-crawled. */\n skipUrls?: string[];\n /** DOM hashes collected in a prior segment \u2014 prevents re-screenshotting structurally identical pages across segments. */\n knownDomHashes?: string[];\n /** When false, disables the puppeteer-extra stealth plugin (playwright-extra) for this crawl.\n * Default true \u2014 stealth is applied unless explicitly set to false. */\n stealth?: boolean;\n /** Desktop viewport width in pixels (default: 1440). */\n viewportWidth?: number;\n /** Desktop viewport height in pixels (default: 900). */\n viewportHeight?: number;\n /** Called every 10 successful screen captures with current visited URLs and remaining queue \u2014 used for checkpoint persistence. */\n onCheckpoint?: (visitedUrls: string[], pendingQueue: string[]) => Promise<void>;\n /** Discovery mode only: called after each page with the current set of discovered original URLs \u2014 enables streaming partial results to callers. */\n onUrlsDiscovered?: (urls: string[]) => Promise<void>;\n}, onProgress?: (pct: number, step: string) => Promise<void>) {\n const tuning = await getCrawlTuning();\n\n // Compile seed path patterns for this crawl run. Applied by isUsefulNavigationUrl()\n // to bypass the CUID guard for explicitly declared URL shapes.\n _activeSeedPatterns = buildSeedPatternRegexes(opts.seedPathPatterns ?? []);\n\n if (opts.screenshotDir) await fs.mkdir(opts.screenshotDir, { recursive: true });\n\n // Upload screenshot to cloud storage if configured, returns cloudUrl or undefined\n const uploadToCloud = async (localPath: string, key: string): Promise<string | undefined> => {\n if (!opts.storageConfig) return undefined;\n if (!existsSyncFs(localPath)) return undefined;\n try {\n const { uploadScreenshotToTenantStorage } = await import('@detiq/app-brain');\n return await uploadScreenshotToTenantStorage(opts.storageConfig as any, localPath, key);\n } catch {\n return undefined;\n }\n };\n\n const isDocker = !!process.env.PLAYWRIGHT_IN_DOCKER || process.env.NODE_ENV === 'production';\n\n // Stagehand v3 uses Vercel AI SDK internally. Model format: \"aisdk-provider/model-name\".\n // Each provider maps to a native AI SDK client; OpenAI-compat baseURL used for non-native ones.\n // Provider \u2192 AI SDK prefix mapping:\n // anthropic \u2192 anthropic, openai \u2192 openai, gemini \u2192 google, grok \u2192 xai,\n // groq \u2192 groq (native), openrouter \u2192 openai+baseURL, ollama \u2192 ollama, nvidia \u2192 openai+baseURL\n\n let stagehandModel = config.llmModel.includes('/') ? config.llmModel : `openai/${config.llmModel}`;\n // clientOptions spread into Stagehand model object (apiKey, baseURL, etc.)\n let stagehandModelOpts: Record<string, string | undefined> = {};\n let stagehandConfigured = false;\n let configuredProvider = '';\n\n try {\n // getTaskAgentLLMConfig: tenant config \u2192 platform admin config \u2192 null (proper fallback chain)\n const crawlLLM = await getTaskAgentLLMConfig(opts.tenantId, 'crawl');\n if (crawlLLM) {\n configuredProvider = crawlLLM.provider;\n const hasKey = crawlLLM.apiKey !== undefined && crawlLLM.apiKey !== null;\n const apiKey = hasKey ? crawlLLM.apiKey : undefined;\n const baseUrl = crawlLLM.baseUrl || undefined;\n const m = crawlLLM.model;\n\n if (m && (hasKey || crawlLLM.provider === 'ollama' || crawlLLM.provider === 'bedrock' || crawlLLM.provider === 'vertex')) {\n stagehandConfigured = true;\n switch (crawlLLM.provider) {\n case 'anthropic':\n stagehandModel = m.includes('/') ? m : `anthropic/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'openai':\n stagehandModel = m.includes('/') ? m : `openai/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'gemini':\n stagehandModel = `google/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'grok':\n stagehandModel = `xai/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'openrouter':\n stagehandModel = `openai/${m}`;\n stagehandModelOpts = { ...(apiKey ? { apiKey } : {}), baseURL: baseUrl || process.env.CRAWLER_OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1' };\n break;\n case 'ollama':\n stagehandModel = `ollama/${m}`;\n stagehandModelOpts = { baseURL: baseUrl || process.env.CRAWLER_OLLAMA_BASE_URL || 'http://localhost:11434' };\n break;\n case 'nvidia':\n stagehandModel = `openai/${m.startsWith('openai/') ? m.slice(7) : m}`;\n stagehandModelOpts = { ...(apiKey ? { apiKey } : {}), baseURL: baseUrl || process.env.CRAWLER_NVIDIA_BASE_URL || 'https://integrate.api.nvidia.com/v1' };\n break;\n case 'groq':\n stagehandModel = `groq/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'mistral':\n stagehandModel = `mistral/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'deepseek':\n stagehandModel = `deepseek/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'perplexity':\n stagehandModel = `perplexity/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'togetherai':\n stagehandModel = `togetherai/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'bedrock':\n // Uses AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_REGION from env\n stagehandModel = `bedrock/${m}`;\n stagehandModelOpts = {};\n break;\n case 'vertex':\n // Uses GOOGLE_APPLICATION_CREDENTIALS or GOOGLE_VERTEX_PROJECT from env\n stagehandModel = `vertex/${m}`;\n stagehandModelOpts = {};\n break;\n case 'azure':\n stagehandModel = `azure/${m}`;\n stagehandModelOpts = { ...(apiKey ? { apiKey } : {}), ...(baseUrl ? { baseURL: baseUrl } : {}) };\n break;\n default:\n stagehandModel = `openai/${m}`;\n stagehandModelOpts = { ...(apiKey ? { apiKey } : {}), ...(baseUrl ? { baseURL: baseUrl } : {}) };\n }\n }\n }\n } catch { /* ignore DB errors, fall through to env var below */ }\n\n // Env var fallback \u2014 if DB lookup failed or returned no key\n if (!stagehandConfigured) {\n // Honor STAGEHAND_MODEL env var to determine preferred provider.\n const envModel = process.env.STAGEHAND_MODEL ?? '';\n const preferAnthropic = envModel.includes('claude') || (!envModel && !process.env.OPENAI_API_KEY);\n if (preferAnthropic && process.env.ANTHROPIC_API_KEY) {\n stagehandModelOpts = { apiKey: process.env.ANTHROPIC_API_KEY };\n const defaultAnthropicModel = process.env.CRAWLER_DEFAULT_MODEL ?? 'claude-sonnet-4-6';\n stagehandModel = envModel.includes('/') ? envModel : `anthropic/${envModel || defaultAnthropicModel}`;\n stagehandConfigured = true;\n } else if (process.env.OPENAI_API_KEY) {\n stagehandModelOpts = { apiKey: process.env.OPENAI_API_KEY };\n const defaultOpenaiModel = process.env.CRAWLER_DEFAULT_MODEL ?? 'gpt-4o';\n stagehandModel = envModel.includes('/') ? envModel : `openai/${envModel || defaultOpenaiModel}`;\n stagehandConfigured = true;\n } else if (process.env.ANTHROPIC_API_KEY) {\n stagehandModelOpts = { apiKey: process.env.ANTHROPIC_API_KEY };\n const defaultAnthropicModel2 = process.env.CRAWLER_DEFAULT_MODEL ?? 'claude-sonnet-4-6';\n stagehandModel = envModel.includes('/') ? envModel : `anthropic/${envModel || defaultAnthropicModel2}`;\n stagehandConfigured = true;\n }\n }\n\n const elementLLM = await AppBrain.getTaskLLMConfig(opts.tenantId, 'elementExtraction').catch(() => null);\n const linkLLM = await AppBrain.getTaskLLMConfig(opts.tenantId, 'linkDiscovery').catch(() => null);\n const projectForProfile = await AppBrain.getProjectMap(opts.tenantId, opts.projectId).catch(() => null);\n const profileProjectName = projectForProfile?.name ?? null;\n const profileAppType = projectForProfile?.appType ?? null;\n const domainProfile = classifyDomainProfile({\n appUrl: opts.appUrl,\n projectName: profileProjectName,\n appType: profileAppType,\n seedText: [\n ...(opts.startUrls ?? []),\n opts.loginInstructions ?? '',\n ...(opts.bestFirstKeywords ?? []),\n ].join(' '),\n });\n const routeDecision = chooseCrawlEngines({\n appUrl: opts.appUrl,\n appType: profileAppType,\n hasCredentials: !!opts.credentials,\n hasStorageState: !!opts.storageState,\n hasAuthToken: !!opts.authToken,\n hasSkyvern: !!opts.skyvernConfig,\n hasProxy: !!opts.proxyUrl,\n profile: domainProfile,\n });\n\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'CRAWL_PROFILE',\n payload: { profile: domainProfile, routeDecision },\n }).catch((err: any) => console.warn('[crawler] profile evidence save failed:', err?.message ?? err));\n\n if (!stagehandConfigured && !opts.discoveryMode) {\n // Discovery mode never calls Stagehand AI \u2014 DOM link extraction only.\n // Skip this guard so URL discovery works even without an AI provider configured.\n throw new Error(\n configuredProvider\n ? `No API key configured for provider \"${configuredProvider}\". Go to Workspace \u2192 Settings \u2192 AI Provider.`\n : 'No AI provider configured. Go to Workspace \u2192 Settings \u2192 AI Provider to set up an AI provider for browser crawling.'\n );\n }\n\n // Anti-detect args applied on all platforms.\n // '--disable-blink-features=AutomationControlled' removes navigator.webdriver at the\n // Chromium level \u2014 more reliable than JS overrides alone.\n // '--disable-http2' defeats Akamai/Cloudflare JA3/JA4 TLS fingerprinting on datacenter IPs.\n const stealthArgs = [\n '--disable-blink-features=AutomationControlled',\n '--disable-http2',\n '--lang=en-US,en',\n `--window-size=${opts.viewportWidth ?? 1440},${opts.viewportHeight ?? 900}`,\n '--disable-features=IsolateOrigins,site-per-process',\n ];\n\n const chromeArgs = isDocker\n ? [\n '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu',\n ...stealthArgs,\n ]\n : [...stealthArgs];\n // Resolve proxy: tiered manager > 'auto' free list > explicit URL\n let resolvedProxyUrl = opts.proxyUrl;\n let tieredProxyManager: TieredProxyManager | undefined;\n if (opts.proxyTiers?.length) {\n tieredProxyManager = new TieredProxyManager(opts.proxyTiers);\n const domain = (() => { try { return new URL(opts.appUrl).hostname; } catch { return opts.appUrl; } })();\n resolvedProxyUrl = tieredProxyManager.selectProxy(domain) ?? resolvedProxyUrl;\n logger.info({ domain, proxyUrl: resolvedProxyUrl }, '[crawler] tiered proxy selected');\n } else if (resolvedProxyUrl === 'auto') {\n logger.info('[crawler] proxyUrl=auto: selecting free proxy from public list...');\n resolvedProxyUrl = (await pickFreeProxy()) ?? undefined;\n if (resolvedProxyUrl) {\n logger.info({ proxyUrl: resolvedProxyUrl }, '[crawler] auto-proxy selected');\n } else {\n logger.warn('[crawler] auto-proxy: no working proxy found, proceeding without proxy');\n }\n }\n // Parse proxy URL into Playwright's native proxy format.\n // We do NOT use --proxy-server Chrome arg because:\n // 1. Chrome ignores credentials in --proxy-server URLs (no auth support via flag)\n // 2. Commas in username (DataImpulse country codes) break Chrome's proxy-list parser\n // Playwright's launchServer({ proxy }) handles 407 auth challenges correctly.\n let playwrightProxy: { server: string; username?: string; password?: string } | undefined;\n if (resolvedProxyUrl) {\n try {\n // Manual parse: new URL() chokes on commas in the username part\n const proxyMatch = resolvedProxyUrl.match(/^(https?|socks5?):\\/\\/(?:([^:@]*)(?::([^@]*))?@)?(.+)$/);\n if (proxyMatch) {\n const [, scheme, rawUser, rawPass, hostPort] = proxyMatch;\n const server = `${scheme}://${hostPort}`;\n const username = rawUser ? decodeURIComponent(rawUser) : undefined;\n const password = rawPass ? decodeURIComponent(rawPass) : undefined;\n playwrightProxy = username ? { server, username, password } : { server };\n logger.info({ server, hasAuth: !!username }, '[crawler] proxy configured (Playwright native)');\n } else {\n playwrightProxy = { server: resolvedProxyUrl };\n }\n } catch {\n playwrightProxy = { server: resolvedProxyUrl };\n }\n }\n\n // Stagehand 3.x uses chrome-launcher under the hood, which fails in Docker\n // because it doesn't pass --no-sandbox and uses a different spawn environment.\n // Fix: spawn Chrome ourselves with the right flags, get its CDP WS URL,\n // then connect Stagehand to the already-running browser via cdpUrl.\n let executablePath: string | undefined;\n try { executablePath = chromium.executablePath(); } catch { /* use CHROME_PATH */ }\n\n if (!executablePath) throw new Error('No Chrome binary found. Set CHROME_PATH or install Playwright browsers.');\n\n // GAP 3: Chrome Profile Inheritance \u2014 local/self-hosted deployments only.\n // Launch a temporary persistent context to export the storageState from the user's Chrome profile,\n // then inject it so the normal session-restore path handles auth (no AI login needed).\n let effectiveStorageState = opts.storageState;\n if (opts.chromeProfilePath && !isDocker) {\n logger.info({ chromeProfilePath: opts.chromeProfilePath }, '[crawler] Exporting session from Chrome profile');\n try {\n const tempCtx = await chromium.launchPersistentContext(opts.chromeProfilePath, {\n headless: true,\n args: [...chromeArgs, '--no-first-run', '--no-default-browser-check'],\n executablePath,\n });\n const exportedState = await tempCtx.storageState();\n await tempCtx.close().catch(() => { });\n if ((exportedState.cookies?.length ?? 0) > 0 || (exportedState.origins?.length ?? 0) > 0) {\n effectiveStorageState = JSON.stringify(exportedState);\n logger.info({ cookies: exportedState.cookies?.length ?? 0, origins: exportedState.origins?.length ?? 0 }, '[crawler] Chrome profile session exported and injected');\n } else {\n logger.warn('[crawler] Chrome profile had no session data \u2014 continuing without profile auth');\n }\n } catch (profileErr) {\n logger.warn({ err: profileErr }, '[crawler] Could not load Chrome profile \u2014 continuing without profile auth');\n }\n } else if (opts.chromeProfilePath && isDocker) {\n logger.warn('[crawler] chromeProfilePath is set but will be ignored in Docker/cloud environments');\n }\n\n // \u2500\u2500 Option 3: Camoufox bootstrap \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Firefox with built-in fingerprint randomisation visits the target first to solve\n // any Cloudflare JS challenge, then we extract the cf_clearance cookie and inject it\n // into the Chromium storageState so Chrome inherits the cleared session.\n if (opts.useFirefox) {\n logger.info('[crawler] useFirefox: launching Camoufox to bootstrap Cloudflare cookies...');\n try {\n // Dynamic import prevents ESM/CJS conflict at API startup when this module is imported\n const { NewBrowser: camoufoxNewBrowser } = await import('camoufox');\n const pw = require('playwright');\n const foxBrowser = await camoufoxNewBrowser(pw, true);\n const foxPage = await foxBrowser.newPage();\n await foxPage.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 30_000 });\n // Give Cloudflare JS challenge up to 8s to complete and set cf_clearance cookie\n await foxPage.waitForTimeout(8_000);\n const foxState = await foxPage.context().storageState();\n await foxBrowser.close().catch(() => { });\n if ((foxState.cookies?.length ?? 0) > 0) {\n // Merge Camoufox cookies into any existing storageState\n if (effectiveStorageState) {\n try {\n const existing = JSON.parse(effectiveStorageState);\n const merged = { ...existing, cookies: [...(existing.cookies ?? []), ...foxState.cookies] };\n effectiveStorageState = JSON.stringify(merged);\n } catch {\n effectiveStorageState = JSON.stringify(foxState);\n }\n } else {\n effectiveStorageState = JSON.stringify(foxState);\n }\n logger.info({ cookies: foxState.cookies.length }, '[crawler] Camoufox bootstrap complete \u2014 cf_clearance injected into Chromium');\n } else {\n logger.warn('[crawler] Camoufox returned no cookies \u2014 continuing without bootstrap');\n }\n } catch (foxErr) {\n logger.warn({ err: foxErr }, '[crawler] Camoufox bootstrap failed \u2014 continuing without it');\n }\n }\n\n const { wsUrl: cdpUrl, proc: chromeProc } = await launchChromeCDP(executablePath, chromeArgs, playwrightProxy, opts.stealth !== false);\n\n // Accumulate token usage from Stagehand's internal LLM calls (extract/act/observe).\n // Stagehand doesn't expose per-call usage externally; we parse it from its logger.\n let stagehandPromptTokens = 0;\n let stagehandCompletionTokens = 0;\n const stagehandLogger = (line: { category?: string; message: string; auxiliary?: Record<string, { value: string; type: string }> }) => {\n if (line.message === 'response' && line.auxiliary?.response?.value) {\n try {\n const resp = JSON.parse(line.auxiliary.response.value);\n if (resp?.usage) {\n stagehandPromptTokens += resp.usage.prompt_tokens ?? 0;\n stagehandCompletionTokens += resp.usage.completion_tokens ?? 0;\n }\n } catch { /* ignore parse errors */ }\n }\n };\n\n const stagehand = new Stagehand({\n env: 'LOCAL',\n model: { modelName: stagehandModel as any, ...stagehandModelOpts },\n serverCache: true,\n verbose: 1,\n logger: stagehandLogger,\n localBrowserLaunchOptions: { cdpUrl, headless: true },\n domSettleTimeout: parseInt(process.env.CRAWLER_DOM_SETTLE_TIMEOUT_MS ?? '') || 2000,\n });\n\n await stagehand.init();\n await onProgress?.(5, 'Browser launched');\n // In Stagehand v3, stagehand.page is undefined when connected via CDP.\n // Use resolvePage() to get the active V3Page (which is a full Playwright proxy).\n const page = await (stagehand as any).resolvePage();\n // Cap all Playwright operations so one stuck page can't freeze the crawl.\n try { page.setDefaultTimeout(tuning.defaultTimeoutMs || 45_000); } catch { /* proxy may not expose this */ }\n try { page.setDefaultNavigationTimeout(tuning.navTimeoutMs || 30_000); } catch { /* proxy may not expose this */ }\n // Stagehand V3Page proxy only supports the 'console' event (page.on throws for others).\n // rawPage will be wired to a real Playwright Page via the CDP connection established below.\n // Declared as `let` so the network-observer block can populate it.\n let rawPage: any = null; // populated after playwrightBrowser connects\n\n // \u2500\u2500 Proxy auth \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Proxy 407 auth is answered via a CDP Fetch.continueWithAuth handler installed on\n // the connectOverCDP page below (see \"proxy auth via CDP Fetch handler\"). page.authenticate()\n // is a Puppeteer API \u2014 it does NOT exist on Playwright's connectOverCDP page and throws,\n // leaving 407 challenges unanswered (net::ERR_INVALID_AUTH_CREDENTIALS).\n\n // \u2500\u2500 Stealth: defeat bot detection (Cloudflare, Akamai, DataDome) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // addInitScript runs in every new document context BEFORE any page JS executes.\n // This overrides navigator.webdriver before anti-bot scripts can read it.\n await page.addInitScript(() => {\n // Core automation flags\n Object.defineProperty(navigator, 'webdriver', { get: () => undefined });\n Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });\n\n // Realistic plugin list (Cloudflare checks length > 0)\n const fakePlugins = ['PDF Viewer', 'Chrome PDF Viewer', 'Chromium PDF Viewer', 'Microsoft Edge PDF Viewer', 'WebKit built-in PDF'];\n Object.defineProperty(navigator, 'plugins', {\n get: () => Object.assign(fakePlugins.map((name, i) => ({ name, filename: 'internal-pdf-viewer', description: '', length: 1, item: () => null, namedItem: () => null })), { item: (i: number) => null, namedItem: () => null, refresh: () => { } }),\n });\n\n // @ts-ignore\n window.chrome = { runtime: {}, loadTimes: () => ({}), csi: () => ({}), app: {} };\n\n // Cloudflare checks navigator.permissions.query \u2014 headless returns \"denied\", real = \"prompt\"\n const origQuery = window.navigator.permissions?.query?.bind(navigator.permissions);\n if (origQuery) {\n // @ts-ignore\n navigator.permissions.query = (params: any) =>\n params?.name === 'notifications'\n ? Promise.resolve({ state: 'prompt', onchange: null } as PermissionStatus)\n : origQuery(params);\n }\n\n // Cloudflare checks Notification.permission \u2014 \"denied\" = bot signal\n try { Object.defineProperty(Notification, 'permission', { get: () => 'default' }); } catch { }\n\n // navigator.connection \u2014 absence signals headless\n // @ts-ignore\n if (!navigator.connection) Object.defineProperty(navigator, 'connection', { get: () => ({ rtt: 50, downlink: 10, effectiveType: '4g', saveData: false }) });\n\n // Remove Playwright/CDP globals leaked into page context\n // @ts-ignore\n delete window.__playwright; delete (window as any).__pw_manual; delete (window as any).__PW_inspect;\n });\n\n // \u2500\u2500 Web Vitals capture: LCP + CLS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // LCP/CLS entries are only delivered to a PerformanceObserver registered with\n // buffered:true \u2014 performance.getEntriesByType(...) after the fact returns [].\n // addInitScript re-runs on every new document (survives page.goto navigations),\n // so the observers are always registered before the page paints. The crawl loop\n // reads the stashed values off window.__zetaLCP / window.__zetaCLS after load.\n await page.addInitScript(() => {\n try {\n // @ts-ignore \u2014 custom stash properties\n window.__zetaLCP = null;\n // @ts-ignore\n window.__zetaCLS = 0;\n new PerformanceObserver((list) => {\n const entries = list.getEntries();\n const last = entries[entries.length - 1] as any;\n // @ts-ignore\n if (last) window.__zetaLCP = last.startTime;\n }).observe({ type: 'largest-contentful-paint', buffered: true });\n new PerformanceObserver((list) => {\n for (const entry of list.getEntries() as any[]) {\n // Ignore shifts triggered by user input (crawler clicks/scrolls).\n // @ts-ignore\n if (!entry.hadRecentInput) window.__zetaCLS += entry.value;\n }\n }).observe({ type: 'layout-shift', buffered: true });\n } catch { /* older engines without these entry types \u2014 leave stashed values at defaults */ }\n });\n\n // \u2500\u2500 API/Bearer token injection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // If an authToken is provided, inject it as an HTTP header on every request\n // and store it in localStorage so client-side code can pick it up.\n if (opts.authToken) {\n const headerName = opts.authTokenHeader ?? 'Authorization';\n const prefix = opts.authTokenPrefix ?? 'Bearer ';\n await page.setExtraHTTPHeaders({ [headerName]: `${prefix}${opts.authToken}` });\n await page.addInitScript((token: string) => {\n localStorage.setItem('auth_token', token);\n localStorage.setItem('access_token', token);\n localStorage.setItem('token', token);\n }, opts.authToken);\n }\n\n // \u2500\u2500 Web Vitals capture: CLS via buffered PerformanceObserver \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // CLS entries are only delivered to a PerformanceObserver; this init script\n // re-runs on every new document. LCP is captured per-page in the crawl loop.\n await page.addInitScript(() => {\n try {\n // @ts-ignore \u2014 custom stash property\n window.__zetaCLS = 0;\n new PerformanceObserver((list) => {\n for (const entry of list.getEntries() as any[]) {\n // Ignore shifts triggered by user input (crawler clicks/scrolls).\n // @ts-ignore\n if (!entry.hadRecentInput) window.__zetaCLS += entry.value;\n }\n }).observe({ type: 'layout-shift', buffered: true });\n } catch { /* Older engines without layout-shift entry type \u2014 leave at 0 */ }\n });\n\n // Intercept SPA route changes (history.pushState / replaceState) to discover JS-router routes\n // that have no <a href> elements \u2014 common in React Router, Next.js, Vue Router apps.\n await page.addInitScript(() => {\n (window as any).__zetaDiscoveredRoutes = (window as any).__zetaDiscoveredRoutes ?? [];\n const push = history.pushState.bind(history);\n const replace = history.replaceState.bind(history);\n history.pushState = function (data: any, unused: string, url?: string | URL | null) {\n const result = push(data, unused, url);\n if (url && typeof url === 'string') (window as any).__zetaDiscoveredRoutes.push(url);\n return result;\n };\n history.replaceState = function (data: any, unused: string, url?: string | URL | null) {\n const result = replace(data, unused, url);\n if (url && typeof url === 'string') (window as any).__zetaDiscoveredRoutes.push(url);\n return result;\n };\n });\n\n // Inject canvas/WebGL fingerprint overrides + hardware concurrency spoof\n await injectFingerprintOverrides(page).catch(() => { });\n\n // \u2500\u2500 Network interception: capture REST/GraphQL API endpoints \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Stagehand v3's page proxy only supports the 'console' event \u2014 to intercept\n // network requests we connect a second Playwright client to the same CDP URL.\n const capturedApiEndpoints: ApiEndpointObservationInput[] = [];\n // P3a: URLs flagged for re-visit after async content detected (drained after main BFS)\n const revisitQueue: string[] = [];\n // P4: XHR-discovered page URL candidates (relative paths from JSON responses)\n const xhrDiscoveredPaths = new Set<string>();\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let playwrightBrowser: any = null;\n try {\n playwrightBrowser = await chromium.connectOverCDP(cdpUrl);\n const pwContext = playwrightBrowser.contexts()[0];\n if (pwContext) {\n // P4: pass XHR URL discovery callback \u2014 adds relative paths to xhrDiscoveredPaths\n attachNetworkObserver(pwContext, capturedApiEndpoints, (relPath) => xhrDiscoveredPaths.add(relPath));\n // Popup/new-window handler \u2014 fires for every window.open() call.\n // Handles two cases:\n // 1. OAuth/SSO provider windows \u2014 wait for close, then continue login flow.\n // 2. App-generated popups (help, report, lightbox-in-window) \u2014 screenshot + save as screen.\n const OAUTH_PROVIDER_RE = /google\\.|github\\.|microsoft\\.|facebook\\.|twitter\\.|linkedin\\.|okta\\.|auth0\\.|ping\\.|onelogin\\.|sso\\.|oauth\\.|\\/authorize\\?|\\/oauth2\\//i;\n pwContext.on('page', (popup: any) => {\n // Wait for the popup to navigate to a real URL (about:blank initially)\n popup.waitForURL((u: string) => !u.startsWith('about:'), { timeout: 10_000 })\n .then(async () => {\n const popupUrl = popup.url();\n if (OAUTH_PROVIDER_RE.test(popupUrl)) {\n // OAuth flow \u2014 just wait for it to close\n logger.info({ url: popupUrl }, '[crawler] OAuth popup navigated to provider');\n popup.waitForEvent('close', { timeout: 120_000 })\n .then(() => logger.info('[crawler] OAuth popup closed \u2014 SSO flow complete'))\n .catch(() => logger.warn('[crawler] OAuth popup timed out or errored'));\n return;\n }\n // App popup \u2014 capture as a screen (skip API/export/download URLs)\n try {\n const _popupPath = (() => { try { return new URL(popupUrl).pathname; } catch { return ''; } })();\n if (API_PATH_RE.test(_popupPath) || EXPORT_PATH_RE.test(_popupPath) || DOWNLOAD_EXT_RE.test(_popupPath)) return;\n } catch {}\n logger.info({ url: popupUrl }, '[crawler] App popup detected \u2014 capturing');\n try {\n await popup.waitForLoadState('domcontentloaded', { timeout: 10_000 }).catch(() => {});\n await popup.waitForLoadState('networkidle', { timeout: 6_000 }).catch(() => {});\n const popupTitle = await popup.title().catch(() => '');\n const popupName = popupTitle || (() => { try { return new URL(popupUrl).pathname.split('/').filter(Boolean).pop() || 'Popup'; } catch { return 'Popup'; } })();\n const popupHash = popupUrl.replace(/[^a-z0-9]/gi, '').slice(-12);\n const popupShotPath = path.join(opts.screenshotDir ?? '/tmp', `popup-${popupHash}.png`);\n await waitForScreenshotReady(popup, popup);\n await popup.screenshot({ path: popupShotPath, fullPage: false }).catch(() => {});\n const popupScreen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, popupName, popupUrl, opts.jobId, 'LINK_FOLLOW').catch(() => null);\n if (popupScreen) {\n const cloudUrl = await uploadToCloud(popupShotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(popupShotPath)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, popupScreen.id, popupShotPath, popupScreen.version, 'DESKTOP', cloudUrl).catch(() => {});\n // GAP 4: DOM snapshot for popup capture\n const popupDom = await capturePageHtml(popup);\n if (popupDom) {\n const popupDomPath = popupShotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(popupDomPath, popupDom, 'utf8');\n const popupDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(popupDomPath)}`;\n AppBrain.updateScreenDomSnapshot(opts.tenantId, popupScreen.id, popupDomPath, await uploadToCloud(popupDomPath, popupDomKey).catch(() => undefined)).catch(() => {});\n }\n const popupEls = await domFallbackElements(popup, popup).catch(() => []);\n for (const el of popupEls) {\n AppBrain.saveElement(opts.tenantId, opts.projectId, popupScreen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => {});\n }\n logger.info({ url: popupUrl, name: popupName, elementCount: popupEls.length }, '[crawler] App popup screen saved');\n }\n } catch (popupErr: any) {\n logger.warn({ url: popupUrl, err: popupErr?.message }, '[crawler] App popup capture failed \u2014 non-fatal');\n }\n })\n .catch(() => {}); // popup may close before navigating (race condition)\n });\n // Cancel any file downloads triggered by link navigation \u2014 the crawler captures\n // pages, not binary files. Without this, clicking download links opens the browser\n // download UI and stalls the crawl waiting for a page load that never comes.\n pwContext.on('download', (dl: any) => { dl.cancel().catch(() => {}); });\n\n // Route-level interception: immediately abort navigation to known API/export/download\n // paths that would trigger file downloads. Uses URL-only matching (no double-fetch)\n // to avoid the extra network round-trip that was causing \"Failed to fetch\" crashes.\n // The download event handler above catches any remaining downloads that slip through.\n try {\n await pwContext.route('**/*', async (route: any, request: any) => {\n const resourceType: string = request.resourceType?.() ?? '';\n if (resourceType !== 'document') { await route.continue().catch(() => {}); return; }\n try {\n const u = new URL(request.url());\n if (API_PATH_RE.test(u.pathname) || EXPORT_PATH_RE.test(u.pathname) || DOWNLOAD_EXT_RE.test(u.pathname)) {\n logger.info({ url: request.url() }, '[crawler] route: aborting API/export/download navigation');\n await route.abort('failed').catch(() => {});\n return;\n }\n } catch {}\n await route.continue().catch(() => {});\n });\n } catch (routeErr: any) {\n logger.warn({ err: routeErr?.message }, '[crawler] route interception setup failed \u2014 downloads may occur');\n }\n }\n // Wire rawPage to the real Playwright page from this CDP connection.\n // This gives us a true Playwright Page that supports all events (.on('response'), etc.)\n // while `page` (Stagehand) is still used for AI actions (act/extract/observe).\n const pwContext2 = playwrightBrowser?.contexts()?.[0];\n if (pwContext2) {\n const pwPages = pwContext2.pages();\n rawPage = pwPages.find((p: any) => p.url() !== 'about:blank') ?? pwPages[0] ?? rawPage;\n }\n\n // \u2500\u2500 Proxy auth via CDP Fetch handler \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // launchServer({ proxy }) applies the proxy at the Chrome flag level, but its\n // credentials are only honored by Playwright's OWN launching client. Since we\n // drive the browser through a separate connectOverCDP client, the proxy 407 goes\n // unanswered (net::ERR_INVALID_AUTH_CREDENTIALS). Answer it via the CDP Fetch domain,\n // then disable interception \u2014 Chrome caches the proxy credentials for the rest of the session.\n if (playwrightProxy?.username && pwContext2 && rawPage && rawPage !== page) {\n try {\n const proxyCdp = await pwContext2.newCDPSession(rawPage);\n await proxyCdp.send('Fetch.enable', { handleAuthRequests: true, patterns: [{ urlPattern: '*' }] });\n proxyCdp.on('Fetch.requestPaused', (e: any) => {\n proxyCdp.send('Fetch.continueRequest', { requestId: e.requestId }).catch(() => { });\n });\n let proxyAuthed = false;\n proxyCdp.on('Fetch.authRequired', async (e: any) => {\n const isProxy = e.authChallenge?.source === 'Proxy';\n try {\n await proxyCdp.send('Fetch.continueWithAuth', {\n requestId: e.requestId,\n authChallengeResponse: isProxy\n ? { response: 'ProvideCredentials', username: playwrightProxy!.username as string, password: playwrightProxy!.password ?? '' }\n : { response: 'Default' },\n });\n } catch { /* ignore */ }\n if (isProxy && !proxyAuthed) {\n proxyAuthed = true;\n proxyCdp.send('Fetch.disable').catch(() => { });\n }\n });\n logger.info({ server: playwrightProxy.server }, '[crawler] proxy auth via CDP Fetch handler enabled');\n } catch (e: any) {\n logger.warn({ err: e?.message }, '[crawler] CDP proxy-auth setup failed \u2014 407 may not resolve');\n }\n }\n } catch {\n // Non-fatal \u2014 crawl proceeds without API endpoint capture\n }\n // Final fallback: if rawPage is still null, use the Stagehand page (events may not work)\n if (!rawPage) {\n rawPage = page;\n logger.warn('[crawler] rawPage fell back to Stagehand proxy \u2014 CDP connectOverCDP failed; route() calls will be skipped');\n }\n\n // \u2500\u2500 HTTP Basic Auth: inject Authorization header for same-origin requests \u2500\u2500\u2500\n // Must use rawPage (real Playwright page) \u2014 Stagehand V3Page proxy does not implement route().\n if (opts.httpBasicUsername && opts.httpBasicPassword && typeof rawPage?.route === 'function') {\n const encoded = Buffer.from(`${opts.httpBasicUsername}:${opts.httpBasicPassword}`).toString('base64');\n const appOrigin = new URL(opts.appUrl).origin;\n await rawPage.route('**/*', (route: any) => {\n const reqUrl = route.request().url();\n if (reqUrl.startsWith(appOrigin)) {\n route.continue({\n headers: { ...route.request().headers(), 'Authorization': `Basic ${encoded}` },\n });\n } else {\n route.continue();\n }\n });\n }\n\n // \u2500\u2500 Crawler login bypass: inject internal secret header on login requests \u2500\u2500\u2500\u2500\n // Prevents the per-email rate limiter from blocking re-auth attempts made by\n // the crawler during long crawl sessions. The API verifies the secret before\n // skipping the limiter.\n const crawlerSecret = process.env.CRAWLER_INTERNAL_SECRET;\n if (crawlerSecret && typeof rawPage?.route === 'function') {\n const loginPattern = `${new URL(opts.appUrl).origin}**/auth/login*`;\n await rawPage.route(loginPattern, (route: any) => {\n route.continue({\n headers: { ...route.request().headers(), 'x-zeta-crawler': crawlerSecret },\n });\n });\n }\n\n try {\n // Step 1: Navigate and authenticate\n await onProgress?.(8, 'Loading app');\n // Use explicit timeout \u2014 Stagehand V3Page proxy silently ignores setDefaultNavigationTimeout.\n // Fall back to 'commit' (HTTP response received) if DOM takes too long; page is still usable.\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 30_000 }).catch(async () => {\n await page.goto(opts.appUrl, { waitUntil: 'commit', timeout: 15_000 }).catch(() => { });\n });\n // Auto-accept cookie consent banners \u2014 common EU sites show consent walls before content.\n await acceptCookieConsent(page, { waitMs: 1_000 }).catch(() => { });\n\n // Fail fast if the app URL itself is unreachable \u2014 datacenter IP block, DNS failure, etc.\n if (page.url().startsWith('chrome-error://')) {\n throw new Error(`Cannot reach ${opts.appUrl} \u2014 the server refused the connection (likely IP block or DNS failure). Go to Project Settings \u2192 Connectivity \u2192 Proxy and select \"Auto\" or enter a residential proxy URL.`);\n }\n // Fail fast if Cloudflare or similar bot-protection challenge is served instead of the real app.\n // These pages never contain testable UI \u2014 crawling them produces zero useful screens.\n const initialTitle = await page.title().catch(() => '');\n const isBotChallenge = /^(just a moment|attention required|access denied|ddos protection|cloudflare|checking your browser|enable javascript)/i.test(initialTitle);\n if (isBotChallenge) {\n throw new Error(`Cannot crawl ${opts.appUrl} \u2014 bot protection challenge detected (title: \"${initialTitle}\"). The site is blocking automated browsers. Go to Project Settings \u2192 Connectivity \u2192 Proxy and select \"Auto\" (free proxies) or enter a residential proxy URL to bypass.`);\n }\n // Wait for SPA client-side redirect to complete (e.g. Next.js useEffect router.replace to /login).\n // Without this, loginWithStagehand may run on an empty/loading root page before the form renders.\n await page.waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => { });\n await waitForStableDOM(page);\n\n // Capture homepage fingerprint for soft-404 detection. SPA catch-all routes return HTTP 200\n // but render identical homepage content for every unrecognised path. We fingerprint here\n // (pre-auth, stable DOM) and skip any BFS page that matches during the main crawl.\n const homeFingerprintTitle = await page.title().catch(() => '');\n const homeFingerprintElemCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"]').length\n ).catch(() => -1);\n\n // \u2500\u2500 Pre-auth public-page discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // The page is unauthenticated here. On sites where login redirects users\n // away from the marketing/landing pages (e.g. \"/\" \u2192 app dashboard), BFS\n // (which runs after auth) will never discover those public pages. We extract\n // nav links from the current unauthenticated view and visit/capture each one\n // before the session is applied, so the marketing pages are captured correctly.\n const preAuthPublicCaptured = new Set<string>();\n if (!opts.discoveryMode) {\n const _appOrigin = new URL(opts.appUrl).origin;\n // Simple URL normalizer for pre-auth use (canonicalize() declared later in scope)\n const _norm = (u: string) => { try { const p = new URL(u); p.hash = ''; return p.href.replace(/\\/$/, ''); } catch { return u; } };\n const _startNorm = _norm(opts.appUrl);\n const _authPathRe = /\\/(sign.?in|sign.?up|log.?in|register|auth|oauth|sso|forgot.?password|reset.?password)(\\/|$|\\?)/i;\n const _skipPathRe = /\\/(terms|privacy|legal|cookie-policy|changelog|blog|imprint)([-/]|$)/i;\n\n const publicNavLinks: string[] = await page.evaluate((originStr: string) => {\n return Array.from(document.querySelectorAll('a[href]'))\n .map((a: Element) => {\n try {\n const u = new URL((a as HTMLAnchorElement).getAttribute('href')!, window.location.href);\n return u.origin === originStr ? u.href.split('#')[0] : '';\n } catch { return ''; }\n })\n .filter((h: string, i: number, arr: string[]) => h && arr.indexOf(h) === i)\n .slice(0, 50);\n }, _appOrigin).catch(() => [] as string[]);\n\n for (const link of publicNavLinks) {\n if (_norm(link) === _startNorm) continue;\n try {\n const { pathname } = new URL(link);\n if (_authPathRe.test(pathname) || _skipPathRe.test(pathname) || API_PATH_RE.test(pathname) || EXPORT_PATH_RE.test(pathname) || DOWNLOAD_EXT_RE.test(pathname)) continue;\n await page.goto(link, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => {});\n await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => {});\n const finalUrl = page.url();\n const finalPath = new URL(finalUrl).pathname;\n if (_authPathRe.test(finalPath)) continue; // redirected to auth \u2014 skip\n if (_norm(finalUrl) === _startNorm) continue; // SPA catch-all redirect\n // Read interactive elements first \u2014 SPA pages show 0 elements without auth.\n // Only lock as pre-auth if the page actually has content; otherwise BFS handles it authenticated.\n const preAuthElements = await readScreen(page).catch(() => [] as Awaited<ReturnType<typeof readScreen>>);\n if (preAuthElements.length === 0) {\n logger.info({ url: finalUrl }, '[crawler] pre-auth page has 0 elements \u2014 deferring to authenticated BFS');\n continue;\n }\n // Detect auth walls that have a tiny number of elements (login button, back link, spinner).\n // These pages redirect or gate on auth \u2014 main BFS must visit them with a live session.\n // Label prefix or exact match \u2014 \"Back to Learn\" matches \"back to\", \"Sign In\" matches \"sign in\"\n const AUTH_WALL_LABEL_RE = /^(sign.?in|log.?in|login|platform access|back\\s+to|checking\\s+auth|get started|create account|register|continue with|join now)/i;\n // Also treat pages with only `a`-role elements (no inputs/buttons) as likely auth walls\n const allAnchorOnly = preAuthElements.every(el => el.role === 'a');\n const looksLikeAuthWall = preAuthElements.length <= 3 && (allAnchorOnly || preAuthElements.every(el => AUTH_WALL_LABEL_RE.test(el.label)));\n if (looksLikeAuthWall) {\n logger.info({ url: finalUrl, elements: preAuthElements.length, labels: preAuthElements.map(e => e.label) }, '[crawler] pre-auth auth wall \u2014 deferring to authenticated BFS');\n continue;\n }\n const pathParts = finalPath.split('/').filter(Boolean);\n const screenName = pathParts.map((p: string) => p.charAt(0).toUpperCase() + p.slice(1).replace(/[-_]/g, ' ')).join(' \u2014 ') || 'Home';\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, screenName, finalUrl, opts.jobId, 'LINK_FOLLOW').catch(() => null);\n if (!screen) continue;\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `${screen.id}-desktop-v${screen.version}.png`);\n // TODO GAP-09: pass opts.screenshotConfig (width/height/quality) here when screenshotConfig is wired into the opts type.\n await page.screenshot({ path: shotPath, fullPage: true }).catch(() => {});\n const cloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`).catch(() => undefined);\n await (AppBrain.saveScreenshot as any)(opts.tenantId, opts.projectId, screen.id, shotPath, screen.version, 'DESKTOP', cloudUrl).catch(() => {});\n // GAP 5: DOM snapshot for pre-auth public page discovery\n const pubDom = await capturePageHtml(page);\n if (pubDom) {\n const pubDomPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(pubDomPath, pubDom, 'utf8');\n const pubDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(pubDomPath)}`;\n AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, pubDomPath, await uploadToCloud(pubDomPath, pubDomKey).catch(() => undefined)).catch(() => {});\n }\n // Save elements found in the pre-auth view\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, screen.id).catch(() => {});\n for (const el of preAuthElements) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.label, el.role, el.expectedData, undefined, undefined, true, undefined, undefined, undefined).catch(() => {});\n }\n preAuthPublicCaptured.add(finalUrl);\n logger.info({ url: finalUrl, screenId: screen.id, elements: preAuthElements.length }, '[crawler] pre-auth public page captured');\n } catch (err: any) {\n logger.warn({ url: link, err: err?.message }, '[crawler] pre-auth public page visit failed \u2014 skipping');\n }\n }\n\n // Navigate back to start so auth phase and fingerprint comparison are correct\n if (preAuthPublicCaptured.size > 0) {\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 20_000 }).catch(() => {});\n await page.waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => {});\n }\n }\n\n // Dedicated logged-out/auth discovery phase. This runs before credentials or\n // storageState are applied, so public pages and auth recovery flows remain\n // visible even when the main crawl later becomes authenticated.\n if (!opts.discoveryMode) {\n try {\n await runAuthDiscoveryPhase(page, opts, new URL(opts.appUrl).origin, onProgress);\n } catch (preAuthErr) {\n logger.warn({ err: preAuthErr }, '[crawler] auth-discovery phase failed \u2014 continuing with authenticated crawl');\n }\n }\n\n // Auth discovery opens OAuth sign-in popups (Google, GitHub, etc.) which fire CDP events that\n // can permanently corrupt the Playwright isolated world. Verify the world is intact; if not,\n // re-navigate to appUrl to force a fresh execution context before BFS begins.\n {\n const worldOk = await page.evaluate(() => true).catch(() => false);\n if (!worldOk) {\n logger.warn('[crawler] isolated world corrupted after auth discovery \u2014 re-navigating to recover');\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => {});\n await page.waitForLoadState('networkidle', { timeout: 6_000 }).catch(() => {});\n }\n }\n\n let didLogin = false; // track whether AI login was actually performed\n\n if (opts.authToken) {\n // Auth token already injected via setExtraHTTPHeaders + addInitScript above.\n // Skip session restore and AI login entirely.\n await onProgress?.(18, 'API token configured \u2014 skipping login');\n logger.info('authToken provided \u2014 skipping AI login');\n } else if (effectiveStorageState) {\n // \u2500\u2500 StorageState session restore: skip AI login entirely \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // User authenticated once via `npx playwright codegen --save-storage=session.json`\n // and saved the resulting JSON in crawl config (encrypted at rest).\n // effectiveStorageState may also come from Chrome profile inheritance (GAP 3).\n logger.info('StorageState found \u2014 restoring session, skipping AI login');\n try {\n const state = JSON.parse(effectiveStorageState!) as {\n cookies?: Array<Record<string, any>>;\n origins?: Array<{ origin: string; localStorage: Array<{ name: string; value: string }> }>;\n };\n\n if (state.cookies?.length) {\n // Apply cookies to both the secondary Playwright context AND Stagehand's own context.\n // Stagehand V3 uses a separate browser context from the CDP secondary client, so\n // cookies added only to playwrightBrowser.contexts()[0] don't reach Stagehand's pages.\n const browserCtx = playwrightBrowser?.contexts()[0];\n if (browserCtx) {\n await browserCtx.addCookies(state.cookies as any);\n }\n // Also apply to Stagehand's context via its page proxy\n try {\n const stagehandCtx = (page as any).context?.();\n if (stagehandCtx && typeof stagehandCtx.addCookies === 'function') {\n await stagehandCtx.addCookies(state.cookies as any);\n }\n } catch { /* Stagehand V3 proxy may not expose context() */ }\n }\n\n if (state.origins?.length) {\n // Apply localStorage via addInitScript to ALL contexts:\n // 1. Secondary Playwright context (rawPage navigations)\n // 2. Stagehand's page directly (Stagehand V3 uses its own context separate from playwrightBrowser)\n // Without #2, Stagehand's BFS navigations never get localStorage \u2192 pages load unauthenticated.\n const originCtx = playwrightBrowser?.contexts()[0];\n if (originCtx) {\n await originCtx.addInitScript((origins: typeof state.origins) => {\n for (const entry of (origins ?? [])) {\n if (window.location.origin === entry.origin) {\n for (const item of entry.localStorage) {\n try { localStorage.setItem(item.name, item.value); } catch { /* quota/sandboxed */ }\n }\n }\n }\n }, state.origins);\n }\n // Stagehand's page \u2014 covers all BFS navigations via Stagehand\n await page.addInitScript((origins: typeof state.origins) => {\n for (const entry of (origins ?? [])) {\n if (window.location.origin === entry.origin) {\n for (const item of entry.localStorage) {\n try { localStorage.setItem(item.name, item.value); } catch { /* quota/sandboxed */ }\n }\n }\n }\n }, state.origins);\n // Also cover rawPage for the initial navigation below\n await rawPage.addInitScript((origins: typeof state.origins) => {\n for (const entry of (origins ?? [])) {\n if (window.location.origin === entry.origin) {\n for (const item of entry.localStorage) {\n try { localStorage.setItem(item.name, item.value); } catch { /* quota/sandboxed */ }\n }\n }\n }\n }, state.origins);\n }\n\n // Navigate to appUrl with cookies now set.\n // We MUST navigate to appUrl (not reload current page) because the initial\n // goto ran without cookies and was redirected to /login. Reloading /login stays\n // at /login even with a valid cookie (public path, no auth redirect). Navigating\n // to appUrl lets server middleware see the cookie and route to the authenticated app.\n await onProgress?.(12, 'Restoring session');\n await rawPage.goto(opts.appUrl, { waitUntil: 'domcontentloaded' }).catch(() => { });\n await waitForStableDOM(page);\n // SPA root pages redirect client-side (useEffect \u2192 router.replace). Wait for it.\n if (page.url() === opts.appUrl || page.url() === opts.appUrl.replace(/\\/$/, '')) {\n await waitForURLChange(page, opts.appUrl).catch(() => { });\n await waitForStableDOM(page);\n }\n\n // Detect if session restore failed \u2014 either by URL redirect or login form presence on root URL\n const postRestoreUrl = page.url();\n const LOGIN_PATH = /\\/(login|signin|sign-in|auth|log-in|sso|oauth|account\\/login)(\\/|$|\\?)/i;\n const ERROR_PATH = /\\/(session-expired|expired|unauthorized|forbidden|401|403|error|logout|logged-out)(\\/|$|\\?)/i;\n const redirectedToLogin = LOGIN_PATH.test(new URL(postRestoreUrl).pathname);\n const redirectedToError = ERROR_PATH.test(new URL(postRestoreUrl).pathname);\n // Also check for login form presence \u2014 catches apps where login page is at root URL (e.g. /)\n const hasLoginForm = await page.evaluate(() => {\n const inputs = Array.from(document.querySelectorAll('input'));\n const hasEmailOrUser = inputs.some((i: any) =>\n ['email', 'username', 'user', 'login'].some((k) =>\n (i.type || '').includes(k) || (i.name || '').toLowerCase().includes(k) ||\n (i.id || '').toLowerCase().includes(k) || (i.placeholder || '').toLowerCase().includes(k)\n )\n );\n const hasPasswordField = inputs.some((i: any) => i.type === 'password');\n return hasEmailOrUser && hasPasswordField;\n }).catch(() => false);\n const sessionFailed = redirectedToLogin || redirectedToError || hasLoginForm;\n if (sessionFailed) {\n logger.warn({ url: postRestoreUrl, loginForm: hasLoginForm, errorUrl: redirectedToError }, 'StorageState restore failed \u2014 session may be expired');\n // Clear the expired session from DB so user is forced to re-capture\n await AppBrain.saveCrawlConfig(opts.tenantId, opts.projectId, { storageState: null }).catch(() => { });\n // Navigate to the login page. First try appUrl \u2014 if it still redirects to an error/login\n // path, probe common login paths at the app origin so Stagehand finds a real login form.\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded' }).catch(() => { });\n await waitForStableDOM(page);\n const urlAfterNav = page.url();\n const stillAtError = ERROR_PATH.test(new URL(urlAfterNav).pathname) || LOGIN_PATH.test(new URL(urlAfterNav).pathname);\n if (stillAtError) {\n const appOrigin = new URL(opts.appUrl).origin;\n for (const loginPath of ['/login', '/signin', '/sign-in', '/auth/login', '/auth']) {\n try {\n await page.goto(`${appOrigin}${loginPath}`, { waitUntil: 'domcontentloaded' });\n const hasForm = await page.evaluate(() => {\n const inputs = Array.from(document.querySelectorAll('input'));\n return inputs.some((i: any) => i.type === 'password');\n }).catch(() => false);\n if (hasForm) { logger.info({ loginPath }, 'Found login form at path'); break; }\n } catch { /* continue to next path */ }\n }\n await waitForStableDOM(page);\n }\n if (opts.credentials) {\n logger.info('Falling back to AI login with credentials');\n await onProgress?.(15, 'Session expired \u2014 logging in with credentials\u2026');\n const loggedIn = await loginWithStagehand(stagehand, opts.credentials, opts.appUrl, { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider }, { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId }, opts.loginInstructions, { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId });\n if (!loggedIn) throw new Error('[SESSION_EXPIRED] Stored session expired and credential login also failed. Check your username / password in Project Settings \u2192 Credentials.');\n didLogin = true;\n } else {\n throw new Error('[SESSION_EXPIRED] Stored session has expired. Please re-capture your session in Project Settings \u2192 Advanced: Session Capture, or add username / password as a login fallback.');\n }\n } else {\n await onProgress?.(18, 'Session restored');\n logger.info({ url: postRestoreUrl }, 'Session restored');\n }\n } catch (err) {\n const msg = String((err as Error).message ?? err);\n // Re-throw errors we threw intentionally above\n if (msg.includes('[SESSION_EXPIRED]') || msg.includes('expired')) throw err;\n logger.warn({ err }, 'StorageState restore failed, falling back to AI login');\n if (opts.credentials) {\n await onProgress?.(15, 'Session restore failed \u2014 logging in with credentials\u2026');\n const loggedIn = await loginWithStagehand(stagehand, opts.credentials, opts.appUrl, { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider }, { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId }, opts.loginInstructions, { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId });\n if (!loggedIn) throw new Error('[SESSION_EXPIRED] Session restore failed and credential login also failed. Check your username / password in Project Settings \u2192 Credentials.');\n didLogin = true;\n } else {\n throw new Error('[SESSION_EXPIRED] Session restore failed and no credentials were provided. Please re-capture your session in Project Settings \u2192 Advanced: Session Capture.');\n }\n }\n } else if (opts.ssoProvider && opts.ssoDomain && opts.ssoClientId && opts.credentials) {\n // \u2500\u2500 GAP 18: SSO ROPC flow \u2014 bypass browser login entirely \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Get a token directly from the IdP and inject it as a Bearer header.\n await onProgress?.(12, 'SSO: fetching token from identity provider');\n try {\n const ssoToken = await getSsoToken(\n {\n provider: opts.ssoProvider as any,\n domain: opts.ssoDomain,\n clientId: opts.ssoClientId,\n clientSecret: opts.ssoClientSecret,\n scope: opts.ssoScope,\n },\n opts.credentials.username,\n opts.credentials.password\n );\n await page.setExtraHTTPHeaders({ 'Authorization': `Bearer ${ssoToken}` });\n await page.addInitScript((t: string) => {\n localStorage.setItem('access_token', t);\n localStorage.setItem('auth_token', t);\n localStorage.setItem('token', t);\n }, ssoToken);\n await page.reload({ waitUntil: 'domcontentloaded' });\n didLogin = true;\n await onProgress?.(18, 'SSO token injected');\n logger.info({ provider: opts.ssoProvider }, '[crawler] SSO token obtained and injected');\n } catch (ssoErr) {\n logger.warn({ err: ssoErr }, '[crawler] SSO token retrieval failed \u2014 falling back to browser login');\n // Fall through to browser-based login\n await onProgress?.(12, 'Logging in');\n didLogin = true;\n const loggedIn = await loginWithStagehand(stagehand, opts.credentials, opts.appUrl, { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider }, { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId }, opts.loginInstructions, { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId });\n if (!loggedIn) {\n logger.warn('Stagehand login failed \u2014 trying Skyvern vision fallback');\n await onProgress?.(14, 'Trying vision fallback');\n const skyvernResult = await skyvernFallback({\n taskDescription: `Log in to ${opts.appUrl} using username \"${opts.credentials.username}\" and navigate to the main dashboard.`,\n url: opts.appUrl,\n credentials: opts.credentials,\n }, opts.skyvernConfig);\n if (skyvernResult === 'failed') {\n throw new Error(\n 'Login failed on both Stagehand (DOM) and Skyvern (vision). ' +\n 'Check credentials. For CAPTCHA/SSO sites, set SKYVERN_API_URL + SKYVERN_API_KEY.'\n );\n }\n }\n await onProgress?.(18, 'Logged in');\n }\n } else if (opts.credentials) {\n await onProgress?.(12, 'Logging in');\n didLogin = true;\n const loggedIn = await loginWithStagehand(stagehand, opts.credentials, opts.appUrl, { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider }, { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId }, opts.loginInstructions, { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId });\n if (!loggedIn) {\n logger.warn('Stagehand login failed \u2014 trying Skyvern vision fallback');\n await onProgress?.(14, 'Trying vision fallback');\n const skyvernResult = await skyvernFallback({\n taskDescription: `Log in to ${opts.appUrl} using username \"${opts.credentials.username}\" and navigate to the main dashboard.`,\n url: opts.appUrl,\n credentials: opts.credentials,\n }, opts.skyvernConfig);\n if (skyvernResult === 'failed') {\n throw new Error(\n 'Login failed on both Stagehand (DOM) and Skyvern (vision). ' +\n 'Check credentials. For CAPTCHA/SSO sites, set SKYVERN_API_URL + SKYVERN_API_KEY.'\n );\n }\n }\n await onProgress?.(18, 'Logged in');\n } else {\n await onProgress?.(18, 'No auth needed');\n }\n\n // Step 2: Crawl\n // If we just logged in (via credentials or session-fallback), capture and persist the new\n // session state so the next crawl reuses it without logging in again.\n if (didLogin) {\n try {\n const freshState = await playwrightBrowser!.contexts()[0]?.storageState();\n if (freshState) {\n await AppBrain.saveCrawlConfig(opts.tenantId, opts.projectId, { storageState: JSON.stringify(freshState) });\n logger.info('Fresh session state captured and saved after credential login');\n await onProgress?.(19, 'Session saved \u2014 will reuse on next crawl');\n }\n } catch (e) {\n logger.warn({ err: e }, 'Could not save refreshed session state \u2014 crawl will continue');\n }\n // Wait for SPA router to complete the post-login redirect before seeding the queue.\n // Without this, Next.js/React apps queue the login URL instead of the dashboard URL.\n await waitForURLChange(page, opts.appUrl);\n }\n const origin = new URL(page.url()).origin;\n const maxScreens = opts.maxScreens ?? Infinity;\n const segmentSize = opts.segmentSize ?? 9_999_999; // effectively unlimited \u2014 segments only exist for checkpointing reliability\n // selective = exact-URL-only mode (recrawl selected screens, no link discovery)\n const selective = !!(opts.selectiveUrls && opts.selectiveUrls.length > 0);\n\n // Mark all screens for this project as active \u2014 post-crawl we'll diff which ones weren't re-discovered.\n if (!selective) {\n await AppBrain.prepareForRecrawl(opts.tenantId, opts.projectId, opts.jobId);\n await AppBrain.clearFlows(opts.tenantId, opts.projectId);\n }\n // Canonicalize URL for dedup: strip tracking params + normalize dynamic ID segments.\n // Prevents /projects/cuid1 and /projects/cuid2 from being queued as separate screens.\n const canonicalize = (raw: string): string => {\n try {\n const u = new URL(raw);\n // Treat www and non-www as the same host \u2014 most sites redirect one to the other\n // but internal links may be inconsistent, causing duplicate crawl entries otherwise.\n u.hostname = u.hostname.replace(/^www\\./, '');\n // Strip params that don't change page content\n [\n 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'ref', 'source', '_gl', 'fbclid', 'gclid',\n 'ts', 'timestamp', 'cache', 'cacheBust', 'cache_bust', '_', 'nonce', 'session', 'sid',\n // App content/state params \u2014 these change the content rendered within the same\n // page template (a playground example, a search query, a tab selection) but do NOT\n // represent structurally distinct pages. Not stripping them causes URL explosion:\n // every unique ?cmd=DSN-XXXXX&example=... or ?q=foo is queued as a new screen.\n 'cmd', 'example', 'query', 'q', 'search', 'keyword', 'keywords',\n 'tab', 'view', 'mode', 'sort', 'order', 'direction', 'orderby',\n 'page', 'p', 'offset', 'limit', 'per_page', 'size', 'rows',\n // Export format params \u2014 same endpoint, different output format, not a new screen\n 'format', 'output', 'export_format', 'download_format', 'fileformat', 'file_format',\n // WooCommerce / e-commerce action params\n 'add-to-cart', 'add_to_wishlist', 'quantity', 'wc-ajax',\n 'min_price', 'max_price', 'removed_item', 'restore', 'remove_item',\n 'undo_item', 'coupon_code', 'apply_coupon', 'added-to-cart',\n 'wc_error', 'wc_notice', 'wc_notice_type', 'update_cart',\n 'proceed', '_wpnonce', 'post_type', 'product_cat',\n // WooCommerce facet/layered-nav filter params \u2014 each combination generates a unique URL\n // but all render the same template; not stripping these causes infinite URL explosion\n // (N filter options \u00D7 M values = exponential queue growth)\n 'filter_color', 'filter_colour', 'filter_size', 'filter_brand', 'filter_category',\n 'filter_rating', 'filter_stock_status', 'filter_pa_color', 'filter_pa_size',\n 'filter_pa_brand', 'filter_pa_material', 'filter_pa_weight', 'filter_pa_style',\n 'filter_pa_gender', 'filter_pa_age', 'filter_pa_type', 'filter_pa_pattern',\n 'query_type_color', 'query_type_size', 'query_type_brand', 'query_type_pa_color',\n 'query_type_pa_size', 'query_type_pa_brand', 'in_stock', 'on_sale',\n // Shopify facet filters\n 'sort_by', 'constraint', 'filter.p.tag', 'filter.v.price.gte', 'filter.v.price.lte',\n 'filter.p.m.global.color', 'filter.p.m.global.size',\n ].forEach(p => u.searchParams.delete(p));\n // Strip any remaining filter_* / query_type_* / filter.* params (WooCommerce/Shopify facets)\n for (const key of Array.from(u.searchParams.keys())) {\n if (/^filter[._]|^query_type_/i.test(key)) u.searchParams.delete(key);\n }\n u.searchParams.sort();\n // Normalize dynamic segments globally: UUIDs, CUIDs, long numeric IDs,\n // and hyphenated numeric record IDs under any parent route.\n u.pathname = u.pathname\n .replace(/\\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?=\\/|$)/gi, '/{id}')\n .replace(/\\/c[a-z0-9]{20,}(?=\\/|$)/g, '/{id}')\n .replace(/\\/\\d{4,}(?=\\/|$)/g, '/{id}')\n // Hyphenated numeric IDs: digits-digits (e.g. 0-9638, 12-4567). Not UUIDs (hex only).\n .replace(/\\/\\d+-\\d+(?=\\/|$)/g, '/{id}')\n .replace(/\\/+$/, '') || '/';\n // Hash-routed SPAs put the actual route in the fragment (\"#/dashboard\",\n // \"#!/settings\") \u2014 keep it so distinct routes dedup separately instead\n // of every hash-route collapsing onto one canonical (hashless) URL.\n if (!/^#!?\\//.test(u.hash)) u.hash = '';\n return u.toString();\n } catch { return raw; }\n };\n\n const gitInfo = getGitInfo();\n\n const visited = new Map<string, string>(); // key = canonical URL\n const crawlWarnings: string[] = []; // non-fatal step failures surfaced in job result\n // Pre-populate from a previous failed job so already-captured URLs are skipped\n if (opts.skipUrls?.length) {\n for (const u of opts.skipUrls) visited.set(canonicalize(u), 'skipped');\n }\n // Pre-auth public pages already captured above \u2014 mark visited so BFS (post-auth)\n // doesn't overwrite them with authenticated redirects showing app content instead.\n for (const u of preAuthPublicCaptured) visited.set(canonicalize(u), 'pre-auth');\n let checkpointSuccessCount = 0;\n let maxSeenTotal = 0; // track high-water mark so progress % never goes backwards\n let lastEmittedPct = 20; // floor above auth-discovery + login phases (max ~19%)\n const crawlLoopStart = Date.now();\n // Global crawl timeout \u2014 prevent BFS from hanging indefinitely on large apps.\n // Default 2 hours; override via CRAWL_GLOBAL_TIMEOUT_MS env var.\n const CRAWL_GLOBAL_TIMEOUT_MS = parseInt(process.env.CRAWL_GLOBAL_TIMEOUT_MS ?? '') || 2 * 60 * 60 * 1000;\n const isCrawlTimedOut = () => (Date.now() - crawlLoopStart) >= CRAWL_GLOBAL_TIMEOUT_MS;\n const startUrl = page.url();\n // Resume from previous segment's pending queue if provided\n const resumeUrls = opts.resumeUrls ?? [];\n // Sitemap-discovered URLs are additional seeds (not a replacement for\n // link-following) \u2014 merged in below unless this is a selective\n // (\"crawl only these URLs\") run or a resumed segment, matching how\n // GraphQL auto-introspection \u2014 fire-and-forget, stored in crawl metadata\n const gqlIntrospectionPromise = (async () => {\n const gqlEndpoints = guessGraphQLEndpoints(opts.appUrl);\n for (const ep of gqlEndpoints) {\n const result = await introspectGraphQL(ep, { timeoutMs: 5_000 }).catch(() => null);\n if (result?.schema) {\n logger.info({ endpoint: ep, typeCount: result.schema.types.length }, '[crawler] GraphQL schema discovered');\n return result;\n }\n }\n return null;\n })();\n\n // seedUrls itself works. Best-effort: discoverSitemapUrls() never throws.\n const sitemapUrls = (opts.useSitemap && !selective && resumeUrls.length === 0)\n ? await discoverSitemapUrls(opts.appUrl, opts.sitemapUrl)\n : [];\n // Filter bad URLs out of resumeUrls (generated dynamic routes from prior segments)\n const filteredResumeUrls = resumeUrls.filter(u => {\n try { return !isGeneratedDynamicPath(new URL(u).pathname); } catch { return true; }\n });\n const seedUrls = selective\n ? opts.selectiveUrls!\n : filteredResumeUrls.length > 0\n ? filteredResumeUrls\n : [\n startUrl,\n // User-configured seed URLs added to queue; link discovery still runs from each.\n ...(opts.startUrls ?? []).filter((u) => canonicalize(u) !== canonicalize(startUrl)),\n ...sitemapUrls.filter((u) => canonicalize(u) !== canonicalize(startUrl)),\n ];\n const queued = new Set<string>(seedUrls.map(canonicalize));\n const queue = new CrawlFrontier(opts.traversalStrategy ?? 'BFS', seedUrls, opts.bestFirstKeywords, opts.urlFilter, opts.includePatterns, opts.excludePatterns);\n // Selective recrawl: block all link-discovery pushes so BFS only visits the requested URLs.\n // Constructor seeding already ran above \u2014 this no-op override fires only for BFS-loop discoveries.\n if (selective) {\n queue.push = () => {};\n }\n const deduplicator = new ContentDeduplicator(parseFloat(process.env.CRAWLER_DEDUP_THRESHOLD ?? '') || 0.88);\n const deadLinkTracker = new DeadLinkTracker();\n const redirectRegistry = new RedirectRegistry();\n // Re-seed from previously-discovered screens so deep routes found by AI link\n // discovery in prior crawls aren't lost when a recrawl starts from scratch.\n // Doc 41 Option D: orphan-classified screens (no inbound nav edges) get a BEST_FIRST\n // score boost via parentElements:0 so they're visited early in the next crawl.\n // Only applies to full recrawls (not selective runs or segment resumptions).\n if (!selective && resumeUrls.length === 0) {\n try {\n const priorMap = projectForProfile ?? await AppBrain.getProjectMap(opts.tenantId, opts.projectId);\n const orphanReport = await AppBrain.getOrphanScreens(opts.tenantId, opts.projectId).catch(() => null);\n const orphanIdSet = new Set<string>(\n (orphanReport?.screens ?? [])\n .filter((s: any) => s.classification !== 'REACHABLE')\n .map((s: any) => s.id as string),\n );\n // Snapshot queued set BEFORE filter so canonical dedup works correctly during filter.\n // Without this, multiple prior screens with the same canonical (e.g. playground?cmd=X1,\n // playground?cmd=X2 \u2192 same canonical) all pass the filter since queued isn't updated yet.\n const seenReseedCanon = new Set<string>(queued);\n const priorScreens = (priorMap?.screens ?? [])\n .filter((s: any) => s.status !== 'PENDING_REMOVAL')\n .filter((s: any) => {\n const u = s.url as string | null;\n if (!u) return false;\n try {\n const { pathname } = new URL(u);\n const stripWww = (h: string) => h.replace(/^www\\./i, '').toLowerCase();\n if (stripWww(new URL(u).hostname) !== stripWww(new URL(startUrl).hostname)) return false;\n // Don't re-seed generated dynamic routes \u2014 they produce duplicate templates.\n // Exception: seed path patterns explicitly declared by the caller.\n if (isGeneratedDynamicPath(pathname) && !_activeSeedPatterns.some(re => re.test(pathname))) return false;\n // Don't re-seed API/export/download paths \u2014 they were misidentified as screens.\n if (!isUsefulNavigationUrl(u, startUrl)) return false;\n // Canonical dedup: mark seen immediately during filter so duplicates are caught.\n const canon = canonicalize(u);\n if (seenReseedCanon.has(canon)) return false;\n seenReseedCanon.add(canon);\n return true;\n } catch { return false; }\n });\n let orphanSeedCount = 0;\n for (const s of priorScreens) {\n const u = s.url as string;\n queued.add(canonicalize(u));\n const isOrphan = orphanIdSet.has(s.id as string);\n queue.push(u, isOrphan ? { parentElements: 0 } : undefined);\n if (isOrphan) orphanSeedCount++;\n }\n if (priorScreens.length > 0) {\n logger.info(\n { count: priorScreens.length, orphanBoosted: orphanSeedCount },\n '[crawler] re-seeded prior screen URLs from DB',\n );\n }\n } catch (err) {\n logger.warn({ err: String(err) }, '[crawler] non-fatal: could not load prior screen URLs for re-seeding');\n }\n }\n // G11: Pre-auth sitemap discovery \u2014 capture public pages before session injection.\n // Many apps have marketing/pricing/docs pages only reachable without auth.\n // We fetch the sitemap, visit each URL, and screenshot pages that DON'T redirect to login.\n if (opts.useSitemap !== false) {\n const g11SitemapUrls: string[] = [];\n const sitemapCandidates = [\n `${opts.appUrl.replace(/\\/$/, '')}/sitemap.xml`,\n `${opts.appUrl.replace(/\\/$/, '')}/sitemap_index.xml`,\n `${opts.appUrl.replace(/\\/$/, '')}/robots.txt`,\n ];\n const LOGIN_REDIRECT_PATH = /\\/(login|signin|sign-in|auth|log-in)(\\/|$|\\?)/i;\n\n try {\n for (const candidate of sitemapCandidates) {\n try {\n const resp = await fetch(candidate, { signal: AbortSignal.timeout(8_000) }).catch(() => null);\n if (!resp?.ok) continue;\n const text = await resp.text();\n if (candidate.endsWith('robots.txt')) {\n const sitemapLines = text.split('\\n').filter((l: string) => l.toLowerCase().startsWith('sitemap:'));\n for (const line of sitemapLines) {\n const u = line.split(':').slice(1).join(':').trim();\n if (u) sitemapCandidates.push(u);\n }\n continue;\n }\n const locs = text.match(/<loc>([^<]+)<\\/loc>/gi) ?? [];\n for (const loc of locs) {\n const u = loc.replace(/<\\/?loc>/gi, '').trim();\n if (u.startsWith('http')) g11SitemapUrls.push(u);\n }\n if (g11SitemapUrls.length > 0) break;\n } catch { /* try next candidate */ }\n }\n\n if (g11SitemapUrls.length > 0) {\n logger.info({ count: g11SitemapUrls.length }, '[crawler] G11: sitemap discovered public URL candidates');\n const sitemapOrigin = new URL(opts.appUrl).origin;\n let sitemapCaptured = 0;\n for (const sUrl of g11SitemapUrls) {\n if (isCrawlTimedOut()) break;\n try {\n const u = new URL(sUrl);\n if (u.origin !== sitemapOrigin) continue;\n if (API_PATH_RE.test(u.pathname) || EXPORT_PATH_RE.test(u.pathname) || DOWNLOAD_EXT_RE.test(u.pathname)) continue;\n await page.goto(sUrl, { waitUntil: 'domcontentloaded', timeout: 12_000 });\n await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => { });\n await waitForStableDOM(page);\n const landedUrl = page.url();\n if (LOGIN_REDIRECT_PATH.test(new URL(landedUrl).pathname)) {\n const canon = canonicalize(sUrl);\n if (!queued.has(canon)) { queued.add(canon); queue.push(sUrl); }\n logger.info({ url: sUrl }, '[crawler] G11: sitemap URL requires auth \u2014 added to BFS queue');\n continue;\n }\n const pagePath = u.pathname.replace(/^\\//, '') || 'home';\n const pageName = pagePath.split('/').map((s: string) => s.charAt(0).toUpperCase() + s.slice(1)).join(' ') || 'Home';\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `sitemap-preauth-${sitemapCaptured}.png`);\n await waitForScreenshotReady(page);\n await page.screenshot({ path: shotPath, fullPage: true }).catch(() => { });\n const pubScreen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, pageName, sUrl, opts.jobId, 'SITEMAP').catch(() => null);\n if (pubScreen) {\n const sitemapCloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, pubScreen.id, shotPath, pubScreen.version, 'DESKTOP', sitemapCloudUrl).catch(() => { });\n // GAP 2: DOM snapshot for G11 pre-auth sitemap path\n const sitemapDom = await capturePageHtml(page);\n if (sitemapDom) {\n const sitemapDomPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(sitemapDomPath, sitemapDom, 'utf8');\n const sitemapDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(sitemapDomPath)}`;\n const sitemapDomCloud = await uploadToCloud(sitemapDomPath, sitemapDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, pubScreen.id, sitemapDomPath, sitemapDomCloud).catch(() => {});\n }\n logger.info({ url: sUrl, name: pageName }, '[crawler] G11: captured public sitemap page');\n }\n sitemapCaptured++;\n } catch (sitemapPageErr) {\n logger.warn({ url: sUrl, err: String(sitemapPageErr) }, '[crawler] G11: sitemap page failed \u2014 skipping');\n }\n }\n logger.info({ captured: sitemapCaptured }, '[crawler] G11: pre-auth sitemap capture complete');\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => { });\n await waitForStableDOM(page);\n }\n } catch (sitemapErr) {\n logger.warn({ err: String(sitemapErr) }, '[crawler] G11: pre-auth sitemap discovery failed \u2014 continuing');\n }\n }\n\n // Discovery-method tracking for orphan-page detection (see AppBrain.getOrphanScreens):\n // the entry point is never an \"orphan\" candidate; anything else in the initial seed\n // batch is a configured seed URL (sitemap-discovered URLs included), not something\n // reached by following a link.\n const canonicalEntryUrl = canonicalize(startUrl);\n const canonicalSitemapUrls = new Set(sitemapUrls.map(canonicalize));\n const canonicalSeedUrls = new Set(seedUrls.map(canonicalize));\n const discoveryMethodFor = (url: string): 'ENTRY_POINT' | 'SEED_URL' | 'SITEMAP' | 'LINK_FOLLOW' => {\n const c = canonicalize(url);\n if (c === canonicalEntryUrl) return 'ENTRY_POINT';\n if (canonicalSitemapUrls.has(c)) return 'SITEMAP';\n if (canonicalSeedUrls.has(c)) return 'SEED_URL';\n return 'LINK_FOLLOW';\n };\n const edges: Array<{ fromUrl: string; toUrl: string }> = [];\n const pendingTransitions: Array<{ fromScreenId: string; elementMeaning: string; targetUrl: string }> = [];\n const pendingSummaryWrites: Promise<void>[] = [];\n const discovered: Array<{\n url: string; screenId?: string; elements?: number;\n elementFacts?: Array<{ meaning: string; role: string; expectedData?: string }>;\n screenshotPath?: string; version?: number; error?: string;\n }> = [];\n const performanceMetrics: PerformanceMetric[] = [];\n const seenDomHashes = new Set<string>(opts.knownDomHashes ?? []);\n\n // Legal/policy-only pages \u2014 no interactive elements worth testing; skip to prevent noise\n // NOTE: /about, /contact, /careers, /help are intentionally NOT skipped \u2014 they have\n // real test targets (contact forms, job apply forms, help search, team content)\n const skipPathExtra = process.env.CRAWL_SKIP_PATH_EXTRA\n ? process.env.CRAWL_SKIP_PATH_EXTRA.split(',').map((p) => p.trim()).filter(Boolean)\n : [];\n const SKIP_PATH = skipPathExtra.length > 0\n ? new RegExp(`/(terms|privacy|dpa|legal|cookie-policy|changelog|blog|imprint|gdpr|compliance|acceptable-use|security-policy|press|sitemap|${skipPathExtra.join('|')})([-/]|$)`, 'i')\n : /\\/(terms|privacy|dpa|legal|cookie-policy|changelog|blog|imprint|gdpr|compliance|acceptable-use|security-policy|press|sitemap)([-/]|$)/i;\n const segIdx = opts.segmentIndex ?? 1;\n\n const robotsCache = opts.respectRobotsTxt ? new RobotsCache() : null;\n // AutoThrottle state \u2014 exponential moving average of navigation latency\n let avgNavMs = 0;\n let navCount = 0;\n // Rate-limit circuit breaker: after 5 consecutive AI errors (429), skip AI for 3 screens then retry\n // (was: 3 errors \u2192 skip 10 screens \u2014 too aggressive for Nvidia NIM which rate-limits quickly)\n let aiErrorStreak = 0;\n let aiSkipCount = 0;\n const aiMinElements = parseInt(process.env.CRAWL_AI_LINK_MIN_ELEMENTS ?? '') || 5;\n let aiRateLimitWarned = false;\n // Hard guard: total URLs attempted (including skips) capped at maxScreens * 4\n // to prevent infinite-URL-explosion from WooCommerce/Shopify facet filter combos\n // that slip through canonicalize() if any new filter param type is encountered.\n let totalAttemptsThisSegment = 0;\n const maxAttempts = Math.max(segmentSize * 4, 200);\n // Count consecutive login-wall redirects \u2014 if too many, abort early (auth-wall site, no creds)\n let loginWallRedirectCount = 0;\n const LOGIN_WALL_ABORT_THRESHOLD = Math.max(8, Math.ceil(segmentSize * 0.4));\n\n let pendingSessionRestore: (() => Promise<void>) | null = null;\n\n // F10: Parallel lite-worker browser tabs \u2014 pull from shared queue while main loop runs.\n // Each worker uses a fresh Playwright page from the same browser context so it shares\n // cookies/session with the main page. DOM-only extraction (no Stagehand AI).\n // Default 5 = 3-5\u00D7 crawl throughput on a single browser context. Set CRAWL_PAGE_PARALLELISM=1 to disable.\n const CRAWL_PAGE_PARALLELISM = Math.max(1, parseInt(process.env.CRAWL_PAGE_PARALLELISM ?? '5', 10));\n\n async function runLiteWorker(workerPage: any): Promise<void> {\n while (queue.length > 0 && visited.size < maxScreens && visited.size < segmentSize) {\n if (opts.abortSignal?.aborted) break;\n if (isCrawlTimedOut()) break;\n if (++totalAttemptsThisSegment > maxAttempts) break;\n\n const url = queue.shift();\n if (!url) break;\n\n const canonUrl = canonicalize(url);\n if (visited.has(canonUrl)) continue;\n\n try {\n const { pathname } = new URL(url);\n if (SKIP_PATH.test(pathname) || (isGeneratedDynamicPath(pathname) && !_activeSeedPatterns.some(re => re.test(pathname)))) continue;\n // Skip API/export paths \u2014 these return data files, not navigable pages\n if (API_PATH_RE.test(pathname) || EXPORT_PATH_RE.test(pathname) || DOWNLOAD_EXT_RE.test(pathname)) continue;\n } catch { continue; }\n\n // Claim URL before first await \u2014 prevents duplicate processing across parallel workers\n visited.set(canonUrl, '_pending_');\n\n try {\n const navErr = await workerPage.goto(url, { waitUntil: 'domcontentloaded', timeout: tuning.navTimeoutMs }).then(() => null as null, (e: any) => e);\n if (navErr && /timeout/i.test(String((navErr as any)?.message ?? navErr))) {\n await workerPage.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 }).catch(() => {});\n }\n\n // Wait for SPA JS to render components before extracting elements or running soft-404 check.\n // domcontentloaded fires before JS executes \u2014 networkidle ensures React/Vue/Angular hydration.\n await workerPage.waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => {});\n // Wait for DOM to stop mutating (React/Vue render cycles) before element extraction.\n await waitForStableDOM(workerPage, 6_000, 400).catch(() => {});\n // Dismiss cookie banners / GDPR overlays so underlying elements are accessible.\n await dismissOverlays(workerPage).catch(() => {});\n\n // Auth wall detection: if navigation redirected to a login page, skip this URL.\n // Lite worker cannot re-authenticate (no Stagehand access) \u2014 mark and skip.\n const lwCurrentUrl = workerPage.url();\n const lwPath = (() => { try { return new URL(lwCurrentUrl).pathname.toLowerCase(); } catch { return ''; } })();\n const lwIsAuthWall = /^\\/(login|signin|sign-in|auth|authenticate|session\\/new|account\\/login|user\\/login)/.test(lwPath) && lwCurrentUrl !== url;\n const lwHasLoginForm = lwIsAuthWall ? false : await workerPage.evaluate(() => {\n const inputs = document.querySelectorAll('input[type=\"password\"]');\n return inputs.length > 0;\n }).catch(() => false);\n if (lwIsAuthWall) {\n logger.warn({ url, landed: lwCurrentUrl }, '[lite-worker] auth wall detected \u2014 queuing for main worker re-auth');\n visited.set(canonUrl, '_auth_wall_');\n if (!revisitQueue.includes(url)) revisitQueue.push(url);\n continue;\n }\n // lwHasLoginForm (direct sign-in/register page): process normally \u2014 capture the form elements.\n // Do NOT add to revisitQueue; P3a cannot do anything useful with a login page revisit.\n\n // Soft-404 detection for lite-worker: skip SPA catch-all URLs that mirror homepage\n if (homeFingerprintElemCount >= 0 && url !== startUrl) {\n const wTitle = await workerPage.title().catch(() => '');\n if (wTitle === homeFingerprintTitle && wTitle !== '') {\n const wElemCount = await workerPage.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"]').length\n ).catch(() => -1);\n if (wElemCount >= 0 && wElemCount === homeFingerprintElemCount) {\n console.log(`[lite-worker] skip ${url} \u2014 soft-404 (homepage fingerprint match)`);\n visited.set(canonUrl, '_soft404_');\n continue;\n }\n }\n }\n\n const pathParts = new URL(url).pathname.split('/').filter(Boolean);\n const name = pathParts.map((p: string) => p.charAt(0).toUpperCase() + p.slice(1).replace(/[-_]/g, ' ')).join(' \u2014 ') || 'Home';\n\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, name, url, opts.jobId, discoveryMethodFor(url));\n visited.set(canonUrl, screen.id);\n\n // Inline auth-wall detection: PHP/legacy apps render session-expired content without URL redirect.\n // URL-redirect case (lwIsAuthWall above) is handled by main BFS via revisitQueue.\n\n const lwBodyText = await workerPage.evaluate(() => (document as any).body?.innerText ?? '').catch(() => '');\n if (INLINE_AUTH_WALL_RE.test(lwBodyText)) {\n logger.warn({ url, screenId: screen.id }, '[lite-worker] Inline session-expired content detected \u2014 marking requiresAuth');\n AppBrain.updateScreenRequiresAuth(opts.tenantId, screen.id, true).catch(() => {});\n visited.set(canonUrl, '_auth_wall_');\n if (!revisitQueue.includes(url)) revisitQueue.push(url);\n continue;\n }\n\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `${screen.id}-desktop-v${screen.version}.png`);\n\n let liteElements = await domFallbackElements(workerPage).catch(() => [] as Awaited<ReturnType<typeof domFallbackElements>>);\n if (liteElements.length === 0) {\n // domFallbackElements returned nothing \u2014 try broader visible-element selector as last resort.\n liteElements = await workerPage.evaluate(() => {\n const sel = 'button,a[href],input,select,textarea,[role],[tabindex=\"0\"],[onclick],[data-action]';\n return Array.from(document.querySelectorAll(sel))\n .filter((el: any) => el.offsetParent !== null)\n .slice(0, 150)\n .map((el: any) => ({\n meaning: el.getAttribute('aria-label') || el.textContent?.trim().slice(0, 100) || el.tagName.toLowerCase(),\n role: el.getAttribute('role') || el.tagName.toLowerCase(),\n expectedData: null, notes: null, boundingRect: null, ariaState: null, parentLandmark: null,\n }));\n }).catch(() => []) as any[];\n }\n const [elements] = await Promise.all([\n Promise.resolve(liteElements),\n workerPage.screenshot({ path: shotPath, fullPage: true })\n .then(async () => {\n const cloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`);\n return (AppBrain.saveScreenshot as any)(opts.tenantId, opts.projectId, screen.id, shotPath, screen.version, 'DESKTOP', cloudUrl);\n })\n .catch(() => {}),\n ]);\n\n // GAP 1: DOM snapshot for lite-worker path\n const lwDom = await capturePageHtml(workerPage);\n if (lwDom) {\n const lwDomPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(lwDomPath, lwDom, 'utf8');\n const lwDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(lwDomPath)}`;\n const lwDomCloud = await uploadToCloud(lwDomPath, lwDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, lwDomPath, lwDomCloud).catch(() => {});\n }\n\n // Nav-link pass \u2014 merged into main save cycle so clearScreenElements covers them too.\n // extractElements (main BFS) never runs for lite-worker screens, so nav/footer roles\n // must be captured here. Running before clear+save prevents additive accumulation.\n const _navEls = await (workerPage.evaluate as any)(() => {\n if (typeof (globalThis as any).__name === 'undefined') (globalThis as any).__name = (fn: any) => fn;\n const seen = new Set<string>();\n const items: Array<{meaning: string; role: string; notes: string}> = [];\n function isV(el: Element) {\n const s = window.getComputedStyle(el);\n return s.display !== 'none' && s.visibility !== 'hidden' && s.opacity !== '0';\n }\n // Wide nav selector: covers semantic nav, ARIA, header links, sidebar (aside/[role=complementary]),\n // and common class-based sidebars used by admin/dashboard pages.\n const NAV_SEL = [\n 'nav a', '[role=\"navigation\"] a', 'header a', 'footer nav a',\n '[aria-label*=\"navigation\" i] a', '[aria-label*=\"sidebar\" i] a',\n 'aside a', '[role=\"complementary\"] a',\n '[class*=\"sidebar\" i] a', '[class*=\"side-nav\" i] a', '[class*=\"sidenav\" i] a',\n '[class*=\"nav-menu\" i] a', '[class*=\"navmenu\" i] a', '[data-nav] a',\n ].join(', ');\n document.querySelectorAll(NAV_SEL).forEach((a: any) => {\n if (!isV(a)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n const href = a.href ?? '';\n if (!label || !href || /^(javascript:|#$)/i.test(href)) return;\n let landmark = 'Site Navigation';\n let cur: any = a.parentElement;\n while (cur) {\n const t = cur.tagName?.toLowerCase();\n const r = cur.getAttribute?.('role')?.toLowerCase();\n const cl = (cur.className ?? '').toLowerCase();\n if (t === 'header' || r === 'banner') { landmark = 'Header'; break; }\n if (t === 'footer' || r === 'contentinfo') { landmark = 'Footer'; break; }\n if (t === 'aside' || r === 'complementary' || cl.includes('sidebar') || cl.includes('sidenav') || cl.includes('side-nav')) { landmark = 'Sidebar'; break; }\n if (t === 'nav' || r === 'navigation') { landmark = cur.getAttribute('aria-label')?.trim() || 'Site Navigation'; break; }\n cur = cur.parentElement;\n }\n const key = `nav|${label.toLowerCase()}|${href}`;\n if (!seen.has(key)) { seen.add(key); items.push({ meaning: label, role: 'nav-link', notes: JSON.stringify({ href: href.slice(0, 150), landmark }) }); }\n });\n let fc = 0;\n document.querySelectorAll('footer a, [role=\"contentinfo\"] a, [class*=\"footer\" i] a').forEach((a: any) => {\n if (fc >= 20 || !isV(a)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n const href = a.href ?? '';\n if (!label || !href) return;\n const key = `footer|${label.toLowerCase()}|${href}`;\n if (!seen.has(key)) { seen.add(key); items.push({ meaning: label, role: 'footer-link', notes: JSON.stringify({ href: href.slice(0, 150) }) }); fc++; }\n });\n // Grandparent-grouping fallback: detects sidebar navigation where each link is\n // individually wrapped (e.g. <div class=\"flex\"><a>link</a></div> \u00D7 many siblings).\n // Runs ALWAYS (not gated on 0 results) so header links don't block sidebar detection.\n // Deduped against hrefs already captured by the semantic pass above.\n {\n const navHrefsSeen = new Set<string>();\n for (const it of items) {\n try { const h = JSON.parse(it.notes ?? '{}').href; if (h) navHrefsSeen.add(h); } catch { /* skip */ }\n }\n const gpGroups = new Map<Element, Array<{label: string; href: string}>>();\n document.querySelectorAll('a[href]').forEach((a: any) => {\n if (!isV(a)) return;\n const href = a.href ?? '';\n if (!href || /^(javascript:|#$|mailto:|tel:)/i.test(href) || navHrefsSeen.has(href)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n if (!label || label.length > 40) return;\n const parent = a.parentElement;\n const gp = parent?.parentElement;\n if (!parent || !gp) return;\n // Only match when parent wraps exactly 1 anchor \u2014 the sidebar <div><a> pattern\n if (parent.querySelectorAll('a').length !== 1) return;\n const gpTag = gp.tagName.toLowerCase();\n if (['body', 'html', 'form'].includes(gpTag)) return;\n const arr = gpGroups.get(gp) ?? [];\n arr.push({ label, href });\n gpGroups.set(gp, arr);\n });\n for (const [, links] of gpGroups.entries()) {\n if (links.length >= 4) {\n for (const { label, href } of links) {\n const k = `cluster|${label.toLowerCase()}|${href}`;\n if (!seen.has(k)) { seen.add(k); items.push({ meaning: label, role: 'nav-link', notes: JSON.stringify({ href: href.slice(0, 150), landmark: 'Sidebar' }) }); }\n }\n }\n }\n }\n return items;\n }).catch(() => [] as any[]);\n\n const allElements = [\n ...elements,\n ..._navEls.map((ne: any) => ({ ...ne, expectedData: undefined, boundingRect: undefined, ariaState: undefined, parentLandmark: undefined })),\n ];\n\n // Persist lite-worker elements to DB \u2014 without this, 80% of screens have 0 DB elements.\n if (allElements.length > 0) {\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, screen.id).catch(() => {});\n for (let _ei = 0; _ei < allElements.length; _ei += 2) {\n const _batch = allElements.slice(_ei, _ei + 2);\n await Promise.all(_batch.map((el: any) =>\n AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => {})\n ));\n }\n logger.info({ url, screenId: screen.id, elements: elements.length, navLinks: _navEls.length }, '[lite-worker] screen captured');\n } else if (!revisitQueue.includes(url)) {\n // 0-element: queue for main BFS re-visit with full Stagehand AI extraction\n logger.warn({ url, screenId: screen.id }, '[lite-worker] 0 elements \u2014 queued for P3a revisit');\n revisitQueue.push(url);\n }\n\n // Non-mutating probes for lite-worker screens: shadow DOM, a11y tree, service worker.\n // Awaited with 15s total timeout \u2014 these are read-only and safe on the shared worker page.\n if (screen?.id) {\n const [shadowRes, a11yRes, swRes] = await Promise.race([\n Promise.allSettled([\n crawlShadowDom(workerPage),\n crawlAccessibilityTree(workerPage),\n inspectServiceWorker(workerPage),\n ]),\n new Promise<PromiseSettledResult<never>[]>((resolve) =>\n setTimeout(() => resolve([\n { status: 'rejected' as const, reason: 'timeout' },\n { status: 'rejected' as const, reason: 'timeout' },\n { status: 'rejected' as const, reason: 'timeout' },\n ]), 15_000)\n ),\n ]);\n const litePayload: Record<string, unknown> = { screenId: screen.id, url };\n if (shadowRes.status === 'fulfilled' && shadowRes.value && (shadowRes.value as any).shadowHostCount > 0)\n litePayload.shadowDom = shadowRes.value;\n if (a11yRes.status === 'fulfilled' && a11yRes.value)\n litePayload.accessibilityTree = a11yRes.value;\n if (swRes.status === 'fulfilled' && (swRes.value as any).supported)\n litePayload.serviceWorker = swRes.value;\n if (Object.keys(litePayload).length > 2) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'PER_SCREEN_PROBES', payload: litePayload,\n }).catch(() => {});\n }\n }\n\n const nextLinks: string[] = await (workerPage.evaluate as any)((originStr: string) => {\n return Array.from(document.querySelectorAll('a[href],[data-href]'))\n .map((a: any) => {\n const raw = a.getAttribute('href') || a.getAttribute('data-href') || '';\n try { return new URL(raw, window.location.href).href; }\n catch { return ''; }\n })\n .filter((h: string) => {\n if (!h) return false;\n try {\n const u = new URL(h);\n if (u.origin !== originStr) return false;\n // Keep hash-router paths (#/route, #!/route) but drop plain fragment anchors (#section)\n if (u.hash && !u.hash.startsWith('#/') && !u.hash.startsWith('#!/')) return false;\n return true;\n } catch { return false; }\n })\n .slice(0, 200);\n }, origin).catch(() => []);\n\n for (const link of nextLinks) {\n if (!isUsefulNavigationUrl(link, origin)) continue;\n const cLink = canonicalize(link);\n if (!visited.has(cLink) && !queued.has(cLink)) {\n queued.add(cLink);\n queue.push(link);\n edges.push({ fromUrl: url, toUrl: link });\n }\n }\n\n discovered.push({ url, screenId: screen.id, elements: elements.length, elementFacts: elements, screenshotPath: shotPath, version: screen.version });\n // Lite workers also advance the progress bar \u2014 without this 4/5 workers are invisible.\n const lwEffMax = isFinite(maxScreens) ? Math.min(visited.size + queue.length, maxScreens * 3) : visited.size + queue.length;\n maxSeenTotal = Math.max(maxSeenTotal, lwEffMax);\n const lwRawPct = 20 + Math.round(Math.min(57, (visited.size / Math.max(1, maxSeenTotal)) * 57));\n const lwPct = Math.max(lastEmittedPct, lwRawPct);\n lastEmittedPct = lwPct;\n await onProgress?.(lwPct, `Crawling screens (${visited.size} mapped, ${queue.length} pending)`).catch(() => {});\n } catch (err: any) {\n logger.warn({ url, err: err?.message ?? String(err) }, '[lite-worker] URL processing failed');\n discovered.push({ url, error: err?.message ?? String(err) });\n }\n }\n }\n\n const liteWorkerPromises: Promise<void>[] = [];\n if (CRAWL_PAGE_PARALLELISM > 1 && playwrightBrowser && !opts.discoveryMode) {\n const pwCtx = playwrightBrowser.contexts()[0];\n for (let i = 1; i < CRAWL_PAGE_PARALLELISM; i++) {\n const wp = await pwCtx.newPage();\n await wp.addInitScript(() => { Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); }).catch(() => {});\n wp.setDefaultTimeout(tuning.defaultTimeoutMs || 45_000);\n liteWorkerPromises.push(runLiteWorker(wp).finally(() => wp.close().catch(() => {})));\n }\n }\n\n while (queue.length > 0 && visited.size < maxScreens && visited.size < segmentSize) {\n if (pendingSessionRestore) {\n await pendingSessionRestore();\n pendingSessionRestore = null;\n }\n if (++totalAttemptsThisSegment > maxAttempts) {\n logger.warn({ maxAttempts, visited: visited.size, queued: queue.length }, '[crawler] attempt cap reached \u2014 stopping to prevent URL explosion');\n break;\n }\n if (opts.abortSignal?.aborted) {\n logger.info('Abort signal received \u2014 stopping crawl');\n throw new Error('CRAWL_ABORTED');\n }\n if (isCrawlTimedOut()) {\n const elapsedMin = Math.round((Date.now() - crawlLoopStart) / 60_000);\n logger.warn({ elapsedMin, visited: visited.size, queued: queue.length }, '[crawler] Global timeout reached \u2014 stopping BFS to prevent runaway crawl');\n await onProgress?.(89, `Crawl timeout after ${elapsedMin}min \u2014 ${visited.size} pages captured`).catch(() => {});\n break;\n }\n // AutoThrottle: delay next request proportional to avg navigation latency\n if (opts.autoThrottle && navCount > 0) {\n const delayMs = Math.min(5_000, Math.max(0, avgNavMs * 0.5));\n if (delayMs > 100) await page.waitForTimeout(delayMs).catch(() => { });\n }\n\n const url = queue.shift()!;\n const canonUrl = canonicalize(url);\n const apiObservationStartIndex = capturedApiEndpoints.length;\n\n // Skip if already visited (canonical match \u2014 catches ID-parameterized duplicates)\n if (visited.has(canonUrl)) continue;\n // Claim immediately before any await \u2014 prevents lite workers from picking up the same URL\n // concurrently while this iteration is suspended (race that causes repeated visits).\n visited.set(canonUrl, '_pending_');\n logger.info({ url, visited: visited.size, queued: queue.length, segment: `${visited.size}/${segmentSize}` }, '[crawler] visiting URL');\n\n // robots.txt compliance \u2014 skip disallowed URLs\n if (robotsCache && !await robotsCache.isAllowed(url)) {\n logger.info({ url }, '[crawler] robots.txt: skipping disallowed URL');\n continue;\n }\n\n // Skip content/legal pages \u2014 they have no interactive form elements worth testing\n try {\n const { pathname } = new URL(url);\n if (SKIP_PATH.test(pathname)) {\n console.log(`[crawler] skip content page: ${url}`);\n continue;\n }\n // Generated ID-like path segments are usually fallback IDs or entity\n // records. They flood the catalog with duplicate page templates, so\n // skip them before screenshots or screen creation.\n // Exception: seed path patterns declared by the caller bypass this guard.\n if (isGeneratedDynamicPath(pathname) && !_activeSeedPatterns.some(re => re.test(pathname))) {\n console.log(`[crawler] skip generated dynamic route: ${url}`);\n continue;\n }\n // Skip API/export/download paths \u2014 navigating to these triggers file downloads.\n // The main BFS uses Stagehand's context which has no route interception.\n if (API_PATH_RE.test(pathname) || EXPORT_PATH_RE.test(pathname) || DOWNLOAD_EXT_RE.test(pathname)) {\n console.log(`[crawler] skip API/export/download path: ${url}`);\n visited.set(canonUrl, '_skipped_api_');\n continue;\n }\n } catch { /* invalid url, let it fall through */ }\n\n try {\n // Security headers \u2014 capture from first document response via CDP.\n // Stagehand V3's page proxy only supports the 'console' event (page.on throws for others).\n // We hook directly into the underlying CDP session's Network.responseReceived event instead.\n let securityHeaders: Record<string, string | null> | null = null;\n let httpStatus: number | null = null;\n const urlBase = url.replace(/[?#].*/, '');\n const cdpSession: any = (page as any).mainSession ?? (page as any)._session ?? null;\n const secHeadersCdp = (evt: any) => {\n if (securityHeaders) return;\n try {\n const responseUrl: string = evt?.response?.url ?? '';\n if (!responseUrl.startsWith(urlBase)) return;\n httpStatus = evt?.response?.status ?? null;\n const headers: Record<string, string> = {};\n // CDP headers come as array of {name, value} objects\n for (const h of (evt?.response?.headers ?? [])) headers[h.name.toLowerCase()] = h.value;\n securityHeaders = {\n csp: headers['content-security-policy'] ?? headers['content-security-policy-report-only'] ?? null,\n hsts: headers['strict-transport-security'] ?? null,\n xContentType: headers['x-content-type-options'] ?? null,\n xFrame: headers['x-frame-options'] ?? null,\n referrer: headers['referrer-policy'] ?? null,\n };\n } catch { /* non-fatal */ }\n };\n if (cdpSession?.on) cdpSession.on('Network.responseReceived', secHeadersCdp);\n\n const wsDetector = attachWebSocketDetector(cdpSession);\n\n if (url !== page.url()) {\n // LCP/CLS observers are registered via the addInitScript above, which\n // re-runs automatically on this navigation \u2014 nothing to do here.\n const navStart = Date.now();\n // Track redirect hops during this navigation\n const redirectHops: Array<{ from: string; to: string; statusCode: number }> = [];\n const onRedirectResponse = (res: any) => {\n const st = res.status();\n if (st >= 300 && st < 400) {\n redirectHops.push({ from: res.url(), to: res.headers()['location'] ?? '', statusCode: st });\n } else if (st >= 400) {\n deadLinkTracker.record(res.url(), st, { sourceUrl: url });\n }\n };\n rawPage.on('response', onRedirectResponse);\n\n // Session Isolation: Clear session before crawling public auth routes\n const AUTH_PATH_REGEX = /\\/(login|register|signup|sign-in|sign-up|forgot-password|reset-password)([-/]|$)/i;\n const isAuthRoute = AUTH_PATH_REGEX.test(new URL(url).pathname);\n const browserCtx = playwrightBrowser?.contexts()[0];\n \n if (isAuthRoute && browserCtx) {\n const currentState = await browserCtx.storageState();\n const hasSession = (currentState.cookies?.length ?? 0) > 0 ||\n currentState.origins?.some((o: any) => (o.localStorage?.length ?? 0) > 0);\n if (hasSession) {\n pendingSessionRestore = async () => {\n const ctx = playwrightBrowser?.contexts()[0];\n if (ctx) {\n await ctx.addCookies(currentState.cookies);\n await rawPage.evaluate((origins: any) => {\n for (const entry of (origins ?? [])) {\n if (window.location.origin === entry.origin) {\n for (const item of entry.localStorage) {\n try { localStorage.setItem(item.name, item.value); } catch {}\n }\n }\n }\n }, currentState.origins).catch(() => {});\n logger.info('[crawler] restored session state after public auth route');\n }\n };\n await browserCtx.clearCookies();\n await rawPage.evaluate(() => {\n try { localStorage.clear(); sessionStorage.clear(); } catch {}\n }).catch(() => {});\n logger.info({ url }, '[crawler] temporarily cleared session for public auth route');\n }\n }\n\n // Try fast 15 s first; only escalate to 30 s on timeout so happy-path pages don't wait\n const navErr15 = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: tuning.navTimeoutMs }).then(() => null, (e: any) => e);\n if (navErr15) {\n if (/timeout/i.test(String(navErr15?.message ?? navErr15))) {\n await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 }).catch((navErr: any) => {\n logger.warn({ url, err: navErr?.message ?? String(navErr) }, '[crawler] navigation failed \u2014 skipping');\n });\n } else {\n logger.warn({ url, err: navErr15?.message ?? String(navErr15) }, '[crawler] navigation failed \u2014 skipping');\n }\n }\n rawPage.off('response', onRedirectResponse);\n if (redirectHops.length > 0) {\n const isCircularRedirect = new Set(redirectHops.map(h => h.from)).size < redirectHops.length;\n redirectRegistry.register({\n originalUrl: url, finalUrl: page.url(),\n hops: redirectHops.map((h, i) => ({ ...h, durationMs: i === 0 ? Date.now() - navStart : 0 })),\n isCircular: isCircularRedirect,\n hopCount: redirectHops.length,\n totalDurationMs: Date.now() - navStart,\n });\n if (isCircularRedirect) {\n logger.warn({ url, hops: redirectHops.map(h => h.from) }, '[crawler] circular redirect detected \u2014 skipping URL');\n continue;\n }\n }\n // Update exponential moving average for AutoThrottle\n const navMs = Date.now() - navStart;\n navCount++;\n avgNavMs = avgNavMs + (navMs - avgNavMs) / navCount;\n }\n // chrome-error:// = TCP/HTTP connection failed (IP block, DNS failure, etc.)\n // Skip immediately \u2014 don't screenshot, don't trigger Skyvern, just move on.\n if (page.url().startsWith('chrome-error://')) {\n console.warn(`[crawler] connection failed for ${url} \u2014 skipping (chrome-error page)`);\n continue;\n }\n // Full page-ready sequence:\n // 1. load \u2014 waits for initial page load (faster than networkidle; XHR handled by waitForStableDOM)\n // 2. DOM stability \u2014 waits for React/Vue hydration to finish mutating the DOM\n // 3. Modal capture \u2014 screenshot app dialogs BEFORE dismissal (they are testable UI states)\n // 4. Overlay dismissal \u2014 removes cookie banners/modals before element extraction\n // 5. Lazy-load scroll \u2014 triggers IntersectionObserver for off-screen images/components\n await (rawPage ?? page).waitForLoadState('load', { timeout: 8_000 }).catch(() => { });\n await waitForStableDOM(page, 8_000, 400, rawPage ?? undefined);\n // If DOM is sparse after stability check (< 15 interactive elements), SPA may still be\n // fetching data \u2014 skeleton is DOM-stable but empty. Extra networkidle pass catches it.\n const sparseCheck = await (rawPage ?? page).evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"],[aria-label]').length\n ).catch(() => 99);\n if (sparseCheck < 15) {\n await (rawPage ?? page).waitForLoadState('networkidle', { timeout: 6_000 }).catch(() => {});\n await waitForStableDOM(page, 4_000, 300, rawPage ?? undefined);\n }\n // Wait for SPA auth-check / loading spinners to resolve before screenshotting.\n // SPAs often show a \"Checking authentication...\" or \"Loading...\" state after networkidle\n // while client-side auth verifies tokens. waitForStableDOM catches DOM mutations but\n // returns as soon as the spinner DOM is stable \u2014 this catches the spinner itself.\n // Stagehand V3 proxy may not expose waitForFunction \u2014 use try/catch, not .catch(),\n // because calling an undefined method throws synchronously before a Promise is created.\n try {\n const spinnerPage = rawPage ?? page;\n if (typeof spinnerPage.waitForFunction === 'function') {\n await spinnerPage.waitForFunction(() => {\n const body = document.body;\n if (!body) return true;\n const text = body.innerText?.toLowerCase() ?? '';\n // Text-based loading indicators\n if (\n text.includes('checking authentication') ||\n text.includes('checking auth') ||\n text.includes('authenticating') ||\n text.includes('verifying session') ||\n text.includes('please wait') ||\n text.includes('loading data') ||\n (text.includes('loading') && text.length < 200)\n ) return false;\n // ARIA-based: aria-busy on any visible element\n const busyEl = body.querySelector('[aria-busy=\"true\"]');\n if (busyEl && (busyEl as HTMLElement).offsetParent !== null) return false;\n // Data attributes: React Query / SWR / TanStack in-flight indicators\n if (body.querySelector('[data-loading=\"true\"],[data-pending=\"true\"],[data-fetching=\"true\"]')) return false;\n // Indeterminate progress bars\n if (body.querySelector('progress:not([value])')) return false;\n // Common CSS class patterns for loading skeletons\n const skeleton = body.querySelector('.skeleton,.skeleton-loader,.shimmer,.pulse-loader,.content-loader');\n if (skeleton && (skeleton as HTMLElement).offsetParent !== null) return false;\n return true;\n }, { timeout: 12_000 });\n }\n } catch { /* timed out or unsupported \u2014 screenshot whatever is there */ }\n\n if (!opts.discoveryMode) {\n // Capture app-generated modals BEFORE dismissing \u2014 cookie/GDPR banners excluded.\n try {\n const appModalVisible = await page.evaluate(() => {\n const dialogs = Array.from(document.querySelectorAll('[role=\"dialog\"], [role=\"alertdialog\"], [aria-modal=\"true\"]'));\n return dialogs.some((el: any) => {\n const text = (el.textContent ?? '').toLowerCase();\n const isCookieBanner = /(cookie|consent|gdpr|privacy policy|accept all|we use cookies)/i.test(text);\n const isVisible = el.offsetParent !== null || el.style.display !== 'none';\n return isVisible && !isCookieBanner;\n });\n }).catch(() => false);\n if (appModalVisible) {\n const modalHash = url.replace(/[^a-z0-9]/gi, '').slice(-12);\n const modalShotPath = path.join(opts.screenshotDir ?? '/tmp', `modal-${modalHash}.png`);\n await page.screenshot({ path: modalShotPath, fullPage: false }).catch(() => { });\n const modalName = await (rawPage ?? page).evaluate(() => {\n const h = document.querySelector('[role=\"dialog\"] h1,[role=\"dialog\"] h2,[role=\"dialog\"] [role=\"heading\"]');\n return h?.textContent?.trim() ?? 'Modal';\n }).catch(() => 'Modal');\n const modalScreen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, modalName, url, opts.jobId, discoveryMethodFor(url)).catch(() => null);\n if (modalScreen) {\n const modalCloudUrl = await uploadToCloud(modalShotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(modalShotPath)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, modalScreen.id, modalShotPath, modalScreen.version, 'DESKTOP', modalCloudUrl).catch(() => { });\n // GAP 3: DOM snapshot for modal/dialog capture\n const modalDom = await capturePageHtml(page);\n if (modalDom) {\n const modalDomPath = modalShotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(modalDomPath, modalDom, 'utf8');\n const modalDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(modalDomPath)}`;\n const modalDomCloud = await uploadToCloud(modalDomPath, modalDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, modalScreen.id, modalDomPath, modalDomCloud).catch(() => {});\n }\n // Extract elements from the modal BEFORE it is dismissed \u2014 use CDP path via rawPage\n const modalElements = await domFallbackElements(page, rawPage ?? undefined).catch(() => []);\n for (const el of modalElements) {\n AppBrain.saveElement(opts.tenantId, opts.projectId, modalScreen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => {});\n }\n logger.info({ url, name: modalName, elementCount: modalElements.length }, '[crawler] captured app modal before dismiss');\n }\n }\n } catch { /* non-fatal */ }\n await dismissOverlays(page);\n // Enhanced infinite scroll \u2014 handles lazy-load, infinite lists, and virtual scrollers\n await infiniteScrollToBottom(page, { maxScrolls: 30, scrollDelay: 350, stabilizeMs: 500 }, rawPage ?? undefined).catch(() => { });\n }\n if (cdpSession?.off) cdpSession.off('Network.responseReceived', secHeadersCdp);\n wsDetector.detach();\n\n // 429 Rate-limit \u2014 exponential backoff with jitter before continuing\n if (httpStatus === 429) {\n const backoffMs = Math.min(60_000, 1_000 * Math.pow(2, Math.min(navCount, 6)));\n logger.warn({ url, httpStatus, backoffMs }, '[crawler] 429 rate-limited \u2014 backing off');\n await new Promise(r => setTimeout(r, backoffMs + Math.random() * 1_000));\n }\n\n // Skip pages that returned an HTTP 4xx/5xx response \u2014 SPAs normally return 200 for all routes,\n // so a real HTTP error means the server knows this URL is invalid.\n if (httpStatus !== null && httpStatus >= 400) {\n logger.info({ url, httpStatus }, '[crawler] skip \u2014 server returned HTTP error');\n continue;\n }\n\n // \u2500\u2500 Mid-crawl session expiry detection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Only trigger re-auth when the app REDIRECTED us away from the intended URL.\n // If we intentionally navigate to /session-expired or /login \u2014 save it as a screen (it's\n // a real page worth testing: messaging, recovery buttons, error UX, etc.).\n const BFS_ERROR_PATH = /\\/(session-expired|expired|unauthorized|forbidden|401|403|logout|logged-out)(\\/|$|\\?)/i;\n const BFS_LOGIN_PATH = /\\/(login|signin|sign-in|auth|log-in|sso|account\\/login)(\\/|$|\\?)/i;\n const landedUrl = page.url();\n const weWantedThisPage = BFS_ERROR_PATH.test(new URL(url).pathname) || BFS_LOGIN_PATH.test(new URL(url).pathname);\n const redirectedToError = !weWantedThisPage && (\n BFS_ERROR_PATH.test(new URL(landedUrl).pathname) || BFS_LOGIN_PATH.test(new URL(landedUrl).pathname)\n );\n if (redirectedToError) {\n // Track login-wall redirects: if the site sends every URL to /login without credentials,\n // abort early rather than burning all maxAttempts on the same login page.\n if (BFS_LOGIN_PATH.test(new URL(landedUrl).pathname)) {\n loginWallRedirectCount++;\n if (!opts.credentials && loginWallRedirectCount >= LOGIN_WALL_ABORT_THRESHOLD) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: {\n url, landed: landedUrl,\n reason: `Login wall detected: ${loginWallRedirectCount} consecutive URLs redirected to login. Add credentials in project settings to crawl authenticated pages.`,\n },\n }).catch(() => {});\n // Checkpoint remaining queue so job-queue can auto-requeue the pending URLs\n await opts.onCheckpoint?.(\n Array.from(visited.entries()).filter(([_k, v]) => v !== '_pending_').map(([k]) => k),\n queue.filter((u: string) => !visited.has(canonicalize(u)))\n ).catch(() => {});\n throw new Error(`[AUTH_FAILURE] Login wall detected: ${loginWallRedirectCount} URLs redirected to the login page. Add credentials in project settings and retry the crawl.`);\n }\n }\n // We asked for /dashboard but landed on /session-expired \u2014 session expired mid-crawl.\n logger.warn({ requested: url, landed: landedUrl }, '[crawler] Mid-crawl redirect to auth/error \u2014 attempting re-auth');\n let reauthed = false;\n if (opts.credentials) {\n reauthed = await loginWithStagehand(\n stagehand, opts.credentials, opts.appUrl,\n { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider },\n { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId },\n undefined,\n { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId },\n ).catch(() => false);\n if (reauthed) {\n logger.info({ url }, '[crawler] Re-auth succeeded \u2014 retrying URL');\n await page.goto(url, { waitUntil: 'domcontentloaded' }).catch(() => { });\n await (rawPage ?? page).waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => { });\n await waitForStableDOM(page, 8_000, 400, rawPage ?? undefined);\n const afterReauthUrl = page.url();\n if (BFS_ERROR_PATH.test(new URL(afterReauthUrl).pathname) || BFS_LOGIN_PATH.test(new URL(afterReauthUrl).pathname)) {\n logger.warn({ url }, '[crawler] Still redirecting after re-auth \u2014 skipping this URL');\n continue;\n }\n } else {\n logger.warn({ url }, '[crawler] Re-auth failed \u2014 stopping BFS (session unrecoverable)');\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: { url, landed: landedUrl, reason: 'Re-authentication failed. Session is unrecoverable. Re-capture the session in project settings and retry the crawl.' },\n }).catch(() => { });\n // Checkpoint remaining queue before aborting so job-queue can auto-requeue\n await opts.onCheckpoint?.(\n Array.from(visited.entries()).filter(([_k, v]) => v !== '_pending_').map(([k]) => k),\n queue.filter((u: string) => !visited.has(canonicalize(u)))\n ).catch(() => {});\n throw new Error('[AUTH_FAILURE] Re-authentication failed. Session is unrecoverable. Re-capture the session in project settings and retry the crawl.');\n }\n } else {\n // Discovery mode: skip auth-required URLs and continue discovering other links.\n // Throwing here aborts the entire BFS \u2014 in discovery mode we want to continue\n // visiting other queued URLs (e.g. sitemap seeds) that may not require auth.\n if (opts.discoveryMode) {\n logger.info({ url, landed: landedUrl }, '[discover] skipping auth-required URL \u2014 no credentials, continuing BFS');\n continue;\n }\n logger.warn('[crawler] Session expired mid-crawl, no credentials to recover \u2014 skipping URL');\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: { url, landed: landedUrl, reason: 'Session expired and no credentials are configured. Add credentials in project settings and re-capture the session.' },\n }).catch(() => { });\n // Checkpoint remaining queue before aborting so job-queue can auto-requeue\n await opts.onCheckpoint?.(\n Array.from(visited.entries()).filter(([_k, v]) => v !== '_pending_').map(([k]) => k),\n queue.filter((u: string) => !visited.has(canonicalize(u)))\n ).catch(() => {});\n throw new Error('[AUTH_FAILURE] Session expired and no credentials are configured. Add credentials in project settings and re-capture the session.');\n }\n }\n // If weWantedThisPage (intentional /login, /session-expired, /404 navigation) \u2014\n // fall through and save it as a real screen. Error pages are legitimate test targets.\n if (!redirectedToError && landedUrl !== url) {\n logger.info({ requested: url, landed: landedUrl }, '[crawler] navigated with redirect');\n }\n // Successful non-login page visit: reset the consecutive login-wall counter\n if (!redirectedToError) loginWallRedirectCount = 0;\n\n // Discovery mode fast-path: record URL + extract DOM links only; skip screenshots/DB/AI.\n // IMPORTANT: DOM hash dedup is intentionally DISABLED in discovery mode \u2014 SPAs use identical\n // page shells for every route, so hashing would skip all pages after the first one.\n if (opts.discoveryMode) {\n visited.set(canonicalize(url), url); // key=canonical for dedup; value=original URL returned to caller\n\n // \u2500\u2500 SPA hydration wait \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // 'domcontentloaded' fires before JS executes, so shadow DOM doesn't exist yet.\n // Wait for network idle to ensure JS bundles are downloaded + executed,\n // then add a brief buffer for component rendering (setTimeout/rAF-deferred work).\n await (rawPage ?? page).waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => { });\n await page.waitForTimeout(500).catch(() => { });\n\n // \u2500\u2500 Link extraction \u2014 three approaches, merged \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // 1. Playwright native locator (auto-pierces shadow DOM in Playwright 1.20+)\n // Works universally for React, Vue, Angular, Polymer, Lit, Stencil, FAST.\n // 2. BFS shadow DOM traversal via evaluate() \u2014 catches any gaps from approach 1.\n // 3. SPA route manifests (Next.js __NEXT_DATA__, React Router registries).\n const rawLinksSet = new Set<string>();\n const addLink = (h: string) => {\n if (!h || h === '#' || h.startsWith('javascript:') || h.startsWith('mailto:') || h.startsWith('tel:')) return;\n try {\n const href = new URL(h, origin).toString();\n if (isUsefulNavigationUrl(href, origin)) rawLinksSet.add(href);\n } catch {\n // ignore malformed links\n }\n };\n\n // 1\uFE0F\u20E3 Playwright locator \u2014 shadow-DOM-piercing (primary approach)\n const pwPage = rawPage ?? page;\n await pwPage.locator('a[href]').evaluateAll((anchors: Element[]) =>\n anchors.map((a: any) => a.href || a.getAttribute('href') || '')\n ).then((hrefs: string[]) => hrefs.forEach(addLink)).catch(() => { });\n\n await pwPage.locator('[data-href],[data-url],[data-link]').evaluateAll((els: Element[]) =>\n els.map((el: any) => el.dataset?.href || el.dataset?.url || el.dataset?.link || '')\n ).then((hrefs: string[]) => hrefs.forEach(addLink)).catch(() => { });\n\n await pwPage.locator('[href]:not(a):not(link):not(base):not(script):not(style)').evaluateAll((els: Element[]) =>\n els.map((el: any) => el.getAttribute('href') || '')\n ).then((hrefs: string[]) => hrefs.forEach(addLink)).catch(() => { });\n\n const playwrightCount = rawLinksSet.size;\n console.log(`[discover] playwright-locator found ${playwrightCount} links for ${url}`);\n\n // 2\uFE0F\u20E3 BFS shadow DOM evaluate \u2014 fallback / complement for stubborn SPAs\n // Runs regardless so it can catch elements the locator misses.\n const evalPage = rawPage ?? page;\n await evalPage.evaluate((o: string) => {\n try {\n const hrefs: string[] = [];\n const add = (h: string) => {\n if (h && h !== '#' && !h.startsWith('javascript:') && !h.startsWith('mailto:') && !h.startsWith('tel:')) {\n if (h.startsWith(o) || h.startsWith('/')) hrefs.push(h);\n }\n };\n const queue: any[] = [document];\n const seenRoots = new WeakSet<any>();\n seenRoots.add(document);\n let shadowRootsFound = 0;\n while (queue.length > 0) {\n const root: any = queue.shift();\n if (!root) continue;\n try {\n root.querySelectorAll('a[href]').forEach((a: any) => add(a.href || a.getAttribute('href') || ''));\n root.querySelectorAll('[data-href],[data-url],[data-link]').forEach((el: any) => {\n add((el.dataset && (el.dataset.href || el.dataset.url || el.dataset.link)) || '');\n });\n root.querySelectorAll('[href]:not(a):not(link):not(base):not(script):not(style)').forEach((el: any) => {\n const h = el.getAttribute('href') || '';\n if (h && !h.startsWith('#')) add(h);\n });\n root.querySelectorAll('*').forEach((el: any) => {\n try {\n if (el.shadowRoot && !seenRoots.has(el.shadowRoot)) {\n seenRoots.add(el.shadowRoot);\n queue.push(el.shadowRoot);\n shadowRootsFound++;\n }\n } catch (_) { /* closed shadow root \u2014 skip */ }\n });\n } catch (_) { /* element threw \u2014 skip */ }\n }\n return { hrefs, shadowRootsFound };\n } catch { return { hrefs: [] as string[], shadowRootsFound: 0 }; }\n }, origin).then((result: any) => {\n (result?.hrefs ?? []).forEach(addLink);\n if (result?.shadowRootsFound > 0) {\n console.log(`[discover] bfs found ${result.shadowRootsFound} shadow roots, added ${rawLinksSet.size - playwrightCount} extra links for ${url}`);\n }\n }).catch(() => { });\n\n // 3\uFE0F\u20E3 SPA route manifests\n await evalPage.evaluate(() => {\n const routes: string[] = [];\n try {\n const nd = (window as any).__NEXT_DATA__;\n if (nd?.page) routes.push(nd.page);\n } catch (_) { /* non-fatal */ }\n try {\n const w = window as any;\n const rr = w.__reactRouterRoutes || (w.__reactRouterManifest?.routes);\n if (rr) {\n const collect = (r: any) => {\n if (r?.path && r.path !== '*') routes.push(r.path.startsWith('/') ? r.path : '/' + r.path);\n if (r?.children) r.children.forEach(collect);\n };\n (Array.isArray(rr) ? rr : Object.values(rr)).forEach(collect);\n }\n } catch (_) { /* non-fatal */ }\n return routes;\n }).then((routes: any[]) => {\n (routes ?? []).forEach(p => {\n try { addLink(new URL(p, origin).href); } catch { /* ignore */ }\n });\n }).catch(() => { });\n\n const rawLinks = Array.from(rawLinksSet);\n console.log(`[discover] ${url} \u2192 rawLinks=${rawLinks.length} origin=${origin} pageUrl=${page.url()}`);\n if (rawLinks.length > 0) console.log(`[discover] sample links: ${rawLinks.slice(0, 5).join(' | ')}`);\n let newlyQueued = 0;\n for (const link of rawLinks) {\n try {\n const resolved = link.startsWith('/') ? `${origin}${link}` : link;\n const u = new URL(resolved);\n // Keep hash-router fragments (#/route, #!/route) \u2014 strip plain anchors (#section)\n if (!/^#!?\\//.test(u.hash)) u.hash = '';\n const clean = u.toString();\n if (!isUsefulNavigationUrl(clean, origin)) continue;\n // Dedup: use canonical form to avoid crawling 1000 product detail pages separately\n const norm = canonicalize(clean);\n if (!visited.has(norm) && !queued.has(norm)) { queued.add(norm); queue.push(clean); newlyQueued++; }\n } catch { /* ignore malformed */ }\n }\n if (newlyQueued > 0) console.log(`[discover] queued ${newlyQueued} new URLs, queue size=${queue.length}`);\n const pct = 10 + Math.round((visited.size / Math.max(1, opts.maxScreens ?? 1000)) * 80);\n await onProgress?.(Math.min(pct, 89), `Discovered ${visited.size} URLs\u2026`);\n // Stream partial results to caller so they can be persisted/shown incrementally\n if (opts.onUrlsDiscovered) {\n await opts.onUrlsDiscovered(Array.from(visited.values())).catch(() => { });\n }\n continue;\n }\n\n // Normal crawl mode: DOM hash dedup \u2014 detect duplicate-structure pages (SPA 404s, template clones).\n // Skip dedup when hash is empty (computeDomHash failed) \u2014 two failed-hash pages would\n // incorrectly match each other and the second would be silently dropped.\n const preDomHash = await computeDomHash(page);\n if (preDomHash !== '' && seenDomHashes.has(preDomHash)) {\n console.log(`[crawler] skip ${url} \u2014 duplicate DOM structure (same content as prior page)`);\n continue;\n }\n const pageTitle = await page.title().catch(() => '');\n if (/\\b(not found|404|page not found|this page could not be found)\\b/i.test(pageTitle)) {\n console.log(`[crawler] skip ${url} \u2014 error page detected (title: \"${pageTitle}\")`);\n seenDomHashes.add(preDomHash); // register so future 404 pages also hit hash-dedup\n continue;\n }\n // Soft-404: SPA catch-all routes return 200 but render identical homepage content.\n // Skip any non-homepage URL whose title + interactive element count matches the homepage.\n if (homeFingerprintElemCount >= 0 && url !== startUrl && pageTitle === homeFingerprintTitle && pageTitle !== '') {\n const pElemCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"]').length\n ).catch(() => -1);\n if (pElemCount >= 0 && pElemCount === homeFingerprintElemCount) {\n console.log(`[crawler] skip ${url} \u2014 soft-404 (homepage fingerprint match, title=\"${pageTitle}\" elems=${pElemCount})`);\n seenDomHashes.add(preDomHash);\n continue;\n }\n }\n // Do NOT add real pages to seenDomHashes \u2014 server-rendered sites (WooCommerce, WordPress)\n // use the same template for many legitimate pages; registering the hash would skip them all.\n\n // Collect Navigation Timing + Paint Timing immediately after DOM stable.\n // LCP/CLS come from the buffered PerformanceObservers registered in the\n // init script above (the synchronous timeline never holds LCP entries).\n const rawPerf = await page.evaluate(() => {\n const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined;\n const paints = performance.getEntriesByType('paint');\n // Prefer pre-registered observer value (window.__zetaLCP) over buffered entries.\n // Buffered entries are often empty if the observer wasn't registered before navigation.\n const lcpFromObserver: number | null = (window as any).__zetaLCP ?? null;\n const lcpEntries = performance.getEntriesByType('largest-contentful-paint');\n const lcpFromEntries = lcpEntries.length > 0\n ? Math.round((lcpEntries[lcpEntries.length - 1] as any).startTime)\n : undefined;\n // @ts-ignore \u2014 stashed by the CLS init script\n // @ts-ignore \u2014 stashed by the web-vitals init script\n const stashedLcp: number | null = (window as any).__zetaLCP ?? null;\n // @ts-ignore\n const stashedCls: number | undefined = (window as any).__zetaCLS;\n return {\n ttfb: nav ? Math.round(nav.responseStart - nav.fetchStart) : undefined,\n fcp: paints.find(p => p.name === 'first-contentful-paint')?.startTime\n ? Math.round(paints.find(p => p.name === 'first-contentful-paint')!.startTime)\n : undefined,\n lcp: lcpFromObserver != null ? Math.round(lcpFromObserver) : lcpFromEntries,\n cls: typeof stashedCls === 'number' ? Math.round(stashedCls * 1000) / 1000 : undefined,\n };\n }).catch(() => null);\n\n // Accessibility audit via axe-core (WCAG 2.0 A/AA + best-practice)\n const a11yResult = await (async () => {\n try {\n const _require = createRequire(import.meta.url);\n const axePath = _require.resolve('axe-core');\n // page.evaluate() with script content bypasses CSP (DevTools Runtime.evaluate).\n // page.addScriptTag({ path }) is blocked by strict-CSP on many production sites.\n const axeContent = readFileSync(axePath, 'utf8');\n await page.evaluate(axeContent);\n const result = await page.evaluate(async () => {\n return (window as any).axe.run(document, {\n runOnly: { type: 'tag', values: ['wcag2a', 'wcag2aa', 'best-practice'] },\n resultTypes: ['violations'],\n });\n });\n // Full violation objects for DB storage (Phase 4.4)\n const violations = result.violations.map((v: any) => ({\n impact: v.impact as string,\n rule: v.id as string,\n description: v.description as string,\n // First offending node's outer HTML (truncated later in saveA11yViolations)\n nodeHtml: (v.nodes?.[0]?.html as string | undefined) ?? undefined,\n wcagTags: (v.tags as string[]).filter((t: string) => t.startsWith('wcag') || t.startsWith('best-')),\n }));\n const criticalCount = violations.filter((v: any) => v.impact === 'critical').length;\n return { violations, violationCount: violations.length, criticalCount };\n } catch (err) {\n logger.warn({ err: String((err as any)?.message ?? err) }, '[crawler] axe-core a11y audit failed (non-fatal)');\n return null;\n }\n })();\n const a11yScore = a11yResult\n ? Math.max(0, 100 - (a11yResult.criticalCount * 20) - ((a11yResult.violationCount - a11yResult.criticalCount) * 5))\n : null;\n\n\n // Screen name strategy (SPA-aware):\n // 1. Title with page-specific segment (e.g. \"Dashboard | ZeTA\")\n // 2. aria-current=\"page\" active nav item (reliable for SPAs)\n // 3. Page-specific headings that are NOT the brand name\n // 4. URL path segments (skipping cuid/UUIDs/numerics)\n const name = await (async () => {\n let brandName = '';\n\n // Compute reliable URL path-based name \u2014 skip cuid/UUID/numeric segments\n let pathName = 'Home';\n try {\n const u = new URL(url);\n const hostname = u.hostname.replace(/^www\\./, '').split('.')[0]!.toLowerCase();\n const allSegs = u.pathname.split('/').filter(Boolean);\n const IS_ID = (s: string) =>\n /^\\d+$/.test(s) || // numeric\n /^[0-9a-f]{8,}$/i.test(s) || // hex id\n /^[a-z]{1,2}[0-9a-z]{20,}$/i.test(s); // cuid/cuid2 (e.g. cm...)\n\n const readable = allSegs\n .filter((s) => !IS_ID(s))\n .map((s) => s.charAt(0).toUpperCase() + s.slice(1).replace(/[-_]/g, ' '));\n\n if (readable.length > 0) {\n const last = readable[readable.length - 1]!;\n const GENERIC = ['edit', 'new', 'create', 'view', 'show', 'index', 'detail', 'details'];\n if (GENERIC.includes(last.toLowerCase()) && readable.length > 1) {\n pathName = `${readable[readable.length - 2]} \u00B7 ${last}`;\n } else {\n pathName = last;\n }\n } else if (allSegs.length > 0) {\n // All segments were IDs \u2014 use the last non-trivial one\n const lastSeg = allSegs[allSegs.length - 1]!;\n pathName = lastSeg.slice(0, 8).toUpperCase();\n }\n\n // Append significant query params\n const SIG_PARAMS = ['product_cat', 'category', 'cat', 'type', 'tag', 'brand', 'filter', 'tab', 'section', 'view', 'play', 'mode', 'id', 'page'];\n const paramSuffix = SIG_PARAMS\n .map((p) => { const v = u.searchParams.get(p); return v ? ` \u00B7 ${v.replace(/[-_]/g, ' ').replace(/\\b\\w/g, (c) => c.toUpperCase())}` : ''; })\n .find(Boolean) ?? '';\n pathName = pathName + paramSuffix;\n\n // Detect brand name from hostname for later comparisons\n brandName = hostname;\n } catch { /* fall through */ }\n\n // 1. Document title \u2014 use only if it has a page-specific segment\n try {\n const title = await page.title();\n if (title && title.length > 0 && title.length < 120) {\n const parts = title.split(/\\s*[|\u2014\\-\u2013\u00B7]\\s*/);\n // Store brand candidate (usually last segment)\n if (parts.length > 1) brandName = (parts[parts.length - 1] ?? brandName).trim().toLowerCase();\n\n if (parts.length > 1) {\n // \"Dashboard | ZeTA\" \u2192 \"Dashboard\"\n const candidate = parts[0].trim();\n if (candidate.length > 2 && !/^\\d[\\d\\s]*$/.test(candidate)) return candidate;\n }\n // Single-segment title \u2014 only use if multi-word, not brand-name-like, and not the generic SPA app title\n const candidate = parts[0].trim();\n const isBrand = candidate.split(/\\s+/).length === 1 &&\n (candidate.toLowerCase().includes(brandName) || candidate.toLowerCase() === brandName);\n const isSiteGenericTitle = homeFingerprintTitle !== '' && candidate === homeFingerprintTitle;\n if (!isBrand && !isSiteGenericTitle && candidate.split(/\\s+/).length > 1 && !/^\\d[\\d\\s]*$/.test(candidate)) {\n return candidate;\n }\n }\n } catch { /* fall through */ }\n\n // 2. Active nav item \u2014 SPAs set aria-current=\"page\" on the active route link\n try {\n const activeNav = await page.locator('[aria-current=\"page\"]').first().textContent({ timeout: tuning.defaultTimeoutMs }).catch(() => null);\n if (activeNav) {\n const t = activeNav.trim();\n if (t.length > 1 && t.length < 60 && t.toLowerCase() !== brandName) return t;\n }\n } catch { /* fall through */ }\n\n // 3. Page-specific heading \u2014 skip if it's just the brand name\n try {\n const selectors = [\n 'main h1', '[role=\"main\"] h1', '.page-title', '.page-header h1', '.content h1',\n 'main h2', '[role=\"main\"] h2', '.page-header h2',\n ];\n for (const sel of selectors) {\n const h = await page.locator(sel).first().textContent({ timeout: tuning.defaultTimeoutMs }).catch(() => null);\n if (!h) continue;\n const t = h.trim();\n if (t.length < 2 || t.length > 80) continue;\n // Skip if it's the brand name (exact or contains hostname)\n if (t.toLowerCase() === brandName) continue;\n if (brandName && t.toLowerCase().replace(/\\s/g, '').includes(brandName.replace(/\\s/g, ''))) continue;\n return t;\n }\n } catch { /* fall through */ }\n\n // Safety: if the only candidate is the brand/hostname, fall back to URL path.\n try {\n const hostname = new URL(url).hostname.replace(/^www\\./, '').split('.')[0]!.toLowerCase();\n if (pathName !== 'Home' || name.toLowerCase() === hostname || name.toLowerCase().replace(/\\s/g, '') === hostname) {\n // name is still brand-name-equivalent \u2014 use URL-derived pathName\n if (name.toLowerCase() === hostname || name.toLowerCase().replace(/\\s/g, '') === hostname) {\n return pathName;\n }\n }\n } catch { /* ignore */ }\n\n return pathName;\n })();\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, name, url, opts.jobId, discoveryMethodFor(url));\n visited.set(canonicalize(url), screen.id);\n\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `${screen.id}-desktop-v${screen.version}.png`);\n\n // Wait for skeleton loaders / aria-busy spinners to resolve before screenshotting and analysis.\n // Stagehand V3 proxy does NOT support page.waitForFunction \u2014 use page.evaluate polling instead.\n await (async () => {\n const deadline = Date.now() + 4_000;\n while (Date.now() < deadline) {\n const ready = await page.evaluate(() => {\n const busy = document.querySelectorAll('[aria-busy=\"true\"], [data-loading=\"true\"]');\n const skeletons = document.querySelectorAll('.skeleton, [class*=\"skeleton\"], [class*=\"Skeleton\"]');\n return busy.length === 0 && skeletons.length === 0;\n }).catch(() => true); // if evaluate fails, assume ready\n if (ready) break;\n await new Promise(r => setTimeout(r, 200));\n }\n })();\n\n // Fire-and-forget per-page analyses \u2014 non-blocking, failures silently swallowed.\n // screen is now declared; page still has current page state and is fully hydrated.\n void (async () => {\n const screenId = screen.id;\n const [seoR, contrastR, flagsR, langR, formsR, a11yManualR] = await Promise.allSettled([\n checkSeo(page, url),\n auditColorContrast(page, url),\n detectFeatureFlags(page, url),\n detectLanguage(page, url),\n detectForms(page),\n auditAccessibility(page, url),\n ]);\n const base = { screenId, jobId: opts.jobId };\n if (seoR.status === 'fulfilled')\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'SEO_CHECK', payload: seoR.value }).catch(() => { });\n if (contrastR.status === 'fulfilled' && (contrastR.value as any).issues?.length)\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'COLOR_CONTRAST', payload: contrastR.value }).catch(() => { });\n if (flagsR.status === 'fulfilled' && (flagsR.value as any).flags?.length)\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'FEATURE_FLAGS', payload: flagsR.value }).catch(() => { });\n if (langR.status === 'fulfilled')\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'LANGUAGE_DETECTION', payload: langR.value }).catch(() => { });\n if (formsR.status === 'fulfilled' && Array.isArray(formsR.value) && formsR.value.length)\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'FORMS_DETECTED', payload: { forms: formsR.value } }).catch(() => { });\n if (a11yManualR.status === 'fulfilled' && (a11yManualR.value as any).violations?.length)\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'A11Y_MANUAL_AUDIT', payload: a11yManualR.value }).catch(() => { });\n })();\n\n // Freeze all CSS animations/transitions so screenshots are stable across runs\n try { await page.addStyleTag({ content: '*, *::before, *::after { animation-duration: 0s !important; animation-delay: 0s !important; transition-duration: 0s !important; transition-delay: 0s !important; animation-play-state: paused !important; animation-fill-mode: both !important; }' }); } catch { /* Stagehand proxy may not expose addStyleTag */ }\n // Freeze JS-driven animations (requestAnimationFrame loops, setInterval animations)\n await page.evaluate(() => {\n try {\n const noop = () => 0;\n Object.defineProperty(window, 'requestAnimationFrame', { value: noop, configurable: true });\n Object.defineProperty(window, 'cancelAnimationFrame', { value: noop, configurable: true });\n } catch { /* property may not be configurable */ }\n }).catch(() => { });\n\n // Replay-first: check for a cached link-discovery recipe before calling AI Stagehand\n const canonUrl = canonicalize(url);\n const linkRecipe = await AppBrain.getActionRecipe(\n opts.tenantId, opts.projectId, new URL(url).hostname, `link-discovery:${canonUrl}`\n ).catch(() => null);\n const cachedLinks: string[] | null = (linkRecipe && (linkRecipe as any).successRate >= 0.7)\n ? (((linkRecipe as any).steps as any[])\n .map((s: any) => s.href)\n .filter((href: string | undefined): href is string => !!href && isUsefulNavigationUrl(href, origin)))\n : null;\n if (cachedLinks) {\n logger.info({ url, cachedCount: cachedLinks.length }, '[crawler] link-discovery: using cached recipe \u2014 AI will still run and merge');\n }\n\n // Emit progress now \u2014 navigation done, page stable.\n // Use the same visited-count formula as the post-capture block so progress\n // advances on EVERY URL visit (not just on successful screen saves).\n {\n const effMax = isFinite(maxScreens) ? Math.min(visited.size + queue.length, maxScreens * 3) : visited.size + queue.length;\n maxSeenTotal = Math.max(maxSeenTotal, effMax);\n const rawPrePct = 20 + Math.round(Math.min(57, (visited.size / Math.max(1, maxSeenTotal)) * 57));\n const preCapturePct = Math.max(lastEmittedPct, rawPrePct);\n lastEmittedPct = preCapturePct;\n await onProgress?.(preCapturePct, `Crawling ${visited.size} of ~${visited.size + queue.length} \u00B7 ${(() => { try { return new URL(url).pathname || '/'; } catch { return '/'; } })()}`);\n }\n\n await waitForScreenshotReady(page, rawPage ?? undefined);\n\n // P3a: Async content detection \u2014 count AFTER networkidle+lazy-load so lazy-fetched content\n // is included. Previously captured before waitForScreenshotReady which caused AI skip logic\n // to see skeleton element counts instead of real populated counts.\n const preDomCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"],[onclick],[aria-label]').length\n ).catch(() => 0);\n await onProgress?.(lastEmittedPct, `Capturing ${(() => { try { return new URL(url).pathname || '/'; } catch { return '/'; } })()}`);\n\n // FM-4: capture device pixel ratio for coordinate scaling in element highlighting\n const pageDpr: number = await (rawPage ?? page).evaluate(() => window.devicePixelRatio ?? 1).catch(() => 1);\n\n // Extract elements first so we can highlight them in the screenshot\n const elements = await extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined).catch((err: any) => {\n console.error('[crawler] extractElements failed:', err);\n return [] as Awaited<ReturnType<typeof extractElements>>;\n });\n\n // Inject bounding boxes for the screenshot\n await page.evaluate((elems: any[]) => {\n const container = document.createElement('div');\n container.id = '__zeta_element_highlights';\n container.style.position = 'absolute';\n container.style.top = '0';\n container.style.left = '0';\n container.style.width = '100%';\n container.style.height = '100%';\n container.style.pointerEvents = 'none';\n container.style.zIndex = '2147483647';\n \n elems.forEach((el, index) => {\n if (!el.boundingRect) return;\n const rect = el.boundingRect;\n const box = document.createElement('div');\n box.style.position = 'absolute';\n box.style.left = (rect.x + window.scrollX) + 'px';\n box.style.top = (rect.y + window.scrollY) + 'px';\n box.style.width = rect.width + 'px';\n box.style.height = rect.height + 'px';\n box.style.border = '2px solid rgba(255, 0, 0, 0.8)';\n box.style.backgroundColor = 'rgba(255, 0, 0, 0.1)';\n box.style.boxSizing = 'border-box';\n \n const label = document.createElement('div');\n label.textContent = el.role || 'element';\n label.style.position = 'absolute';\n label.style.top = '-16px';\n label.style.left = '-2px';\n label.style.backgroundColor = 'rgba(255, 0, 0, 0.9)';\n label.style.color = '#FFF';\n label.style.fontSize = '10px';\n label.style.padding = '2px 4px';\n label.style.borderRadius = '2px';\n label.style.whiteSpace = 'nowrap';\n label.style.fontFamily = 'monospace';\n box.appendChild(label);\n \n container.appendChild(box);\n });\n document.body.appendChild(container);\n }, elements).catch(() => {});\n\n // Parallelize: screenshot + link discovery + AT capture\n const [, nextLinks, atElements] = await Promise.all([\n page.screenshot({ path: shotPath, fullPage: true })\n .then(async () => {\n const cloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`);\n return (AppBrain.saveScreenshot as any)(opts.tenantId, opts.projectId, screen.id, shotPath, screen.version, 'DESKTOP', cloudUrl, pageDpr);\n })\n .catch((err: any) => console.error('[crawler] page.screenshot failed:', err)),\n // Always run AI link discovery (even when cache exists) \u2014 cache is merged in, not used as a replacement.\n // Skipping AI when cache exists was a bug: stale cache from broken crawls permanently blocked discovery.\n // Note: preDomCount < aiMinElements guard removed \u2014 it was backwards: sparse pages (SPAs) need AI most.\n discoverLinks(stagehand, origin, page, linkLLM ?? undefined, aiSkipCount > 0, rawPage ?? undefined)\n .then((metas) => {\n // Persist nav-graph edges fire-and-forget\n if (metas.length > 0) {\n AppBrain.saveDiscoveredLinks(opts.tenantId, opts.projectId, screen.id, metas.map((m) => ({\n href: m.url, text: m.text, landmark: m.landmark, linkType: 'NAV_LINK', source: m.source, jobId: opts.jobId,\n }))).catch(() => {});\n }\n return metas.map(m => m.url);\n })\n .then((freshLinks) => {\n if (aiSkipCount > 0) aiSkipCount--;\n aiErrorStreak = 0;\n const freshUrls = freshLinks;\n const merged = (cachedLinks ? Array.from(new Set([...cachedLinks, ...freshUrls])) : freshUrls)\n .filter((href) => isUsefulNavigationUrl(href, origin));\n logger.info({ url, domLinks: freshLinks.length, cached: cachedLinks?.length ?? 0, merged: merged.length }, '[crawler] link-discovery: result');\n // Always persist fresh recipe so stale cache gets overwritten with new AI discoveries\n if (merged.length > 0) {\n AppBrain.saveActionRecipe(opts.tenantId, opts.projectId, {\n domain: new URL(url).hostname,\n purpose: `link-discovery:${canonUrl}`,\n fingerprint: sha256(canonUrl),\n steps: merged.map((href) => ({ action: 'link', href })),\n successRate: 0.8,\n }).catch(() => { });\n }\n return merged;\n })\n .catch((err: any) => {\n const fallback: string[] = (err?.domLinks ?? []).map((l: DiscoveredLinkMeta) => l.url);\n if (err?.isRateLimit) {\n aiErrorStreak++;\n if (aiErrorStreak >= 5) { aiSkipCount = 3; aiErrorStreak = 0; logger.warn('[crawler] 5 consecutive AI rate limits \u2014 pausing AI link discovery for next 3 screens then retrying'); }\n if (!aiRateLimitWarned) {\n aiRateLimitWarned = true;\n onProgress?.(20, 'AI quota exhausted \u2014 falling back to DOM-only link discovery').catch(() => { });\n }\n }\n return fallback;\n }),\n readScreen(rawPage ?? page).catch(() => [] as Awaited<ReturnType<typeof readScreen>>),\n ]);\n\n // Cleanup highlights\n await page.evaluate(() => {\n const container = document.getElementById('__zeta_element_highlights');\n if (container) container.remove();\n }).catch(() => {});\n logger.info({ url, screenId: screen.id, version: screen.version, elements: elements.length, links: nextLinks.length, atSample: atElements.slice(0, 3).map((a: any) => a.label) }, '[crawler] screen captured');\n console.log('[crawler] AT:', JSON.stringify(atElements.slice(0, 5)));\n // Fire-and-forget keyboard-nav probe \u2014 records Tab sequence and focus-indicator issues per screen\n probeKeyboardNav(page).then((kbResult) => {\n if (kbResult.focusableCount > 0) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id, jobId: opts.jobId, type: 'KEYBOARD_NAV', payload: kbResult,\n }).catch(() => { });\n }\n }).catch(() => { });\n\n // Per-screen probes: split read-only (awaited, safe on main page) vs mutating (isolated page).\n // READ-ONLY probes are awaited before BFS navigates \u2014 DOM must reflect current screen.\n // MUTATING probes (dropdowns/CRUD/filters/advanced) open a fresh page to isolate state changes.\n {\n // Resolve browser context from rawPage (actual Playwright page, not Stagehand proxy).\n const safeContext: import('playwright').BrowserContext | null =\n typeof (rawPage as any)?.context === 'function'\n ? (rawPage as any).context()\n : typeof (page as any)?.context === 'function'\n ? (page as any).context()\n : playwrightBrowser?.contexts()[0] ?? null;\n\n // --- Read-only probes: awaited with 25s timeout, never mutate page state ---\n const roTimeout = new Promise<PromiseSettledResult<never>[]>((resolve) =>\n setTimeout(() => resolve([\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n ]), 25_000)\n );\n const [nestedCtxRes, shadowRes, a11yRes, perfRes, swRes] = await Promise.race([\n Promise.allSettled([\n crawlNestedContexts(rawPage ?? page, safeContext, url),\n crawlShadowDom(rawPage ?? page),\n crawlAccessibilityTree(rawPage ?? page),\n collectPerfMetrics(rawPage ?? page, url),\n inspectServiceWorker(rawPage ?? page),\n ]),\n roTimeout,\n ]);\n\n const roPayload: Record<string, unknown> = { screenId: screen.id, url };\n if (nestedCtxRes.status === 'fulfilled' && nestedCtxRes.value && (nestedCtxRes.value as any).totalContextsFound > 0)\n roPayload.nestedContexts = nestedCtxRes.value;\n if (shadowRes.status === 'fulfilled' && shadowRes.value && (shadowRes.value as any).shadowHostCount > 0)\n roPayload.shadowDom = shadowRes.value;\n if (a11yRes.status === 'fulfilled' && a11yRes.value)\n roPayload.accessibilityTree = a11yRes.value;\n if (perfRes.status === 'fulfilled' && (perfRes.value as any).requestCount > 0)\n roPayload.performance = perfRes.value;\n if (swRes.status === 'fulfilled' && (swRes.value as any).supported)\n roPayload.serviceWorker = swRes.value;\n if (Object.keys(roPayload).length > 2) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'PER_SCREEN_PROBES', payload: roPayload,\n }).catch(() => {});\n }\n\n // --- Mutating probes (interactive): isolated page, fire-and-forget, only when interactive ---\n if (screen?.id && opts.interactive !== false && safeContext) {\n void (async () => {\n let probePage: import('playwright').Page | null = null;\n try {\n // Cap concurrent probe pages: if too many already open, skip to prevent resource exhaustion.\n const openProbePages = safeContext.pages().length;\n if (openProbePages > 8) {\n logger.warn({ url, openProbePages }, '[crawler] probe page cap reached \u2014 skipping mutating probes for this screen');\n return;\n }\n probePage = await safeContext.newPage();\n await probePage.goto(url, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => {});\n await probePage.waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => {});\n await waitForStableDOM(probePage as any, 4_000, 400).catch(() => {});\n\n const muTimeout = new Promise<PromiseSettledResult<never>[]>((resolve) =>\n setTimeout(() => resolve([\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n ]), 60_000)\n );\n const [dropEnumRes, crudRes, filterRes, advancedRes] = await Promise.race([\n Promise.allSettled([\n enumerateDropdowns(probePage),\n probeCrudFlows(probePage, name),\n crawlFiltersAndPagination(probePage),\n probeAdvancedUI(probePage),\n ]),\n muTimeout,\n ]);\n\n const muPayload: Record<string, unknown> = { screenId: screen.id, url };\n if (dropEnumRes.status === 'fulfilled' && (dropEnumRes.value as any).totalOptionsFound > 0)\n muPayload.dropdowns = dropEnumRes.value;\n if (crudRes.status === 'fulfilled' && ((crudRes.value as any).flows?.length > 0 || (crudRes.value as any).toastsObserved?.length > 0))\n muPayload.crudFlows = crudRes.value;\n if (filterRes.status === 'fulfilled' && (filterRes.value as any).filters?.length > 0)\n muPayload.filtersAndPagination = filterRes.value;\n if (advancedRes.status === 'fulfilled' && advancedRes.value &&\n ((advancedRes.value as any).datePickers?.length > 0 || (advancedRes.value as any).sliders?.length > 0 ||\n (advancedRes.value as any).typeaheads?.length > 0 || (advancedRes.value as any).dragDrop?.library !== 'none'))\n muPayload.advancedUI = advancedRes.value;\n if (Object.keys(muPayload).length > 2) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'PER_SCREEN_PROBES_MUTATING', payload: muPayload,\n }).catch(() => {});\n }\n } catch {\n // non-fatal \u2014 probe failures must not block BFS\n } finally {\n await probePage?.close().catch(() => {});\n }\n })();\n }\n }\n\n // Inline auth-wall detection: PHP/legacy apps render session-expired content\n // without changing the URL, bypassing all URL-path-based guards above.\n const INLINE_AUTH_WALL_RE = /your login session (was|has been) expired|session (has )?expired[^.]*click|please (log ?in|sign ?in) to continue|you (are|were) logged out|your session has timed out/i;\n const pageBodyText = await page.evaluate(() => (document as any).body?.innerText ?? '').catch(() => '');\n if (INLINE_AUTH_WALL_RE.test(pageBodyText)) {\n logger.warn({ url, screenId: screen.id }, '[crawler] Inline session-expired content detected \u2014 skipping DOM snapshot, marking requiresAuth');\n AppBrain.updateScreenRequiresAuth(opts.tenantId, screen.id, true).catch(() => {});\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id, jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: { url, reason: 'Inline session-expired page rendered without URL redirect. Re-authenticate and re-crawl.' },\n }).catch(() => {});\n } else {\n\n // Capture DOM snapshot for structural analysis, and extract Markdown/text\n // content from the same DOM (crawl4AI-parity text output) \u2014 no extra fetch.\n try {\n const domContent = await capturePageHtml(page);\n if (!domContent) {\n logger.warn({ url, screenId: screen.id }, '[crawler] markdown extraction skipped: DOM snapshot unavailable');\n } else {\n const domPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(domPath, domContent, 'utf8');\n // Upload DOM snapshot to cloud alongside PNG, then persist both paths\n (async () => {\n const domKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(domPath)}`;\n const domCloudUrl = await uploadToCloud(domPath, domKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, domPath, domCloudUrl).catch(() => {});\n })();\n\n // Supplement markdown with iFrame and Shadow DOM content\n const [iframeContent, shadowContent] = await Promise.all([\n extractIframeContent(page).catch(() => []),\n pierceShadowDom(page).catch(() => ''),\n ]);\n const supplemental = [\n ...iframeContent.map((f: any) => f.markdown).filter(Boolean),\n shadowContent,\n ].join('\\n\\n').trim();\n\n const extracted = extractMarkdown(\n supplemental ? domContent + '\\n<!-- iframe/shadow -->\\n' + supplemental.slice(0, 3_000) : domContent,\n url\n );\n let fitMarkdown: string | undefined;\n if (extracted) {\n const mdPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.md');\n fitMarkdown = buildFitMarkdown(extracted.markdown, [\n ...domainProfile.importantScreenPatterns,\n ...domainProfile.workflowGoals,\n ...(opts.bestFirstKeywords ?? []),\n ]);\n const { text: scrubbed, scrubbed: hadPii } = scrubPii(extracted.markdown);\n if (hadPii) logger.info({ url }, '[crawler] PII detected and redacted from markdown');\n const dedupResult = deduplicator.check(url, scrubbed);\n if (dedupResult.isDuplicate) {\n logger.info({ url, similarUrl: dedupResult.similarUrl, score: dedupResult.similarityScore }, '[crawler] near-duplicate page skipped');\n }\n await fs.writeFile(mdPath, scrubbed, 'utf8');\n\n // Generate a one-sentence AI summary from the markdown \u2014 fire-and-forget\n const summaryPromise = (async () => {\n try {\n const llmCfg = await getCachedCrawlLLM(opts.tenantId);\n if (!llmCfg) return undefined;\n const snippet = extracted.markdown.slice(0, 1200);\n // Skip LLM when content is too thin \u2014 output would be useless\n if (snippet.trim().length < 80) return undefined;\n const summarySeed = deterministicSeed(`${opts.tenantId}:${opts.projectId ?? ''}:page-summary:${url}`);\n const { text, usage } = await askTracked(\n 'You are a QA analyst. Output ONLY a single complete sentence (no preamble, no quotes) describing what this screen does or shows. Be specific. Stop after the first sentence.',\n `Screen: \"${name}\"\\nURL: ${url}\\n\\nContent:\\n${snippet}`,\n llmCfg,\n 200,\n undefined,\n { temperature: 0, seed: summarySeed },\n );\n if (usage) {\n recordLLMCall({\n tenantId: opts.tenantId,\n projectId: opts.projectId,\n jobId: opts.jobId,\n agentType: 'crawl_summary',\n label: `page_summary:${name}`,\n usage,\n }).catch(() => { });\n }\n // Keep only the first sentence if the LLM returned multiple\n const clean = text.trim().replace(/^[\"']|[\"']$/g, '');\n const firstSentence = clean.match(/^[^.!?]+[.!?]/)?.[0] ?? clean;\n return firstSentence.trim();\n } catch { return undefined; }\n })();\n\n AppBrain.updateScreenMarkdown(opts.tenantId, opts.projectId, screen.id, {\n markdownPath: mdPath,\n markdownMethod: extracted.method,\n markdownWordCount: extracted.wordCount,\n markdown: fitMarkdown ?? extracted.markdown,\n heading: extracted.title || name,\n }).catch((err: any) => console.warn('[crawler] markdown extraction save failed:', err));\n\n pendingSummaryWrites.push(\n summaryPromise.then((aiSummary) => {\n if (aiSummary) AppBrain.updateScreenAiSummary(opts.tenantId, screen.id, aiSummary).catch((e: any) => {\n logger.warn({ screenId: screen.id, err: String(e?.message ?? e) }, '[crawler] aiSummary DB save failed');\n });\n }).catch((e: any) => {\n logger.warn({ screenId: screen.id, err: String(e?.message ?? e) }, '[crawler] aiSummary generation failed');\n })\n );\n }\n\n const structuredJson = summarizeStructuredElements(atElements);\n const artifact = buildCrawlArtifactEnvelope({\n tenantId: opts.tenantId,\n projectId: opts.projectId,\n jobId: opts.jobId,\n url,\n canonicalUrl: canonicalize(url),\n screenId: screen.id,\n screenshotPath: shotPath,\n domPath,\n domContent,\n markdown: extracted?.markdown,\n fitMarkdown,\n accessibilityElements: atElements,\n structuredJson,\n evidence: [\n { type: 'domain_profile', payload: { industry: domainProfile.industry, confidence: domainProfile.confidence } },\n { type: 'engine_route', payload: routeDecision },\n { type: 'screen_fingerprints', payload: { urlCanonicalHash: sha256(canonicalize(url)) } },\n ],\n });\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id,\n jobId: opts.jobId,\n type: 'SCREEN_ARTIFACT_ENVELOPE',\n payload: artifact,\n }).catch((err: any) => console.warn('[crawler] artifact evidence save failed:', err?.message ?? err));\n }\n } catch (err: any) {\n logger.warn({ url, screenId: screen.id, err: String(err?.message ?? err) }, '[crawler] markdown extraction failed');\n }\n } // end: inline auth-wall else\n\n // Persist a11y score + individual violations \u2014 fire-and-forget, non-fatal\n if (a11yScore !== null) {\n AppBrain.updateScreenA11y(opts.tenantId, screen.id, { a11yScore })\n .catch((err: any) => console.warn('[crawler] a11y score update failed:', err));\n }\n if (a11yResult !== null && a11yResult.violations.length > 0) {\n AppBrain.saveA11yViolations(opts.tenantId, opts.projectId, screen.id, a11yResult.violations, opts.jobId)\n .catch((err: any) => console.warn('[crawler] a11y violations save failed:', err));\n }\n\n // DOM hash was registered before saveScreen \u2014 no action needed here.\n\n // Build a role\u2192selectorHint lookup from AT data so fingerprints can include tag hints\n const atByRole = new Map<string, string>();\n for (const at of atElements) {\n if (!atByRole.has(at.role)) atByRole.set(at.role, at.selectorHint);\n }\n\n // Auto-create DESKTOP visual baseline on first crawl (no-op on recrawls)\n AppBrain.autoCreateVisualBaseline(opts.tenantId, opts.projectId, screen.id, 'DESKTOP', shotPath, gitInfo.branch, gitInfo.commit || undefined)\n .catch(() => { });\n\n // Phase 2: compute element hash for stale-test detection\n const newElementHash = computeElementHash(elements);\n AppBrain.updateElementHash(opts.tenantId, screen.id, newElementHash, (screen as any).elementHash ?? null)\n .catch((err: any) => console.warn('[crawler] element hash update failed:', err));\n\n // Phase 3: perceptual screenshot diff \u2014 non-blocking\n if (screen.version > 1) {\n (async () => {\n try {\n const prevShot = await AppBrain.getPreviousScreenshotPath(opts.tenantId, screen.id, screen.version - 1);\n if (prevShot) {\n const { screenshotDiffPercent } = await import('./phash.js');\n const { pHashDistance, changeLevel } = await screenshotDiffPercent(prevShot, shotPath);\n await AppBrain.saveScreenDiff(opts.tenantId, opts.projectId, screen.id, screen.version - 1, screen.version, pHashDistance, changeLevel);\n }\n } catch (err) {\n console.warn('[crawler] pHash diff skipped:', err);\n }\n })();\n }\n\n // VisualDiff pipeline \u2014 compare against approved baseline (not previous screenshot)\n if (screen.version > 1) {\n (async () => {\n try {\n const baseline = await AppBrain.getVisualBaselineForDiff(opts.tenantId, screen.id, 'DESKTOP', gitInfo.branch);\n if (baseline && baseline.storagePath !== shotPath) {\n // Resolve baseline file path \u2014 local copy may have been rotated; fall back to cloud download\n let baselinePath: string = baseline.storagePath;\n let tempBaselinePath: string | null = null;\n const localExists = await fs.access(baseline.storagePath).then(() => true, () => false);\n if (!localExists) {\n if (baseline.cloudUrl) {\n try {\n const resp = await fetch(baseline.cloudUrl);\n if (resp.ok) {\n const buf = Buffer.from(await resp.arrayBuffer());\n tempBaselinePath = `${shotPath}.baseline-tmp.png`;\n await fs.writeFile(tempBaselinePath, buf);\n baselinePath = tempBaselinePath;\n logger.info({ screenId: screen.id }, '[crawler] VisualDiff baseline downloaded from cloud storage');\n } else {\n logger.warn({ screenId: screen.id, status: resp.status }, '[crawler] VisualDiff skipped \u2014 baseline cloud fetch returned non-200');\n return;\n }\n } catch (dlErr) {\n logger.warn({ screenId: screen.id, err: String(dlErr) }, '[crawler] VisualDiff skipped \u2014 baseline cloud download failed');\n return;\n }\n } else {\n logger.warn({ screenId: screen.id }, '[crawler] VisualDiff skipped \u2014 baseline not on disk and no cloudUrl available');\n return;\n }\n }\n try {\n const { screenshotDiffPercent, gridLayoutDiff } = await import('./phash.js');\n const [{ pHashDistance, changeLevel }, layoutChanges, elementShifts] = await Promise.all([\n screenshotDiffPercent(baselinePath, shotPath, baseline.ignoredRegions),\n gridLayoutDiff(baselinePath, shotPath, baseline.ignoredRegions),\n AppBrain.computeElementLayoutDiff(opts.tenantId, screen.id, 'DESKTOP'),\n ]);\n let verdict = pHashVerdict(pHashDistance, changeLevel, [\n ...layoutChanges,\n ...elementShifts.map((s) => ({ location: 'element', severity: s.severity, description: s.description })),\n ]);\n\n // pHash is a cheap, always-on filter; only spend an LLM call on the\n // screens it flags as worth a closer look. It also can't tell\n // meaningful UI changes apart from anti-aliasing/font-rendering noise,\n // which is exactly what Visual AI comparison exists to filter out.\n if (verdict.changeType === 'SIGNIFICANT' || verdict.changeType === 'CRITICAL') {\n try {\n const regions = baseline.ignoredRegions ?? [];\n // Same mask the pHash passes already applied \u2014 otherwise a\n // manually-masked region (timestamp, ad banner, live counter)\n // still reaches the AI verdict unmasked and can get flagged.\n const [baselineBuffer, newBuffer] = regions.length > 0\n ? await (async () => {\n const { applyMask } = await import('./phash.js');\n return Promise.all([applyMask(baselinePath, regions), applyMask(shotPath, regions)]);\n })()\n : await Promise.all([\n fs.readFile(baselinePath),\n fs.readFile(shotPath),\n ]);\n const aiResult = await aiVisualCompare({\n baselineImageBase64: baselineBuffer.toString('base64'),\n newImageBase64: newBuffer.toString('base64'),\n screenName: screen.name,\n screenPurpose: 'Application screen captured during automated crawl',\n tenantId: opts.tenantId,\n projectId: opts.projectId,\n });\n verdict = mergeAiVisualVerdict(verdict, aiResult, screen.name);\n } catch (aiErr) {\n logger.warn({ screenId: screen.id, err: String(aiErr) }, '[crawler] AI visual compare failed, keeping pHash-only verdict');\n }\n }\n\n let { changeType, recommendation, changes: allChanges, bugReportDraft, aiSummary } = verdict;\n\n // R7: Apply per-project visual diff threshold \u2014 suppress diffs below the threshold\n if (changeType !== 'NONE') {\n try {\n const project = await AppBrain.getProject(opts.tenantId, opts.projectId);\n const threshold = (project as any)?.visualDiffThreshold ?? null;\n if (threshold !== null && pHashDistance < threshold) {\n changeType = 'NONE';\n }\n } catch { /* non-fatal \u2014 use verdict as-is */ }\n }\n\n if (changeType !== 'NONE') {\n let newScreenshotCloudUrl: string | undefined;\n let diffImageCloudUrl: string | undefined;\n try {\n const { getTenantStorageConfig, uploadScreenshotToTenantStorage, buildArtifactKey } = await import('@detiq/app-brain');\n const storageCfg = await getTenantStorageConfig(opts.tenantId).catch(() => null);\n if (storageCfg) {\n const key = buildArtifactKey(opts.tenantId, opts.projectId, 'visual-diffs', `${screen.id}-v${screen.version}.png`, storageCfg.prefix);\n newScreenshotCloudUrl = await uploadScreenshotToTenantStorage(storageCfg, shotPath, key);\n\n // R5: Generate and upload pixelmatch diff image (changed pixels in red)\n try {\n const { generatePixelmatchDiff } = await import('./phash.js');\n const diffBuffer = await generatePixelmatchDiff(baselinePath, shotPath, baseline.ignoredRegions ?? []);\n const diffTmpPath = `${shotPath}.diff.png`;\n await fs.writeFile(diffTmpPath, diffBuffer);\n const diffKey = buildArtifactKey(opts.tenantId, opts.projectId, 'visual-diffs', `${screen.id}-v${screen.version}-diff.png`, storageCfg.prefix);\n diffImageCloudUrl = await uploadScreenshotToTenantStorage(storageCfg, diffTmpPath, diffKey);\n fs.unlink(diffTmpPath).catch(() => {});\n } catch (diffErr) {\n logger.warn({ screenId: screen.id, err: String(diffErr) }, '[crawler] pixelmatch diff generation failed, skipping');\n }\n }\n } catch { /* non-fatal \u2014 falls back to local path */ }\n await AppBrain.saveVisualDiff(opts.tenantId, {\n baselineId: baseline.id,\n newScreenshotPath: shotPath,\n newScreenshotCloudUrl,\n diffImageCloudUrl,\n diffScore: pHashDistance,\n changeType,\n changes: allChanges,\n recommendation,\n bugReportDraft,\n aiSummary,\n });\n }\n } finally {\n if (tempBaselinePath) fs.unlink(tempBaselinePath).catch(() => {});\n }\n }\n } catch (err: any) {\n console.warn('[crawler] VisualDiff pipeline failed:', err);\n }\n })();\n }\n\n const linkMappings = await extractLinkMappings(page, origin);\n\n // Auth-wall guard: check if the page drifted to a login/error URL during the async\n // element extraction window (30-90s). If so, the `elements` array contains login-page\n // elements \u2014 saving them would corrupt the screen's element catalog.\n const postExtractUrl = (() => { try { return page.url(); } catch { return url; } })();\n const postExtractParsed = (() => { try { return new URL(postExtractUrl); } catch { return new URL(url); } })();\n const driftedToAuthWall = !weWantedThisPage && (\n BFS_LOGIN_PATH.test(postExtractParsed.pathname) || BFS_ERROR_PATH.test(postExtractParsed.pathname)\n );\n if (driftedToAuthWall) {\n logger.warn({ url, postExtractUrl }, '[crawler] Page drifted to auth wall during element extraction \u2014 skipping element save to prevent login-page element contamination');\n AppBrain.updateScreenRequiresAuth(opts.tenantId, screen.id, true).catch(() => {});\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id,\n jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: { url, landed: postExtractUrl, reason: 'Session expired during element extraction. Re-capture session and re-crawl this page.' },\n }).catch(() => {});\n } else {\n if (elements.length === 0) {\n // Extraction returned nothing \u2014 keep existing elements rather than wiping them.\n // Causes: page.evaluate failure, contentFallbackElements threw, SPA not yet hydrated.\n logger.warn({ url, screenId: screen.id }, '[crawler] extractElements returned 0 \u2014 preserving existing elements to avoid data loss');\n // Queue for re-visit with longer wait \u2014 SPA content may not have hydrated yet\n if (!revisitQueue.includes(url)) {\n revisitQueue.push(url);\n logger.info({ url }, '[crawler] 0-element page queued for re-visit with extended hydration wait');\n }\n } else {\n // Clear existing elements before re-saving \u2014 prevents duplicates on re-crawl\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, screen.id).catch(() => {});\n // Batch element saves: 2 concurrent DB writes (4 caused pool saturation at 5 workers)\n for (let _ei = 0; _ei < elements.length; _ei += 2) {\n const _batch = elements.slice(_ei, _ei + 2);\n await Promise.all(_batch.map(async (el: any) => {\n const saved = await AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark);\n // Populate ElementFingerprint \u2014 fire-and-forget, failures are non-fatal\n const label = el.meaning;\n const role = el.role ?? 'unknown';\n const selectorHint = atByRole.get(role) ?? role;\n const selectors = [\n { type: 'role-label', value: `${role}:${label}`, confidence: 0.9 },\n { type: 'aria-label', value: label, confidence: 0.85 },\n { type: 'tag-hint', value: selectorHint, confidence: 0.6 },\n ];\n await AppBrain.saveElementFingerprint(opts.tenantId, opts.projectId, (saved as any).id, selectors).catch(console.warn);\n }));\n }\n } // end inner else: elements.length > 0\n for (const lm of linkMappings) {\n const safety = assessActionSafety(lm.label, domainProfile);\n if (!safety.allowed) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id,\n jobId: opts.jobId,\n type: 'ACTION_BLOCKED_BY_SAFETY_POLICY',\n payload: { label: lm.label, href: lm.href, decision: safety, profile: domainProfile.industry },\n }).catch(() => { });\n continue;\n }\n pendingTransitions.push({ fromScreenId: screen.id, elementMeaning: lm.label, targetUrl: lm.href });\n AppBrain.saveActionRecipe(opts.tenantId, opts.projectId, {\n domain: new URL(url).hostname,\n purpose: `navigate:${lm.label}`,\n fingerprint: sha256(`${canonicalize(url)}:${lm.label}:${canonicalize(lm.href)}`),\n steps: [{ action: 'click', label: lm.label, targetUrl: lm.href, fromUrl: url }],\n successRate: 0.5,\n }).catch(() => { });\n\n if (!selective) {\n try {\n const targetPath = new URL(lm.href).pathname;\n const canonLmHref = canonicalize(lm.href);\n if (\n !SKIP_PATH.test(targetPath) &&\n isUsefulNavigationUrl(lm.href, origin) &&\n !queued.has(canonLmHref) &&\n !visited.has(canonLmHref) &&\n queued.size < maxScreens * 3\n ) {\n if (robotsCache && !await robotsCache.isAllowed(lm.href)) continue;\n queued.add(canonLmHref);\n queue.push(lm.href, { parentElements: elements.length });\n edges.push({ fromUrl: url, toUrl: lm.href });\n logger.info({ fromUrl: url, newUrl: lm.href, label: lm.label, queueSize: queue.length }, '[crawler] anchor mapping added to queue');\n }\n } catch { /* ignore invalid link mapping */ }\n }\n }\n if (!selective) {\n for (const href of nextLinks) {\n edges.push({ fromUrl: url, toUrl: href });\n // Skip WooCommerce/e-commerce action URLs \u2014 these are AJAX/form actions that render\n // the same page template with a compare widget; they are not distinct page routes.\n // They would all get queued (different `id` param = different canonical URL), navigated,\n // found \"duplicate DOM\", and burn through totalAttemptsThisSegment without any gain.\n try {\n const hrefParams = new URL(href).searchParams;\n const actionVal = hrefParams.get('action') ?? '';\n if (/^yith-|^wc-|^vc_|^elementor/.test(actionVal)) continue;\n } catch { /* invalid URL, let it fall through */ }\n const canonHref = canonicalize(href);\n if (!queued.has(canonHref) && !visited.has(canonHref) && queued.size < maxScreens * 3) {\n // Don't flood the queue with generated ID-like route segments.\n try {\n const hrefPath = new URL(href).pathname;\n if (isGeneratedDynamicPath(hrefPath) && !_activeSeedPatterns.some(re => re.test(hrefPath))) continue;\n } catch { /* ignore invalid URLs */ }\n if (robotsCache && !await robotsCache.isAllowed(href)) continue;\n queued.add(canonHref);\n queue.push(href, { parentElements: elements.length }); // navigate to actual URL, dedup by canonical\n logger.info({ newUrl: href, queueSize: queue.length }, '[crawler] new URL added to queue');\n }\n }\n logger.info({ fromUrl: url, discovered: nextLinks.length, queueAfter: queue.length, visitedSoFar: visited.size }, '[crawler] link processing done');\n\n // Harvest SPA routes captured via history.pushState/replaceState interception\n try {\n const jsRoutes = await page.evaluate(() => {\n const routes = (window as any).__zetaDiscoveredRoutes ?? [];\n (window as any).__zetaDiscoveredRoutes = [];\n return routes as string[];\n }).catch(() => [] as string[]);\n for (const route of jsRoutes) {\n try {\n const abs = route.startsWith('http') ? route : `${origin}${route.startsWith('/') ? '' : '/'}${route}`;\n const canonRoute = canonicalize(abs);\n if (!queued.has(canonRoute) && !visited.has(canonRoute)) {\n queued.add(canonRoute);\n queue.push(abs);\n logger.info({ route: abs }, '[crawler] history.pushState: discovered SPA route');\n }\n } catch { /* ignore invalid routes */ }\n }\n } catch { /* non-fatal */ }\n\n // P3a: Post-extraction DOM count \u2014 detect async-loaded content.\n // Only check sparse pages (preDomCount < 25) where async widgets are likely.\n // If DOM grew significantly during AI extraction, re-visit later with networkidle.\n const asyncContentCheckMinDom = parseInt(process.env.CRAWLER_ASYNC_CONTENT_MIN_DOM ?? '') || 25;\n if (preDomCount < asyncContentCheckMinDom && !revisitQueue.includes(url)) {\n try {\n const postDomCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"],[onclick],[aria-label]').length\n ).catch(() => 0);\n const asyncGrowthRatio = parseFloat(process.env.CRAWLER_ASYNC_GROWTH_RATIO ?? '') || 1.3;\n const asyncGrowthFloor = parseInt(process.env.CRAWLER_ASYNC_GROWTH_FLOOR ?? '') || 4;\n if (postDomCount > preDomCount * asyncGrowthRatio + asyncGrowthFloor) {\n revisitQueue.push(url);\n logger.info({ url, preDomCount, postDomCount }, '[P3a] Async content detected \u2014 scheduled for re-visit');\n }\n } catch { /* non-fatal */ }\n }\n\n // P2: Static JS router detection \u2014 scan bundle for declared client-side routes.\n // Only run on first 5 pages (bundle is the same across pages; scanning every page is wasteful).\n if (visited.size <= (parseInt(process.env.CRAWLER_SPA_ROUTER_DETECT_LIMIT ?? '') || 5)) {\n try {\n const jsDetectedRoutes = await detectJsRoutes(page, origin);\n for (const route of jsDetectedRoutes) {\n const canonRoute = canonicalize(route);\n if (isUsefulNavigationUrl(route, origin) && !queued.has(canonRoute) && !visited.has(canonRoute) && queued.size < maxScreens * 3) {\n queued.add(canonRoute);\n queue.push(route, { parentElements: elements.length });\n logger.info({ route }, '[P2] JS router: discovered route added to queue');\n }\n }\n } catch { /* non-fatal */ }\n }\n\n // P4: Drain XHR-discovered page URL candidates (accumulated by network-observer callback).\n // These are relative paths extracted from JSON API response bodies.\n for (const relPath of [...xhrDiscoveredPaths]) {\n xhrDiscoveredPaths.delete(relPath);\n try {\n const abs = `${origin}${relPath}`;\n const canon = canonicalize(abs);\n if (isUsefulNavigationUrl(abs, origin) && !queued.has(canon) && !visited.has(canon) && queued.size < maxScreens * 3) {\n queued.add(canon);\n queue.push(abs);\n logger.info({ url: abs }, '[P4] XHR: page URL from JSON response added to queue');\n }\n } catch { /* ignore invalid paths */ }\n }\n\n // Gap 5: Skyvern URL-discovery bootstrap for pages that defeat DOM link extraction.\n // Triggered per-page when: zero DOM links found + fewer than 5 elements (dead-end / canvas page).\n // Skyvern returns URLs it discovered \u2192 added to queue for ZeTa's own BFS crawl (not saved directly).\n // ZeTa does all actual crawling \u2014 Skyvern is only a URL-discovery override layer.\n if (!selective && nextLinks.length === 0 && elements.length < (parseInt(process.env.CRAWL_SKYVERN_PAGE_MIN_ELEMENTS ?? '') || 5) && opts.skyvernConfig) {\n try {\n logger.info({ url }, 'Gap 5: thin page detected \u2014 asking Skyvern to discover navigation URLs');\n const skyvernNav = await skyvernNavigate(\n url,\n ['Find and return all navigation links, menu items, and page URLs accessible from this screen'],\n opts.skyvernConfig,\n );\n for (const skyvernUrl of skyvernNav.visitedUrls) {\n const canonSkyvernUrl = canonicalize(skyvernUrl);\n if (!queued.has(canonSkyvernUrl) && !visited.has(canonSkyvernUrl) && queued.size < maxScreens * 3) {\n logger.info({ url: skyvernUrl }, 'Gap 5: Skyvern-discovered URL added to ZeTa crawl queue');\n queued.add(canonSkyvernUrl);\n queue.push(skyvernUrl); // ZeTa will crawl this normally\n // Wire the KAG edge so the Skyvern-discovered page isn't flagged as an orphan\n pendingTransitions.push({ fromScreenId: screen.id, elementMeaning: 'Skyvern-discovered link', targetUrl: skyvernUrl });\n }\n }\n } catch { /* non-fatal \u2014 Skyvern unavailable */ }\n }\n }\n } // end auth-wall guard else\n\n if (rawPerf) {\n performanceMetrics.push({ url, screenName: name, ...rawPerf });\n }\n\n const screenApiEndpoints = capturedApiEndpoints.slice(apiObservationStartIndex);\n if (screenApiEndpoints.length > 0) {\n AppBrain.saveApiEndpointObservations(opts.tenantId, opts.projectId, screen.id, screenApiEndpoints)\n .then(() => AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id,\n jobId: opts.jobId,\n type: 'API_ENDPOINT_OBSERVATIONS',\n payload: { endpoints: screenApiEndpoints },\n }))\n .catch((err: any) => console.warn('[crawler] API endpoint observation save failed:', err?.message ?? err));\n }\n\n // Persist performance snapshot (web vitals + optional Lighthouse) \u2014 fire-and-forget\n if (opts.jobId && (rawPerf || process.env.ENABLE_LIGHTHOUSE)) {\n (async () => {\n try {\n const lhScores = await runLighthouse(url);\n await AppBrain.savePerformanceSnapshot(opts.tenantId, screen.id, opts.jobId!, {\n lcp: rawPerf?.lcp,\n fcp: rawPerf?.fcp,\n cls: rawPerf?.cls,\n ttfb: rawPerf?.ttfb,\n viewport: opts.viewport ?? 'DESKTOP',\n ...(lhScores ? {\n lighthousePerf: lhScores.perf,\n lighthouseA11y: lhScores.a11y,\n lighthouseSEO: lhScores.seo,\n lighthouseBP: lhScores.bp,\n lighthouseReport: lhScores.report,\n } : {}),\n });\n } catch (perfErr) {\n console.warn('[crawler] savePerformanceSnapshot failed (non-fatal):', perfErr);\n }\n })();\n }\n\n discovered.push({ url, screenId: screen.id, elements: elements.length, elementFacts: elements, screenshotPath: shotPath, version: screen.version });\n // Progress: 20% baseline + up to 60% across discovered screens.\n // Cap maxSeenTotal at maxScreens * 3 so unbounded link discovery does not\n // collapse the denominator and freeze progress in the 20-22% band.\n const effectiveMax = isFinite(maxScreens) ? Math.min(visited.size + queue.length, maxScreens * 3) : visited.size + queue.length;\n maxSeenTotal = Math.max(maxSeenTotal, effectiveMax);\n const rawPct = 20 + Math.round(Math.min(60, (visited.size / Math.max(1, maxSeenTotal)) * 60));\n const clampedPct = Math.max(lastEmittedPct, rawPct);\n lastEmittedPct = clampedPct;\n await onProgress?.(clampedPct, `Crawling screens (${visited.size} mapped, ${queue.length} pending)`);\n logger.info({ name, elements: elements.length }, 'Screen crawled');\n // Checkpoint every 10 successes so a failed job can be resumed from close to where it stopped\n if (++checkpointSuccessCount % 5 === 0) {\n await opts.onCheckpoint?.(\n Array.from(visited.entries()).filter(([_k, v]) => v !== '_pending_').map(([k]) => k),\n queue.filter(u => !visited.has(canonicalize(u)))\n );\n }\n } catch (err: any) {\n logger.warn({ url, err: err?.message ?? String(err), stack: err?.stack?.split('\\n').slice(0, 5).join(' | ') }, 'Screen crawl failed');\n discovered.push({ url, error: err?.message ?? String(err) });\n }\n }\n\n // Wait for any lite workers still processing URLs from the shared queue\n if (liteWorkerPromises.length > 0) await Promise.all(liteWorkerPromises);\n\n // Discovery mode: return collected URLs and skip all post-crawl analysis phases.\n // Use visited.values() (original URLs) not .keys() (canonical forms with /{id} placeholders).\n // Filter out sentinel strings (_pending_, _auth_wall_, _soft404_, etc.) that mark\n // in-progress or skipped entries \u2014 only keep actual http(s) URLs.\n if (opts.discoveryMode) {\n return {\n discoveredUrls: Array.from(visited.values()).filter((v: string) => v.startsWith('http')),\n screensFound: 0,\n screensErrored: 0,\n screensSkippedToNextSegment: 0,\n isPartial: false,\n discovered: [],\n apiEndpoints: [],\n performanceMetrics: [],\n pendingUrls: [],\n segmentIndex: segIdx,\n hasMoreSegments: false,\n domHashes: Array.from(seenDomHashes),\n };\n }\n\n // Gap 5: Skyvern post-crawl top-up for canvas/non-DOM apps where total screens < 10.\n // Skyvern discovers URLs \u2192 ZeTa's own BFS crawl processes each one normally.\n // Skyvern is ONLY a URL-discovery layer here \u2014 it does NOT save screens directly.\n // Use only successfully-saved screens (screenId present), not total discovered including errors.\n const successfulScreenCount = discovered.filter(d => d.screenId).length;\n const skyvernMinScreens = parseInt(process.env.CRAWL_SKYVERN_MIN_SCREENS ?? '') || 10;\n if (!selective && successfulScreenCount < skyvernMinScreens && opts.skyvernConfig) {\n await onProgress?.(78, 'Few screens found \u2014 using Skyvern to discover additional navigation URLs');\n const currentUrl = page.url();\n const skyvernNav = await skyvernNavigate(\n currentUrl,\n [\n 'Explore the main navigation and visit each top-level section',\n 'Click any sidebar or top menu items to discover sub-pages',\n ],\n opts.skyvernConfig,\n );\n const skyvernUrls = skyvernNav.visitedUrls.filter((u) => !visited.has(canonicalize(u)));\n if (skyvernUrls.length > 0) {\n logger.info({ count: skyvernUrls.length }, 'Gap 5: Skyvern found new URLs \u2014 processing with ZeTa native crawler');\n // Process each URL with ZeTa's own Playwright-based extraction\n for (const skyvernUrl of skyvernUrls) {\n if (isCrawlTimedOut() || visited.size >= maxScreens) break;\n try {\n await page.goto(skyvernUrl, { waitUntil: 'domcontentloaded', timeout: 20000 });\n await new Promise<void>(r => setTimeout(r, 1500));\n const skyvernName = new URL(skyvernUrl).pathname.split('/').filter(Boolean).pop() ?? 'Screen';\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, skyvernName, skyvernUrl, opts.jobId, 'SKYVERN_AI');\n const shotPath = `${opts.screenshotDir ?? '/tmp'}/${screen.id}-v${screen.version}.png`;\n await waitForScreenshotReady(page, rawPage ?? undefined);\n await page.screenshot({ path: shotPath, fullPage: true });\n const skyvernCloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, screen.id, shotPath, screen.version, 'DESKTOP', skyvernCloudUrl);\n // GAP 7: DOM snapshot for Skyvern primary URLs\n const skyvernDom = await capturePageHtml(page);\n if (skyvernDom) {\n const skyvernDomPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(skyvernDomPath, skyvernDom, 'utf8');\n const skyvernDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(skyvernDomPath)}`;\n const skyvernDomCloud = await uploadToCloud(skyvernDomPath, skyvernDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, skyvernDomPath, skyvernDomCloud).catch(() => {});\n }\n const [elems, links, linkMappings] = await Promise.all([\n extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined),\n discoverLinks(stagehand, origin, page, linkLLM ?? undefined, aiSkipCount > 0, rawPage ?? undefined).then((metas) => {\n if (metas.length > 0) {\n AppBrain.saveDiscoveredLinks(opts.tenantId, opts.projectId, screen.id, metas.map((m) => ({\n href: m.url, text: m.text, landmark: m.landmark, linkType: 'NAV_LINK', source: m.source, jobId: opts.jobId,\n }))).catch(() => {});\n }\n return metas.map(m => m.url);\n }),\n extractLinkMappings(page, origin),\n ]);\n for (const el of elems) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => { });\n }\n visited.set(canonicalize(skyvernUrl), screen.id);\n discovered.push({ url: skyvernUrl, screenId: screen.id, elements: elems.length, version: screen.version });\n // Wire KAG element->screen transitions for this Skyvern-discovered page too \u2014\n // without this, any page only ever reached via Skyvern always looks orphaned\n // (zero inbound edges) even when a real DOM link exists elsewhere pointing to it.\n for (const lm of linkMappings) {\n pendingTransitions.push({ fromScreenId: screen.id, elementMeaning: lm.label, targetUrl: lm.href });\n }\n // Also enqueue links Skyvern page found for further ZeTa crawling\n for (const link of links) {\n const href = link;\n const c = canonicalize(href);\n if (isUsefulNavigationUrl(href, origin) && !queued.has(c) && !visited.has(c)) { queued.add(c); queue.push(href); }\n }\n } catch (err) {\n logger.warn({ url: skyvernUrl, err: String(err) }, 'Gap 5: ZeTa crawl of Skyvern URL failed');\n }\n }\n // Drain any newly queued URLs from Skyvern pages\n while (queue.length > 0 && visited.size < maxScreens && !isCrawlTimedOut()) {\n const href = queue.shift()!;\n const canonHref = canonicalize(href);\n if (visited.has(canonHref)) continue;\n if (!isUsefulNavigationUrl(href, origin)) continue;\n try {\n await page.goto(href, { waitUntil: 'domcontentloaded', timeout: 20000 });\n await new Promise<void>(r => setTimeout(r, 1000));\n const nm = new URL(href).pathname.split('/').filter(Boolean).pop() ?? 'Screen';\n const sc = await AppBrain.saveScreen(opts.tenantId, opts.projectId, nm, href, opts.jobId, 'SKYVERN_AI');\n const sp = `${opts.screenshotDir ?? '/tmp'}/${sc.id}-v${sc.version}.png`;\n await waitForScreenshotReady(page, rawPage ?? undefined);\n await page.screenshot({ path: sp, fullPage: true });\n const skyvernDrainCloudUrl = await uploadToCloud(sp, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(sp)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, sc.id, sp, sc.version, 'DESKTOP', skyvernDrainCloudUrl);\n // GAP 8: DOM snapshot for Skyvern drain-queue URLs\n const skyvernDrainDom = await capturePageHtml(page);\n if (skyvernDrainDom) {\n const skyvernDrainDomPath = sp.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(skyvernDrainDomPath, skyvernDrainDom, 'utf8');\n const skyvernDrainDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(skyvernDrainDomPath)}`;\n const skyvernDrainDomCloud = await uploadToCloud(skyvernDrainDomPath, skyvernDrainDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, sc.id, skyvernDrainDomPath, skyvernDrainDomCloud).catch(() => {});\n }\n const [elems2, linkMappings2] = await Promise.all([\n extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined),\n extractLinkMappings(page, origin),\n ]);\n for (const el of elems2) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, sc.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => { });\n }\n visited.set(canonHref, sc.id);\n discovered.push({ url: href, screenId: sc.id, elements: elems2.length, version: sc.version });\n for (const lm of linkMappings2) {\n pendingTransitions.push({ fromScreenId: sc.id, elementMeaning: lm.label, targetUrl: lm.href });\n }\n } catch { /* non-fatal */ }\n }\n }\n }\n\n if (pendingSessionRestore) {\n await pendingSessionRestore();\n pendingSessionRestore = null;\n }\n\n // P1: URL Pattern LLM Completion \u2014 post-crawl LLM prediction of undiscovered URLs.\n // Single LLM call predicts missing routes from discovered URL patterns, HEAD-validates each.\n // Saves URL_CANDIDATES evidence so the ActivityDrawer shows what was found.\n try {\n const { runUrlPatternCompletion } = await import('./url-pattern-completer.js');\n const llmCfgForPatterns = await getCachedCrawlLLM(opts.tenantId);\n const urlPatternCandidates = await runUrlPatternCompletion(\n Array.from(visited.keys()),\n opts.appUrl,\n llmCfgForPatterns,\n );\n if (urlPatternCandidates.length > 0) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'URL_CANDIDATES',\n payload: {\n candidates: urlPatternCandidates,\n hits: urlPatternCandidates.filter(c => c.status === 'hit').length,\n total: urlPatternCandidates.length,\n },\n }).catch(() => { });\n logger.info(\n { hits: urlPatternCandidates.filter(c => c.status === 'hit').length, total: urlPatternCandidates.length },\n '[P1] URL pattern completion saved to evidence',\n );\n }\n } catch (err) {\n const msg = String(err);\n logger.warn({ err: msg }, '[P1] URL pattern completion failed \u2014 non-fatal, continuing');\n crawlWarnings.push(`url-completer skipped: ${msg.includes('401') || msg.toLowerCase().includes('api key') || msg.toLowerCase().includes('authentication') ? 'LLM API key invalid or missing' : msg}`);\n }\n\n // P3a: Async content re-visit \u2014 revisit pages where DOM grew significantly during extraction.\n // Uses networkidle wait + longer stability period to capture fully-loaded dashboard content.\n if (revisitQueue.length > 0) {\n await onProgress?.(79, `Re-visiting ${revisitQueue.length} page(s) with async content\u2026`);\n logger.info({ count: revisitQueue.length }, '[P3a] Starting async content re-visit pass');\n for (const revisitUrl of revisitQueue.slice(0, 20)) { // cap at 20 re-visits; also guard global timeout\n if (isCrawlTimedOut()) break;\n const rawScreenId = visited.get(canonicalize(revisitUrl));\n // Auth-wall pages are stored as '_auth_wall_' \u2014 not a real screen ID.\n // Navigate with the authenticated main page; it will redirect to the real content.\n const isAuthWallRevisit = rawScreenId === '_auth_wall_';\n if (!rawScreenId) continue;\n try {\n await page.goto(revisitUrl, { waitUntil: 'networkidle', timeout: 25_000 });\n await new Promise<void>(r => setTimeout(r, 2_000));\n await waitForScreenshotReady(page, rawPage ?? undefined);\n\n // After navigation, check where we actually landed (auth may redirect)\n const landedUrl = (rawPage ?? page).url?.() ?? revisitUrl;\n const landedCanon = canonicalize(landedUrl);\n let existingScreenId = isAuthWallRevisit\n ? (visited.get(landedCanon) ?? null) // use screen at redirected URL if known\n : rawScreenId;\n\n // If auth-wall redirect landed on an unvisited page, save it as a new screen\n if (isAuthWallRevisit && (!existingScreenId || existingScreenId.startsWith('_')) && !visited.has(landedCanon)) {\n const pathParts = new URL(landedUrl).pathname.split('/').filter(Boolean);\n const screenName = pathParts.map((p: string) => p.charAt(0).toUpperCase() + p.slice(1).replace(/[-_]/g, ' ')).join(' \u2014 ') || 'Home';\n const newScreen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, screenName, landedUrl, opts.jobId, 'LINK_FOLLOW').catch(() => null);\n if (newScreen) {\n visited.set(landedCanon, newScreen.id);\n existingScreenId = newScreen.id;\n }\n }\n\n if (!existingScreenId || existingScreenId.startsWith('_')) {\n logger.warn({ url: revisitUrl, landed: landedUrl }, '[P3a] Re-visit skipped \u2014 could not resolve screen ID');\n continue;\n }\n\n const shotPath2 = `${opts.screenshotDir ?? '/tmp'}/${existingScreenId}-revisit.png`;\n await page.screenshot({ path: shotPath2, fullPage: true });\n const p3aCloudUrl = await uploadToCloud(shotPath2, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath2)}`).catch(() => undefined);\n await (AppBrain.saveScreenshot as any)(opts.tenantId, opts.projectId, existingScreenId, shotPath2, 1, 'DESKTOP', p3aCloudUrl).catch(() => {});\n // GAP 10: DOM snapshot for P3a auth-wall revisit\n const p3aDom = await capturePageHtml(page);\n if (p3aDom) {\n const p3aDomPath = shotPath2.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(p3aDomPath, p3aDom, 'utf8');\n const p3aDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(p3aDomPath)}`;\n const p3aDomCloud = await uploadToCloud(p3aDomPath, p3aDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, existingScreenId, p3aDomPath, p3aDomCloud).catch(() => {});\n }\n // Re-extract elements with the async-loaded content now visible\n const revisitElements = await extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined).catch(() => []);\n if (revisitElements.length > 0) {\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, existingScreenId).catch(() => {});\n for (const el of revisitElements) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, existingScreenId, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => { });\n }\n } else {\n // P3a got 0 elements \u2014 check if it's an inline session-expired page.\n const p3aBodyText = await page.evaluate(() => (document as any).body?.innerText ?? '').catch(() => '');\n if (INLINE_AUTH_WALL_RE.test(p3aBodyText)) {\n logger.warn({ url: revisitUrl, screenId: existingScreenId }, '[P3a] Re-visit got 0 elements \u2014 inline session-expired content, marking requiresAuth');\n AppBrain.updateScreenRequiresAuth(opts.tenantId, existingScreenId, true).catch(() => {});\n }\n }\n // Harvest any new links revealed by async content\n const revisitLinks = await discoverLinks(stagehand, origin, page, linkLLM ?? undefined, false, rawPage ?? undefined)\n .then((metas) => {\n if (metas.length > 0) {\n AppBrain.saveDiscoveredLinks(opts.tenantId, opts.projectId, existingScreenId, metas.map((m) => ({\n href: m.url, text: m.text, landmark: m.landmark, linkType: 'NAV_LINK', source: m.source, jobId: opts.jobId,\n }))).catch(() => {});\n }\n return metas.map(m => m.url);\n })\n .catch(() => []);\n for (const href of revisitLinks) {\n const canon = canonicalize(href);\n if (isUsefulNavigationUrl(href, origin) && !queued.has(canon) && !visited.has(canon) && queued.size < maxScreens * 3) {\n queued.add(canon);\n queue.push(href);\n }\n }\n logger.info({ url: revisitUrl, landed: landedUrl, elements: revisitElements.length, newLinks: revisitLinks.length }, '[P3a] Re-visit complete');\n } catch (err) {\n logger.warn({ url: revisitUrl, err: String(err) }, '[P3a] Re-visit failed \u2014 non-fatal');\n }\n }\n }\n\n // P3b: Extended BFS \u2014 process any links discovered during P3a revisit pass.\n // Without this, auth-wall pages redirect to real app pages, AI discovers new links,\n // but those links are pushed to queue and NEVER processed (main BFS already exited).\n if (queue.length > 0 && visited.size < maxScreens) {\n const p3bCount = Math.min(queue.length, maxScreens - visited.size);\n logger.info({ newLinks: p3bCount }, '[P3b] Extended BFS \u2014 processing links discovered during revisit pass');\n await onProgress?.(82, `Extended crawl: ${p3bCount} newly discovered page(s)\u2026`);\n while (queue.length > 0 && visited.size < maxScreens && visited.size < segmentSize) {\n if (isCrawlTimedOut()) break;\n const href = queue.shift();\n if (!href) break;\n const canonHref = canonicalize(href);\n if (visited.has(canonHref)) continue;\n if (!isUsefulNavigationUrl(href, origin)) continue;\n visited.set(canonHref, '_pending_');\n try {\n await page.goto(href, { waitUntil: 'networkidle', timeout: 25_000 }).catch(() => {});\n await waitForScreenshotReady(page, rawPage ?? undefined);\n const pathParts = new URL(href).pathname.split('/').filter(Boolean);\n const nm = pathParts.map((p: string) => p.charAt(0).toUpperCase() + p.slice(1).replace(/[-_]/g, ' ')).join(' \u2014 ') || 'Home';\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, nm, href, opts.jobId, 'LINK_FOLLOW');\n visited.set(canonHref, screen.id);\n const sp = `${opts.screenshotDir ?? '/tmp'}/${screen.id}-v${screen.version}.png`;\n await page.screenshot({ path: sp, fullPage: true }).catch(() => {});\n const cloudUrl3 = await uploadToCloud(sp, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(sp)}`).catch(() => '');\n await (AppBrain.saveScreenshot as any)(opts.tenantId, opts.projectId, screen.id, sp, screen.version, 'DESKTOP', cloudUrl3).catch(() => {});\n // GAP 6: DOM snapshot for P3b extended BFS\n const p3bDom = await capturePageHtml(page);\n if (p3bDom) {\n const p3bDomPath = sp.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(p3bDomPath, p3bDom, 'utf8');\n const p3bDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(p3bDomPath)}`;\n const p3bDomCloud = await uploadToCloud(p3bDomPath, p3bDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, p3bDomPath, p3bDomCloud).catch(() => {});\n }\n const [p3bElems, p3bLinks] = await Promise.all([\n extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined).catch(() => []),\n discoverLinks(stagehand, origin, page, linkLLM ?? undefined, aiSkipCount > 0, rawPage ?? undefined)\n .then((metas) => {\n if (metas.length > 0) {\n AppBrain.saveDiscoveredLinks(opts.tenantId, opts.projectId, screen.id, metas.map((m) => ({\n href: m.url, text: m.text, landmark: m.landmark, linkType: 'NAV_LINK', source: m.source, jobId: opts.jobId,\n }))).catch(() => {});\n }\n return metas.map(m => m.url);\n })\n .catch(() => []),\n ]);\n if (p3bElems.length > 0) {\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, screen.id).catch(() => {});\n for (let _ei3 = 0; _ei3 < p3bElems.length; _ei3 += 2) {\n const _b3 = p3bElems.slice(_ei3, _ei3 + 2);\n await Promise.all(_b3.map((el: any) =>\n AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => {})\n ));\n }\n }\n for (const link of p3bLinks) {\n const c = canonicalize(link);\n if (isUsefulNavigationUrl(link, origin) && !queued.has(c) && !visited.has(c) && queued.size < maxScreens * 3) {\n queued.add(c); queue.push(link);\n }\n }\n discovered.push({ url: href, screenId: screen.id, elements: p3bElems.length, version: screen.version });\n logger.info({ url: href, elements: p3bElems.length, newLinks: p3bLinks.length }, '[P3b] Extended BFS screen captured');\n } catch (err) {\n logger.warn({ url: href, err: String(err) }, '[P3b] Extended BFS URL failed');\n visited.set(canonHref, '_error_');\n }\n }\n }\n\n // P6: Gap Pass \u2014 LLM gap analysis on discovered screens to find structurally missing pages.\n // Runs after P3a re-visits so the gap analysis has the most complete screen list possible.\n // Confirmed gap URLs (HEAD=200) are visited directly with the existing browser.\n if (visited.size >= (parseInt(process.env.CRAWLER_GAP_PASS_MIN_SCREENS ?? '') || 3)) {\n try {\n await onProgress?.(80, 'Running gap analysis\u2026');\n const llmCfgForGap = await getCachedCrawlLLM(opts.tenantId);\n const discoveredForGap = Array.from(visited.entries()).map(([url, screenId]) => {\n const d = discovered.find(dd => dd.screenId === screenId);\n return { url, name: d ? (new URL(url).pathname.split('/').filter(Boolean).pop() ?? 'screen') : undefined, elements: d?.elements };\n });\n const gapCandidates = await runGapAnalysis(discoveredForGap, opts.appUrl, llmCfgForGap);\n const confirmedGaps = gapCandidates.filter(g => g.confirmedUrl && !visited.has(canonicalize(g.confirmedUrl!)));\n\n if (confirmedGaps.length > 0) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'URL_CANDIDATES',\n payload: {\n source: 'gap-pass',\n candidates: gapCandidates.map(g => ({ url: g.confirmedUrl ?? g.urlPatterns[0], confidence: g.confidence, reason: g.rationale, status: g.confirmedUrl ? 'hit' : 'miss' })),\n hits: confirmedGaps.length,\n total: gapCandidates.length,\n },\n }).catch(() => { });\n logger.info({ confirmed: confirmedGaps.length, total: gapCandidates.length }, '[P6] Gap pass: visiting confirmed gap URLs');\n\n // Visit each confirmed gap URL with the existing browser (depth=1, no link traversal)\n const gapLoginPattern = /\\/(login|signin|sign-in|auth|log-in)(\\/|$|\\?)/i;\n for (const gap of confirmedGaps.slice(0, parseInt(process.env.CRAWLER_GAP_PASS_MAX_VISITS ?? '') || 25)) {\n if (isCrawlTimedOut() || visited.size >= maxScreens) break;\n const gapUrl = gap.confirmedUrl!;\n try {\n await page.goto(gapUrl, { waitUntil: 'domcontentloaded', timeout: 20_000 });\n // Skip if session expired \u2014 don't save a login-page screenshot as the gap result\n if (gapLoginPattern.test(page.url())) {\n logger.warn({ gapUrl, landed: page.url() }, '[P6] Gap URL redirected to login \u2014 skipping');\n continue;\n }\n await new Promise<void>(r => setTimeout(r, 1_500));\n const gapName = gap.category;\n const gapScreen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, gapName, gapUrl, opts.jobId, 'ENTRY_POINT');\n const gapShot = `${opts.screenshotDir ?? '/tmp'}/${gapScreen.id}-v${gapScreen.version}.png`;\n await waitForScreenshotReady(page, rawPage ?? undefined);\n await page.screenshot({ path: gapShot, fullPage: true });\n const gapCloudUrl = await uploadToCloud(gapShot, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(gapShot)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, gapScreen.id, gapShot, gapScreen.version, 'DESKTOP', gapCloudUrl);\n // GAP 9: DOM snapshot for P6 gap-pass\n const gapDom = await capturePageHtml(page);\n if (gapDom) {\n const gapDomPath = gapShot.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(gapDomPath, gapDom, 'utf8');\n const gapDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(gapDomPath)}`;\n const gapDomCloud = await uploadToCloud(gapDomPath, gapDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, gapScreen.id, gapDomPath, gapDomCloud).catch(() => {});\n }\n const [gapElems, gapLinks, gapLinkMaps] = await Promise.all([\n extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined).catch(() => []),\n discoverLinks(stagehand, origin, page, linkLLM ?? undefined, false, rawPage ?? undefined)\n .then((metas) => {\n if (metas.length > 0) {\n AppBrain.saveDiscoveredLinks(opts.tenantId, opts.projectId, gapScreen.id, metas.map((m) => ({\n href: m.url, text: m.text, landmark: m.landmark, linkType: 'NAV_LINK', source: m.source, jobId: opts.jobId,\n }))).catch(() => {});\n }\n return metas.map(m => m.url);\n })\n .catch(() => []),\n extractLinkMappings(page, origin).catch(() => []),\n ]);\n for (const el of gapElems) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, gapScreen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => { });\n }\n if (gapElems.length === 0) {\n const gapBodyText = await page.evaluate(() => (document as any).body?.innerText ?? '').catch(() => '');\n if (INLINE_AUTH_WALL_RE.test(gapBodyText)) {\n logger.warn({ url: gapUrl, screenId: gapScreen.id }, '[P6] Gap URL got 0 elements \u2014 inline session-expired content, marking requiresAuth');\n AppBrain.updateScreenRequiresAuth(opts.tenantId, gapScreen.id, true).catch(() => {});\n }\n }\n visited.set(canonicalize(gapUrl), gapScreen.id);\n discovered.push({ url: gapUrl, screenId: gapScreen.id, elements: gapElems.length, version: gapScreen.version });\n for (const lm of gapLinkMaps) {\n pendingTransitions.push({ fromScreenId: gapScreen.id, elementMeaning: lm.label, targetUrl: lm.href });\n }\n // Enqueue gap page's links for further crawl (within maxScreens budget)\n for (const href of gapLinks) {\n const canon = canonicalize(href);\n if (isUsefulNavigationUrl(href, origin) && !queued.has(canon) && !visited.has(canon) && queued.size < maxScreens * 3) {\n queued.add(canon); queue.push(href);\n }\n }\n logger.info({ url: gapUrl, elements: gapElems.length, category: gap.category }, '[P6] Gap URL captured');\n } catch (err) {\n logger.warn({ url: gapUrl, err: String(err) }, '[P6] Gap URL visit failed \u2014 non-fatal');\n }\n }\n } else {\n logger.info({ total: gapCandidates.length }, '[P6] Gap pass: no confirmed gaps found');\n }\n } catch (err) {\n const msg = String(err);\n logger.warn({ err: msg }, '[P6] Gap pass failed \u2014 non-fatal, continuing');\n crawlWarnings.push(`gap-analysis skipped: ${msg.includes('401') || msg.toLowerCase().includes('api key') || msg.toLowerCase().includes('authentication') ? 'LLM API key invalid or missing' : msg}`);\n }\n }\n\n // After crawl: mark screens not re-discovered as PENDING_REMOVAL (non-destructive diff)\n // Only run if crawl actually found screens \u2014 0 discovered means failed/aborted run, not evidence of removal\n if (!selective && visited.size > 0) {\n // Only pass canonical URLs of screens that were actually visited (saveScreen called).\n // Exclude marker strings (_skipped_api_, _pending_, _soft404_, pre-auth, skipped)\n // so that skipped API/export paths don't pollute the discoveredSet and prevent removal\n // of old API-path screens from previous crawls.\n const VISIT_MARKER_RE = /^_|^pre-auth$|^skipped$/;\n const discoveredUrls = Array.from(visited.entries())\n .filter(([, v]) => typeof v === 'string' && !VISIT_MARKER_RE.test(v))\n .map(([k]) => k);\n await AppBrain.markRemovedScreens(opts.tenantId, opts.projectId, discoveredUrls, opts.jobId);\n }\n\n // Step 3: Save flows\n await onProgress?.(82, 'Saving app map');\n for (const edge of edges) {\n const fromId = visited.get(canonicalize(edge.fromUrl));\n const toId = visited.get(canonicalize(edge.toUrl));\n if (fromId && toId && fromId !== toId) {\n await AppBrain.saveFlow(opts.tenantId, opts.projectId, `${edge.fromUrl} -> ${edge.toUrl}`, fromId, toId);\n }\n }\n\n // Step 4: Wire KAG element-level transitions\n // For each <a href> link captured from each screen, resolve the href to a visited screenId\n // and store transitionsToScreenId on the matching element.\n await onProgress?.(84, 'Wiring navigation graph (KAG)');\n // Secondary index: pathname \u2192 [canonicalUrl, ...] for subset-param fuzzy matching.\n // A link to /product?id=5 should resolve to a page visited at /product?id=5&session=abc\n // even though their canonical forms differ (session param not in the strip list).\n const visitedByPath = new Map<string, string[]>();\n for (const [canonUrl] of visited) {\n try {\n const p = new URL(canonUrl).pathname;\n const arr = visitedByPath.get(p);\n if (arr) arr.push(canonUrl); else visitedByPath.set(p, [canonUrl]);\n } catch { /* invalid canonical \u2014 skip */ }\n }\n for (const pt of pendingTransitions) {\n let toScreenId = visited.get(canonicalize(pt.targetUrl));\n if (!toScreenId) {\n // Fuzzy fallback: find a visited URL at the same pathname whose params are a superset\n // of the link's params (handles extra session/tracking params on the visited side).\n try {\n const targetCanon = new URL(canonicalize(pt.targetUrl));\n const candidates = visitedByPath.get(targetCanon.pathname) ?? [];\n for (const cand of candidates) {\n const candUrl = new URL(cand);\n let allMatch = true;\n for (const [k, v] of targetCanon.searchParams) {\n if (candUrl.searchParams.get(k) !== v) { allMatch = false; break; }\n }\n if (allMatch) { toScreenId = visited.get(cand); break; }\n }\n } catch { /* non-fatal */ }\n }\n if (toScreenId && toScreenId !== pt.fromScreenId) {\n await AppBrain.setElementTransition(opts.tenantId, pt.fromScreenId, pt.elementMeaning, toScreenId).catch(() => { });\n await AppBrain.saveScreenTransition(opts.tenantId, opts.projectId, {\n fromScreenId: pt.fromScreenId,\n toScreenId,\n action: {\n type: 'click',\n label: pt.elementMeaning,\n targetUrl: pt.targetUrl,\n source: 'crawl-link-mapping',\n },\n confidence: 0.8,\n jobId: opts.jobId,\n }).catch(() => { });\n }\n }\n const transitionCount = pendingTransitions.filter(pt => {\n if (visited.get(canonicalize(pt.targetUrl))) return true;\n try {\n const tc = new URL(canonicalize(pt.targetUrl));\n return (visitedByPath.get(tc.pathname) ?? []).some(cand => {\n const cu = new URL(cand);\n for (const [k, v] of tc.searchParams) { if (cu.searchParams.get(k) !== v) return false; }\n return true;\n });\n } catch { return false; }\n }).length;\n logger.info({ transitionCount }, 'KAG: wired element\u2192screen transitions');\n\n // Navigation graph: resolve DiscoveredLink.toScreenId by matching href \u2192 visited screen IDs.\n // Build a raw-href \u2192 screenId map using both canonical and pathname-based lookups.\n if (opts.jobId) {\n const hrefToScreenId = new Map<string, string>();\n for (const [canonUrl, screenId] of visited) {\n if (screenId && screenId !== '_pending_' && screenId !== '_error_') {\n hrefToScreenId.set(canonUrl, screenId);\n try {\n const u = new URL(canonUrl);\n hrefToScreenId.set(u.href, screenId);\n // Also index by origin+pathname so links with extra query params still resolve\n hrefToScreenId.set(u.origin + u.pathname, screenId);\n hrefToScreenId.set(u.origin + u.pathname.replace(/\\/$/, ''), screenId);\n } catch { /* skip */ }\n }\n }\n AppBrain.resolveDiscoveredLinkTargets(opts.tenantId, opts.projectId, opts.jobId, hrefToScreenId).catch(() => {});\n }\n\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'WORKFLOW_GRAPH_SUMMARY',\n payload: {\n transitionCount,\n screenCount: visited.size,\n profile: domainProfile.industry,\n },\n }).catch(() => { });\n\n if (capturedApiEndpoints.length > 0) {\n logger.info({ count: capturedApiEndpoints.length }, 'Captured unique API endpoint patterns');\n }\n\n if (visited.size >= 5) {\n await onProgress?.(90, `App map saved \u00B7 ${visited.size} screens, ${edges.length} flows wired`);\n }\n\n // P5: Export session cookies BEFORE session health check so we can reuse them even if\n // the main browser session is stale. The cookie jar stays valid for fresh browser contexts\n // even when the CDP-connected Stagehand page shows a redirect to /login.\n let mainStorageState: any;\n try {\n mainStorageState = await playwrightBrowser!.contexts()[0]?.storageState();\n } catch { /* non-fatal */ }\n\n // P5: Orphan page auth re-verify \u2014 confirm session is still alive before tail-end viewport pass.\n // The main BFS can span many minutes; the session may have expired by the time we reach here.\n // If expired, attempt re-auth via Stagehand before proceeding.\n // Creative resilience: even if the main browser is dead, we still run the viewport pass using\n // the exported cookie jar \u2014 fresh browsers are often accepted by servers even after CDP session loss.\n let sessionAliveForViewports = true;\n try {\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 15_000 });\n const sessionCheckUrl = page.url();\n const loginKeywords = /login|signin|sign-in|\\/auth[/?#]/i;\n if (loginKeywords.test(sessionCheckUrl)) {\n logger.warn({ landed: sessionCheckUrl }, '[P5] Session expired before viewport pass \u2014 attempting re-auth');\n let reauthed = false;\n if (opts.credentials) {\n reauthed = await loginWithStagehand(\n stagehand, opts.credentials, opts.appUrl,\n { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider },\n { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId },\n undefined,\n { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId },\n ).catch(() => false);\n }\n if (reauthed) {\n // Refresh cookie jar with newly authenticated session\n try { mainStorageState = await playwrightBrowser!.contexts()[0]?.storageState(); } catch { /* keep prior */ }\n logger.info('[P5] Re-auth succeeded \u2014 proceeding with viewport pass');\n } else {\n sessionAliveForViewports = false;\n const hasCookies = (mainStorageState?.cookies?.length ?? 0) > 0;\n logger.warn({ landed: sessionCheckUrl, hasCookies }, '[P5] Re-auth failed \u2014 will attempt viewport pass with exported cookies');\n if (!hasCookies) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: {\n url: opts.appUrl,\n landed: sessionCheckUrl,\n reason: 'Session expired before mobile/tablet viewport pass and re-auth failed. Re-capture the session in project settings.',\n },\n }).catch(() => { });\n }\n }\n } else {\n logger.info({ url: sessionCheckUrl }, '[P5] Session alive \u2014 proceeding with viewport pass');\n }\n } catch (err) {\n logger.warn({ err: String(err) }, '[P5] Session health check navigation failed \u2014 proceeding with viewport pass anyway');\n }\n\n // Step 5: Multi-viewport pass \u2014 screenshot + DOM element extraction at each device profile.\n // Only DESKTOP (the main crawl above) runs Stagehand AI navigation and link discovery.\n // Mobile/tablet viewports navigate to already-discovered screens and re-extract elements\n // with their viewport-specific bounding rects.\n //\n // IMPORTANT: We launch a fresh Playwright browser per viewport profile instead of calling\n // playwrightBrowser.newContext() on the CDP-connected instance. CDP-connected browsers\n // share the DevTools session with Stagehand and cannot reliably set device emulation\n // (isMobile, hasTouch, viewport, deviceScaleFactor) on new contexts \u2014 the flags are\n // silently ignored, so screenshots come out at desktop dimensions regardless of profile.\n const extraProfiles = (opts.deviceProfiles ?? []).filter((p) => p !== 'DESKTOP');\n // Run the viewport pass even when the main session is dead, as long as we exported cookies \u2014\n // fresh browsers often authenticate successfully with the saved cookie jar.\n const hasExportedAuth = (mainStorageState?.cookies?.length ?? 0) > 0;\n if ((sessionAliveForViewports || hasExportedAuth) && extraProfiles.length > 0 && discovered.length > 0) {\n const { devices, chromium: pwChromium } = await import('playwright');\n const DEVICE_MAP: Record<string, any> = {\n // Override viewport heights: Playwright's device descriptors use viewport-minus-browser-chrome\n // (659 for iPhone 15, ~980 for iPad Pro 11). Override to full logical screen dimensions so\n // screenshots match what users see on device and mobile-detection scripts pass.\n MOBILE_PORTRAIT: { ...devices['iPhone 15'], viewport: { width: 393, height: 852 } },\n TABLET: { ...devices['iPad Pro 11'], viewport: { width: 834, height: 1194 } },\n };\n\n for (const profile of extraProfiles) {\n const deviceConfig = DEVICE_MAP[profile];\n if (!deviceConfig) continue;\n await onProgress?.(95, `Capturing ${profile} screenshots + elements\u2026`);\n\n // Launch a dedicated browser for this viewport \u2014 no CDP sharing\n let mobileBrowser: import('playwright').Browser | null = null;\n try {\n mobileBrowser = await pwChromium.launch({\n headless: true,\n executablePath,\n args: chromeArgs,\n });\n const mobileCtx = await mobileBrowser.newContext({\n ...deviceConfig,\n ignoreHTTPSErrors: true,\n ...(mainStorageState ? { storageState: mainStorageState } : {}),\n });\n mobileCtx.on('download', (dl: any) => { dl.cancel().catch(() => {}); });\n const mobilePage = await mobileCtx.newPage();\n\n for (const disc of discovered) {\n if (isCrawlTimedOut()) break;\n if (!disc.screenId) continue;\n try {\n await mobilePage.goto(disc.url, { waitUntil: 'domcontentloaded', timeout: 20_000 });\n await mobilePage.waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => { });\n await dismissOverlays(mobilePage);\n try { await mobilePage.addStyleTag({ content: '*, *::before, *::after { animation-duration: 0s !important; transition-duration: 0s !important; }' }); } catch { /* ignore */ }\n // mobilePage is a real Playwright page \u2014 pass it as rawPage so CDP wheel events\n // trigger virtual scrollers (react-window / TanStack Virtual) at mobile viewports.\n await infiniteScrollToBottom(mobilePage, { maxScrolls: 20, scrollDelay: 300, stabilizeMs: 400 }, mobilePage).catch(() => { });\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `${disc.screenId}-${profile.toLowerCase()}-v${disc.version}.png`);\n await waitForScreenshotReady(mobilePage, mobilePage);\n // Screenshot and DOM element extraction run in parallel\n const [, vpElements] = await Promise.all([\n mobilePage.screenshot({ path: shotPath, fullPage: true }),\n domFallbackElements(mobilePage, mobilePage),\n ]);\n const cloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, disc.screenId, shotPath, disc.version!, profile, cloudUrl);\n AppBrain.autoCreateVisualBaseline(opts.tenantId, opts.projectId, disc.screenId, profile, shotPath, gitInfo.branch, gitInfo.commit || undefined).catch(() => { });\n // Save viewport-specific element records (bounding rects differ per viewport)\n for (const el of vpElements) {\n AppBrain.saveElement(\n opts.tenantId, opts.projectId, disc.screenId,\n el.meaning, el.role, el.expectedData, el.notes,\n undefined, true, el.boundingRect, el.ariaState, el.parentLandmark,\n profile,\n ).catch(() => { });\n }\n } catch (err) {\n logger.warn({ profile, url: disc.url, err: String(err) }, `[P5] ${profile} screenshot failed \u2014 skipping screen`);\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n screenId: disc.screenId,\n type: 'VIEWPORT_SCREENSHOT_FAILURE',\n payload: { profile, url: disc.url, reason: String(err) },\n }).catch(() => { });\n }\n }\n await mobilePage.close().catch(() => { });\n await mobileCtx.close().catch(() => { });\n } catch (profileErr) {\n logger.warn({ profile, err: String(profileErr) }, `[P5] ${profile} browser launch failed`);\n } finally {\n await mobileBrowser?.close().catch(() => { });\n }\n }\n }\n\n // Step 6: Interactive probe \u2014 always-on (C-06) to capture real validation errors, toasts, and modals.\n // Previously gated on opts.interactive or sparse crawls; now unconditional for accurate expected-result generation.\n const shouldRunInteractiveProbe = true;\n if (shouldRunInteractiveProbe) {\n await onProgress?.(88, 'Running interactive probe (capturing real errors & modals)');\n const probeInputs = discovered\n .filter((d) => d.screenId)\n .map((d) => ({ url: d.url, screenId: d.screenId!, elements: d.elementFacts ?? [] }));\n await probeAllScreens(page, opts.tenantId, opts.projectId, probeInputs, onProgress, opts.jobId);\n }\n\n // Step 7: End-of-crawl state graph coverage report.\n // Per-screen probes (dropdown, CRUD, filter, DnD, nested-contexts, shadow-DOM,\n // accessibility-tree, performance, service-worker) run per-screen inside the BFS\n // loop above and are saved as PER_SCREEN_PROBES evidence.\n try {\n await onProgress?.(90, 'Generating state graph coverage report');\n // Populate stateGraph from discovered screens + BFS edges (previously always empty).\n const stateGraph = new ScreenTransitionGraph();\n const now = new Date().toISOString();\n for (const d of discovered) {\n if (!d.screenId || !d.url) continue;\n const hashVal = simHash32(d.url);\n stateGraph.addState({\n id: d.screenId,\n url: d.url,\n normalizedUrl: d.url,\n title: d.url,\n interactiveElementCount: d.elements ?? 0,\n domFingerprint: hashVal.toString(16).padStart(8, '0'),\n simHashValue: hashVal,\n visitedAt: now,\n });\n }\n // Wire transitions from BFS edges\n for (const edge of edges) {\n const fromId = visited.get(canonicalize(edge.fromUrl));\n const toId = visited.get(canonicalize(edge.toUrl));\n if (fromId && toId && fromId !== '_pending_' && fromId !== '_error_' &&\n toId !== '_pending_' && toId !== '_error_') {\n stateGraph.addTransition(fromId, toId, 'navigate', edge.toUrl, now);\n }\n }\n const coveragePayload: Record<string, unknown> = {\n stateGraph: stateGraph.getCoverageReport(),\n totalScreensCrawled: discovered.filter(d => !!d.screenId).length,\n };\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'CRAWL_COVERAGE_REPORT',\n payload: coveragePayload,\n }).catch(() => { });\n } catch (extErr) {\n logger.warn({ err: String(extErr) }, '[coverage-report] non-fatal error');\n }\n\n await onProgress?.(97, 'Running post-crawl analysis');\n\n // \u2500\u2500 Per-crawl summaries (fire-and-forget, non-blocking) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const successScreens = discovered.filter(d => !!d.screenId);\n ; (async () => {\n try {\n // 1. Sitemap XML\n if (successScreens.length > 0) {\n const sitemapUrls = screensToSitemapUrls(successScreens.map(d => ({ url: d.url })));\n const sitemapPath = path.join(opts.screenshotDir ?? '/tmp', 'sitemap.xml');\n await writeSitemap(sitemapUrls, sitemapPath);\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'SITEMAP_WRITTEN', payload: { path: sitemapPath, urlCount: sitemapUrls.length },\n }).catch(() => { });\n }\n\n // 2. OpenAPI spec from captured API endpoints\n if (capturedApiEndpoints.length > 0) {\n const spec = generateOpenApiSpec(capturedApiEndpoints, { title: `${opts.projectId} API`, version: '1.0.0' });\n const yamlStr = specToYaml(spec);\n const specPath = path.join(opts.screenshotDir ?? '/tmp', 'openapi.yaml');\n await fs.writeFile(specPath, yamlStr, 'utf8');\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'OPENAPI_SPEC', payload: { path: specPath, endpointCount: capturedApiEndpoints.length },\n }).catch(() => { });\n }\n\n // 3. Dead link summary\n const deadStats = deadLinkTracker.stats();\n if (deadStats.total > 0) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'DEAD_LINKS', payload: { ...deadStats, links: deadLinkTracker.getDeadLinks() },\n }).catch(() => { });\n }\n\n // 4. Redirect chain summary\n const redirectStats = redirectRegistry.stats();\n if (redirectStats.withRedirects > 0) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'REDIRECT_CHAINS', payload: { ...redirectStats, problematic: redirectRegistry.getProblematic() },\n }).catch(() => { });\n }\n\n // 5. Playwright test generation (first 5 screens as sample)\n if (successScreens.length > 0) {\n const sampleScreens = successScreens.slice(0, 5).map(d => ({\n id: d.screenId!, url: d.url, name: d.url,\n }));\n const playwrightScript = generatePlaywrightTest(sampleScreens);\n const testPath = path.join(opts.screenshotDir ?? '/tmp', 'generated.spec.ts');\n await fs.writeFile(testPath, playwrightScript, 'utf8');\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'PLAYWRIGHT_TEST_GENERATED', payload: { path: testPath, screenCount: sampleScreens.length },\n }).catch(() => { });\n }\n\n // 6. Webhook notification (if configured on project)\n const webhookUrl = (opts as any).webhookUrl;\n if (webhookUrl) {\n const notifier = new WebhookNotifier({ url: webhookUrl, secret: (opts as any).webhookSecret });\n await notifier.notify('crawl.completed', opts.jobId ?? '', opts.projectId, opts.tenantId, {\n screensFound: successScreens.length,\n apiEndpoints: capturedApiEndpoints.length,\n deadLinks: deadLinkTracker.stats().total,\n }).catch(() => { });\n }\n } catch { /* post-crawl analysis is non-fatal */ }\n })();\n\n await onProgress?.(98, 'Finalizing');\n // Remaining queue = URLs discovered but not yet crawled due to segment limit\n const wasTimeout = isCrawlTimedOut();\n const pendingUrls = queue.filter((u) => !visited.has(canonicalize(u)));\n // All fully-processed URLs (exclude '_pending_' entries interrupted by timeout/abort)\n const visitedUrls = Array.from(visited.entries())\n .filter(([_k, v]) => v !== '_pending_')\n .map(([k]) => k);\n const hasMoreSegments = pendingUrls.length > 0;\n if (wasTimeout && pendingUrls.length > 0) {\n const elapsedMin = Math.round((Date.now() - crawlLoopStart) / 60_000);\n crawlWarnings.push(`global-timeout: crawl stopped after ${elapsedMin} minutes with ${pendingUrls.length} URLs remaining`);\n }\n const screensSucceeded = discovered.filter(d => !!d.screenId).length;\n const screensErrored = discovered.filter(d => !!d.error && !d.screenId).length;\n\n // Drain pending AI summary writes before marking the job done \u2014 ensures descriptions\n // are visible immediately after crawl completes. Cap wait at 30 s per screen, 60 s total.\n if (pendingSummaryWrites.length > 0) {\n await Promise.race([\n Promise.allSettled(pendingSummaryWrites),\n new Promise<void>((resolve) => setTimeout(resolve, Math.min(60_000, pendingSummaryWrites.length * 3_000))),\n ]);\n }\n\n // Detect systematic element/link extraction failure across all screens\n if (screensSucceeded >= 3) {\n const screensWithElements = discovered.filter(d => (d.elements ?? 0) > 0 && d.screenId).length;\n if (screensWithElements === 0) {\n crawlWarnings.push(\n `element-extraction: 0 elements found across all ${screensSucceeded} screens \u2014 ` +\n `DOM evaluate may be failing (check server logs for \"page.evaluate threw\" warnings)`,\n );\n }\n }\n\n return {\n screensFound: screensSucceeded, // successful captures only (not errors)\n screensErrored, // pages visited but failed to capture\n screensSkippedToNextSegment: pendingUrls.length,\n isPartial: hasMoreSegments, // true = more segments auto-queued\n discovered,\n apiEndpoints: capturedApiEndpoints,\n performanceMetrics,\n pendingUrls, // feed into next segment's resumeUrls\n visitedUrls, // all fully-processed URLs for skipUrls in continuation\n wasTimeout, // true when global timeout triggered the BFS break\n segmentIndex: segIdx, // which segment this was\n hasMoreSegments,\n domHashes: Array.from(seenDomHashes), // carry forward to next segment to avoid re-screenshotting\n crawlWarnings: crawlWarnings.length > 0 ? crawlWarnings : undefined,\n };\n } finally {\n // Log accumulated Stagehand LLM usage (extract/act/observe calls) to cost ledger.\n if (stagehandPromptTokens > 0 || stagehandCompletionTokens > 0) {\n const totalTokens = stagehandPromptTokens + stagehandCompletionTokens;\n const shProvider = stagehandModel.includes('/') ? stagehandModel.split('/')[0] : configuredProvider || 'openai';\n const shModel = stagehandModel.includes('/') ? stagehandModel.split('/').slice(1).join('/') : stagehandModel;\n const shUsage = {\n provider: shProvider,\n model: shModel,\n promptTokens: stagehandPromptTokens,\n completionTokens: stagehandCompletionTokens,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n totalTokens,\n };\n recordLLMCall({\n tenantId: opts.tenantId,\n projectId: opts.projectId,\n jobId: opts.jobId,\n agentType: 'crawl_stagehand',\n label: 'stagehand_browser_actions',\n usage: { ...shUsage, estimatedCostUsd: estimateCost(shUsage, `${shProvider}/${shModel}`) },\n }).catch(() => { });\n }\n await playwrightBrowser?.close().catch(() => { });\n await stagehand.close().catch(() => { });\n await chromeProc.close().catch(() => { });\n }\n}\n\n// Elements whose meanings indicate UI state toggles or noise \u2014 filtered from both DOM and AI results.\nconst ELEMENT_NOISE = /^(cookie|consent|privacy|accept|decline|dismiss|close|copy|\u00A9|v\\d|switch to (dark|light)|dark mode|light mode|toggle (dark|light|theme)|theme (toggle|switch)|share|tweet|follow|subscribe to newsletter|skip to|back to top|\\s*$)/i;\n\nasync function extractElements(stagehand: Stagehand, page: any, llmCfg?: { provider: string; model: string; apiKey?: string; baseUrl?: string } | null, rawPage?: any): Promise<Array<{ meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number>; ariaState?: Record<string, string>; parentLandmark?: string }>> {\n // llmCfg reserved for per-task model selection (future: create task-scoped Stagehand)\n // DOM-first: fast, no LLM cost, covers server-rendered and most SPAs.\n // Threshold >= 2 so a lone dark-mode button doesn't suppress AI fallback for rich pages.\n // rawPage: real Playwright CDP page used for page.evaluate() \u2014 avoids Stagehand's proxy\n // re-bundling the function with esbuild (which injects __name, breaking browser eval).\n const domElements = await domFallbackElements(page, rawPage).catch((err: any) => {\n console.warn('[crawler] domFallbackElements failed (page context issue or DOM error):', err?.message ?? err);\n return [] as Array<{ meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number>; ariaState?: Record<string, string>; parentLandmark?: string }>;\n });\n\n // FM-8: extract interactive elements from visible same-origin iframes\n const iframeElements: typeof domElements = [];\n try {\n const iframes = page.frames ? page.frames() : [];\n for (const frame of iframes) {\n if (frame === page.mainFrame?.()) continue; // skip main frame\n const iframeUrl: string = await frame.url().catch(() => '');\n if (!iframeUrl || iframeUrl === 'about:blank' || iframeUrl.startsWith('javascript:')) continue;\n const frameEls = await domFallbackElements(frame).catch(() => []);\n // Tag iframe elements with source context\n for (const el of frameEls.slice(0, 30)) {\n iframeElements.push({ ...el, notes: el.notes ? `${el.notes} [in iframe]` : '[in iframe]' });\n }\n }\n } catch { /* iframes may be cross-origin or inaccessible \u2014 skip silently */ }\n\n // FM-7: reveal dynamic elements \u2014 click/hover trigger elements that show dropdowns or modals\n // Only run when base DOM found elements (not on blank pages) to avoid spurious interactions.\n let dynamicElements: typeof domElements = [];\n if (domElements.length > 0) {\n try {\n dynamicElements = await page.evaluate(() => {\n const out: { meaning: string; role: string; notes: string }[] = [];\n const seen = new Set<string>();\n // Look for select/combobox/listbox that aren't already captured as interactive elements\n const triggers = document.querySelectorAll<HTMLElement>('[role=\"combobox\"],[role=\"listbox\"] [role=\"option\"],[aria-haspopup]');\n triggers.forEach((el) => {\n const label = (el.getAttribute('aria-label') || el.textContent?.trim() || '').slice(0, 80);\n if (!label || seen.has(label)) return;\n // Don't duplicate what's already captured\n const role = el.getAttribute('role') ?? el.tagName.toLowerCase();\n seen.add(label);\n out.push({ meaning: label, role, notes: '[dynamic/revealed]' });\n });\n return out.slice(0, 30);\n }).catch(() => []);\n } catch { dynamicElements = []; }\n }\n\n // Always capture content elements (headings, meta, cards, nav, FAQ) regardless of interactive count.\n // Previously this was fallback-only; now both paths run together so static sections are\n // always visible to the test generator even on pages with forms.\n const contentElements = await contentFallbackElements(page).catch((err: any) => {\n console.warn('[crawler] contentFallbackElements failed (page context issue):', err?.message ?? err);\n return [] as Array<{ meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number> }>;\n });\n\n // Cross-source text deduplication: strips wrapper phrases like \"Button to expand '...' details\"\n // and \"... FAQ button\" so duplicate FAQ buttons from DOM + content sources are collapsed.\n const crossSourceDedup = <T extends { meaning: string; role: string }>(arr: T[]): T[] => {\n const stripPhrases = (s: string) => s\n .replace(/^button to expand ['\"]?|['\"]?\\s*details$/gi, '')\n .replace(/\\s+(faq\\s*)?button$/i, '')\n .replace(/^button:\\s*/i, '')\n .toLowerCase().trim().slice(0, 80);\n const ROLE_PRIORITY: Record<string, number> = { 'faq-question': 10, 'faq-answer': 9, 'h1': 8, 'h2': 7, 'h3': 6, 'h4': 5, 'heading': 8, button: 3, a: 2 };\n const normMap = new Map<string, number>();\n const result: T[] = [];\n for (const el of arr) {\n const norm = stripPhrases(el.meaning);\n if (!norm) { result.push(el); continue; }\n const existingIdx = normMap.get(norm);\n if (existingIdx === undefined) { normMap.set(norm, result.length); result.push(el); }\n else {\n const exPri = ROLE_PRIORITY[result[existingIdx].role] ?? 1;\n const thisPri = ROLE_PRIORITY[el.role] ?? 1;\n if (thisPri > exPri) result[existingIdx] = el;\n }\n }\n return result;\n };\n\n if (domElements.length >= 2) return crossSourceDedup([...domElements, ...iframeElements, ...dynamicElements, ...contentElements]);\n\n // Static/marketing page \u2014 no interactive widgets; use content elements.\n if (contentElements.length > 0) return crossSourceDedup([...domElements, ...contentElements]);\n\n // AI fallback: DOM found nothing or only noise \u2014 try AI (pure SPA, shadow DOM, canvas-based).\n try {\n const extracted = await Promise.race([\n stagehand.extract(\n 'Extract ONLY the meaningful form and action elements on this page \u2014 inputs, selects, textareas, and action buttons. ' +\n 'For each: a clear human-readable purpose (e.g. \"Email address input\", \"Submit password reset button\"), ' +\n 'its role (button/input/select/checkbox/textarea), and for inputs the expected data type ' +\n '(valid_email/password/phone/date/search_term/text). ' +\n 'SKIP: navigation links, header/footer links, cookie banners, theme toggles (dark mode/light mode), ' +\n 'social share buttons, version strings, decorative elements, any button inside a nav or header. ' +\n 'Focus ONLY on main content forms and primary action buttons. Return at most 20 elements.',\n ElementSchema as any\n ),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 30_000)),\n ]);\n if (!extracted) return domElements;\n // Apply noise filter to AI results \u2014 AI doesn't always follow skip instructions\n const filtered = (extracted as any).elements.filter((e: any) => !ELEMENT_NOISE.test(e.meaning ?? ''));\n return filtered.slice(0, 40);\n } catch {\n return domElements;\n }\n}\n\nasync function discoverLinks(stagehand: Stagehand, origin: string, page: any, llmCfg?: { provider: string; model: string; apiKey?: string; baseUrl?: string } | null, skipAi = false, rawPage?: any): Promise<DiscoveredLinkMeta[]> {\n // Expand collapsed nav menus (hamburger, aria-haspopup, Radix closed triggers) so hidden routes\n // become part of the DOM before querying. This catches SPA nav dropdowns that only render on click.\n const navExpanded = await expandNavMenus(page);\n\n // DOM-first: <a href> links \u2014 standard apps. AI supplements when DOM coverage is < 20 unique links.\n // Threshold of 20 (not 8) because nav sidebars quickly provide 8+ links while missing deep content URLs.\n const domLinks = await domFallbackLinks(page, origin, rawPage);\n\n // Interact with tabs, carousels, and accordions to reveal hidden content and discover more links.\n // interactAndCollectLinks returns string[] \u2014 convert to DiscoveredLinkMeta[] with source INTERACTIVE.\n const interactiveRaw = await interactAndCollectLinks(page, origin);\n const interactiveLinks: DiscoveredLinkMeta[] = interactiveRaw.map((url) => ({ url, source: 'INTERACTIVE' as const }));\n\n // Dismiss any opened menus so page is clean for screenshot/element extraction after this call.\n if (navExpanded) {\n page.keyboard?.press('Escape').catch(() => { });\n await page.evaluate(() => {\n // Also click any currently-open triggers to close them (toggle pattern)\n document.querySelectorAll<HTMLElement>('[aria-expanded=\"true\"],[data-state=\"open\"],[data-headlessui-state=\"open\"]').forEach(el => {\n try { el.click(); } catch { /* ignore */ }\n });\n }).catch(() => { });\n }\n\n // Deduplicate by URL \u2014 DOM wins over INTERACTIVE for metadata richness.\n const seenUrls = new Set<string>();\n const allDomLinks: DiscoveredLinkMeta[] = [];\n for (const link of [...domLinks, ...interactiveLinks]) {\n if (!seenUrls.has(link.url)) {\n seenUrls.add(link.url);\n allDomLinks.push(link);\n }\n }\n\n if (allDomLinks.length >= 50 || skipAi) return allDomLinks;\n\n // AI complement: DOM found fewer than 50 unique links \u2014 SPA likely has JS-router pages not in <a href>.\n // Always merge DOM + AI so we never lose already-discovered links.\n // 12s timeout: allows 1 OpenAI retry (4.8s delay) but bails before the 2nd retry wastes more time.\n try {\n const extracted = await Promise.race([\n stagehand.extract(\n `Find all in-app navigation links for this application (origin: ${origin}). ` +\n 'Include: main nav, sidebar, content links, feature pages, settings pages. ' +\n 'Exclude: logout, sign out, delete, external sites, anchor-only links (#), mailto:, javascript:.',\n LinksSchema as any\n ),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 12_000)),\n ]);\n if (!extracted) return allDomLinks;\n const { links } = extracted as any;\n const currentUrl: string = page.url?.() ?? '';\n const aiLinks: DiscoveredLinkMeta[] = links\n .map((href: string) => {\n try { const u = new URL(href, currentUrl); if (!/^#!?\\//.test(u.hash)) u.hash = ''; return u.toString(); }\n catch { return null; }\n })\n .filter((u: string | null): u is string => {\n if (!u) return false;\n return isUsefulNavigationUrl(u, origin);\n })\n .map((url: string) => ({ url, source: 'AI' as const }));\n\n // Always merge DOM + AI \u2014 AI complements, never replaces. Dedup by URL.\n const merged: DiscoveredLinkMeta[] = [...allDomLinks];\n const mergedUrls = new Set(merged.map((l) => l.url));\n for (const link of aiLinks) {\n if (!mergedUrls.has(link.url) && isUsefulNavigationUrl(link.url, origin)) {\n mergedUrls.add(link.url);\n merged.push(link);\n }\n }\n return merged.filter((l) => isUsefulNavigationUrl(l.url, origin));\n } catch (err: any) {\n // Detect OpenAI rate-limit errors \u2014 signal caller via thrown special error so circuit breaker can trip\n const is429 = err?.status === 429 || String(err?.message ?? '').includes('429') || String(err?.message ?? '').includes('rate limit');\n if (is429) throw Object.assign(new Error('RATE_LIMITED'), { isRateLimit: true, domLinks: allDomLinks });\n return allDomLinks;\n }\n}\n\nexport async function domFallbackElements(page: any, rawPage?: any): Promise<Array<{ meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number>; ariaState?: Record<string, string>; parentLandmark?: string }>> {\n // Named function so we can .toString() it for CDP Runtime.evaluate fallback\n function _browserEval() {\n const out: { meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number>; ariaState?: Record<string, string>; parentLandmark?: string }[] = [];\n const seen = new Set<string>();\n // UI chrome noise: cookie banners, theme toggles, version strings, social/share buttons\n const noise = /^(cookie|consent|privacy|accept|decline|dismiss|close|copy|\u00A9|v\\d|switch to (dark|light)|dark mode|light mode|toggle (dark|light|theme)|theme (toggle|switch)|share|tweet|follow|subscribe to newsletter|skip to|back to top|\\s*$)/i;\n\n const querySelectorAllDeep = (root: any, selector: string): Element[] => {\n const results: Element[] = [];\n const queue: any[] = [root];\n while (queue.length > 0) {\n const current = queue.shift();\n Array.from(current.querySelectorAll(selector)).forEach((el: any) => results.push(el));\n current.querySelectorAll('*').forEach((el: any) => {\n if (el.shadowRoot) queue.push(el.shadowRoot);\n });\n }\n return results;\n };\n\n // Expanded selector \u2014 all interactive ARIA roles + native form elements + rich editors + bare nav links\n const selector = 'input:not([type=hidden]),select,textarea,button,a[href],[role=\"button\"],[role=\"checkbox\"],[role=\"radio\"],[role=\"combobox\"],[role=\"slider\"],[role=\"spinbutton\"],[role=\"switch\"],[role=\"tab\"],[role=\"dialog\"],[role=\"alertdialog\"],[role=\"menu\"],[role=\"menuitem\"],[role=\"menuitemcheckbox\"],[role=\"menuitemradio\"],[role=\"listbox\"],[role=\"option\"],[role=\"treeitem\"],[role=\"searchbox\"],[role=\"gridcell\"],[role=\"link\"],[contenteditable=\"true\"]';\n\n querySelectorAllDeep(document, selector).forEach((el: any) => {\n const style = window.getComputedStyle(el);\n // Enhanced actionability checks\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0' || style.pointerEvents === 'none') return;\n if (el.hasAttribute('inert') || el.getAttribute('aria-disabled') === 'true') return;\n\n const rect = el.getBoundingClientRect();\n const hasAccessibleLabel = !!(el.getAttribute('aria-label') || el.getAttribute('aria-labelledby'));\n if (rect.width === 0 && rect.height === 0 && !hasAccessibleLabel) return;\n\n // Skip elements inside 3rd-party chat widgets, cookie banners, floating overlays \u2014 these appear on EVERY page\n if (el.closest('[id*=\"intercom\"],[class*=\"intercom-\"],[id*=\"crisp\"],[class*=\"crisp-\"],[id*=\"freshchat\"],[id*=\"freshdesk\"],[id*=\"drift\"],[class*=\"drift-\"],[id*=\"hubspot-\"],[class*=\"hs-chat\"],[class*=\"hs-widget\"],[id*=\"tawk\"],[class*=\"tawk-\"],[id*=\"chat-widget\"],[class*=\"chat-widget\"],[class*=\"chatbot\"],[id*=\"zopim\"],[id*=\"ze-snippet\"],[class*=\"cookie-banner\"],[class*=\"cookie-consent\"],[class*=\"gdpr-banner\"],[id*=\"cookie-law\"],[class*=\"cookie-law\"],[id*=\"popup-form\"],[class*=\"popup-form\"],[class*=\"floating-form\"],[class*=\"sticky-cta\"],[id*=\"wm-ipp\"],[class*=\"wm-ipp\"]')) return;\n\n const tag = el.tagName.toLowerCase();\n const ariaRole = el.getAttribute('role');\n const isActionEl = tag === 'button' || tag === 'a' || ariaRole === 'button';\n\n // Skip plain anchor links inside <footer> only \u2014 footer chrome (sitemap, legal links) has no test value.\n // Header nav links ARE test targets (SPA primary navigation lives in <header>) \u2014 do NOT skip.\n // Do NOT skip <nav> elements: SPA dashboard sidebars live in <nav> and are primary test targets.\n if (tag === 'a') {\n let p = el.parentElement;\n while (p) {\n if (p.tagName?.toLowerCase() === 'footer') return;\n p = p.parentElement;\n }\n }\n\n // Label resolution: explicit <label for>, implicit wrapping <label>, aria-label, placeholder\n let labelText = '';\n if (el.id) {\n const linkedLabel = document.querySelector(`label[for=\"${el.id}\"]`);\n if (linkedLabel) labelText = linkedLabel.textContent?.trim() || '';\n }\n // Implicit label: input is a child of <label> (no for= attribute needed)\n if (!labelText) {\n const wrappingLabel = el.closest('label');\n if (wrappingLabel) {\n const clone = wrappingLabel.cloneNode(true) as Element;\n clone.querySelectorAll('input,select,textarea,button').forEach((c: any) => c.remove());\n labelText = clone.textContent?.replace(/\\s+/g, ' ').trim() || '';\n }\n }\n\n const label = (\n el.getAttribute('aria-label') ||\n el.getAttribute('placeholder') ||\n labelText ||\n el.innerText?.replace(/\\s+/g, ' ').trim() ||\n el.getAttribute('name') ||\n ''\n ).slice(0, 80);\n\n if (!label || noise.test(label) || label.length > 70) return;\n\n const role = tag === 'input' ? (el.type || 'text') : el.hasAttribute('contenteditable') ? 'rich-text' : (ariaRole || tag);\n const key = `${role}:${label.toLowerCase()}`;\n if (seen.has(key)) return;\n seen.add(key);\n\n let expectedData: string | undefined;\n if (tag === 'input') {\n if (el.type === 'email' || /email/i.test(label)) expectedData = 'valid_email';\n else if (el.type === 'password' || /password/i.test(label)) expectedData = 'password';\n else if (el.type === 'tel' || /phone|mobile/i.test(label)) expectedData = 'phone';\n else if (el.type === 'date' || /\\bdate\\b/i.test(label)) expectedData = 'date';\n else if (/\\b(code|otp|token)\\b/i.test(label)) expectedData = 'one_time_code';\n else if (/\\b(search|query)\\b/i.test(label)) expectedData = 'search_term';\n else if (el.type === 'number' || /\\b(amount|quantity|count|age|year)\\b/i.test(label)) expectedData = 'number';\n else if (el.type === 'url' || /\\b(url|website|link)\\b/i.test(label)) expectedData = 'url';\n else if (el.type === 'file') expectedData = 'file';\n }\n\n // Multi-Attribute Identity\n const attrs: Record<string, string> = {};\n if (el.id) attrs.id = el.id;\n if (el.name) attrs.name = el.name;\n if (el.getAttribute('data-testid')) attrs['data-testid'] = el.getAttribute('data-testid');\n\n // HTML5 validation attributes \u2014 ground test boundary values in real constraints\n if (tag === 'input' || tag === 'textarea') {\n if (el.required) attrs.required = 'true';\n if (el.pattern) attrs.pattern = el.pattern;\n if (el.minLength > 0) attrs.minLength = String(el.minLength);\n if (el.maxLength > 0 && el.maxLength < 524288) attrs.maxLength = String(el.maxLength);\n if (el.min !== '') attrs.min = String(el.min);\n if (el.max !== '') attrs.max = String(el.max);\n if (el.step && el.step !== 'any') attrs.step = String(el.step);\n if (el.accept) attrs.accept = el.accept;\n if (el.multiple) attrs.multiple = 'true';\n if (el.readOnly) attrs.readOnly = 'true';\n if (el.disabled) attrs.disabled = 'true';\n if (el.autocomplete && el.autocomplete !== 'on') attrs.autocomplete = el.autocomplete;\n }\n // CSS class hint \u2014 first component-library class for COMPONENT file detection\n const cssClass = (el.className || '')\n .split(' ')\n .map((c: string) => c.trim())\n .find((c: string) => c.length > 2 && !/^(true|false|active|disabled|hidden|visible)$/i.test(c));\n if (cssClass) attrs.cssClass = cssClass;\n\n // GAP 4: Select option enumeration \u2014 test generator knows valid values\n if (tag === 'select' && el.options?.length > 0 && el.options.length <= 60) {\n const opts = Array.from(el.options).map((o: any) => {\n const entry: Record<string, any> = { v: o.value, l: o.text.trim() };\n if (o.selected) entry.s = true;\n return entry;\n }).filter((o: any) => o.l);\n if (opts.length > 0) attrs.selectOptions = JSON.stringify(opts);\n }\n\n // GAP 6: aria-describedby help text \u2014 captures real constraint text (e.g. \"min 8 chars\")\n const describedById = el.getAttribute('aria-describedby');\n if (describedById) {\n const helpEl = document.getElementById(describedById.split(' ')[0]);\n const helpText = helpEl?.textContent?.trim().slice(0, 200);\n if (helpText) attrs.helpText = helpText;\n }\n\n // GAP 1: Form grouping \u2014 inputs/buttons tagged with their containing form\n const form = el.closest('form');\n if (form) {\n if ((form as any).id) attrs.formId = (form as any).id;\n const formAction = form.getAttribute('action');\n if (formAction && !formAction.startsWith('javascript:')) attrs.formAction = formAction.slice(0, 120);\n const formMethod = (form as any).method;\n if (formMethod) attrs.formMethod = formMethod.toUpperCase();\n }\n const fieldset = el.closest('fieldset');\n if (fieldset) {\n const legendText = fieldset.querySelector('legend')?.textContent?.trim().slice(0, 60);\n if (legendText) attrs.fieldsetGroup = legendText;\n }\n\n // GAP 7: Button classification \u2014 type + destructive intent\n if (tag === 'button' || ariaRole === 'button') {\n if (el.type && el.type !== 'button') attrs.buttonType = el.type; // submit | reset\n if (/\\b(delete|remove|destroy|revoke|clear|reset|discard|cancel)\\b/i.test(label)) attrs.isDestructive = 'true';\n }\n\n // ARIA state snapshot \u2014 promoted to first-class field (Phase 1)\n const stateMap: Record<string, string> = {};\n const ariaExpanded = el.getAttribute('aria-expanded');\n const ariaChecked = el.getAttribute('aria-checked');\n const ariaPressed = el.getAttribute('aria-pressed');\n const ariaSelected = el.getAttribute('aria-selected');\n const ariaInvalid = el.getAttribute('aria-invalid');\n const ariaCurrent = el.getAttribute('aria-current');\n if (ariaExpanded !== null) stateMap.expanded = ariaExpanded;\n if (ariaChecked !== null) stateMap.checked = ariaChecked;\n if (ariaPressed !== null) stateMap.pressed = ariaPressed;\n if (ariaSelected !== null) stateMap.selected = ariaSelected;\n if (ariaInvalid && ariaInvalid !== 'false') stateMap.invalid = ariaInvalid;\n if (ariaCurrent) stateMap.current = ariaCurrent;\n if (el.getAttribute('aria-required') === 'true' && !attrs.required) stateMap.required = 'true';\n\n // Parent landmark \u2014 promoted to first-class field (Phase 1)\n const getRegion = (node: any): string | undefined => {\n let p = node.parentElement;\n while (p && p !== document.body) {\n const ptag = p.tagName?.toLowerCase();\n const prole = p.getAttribute?.('role');\n if (prole === 'dialog' || prole === 'alertdialog') return 'modal';\n if (prole === 'main' || ptag === 'main') return 'main';\n if (prole === 'complementary' || ptag === 'aside') return 'aside';\n if (prole === 'navigation' || ptag === 'nav') return 'nav';\n if (prole === 'banner' || ptag === 'header') return 'header';\n if (prole === 'contentinfo' || ptag === 'footer') return 'footer';\n p = p.parentElement;\n }\n return undefined;\n };\n const parentLandmark = getRegion(el);\n\n // GAP 8: Rich text editor detection\n if (el.hasAttribute('contenteditable')) {\n const cls = ((el.className || '') + ' ' + (el.getAttribute('data-type') || '')).toLowerCase();\n const editorType = cls.includes('tiptap') || cls.includes('prosemirror') ? 'tiptap' :\n cls.includes('cm-') || cls.includes('codemirror') ? 'codemirror' :\n (window as any).Quill ? 'quill' :\n typeof (window as any).monaco !== 'undefined' ? 'monaco' : 'contenteditable';\n attrs.editorType = editorType;\n }\n\n const notes = Object.keys(attrs).length > 0 ? JSON.stringify(attrs) : undefined;\n const boundingRect = {\n x: Math.round(rect.x), y: Math.round(rect.y),\n width: Math.round(rect.width), height: Math.round(rect.height),\n top: Math.round(rect.top), left: Math.round(rect.left),\n right: Math.round(rect.right), bottom: Math.round(rect.bottom),\n };\n out.push({\n meaning: label, role, expectedData, notes,\n boundingRect,\n ariaState: Object.keys(stateMap).length > 0 ? stateMap : undefined,\n parentLandmark: parentLandmark ?? undefined,\n });\n });\n\n // Form fields first, then buttons\n const priority = (e: typeof out[0]) =>\n ['email', 'password', 'text', 'tel', 'date', 'number', 'select', 'textarea', 'url', 'file'].includes(e.role) ? 0 : 1;\n out.sort((a, b) => priority(a) - priority(b));\n return out; // Cap removed\n }\n // CDP Runtime.evaluate bypasses Playwright's isolated world entirely.\n // The \"__name is not defined\" error comes from Playwright's own UtilityScript being absent\n // from the isolated world (destroyed by navigation events in Stagehand's CDP session).\n // Solution: when rawPage (a real Playwright Page) is available, use CDP Runtime.evaluate\n // as the PRIMARY path \u2014 no isolated world needed, no __name dependency.\n //\n // esbuild injects __name() calls for named arrow-function constants inside _browserEval\n // (e.g. querySelectorAllDeep). When _browserEval.toString() is sent to the browser,\n // the browser throws \"ReferenceError: __name is not defined\". Fix: prepend a tiny\n // __name polyfill that just returns the function (name-setting is non-critical).\n const _browserEvalStr = `(function(){const __name=(fn,n)=>{try{Object.defineProperty(fn,'name',{value:n,configurable:true})}catch(e){}return fn};return(${_browserEval.toString()})()})();`;\n\n if (rawPage && typeof rawPage.context === 'function') {\n try {\n const ctx = rawPage.context();\n if (typeof ctx?.newCDPSession === 'function') {\n const cdp = await ctx.newCDPSession(rawPage);\n try {\n const evalResult = await cdp.send('Runtime.evaluate', {\n expression: _browserEvalStr,\n returnByValue: true,\n awaitPromise: false,\n });\n if (evalResult?.exceptionDetails) {\n console.warn('[crawler] domFallbackElements CDP primary error:', evalResult.exceptionDetails?.exception?.description ?? evalResult.exceptionDetails?.text);\n } else if (Array.isArray(evalResult?.result?.value)) {\n return (evalResult.result.value as any[]).map((e: any) => ({ ...e, isInteractive: true }));\n }\n } finally {\n cdp.detach().catch(() => {});\n }\n }\n } catch (cdpPrimaryErr: any) {\n console.warn('[crawler] domFallbackElements CDP primary failed, trying page.evaluate:', cdpPrimaryErr?.message ?? String(cdpPrimaryErr));\n }\n }\n\n // Fallback: pass the pre-serialized string expression so esbuild's __name() wrapper\n // for nested named functions never reaches the browser (Function.prototype.toString\n // returns the source including __name() calls for any nested named arrow constants).\n // Playwright accepts a JS expression string directly \u2014 no isolated-world __name leakage.\n const evalPage = rawPage ?? page;\n const _doEvaluate = (): Promise<any> => evalPage.evaluate(_browserEvalStr as any);\n let result: any[];\n try {\n result = await _doEvaluate();\n } catch (err1: any) {\n // Second attempt after a brief wait \u2014 isolated world may need a tick to settle\n await new Promise<void>(r => setTimeout(r, 500));\n try {\n result = await _doEvaluate();\n } catch (err2: any) {\n console.warn('[crawler] domFallbackElements page.evaluate threw (attempt 2):', err2?.message ?? String(err2));\n return [];\n }\n }\n return (result ?? []).map((e: any) => ({ ...e, isInteractive: true }));\n}\n\n/** Capture content anatomy for EVERY page \u2014 not just static ones.\n * Headings, meta tags, cards, chips, FAQ items, nav/footer structure, section text.\n * Previously fallback-only; now always runs alongside domFallbackElements so\n * the test generator sees ALL page content, not just interactive widgets. */\nasync function contentFallbackElements(page: any): Promise<Array<{ meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number> }>> {\n return page.evaluate(() => {\n const out: { meaning: string; role: string; notes?: string; boundingRect?: Record<string, number> }[] = [];\n const seen = new Set<string>();\n const captureRect = (el: Element): Record<string, number> | undefined => {\n try {\n const r = el.getBoundingClientRect();\n if (r.width === 0 && r.height === 0) return undefined;\n return { x: r.x, y: r.y, width: r.width, height: r.height, top: r.top, right: r.right, bottom: r.bottom, left: r.left };\n } catch { return undefined; }\n };\n const addUniq = (item: { meaning: string; role: string; notes?: string }, el?: Element) => {\n const key = `${item.role}:${item.meaning.toLowerCase().slice(0, 60)}`;\n if (!seen.has(key) && item.meaning.trim().length > 1) {\n seen.add(key);\n out.push(el ? { ...item, boundingRect: captureRect(el) } : item);\n }\n };\n const isVisible = (el: Element) => {\n const s = window.getComputedStyle(el);\n return s.display !== 'none' && s.visibility !== 'hidden' && s.opacity !== '0' && (el as HTMLElement).offsetParent !== null;\n };\n\n // 1. Page-level meta (title, description, og:, canonical)\n const title = document.title?.trim();\n if (title) addUniq({ meaning: title, role: 'page-title', notes: JSON.stringify({ tag: 'title' }) });\n const desc = document.querySelector('meta[name=\"description\"]')?.getAttribute('content')?.trim();\n if (desc) addUniq({ meaning: desc, role: 'meta-description', notes: JSON.stringify({ tag: 'meta[name=description]' }) });\n const ogTitle = document.querySelector('meta[property=\"og:title\"]')?.getAttribute('content')?.trim();\n if (ogTitle) addUniq({ meaning: ogTitle, role: 'og-title', notes: JSON.stringify({ tag: 'meta[property=og:title]' }) });\n const canonical = document.querySelector('link[rel=\"canonical\"]')?.getAttribute('href')?.trim();\n if (canonical) addUniq({ meaning: canonical, role: 'canonical-url', notes: JSON.stringify({ tag: 'link[rel=canonical]' }) });\n\n // 2. All headings h1\u2013h6 \u2014 full page structure\n document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach((h: any) => {\n if (!isVisible(h)) return;\n const text = h.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 100);\n if (text) addUniq({ meaning: text, role: h.tagName.toLowerCase(), notes: JSON.stringify({ level: h.tagName }) }, h);\n });\n\n // 3. FAQ / accordion \u2014 <details>/<summary>, ARIA pattern, and class-name scan\n document.querySelectorAll('details, [data-state=\"closed\"], [data-state=\"open\"]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const summary = el.tagName === 'DETAILS'\n ? el.querySelector('summary')\n : el.querySelector('[class*=\"trigger\" i], [class*=\"header\" i], [class*=\"question\" i], [class*=\"title\" i]') ?? el;\n const qText = summary?.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 120);\n if (qText && qText.length > 3) {\n addUniq({ meaning: qText, role: 'faq-question', notes: JSON.stringify({ expanded: el.hasAttribute('open') || el.getAttribute('data-state') === 'open' }) });\n }\n // Answer: for <details> it's the non-summary child; for React accordions try both child content and next sibling\n const contentEl = el.tagName === 'DETAILS'\n ? Array.from(el.children).find((c: any) => c.tagName !== 'SUMMARY')\n : (el.querySelector('[class*=\"content\" i], [class*=\"answer\" i], [class*=\"panel\" i], [class*=\"body\" i]:not(body)') ?? el.nextElementSibling);\n if (contentEl) {\n const aText = (contentEl as any).textContent?.replace(/\\s+/g, ' ').trim().slice(0, 200);\n if (aText && aText.length > 5 && aText !== qText) addUniq({ meaning: aText, role: 'faq-answer', notes: JSON.stringify({ question: qText }) });\n }\n });\n // 3b. FAQ by class-name container scan \u2014 catches sites without ARIA or data-state attributes\n document.querySelectorAll('[class*=\"faq\" i]:not(script):not(style):not(nav), [id*=\"faq\" i]:not(script):not(style)').forEach((container: any) => {\n if (!isVisible(container)) return;\n const qEls = container.querySelectorAll('[class*=\"question\" i], [class*=\"trigger\" i], summary, dt, [class*=\"heading\" i]');\n const aEls = container.querySelectorAll('[class*=\"answer\" i], [class*=\"content\" i]:not(main):not(article), [class*=\"panel\" i], dd');\n qEls.forEach((q: any) => {\n const qText = q.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 120);\n if (qText && qText.length > 3) addUniq({ meaning: qText, role: 'faq-question', notes: JSON.stringify({ source: 'class-faq' }) });\n });\n aEls.forEach((a: any) => {\n const aText = a.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 200);\n if (aText && aText.length > 5) addUniq({ meaning: aText, role: 'faq-answer', notes: JSON.stringify({ source: 'class-faq' }) });\n });\n });\n\n // 4. Card and chip content (component-library agnostic)\n document.querySelectorAll('[class*=\"card\" i]:not(nav):not(header):not(footer), [class*=\"chip\" i], [class*=\"badge\" i], [class*=\"tag\" i], [class*=\"pill\" i]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 150);\n if (text && text.length > 2 && text.length < 200) addUniq({ meaning: text, role: 'content-card' }, el);\n });\n\n // 5. Feature / service list items inside main content (capped per category)\n const mainContent = document.querySelector('main, [role=\"main\"], article') ?? document.body;\n let listItemCount = 0;\n mainContent.querySelectorAll('li').forEach((li: any) => {\n if (listItemCount >= 50) return;\n if (!isVisible(li)) return;\n const text = li.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 150);\n if (text && text.length > 3 && text.length < 200) { addUniq({ meaning: text, role: 'list-item' }, li); listItemCount++; }\n });\n\n // 6. First paragraph in each section (key descriptive copy)\n mainContent.querySelectorAll('section > p:first-of-type, article > p:first-of-type, [class*=\"section\" i] > p:first-of-type').forEach((p: any) => {\n if (!isVisible(p)) return;\n const text = p.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 250);\n if (text && text.length > 10) addUniq({ meaning: text, role: 'section-paragraph' }, p);\n });\n\n // 7. CTA section text (standalone paragraphs near buttons that aren't form fields)\n document.querySelectorAll('[class*=\"cta\" i] p, [class*=\"call-to-action\" i] p, section:not(form) > p').forEach((p: any) => {\n if (!isVisible(p)) return;\n const text = p.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 300);\n if (text && text.length > 10 && text.length < 400) addUniq({ meaning: text, role: 'cta-section' });\n });\n\n // 8. Navigation links \u2014 explicitly captured (excluded from interactive element selector)\n // Use a lighter visibility check: skip offsetParent because nav is often inside a responsive\n // container (e.g. hidden lg:grid) that may be display:none at the crawler's viewport,\n // causing offsetParent to be null even though the link exists in the page's nav structure.\n const isNavVisible = (el: Element) => {\n const s = window.getComputedStyle(el);\n return s.display !== 'none' && s.visibility !== 'hidden' && s.opacity !== '0';\n };\n const navSel = [\n 'nav a', '[role=\"navigation\"] a', 'header a', 'header nav a', 'footer nav a',\n '[aria-label*=\"navigation\" i] a', '[aria-label*=\"menu\" i] a', '[aria-label*=\"sidebar\" i] a',\n 'aside a', '[role=\"complementary\"] a',\n '[class*=\"sidebar\" i] a', '[class*=\"side-nav\" i] a', '[class*=\"sidenav\" i] a',\n '[class*=\"nav-menu\" i] a', '[class*=\"navmenu\" i] a', '[data-nav] a',\n ].join(', ');\n const navLinksFoundCount = { n: 0 };\n document.querySelectorAll(navSel).forEach((a: any) => {\n if (!isNavVisible(a)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n const href = a.href;\n if (!label || !href || /^(javascript:|#$)/i.test(href)) return;\n let landmark = 'Site Navigation';\n let el: any = a.parentElement;\n while (el) {\n const tag = el.tagName?.toLowerCase();\n const role = el.getAttribute?.('role')?.toLowerCase();\n const cl = (el.className ?? '').toLowerCase();\n if (tag === 'header' || role === 'banner') { landmark = 'Header'; break; }\n if (tag === 'footer' || role === 'contentinfo') { landmark = 'Footer'; break; }\n if (tag === 'aside' || role === 'complementary' || cl.includes('sidebar') || cl.includes('sidenav') || cl.includes('side-nav')) { landmark = 'Sidebar'; break; }\n if (tag === 'nav' || role === 'navigation') {\n const directLabel = el.getAttribute('aria-label')?.trim() ?? '';\n const labelId = el.getAttribute('aria-labelledby');\n const referencedLabel = labelId ? (document.getElementById(labelId)?.textContent?.trim() ?? '') : '';\n landmark = directLabel || referencedLabel || 'Site Navigation';\n break;\n }\n el = el.parentElement;\n }\n addUniq({ meaning: label, role: 'nav-link', notes: JSON.stringify({ href: href.slice(0, 150), landmark }) });\n navLinksFoundCount.n++;\n });\n // Grandparent-grouping fallback: detects sidebar navigation where each link is individually\n // wrapped (e.g. <div class=\"flex\"><a>link</a></div> \u00D7 many siblings). Runs ALWAYS so header\n // links don't block sidebar detection. Deduped against hrefs already in the semantic pass.\n {\n const navHrefsAlready = new Set<string>();\n for (const item of out) {\n if (item.role === 'nav-link') {\n try { const h = JSON.parse(item.notes ?? '{}').href; if (h) navHrefsAlready.add(h); } catch { /* skip */ }\n }\n }\n const gpGroups2 = new Map<Element, Array<{label: string; href: string}>>();\n document.querySelectorAll('a[href]').forEach((a: any) => {\n if (!isNavVisible(a)) return;\n const href = a.href ?? '';\n if (!href || /^(javascript:|#$|mailto:|tel:)/i.test(href) || navHrefsAlready.has(href)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n if (!label || label.length > 40) return;\n const parent = a.parentElement;\n const gp = parent?.parentElement;\n if (!parent || !gp) return;\n if (parent.querySelectorAll('a').length !== 1) return;\n const gpTag = gp.tagName.toLowerCase();\n if (['body', 'html', 'form'].includes(gpTag)) return;\n const arr = gpGroups2.get(gp) ?? [];\n arr.push({ label, href });\n gpGroups2.set(gp, arr);\n });\n for (const [, links] of gpGroups2.entries()) {\n if (links.length >= 4) {\n for (const { label, href } of links) {\n addUniq({ meaning: label, role: 'nav-link', notes: JSON.stringify({ href: href.slice(0, 150), landmark: 'Sidebar' }) });\n }\n }\n }\n }\n\n // 9. Breadcrumb items\n document.querySelectorAll('[aria-label*=\"breadcrumb\" i] a, [class*=\"breadcrumb\" i] a, nav[aria-label*=\"breadcrumb\" i] a').forEach((a: any) => {\n const label = a.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 60);\n const href = a.href;\n if (label) addUniq({ meaning: label, role: 'breadcrumb-item', notes: JSON.stringify({ href: href?.slice(0, 150) }) });\n });\n\n // 10. Footer links and contact info (capped at 25)\n // Matches semantic <footer>, ARIA contentinfo, and common div/section footer patterns\n let footerLinkCount = 0;\n const footerEls = new Set<Element>();\n document.querySelectorAll('footer, [role=\"contentinfo\"], [class*=\"footer\" i]:not(script):not(style):not(nav), [id*=\"footer\" i]:not(script):not(style)').forEach((f: any) => footerEls.add(f));\n const footerLinks: Element[] = [];\n footerEls.forEach((f) => f.querySelectorAll('a').forEach((a: Element) => footerLinks.push(a)));\n // Deduplicate links that appear in multiple matched footer containers\n const seenFooterHrefs = new Set<string>();\n footerLinks.filter((a: any) => {\n const href = a.href ?? '';\n if (seenFooterHrefs.has(href)) return false;\n seenFooterHrefs.add(href);\n return true;\n }).forEach((a: any) => {\n if (footerLinkCount >= 25) return;\n if (!isVisible(a)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n const href = a.href ?? '';\n if (!label) return;\n if (/^mailto:/i.test(href)) {\n addUniq({ meaning: label || href, role: 'footer-contact', notes: JSON.stringify({ href }) }); footerLinkCount++;\n } else if (/^tel:/i.test(href)) {\n addUniq({ meaning: label || href, role: 'footer-contact', notes: JSON.stringify({ href }) }); footerLinkCount++;\n } else if (label.length > 0) {\n addUniq({ meaning: label, role: 'footer-link', notes: JSON.stringify({ href: href.slice(0, 150) }) }); footerLinkCount++;\n }\n });\n\n // 11. All image types \u2014 img tags (with or without alt), picture/source, CSS background-image, lazy-load patterns\n let imgCount = 0;\n // Lighter visibility check for images: skip only display:none or visibility:hidden.\n // Do NOT check offsetParent (fails for position:fixed heroes) or opacity (kills fade-in animations).\n const isImgVisible = (el: any) => {\n const s = window.getComputedStyle(el);\n return s.display !== 'none' && s.visibility !== 'hidden';\n };\n // 11a. <img> \u2014 both with and without alt (capped at 20)\n document.querySelectorAll('img').forEach((img: any) => {\n if (imgCount >= 20) return;\n if (!isImgVisible(img)) return;\n const alt = img.getAttribute('alt')?.trim().slice(0, 80) ?? '';\n const src = (img.getAttribute('src') || img.getAttribute('data-src') || img.getAttribute('data-lazy-src') || img.getAttribute('data-original') || '').slice(0, 120);\n // Also grab first URL from srcset (Next.js Image component uses srcset directly on <img>)\n const srcsetFirst = img.getAttribute('srcset')?.split(',')[0]?.trim().split(' ')[0]?.slice(0, 120) ?? '';\n const resolvedSrc = src || srcsetFirst;\n if (!resolvedSrc && !alt) return;\n const label = alt || resolvedSrc.split('/').pop()?.split('?')[0]?.slice(0, 60) || 'Image';\n addUniq({ meaning: label, role: alt ? 'image' : 'image-no-alt', notes: JSON.stringify({ src: resolvedSrc, alt, hasAlt: !!alt }) });\n imgCount++;\n });\n // 11b. <picture> / <source srcset> \u2014 responsive images\n document.querySelectorAll('picture source[srcset]').forEach((src: any) => {\n if (imgCount >= 25) return;\n const srcset = src.getAttribute('srcset')?.split(',')[0]?.trim().split(' ')[0]?.slice(0, 120) ?? '';\n const media = src.getAttribute('media') ?? '';\n if (srcset) { addUniq({ meaning: `Responsive image${media ? ' (' + media + ')' : ''}: ${srcset.split('/').pop()?.split('?')[0] ?? ''}`, role: 'picture-source', notes: JSON.stringify({ srcset: srcset.slice(0, 150), media }) }); imgCount++; }\n });\n // 11c. CSS background-image via inline style and computed style (capped at 15)\n let bgCount = 0;\n document.querySelectorAll('[style*=\"background-image\"], [style*=\"background:\"]').forEach((el: any) => {\n if (bgCount >= 15) return;\n if (!isImgVisible(el)) return;\n const style = el.getAttribute('style') ?? '';\n const match = style.match(/url\\(['\"]?([^'\")\\s]+)['\"]?\\)/i);\n if (match) {\n const url = match[1].slice(0, 120);\n const role = el.tagName.toLowerCase();\n const context = (el.getAttribute('aria-label') || el.getAttribute('title') || el.className.split(' ').find((c: string) => c.length > 3 && !['true','false'].includes(c)) || '').slice(0, 60);\n addUniq({ meaning: context || `BG image on <${role}>: ${url.split('/').pop()?.split('?')[0] ?? url}`, role: 'bg-image', notes: JSON.stringify({ url, element: role, context }) });\n bgCount++;\n }\n });\n // 11d. Computed background-image on key visual elements (expanded class list)\n document.querySelectorAll('[class*=\"hero\" i], [class*=\"banner\" i], [class*=\"cover\" i], [class*=\"header-bg\" i], [class*=\"card\" i]:not(nav), [class*=\"feature\" i], [class*=\"service\" i], [class*=\"about\" i], [class*=\"team\" i], section').forEach((el: any) => {\n if (bgCount >= 15) return;\n if (!isImgVisible(el)) return;\n try {\n const computed = window.getComputedStyle(el).backgroundImage;\n if (computed && computed !== 'none' && computed.includes('url(')) {\n const match = computed.match(/url\\(['\"]?([^'\")\\s]+)['\"]?\\)/i);\n if (match) {\n const url = match[1].slice(0, 120);\n const tag = el.tagName.toLowerCase();\n const cls = Array.from(el.classList as DOMTokenList).find((c: any) => typeof c === 'string' && c.length > 3 && !/^(true|false|active|visible)$/.test(c)) ?? '';\n addUniq({ meaning: `CSS bg image on .${cls || tag}: ${url.split('/').pop()?.split('?')[0] ?? url}`, role: 'bg-image', notes: JSON.stringify({ url, cssClass: cls, element: tag }) });\n bgCount++;\n }\n }\n } catch { /* getComputedStyle not always available */ }\n });\n // 11e. Lazy-load data attribute patterns (data-bg, data-background, data-lazy)\n document.querySelectorAll('[data-bg], [data-background], [data-background-image]').forEach((el: any) => {\n if (bgCount >= 15) return;\n if (!isVisible(el)) return;\n const url = (el.getAttribute('data-bg') || el.getAttribute('data-background') || el.getAttribute('data-background-image') || '').slice(0, 120);\n if (url) { addUniq({ meaning: `Lazy BG image: ${url.split('/').pop()?.split('?')[0] ?? url}`, role: 'bg-image', notes: JSON.stringify({ url, pattern: 'data-bg' }) }); bgCount++; }\n });\n\n // 12. Content links outside nav/header/footer (capped at 40)\n const navTags = new Set(['nav', 'header', 'footer']);\n let contentLinkCount = 0;\n document.querySelectorAll('a[href]').forEach((a: any) => {\n if (contentLinkCount >= 40) return;\n if (!isVisible(a)) return;\n let p = a.parentElement;\n while (p) { if (navTags.has(p.tagName?.toLowerCase())) return; p = p.parentElement; }\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 80);\n const href = a.href;\n if (label && href && !/^(#$|javascript:|mailto:|tel:)/i.test(href)) {\n const isExternal = !href.includes(location.hostname);\n addUniq({ meaning: label, role: isExternal ? 'external-link' : 'internal-link', notes: JSON.stringify({ href: href.slice(0, 120) }) });\n contentLinkCount++;\n }\n });\n\n // 13. Animated / interactive content markers\n const hasAnimation = !!document.querySelector('[class*=\"animate\"], [class*=\"motion\"], [class*=\"transition\"], [class*=\"scroll-\"], [data-aos], [data-scroll]');\n if (hasAnimation) addUniq({ meaning: 'CSS animations / scroll effects detected on page', role: 'animation-layer', notes: JSON.stringify({ detected: true }) });\n if (document.querySelector('video')) addUniq({ meaning: 'Video element present', role: 'video', notes: JSON.stringify({ count: document.querySelectorAll('video').length }) });\n if (document.querySelector('canvas')) addUniq({ meaning: 'Canvas element present', role: 'canvas' });\n\n // C-07: Section structure as named semantic units\n document.querySelectorAll('main section, article section, [role=\"main\"] section').forEach((el: any) => {\n if (!isVisible(el)) return;\n const heading = el.querySelector('h1,h2,h3,h4')?.textContent?.trim() ?? '';\n const itemCount = el.querySelectorAll('li, [class*=\"card\" i], [class*=\"chip\" i]').length;\n const paragraphs = el.querySelectorAll('p').length;\n const meaning = heading || `Section (${itemCount} items)`;\n if (meaning) addUniq({ meaning, role: 'page-section', notes: JSON.stringify({ heading, itemCount, paragraphs, id: el.id || el.getAttribute('data-section') }) });\n });\n\n // 14. Extended meta tags (og:description, og:image, twitter card)\n const ogDesc = document.querySelector('meta[property=\"og:description\"]')?.getAttribute('content')?.trim();\n if (ogDesc) addUniq({ meaning: ogDesc, role: 'og-description', notes: JSON.stringify({ tag: 'meta[property=og:description]' }) });\n const ogImage = document.querySelector('meta[property=\"og:image\"]')?.getAttribute('content')?.trim();\n if (ogImage) addUniq({ meaning: ogImage, role: 'og-image', notes: JSON.stringify({ tag: 'meta[property=og:image]', src: ogImage }) });\n const twitterTitle = document.querySelector('meta[name=\"twitter:title\"]')?.getAttribute('content')?.trim();\n if (twitterTitle) addUniq({ meaning: twitterTitle, role: 'twitter-title', notes: JSON.stringify({ tag: 'meta[name=twitter:title]' }) });\n const twitterDesc = document.querySelector('meta[name=\"twitter:description\"]')?.getAttribute('content')?.trim();\n if (twitterDesc) addUniq({ meaning: twitterDesc, role: 'twitter-description', notes: JSON.stringify({ tag: 'meta[name=twitter:description]' }) });\n const jsonFonts: string[] = [];\n document.querySelectorAll('link[rel=\"preload\"][as=\"font\"], link[href*=\"fonts.googleapis\"]').forEach((l: any) => {\n const url = l.href?.slice(0, 120);\n if (url) jsonFonts.push(url);\n });\n if (jsonFonts.length) addUniq({ meaning: `Font imports: ${jsonFonts.length} font file(s)`, role: 'font-stack', notes: JSON.stringify({ fonts: jsonFonts.slice(0, 5) }) });\n\n // 15. JSON-LD structured data \u2014 extract FAQ answers, deliverables, tech stack, metrics\n document.querySelectorAll('script[type=\"application/ld+json\"], script[class*=\"tsr\"]').forEach((s: any) => {\n try {\n const data = JSON.parse(s.textContent ?? '{}');\n const items = Array.isArray(data) ? data : [data];\n for (const item of items) {\n // FAQ answers from JSON-LD (often NOT rendered in collapsed accordions)\n const faqArr = item.mainEntity ?? item.faqs ?? item.questions ?? item.faq ?? [];\n (Array.isArray(faqArr) ? faqArr : []).forEach((f: any) => {\n const q = f.name ?? f.question ?? '';\n const a = f.acceptedAnswer?.text ?? f.answer ?? '';\n if (q) addUniq({ meaning: String(q).slice(0, 150), role: 'faq-question', notes: JSON.stringify({ source: 'json-ld' }) });\n if (a) addUniq({ meaning: String(a).slice(0, 200), role: 'faq-answer', notes: JSON.stringify({ question: String(q).slice(0, 80), source: 'json-ld' }) });\n });\n // Deliverables with descriptions\n const deliverables = item.deliverables ?? item.services ?? item.offerings ?? [];\n (Array.isArray(deliverables) ? deliverables : []).forEach((d: any) => {\n const title = d.title ?? d.name ?? '';\n const desc = d.description ?? d.desc ?? '';\n if (title) addUniq({ meaning: `${title}${desc ? ': ' + desc.slice(0, 120) : ''}`, role: 'deliverable', notes: JSON.stringify({ title, description: String(desc).slice(0, 200) }) });\n });\n // Tech stack items\n const stack = item.stack ?? item.technologies ?? item.tools ?? [];\n (Array.isArray(stack) ? stack : []).forEach((tool: any) => {\n const name = typeof tool === 'string' ? tool : (tool.name ?? '');\n if (name) addUniq({ meaning: name, role: 'tech-stack-item', notes: JSON.stringify({ source: 'json-ld' }) });\n });\n // Outcome/metric cards\n const outcomes = item.outcomes ?? item.metrics ?? item.stats ?? [];\n (Array.isArray(outcomes) ? outcomes : []).forEach((m: any) => {\n const metric = m.metric ?? m.value ?? '';\n const label = m.label ?? m.name ?? '';\n if (metric && label) addUniq({ meaning: `${metric} \u2014 ${label}`, role: 'metric-card', notes: JSON.stringify({ metric, label }) });\n });\n // Features list\n const features = item.features ?? item.capabilities ?? [];\n (Array.isArray(features) ? features : []).forEach((f: any) => {\n const name = typeof f === 'string' ? f : (f.name ?? '');\n if (name) addUniq({ meaning: name, role: 'feature-badge', notes: JSON.stringify({ source: 'json-ld' }) });\n });\n // HowTo steps (tutorials, guides, recipes)\n if (item['@type'] === 'HowTo' || item['@type'] === 'Recipe') {\n const steps = item.step ?? item.steps ?? [];\n (Array.isArray(steps) ? steps : []).forEach((step: any, idx: number) => {\n const text = step.text ?? step.description ?? (typeof step === 'string' ? step : '');\n const name = step.name ?? `Step ${idx + 1}`;\n if (text) addUniq({ meaning: `${name}: ${String(text).slice(0, 200)}`, role: 'howto-step', notes: JSON.stringify({ stepIndex: idx + 1, name }) });\n });\n }\n // BreadcrumbList \u2014 page hierarchy for navigation test generation\n if (item['@type'] === 'BreadcrumbList') {\n const crumbs = item.itemListElement ?? [];\n (Array.isArray(crumbs) ? crumbs : []).forEach((crumb: any) => {\n const name = crumb.name ?? crumb.item?.name ?? '';\n const url = crumb.item?.['@id'] ?? crumb.item ?? '';\n if (name) addUniq({ meaning: name, role: 'breadcrumb-item', notes: JSON.stringify({ position: crumb.position, url }) });\n });\n }\n // Event details (conference, webinar, workshop)\n if (item['@type'] === 'Event') {\n const name = item.name ?? '';\n const startDate = item.startDate ?? '';\n const location = item.location?.name ?? item.location?.address?.streetAddress ?? '';\n if (name) addUniq({ meaning: name, role: 'event-name', notes: JSON.stringify({ startDate, location, source: 'json-ld' }) });\n }\n // JobPosting \u2014 for job boards and career pages\n if (item['@type'] === 'JobPosting') {\n const title = item.title ?? '';\n const desc = item.description ?? '';\n const employer = item.hiringOrganization?.name ?? '';\n if (title) addUniq({ meaning: `${title}${employer ? ' at ' + employer : ''}`, role: 'job-posting', notes: JSON.stringify({ description: String(desc).slice(0, 200) }) });\n }\n // Review / AggregateRating \u2014 for product and service pages\n if (item['@type'] === 'Review') {\n const body = item.reviewBody ?? '';\n const rating = item.reviewRating?.ratingValue ?? '';\n const author = item.author?.name ?? '';\n if (body) addUniq({ meaning: String(body).slice(0, 200), role: 'review-text', notes: JSON.stringify({ rating, author }) });\n }\n }\n } catch { /* non-fatal \u2014 malformed JSON-LD */ }\n });\n\n // 16. Tab panels \u2014 capture visible and aria-labeled panels (process steps, tabbed content)\n document.querySelectorAll('[role=\"tabpanel\"], [data-state=\"active\"][id*=\"panel\"], [id*=\"panel\"][aria-labelledby]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const heading = el.querySelector('h2, h3, h4')?.textContent?.trim() ?? '';\n const desc = el.querySelector('p')?.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 200) ?? '';\n const badges = Array.from(el.querySelectorAll('[class*=\"badge\" i], [class*=\"tag\" i], [class*=\"pill\" i], [class*=\"chip\" i], [class*=\"rounded-full\" i]')).map((b: any) => b.textContent?.trim()).filter(Boolean).slice(0, 8);\n const meaning = heading || desc;\n if (meaning) addUniq({ meaning: meaning.slice(0, 150), role: 'tab-panel', notes: JSON.stringify({ heading, description: desc, badges, panelId: el.id }) });\n });\n\n // 17. FAQ accordion: aria-controls pattern \u2014 find answer panel via aria-controls attribute\n // Include both aria-expanded buttons and plain aria-controls (some FAQ components omit aria-expanded)\n document.querySelectorAll('[aria-controls]').forEach((btn: any) => {\n if (!isVisible(btn)) return;\n const panelId = btn.getAttribute('aria-controls');\n if (!panelId) return;\n const panel = document.getElementById(panelId);\n if (!panel) return;\n const qText = btn.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 120);\n // Read panel text even if hidden (accordion may be collapsed)\n const aText = panel.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 200);\n if (qText && qText.length > 3) addUniq({ meaning: qText, role: 'faq-question', notes: JSON.stringify({ panelId, expanded: btn.getAttribute('aria-expanded') }) });\n if (aText && aText.length > 5 && aText !== qText) addUniq({ meaning: aText, role: 'faq-answer', notes: JSON.stringify({ question: qText?.slice(0, 80), source: 'aria-controls' }) });\n });\n\n // 18. Tech stack / tool pills \u2014 monospace pill elements outside nav/footer\n const mainEl = document.querySelector('main, [role=\"main\"], article') ?? document.body;\n mainEl.querySelectorAll('[class*=\"mono\" i]:not(code):not(pre), [class*=\"pill\" i]:not(nav), [class*=\"chip\" i]:not(nav), [class*=\"tag\" i]:not(nav), [class*=\"badge\" i]:not(nav)').forEach((el: any) => {\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 60);\n if (text && text.length > 1 && text.length < 60 && !text.includes(' ')) {\n // Single-word or hyphenated tool name\n addUniq({ meaning: text, role: 'tech-stack-item', notes: JSON.stringify({ source: 'dom-pill' }) });\n } else if (text && text.length > 1 && text.length < 40) {\n addUniq({ meaning: text, role: 'feature-badge', notes: JSON.stringify({ source: 'dom-pill' }) });\n }\n });\n\n // 19. Related/linked service cards in main content (cards with links to other pages)\n mainEl.querySelectorAll('a[href][class*=\"card\" i], [class*=\"card\" i] a[href], [class*=\"service\" i][href], a[class*=\"service\" i]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const anchor = el.tagName === 'A' ? el : el.querySelector('a');\n if (!anchor) return;\n const href = anchor.href;\n if (!href || /^(#|javascript:|mailto:|tel:)/i.test(href)) return;\n const heading = el.querySelector('h2, h3, h4')?.textContent?.trim() ?? '';\n const desc = el.querySelector('p')?.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 120) ?? '';\n const label = anchor.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 80) ?? '';\n const meaning = heading || label || 'Linked card';\n if (meaning && meaning !== 'Linked card' || (heading && desc)) {\n addUniq({ meaning: `${heading || meaning}${desc ? ': ' + desc : ''}`.slice(0, 180), role: 'service-card', notes: JSON.stringify({ href: href.slice(0, 150), heading, description: desc }) });\n }\n });\n\n // 20. Metric/outcome cards \u2014 structured numeric data cards\n mainEl.querySelectorAll('[class*=\"metric\" i], [class*=\"outcome\" i], [class*=\"stat\" i], [class*=\"kpi\" i]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 100);\n if (text && text.length > 2 && text.length < 120) addUniq({ meaning: text, role: 'metric-card', notes: JSON.stringify({ source: 'dom-class' }) });\n });\n\n // 21. Screen-reader-only headings (sr-only) \u2014 accessibility landmarks hidden from visual view\n document.querySelectorAll('.sr-only, [class*=\"sr-only\" i], [class*=\"visually-hidden\" i]').forEach((el: any) => {\n const tag = el.tagName?.toLowerCase() ?? '';\n if (!/^h[1-6]$/.test(tag)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 100);\n if (text) addUniq({ meaning: text, role: `${tag}-sr-only`, notes: JSON.stringify({ srOnly: true, tag }) });\n });\n\n // 22. CSS custom property (design token) detection\n // Step 1: enumerate :root / html rules from all same-origin stylesheets\n try {\n const cssTokens: Record<string, string> = {};\n const rootStyle = window.getComputedStyle(document.documentElement);\n // Enumerate from stylesheets (catches ALL custom properties, not just a hardcoded list)\n try {\n for (let si = 0; si < document.styleSheets.length; si++) {\n try {\n const sheet = document.styleSheets[si];\n const rules = sheet.cssRules;\n for (let ri = 0; ri < rules.length; ri++) {\n const rule = rules[ri] as any;\n if (rule.selectorText === ':root' || rule.selectorText === 'html' || rule.selectorText === ':root, html') {\n const style = rule.style;\n for (let pi = 0; pi < style.length; pi++) {\n const prop = style[pi];\n if (prop.startsWith('--') && Object.keys(cssTokens).length < 30) {\n const val = style.getPropertyValue(prop).trim();\n if (val) cssTokens[prop] = val.slice(0, 60);\n }\n }\n }\n }\n } catch { /* cross-origin sheet, skip */ }\n }\n } catch { /* no styleSheets access */ }\n // Step 2: fall back to computed value probe with common framework naming schemes\n // Covers: plain CSS, Tailwind v4, Bootstrap, Material UI, Shadcn/ui, custom brands\n const probePrefixes = ['', '--color-', '--bs-', '--brand-', '--clr-', '--theme-', '--md-sys-color-'];\n const probeNames = ['primary', 'secondary', 'accent', 'background', 'foreground', 'surface', 'text', 'muted', 'border', 'ring', 'card', 'destructive', 'warning', 'success'];\n const probeFonts = ['--font-sans', '--font-mono', '--font-display', '--font-heading', '--font-body', '--font-family-base'];\n for (const pfx of probePrefixes) {\n for (const name of probeNames) {\n const v = `${pfx}${name}`;\n if (!cssTokens[v]) {\n const val = rootStyle.getPropertyValue(v).trim();\n if (val) cssTokens[v] = val.slice(0, 60);\n }\n }\n }\n for (const v of probeFonts) {\n if (!cssTokens[v]) {\n const val = rootStyle.getPropertyValue(v).trim();\n if (val) cssTokens[v] = val.slice(0, 60);\n }\n }\n if (Object.keys(cssTokens).length > 0) {\n const limited = Object.fromEntries(Object.entries(cssTokens).slice(0, 25));\n addUniq({ meaning: `Design tokens: ${Object.keys(limited).join(', ')}`, role: 'design-tokens', notes: JSON.stringify(limited) });\n }\n } catch { /* computed styles not available */ }\n\n // 23. Data tables \u2014 headers + row count (critical for business/admin pages)\n document.querySelectorAll('table').forEach((table: any) => {\n if (!isVisible(table)) return;\n const headers = Array.from(table.querySelectorAll('thead th, thead td, tr:first-child th')).map((th: any) => th.textContent?.trim()).filter(Boolean).slice(0, 8);\n const rowCount = table.querySelectorAll('tbody tr').length;\n if (headers.length > 0) addUniq({ meaning: `Table: ${headers.join(' \u00B7 ')}`, role: 'data-table', notes: JSON.stringify({ headers, rowCount }) });\n });\n\n // 24. Definition lists \u2014 term/description pairs (used for specs, glossaries, FAQs, metadata)\n document.querySelectorAll('dl').forEach((dl: any) => {\n if (!isVisible(dl)) return;\n const terms = Array.from(dl.querySelectorAll('dt')).map((dt: any) => dt.textContent?.trim()).filter(Boolean).slice(0, 10);\n if (terms.length > 0) addUniq({ meaning: `Definition list: ${terms.slice(0, 4).join(', ')}`, role: 'definition-list', notes: JSON.stringify({ terms: terms.slice(0, 10) }) });\n });\n\n // 25. Blockquotes / testimonials / reviews / pull quotes\n let quoteCount = 0;\n document.querySelectorAll('blockquote, [class*=\"testimonial\" i], [class*=\"review\" i]:not(script), [class*=\"quote\" i]:not([class*=\"icon\"]), [class*=\"pullquote\" i]').forEach((el: any) => {\n if (quoteCount >= 10) return;\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 200);\n const author = el.querySelector('[class*=\"author\" i], [class*=\"name\" i], cite')?.textContent?.trim().slice(0, 60) ?? '';\n if (text && text.length > 20) { addUniq({ meaning: `${text.slice(0, 160)}${author ? ' \u2014 ' + author : ''}`, role: 'testimonial', notes: JSON.stringify({ author }) }); quoteCount++; }\n });\n\n // 26. Alert / notice / notification banners (non-interactive, but key content for test assertions)\n document.querySelectorAll('[role=\"alert\"], [role=\"status\"], [role=\"banner\"]:not(header), .alert, .notice, .notification, .warning-banner, .error-banner, .success-banner, [class*=\"alert-\" i]:not(button), [class*=\"toast\" i]:not(button), [class*=\"snackbar\" i]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 150);\n if (text && text.length > 5) addUniq({ meaning: text, role: 'alert-banner', notes: JSON.stringify({ ariaRole: el.getAttribute('role') }) }, el);\n });\n\n // 27. Pricing / plan cards \u2014 structured pricing content\n let pricingCount = 0;\n document.querySelectorAll('[class*=\"pricing\" i], [class*=\"plan\" i]:not(main):not(article), [class*=\"tier\" i]:not(nav), [class*=\"package\" i]:not(script)').forEach((el: any) => {\n if (pricingCount >= 8) return;\n if (!isVisible(el)) return;\n const name = el.querySelector('h2,h3,h4,[class*=\"plan-name\" i],[class*=\"tier-name\" i]')?.textContent?.trim().slice(0, 60) ?? '';\n const price = el.querySelector('[class*=\"price\" i],[class*=\"amount\" i]')?.textContent?.trim().slice(0, 40) ?? '';\n if (name || price) { addUniq({ meaning: `${name || 'Plan'}${price ? ': ' + price : ''}`, role: 'pricing-plan', notes: JSON.stringify({ planName: name, price }) }); pricingCount++; }\n });\n\n // 28. Pagination \u2014 page navigation for multi-page content\n const paginationEl = document.querySelector('[role=\"navigation\"][aria-label*=\"paginat\" i], [class*=\"pagination\" i], [aria-label*=\"paginat\" i]');\n if (paginationEl && isVisible(paginationEl)) {\n const pages = Array.from(paginationEl.querySelectorAll('a, button')).map((p: any) => p.textContent?.trim()).filter(Boolean).slice(0, 10);\n if (pages.length > 0) addUniq({ meaning: `Pagination: ${pages.join(', ')}`, role: 'pagination', notes: JSON.stringify({ pages }) });\n }\n\n // 29. Code blocks / pre blocks \u2014 critical for developer documentation pages\n let codeCount = 0;\n document.querySelectorAll('pre code, [class*=\"code-block\" i], [class*=\"highlight\" i] pre').forEach((el: any) => {\n if (codeCount >= 5) return;\n if (!isVisible(el)) return;\n const lang = el.getAttribute('class')?.match(/language-(\\w+)/)?.[1] ?? '';\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 100);\n if (text && text.length > 10) { addUniq({ meaning: `Code example${lang ? ' (' + lang + ')' : ''}: ${text.slice(0, 80)}`, role: 'code-block', notes: JSON.stringify({ language: lang }) }); codeCount++; }\n });\n\n // 30. Dropdown / select menu items exposed via ARIA listbox/option\n let dropdownCount = 0;\n document.querySelectorAll('[role=\"listbox\"] [role=\"option\"], [role=\"option\"]:not([role=\"listbox\"] *)').forEach((el: any) => {\n if (dropdownCount >= 20) return;\n if (!isVisible(el)) return;\n const text = el.textContent?.trim().slice(0, 80);\n if (text) { addUniq({ meaning: text, role: 'dropdown-option', notes: JSON.stringify({ selected: el.getAttribute('aria-selected') }) }); dropdownCount++; }\n });\n\n // 31. Timeline / process steps (common on landing pages)\n let timelineCount = 0;\n document.querySelectorAll('[class*=\"timeline\" i] li, [class*=\"timeline\" i] [class*=\"step\" i], [class*=\"process\" i] li, [class*=\"steps\" i] li').forEach((el: any) => {\n if (timelineCount >= 10) return;\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 150);\n if (text && text.length > 5) { addUniq({ meaning: text, role: 'timeline-step', notes: JSON.stringify({ source: 'dom-class' }) }); timelineCount++; }\n });\n\n // 32. Team members / person cards \u2014 social proof and about pages\n let teamCount = 0;\n document.querySelectorAll('[class*=\"team-member\" i], [class*=\"team-card\" i], [class*=\"person-card\" i], [class*=\"bio\" i][class*=\"card\" i]').forEach((el: any) => {\n if (teamCount >= 10) return;\n if (!isVisible(el)) return;\n const name = el.querySelector('[class*=\"name\" i], h3, h4')?.textContent?.trim().slice(0, 60) ?? '';\n const role = el.querySelector('[class*=\"role\" i], [class*=\"title\" i], [class*=\"position\" i]')?.textContent?.trim().slice(0, 60) ?? '';\n if (name) { addUniq({ meaning: `${name}${role ? ' \u2014 ' + role : ''}`, role: 'team-member', notes: JSON.stringify({ name, role }) }); teamCount++; }\n });\n\n // 33. Video embeds \u2014 YouTube, Vimeo, Wistia, Loom iframes (src is readable even cross-origin)\n document.querySelectorAll('iframe').forEach((iframe: any) => {\n const src = iframe.getAttribute('src') || iframe.getAttribute('data-src') || '';\n const title = iframe.getAttribute('title') || iframe.getAttribute('aria-label') || '';\n if (!src) return;\n if (/youtube\\.com\\/embed|youtu\\.be\\/|youtube-nocookie\\.com/i.test(src)) {\n const videoId = src.match(/\\/embed\\/([^/?&]+)/)?.[1] ?? '';\n addUniq({ meaning: title || `YouTube video${videoId ? ' (ID: ' + videoId + ')' : ''}`, role: 'video-embed', notes: JSON.stringify({ platform: 'youtube', src: src.slice(0, 200), title, videoId }) });\n } else if (/vimeo\\.com\\/video\\//i.test(src)) {\n const videoId = src.match(/video\\/(\\d+)/)?.[1] ?? '';\n addUniq({ meaning: title || `Vimeo video${videoId ? ' (ID: ' + videoId + ')' : ''}`, role: 'video-embed', notes: JSON.stringify({ platform: 'vimeo', src: src.slice(0, 200), title, videoId }) });\n } else if (/wistia\\.com|loom\\.com|dailymotion\\.com|twitch\\.tv|brightcove\\.com/i.test(src)) {\n const platform = /wistia/.test(src) ? 'wistia' : /loom/.test(src) ? 'loom' : /dailymotion/.test(src) ? 'dailymotion' : /twitch/.test(src) ? 'twitch' : 'brightcove';\n addUniq({ meaning: title || `${platform} video`, role: 'video-embed', notes: JSON.stringify({ platform, src: src.slice(0, 200), title }) });\n } else if (/maps\\.google\\.com|google\\.com\\/maps\\/embed/i.test(src)) {\n const q = new URLSearchParams(src.split('?')[1] ?? '').get('q') ?? new URLSearchParams(src.split('?')[1] ?? '').get('query') ?? '';\n addUniq({ meaning: title || `Google Maps${q ? ': ' + decodeURIComponent(q).slice(0, 80) : ''}`, role: 'map-embed', notes: JSON.stringify({ provider: 'google', src: src.slice(0, 200), query: q }) });\n } else if (/openstreetmap\\.org|mapbox\\.com|here\\.com|maps\\.apple\\.com/i.test(src)) {\n const provider = /openstreetmap/.test(src) ? 'OpenStreetMap' : /mapbox/.test(src) ? 'Mapbox' : /here\\.com/.test(src) ? 'HERE Maps' : 'Apple Maps';\n addUniq({ meaning: title || `${provider} embed`, role: 'map-embed', notes: JSON.stringify({ provider, src: src.slice(0, 200), title }) });\n }\n });\n\n // 34. SVG content \u2014 only meaningful SVGs (have title/aria-label AND are large enough to be illustrations)\n document.querySelectorAll('svg').forEach((svg: any) => {\n if (!isVisible(svg)) return;\n const titleEl = svg.querySelector('title');\n const label = svg.getAttribute('aria-label')?.trim() || titleEl?.textContent?.trim() || '';\n if (!label) return;\n const rect = svg.getBoundingClientRect();\n if (rect.width < 48 && rect.height < 48) return; // Skip icon-size SVGs\n addUniq({ meaning: label.slice(0, 100), role: 'svg-image', notes: JSON.stringify({ width: Math.round(rect.width), height: Math.round(rect.height) }) });\n });\n\n // 35. Animated counters \u2014 read data-target/data-count BEFORE animation completes\n let counterCount = 0;\n document.querySelectorAll('[data-count],[data-target],[data-to],[data-countup],[class*=\"counter\" i]:not(button),[class*=\"count-up\" i],[class*=\"odometer\" i]').forEach((el: any) => {\n if (counterCount >= 15) return;\n if (!isVisible(el)) return;\n const targetVal = el.getAttribute('data-count') || el.getAttribute('data-target') || el.getAttribute('data-to') || el.getAttribute('data-countup') || '';\n const currentText = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 40) ?? '';\n const contextLabel = el.closest('[class*=\"stat\" i],[class*=\"metric\" i],[class*=\"kpi\" i],[class*=\"counter-item\" i]')?.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 80) ?? '';\n const value = targetVal || currentText;\n if (value && value !== '0') {\n addUniq({ meaning: contextLabel.slice(0, 100) || `Counter: ${value}`, role: 'animated-counter', notes: JSON.stringify({ targetValue: targetVal, displayedValue: currentText }) });\n counterCount++;\n }\n });\n\n // 36. Client / partner logos \u2014 distinguish from generic images\n let logoCount = 0;\n document.querySelectorAll('[class*=\"client\" i] img,[class*=\"partner\" i] img,[class*=\"logo-grid\" i] img,[class*=\"clients-\" i] img,[class*=\"brand-logo\" i] img,[class*=\"trust-logo\" i] img,[class*=\"sponsor\" i] img').forEach((img: any) => {\n if (logoCount >= 20) return;\n if (!isVisible(img)) return;\n const alt = img.getAttribute('alt')?.trim().slice(0, 60) ?? '';\n const src = (img.getAttribute('src') || img.getAttribute('data-src') || '').slice(0, 120);\n if (!alt && !src) return;\n addUniq({ meaning: alt || src.split('/').pop()?.split('?')[0]?.slice(0, 50) || 'Client logo', role: 'client-logo', notes: JSON.stringify({ alt, src, hasAlt: !!alt }) });\n logoCount++;\n });\n\n // 37. Awards / certifications / trust badges\n let awardCount = 0;\n document.querySelectorAll('[class*=\"award\" i],[class*=\"certif\" i]:not(script):not(link),[class*=\"accredit\" i],[class*=\"trust-badge\" i],[class*=\"recognition\" i],[class*=\"badge\" i][class*=\"award\" i]').forEach((el: any) => {\n if (awardCount >= 10) return;\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 80);\n const imgEl = el.querySelector('img');\n const label = text || imgEl?.getAttribute('alt')?.trim() || '';\n if (label && label.length > 2) { addUniq({ meaning: label, role: 'award-badge', notes: JSON.stringify({ hasImage: !!imgEl }) }); awardCount++; }\n });\n\n // 38. A/B testing detection \u2014 captures active experiments (not variant content)\n try {\n const abTools: string[] = [];\n if ((window as any).optimizely || (window as any).Optimizely) abTools.push('Optimizely');\n if ((window as any).VWO || (window as any)._vwo_code) abTools.push('VWO');\n if ((window as any).__ABTasty || (window as any).ABTasty) abTools.push('AB Tasty');\n if (document.querySelector('script[src*=\"optimize.js\"]')) abTools.push('Google Optimize');\n if ((window as any).splitbee) abTools.push('Splitbee');\n if ((window as any).__GROWTHBOOK__ || document.querySelector('script[src*=\"growthbook\"]')) abTools.push('GrowthBook');\n if ((window as any).Kameleoon) abTools.push('Kameleoon');\n if (abTools.length > 0) {\n const optExp = (window as any).optimizely?.get?.('state')?.getActiveExperimentIds?.() ?? [];\n addUniq({ meaning: `A/B testing: ${abTools.join(', ')}${optExp.length ? ' (' + optExp.length + ' active experiments)' : ''}`, role: 'ab-test-layer', notes: JSON.stringify({ tools: abTools, activeExperiments: optExp.slice(0, 10) }) });\n }\n } catch { /* best-effort */ }\n\n // 39. Geo / personalization detection\n try {\n const signals: string[] = [];\n if ((window as any).__geo || (window as any).__country || (window as any).__region) signals.push('window geo globals');\n if (document.querySelector('[data-geo],[data-country],[data-region],[data-locale]')) signals.push('data-geo DOM attributes');\n const ipScripts = Array.from(document.querySelectorAll('script[src]')).filter((s: any) => /ipinfo|maxmind|ipstack|ipgeolocation/i.test(s.getAttribute('src') ?? '')).length;\n if (ipScripts > 0) signals.push('IP geolocation script');\n if ((window as any).Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone) signals.push(`timezone: ${(window as any).Intl.DateTimeFormat().resolvedOptions().timeZone}`);\n if (signals.length > 1) {\n addUniq({ meaning: `Personalization/geo signals: ${signals.join('; ')}`, role: 'personalization-layer', notes: JSON.stringify({ signals }) });\n }\n } catch { /* best-effort */ }\n\n // 40. Hover-revealed content \u2014 read DOM text of CSS-hidden children on hover triggers\n let hoverCount = 0;\n document.querySelectorAll('[class*=\"group\"]:not(nav):not(ul):not(ol),[class*=\"hover-trigger\" i],[data-hover],[class*=\"has-dropdown\" i]').forEach((trigger: any) => {\n if (hoverCount >= 8) return;\n if (!isVisible(trigger)) return;\n const hiddenChildren = Array.from(trigger.querySelectorAll('[class*=\"group-hover\"],[class*=\"hover-content\" i],[class*=\"dropdown-menu\" i],[class*=\"submenu\" i]')).filter((c: any) => {\n try { const s = window.getComputedStyle(c); return s.display === 'none' || s.visibility === 'hidden' || parseFloat(s.opacity) < 0.1; } catch { return false; }\n });\n for (const child of hiddenChildren.slice(0, 3)) {\n const text = (child as any).textContent?.replace(/\\s+/g, ' ').trim().slice(0, 150);\n if (text && text.length > 3) {\n addUniq({ meaning: text, role: 'hover-content', notes: JSON.stringify({ triggerClass: (trigger.className?.toString() ?? '').slice(0, 60) }) });\n hoverCount++;\n }\n }\n });\n\n return out.slice(0, 400); // Per-category caps above; raised global cap to 400 for new categories\n }).then((elems: any[]) => elems.map((e: any) => ({ ...e, isInteractive: false }))).catch(() => []);\n}\n\n/**\n * Click through tabs, advance carousels, open accordions \u2014 collect links that only appear\n * inside those interactive panels. Does not navigate away from the current page.\n */\nasync function interactAndCollectLinks(page: any, origin: string): Promise<string[]> {\n const collected = new Set<string>();\n const sleep = (ms: number) => new Promise<void>(r => setTimeout(r, ms));\n\n const collectCurrentLinks = async () => {\n const links: string[] = await page.evaluate((origin: string) => {\n const out: string[] = [];\n const logout = /logout|log out|sign out|delete/i;\n document.querySelectorAll<HTMLAnchorElement>('a[href]').forEach(a => {\n if (logout.test(a.textContent ?? '')) return;\n try {\n const u = new URL(a.href);\n if (u.origin === origin) { if (u.hash && !/^#!?\\//.test(u.hash)) u.hash = ''; out.push(u.toString()); }\n } catch { /* ignore */ }\n });\n return out;\n }, origin).catch(() => []);\n links.forEach(l => collected.add(l));\n };\n\n try {\n // \u2500\u2500 Tabs: click each tab individually, collect links from revealed panel \u2500\u2500\n const tabCount: number = await page.evaluate(() =>\n document.querySelectorAll('[role=\"tab\"]').length\n ).catch(() => 0);\n\n for (let i = 0; i < Math.min(tabCount, 30); i++) {\n try {\n const clicked = await page.evaluate((idx: number) => {\n const tabs = document.querySelectorAll<HTMLElement>('[role=\"tab\"]');\n const tab = tabs[idx];\n if (!tab) return false;\n const s = window.getComputedStyle(tab);\n const r = tab.getBoundingClientRect();\n if (s.display === 'none' || r.width < 4 || r.height < 4) return false;\n tab.click();\n return true;\n }, i).catch(() => false);\n if (clicked) {\n await sleep(350);\n await collectCurrentLinks();\n }\n } catch { /* skip */ }\n }\n\n // \u2500\u2500 Carousels: advance next button up to 8 times, collect links each slide \u2500\u2500\n const carouselNextSel = [\n 'button[aria-label*=\"next\" i]', 'button[aria-label*=\"forward\" i]',\n 'button[aria-label*=\"right\" i]', '[data-direction=\"next\"]',\n '[class*=\"carousel\" i] button[class*=\"next\" i]',\n '[class*=\"slider\" i] button[class*=\"next\" i]',\n ].join(', ');\n\n for (let i = 0; i < 8; i++) {\n const advanced: boolean = await page.evaluate((sel: string) => {\n const btn = document.querySelector<HTMLElement>(sel);\n if (!btn) return false;\n const s = window.getComputedStyle(btn);\n const r = btn.getBoundingClientRect();\n if (s.display === 'none' || r.width < 4 || r.height < 4) return false;\n btn.click();\n return true;\n }, carouselNextSel).catch(() => false);\n if (!advanced) break;\n await sleep(300);\n await collectCurrentLinks();\n }\n\n // \u2500\u2500 Accordions / disclosure panels: open collapsed sections \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const accordionCount: number = await page.evaluate(() =>\n document.querySelectorAll('details:not([open]) > summary, [data-state=\"closed\"] > button, [aria-expanded=\"false\"][class*=\"accordion\" i]').length\n ).catch(() => 0);\n\n for (let i = 0; i < Math.min(accordionCount, 20); i++) {\n try {\n await page.evaluate((idx: number) => {\n const items = document.querySelectorAll<HTMLElement>(\n 'details:not([open]) > summary, [data-state=\"closed\"] > button, [aria-expanded=\"false\"][class*=\"accordion\" i]'\n );\n const el = items[idx];\n if (el) { try { el.click(); } catch { /* ignore */ } }\n }, i).catch(() => { });\n await sleep(250);\n await collectCurrentLinks();\n } catch { /* skip */ }\n }\n } catch { /* best-effort */ }\n\n return Array.from(collected);\n}\n\n/** Click collapsed nav triggers (hamburger menus, aria-haspopup buttons, Radix/Headless UI toggles)\n * to reveal routes that only exist in the DOM after user interaction.\n * Returns true if anything was clicked so caller can dismiss afterward. */\nasync function expandNavMenus(page: any): Promise<boolean> {\n try {\n const clicked = await page.evaluate(() => {\n const isVisible = (el: HTMLElement) => {\n const s = window.getComputedStyle(el);\n if (s.display === 'none' || s.visibility === 'hidden' || parseFloat(s.opacity) < 0.1) return false;\n const r = el.getBoundingClientRect();\n return r.width > 4 && r.height > 4;\n };\n const inBadContext = (el: HTMLElement) => {\n let p = el.parentElement;\n while (p) {\n const tag = p.tagName?.toLowerCase();\n const role = p.getAttribute('role') ?? '';\n if (['table', 'select'].includes(tag ?? '') ||\n ['dialog', 'alertdialog', 'combobox', 'listbox', 'grid', 'treegrid'].includes(role)) return true;\n p = p.parentElement;\n }\n return false;\n };\n const targets = new Set<HTMLElement>();\n // aria-haspopup: canonical menu-trigger pattern\n document.querySelectorAll<HTMLElement>('[aria-haspopup]:not([aria-expanded=\"true\"])').forEach(el => {\n if (isVisible(el) && !inBadContext(el)) targets.add(el);\n });\n // aria-expanded=false: collapsed nav sections\n document.querySelectorAll<HTMLElement>('[aria-expanded=\"false\"]').forEach(el => {\n if ((el.tagName === 'BUTTON' || el.getAttribute('role') === 'button') && isVisible(el) && !inBadContext(el)) targets.add(el);\n });\n // Radix UI / Headless UI closed triggers\n document.querySelectorAll<HTMLElement>('[data-state=\"closed\"],[data-headlessui-state=\"closed\"]').forEach(el => {\n if ((el.tagName === 'BUTTON' || el.getAttribute('role') === 'button') && isVisible(el) && !inBadContext(el)) targets.add(el);\n });\n let count = 0;\n targets.forEach(el => { try { (el as HTMLElement).click(); count++; } catch { /* ignore */ } });\n return count;\n });\n if (clicked > 0) await new Promise(r => setTimeout(r, 500));\n\n // \u2500\u2500 Hover sweep: reveal CSS :hover dropdown menus \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Pure CSS hover menus need real mouse moves \u2014 JS click alone won't trigger :hover\n try {\n const navHandles = await page.$$(\n 'nav > ul > li, nav > li, header > ul > li, header > nav > ul > li, ' +\n '[role=\"navigation\"] > ul > li, [role=\"menubar\"] > [role=\"menuitem\"], ' +\n '[class*=\"nav\"] > ul > li, [class*=\"menu\"] > li'\n ).catch(() => [] as any[]);\n for (const h of (navHandles as any[]).slice(0, 40)) {\n try { await h.hover({ force: true, timeout: 600 }); await page.waitForTimeout(280); } catch { /* skip invisible */ }\n }\n if ((navHandles as any[]).length > 0) {\n await page.mouse.move(2, 2); // dismiss hover state\n await page.waitForTimeout(150);\n }\n } catch { /* non-fatal */ }\n\n return (clicked as number) > 0;\n } catch { return false; }\n}\n\nasync function domFallbackLinks(page: any, origin: string, rawPage?: any): Promise<DiscoveredLinkMeta[]> {\n // Named function so .toString() gives the raw function body for CDP evaluation.\n // esbuild wraps nested named arrow-function constants with __name() \u2014 prepend a\n // tiny polyfill so the browser has it when we serialize this function as a string.\n // IMPORTANT: _linkEval is serialized to a string via .toString() and evaluated in the\n // browser via CDP. It CANNOT contain TypeScript types or Node.js imports.\n function _linkEval(originStr: string) {\n const logout = /logout|log out|sign out|delete/i;\n const isRouteHash = (hash: string) => /^#!?\\//.test(hash);\n const seen = new Map();\n const add = (rawHref: string, textContent: string) => {\n if (logout.test(textContent)) return;\n if (!rawHref) return;\n if (rawHref.startsWith('#') && !isRouteHash(rawHref)) return;\n if (rawHref.startsWith('mailto:') || rawHref.startsWith('javascript:')) return;\n try {\n const u = new URL(rawHref, location.href);\n if (!isRouteHash(u.hash)) u.hash = '';\n if (new URL(u).origin === originStr) seen.set(u.toString(), (textContent || '').trim().slice(0, 120));\n } catch { /* ignore */ }\n };\n const allRoots: Array<Document | ShadowRoot> = [document];\n const rootSeen = new WeakSet<Document | ShadowRoot>();\n rootSeen.add(document);\n while (allRoots.length > 0) {\n const root = allRoots.shift();\n if (!root) continue;\n try {\n root.querySelectorAll('a[href]').forEach((a) => add((a as HTMLAnchorElement).href || a.getAttribute('href') || '', a.textContent || ''));\n root.querySelectorAll('[href]:not(a):not(link):not(base):not(script)').forEach((el) => {\n add(el.getAttribute('href') || '', el.textContent || '');\n });\n root.querySelectorAll('[data-href]').forEach((el) => {\n add(el.getAttribute('data-href') || '', el.textContent || '');\n });\n // Form[action] GET forms: JSP/MVC apps navigate via form submissions (not anchor links)\n root.querySelectorAll('form[action]').forEach((form) => {\n const method = (form.getAttribute('method') || 'get').toLowerCase();\n if (method !== 'post') add(form.getAttribute('action') || '', form.getAttribute('aria-label') || '');\n });\n root.querySelectorAll('*').forEach((el) => {\n try {\n if (el.shadowRoot && !rootSeen.has(el.shadowRoot)) {\n rootSeen.add(el.shadowRoot);\n allRoots.push(el.shadowRoot);\n }\n } catch (_) { /* closed/cross-origin shadow root */ }\n });\n } catch (_) { /* element threw \u2014 skip root */ }\n }\n return Array.from(seen.entries()).map(([url, text]) => ({ url, text }));\n }\n\n function inferLandmark(url: string): string | undefined {\n const p = url.toLowerCase();\n if (p.includes('/auth') || p.includes('/login') || p.includes('/register')) return 'nav';\n return undefined;\n }\n\n function toMeta(raw: Array<{ url: string; text: string }>): DiscoveredLinkMeta[] {\n return raw.map(({ url, text }) => ({\n url,\n text: text || undefined,\n landmark: inferLandmark(url),\n source: 'DOM' as const,\n }));\n }\n\n const _linkEvalStr = `(function(){const __name=(fn,n)=>{try{Object.defineProperty(fn,'name',{value:n,configurable:true})}catch(e){}return fn};return(${_linkEval.toString()})(${JSON.stringify(origin)})})();`;\n\n // CDP primary \u2014 bypasses Stagehand isolated world entirely\n if (rawPage && typeof rawPage.context === 'function') {\n try {\n const ctx = rawPage.context();\n if (typeof ctx?.newCDPSession === 'function') {\n const cdp = await ctx.newCDPSession(rawPage);\n try {\n const evalResult = await cdp.send('Runtime.evaluate', {\n expression: _linkEvalStr,\n returnByValue: true,\n awaitPromise: false,\n });\n if (!evalResult?.exceptionDetails && Array.isArray(evalResult?.result?.value)) {\n return toMeta(evalResult.result.value as Array<{ url: string; text: string }>);\n }\n if (evalResult?.exceptionDetails) {\n console.warn('[crawler] domFallbackLinks CDP error:', evalResult.exceptionDetails?.exception?.description ?? evalResult.exceptionDetails?.text);\n }\n } finally {\n cdp.detach().catch(() => {});\n }\n }\n } catch (cdpErr: any) {\n console.warn('[crawler] domFallbackLinks CDP failed:', cdpErr?.message ?? String(cdpErr));\n }\n }\n\n // Fallback: pass string expression so esbuild __name wrapper never reaches browser\n const evalPage = rawPage ?? page;\n return (evalPage.evaluate(_linkEvalStr as any) as Promise<Array<{ url: string; text: string }>>).then(toMeta).catch((err: any) => {\n console.warn('[crawler] domFallbackLinks page.evaluate threw:', err?.message ?? String(err));\n return [];\n });\n}\n\n/** Extract label\u2192href pairs for all in-app anchor links \u2014 used to seed KAG element transitions. */\nasync function extractLinkMappings(page: any, origin: string): Promise<Array<{ label: string; href: string }>> {\n return page.evaluate((origin: string) => {\n const logout = /logout|log out|sign out|delete/i;\n return Array.from(document.querySelectorAll('a[href]'))\n .filter((a: any) => !logout.test(a.textContent ?? ''))\n .map((a: any) => {\n const label = (\n a.getAttribute('aria-label') ||\n a.textContent?.replace(/\\s+/g, ' ').trim() ||\n a.getAttribute('title') ||\n ''\n ).slice(0, 80);\n const href = (() => { try { const u = new URL(a.href); if (!/^#!?\\//.test(u.hash)) u.hash = ''; return u.toString(); } catch { return ''; } })();\n return { label, href };\n })\n .filter(({ label, href }: { label: string; href: string }) =>\n label.length > 2 && href.length > 0 &&\n (() => { try { return new URL(href).origin === origin; } catch { return false; } })()\n );\n }, origin).catch(() => []);\n}\n\n/** \n * Computes a structural hash of the DOM to detect repeating screens/components.\n * Strips out text and focuses only on the sequence of semantic/form tags.\n */\nasync function computeDomHash(page: any): Promise<string> {\n return page.evaluate(() => {\n let hashStr = '';\n const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);\n let node;\n while ((node = walker.nextNode())) {\n const el = node as HTMLElement;\n // Only include structural/semantic tags that matter for UI layouts\n if (/^(MAIN|SECTION|NAV|FORM|INPUT|SELECT|TEXTAREA|BUTTON|TABLE|TR|TD|TH|UL|LI|A|H1|H2|H3)$/.test(el.tagName)) {\n // Count structural nesting depth \u2014 distinguishes modal dialogs (deeply nested)\n // from top-level nav/forms (shallow), preventing false duplicate matches.\n let depth = 0;\n let parent = el.parentElement;\n while (parent) {\n if (/^(MAIN|SECTION|NAV|FORM|INPUT|SELECT|TEXTAREA|BUTTON|TABLE|TR|TD|TH|UL|LI|A|H1|H2|H3)$/.test(parent.tagName)) depth++;\n parent = parent.parentElement;\n }\n hashStr += el.tagName + depth + '|';\n }\n }\n // Very simple hashing function (djb2 style)\n let hash = 5381;\n for (let i = 0; i < hashStr.length; i++) {\n hash = (hash * 33) ^ hashStr.charCodeAt(i);\n }\n return (hash >>> 0).toString(16);\n }).catch(() => '');\n}\n\nasync function waitForURLChange(page: any, fromUrl: string, timeout = 10_000): Promise<void> {\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const current = page.url();\n try {\n const from = new URL(fromUrl);\n const now = new URL(current);\n if (now.pathname !== from.pathname || now.origin !== from.origin) return;\n } catch {\n if (current !== fromUrl) return;\n }\n await new Promise(r => setTimeout(r, 200));\n }\n // Timed out \u2014 proceed with current URL (may still be login page)\n}\n\n/**\n * Dismiss common overlay patterns (cookie banners, GDPR consent, chat widgets, newsletter modals)\n * before element extraction \u2014 prevents banner elements from polluting the element model.\n */\nasync function dismissOverlays(page: any): Promise<void> {\n const selectors = [\n // OneTrust / CookieBot / TrustArc (most common GDPR banners)\n '#onetrust-accept-btn-handler',\n '#accept-cookie-consent',\n '.cc-btn.cc-allow',\n '[data-cookiebanner] button',\n '[id*=\"cookie-accept\"]',\n '[class*=\"cookie-accept\"]',\n '[id*=\"cookieAccept\"]',\n '[class*=\"cookieAccept\"]',\n 'button[aria-label*=\"Accept cookies\" i]',\n 'button[aria-label*=\"Accept all\" i]',\n 'button[title*=\"Accept\" i][class*=\"cookie\" i]',\n // Intercom / Drift / HubSpot chat\n '[class*=\"intercom-close\"]',\n '#hubspot-messages-iframe-container [aria-label*=\"close\" i]',\n // Generic overlay close buttons\n '[role=\"dialog\"] button[aria-label=\"Close\" i]',\n '[role=\"dialog\"] button[aria-label=\"Dismiss\" i]',\n // Newsletter popups\n 'button[class*=\"modal-close\"]',\n 'button[class*=\"popup-close\"]',\n '[class*=\"newsletter\"] button[class*=\"close\"]',\n ];\n for (const sel of selectors) {\n try {\n const el = page.locator(sel).first();\n if (await el.isVisible({ timeout: 300 }).catch(() => false)) {\n await el.click({ timeout: 500, force: true }).catch(() => { });\n }\n } catch { /* overlay not present \u2014 skip */ }\n }\n // Brief settle after dismissals \u2014 Node.js timer, no dependency on page.waitForTimeout proxy\n await new Promise<void>(r => setTimeout(r, 300));\n}\n\n/**\n * Scroll the full page height to trigger IntersectionObserver-based lazy loads\n * (images, components, infinite-scroll content). Scrolls back to top before capture.\n */\nasync function scrollToTriggerLazyLoad(page: any, rawPage?: any): Promise<void> {\n const evalPage = rawPage ?? page;\n try {\n // Scroll the full page in viewport-sized steps.\n // window.scrollTo handles standard scroll containers and triggers IntersectionObserver.\n const { scrollHeight, innerHeight, innerWidth } = await evalPage.evaluate(() => ({\n scrollHeight: Math.min(document.body.scrollHeight, 12_000),\n innerHeight: window.innerHeight || 800,\n innerWidth: window.innerWidth || 1280,\n })).catch(() => ({ scrollHeight: 0, innerHeight: 800, innerWidth: 1280 }));\n\n if (scrollHeight > innerHeight) {\n // CDP wheel events trigger virtual scrollers (react-window / TanStack Virtual / AG Grid)\n // which ignore window.scrollTo but listen on their own container via wheel events.\n let cdp: any = null;\n if (rawPage && typeof rawPage.context === 'function') {\n try {\n const ctx = rawPage.context();\n if (typeof ctx?.newCDPSession === 'function') cdp = await ctx.newCDPSession(rawPage);\n } catch { cdp = null; }\n }\n\n const step = Math.max(innerHeight, 400);\n for (let y = step; y < scrollHeight; y += step) {\n await evalPage.evaluate((pos: number) => window.scrollTo(0, pos), y).catch(() => {});\n if (cdp) {\n await cdp.send('Input.dispatchMouseEvent', {\n type: 'mouseWheel',\n x: Math.floor(innerWidth / 2),\n y: Math.floor(innerHeight / 2),\n deltaX: 0,\n deltaY: step,\n modifiers: 0,\n }).catch(() => {});\n }\n // Node.js-side wait \u2014 does NOT depend on page.waitForTimeout (Stagehand proxy may lack it)\n await new Promise<void>(r => setTimeout(r, 150));\n }\n // Scroll back to top\n await evalPage.evaluate(() => window.scrollTo(0, 0)).catch(() => {});\n if (cdp) cdp.detach().catch(() => {});\n }\n\n // Let lazy-triggered content render before extraction\n await new Promise<void>(r => setTimeout(r, 400));\n // Wait for networkidle: IntersectionObserver fires on scroll but async data fetches\n // (React Query, SWR, Apollo) triggered by it may still be in-flight. networkidle ensures\n // all XHR/fetch requests spawned by the scroll complete before DOM stability check.\n const scrollWaitPage = rawPage ?? page;\n if (typeof scrollWaitPage.waitForLoadState === 'function') {\n await scrollWaitPage.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => {});\n }\n // Re-check DOM stability (shadow-piercing) after scroll-triggered mutations + data fetches\n await waitForStableDOM(page, 4_000, 500, rawPage);\n } catch { /* scroll failed \u2014 non-fatal, proceed */ }\n}\n\nasync function waitForStableDOM(page: any, maxWait = 8_000, stabilityMs = 400, rawPage?: any): Promise<void> {\n const evalPage = rawPage ?? page; // prefer rawPage \u2014 avoids Stagehand proxy + __name isolated-world issues\n const deadline = Date.now() + maxWait;\n let lastCount = -1;\n let stableAt = 0;\n let evalErrors = 0;\n while (Date.now() < deadline) {\n const count: number = await evalPage.evaluate(() => {\n // Shadow-piercing counter: querySelectorAll('*') only counts light-DOM elements;\n // shadow roots are separate trees. Counting both ensures changes inside web components\n // (e.g. Material UI, Lit, Shoelace) reset the stability timer correctly.\n let c = 0;\n const visit = (root: Document | ShadowRoot) => {\n const els = root.querySelectorAll('*');\n c += els.length;\n els.forEach((el: any) => { if (el.shadowRoot) visit(el.shadowRoot); });\n };\n visit(document);\n return c;\n }).catch(() => -1);\n if (count === -1) {\n // evaluate failed (isolated world broken) \u2014 after 3 consecutive failures, wait stabilityMs and bail\n if (++evalErrors >= 3) {\n await new Promise(r => setTimeout(r, stabilityMs));\n return;\n }\n } else {\n evalErrors = 0;\n if (count !== lastCount) {\n lastCount = count;\n stableAt = Date.now();\n } else if (Date.now() - stableAt >= stabilityMs) {\n return;\n }\n }\n await new Promise(r => setTimeout(r, 100));\n }\n // Timed out \u2014 DOM may still be loading, proceed anyway\n}\n\nasync function waitForScreenshotReady(page: any, rawPage?: any): Promise<void> {\n const hardDeadline = Date.now() + 30_000;\n const withHardCap = <T>(p: Promise<T>): Promise<T | void> =>\n Promise.race([p, new Promise<void>((resolve) => setTimeout(resolve, Math.max(0, hardDeadline - Date.now())))]);\n // Use rawPage for load-state waits \u2014 Stagehand proxy may not expose waitForLoadState\n const waitPage = rawPage ?? page;\n const evalPage = rawPage ?? page;\n try {\n await withHardCap(waitPage.waitForLoadState('domcontentloaded', { timeout: 5_000 }).catch(() => { }));\n await withHardCap(waitPage.waitForLoadState('networkidle', { timeout: 12_000 }).catch(() => { }));\n await withHardCap(evalPage.evaluate(() => {\n if (document.readyState === 'complete') return true;\n return new Promise<boolean>((resolve) => {\n const done = () => resolve(true);\n window.addEventListener('load', done, { once: true });\n setTimeout(done, 4_000);\n });\n }).catch(() => { }));\n await withHardCap(evalPage.evaluate(async () => {\n const fonts = (document as any).fonts;\n if (fonts?.ready) await fonts.ready;\n }).catch(() => { }));\n await withHardCap(scrollToTriggerLazyLoad(rawPage ?? page, rawPage));\n await withHardCap(waitForStableDOM(page, 4_000, 700, rawPage));\n await withHardCap(evalPage.evaluate(async () => {\n const pending = Array.from(document.images).filter((img) => !img.complete);\n if (pending.length === 0) return;\n await Promise.race([\n Promise.all(pending.map((img) => new Promise<void>((resolve) => {\n img.addEventListener('load', () => resolve(), { once: true });\n img.addEventListener('error', () => resolve(), { once: true });\n }))),\n new Promise<void>((resolve) => setTimeout(resolve, 4_000)),\n ]);\n }).catch(() => { }));\n await withHardCap(waitForStableDOM(page, 2_000, 500, rawPage));\n } catch { /* readiness is best-effort; never fail the crawl for a continuously mutating page */ }\n}\n\nasync function hasMeaningfulAuthOrPublicState(page: any, requestedUrl: string): Promise<boolean> {\n const pathLooksRelevant = (() => {\n try {\n const pathname = new URL(page.url?.() ?? requestedUrl).pathname;\n return AUTH_PATH_RE.test(pathname) || PUBLIC_PATH_RE.test(pathname);\n } catch {\n return false;\n }\n })();\n\n const domState = await page.evaluate(() => {\n const text = (document.body?.innerText ?? '').toLowerCase();\n const inputs = Array.from(document.querySelectorAll('input')) as HTMLInputElement[];\n const hasPassword = inputs.some((i) => i.type === 'password');\n const hasIdentityInput = inputs.some((i) => {\n const meta = `${i.type} ${i.name} ${i.id} ${i.placeholder} ${i.autocomplete}`.toLowerCase();\n return /(email|username|user|login|phone|otp|code|password)/.test(meta);\n });\n const hasAuthCopy = /(sign in|log in|login|sign up|create account|register|forgot password|reset password|verify email|one-time|otp|continue with email)/i.test(text);\n const hasPublicNav = /(pricing|contact|features|documentation|docs|about|privacy|terms)/i.test(text);\n // Soft-404: page says \"not found\" / \"404\" with no real auth form\n const isSoft404 = !hasPassword && !hasIdentityInput &&\n /(page not found|404|this page (could not|doesn'?t) (be found|exist)|we couldn'?t find|no longer exists|been moved|doesn'?t exist)/i.test(text);\n return { hasPassword, hasIdentityInput, hasAuthCopy, hasPublicNav, isSoft404 };\n }).catch(() => ({ hasPassword: false, hasIdentityInput: false, hasAuthCopy: false, hasPublicNav: false, isSoft404: false }));\n\n // Soft-404 with no auth form \u2014 path match alone is not enough\n if (domState.isSoft404) return false;\n\n const domLooksRelevant = domState.hasPassword || domState.hasIdentityInput || domState.hasAuthCopy || domState.hasPublicNav;\n return pathLooksRelevant || domLooksRelevant;\n}\n\nasync function discoverAuthCandidates(page: any, origin: string): Promise<{\n links: Array<{ href: string; label: string; flowType: AuthFlowType }>;\n clicks: Array<{ selector: string; label: string; flowType: AuthFlowType }>;\n}> {\n return page.evaluate((siteOrigin: string) => {\n type BrowserFlowType = 'public' | 'login' | 'register' | 'password_reset' | 'verification' | 'invite' | 'session_recovery';\n const authTextRe = /(sign\\s*in|log\\s*in|login|sign\\s*up|signup|register|create account|forgot password|reset password|use email|continue with email|back to login|verify|invite|get started|start free trial)/i;\n const skipTextRe = /(logout|log out|sign out|delete|remove|discard|cancel subscription|payment|billing)/i;\n const authPathRe = /\\/(login|log-in|signin|sign-in|auth|oauth|sso|account\\/login|user\\/login|app\\/login|register|signup|sign-up|create-account|forgot|reset|password|verify-email|invite)(\\/|$|\\?)/i;\n const publicPathRe = /\\/($|pricing|contact|about|help|docs|features|security|privacy|terms)(\\/|$|\\?)/i;\n const sameSiteBrowser = (href: string) => {\n try {\n const u = new URL(href, location.href);\n const s = new URL(siteOrigin);\n const strip = (h: string) => h.replace(/^www\\./i, '');\n return strip(u.hostname) === strip(s.hostname);\n } catch {\n return false;\n }\n };\n const flowTypeFor = (value: string): BrowserFlowType => {\n const v = value.toLowerCase();\n if (/(forgot|reset|password)/.test(v)) return 'password_reset';\n if (/(register|signup|sign up|create account|join)/.test(v)) return 'register';\n if (/(verify|verification|otp|mfa|2fa|invite)/.test(v)) return v.includes('invite') ? 'invite' : 'verification';\n if (/(session-expired|expired|unauthorized|forbidden|401|403|logout|logged-out)/.test(v)) return 'session_recovery';\n if (/(login|log in|signin|sign in|auth|sso|oauth)/.test(v)) return 'login';\n return 'public';\n };\n const textOf = (el: Element) => (\n el.textContent ||\n el.getAttribute('aria-label') ||\n el.getAttribute('title') ||\n el.getAttribute('placeholder') ||\n ''\n ).replace(/\\s+/g, ' ').trim();\n const isVisible = (el: Element) => {\n const rect = (el as HTMLElement).getBoundingClientRect?.();\n const style = window.getComputedStyle(el as HTMLElement);\n return !!rect && rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';\n };\n const links = new Map<string, { href: string; label: string; flowType: BrowserFlowType }>();\n const addHref = (hrefRaw: string | null, labelRaw: string) => {\n if (!hrefRaw || /^(javascript|mailto|tel):/i.test(hrefRaw)) return;\n let href = '';\n try { href = new URL(hrefRaw, location.href).toString(); } catch { return; }\n if (!sameSiteBrowser(href)) return;\n const u = new URL(href);\n const label = labelRaw || u.pathname;\n if (skipTextRe.test(label) || skipTextRe.test(u.pathname)) return;\n if (!authTextRe.test(label) && !authPathRe.test(u.pathname) && !publicPathRe.test(u.pathname)) return;\n const key = `${u.origin}${u.pathname.replace(/\\/$/, '') || '/'}${u.search}`;\n if (!links.has(key)) links.set(key, { href, label, flowType: flowTypeFor(`${label} ${u.pathname}`) });\n };\n\n const walk = (root: Document | ShadowRoot) => {\n root.querySelectorAll('a[href]').forEach((el) => addHref((el as HTMLAnchorElement).href || el.getAttribute('href'), textOf(el)));\n root.querySelectorAll('[data-href],[data-url],[data-link]').forEach((el: any) => addHref(el.dataset?.href || el.dataset?.url || el.dataset?.link || '', textOf(el)));\n root.querySelectorAll('*').forEach((el: any) => { if (el.shadowRoot) walk(el.shadowRoot); });\n };\n walk(document);\n\n const clicks: Array<{ selector: string; label: string; flowType: BrowserFlowType }> = [];\n const clickEls = Array.from(document.querySelectorAll('button,[role=\"button\"],a:not([href]),[data-state],[aria-haspopup]')) as HTMLElement[];\n let idx = 0;\n for (const el of clickEls) {\n if (clicks.length >= 12) break;\n if (!isVisible(el)) continue;\n const label = textOf(el);\n if (!label || !authTextRe.test(label) || skipTextRe.test(label)) continue;\n const type = (el.getAttribute('type') || '').toLowerCase();\n const inCredentialForm = !!el.closest('form')?.querySelector('input[type=\"password\"],input[type=\"email\"],input[name*=\"user\" i],input[name*=\"email\" i]');\n const submitLike = type === 'submit' || /^(login|log in|sign in|continue)$/i.test(label);\n // Avoid submitting empty login forms. Links/buttons that change auth state, such as\n // \"Forgot password\" or \"Create account\", are safe to click even inside the form.\n if (inCredentialForm && submitLike && !/(forgot|reset|register|sign up|create account|back to login|use email)/i.test(label)) continue;\n const attr = `zeta-auth-${idx++}`;\n el.setAttribute('data-zeta-auth-discovery-id', attr);\n clicks.push({ selector: `[data-zeta-auth-discovery-id=\"${attr}\"]`, label, flowType: flowTypeFor(label) });\n }\n\n return { links: Array.from(links.values()).slice(0, 32), clicks };\n }, origin).catch(() => ({ links: [], clicks: [] }));\n}\n\nasync function captureAuthDiscoveryScreen(\n page: any,\n opts: AuthDiscoveryOptions,\n requestedUrl: string,\n source: AuthDiscoverySource,\n ordinal: number,\n trigger?: { label?: string; flowType?: AuthFlowType; sameUrlState?: boolean },\n): Promise<{ captured: boolean; finalUrl: string; flowType: AuthFlowType }> {\n const finalUrl = page.url?.() ?? requestedUrl;\n if (finalUrl.startsWith('chrome-error://')) return { captured: false, finalUrl, flowType: 'public' };\n if (!(await hasMeaningfulAuthOrPublicState(page, requestedUrl))) {\n return { captured: false, finalUrl, flowType: flowTypeForUrlOrText(`${requestedUrl} ${finalUrl} ${trigger?.label ?? ''}`) };\n }\n\n const flowType = trigger?.flowType ?? flowTypeForUrlOrText(`${requestedUrl} ${finalUrl} ${trigger?.label ?? ''}`);\n const title = await page.title().catch(() => '');\n const baseName = title?.trim() && !/^(untitled|about:blank)$/i.test(title.trim())\n ? title.trim().slice(0, 72)\n : titleFromUrl(finalUrl);\n const prefix = flowType === 'public' ? 'Public' : `Auth ${flowType.replace('_', ' ')}`;\n const name = `${prefix} \u00B7 ${trigger?.label ? trigger.label.slice(0, 48) : baseName}`.replace(/\\s+/g, ' ');\n const screenUrl = trigger?.sameUrlState\n ? `${finalUrl.split('#')[0]}#zeta-auth-flow=${compactSlug(trigger.label ?? `${flowType}-${ordinal}`)}`\n : finalUrl;\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `auth-discovery-${opts.jobId ?? 'run'}-${ordinal}.png`);\n\n await waitForScreenshotReady(page);\n await page.screenshot({ path: shotPath, fullPage: true }).catch(() => { });\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, name, screenUrl, opts.jobId, source === 'entry' ? 'ENTRY_POINT' : 'SEED_URL').catch(() => null);\n if (!screen) return { captured: false, finalUrl, flowType };\n let authCloudUrl: string | undefined;\n if (opts.storageConfig && existsSyncFs(shotPath)) {\n try {\n const { uploadScreenshotToTenantStorage } = await import('@detiq/app-brain');\n authCloudUrl = await uploadScreenshotToTenantStorage(opts.storageConfig as any, shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`);\n } catch { /* non-fatal */ }\n }\n if (existsSyncFs(shotPath)) {\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, screen.id, shotPath, screen.version, 'DESKTOP', authCloudUrl).catch(() => { });\n }\n // GAP 11: DOM snapshot for auth-discovery phase\n const authDomContent = await capturePageHtml(page);\n if (authDomContent && opts.screenshotDir) {\n const authDomPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(authDomPath, authDomContent, 'utf8');\n let authDomCloudUrl: string | undefined;\n if (opts.storageConfig) {\n try {\n const { uploadScreenshotToTenantStorage } = await import('@detiq/app-brain');\n authDomCloudUrl = await uploadScreenshotToTenantStorage(opts.storageConfig as any, authDomPath, `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(authDomPath)}`);\n } catch { /* non-fatal */ }\n }\n await AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, authDomPath, authDomCloudUrl).catch(() => {});\n }\n // Extract and save interactive elements (inputs, buttons, links) for this auth-discovery screen.\n // Without this, login pages and auth flows always show 0 elements in Crawl Captures.\n const authDiscoveryElements = await readScreen(page).catch(() => [] as Awaited<ReturnType<typeof readScreen>>);\n if (authDiscoveryElements.length > 0) {\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, screen.id).catch(() => {});\n for (const el of authDiscoveryElements) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.label, el.role, el.expectedData, undefined, undefined, true, undefined, undefined, undefined).catch(() => {});\n }\n logger.info({ screenId: screen.id, elements: authDiscoveryElements.length }, '[crawler] auth-discovery: saved elements');\n }\n await AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id,\n jobId: opts.jobId,\n type: 'AUTH_DISCOVERY',\n payload: {\n requestedUrl,\n finalUrl,\n screenUrl,\n authState: flowType === 'public' ? 'logged_out' : 'auth_flow',\n flowType,\n source,\n triggerLabel: trigger?.label ?? null,\n },\n }).catch(() => { });\n logger.info({ requestedUrl, finalUrl, screenUrl, flowType, source }, '[crawler] auth-discovery: captured screen');\n return { captured: true, finalUrl, flowType };\n}\n\nasync function runAuthDiscoveryPhase(\n page: any,\n opts: AuthDiscoveryOptions,\n origin: string,\n onProgress?: AuthDiscoveryProgress,\n): Promise<{ captured: number; discoveredUrls: string[] }> {\n const tuning = await getCrawlTuning();\n const queue: Array<{ url: string; source: AuthDiscoverySource }> = [];\n const queued = new Set<string>();\n const capturedKeys = new Set<string>();\n const discoveredUrls = new Set<string>();\n const enqueue = (url: string, source: AuthDiscoverySource) => {\n if (!shouldSeedAuthDiscoveryUrl(url, origin)) return;\n const key = normalizeAuthUrl(url);\n if (queued.has(key) || queue.length >= AUTH_DISCOVERY_MAX_QUEUE) return;\n queued.add(key);\n queue.push({ url, source });\n };\n\n enqueue(opts.appUrl, 'entry');\n for (const p of AUTH_DISCOVERY_PATHS) {\n try { enqueue(new URL(p, origin).toString(), 'seed_path'); } catch { /* ignore bad seed */ }\n }\n\n // Capture homepage DOM fingerprint for soft-404 detection.\n // SPA catch-all sites return 200 for every path but render identical content.\n // If a seeded path produces the same element count + title as the homepage, it's\n // a phantom route \u2014 skip it so auth paths don't pollute the discovered URL list.\n let homeTitle = '';\n let homeElemCount = -1;\n try {\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => null);\n await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => { });\n homeTitle = await page.title().catch(() => '');\n homeElemCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"]').length\n ).catch(() => -1);\n } catch { /* best-effort */ }\n\n let captured = 0;\n let ordinal = 0;\n await onProgress?.(10, 'Discovering public and auth flows');\n\n while (queue.length > 0 && captured < AUTH_DISCOVERY_MAX_SCREENS) {\n const current = queue.shift()!;\n const _authPct = 10 + Math.round((captured / AUTH_DISCOVERY_MAX_SCREENS) * 7);\n const _authPath = current.url.replace(/^https?:\\/\\/[^/]+/, '') || '/';\n await onProgress?.(_authPct, `Auth discovery \u00B7 ${_authPath} \u00B7 ${captured} found`);\n try {\n const response = await page.goto(current.url, { waitUntil: 'domcontentloaded', timeout: tuning.navTimeoutMs }).catch(() => null);\n if (response && response.status && response.status() >= 400) continue;\n await page.waitForLoadState('networkidle', { timeout: 6_000 }).catch(() => { });\n await waitForStableDOM(page);\n await acceptCookieConsent(page, { waitMs: 400 }).catch(() => { });\n\n // Soft-404 detection: SPA returns 200 for unknown paths but renders homepage.\n // Skip if title + element count match the homepage fingerprint exactly.\n if (current.source === 'seed_path' && homeElemCount >= 0) {\n const pageTitle = await page.title().catch(() => '');\n const elemCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"]').length\n ).catch(() => -1);\n if (pageTitle === homeTitle && elemCount === homeElemCount) continue;\n }\n\n const finalUrl = page.url?.() ?? current.url;\n const captureKey = normalizeAuthUrl(finalUrl);\n if (!capturedKeys.has(captureKey)) {\n const result = await captureAuthDiscoveryScreen(page, opts, current.url, current.source, ordinal++);\n if (result.captured) {\n captured++;\n capturedKeys.add(captureKey);\n discoveredUrls.add(result.finalUrl);\n }\n }\n\n const candidates = await discoverAuthCandidates(page, origin);\n for (const link of candidates.links) enqueue(link.href, 'page_link');\n\n const baseUrlForClicks = finalUrl;\n const clickLimit = Math.min(candidates.clicks.length, AUTH_DISCOVERY_MAX_CLICKS_PER_PAGE);\n for (let i = 0; i < clickLimit && captured < AUTH_DISCOVERY_MAX_SCREENS; i++) {\n await page.goto(baseUrlForClicks, { waitUntil: 'domcontentloaded', timeout: 12_000 }).catch(() => { });\n await page.waitForLoadState('networkidle', { timeout: 4_000 }).catch(() => { });\n await waitForStableDOM(page);\n const freshCandidates = await discoverAuthCandidates(page, origin);\n const click = freshCandidates.clicks[i];\n if (!click) continue;\n const beforeUrl = page.url?.() ?? baseUrlForClicks;\n await page.locator(click.selector).first().click({ timeout: 4_000 }).catch(() => { });\n await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => { });\n await waitForStableDOM(page);\n const afterUrl = page.url?.() ?? beforeUrl;\n const sameUrlState = normalizeAuthUrl(beforeUrl) === normalizeAuthUrl(afterUrl);\n const stateKey = sameUrlState\n ? `${normalizeAuthUrl(afterUrl)}::${compactSlug(click.label)}`\n : normalizeAuthUrl(afterUrl);\n if (capturedKeys.has(stateKey)) continue;\n const result = await captureAuthDiscoveryScreen(page, opts, beforeUrl, 'auth_click', ordinal++, {\n label: click.label,\n flowType: click.flowType,\n sameUrlState,\n });\n if (result.captured) {\n captured++;\n capturedKeys.add(stateKey);\n discoveredUrls.add(result.finalUrl);\n const nested = await discoverAuthCandidates(page, origin);\n for (const link of nested.links) enqueue(link.href, 'page_link');\n }\n }\n } catch (err) {\n logger.warn({ url: current.url, err: String((err as Error)?.message ?? err) }, '[crawler] auth-discovery: URL failed \u2014 skipping');\n }\n }\n\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => { });\n await waitForStableDOM(page).catch(() => { });\n await AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'AUTH_DISCOVERY_SUMMARY',\n payload: { captured, discoveredUrls: Array.from(discoveredUrls), maxScreens: AUTH_DISCOVERY_MAX_SCREENS },\n }).catch(() => { });\n logger.info({ captured, discovered: discoveredUrls.size }, '[crawler] auth-discovery: phase complete');\n return { captured, discoveredUrls: Array.from(discoveredUrls) };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * ZeTa-AI Crawler \u2014 Stagehand hybrid architecture\n *\n * Three-layer stack:\n * Layer 1 \u2014 Playwright (deterministic): navigation, screenshots, DOM fallbacks\n * Layer 2 \u2014 Stagehand act/extract (AI): login, element understanding, smart link discovery\n * Layer 3 \u2014 Skyvern (vision): fallback for CAPTCHAs, legacy apps, visual-only flows\n *\n * enableCaching: true \u2192 repeat crawls of the same site cost ~zero AI tokens after first run.\n */\n\nimport { Stagehand } from '@browserbasehq/stagehand';\n// Option 2: rebrowser-playwright-core patches the CDP Runtime.enable leak at protocol level \u2014\n// the deepest possible stealth, defeats detection methods that JS init scripts cannot touch.\n// @ts-ignore\nimport { chromium } from 'rebrowser-playwright-core';\nimport { chromium as stealthChromium } from 'playwright-extra';\n// @ts-ignore\nimport StealthPlugin from 'puppeteer-extra-plugin-stealth';\n// Option 3: Camoufox \u2014 Firefox-based browser with built-in fingerprint randomisation.\n// Loaded dynamically (not at startup) to avoid ESM/CJS conflict when API imports crawler.\nimport { spawn, execSync, type ChildProcess } from 'node:child_process';\nimport { existsSync as existsSyncFs, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\n\nstealthChromium.use(StealthPlugin());\nimport { z } from 'zod';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { AppBrain, recordLLMCall } from '@detiq/app-brain';\nimport { aiVisualCompare, askTracked, deterministicSeed, estimateCost, getTaskAgentLLMConfig } from '@detiq/agents';\nimport { config } from '@detiq/core';\nimport { pHashVerdict, mergeAiVisualVerdict } from './visual-diff-verdict.js';\nimport type { Credentials } from './auth.js';\nimport { skyvernFallback, skyvernNavigate, type SkyvernConfig } from './skyvern.js';\nimport { loginWithStagehand } from './ai-login.js';\nimport { readScreen } from './screen-reader.js';\nimport { probeAllScreens, probeKeyboardNav } from './interactive-probe.js';\nimport { computeElementHash } from './element-hash.js';\nimport { logger } from './logger.js';\nimport { solveCaptcha } from './captcha-solver.js';\nimport { waitForEmailOTP } from './email-otp.js';\nimport { getSsoToken } from './sso-token.js';\nimport { discoverSitemapUrls, sameSite } from './sitemap.js';\nimport { extractMarkdown } from './markdown-extract.js';\nimport { CrawlFrontier, type TraversalStrategy } from './frontier.js';\nimport { RobotsCache } from './robots-txt.js';\nimport { classifyDomainProfile } from './profiles/domain-profile.js';\nimport { chooseCrawlEngines } from './engine-router.js';\nimport { assessActionSafety } from './policies/crawl-safety.js';\nimport { attachNetworkObserver, type ApiEndpointObservationInput } from './network-observer.js';\nimport { scrubPii } from './pii-scrubber.js';\nimport { computeContentHash } from './incremental-diff.js';\nimport { isPdfUrl, extractPdfFromUrl } from './pdf-extractor.js';\nimport { attachWebSocketDetector } from './websocket-detector.js';\nimport { ContentDeduplicator } from './content-dedup.js';\nimport { guessGraphQLEndpoints, introspectGraphQL } from './graphql-detector.js';\nimport { acceptCookieConsent } from './cookie-consent.js';\nimport { detectJsRoutes } from './js-router-detector.js';\nimport { runGapAnalysis } from './gap-pass.js';\nimport { buildCrawlArtifactEnvelope, buildFitMarkdown, sha256, summarizeStructuredElements } from './extractors/artifact-envelope.js';\nimport { pickFreeProxy, TieredProxyManager } from './proxy.js';\nimport type { ProxyTierConfig } from './proxy.js';\nimport { infiniteScrollToBottom, extractIframeContent, pierceShadowDom, injectFingerprintOverrides } from './stealth/human-behavior.js';\nimport { checkSeo } from './seo-checker.js';\nimport { auditColorContrast } from './color-contrast.js';\nimport { detectFeatureFlags } from './feature-flag-detector.js';\nimport { detectLanguage } from './language-detector.js';\nimport { detectForms } from './form-detector.js';\nimport { auditAccessibility } from './accessibility-auditor.js';\nimport { RedirectRegistry } from './redirect-tracker.js';\nimport { DeadLinkTracker } from './dead-link-detector.js';\nimport { screensToSitemapUrls, writeSitemap } from './sitemap-writer.js';\nimport { generateOpenApiSpec, specToYaml } from './openapi-generator.js';\nimport { WebhookNotifier } from './webhook-notifier.js';\nimport { generatePlaywrightTest } from './playwright-recorder.js';\nimport { enumerateDropdowns } from './dropdown-enumerator.js';\nimport { probeCrudFlows } from './crud-interaction.js';\nimport { crawlFiltersAndPagination } from './filter-pagination-crawler.js';\nimport { probeMultiContext } from './multi-context-handler.js';\nimport { probeAdvancedUI } from './advanced-ui-probes.js';\nimport { ScreenTransitionGraph, simHash32 } from './state-graph.js';\nimport { crawlNestedContexts } from './nested-window-crawler.js';\nimport { crawlShadowDom } from './shadow-dom-crawler.js';\nimport { crawlAccessibilityTree } from './accessibility-tree-crawler.js';\nimport { collectPerfMetrics } from './performance-metrics.js';\nimport { inspectServiceWorker } from './service-worker-interceptor.js';\n\nasync function getCrawlTuning() {\n const { getSystemConfig } = await import('@detiq/core');\n const cfg = await getSystemConfig('crawl_tuning');\n return {\n navTimeoutMs: parseInt(String(cfg?.navTimeoutMs ?? '15000'), 10),\n defaultTimeoutMs: parseInt(String(cfg?.defaultTimeoutMs ?? '2000'), 10),\n userAgent: String(cfg?.userAgent ?? 'ZeTa-Crawler/1.0 (+https://zeta.taodigitalsolutions.com/crawler)'),\n };\n}\n\n// Module-level cache for per-crawl LLM config \u2014 avoids redundant DB round-trips inside per-page loops.\n// Keyed by tenantId so multi-tenant workers don't share configs across tenants.\nconst _crawlLLMCache = new Map<string, any>();\nasync function getCachedCrawlLLM(tenantId: string): Promise<any> {\n if (_crawlLLMCache.has(tenantId)) return _crawlLLMCache.get(tenantId);\n const cfg = await getTaskAgentLLMConfig(tenantId, 'crawl').catch(() => null);\n if (cfg) _crawlLLMCache.set(tenantId, cfg);\n return cfg;\n}\n\nfunction getGitInfo(): { branch: string; commit: string } {\n try {\n const branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8', timeout: 3000 }).trim();\n const commit = execSync('git rev-parse HEAD', { encoding: 'utf8', timeout: 3000 }).trim().slice(0, 12);\n return { branch: branch || 'main', commit };\n } catch {\n return { branch: 'main', commit: '' };\n }\n}\n\ninterface PerformanceMetric {\n url: string;\n screenName: string;\n lcp?: number;\n fcp?: number;\n ttfb?: number;\n cls?: number;\n}\n\nexport interface DiscoveredLinkMeta {\n url: string;\n text?: string;\n landmark?: string;\n source: 'DOM' | 'AI' | 'INTERACTIVE';\n}\n\nconst ALLOWED_NUMERIC_PATHS = new Set(['/2fa', '/404', '/500', '/403', '/401']);\n\n// Seed path patterns compiled for the active crawl. Set by crawlProject() at the\n// start of each run. All isUsefulNavigationUrl() calls share this for the duration.\nlet _activeSeedPatterns: RegExp[] = [];\nconst UUID_PATH_SEGMENT_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst CUID_PATH_SEGMENT_RE = /^c[a-z0-9]{20,}$/i;\n// Match 4+ digit pure numeric IDs only \u2014 aligns with canonicalize()'s /\\d{4,}/ threshold.\n// 1-3 digit segments (page/2/, /tag/books/page/3/) are valid pagination \u2014 do NOT skip them.\nconst NUMERIC_ID_PATH_SEGMENT_RE = /^\\d{4,}$/;\nconst COMPOUND_NUMERIC_ID_PATH_SEGMENT_RE = /^\\d+-\\d+$/;\n\nfunction normalizePathForNumericGuard(pathname: string): string {\n const normalized = pathname.replace(/\\/+$/, '') || '/';\n return normalized;\n}\n\nfunction isGeneratedPathSegment(segment: string): boolean {\n return UUID_PATH_SEGMENT_RE.test(segment)\n || CUID_PATH_SEGMENT_RE.test(segment)\n || COMPOUND_NUMERIC_ID_PATH_SEGMENT_RE.test(segment)\n || NUMERIC_ID_PATH_SEGMENT_RE.test(segment);\n}\n\nfunction isGeneratedDynamicPath(pathname: string): boolean {\n const normalized = normalizePathForNumericGuard(pathname);\n if (ALLOWED_NUMERIC_PATHS.has(normalized)) return false;\n\n // Parent-route agnostic: any generated ID-like segment can create hundreds of\n // duplicate detail/fallback screens under different sections of the app.\n return normalized.split('/').filter(Boolean).some(isGeneratedPathSegment);\n}\n\n// File extensions that trigger browser downloads rather than page renders.\n// URLs ending with these are skipped from the BFS queue entirely.\nconst DOWNLOAD_EXT_RE = /\\.(pdf|zip|gz|tar|rar|7z|exe|dmg|pkg|deb|rpm|msi|apk|ipa|doc|docx|xls|xlsx|ppt|pptx|csv|json|xml|yaml|yml|txt|log|sql|db|sqlite|mp4|mp3|avi|mov|mkv|webm|wav|ogg|flac|jpg|jpeg|png|gif|bmp|svg|webp|ico|woff|woff2|ttf|eot|otf|bin|iso|img|vhd|vmdk)(\\?.*)?$/i;\n\n// API endpoint path patterns \u2014 these return data (JSON/CSV/binary), not rendered pages.\n// Crawling them triggers file downloads and wastes BFS slots.\nconst API_PATH_RE = /^\\/api\\//i;\n\n// Export/download path segments that appear in apps \u2014 these return file data even without\n// a file extension in the URL (e.g. /admin/exports/report, /download/invoice/123).\nconst EXPORT_PATH_RE = /\\/(exports?|downloads?|export-csv|export-pdf|export-excel|download-report|generate-report|report-download)(\\/|$|\\?)/i;\n\nfunction isUsefulNavigationUrl(href: string, siteOrigin: string): boolean {\n try {\n const u = new URL(href);\n if (!sameSite(u.toString(), siteOrigin)) return false;\n if (/\\/(logout|logged-out|signout|sign-out)(\\/|$|\\?)/i.test(u.pathname)) return false;\n // Bypass CUID/UUID guard for seed path patterns declared by the caller.\n // _activeSeedPatterns is set per-crawl by crawlProject.\n if (isGeneratedDynamicPath(u.pathname) && !_activeSeedPatterns.some(re => re.test(u.pathname))) return false;\n if (DOWNLOAD_EXT_RE.test(u.pathname)) return false;\n if (API_PATH_RE.test(u.pathname)) return false;\n if (EXPORT_PATH_RE.test(u.pathname)) return false;\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Compile seedPathPatterns (e.g., ['/projects/{id}/tests']) into RegExp matchers.\n * {id} matches any single path segment (CUID, UUID, numeric, slug, etc.).\n * Example: '/projects/{id}/tests' \u2192 /^\\/projects\\/[^/]+\\/tests(\\/.*)?$/i\n */\nfunction buildSeedPatternRegexes(patterns: string[]): RegExp[] {\n return patterns.map((p) => {\n const parts = p.split('{id}').map(part => part.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&'));\n const body = parts.join('[^/]+');\n return new RegExp(`^${body}(/.*)?$`, 'i');\n });\n}\n\ntype AuthFlowType = 'public' | 'login' | 'register' | 'password_reset' | 'verification' | 'invite' | 'session_recovery';\ntype AuthDiscoverySource = 'entry' | 'seed_path' | 'page_link' | 'auth_click';\ntype AuthDiscoveryProgress = (pct: number, step: string) => void | Promise<void>;\ntype AuthDiscoveryOptions = {\n appUrl: string;\n tenantId: string;\n projectId: string;\n jobId?: string;\n screenshotDir?: string;\n storageConfig?: any;\n};\n\nconst AUTH_DISCOVERY_MAX_SCREENS = parseInt(process.env.CRAWLER_AUTH_DISCOVERY_MAX_SCREENS ?? '') || 36;\nconst AUTH_DISCOVERY_MAX_QUEUE = parseInt(process.env.CRAWLER_AUTH_DISCOVERY_MAX_QUEUE ?? '') || 48;\nconst AUTH_DISCOVERY_MAX_CLICKS_PER_PAGE = parseInt(process.env.CRAWLER_AUTH_DISCOVERY_MAX_CLICKS_PER_PAGE ?? '') || 6;\nconst AUTH_DISCOVERY_PATHS = [\n '/',\n '/login', '/log-in', '/signin', '/sign-in', '/auth', '/auth/login', '/account/login', '/user/login', '/app/login',\n '/register', '/signup', '/sign-up', '/create-account', '/join',\n '/forgot-password', '/forgot', '/password/forgot', '/reset-password', '/password/reset',\n '/verify-email', '/invite',\n '/pricing', '/contact', '/about', '/help', '/docs',\n];\nconst AUTH_PATH_RE = /\\/(login|log-in|signin|sign-in|auth|oauth|sso|account\\/login|user\\/login|app\\/login|register|signup|sign-up|create-account|forgot|reset|password|verify-email|invite)(\\/|$|\\?)/i;\nconst PUBLIC_PATH_RE = /\\/($|pricing|contact|about|help|docs|features|security|privacy|terms)(\\/|$|\\?)/i;\n\nfunction compactSlug(input: string, fallback = 'state'): string {\n const slug = input.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 48);\n return slug || fallback;\n}\n\nfunction titleFromUrl(url: string, fallback = 'Page'): string {\n try {\n const u = new URL(url);\n const parts = u.pathname.split('/').filter(Boolean);\n if (parts.length === 0) return 'Home';\n return parts\n .slice(-2)\n .join(' ')\n .replace(/[-_]+/g, ' ')\n .replace(/\\b\\w/g, (m) => m.toUpperCase());\n } catch {\n return fallback;\n }\n}\n\nfunction flowTypeForUrlOrText(value: string): AuthFlowType {\n const v = value.toLowerCase();\n if (/(forgot|reset|password)/.test(v)) return 'password_reset';\n if (/(register|signup|sign up|create account|join)/.test(v)) return 'register';\n if (/(verify|verification|otp|mfa|2fa|invite)/.test(v)) return v.includes('invite') ? 'invite' : 'verification';\n if (/(session-expired|expired|unauthorized|forbidden|401|403|logout|logged-out)/.test(v)) return 'session_recovery';\n if (/(login|log in|signin|sign in|auth|sso|oauth)/.test(v)) return 'login';\n return 'public';\n}\n\nfunction shouldSeedAuthDiscoveryUrl(url: string, origin: string): boolean {\n try {\n const u = new URL(url);\n if (!sameSite(u.toString(), origin)) return false;\n if (/\\/(logout|logged-out|signout|sign-out|delete|remove|destroy)(\\/|$|\\?)/i.test(u.pathname)) return false;\n return AUTH_PATH_RE.test(u.pathname) || PUBLIC_PATH_RE.test(u.pathname);\n } catch {\n return false;\n }\n}\n\nfunction normalizeAuthUrl(url: string): string {\n try {\n const u = new URL(url);\n u.hash = '';\n return `${u.origin}${u.pathname.replace(/\\/$/, '') || '/'}${u.search}`;\n } catch {\n return url;\n }\n}\n\nasync function capturePageHtml(page: any): Promise<string | null> {\n let html: string | null = null;\n\n try {\n if (typeof page.content === 'function') {\n const raw = await page.content();\n if (typeof raw === 'string' && raw.trim()) html = raw;\n }\n } catch (err: any) {\n logger.warn({ err: String(err?.message ?? err) }, '[crawler] page.content() failed; trying DOM evaluate fallback');\n }\n\n if (!html) {\n try {\n html = await page.evaluate(() => {\n const type = document.doctype;\n const doctype = type\n ? '<!DOCTYPE ' + type.name +\n (type.publicId ? ' PUBLIC \"' + type.publicId + '\"' : '') +\n (type.systemId ? ' \"' + type.systemId + '\"' : '') +\n '>'\n : '<!DOCTYPE html>';\n return doctype + '\\n' + (document.documentElement?.outerHTML ?? document.body?.outerHTML ?? '');\n });\n if (typeof html !== 'string' || !html.trim()) html = null;\n } catch (err: any) {\n logger.warn({ err: String(err?.message ?? err) }, '[crawler] DOM snapshot capture failed');\n return null;\n }\n }\n\n if (!html) return null;\n\n // Inline all accessible stylesheets so the snapshot renders correctly offline\n // (srcDoc iframes have a null origin \u2014 external CSS loads fail cross-origin).\n try {\n html = await page.evaluate(() => {\n // Strip script tags \u2014 execution is blocked by CSP/sandbox anyway; removing reduces size and avoids leaking inline tokens.\n document.querySelectorAll('script').forEach((s: any) => s.remove());\n for (const sheet of Array.from(document.styleSheets)) {\n try {\n // cssRules throws SecurityError for cross-origin sheets \u2014 skip those\n const cssText = Array.from(sheet.cssRules).map((r: any) => r.cssText).join('\\n');\n const style = document.createElement('style');\n style.textContent = cssText;\n const owner = sheet.ownerNode as Element | null;\n owner?.replaceWith(style);\n } catch { /* cross-origin CDN sheet \u2014 leave <link> in place */ }\n }\n const doctype = (() => {\n const dt = document.doctype;\n return dt ? `<!DOCTYPE ${dt.name}>` : '<!DOCTYPE html>';\n })();\n return doctype + '\\n' + (document.documentElement?.outerHTML ?? '');\n });\n if (typeof html !== 'string' || !html.trim()) html = null;\n } catch (err: any) {\n logger.warn({ err: String(err?.message ?? err) }, '[crawler] CSS inlining failed; using raw HTML');\n // html already has the raw value from page.content() \u2014 usable as-is\n }\n\n return html;\n}\n\n/** Launch Chrome on a random CDP port and return its WebSocket debugger URL. */\nasync function launchChromeCDP(\n execPath: string,\n extraArgs: string[],\n proxy?: { server: string; username?: string; password?: string },\n useStealthPlugin = true,\n): Promise<{ wsUrl: string; proc: any }> {\n // Use a random port in 9200-9900 range to avoid clashes between concurrent crawls.\n const port = 9200 + Math.floor(Math.random() * 700);\n\n // Use stealthChromium (playwright-extra + puppeteer-extra-plugin-stealth) by default.\n // Pass useStealthPlugin=false to opt out for a specific crawl job (opts.stealth === false).\n const launcher = useStealthPlugin ? stealthChromium : chromium;\n const browserServer = await launcher.launchServer({\n headless: true,\n executablePath: execPath,\n // Use Playwright's native proxy option \u2014 it handles 407 auth challenges automatically.\n // The --proxy-server Chrome flag does NOT support credentials with special chars (commas).\n ...(proxy ? { proxy } : {}),\n args: [\n ...extraArgs,\n `--remote-debugging-port=${port}`,\n '--remote-allow-origins=*',\n '--no-first-run',\n '--no-default-browser-check',\n ],\n });\n\n // Poll until Chrome's debug port is ready (up to 10 s).\n const deadline = Date.now() + 10_000;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, 300));\n try {\n const res = await fetch(`http://127.0.0.1:${port}/json/version`);\n if (res.ok) {\n const { webSocketDebuggerUrl } = await res.json() as { webSocketDebuggerUrl: string };\n return { wsUrl: webSocketDebuggerUrl, proc: browserServer };\n }\n } catch { /* not ready */ }\n }\n await browserServer.close();\n throw new Error(`Chrome failed to open CDP port ${port} within 10 s`);\n}\n\n/**\n * Lightweight pre-crawl link discovery: loads the app URL in a headless (proxy-aware) browser\n * and returns same-site `<a href>` links. Complements sitemap discovery for SPA/app sites that\n * have no sitemap.xml. Best-effort \u2014 returns [] on any failure (bot wall, timeout, etc.).\n * chromium.launch({ proxy }) handles proxy 407 auth itself (same client), so no CDP handler needed.\n */\nexport async function discoverLinksViaBrowser(\n appUrl: string,\n opts?: { proxyUrl?: string; maxLinks?: number },\n): Promise<string[]> {\n let proxy: { server: string; username?: string; password?: string } | undefined;\n const purl = opts?.proxyUrl;\n if (purl && purl !== 'auto') {\n const m = purl.match(/^(https?|socks5?):\\/\\/(?:([^:@]*)(?::([^@]*))?@)?(.+)$/);\n if (m) {\n const [, scheme, user, pass, hostPort] = m;\n proxy = user\n ? { server: `${scheme}://${hostPort}`, username: decodeURIComponent(user), password: decodeURIComponent(pass ?? '') }\n : { server: `${scheme}://${hostPort}` };\n } else {\n proxy = { server: purl };\n }\n }\n let executablePath: string | undefined;\n try { executablePath = chromium.executablePath(); } catch { /* fall back to CHROME_PATH */ }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let browser: any = null;\n try {\n browser = await chromium.launch({\n headless: true,\n ...(executablePath ? { executablePath } : {}),\n ...(proxy ? { proxy } : {}),\n args: ['--no-sandbox', '--disable-dev-shm-usage'],\n });\n const page = await browser.newPage();\n await page.goto(appUrl, { waitUntil: 'networkidle', timeout: 30_000 }).catch(() => { });\n await page.waitForTimeout(2_500); // let SPA / Web Components hydrate before scraping links\n const hrefs: string[] = await page.evaluate((origin: string) => {\n const found = new Set<string>();\n const walk = (root: Document | ShadowRoot | Element) => {\n (root as any).querySelectorAll('a[href]').forEach((a: any) => {\n const h: string = a.href || a.getAttribute('href') || '';\n if (h && (h.startsWith(origin) || h.startsWith('/'))) found.add(h);\n });\n (root as any).querySelectorAll('*').forEach((el: any) => {\n if (el.shadowRoot) walk(el.shadowRoot);\n });\n };\n walk(document);\n return [...found];\n }, new URL(appUrl).origin).catch(() => [] as string[]);\n return [...new Set(hrefs.filter((h) => sameSite(h, appUrl)))].slice(0, opts?.maxLinks ?? 500);\n } catch {\n return [];\n } finally {\n if (browser) await browser.close().catch(() => { });\n }\n}\n\n/**\n * Run a Lighthouse audit against a URL and return category scores (0-100 integers).\n * Requires ENABLE_LIGHTHOUSE=true env var \u2014 disabled by default to avoid slowing crawls.\n * Returns null on any error or when disabled.\n */\nasync function runLighthouse(url: string): Promise<{\n perf: number; a11y: number; seo: number; bp: number; report: object;\n} | null> {\n if (!process.env.ENABLE_LIGHTHOUSE) return null;\n try {\n const { default: lighthouse } = await import('lighthouse');\n const chromeLauncher = await import('chrome-launcher');\n const chrome = await chromeLauncher.launch({\n chromeFlags: ['--headless', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage'],\n });\n try {\n const result = await lighthouse(url, {\n port: chrome.port,\n output: 'json',\n logLevel: 'error',\n onlyCategories: ['performance', 'accessibility', 'seo', 'best-practices'],\n } as any);\n if (!result?.lhr?.categories) return null;\n const cats = result.lhr.categories as Record<string, { score: number | null }>;\n const score = (key: string) => Math.round((cats[key]?.score ?? 0) * 100);\n return {\n perf: score('performance'),\n a11y: score('accessibility'),\n seo: score('seo'),\n bp: score('best-practices'),\n report: result.lhr as object,\n };\n } finally {\n await chrome.kill();\n }\n } catch (err) {\n console.warn('[crawler] Lighthouse run failed (non-fatal):', err);\n return null;\n }\n}\n\nconst ElementSchema = z.object({\n elements: z.array(z.object({\n meaning: z.string(),\n role: z.string(),\n expectedData: z.string().optional(),\n })),\n});\n\nconst LinksSchema = z.object({\n links: z.array(z.string()),\n});\n\nconst TwoFASchema = z.object({\n has2FA: z.boolean(),\n fieldLabel: z.string().optional(),\n});\n\n// Shared across all crawl phases (lite-worker, main BFS, P3a, P6).\n// PHP/legacy apps render session-expired content inline without URL redirect.\nconst INLINE_AUTH_WALL_RE = /your login session (was|has been) expired|session (has )?expired[^.]*click|please (log ?in|sign ?in) to continue|you (are|were) logged out|your session has timed out/i;\n\nexport async function crawlProject(opts: {\n tenantId: string;\n projectId: string;\n appUrl: string;\n /** The viewport used for this crawl pass */\n viewport?: 'DESKTOP' | 'MOBILE_PORTRAIT' | 'TABLET';\n credentials?: Credentials;\n /** Playwright storageState JSON string \u2014 if present, session is restored and AI login is skipped. */\n storageState?: string;\n screenshotDir?: string;\n /** Cloud storage config for immediate screenshot upload. If set, screenshots are uploaded to cloud immediately after capture and cloudUrl is persisted. */\n storageConfig?: { provider: string; bucket: string; region?: string; accountId?: string; endpointUrl?: string; accessKeyId?: string; secretAccessKey?: string; prefix?: string; publicUrl?: string } | null;\n /** When true, run a fast URL-only discovery crawl \u2014 skips screenshots, DB saves, and AI element extraction. Returns discoveredUrls in the result object. */\n discoveryMode?: boolean;\n maxScreens?: number;\n /** Seed URLs added to the initial crawl queue \u2014 link discovery still runs from each page. */\n startUrls?: string[];\n /** When provided, crawl ONLY these exact URLs (no link-following, no full screen clear). Used for selected-screen recrawl. */\n selectiveUrls?: string[];\n /**\n * URL path patterns that bypass the CUID/UUID generated-ID filter during BFS link discovery.\n * Use {id} as a placeholder for any generated path segment (CUID, UUID, numeric ID, etc.).\n * Example: ['/projects/{id}/tests', '/workspaces/{id}/settings']\n * Without this, all URLs containing generated IDs are silently skipped by the BFS.\n */\n seedPathPatterns?: string[];\n /** When true, run the interactive probe after static crawl to capture real validation errors, toasts, and modals. */\n interactive?: boolean;\n /** Optional abort signal \u2014 abort() cancels the crawl between page navigations. */\n abortSignal?: AbortSignal;\n /** Platform job ID \u2014 stored on screens so we can diff which were found in each crawl. */\n jobId?: string;\n /** Device profiles to capture screenshots for after the main DESKTOP crawl.\n * Values: 'MOBILE_PORTRAIT' | 'TABLET'\n * The main crawl always runs as DESKTOP. Extra profiles trigger a screenshot-only pass.\n */\n deviceProfiles?: string[];\n /** HTTP Basic Auth credentials \u2014 injected as Authorization header on same-origin requests. */\n httpBasicUsername?: string;\n httpBasicPassword?: string;\n /** Bearer/API token \u2014 injected as a request header and into localStorage. Skips AI login. */\n authToken?: string;\n /** Header name for authToken (default: 'Authorization'). */\n authTokenHeader?: string;\n /** Prefix for authToken value (default: 'Bearer '). */\n authTokenPrefix?: string;\n /** CAPTCHA solving API key (2captcha or CapSolver). */\n captchaSolverApiKey?: string;\n /** CAPTCHA solving service provider (default: '2captcha'). */\n captchaSolverProvider?: '2captcha' | 'capsolver';\n /**\n * Path to a Chrome user data directory for profile inheritance.\n * When set, the crawler exports the existing session from this profile and injects it,\n * so the agent is already logged in. Works for local/self-hosted deployments only.\n * Ignored on cloud/Docker (headless env cannot open another Chrome instance safely).\n */\n chromeProfilePath?: string;\n /** MailSlurp API key for email OTP auto-retrieval (GAP 5). */\n mailslurpApiKey?: string;\n /** MailSlurp inbox ID to poll for OTP emails (GAP 5). */\n mailslurpInboxId?: string;\n /** SSO provider for ROPC token flow \u2014 'okta' | 'azure_ad' | 'generic_oidc' (GAP 18). */\n ssoProvider?: string;\n /** SSO domain or Azure tenant ID (GAP 18). */\n ssoDomain?: string;\n /** SSO OAuth2 client ID (GAP 18). */\n ssoClientId?: string;\n /** SSO OAuth2 client secret (GAP 18). */\n ssoClientSecret?: string;\n /** SSO scopes (space-separated, default: 'openid profile') (GAP 18). */\n ssoScope?: string;\n /** HTTP/HTTPS/SOCKS5 proxy URL \u2014 e.g. 'http://user:pass@proxy.example.com:8080' or 'socks5://proxy:1080'.\n * Useful for sites that block datacenter IPs (Akamai, Cloudflare Bot Manager). */\n proxyUrl?: string;\n /** Tiered proxy configuration for automatic per-domain escalation (free \u2192 datacenter \u2192 residential \u2192 premium). */\n proxyTiers?: ProxyTierConfig[];\n /** Use Camoufox (Firefox) as a cookie bootstrapper before the main Chromium crawl.\n * Camoufox visits the URL first to solve Cloudflare JS challenges and extract session\n * cookies, which are then injected into the Chromium crawl as storageState.\n * Enable via Project Settings \u2192 Crawl Config \u2192 useFirefox: true. */\n useFirefox?: boolean;\n /** Natural language login instructions for Stagehand AI login. E.g. \"Click Sign In in the nav, fill email, click Continue\". */\n loginInstructions?: string;\n /** Skyvern vision fallback config from workspace settings (overrides SKYVERN_API_URL/KEY env vars). */\n skyvernConfig?: SkyvernConfig;\n /**\n * Max screens to crawl per segment (default 50).\n * After this limit the crawl pauses and remaining URLs are saved so the\n * next job can continue. Total crawl is unlimited \u2014 just runs in multiple jobs.\n */\n segmentSize?: number;\n /** URLs still queued from a previous segment \u2014 injected by the job-queue auto-continuation. */\n resumeUrls?: string[];\n /** Segment number (1-based) \u2014 used for progress display only. */\n segmentIndex?: number;\n /** Seed the crawl queue from the project's sitemap.xml, in addition to link-following. */\n useSitemap?: boolean;\n /** Explicit sitemap URL override \u2014 defaults to `${origin}/sitemap.xml` when useSitemap is set. */\n sitemapUrl?: string;\n /** Crawl queue traversal order. Default BFS \u2014 unchanged behavior from before this option existed. */\n traversalStrategy?: TraversalStrategy;\n /** BEST_FIRST only: URLs containing any of these (case-insensitive) are prioritized. */\n bestFirstKeywords?: string[];\n /** When true, skip URLs disallowed by the site's robots.txt. Default false. */\n respectRobotsTxt?: boolean;\n /** When true, dynamically slow crawl speed when server response latency is high (Scrapy-style AutoThrottle). Default false. */\n autoThrottle?: boolean;\n /** Regex pattern \u2014 only crawl URLs whose path+query match this pattern. */\n urlFilter?: string;\n /** Glob patterns \u2014 only enqueue URLs whose pathname matches at least one (supports * and **). */\n includePatterns?: string[];\n /** Glob patterns \u2014 skip URLs whose pathname matches any of these (supports * and **). */\n excludePatterns?: string[];\n /** Already-captured URLs from a previous failed job \u2014 pre-seeded into visited map so they're never re-crawled. */\n skipUrls?: string[];\n /** DOM hashes collected in a prior segment \u2014 prevents re-screenshotting structurally identical pages across segments. */\n knownDomHashes?: string[];\n /** When false, disables the puppeteer-extra stealth plugin (playwright-extra) for this crawl.\n * Default true \u2014 stealth is applied unless explicitly set to false. */\n stealth?: boolean;\n /** Desktop viewport width in pixels (default: 1440). */\n viewportWidth?: number;\n /** Desktop viewport height in pixels (default: 900). */\n viewportHeight?: number;\n /** Called every 10 successful screen captures with current visited URLs and remaining queue \u2014 used for checkpoint persistence. */\n onCheckpoint?: (visitedUrls: string[], pendingQueue: string[]) => Promise<void>;\n /** Discovery mode only: called after each page with the current set of discovered original URLs \u2014 enables streaming partial results to callers. */\n onUrlsDiscovered?: (urls: string[]) => Promise<void>;\n}, onProgress?: (pct: number, step: string) => Promise<void>) {\n const tuning = await getCrawlTuning();\n\n // Compile seed path patterns for this crawl run. Applied by isUsefulNavigationUrl()\n // to bypass the CUID guard for explicitly declared URL shapes.\n _activeSeedPatterns = buildSeedPatternRegexes(opts.seedPathPatterns ?? []);\n\n if (opts.screenshotDir) await fs.mkdir(opts.screenshotDir, { recursive: true });\n\n // Upload screenshot to cloud storage if configured, returns cloudUrl or undefined\n const uploadToCloud = async (localPath: string, key: string): Promise<string | undefined> => {\n if (!opts.storageConfig) return undefined;\n if (!existsSyncFs(localPath)) return undefined;\n try {\n const { uploadScreenshotToTenantStorage } = await import('@detiq/app-brain');\n return await uploadScreenshotToTenantStorage(opts.storageConfig as any, localPath, key);\n } catch {\n return undefined;\n }\n };\n\n const isDocker = !!process.env.PLAYWRIGHT_IN_DOCKER || process.env.NODE_ENV === 'production';\n\n // Stagehand v3 uses Vercel AI SDK internally. Model format: \"aisdk-provider/model-name\".\n // Each provider maps to a native AI SDK client; OpenAI-compat baseURL used for non-native ones.\n // Provider \u2192 AI SDK prefix mapping:\n // anthropic \u2192 anthropic, openai \u2192 openai, gemini \u2192 google, grok \u2192 xai,\n // groq \u2192 groq (native), openrouter \u2192 openai+baseURL, ollama \u2192 ollama, nvidia \u2192 openai+baseURL\n\n let stagehandModel = config.llmModel.includes('/') ? config.llmModel : `openai/${config.llmModel}`;\n // clientOptions spread into Stagehand model object (apiKey, baseURL, etc.)\n let stagehandModelOpts: Record<string, string | undefined> = {};\n let stagehandConfigured = false;\n let configuredProvider = '';\n\n try {\n // getTaskAgentLLMConfig: tenant config \u2192 platform admin config \u2192 null (proper fallback chain)\n const crawlLLM = await getTaskAgentLLMConfig(opts.tenantId, 'crawl');\n if (crawlLLM) {\n configuredProvider = crawlLLM.provider;\n const hasKey = crawlLLM.apiKey !== undefined && crawlLLM.apiKey !== null;\n const apiKey = hasKey ? crawlLLM.apiKey : undefined;\n const baseUrl = crawlLLM.baseUrl || undefined;\n const m = crawlLLM.model;\n\n if (m && (hasKey || crawlLLM.provider === 'ollama' || crawlLLM.provider === 'bedrock' || crawlLLM.provider === 'vertex')) {\n stagehandConfigured = true;\n switch (crawlLLM.provider) {\n case 'anthropic':\n stagehandModel = m.includes('/') ? m : `anthropic/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'openai':\n stagehandModel = m.includes('/') ? m : `openai/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'gemini':\n stagehandModel = `google/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'grok':\n stagehandModel = `xai/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'openrouter':\n stagehandModel = `openai/${m}`;\n stagehandModelOpts = { ...(apiKey ? { apiKey } : {}), baseURL: baseUrl || process.env.CRAWLER_OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1' };\n break;\n case 'ollama':\n stagehandModel = `ollama/${m}`;\n stagehandModelOpts = { baseURL: baseUrl || process.env.CRAWLER_OLLAMA_BASE_URL || 'http://localhost:11434' };\n break;\n case 'nvidia':\n stagehandModel = `openai/${m.startsWith('openai/') ? m.slice(7) : m}`;\n stagehandModelOpts = { ...(apiKey ? { apiKey } : {}), baseURL: baseUrl || process.env.CRAWLER_NVIDIA_BASE_URL || 'https://integrate.api.nvidia.com/v1' };\n break;\n case 'groq':\n stagehandModel = `groq/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'mistral':\n stagehandModel = `mistral/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'deepseek':\n stagehandModel = `deepseek/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'perplexity':\n stagehandModel = `perplexity/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'togetherai':\n stagehandModel = `togetherai/${m}`;\n stagehandModelOpts = apiKey ? { apiKey } : {};\n break;\n case 'bedrock':\n // Uses AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_REGION from env\n stagehandModel = `bedrock/${m}`;\n stagehandModelOpts = {};\n break;\n case 'vertex':\n // Uses GOOGLE_APPLICATION_CREDENTIALS or GOOGLE_VERTEX_PROJECT from env\n stagehandModel = `vertex/${m}`;\n stagehandModelOpts = {};\n break;\n case 'azure':\n stagehandModel = `azure/${m}`;\n stagehandModelOpts = { ...(apiKey ? { apiKey } : {}), ...(baseUrl ? { baseURL: baseUrl } : {}) };\n break;\n default:\n stagehandModel = `openai/${m}`;\n stagehandModelOpts = { ...(apiKey ? { apiKey } : {}), ...(baseUrl ? { baseURL: baseUrl } : {}) };\n }\n }\n }\n } catch { /* ignore DB errors, fall through to env var below */ }\n\n // Env var fallback \u2014 if DB lookup failed or returned no key\n if (!stagehandConfigured) {\n // Honor STAGEHAND_MODEL env var to determine preferred provider.\n const envModel = process.env.STAGEHAND_MODEL ?? '';\n const preferAnthropic = envModel.includes('claude') || (!envModel && !process.env.OPENAI_API_KEY);\n if (preferAnthropic && process.env.ANTHROPIC_API_KEY) {\n stagehandModelOpts = { apiKey: process.env.ANTHROPIC_API_KEY };\n const defaultAnthropicModel = process.env.CRAWLER_DEFAULT_MODEL ?? 'claude-sonnet-4-6';\n stagehandModel = envModel.includes('/') ? envModel : `anthropic/${envModel || defaultAnthropicModel}`;\n stagehandConfigured = true;\n } else if (process.env.OPENAI_API_KEY) {\n stagehandModelOpts = { apiKey: process.env.OPENAI_API_KEY };\n const defaultOpenaiModel = process.env.CRAWLER_DEFAULT_MODEL ?? 'gpt-4o';\n stagehandModel = envModel.includes('/') ? envModel : `openai/${envModel || defaultOpenaiModel}`;\n stagehandConfigured = true;\n } else if (process.env.ANTHROPIC_API_KEY) {\n stagehandModelOpts = { apiKey: process.env.ANTHROPIC_API_KEY };\n const defaultAnthropicModel2 = process.env.CRAWLER_DEFAULT_MODEL ?? 'claude-sonnet-4-6';\n stagehandModel = envModel.includes('/') ? envModel : `anthropic/${envModel || defaultAnthropicModel2}`;\n stagehandConfigured = true;\n }\n }\n\n const elementLLM = await AppBrain.getTaskLLMConfig(opts.tenantId, 'elementExtraction').catch(() => null);\n const linkLLM = await AppBrain.getTaskLLMConfig(opts.tenantId, 'linkDiscovery').catch(() => null);\n const projectForProfile = await AppBrain.getProjectMap(opts.tenantId, opts.projectId).catch(() => null);\n const profileProjectName = projectForProfile?.name ?? null;\n const profileAppType = projectForProfile?.appType ?? null;\n const domainProfile = classifyDomainProfile({\n appUrl: opts.appUrl,\n projectName: profileProjectName,\n appType: profileAppType,\n seedText: [\n ...(opts.startUrls ?? []),\n opts.loginInstructions ?? '',\n ...(opts.bestFirstKeywords ?? []),\n ].join(' '),\n });\n const routeDecision = chooseCrawlEngines({\n appUrl: opts.appUrl,\n appType: profileAppType,\n hasCredentials: !!opts.credentials,\n hasStorageState: !!opts.storageState,\n hasAuthToken: !!opts.authToken,\n hasSkyvern: !!opts.skyvernConfig,\n hasProxy: !!opts.proxyUrl,\n profile: domainProfile,\n });\n\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'CRAWL_PROFILE',\n payload: { profile: domainProfile, routeDecision },\n }).catch((err: any) => console.warn('[crawler] profile evidence save failed:', err?.message ?? err));\n\n if (!stagehandConfigured && !opts.discoveryMode) {\n // Discovery mode never calls Stagehand AI \u2014 DOM link extraction only.\n // Skip this guard so URL discovery works even without an AI provider configured.\n throw new Error(\n configuredProvider\n ? `No API key configured for provider \"${configuredProvider}\". Go to Workspace \u2192 Settings \u2192 AI Provider.`\n : 'No AI provider configured. Go to Workspace \u2192 Settings \u2192 AI Provider to set up an AI provider for browser crawling.'\n );\n }\n\n // Anti-detect args applied on all platforms.\n // '--disable-blink-features=AutomationControlled' removes navigator.webdriver at the\n // Chromium level \u2014 more reliable than JS overrides alone.\n // '--disable-http2' defeats Akamai/Cloudflare JA3/JA4 TLS fingerprinting on datacenter IPs.\n const stealthArgs = [\n '--disable-blink-features=AutomationControlled',\n '--disable-http2',\n '--lang=en-US,en',\n `--window-size=${opts.viewportWidth ?? 1440},${opts.viewportHeight ?? 900}`,\n '--disable-features=IsolateOrigins,site-per-process',\n ];\n\n const chromeArgs = isDocker\n ? [\n '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu',\n ...stealthArgs,\n ]\n : [...stealthArgs];\n // Resolve proxy: tiered manager > 'auto' free list > explicit URL\n let resolvedProxyUrl = opts.proxyUrl;\n let tieredProxyManager: TieredProxyManager | undefined;\n if (opts.proxyTiers?.length) {\n tieredProxyManager = new TieredProxyManager(opts.proxyTiers);\n const domain = (() => { try { return new URL(opts.appUrl).hostname; } catch { return opts.appUrl; } })();\n resolvedProxyUrl = tieredProxyManager.selectProxy(domain) ?? resolvedProxyUrl;\n logger.info({ domain, proxyUrl: resolvedProxyUrl }, '[crawler] tiered proxy selected');\n } else if (resolvedProxyUrl === 'auto') {\n logger.info('[crawler] proxyUrl=auto: selecting free proxy from public list...');\n resolvedProxyUrl = (await pickFreeProxy()) ?? undefined;\n if (resolvedProxyUrl) {\n logger.info({ proxyUrl: resolvedProxyUrl }, '[crawler] auto-proxy selected');\n } else {\n logger.warn('[crawler] auto-proxy: no working proxy found, proceeding without proxy');\n }\n }\n // Parse proxy URL into Playwright's native proxy format.\n // We do NOT use --proxy-server Chrome arg because:\n // 1. Chrome ignores credentials in --proxy-server URLs (no auth support via flag)\n // 2. Commas in username (DataImpulse country codes) break Chrome's proxy-list parser\n // Playwright's launchServer({ proxy }) handles 407 auth challenges correctly.\n let playwrightProxy: { server: string; username?: string; password?: string } | undefined;\n if (resolvedProxyUrl) {\n try {\n // Manual parse: new URL() chokes on commas in the username part\n const proxyMatch = resolvedProxyUrl.match(/^(https?|socks5?):\\/\\/(?:([^:@]*)(?::([^@]*))?@)?(.+)$/);\n if (proxyMatch) {\n const [, scheme, rawUser, rawPass, hostPort] = proxyMatch;\n const server = `${scheme}://${hostPort}`;\n const username = rawUser ? decodeURIComponent(rawUser) : undefined;\n const password = rawPass ? decodeURIComponent(rawPass) : undefined;\n playwrightProxy = username ? { server, username, password } : { server };\n logger.info({ server, hasAuth: !!username }, '[crawler] proxy configured (Playwright native)');\n } else {\n playwrightProxy = { server: resolvedProxyUrl };\n }\n } catch {\n playwrightProxy = { server: resolvedProxyUrl };\n }\n }\n\n // Stagehand 3.x uses chrome-launcher under the hood, which fails in Docker\n // because it doesn't pass --no-sandbox and uses a different spawn environment.\n // Fix: spawn Chrome ourselves with the right flags, get its CDP WS URL,\n // then connect Stagehand to the already-running browser via cdpUrl.\n let executablePath: string | undefined;\n try { executablePath = chromium.executablePath(); } catch { /* use CHROME_PATH */ }\n\n if (!executablePath) throw new Error('No Chrome binary found. Set CHROME_PATH or install Playwright browsers.');\n\n // GAP 3: Chrome Profile Inheritance \u2014 local/self-hosted deployments only.\n // Launch a temporary persistent context to export the storageState from the user's Chrome profile,\n // then inject it so the normal session-restore path handles auth (no AI login needed).\n let effectiveStorageState = opts.storageState;\n if (opts.chromeProfilePath && !isDocker) {\n logger.info({ chromeProfilePath: opts.chromeProfilePath }, '[crawler] Exporting session from Chrome profile');\n try {\n const tempCtx = await chromium.launchPersistentContext(opts.chromeProfilePath, {\n headless: true,\n args: [...chromeArgs, '--no-first-run', '--no-default-browser-check'],\n executablePath,\n });\n const exportedState = await tempCtx.storageState();\n await tempCtx.close().catch(() => { });\n if ((exportedState.cookies?.length ?? 0) > 0 || (exportedState.origins?.length ?? 0) > 0) {\n effectiveStorageState = JSON.stringify(exportedState);\n logger.info({ cookies: exportedState.cookies?.length ?? 0, origins: exportedState.origins?.length ?? 0 }, '[crawler] Chrome profile session exported and injected');\n } else {\n logger.warn('[crawler] Chrome profile had no session data \u2014 continuing without profile auth');\n }\n } catch (profileErr) {\n logger.warn({ err: profileErr }, '[crawler] Could not load Chrome profile \u2014 continuing without profile auth');\n }\n } else if (opts.chromeProfilePath && isDocker) {\n logger.warn('[crawler] chromeProfilePath is set but will be ignored in Docker/cloud environments');\n }\n\n // \u2500\u2500 Option 3: Camoufox bootstrap \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Firefox with built-in fingerprint randomisation visits the target first to solve\n // any Cloudflare JS challenge, then we extract the cf_clearance cookie and inject it\n // into the Chromium storageState so Chrome inherits the cleared session.\n if (opts.useFirefox) {\n logger.info('[crawler] useFirefox: launching Camoufox to bootstrap Cloudflare cookies...');\n try {\n // Dynamic import prevents ESM/CJS conflict at API startup when this module is imported\n const { NewBrowser: camoufoxNewBrowser } = await import('camoufox');\n const pw = require('playwright');\n const foxBrowser = await camoufoxNewBrowser(pw, true);\n const foxPage = await foxBrowser.newPage();\n await foxPage.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 30_000 });\n // Give Cloudflare JS challenge up to 8s to complete and set cf_clearance cookie\n await foxPage.waitForTimeout(8_000);\n const foxState = await foxPage.context().storageState();\n await foxBrowser.close().catch(() => { });\n if ((foxState.cookies?.length ?? 0) > 0) {\n // Merge Camoufox cookies into any existing storageState\n if (effectiveStorageState) {\n try {\n const existing = JSON.parse(effectiveStorageState);\n const merged = { ...existing, cookies: [...(existing.cookies ?? []), ...foxState.cookies] };\n effectiveStorageState = JSON.stringify(merged);\n } catch {\n effectiveStorageState = JSON.stringify(foxState);\n }\n } else {\n effectiveStorageState = JSON.stringify(foxState);\n }\n logger.info({ cookies: foxState.cookies.length }, '[crawler] Camoufox bootstrap complete \u2014 cf_clearance injected into Chromium');\n } else {\n logger.warn('[crawler] Camoufox returned no cookies \u2014 continuing without bootstrap');\n }\n } catch (foxErr) {\n logger.warn({ err: foxErr }, '[crawler] Camoufox bootstrap failed \u2014 continuing without it');\n }\n }\n\n const { wsUrl: cdpUrl, proc: chromeProc } = await launchChromeCDP(executablePath, chromeArgs, playwrightProxy, opts.stealth !== false);\n\n // Accumulate token usage from Stagehand's internal LLM calls (extract/act/observe).\n // Stagehand doesn't expose per-call usage externally; we parse it from its logger.\n let stagehandPromptTokens = 0;\n let stagehandCompletionTokens = 0;\n const stagehandLogger = (line: { category?: string; message: string; auxiliary?: Record<string, { value: string; type: string }> }) => {\n if (line.message === 'response' && line.auxiliary?.response?.value) {\n try {\n const resp = JSON.parse(line.auxiliary.response.value);\n if (resp?.usage) {\n stagehandPromptTokens += resp.usage.prompt_tokens ?? 0;\n stagehandCompletionTokens += resp.usage.completion_tokens ?? 0;\n }\n } catch { /* ignore parse errors */ }\n }\n };\n\n const stagehand = new Stagehand({\n env: 'LOCAL',\n model: { modelName: stagehandModel as any, ...stagehandModelOpts },\n serverCache: true,\n verbose: 1,\n logger: stagehandLogger,\n localBrowserLaunchOptions: { cdpUrl, headless: true },\n domSettleTimeout: parseInt(process.env.CRAWLER_DOM_SETTLE_TIMEOUT_MS ?? '') || 2000,\n });\n\n await stagehand.init();\n await onProgress?.(5, 'Browser launched');\n // In Stagehand v3, stagehand.page is undefined when connected via CDP.\n // Use resolvePage() to get the active V3Page (which is a full Playwright proxy).\n const page = await (stagehand as any).resolvePage();\n // Cap all Playwright operations so one stuck page can't freeze the crawl.\n try { page.setDefaultTimeout(tuning.defaultTimeoutMs || 45_000); } catch { /* proxy may not expose this */ }\n try { page.setDefaultNavigationTimeout(tuning.navTimeoutMs || 30_000); } catch { /* proxy may not expose this */ }\n // Stagehand V3Page proxy only supports the 'console' event (page.on throws for others).\n // rawPage will be wired to a real Playwright Page via the CDP connection established below.\n // Declared as `let` so the network-observer block can populate it.\n let rawPage: any = null; // populated after playwrightBrowser connects\n\n // \u2500\u2500 Proxy auth \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Proxy 407 auth is answered via a CDP Fetch.continueWithAuth handler installed on\n // the connectOverCDP page below (see \"proxy auth via CDP Fetch handler\"). page.authenticate()\n // is a Puppeteer API \u2014 it does NOT exist on Playwright's connectOverCDP page and throws,\n // leaving 407 challenges unanswered (net::ERR_INVALID_AUTH_CREDENTIALS).\n\n // \u2500\u2500 Stealth: defeat bot detection (Cloudflare, Akamai, DataDome) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // addInitScript runs in every new document context BEFORE any page JS executes.\n // This overrides navigator.webdriver before anti-bot scripts can read it.\n await page.addInitScript(() => {\n // Core automation flags\n Object.defineProperty(navigator, 'webdriver', { get: () => undefined });\n Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });\n\n // Realistic plugin list (Cloudflare checks length > 0)\n const fakePlugins = ['PDF Viewer', 'Chrome PDF Viewer', 'Chromium PDF Viewer', 'Microsoft Edge PDF Viewer', 'WebKit built-in PDF'];\n Object.defineProperty(navigator, 'plugins', {\n get: () => Object.assign(fakePlugins.map((name, i) => ({ name, filename: 'internal-pdf-viewer', description: '', length: 1, item: () => null, namedItem: () => null })), { item: (i: number) => null, namedItem: () => null, refresh: () => { } }),\n });\n\n // @ts-ignore\n window.chrome = { runtime: {}, loadTimes: () => ({}), csi: () => ({}), app: {} };\n\n // Cloudflare checks navigator.permissions.query \u2014 headless returns \"denied\", real = \"prompt\"\n const origQuery = window.navigator.permissions?.query?.bind(navigator.permissions);\n if (origQuery) {\n // @ts-ignore\n navigator.permissions.query = (params: any) =>\n params?.name === 'notifications'\n ? Promise.resolve({ state: 'prompt', onchange: null } as PermissionStatus)\n : origQuery(params);\n }\n\n // Cloudflare checks Notification.permission \u2014 \"denied\" = bot signal\n try { Object.defineProperty(Notification, 'permission', { get: () => 'default' }); } catch { }\n\n // navigator.connection \u2014 absence signals headless\n // @ts-ignore\n if (!navigator.connection) Object.defineProperty(navigator, 'connection', { get: () => ({ rtt: 50, downlink: 10, effectiveType: '4g', saveData: false }) });\n\n // Remove Playwright/CDP globals leaked into page context\n // @ts-ignore\n delete window.__playwright; delete (window as any).__pw_manual; delete (window as any).__PW_inspect;\n });\n\n // \u2500\u2500 Web Vitals capture: LCP + CLS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // LCP/CLS entries are only delivered to a PerformanceObserver registered with\n // buffered:true \u2014 performance.getEntriesByType(...) after the fact returns [].\n // addInitScript re-runs on every new document (survives page.goto navigations),\n // so the observers are always registered before the page paints. The crawl loop\n // reads the stashed values off window.__zetaLCP / window.__zetaCLS after load.\n await page.addInitScript(() => {\n try {\n // @ts-ignore \u2014 custom stash properties\n window.__zetaLCP = null;\n // @ts-ignore\n window.__zetaCLS = 0;\n new PerformanceObserver((list) => {\n const entries = list.getEntries();\n const last = entries[entries.length - 1] as any;\n // @ts-ignore\n if (last) window.__zetaLCP = last.startTime;\n }).observe({ type: 'largest-contentful-paint', buffered: true });\n new PerformanceObserver((list) => {\n for (const entry of list.getEntries() as any[]) {\n // Ignore shifts triggered by user input (crawler clicks/scrolls).\n // @ts-ignore\n if (!entry.hadRecentInput) window.__zetaCLS += entry.value;\n }\n }).observe({ type: 'layout-shift', buffered: true });\n } catch { /* older engines without these entry types \u2014 leave stashed values at defaults */ }\n });\n\n // \u2500\u2500 API/Bearer token injection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // If an authToken is provided, inject it as an HTTP header on every request\n // and store it in localStorage so client-side code can pick it up.\n if (opts.authToken) {\n const headerName = opts.authTokenHeader ?? 'Authorization';\n const prefix = opts.authTokenPrefix ?? 'Bearer ';\n await page.setExtraHTTPHeaders({ [headerName]: `${prefix}${opts.authToken}` });\n await page.addInitScript((token: string) => {\n localStorage.setItem('auth_token', token);\n localStorage.setItem('access_token', token);\n localStorage.setItem('token', token);\n }, opts.authToken);\n }\n\n // \u2500\u2500 Web Vitals capture: CLS via buffered PerformanceObserver \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // CLS entries are only delivered to a PerformanceObserver; this init script\n // re-runs on every new document. LCP is captured per-page in the crawl loop.\n await page.addInitScript(() => {\n try {\n // @ts-ignore \u2014 custom stash property\n window.__zetaCLS = 0;\n new PerformanceObserver((list) => {\n for (const entry of list.getEntries() as any[]) {\n // Ignore shifts triggered by user input (crawler clicks/scrolls).\n // @ts-ignore\n if (!entry.hadRecentInput) window.__zetaCLS += entry.value;\n }\n }).observe({ type: 'layout-shift', buffered: true });\n } catch { /* Older engines without layout-shift entry type \u2014 leave at 0 */ }\n });\n\n // Intercept SPA route changes (history.pushState / replaceState) to discover JS-router routes\n // that have no <a href> elements \u2014 common in React Router, Next.js, Vue Router apps.\n await page.addInitScript(() => {\n (window as any).__zetaDiscoveredRoutes = (window as any).__zetaDiscoveredRoutes ?? [];\n const push = history.pushState.bind(history);\n const replace = history.replaceState.bind(history);\n history.pushState = function (data: any, unused: string, url?: string | URL | null) {\n const result = push(data, unused, url);\n if (url && typeof url === 'string') (window as any).__zetaDiscoveredRoutes.push(url);\n return result;\n };\n history.replaceState = function (data: any, unused: string, url?: string | URL | null) {\n const result = replace(data, unused, url);\n if (url && typeof url === 'string') (window as any).__zetaDiscoveredRoutes.push(url);\n return result;\n };\n });\n\n // Inject canvas/WebGL fingerprint overrides + hardware concurrency spoof\n await injectFingerprintOverrides(page).catch(() => { });\n\n // \u2500\u2500 Network interception: capture REST/GraphQL API endpoints \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Stagehand v3's page proxy only supports the 'console' event \u2014 to intercept\n // network requests we connect a second Playwright client to the same CDP URL.\n const capturedApiEndpoints: ApiEndpointObservationInput[] = [];\n // P3a: URLs flagged for re-visit after async content detected (drained after main BFS)\n const revisitQueue: string[] = [];\n // P4: XHR-discovered page URL candidates (relative paths from JSON responses)\n const xhrDiscoveredPaths = new Set<string>();\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let playwrightBrowser: any = null;\n try {\n playwrightBrowser = await chromium.connectOverCDP(cdpUrl);\n const pwContext = playwrightBrowser.contexts()[0];\n if (pwContext) {\n // P4: pass XHR URL discovery callback \u2014 adds relative paths to xhrDiscoveredPaths\n attachNetworkObserver(pwContext, capturedApiEndpoints, (relPath) => xhrDiscoveredPaths.add(relPath));\n // Popup/new-window handler \u2014 fires for every window.open() call.\n // Handles two cases:\n // 1. OAuth/SSO provider windows \u2014 wait for close, then continue login flow.\n // 2. App-generated popups (help, report, lightbox-in-window) \u2014 screenshot + save as screen.\n const OAUTH_PROVIDER_RE = /google\\.|github\\.|microsoft\\.|facebook\\.|twitter\\.|linkedin\\.|okta\\.|auth0\\.|ping\\.|onelogin\\.|sso\\.|oauth\\.|\\/authorize\\?|\\/oauth2\\//i;\n pwContext.on('page', (popup: any) => {\n // Wait for the popup to navigate to a real URL (about:blank initially)\n popup.waitForURL((u: string) => !u.startsWith('about:'), { timeout: 10_000 })\n .then(async () => {\n const popupUrl = popup.url();\n if (OAUTH_PROVIDER_RE.test(popupUrl)) {\n // OAuth flow \u2014 just wait for it to close\n logger.info({ url: popupUrl }, '[crawler] OAuth popup navigated to provider');\n popup.waitForEvent('close', { timeout: 120_000 })\n .then(() => logger.info('[crawler] OAuth popup closed \u2014 SSO flow complete'))\n .catch(() => logger.warn('[crawler] OAuth popup timed out or errored'));\n return;\n }\n // App popup \u2014 capture as a screen (skip API/export/download URLs)\n try {\n const _popupPath = (() => { try { return new URL(popupUrl).pathname; } catch { return ''; } })();\n if (API_PATH_RE.test(_popupPath) || EXPORT_PATH_RE.test(_popupPath) || DOWNLOAD_EXT_RE.test(_popupPath)) return;\n } catch {}\n logger.info({ url: popupUrl }, '[crawler] App popup detected \u2014 capturing');\n try {\n await popup.waitForLoadState('domcontentloaded', { timeout: 10_000 }).catch(() => {});\n await popup.waitForLoadState('networkidle', { timeout: 6_000 }).catch(() => {});\n const popupTitle = await popup.title().catch(() => '');\n const popupName = popupTitle || (() => { try { return new URL(popupUrl).pathname.split('/').filter(Boolean).pop() || 'Popup'; } catch { return 'Popup'; } })();\n const popupHash = popupUrl.replace(/[^a-z0-9]/gi, '').slice(-12);\n const popupShotPath = path.join(opts.screenshotDir ?? '/tmp', `popup-${popupHash}.png`);\n await waitForScreenshotReady(popup, popup);\n await popup.screenshot({ path: popupShotPath, fullPage: false }).catch(() => {});\n const popupScreen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, popupName, popupUrl, opts.jobId, 'LINK_FOLLOW').catch(() => null);\n if (popupScreen) {\n const cloudUrl = await uploadToCloud(popupShotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(popupShotPath)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, popupScreen.id, popupShotPath, popupScreen.version, 'DESKTOP', cloudUrl).catch(() => {});\n // GAP 4: DOM snapshot for popup capture\n const popupDom = await capturePageHtml(popup);\n if (popupDom) {\n const popupDomPath = popupShotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(popupDomPath, popupDom, 'utf8');\n const popupDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(popupDomPath)}`;\n AppBrain.updateScreenDomSnapshot(opts.tenantId, popupScreen.id, popupDomPath, await uploadToCloud(popupDomPath, popupDomKey).catch(() => undefined)).catch(() => {});\n }\n const popupEls = await domFallbackElements(popup, popup).catch(() => []);\n for (const el of popupEls) {\n AppBrain.saveElement(opts.tenantId, opts.projectId, popupScreen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => {});\n }\n logger.info({ url: popupUrl, name: popupName, elementCount: popupEls.length }, '[crawler] App popup screen saved');\n }\n } catch (popupErr: any) {\n logger.warn({ url: popupUrl, err: popupErr?.message }, '[crawler] App popup capture failed \u2014 non-fatal');\n }\n })\n .catch(() => {}); // popup may close before navigating (race condition)\n });\n // Cancel any file downloads triggered by link navigation \u2014 the crawler captures\n // pages, not binary files. Without this, clicking download links opens the browser\n // download UI and stalls the crawl waiting for a page load that never comes.\n pwContext.on('download', (dl: any) => { dl.cancel().catch(() => {}); });\n\n // Route-level interception: immediately abort navigation to known API/export/download\n // paths that would trigger file downloads. Uses URL-only matching (no double-fetch)\n // to avoid the extra network round-trip that was causing \"Failed to fetch\" crashes.\n // The download event handler above catches any remaining downloads that slip through.\n try {\n await pwContext.route('**/*', async (route: any, request: any) => {\n const resourceType: string = request.resourceType?.() ?? '';\n if (resourceType !== 'document') { await route.continue().catch(() => {}); return; }\n try {\n const u = new URL(request.url());\n if (API_PATH_RE.test(u.pathname) || EXPORT_PATH_RE.test(u.pathname) || DOWNLOAD_EXT_RE.test(u.pathname)) {\n logger.info({ url: request.url() }, '[crawler] route: aborting API/export/download navigation');\n await route.abort('failed').catch(() => {});\n return;\n }\n } catch {}\n await route.continue().catch(() => {});\n });\n } catch (routeErr: any) {\n logger.warn({ err: routeErr?.message }, '[crawler] route interception setup failed \u2014 downloads may occur');\n }\n }\n // Wire rawPage to the real Playwright page from this CDP connection.\n // This gives us a true Playwright Page that supports all events (.on('response'), etc.)\n // while `page` (Stagehand) is still used for AI actions (act/extract/observe).\n const pwContext2 = playwrightBrowser?.contexts()?.[0];\n if (pwContext2) {\n const pwPages = pwContext2.pages();\n rawPage = pwPages.find((p: any) => p.url() !== 'about:blank') ?? pwPages[0] ?? rawPage;\n }\n\n // \u2500\u2500 Proxy auth via CDP Fetch handler \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // launchServer({ proxy }) applies the proxy at the Chrome flag level, but its\n // credentials are only honored by Playwright's OWN launching client. Since we\n // drive the browser through a separate connectOverCDP client, the proxy 407 goes\n // unanswered (net::ERR_INVALID_AUTH_CREDENTIALS). Answer it via the CDP Fetch domain,\n // then disable interception \u2014 Chrome caches the proxy credentials for the rest of the session.\n if (playwrightProxy?.username && pwContext2 && rawPage && rawPage !== page) {\n try {\n const proxyCdp = await pwContext2.newCDPSession(rawPage);\n await proxyCdp.send('Fetch.enable', { handleAuthRequests: true, patterns: [{ urlPattern: '*' }] });\n proxyCdp.on('Fetch.requestPaused', (e: any) => {\n proxyCdp.send('Fetch.continueRequest', { requestId: e.requestId }).catch(() => { });\n });\n let proxyAuthed = false;\n proxyCdp.on('Fetch.authRequired', async (e: any) => {\n const isProxy = e.authChallenge?.source === 'Proxy';\n try {\n await proxyCdp.send('Fetch.continueWithAuth', {\n requestId: e.requestId,\n authChallengeResponse: isProxy\n ? { response: 'ProvideCredentials', username: playwrightProxy!.username as string, password: playwrightProxy!.password ?? '' }\n : { response: 'Default' },\n });\n } catch { /* ignore */ }\n if (isProxy && !proxyAuthed) {\n proxyAuthed = true;\n proxyCdp.send('Fetch.disable').catch(() => { });\n }\n });\n logger.info({ server: playwrightProxy.server }, '[crawler] proxy auth via CDP Fetch handler enabled');\n } catch (e: any) {\n logger.warn({ err: e?.message }, '[crawler] CDP proxy-auth setup failed \u2014 407 may not resolve');\n }\n }\n } catch {\n // Non-fatal \u2014 crawl proceeds without API endpoint capture\n }\n // Final fallback: if rawPage is still null, use the Stagehand page (events may not work)\n if (!rawPage) {\n rawPage = page;\n logger.warn('[crawler] rawPage fell back to Stagehand proxy \u2014 CDP connectOverCDP failed; route() calls will be skipped');\n }\n\n // \u2500\u2500 HTTP Basic Auth: inject Authorization header for same-origin requests \u2500\u2500\u2500\n // Must use rawPage (real Playwright page) \u2014 Stagehand V3Page proxy does not implement route().\n if (opts.httpBasicUsername && opts.httpBasicPassword && typeof rawPage?.route === 'function') {\n const encoded = Buffer.from(`${opts.httpBasicUsername}:${opts.httpBasicPassword}`).toString('base64');\n const appOrigin = new URL(opts.appUrl).origin;\n await rawPage.route('**/*', (route: any) => {\n const reqUrl = route.request().url();\n if (reqUrl.startsWith(appOrigin)) {\n route.continue({\n headers: { ...route.request().headers(), 'Authorization': `Basic ${encoded}` },\n });\n } else {\n route.continue();\n }\n });\n }\n\n // \u2500\u2500 Crawler login bypass: inject internal secret header on login requests \u2500\u2500\u2500\u2500\n // Prevents the per-email rate limiter from blocking re-auth attempts made by\n // the crawler during long crawl sessions. The API verifies the secret before\n // skipping the limiter.\n const crawlerSecret = process.env.CRAWLER_INTERNAL_SECRET;\n if (crawlerSecret && typeof rawPage?.route === 'function') {\n const loginPattern = `${new URL(opts.appUrl).origin}**/auth/login*`;\n await rawPage.route(loginPattern, (route: any) => {\n route.continue({\n headers: { ...route.request().headers(), 'x-zeta-crawler': crawlerSecret },\n });\n });\n }\n\n try {\n // Step 1: Navigate and authenticate\n await onProgress?.(8, 'Loading app');\n // Use explicit timeout \u2014 Stagehand V3Page proxy silently ignores setDefaultNavigationTimeout.\n // Fall back to 'commit' (HTTP response received) if DOM takes too long; page is still usable.\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 30_000 }).catch(async () => {\n await page.goto(opts.appUrl, { waitUntil: 'commit', timeout: 15_000 }).catch(() => { });\n });\n // Auto-accept cookie consent banners \u2014 common EU sites show consent walls before content.\n await acceptCookieConsent(page, { waitMs: 1_000 }).catch(() => { });\n\n // Fail fast if the app URL itself is unreachable \u2014 datacenter IP block, DNS failure, etc.\n if (page.url().startsWith('chrome-error://')) {\n throw new Error(`Cannot reach ${opts.appUrl} \u2014 the server refused the connection (likely IP block or DNS failure). Go to Project Settings \u2192 Connectivity \u2192 Proxy and select \"Auto\" or enter a residential proxy URL.`);\n }\n // Fail fast if Cloudflare or similar bot-protection challenge is served instead of the real app.\n // These pages never contain testable UI \u2014 crawling them produces zero useful screens.\n const initialTitle = await page.title().catch(() => '');\n const isBotChallenge = /^(just a moment|attention required|access denied|ddos protection|cloudflare|checking your browser|enable javascript)/i.test(initialTitle);\n if (isBotChallenge) {\n throw new Error(`Cannot crawl ${opts.appUrl} \u2014 bot protection challenge detected (title: \"${initialTitle}\"). The site is blocking automated browsers. Go to Project Settings \u2192 Connectivity \u2192 Proxy and select \"Auto\" (free proxies) or enter a residential proxy URL to bypass.`);\n }\n // Wait for SPA client-side redirect to complete (e.g. Next.js useEffect router.replace to /login).\n // Without this, loginWithStagehand may run on an empty/loading root page before the form renders.\n await page.waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => { });\n await waitForStableDOM(page);\n\n // Capture homepage fingerprint for soft-404 detection. SPA catch-all routes return HTTP 200\n // but render identical homepage content for every unrecognised path. We fingerprint here\n // (pre-auth, stable DOM) and skip any BFS page that matches during the main crawl.\n const homeFingerprintTitle = await page.title().catch(() => '');\n const homeFingerprintElemCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"]').length\n ).catch(() => -1);\n\n // \u2500\u2500 Pre-auth public-page discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // The page is unauthenticated here. On sites where login redirects users\n // away from the marketing/landing pages (e.g. \"/\" \u2192 app dashboard), BFS\n // (which runs after auth) will never discover those public pages. We extract\n // nav links from the current unauthenticated view and visit/capture each one\n // before the session is applied, so the marketing pages are captured correctly.\n const preAuthPublicCaptured = new Set<string>();\n if (!opts.discoveryMode) {\n const _appOrigin = new URL(opts.appUrl).origin;\n // Simple URL normalizer for pre-auth use (canonicalize() declared later in scope)\n const _norm = (u: string) => { try { const p = new URL(u); p.hash = ''; return p.href.replace(/\\/$/, ''); } catch { return u; } };\n const _startNorm = _norm(opts.appUrl);\n const _authPathRe = /\\/(sign.?in|sign.?up|log.?in|register|auth|oauth|sso|forgot.?password|reset.?password)(\\/|$|\\?)/i;\n const _skipPathRe = /\\/(terms|privacy|legal|cookie-policy|changelog|blog|imprint)([-/]|$)/i;\n\n const publicNavLinks: string[] = await page.evaluate((originStr: string) => {\n return Array.from(document.querySelectorAll('a[href]'))\n .map((a: Element) => {\n try {\n const u = new URL((a as HTMLAnchorElement).getAttribute('href')!, window.location.href);\n return u.origin === originStr ? u.href.split('#')[0] : '';\n } catch { return ''; }\n })\n .filter((h: string, i: number, arr: string[]) => h && arr.indexOf(h) === i)\n .slice(0, 50);\n }, _appOrigin).catch(() => [] as string[]);\n\n for (const link of publicNavLinks) {\n if (_norm(link) === _startNorm) continue;\n try {\n const { pathname } = new URL(link);\n if (_authPathRe.test(pathname) || _skipPathRe.test(pathname) || API_PATH_RE.test(pathname) || EXPORT_PATH_RE.test(pathname) || DOWNLOAD_EXT_RE.test(pathname)) continue;\n await page.goto(link, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => {});\n await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => {});\n const finalUrl = page.url();\n const finalPath = new URL(finalUrl).pathname;\n if (_authPathRe.test(finalPath)) continue; // redirected to auth \u2014 skip\n if (_norm(finalUrl) === _startNorm) continue; // SPA catch-all redirect\n // Read interactive elements first \u2014 SPA pages show 0 elements without auth.\n // Only lock as pre-auth if the page actually has content; otherwise BFS handles it authenticated.\n const preAuthElements = await readScreen(page).catch(() => [] as Awaited<ReturnType<typeof readScreen>>);\n if (preAuthElements.length === 0) {\n logger.info({ url: finalUrl }, '[crawler] pre-auth page has 0 elements \u2014 deferring to authenticated BFS');\n continue;\n }\n // Detect auth walls that have a tiny number of elements (login button, back link, spinner).\n // These pages redirect or gate on auth \u2014 main BFS must visit them with a live session.\n // Label prefix or exact match \u2014 \"Back to Learn\" matches \"back to\", \"Sign In\" matches \"sign in\"\n const AUTH_WALL_LABEL_RE = /^(sign.?in|log.?in|login|platform access|back\\s+to|checking\\s+auth|get started|create account|register|continue with|join now)/i;\n // Also treat pages with only `a`-role elements (no inputs/buttons) as likely auth walls\n const allAnchorOnly = preAuthElements.every(el => el.role === 'a');\n const looksLikeAuthWall = preAuthElements.length <= 3 && (allAnchorOnly || preAuthElements.every(el => AUTH_WALL_LABEL_RE.test(el.label)));\n if (looksLikeAuthWall) {\n logger.info({ url: finalUrl, elements: preAuthElements.length, labels: preAuthElements.map(e => e.label) }, '[crawler] pre-auth auth wall \u2014 deferring to authenticated BFS');\n continue;\n }\n const pathParts = finalPath.split('/').filter(Boolean);\n const screenName = pathParts.map((p: string) => p.charAt(0).toUpperCase() + p.slice(1).replace(/[-_]/g, ' ')).join(' \u2014 ') || 'Home';\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, screenName, finalUrl, opts.jobId, 'LINK_FOLLOW').catch(() => null);\n if (!screen) continue;\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `${screen.id}-desktop-v${screen.version}.png`);\n // TODO GAP-09: pass opts.screenshotConfig (width/height/quality) here when screenshotConfig is wired into the opts type.\n await page.screenshot({ path: shotPath, fullPage: true }).catch(() => {});\n const cloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`).catch(() => undefined);\n await (AppBrain.saveScreenshot as any)(opts.tenantId, opts.projectId, screen.id, shotPath, screen.version, 'DESKTOP', cloudUrl).catch(() => {});\n // GAP 5: DOM snapshot for pre-auth public page discovery\n const pubDom = await capturePageHtml(page);\n if (pubDom) {\n const pubDomPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(pubDomPath, pubDom, 'utf8');\n const pubDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(pubDomPath)}`;\n AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, pubDomPath, await uploadToCloud(pubDomPath, pubDomKey).catch(() => undefined)).catch(() => {});\n }\n // Save elements found in the pre-auth view\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, screen.id).catch(() => {});\n for (const el of preAuthElements) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.label, el.role, el.expectedData, undefined, undefined, true, undefined, undefined, undefined).catch(() => {});\n }\n preAuthPublicCaptured.add(finalUrl);\n logger.info({ url: finalUrl, screenId: screen.id, elements: preAuthElements.length }, '[crawler] pre-auth public page captured');\n } catch (err: any) {\n logger.warn({ url: link, err: err?.message }, '[crawler] pre-auth public page visit failed \u2014 skipping');\n }\n }\n\n // Navigate back to start so auth phase and fingerprint comparison are correct\n if (preAuthPublicCaptured.size > 0) {\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 20_000 }).catch(() => {});\n await page.waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => {});\n }\n }\n\n // Dedicated logged-out/auth discovery phase. This runs before credentials or\n // storageState are applied, so public pages and auth recovery flows remain\n // visible even when the main crawl later becomes authenticated.\n if (!opts.discoveryMode) {\n try {\n await runAuthDiscoveryPhase(page, opts, new URL(opts.appUrl).origin, onProgress);\n } catch (preAuthErr) {\n logger.warn({ err: preAuthErr }, '[crawler] auth-discovery phase failed \u2014 continuing with authenticated crawl');\n }\n }\n\n // Auth discovery opens OAuth sign-in popups (Google, GitHub, etc.) which fire CDP events that\n // can permanently corrupt the Playwright isolated world. Verify the world is intact; if not,\n // re-navigate to appUrl to force a fresh execution context before BFS begins.\n {\n const worldOk = await page.evaluate(() => true).catch(() => false);\n if (!worldOk) {\n logger.warn('[crawler] isolated world corrupted after auth discovery \u2014 re-navigating to recover');\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => {});\n await page.waitForLoadState('networkidle', { timeout: 6_000 }).catch(() => {});\n }\n }\n\n let didLogin = false; // track whether AI login was actually performed\n\n if (opts.authToken) {\n // Auth token already injected via setExtraHTTPHeaders + addInitScript above.\n // Skip session restore and AI login entirely.\n await onProgress?.(18, 'API token configured \u2014 skipping login');\n logger.info('authToken provided \u2014 skipping AI login');\n } else if (effectiveStorageState) {\n // \u2500\u2500 StorageState session restore: skip AI login entirely \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // User authenticated once via `npx playwright codegen --save-storage=session.json`\n // and saved the resulting JSON in crawl config (encrypted at rest).\n // effectiveStorageState may also come from Chrome profile inheritance (GAP 3).\n logger.info('StorageState found \u2014 restoring session, skipping AI login');\n try {\n const state = JSON.parse(effectiveStorageState!) as {\n cookies?: Array<Record<string, any>>;\n origins?: Array<{ origin: string; localStorage: Array<{ name: string; value: string }> }>;\n };\n\n if (state.cookies?.length) {\n // Apply cookies to both the secondary Playwright context AND Stagehand's own context.\n // Stagehand V3 uses a separate browser context from the CDP secondary client, so\n // cookies added only to playwrightBrowser.contexts()[0] don't reach Stagehand's pages.\n const browserCtx = playwrightBrowser?.contexts()[0];\n if (browserCtx) {\n await browserCtx.addCookies(state.cookies as any);\n }\n // Also apply to Stagehand's context via its page proxy\n try {\n const stagehandCtx = (page as any).context?.();\n if (stagehandCtx && typeof stagehandCtx.addCookies === 'function') {\n await stagehandCtx.addCookies(state.cookies as any);\n }\n } catch { /* Stagehand V3 proxy may not expose context() */ }\n }\n\n if (state.origins?.length) {\n // Apply localStorage via addInitScript to ALL contexts:\n // 1. Secondary Playwright context (rawPage navigations)\n // 2. Stagehand's page directly (Stagehand V3 uses its own context separate from playwrightBrowser)\n // Without #2, Stagehand's BFS navigations never get localStorage \u2192 pages load unauthenticated.\n const originCtx = playwrightBrowser?.contexts()[0];\n if (originCtx) {\n await originCtx.addInitScript((origins: typeof state.origins) => {\n for (const entry of (origins ?? [])) {\n if (window.location.origin === entry.origin) {\n for (const item of entry.localStorage) {\n try { localStorage.setItem(item.name, item.value); } catch { /* quota/sandboxed */ }\n }\n }\n }\n }, state.origins);\n }\n // Stagehand's page \u2014 covers all BFS navigations via Stagehand\n await page.addInitScript((origins: typeof state.origins) => {\n for (const entry of (origins ?? [])) {\n if (window.location.origin === entry.origin) {\n for (const item of entry.localStorage) {\n try { localStorage.setItem(item.name, item.value); } catch { /* quota/sandboxed */ }\n }\n }\n }\n }, state.origins);\n // Also cover rawPage for the initial navigation below\n await rawPage.addInitScript((origins: typeof state.origins) => {\n for (const entry of (origins ?? [])) {\n if (window.location.origin === entry.origin) {\n for (const item of entry.localStorage) {\n try { localStorage.setItem(item.name, item.value); } catch { /* quota/sandboxed */ }\n }\n }\n }\n }, state.origins);\n }\n\n // Navigate to appUrl with cookies now set.\n // We MUST navigate to appUrl (not reload current page) because the initial\n // goto ran without cookies and was redirected to /login. Reloading /login stays\n // at /login even with a valid cookie (public path, no auth redirect). Navigating\n // to appUrl lets server middleware see the cookie and route to the authenticated app.\n await onProgress?.(12, 'Restoring session');\n await rawPage.goto(opts.appUrl, { waitUntil: 'domcontentloaded' }).catch(() => { });\n await waitForStableDOM(page);\n // SPA root pages redirect client-side (useEffect \u2192 router.replace). Wait for it.\n if (page.url() === opts.appUrl || page.url() === opts.appUrl.replace(/\\/$/, '')) {\n await waitForURLChange(page, opts.appUrl).catch(() => { });\n await waitForStableDOM(page);\n }\n\n // Detect if session restore failed \u2014 either by URL redirect or login form presence on root URL\n const postRestoreUrl = page.url();\n const LOGIN_PATH = /\\/(login|signin|sign-in|auth|log-in|sso|oauth|account\\/login)(\\/|$|\\?)/i;\n const ERROR_PATH = /\\/(session-expired|expired|unauthorized|forbidden|401|403|error|logout|logged-out)(\\/|$|\\?)/i;\n const redirectedToLogin = LOGIN_PATH.test(new URL(postRestoreUrl).pathname);\n const redirectedToError = ERROR_PATH.test(new URL(postRestoreUrl).pathname);\n // Also check for login form presence \u2014 catches apps where login page is at root URL (e.g. /)\n const hasLoginForm = await page.evaluate(() => {\n const inputs = Array.from(document.querySelectorAll('input'));\n const hasEmailOrUser = inputs.some((i: any) =>\n ['email', 'username', 'user', 'login'].some((k) =>\n (i.type || '').includes(k) || (i.name || '').toLowerCase().includes(k) ||\n (i.id || '').toLowerCase().includes(k) || (i.placeholder || '').toLowerCase().includes(k)\n )\n );\n const hasPasswordField = inputs.some((i: any) => i.type === 'password');\n return hasEmailOrUser && hasPasswordField;\n }).catch(() => false);\n const sessionFailed = redirectedToLogin || redirectedToError || hasLoginForm;\n if (sessionFailed) {\n logger.warn({ url: postRestoreUrl, loginForm: hasLoginForm, errorUrl: redirectedToError }, 'StorageState restore failed \u2014 session may be expired');\n // Clear the expired session from DB so user is forced to re-capture\n await AppBrain.saveCrawlConfig(opts.tenantId, opts.projectId, { storageState: null }).catch(() => { });\n // Navigate to the login page. First try appUrl \u2014 if it still redirects to an error/login\n // path, probe common login paths at the app origin so Stagehand finds a real login form.\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded' }).catch(() => { });\n await waitForStableDOM(page);\n const urlAfterNav = page.url();\n const stillAtError = ERROR_PATH.test(new URL(urlAfterNav).pathname) || LOGIN_PATH.test(new URL(urlAfterNav).pathname);\n if (stillAtError) {\n const appOrigin = new URL(opts.appUrl).origin;\n for (const loginPath of ['/login', '/signin', '/sign-in', '/auth/login', '/auth']) {\n try {\n await page.goto(`${appOrigin}${loginPath}`, { waitUntil: 'domcontentloaded' });\n const hasForm = await page.evaluate(() => {\n const inputs = Array.from(document.querySelectorAll('input'));\n return inputs.some((i: any) => i.type === 'password');\n }).catch(() => false);\n if (hasForm) { logger.info({ loginPath }, 'Found login form at path'); break; }\n } catch { /* continue to next path */ }\n }\n await waitForStableDOM(page);\n }\n if (opts.credentials) {\n logger.info('Falling back to AI login with credentials');\n await onProgress?.(15, 'Session expired \u2014 logging in with credentials\u2026');\n const loggedIn = await loginWithStagehand(stagehand, opts.credentials, opts.appUrl, { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider }, { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId }, opts.loginInstructions, { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId });\n if (!loggedIn) throw new Error('[SESSION_EXPIRED] Stored session expired and credential login also failed. Check your username / password in Project Settings \u2192 Credentials.');\n didLogin = true;\n } else {\n throw new Error('[SESSION_EXPIRED] Stored session has expired. Please re-capture your session in Project Settings \u2192 Advanced: Session Capture, or add username / password as a login fallback.');\n }\n } else {\n await onProgress?.(18, 'Session restored');\n logger.info({ url: postRestoreUrl }, 'Session restored');\n }\n } catch (err) {\n const msg = String((err as Error).message ?? err);\n // Re-throw errors we threw intentionally above\n if (msg.includes('[SESSION_EXPIRED]') || msg.includes('expired')) throw err;\n logger.warn({ err }, 'StorageState restore failed, falling back to AI login');\n if (opts.credentials) {\n await onProgress?.(15, 'Session restore failed \u2014 logging in with credentials\u2026');\n const loggedIn = await loginWithStagehand(stagehand, opts.credentials, opts.appUrl, { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider }, { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId }, opts.loginInstructions, { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId });\n if (!loggedIn) throw new Error('[SESSION_EXPIRED] Session restore failed and credential login also failed. Check your username / password in Project Settings \u2192 Credentials.');\n didLogin = true;\n } else {\n throw new Error('[SESSION_EXPIRED] Session restore failed and no credentials were provided. Please re-capture your session in Project Settings \u2192 Advanced: Session Capture.');\n }\n }\n } else if (opts.ssoProvider && opts.ssoDomain && opts.ssoClientId && opts.credentials) {\n // \u2500\u2500 GAP 18: SSO ROPC flow \u2014 bypass browser login entirely \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Get a token directly from the IdP and inject it as a Bearer header.\n await onProgress?.(12, 'SSO: fetching token from identity provider');\n try {\n const ssoToken = await getSsoToken(\n {\n provider: opts.ssoProvider as any,\n domain: opts.ssoDomain,\n clientId: opts.ssoClientId,\n clientSecret: opts.ssoClientSecret,\n scope: opts.ssoScope,\n },\n opts.credentials.username,\n opts.credentials.password\n );\n await page.setExtraHTTPHeaders({ 'Authorization': `Bearer ${ssoToken}` });\n await page.addInitScript((t: string) => {\n localStorage.setItem('access_token', t);\n localStorage.setItem('auth_token', t);\n localStorage.setItem('token', t);\n }, ssoToken);\n await page.reload({ waitUntil: 'domcontentloaded' });\n didLogin = true;\n await onProgress?.(18, 'SSO token injected');\n logger.info({ provider: opts.ssoProvider }, '[crawler] SSO token obtained and injected');\n } catch (ssoErr) {\n logger.warn({ err: ssoErr }, '[crawler] SSO token retrieval failed \u2014 falling back to browser login');\n // Fall through to browser-based login\n await onProgress?.(12, 'Logging in');\n didLogin = true;\n const loggedIn = await loginWithStagehand(stagehand, opts.credentials, opts.appUrl, { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider }, { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId }, opts.loginInstructions, { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId });\n if (!loggedIn) {\n logger.warn('Stagehand login failed \u2014 trying Skyvern vision fallback');\n await onProgress?.(14, 'Trying vision fallback');\n const skyvernResult = await skyvernFallback({\n taskDescription: `Log in to ${opts.appUrl} using username \"${opts.credentials.username}\" and navigate to the main dashboard.`,\n url: opts.appUrl,\n credentials: opts.credentials,\n }, opts.skyvernConfig);\n if (skyvernResult === 'failed') {\n throw new Error(\n 'Login failed on both Stagehand (DOM) and Skyvern (vision). ' +\n 'Check credentials. For CAPTCHA/SSO sites, set SKYVERN_API_URL + SKYVERN_API_KEY.'\n );\n }\n }\n await onProgress?.(18, 'Logged in');\n }\n } else if (opts.credentials) {\n await onProgress?.(12, 'Logging in');\n didLogin = true;\n const loggedIn = await loginWithStagehand(stagehand, opts.credentials, opts.appUrl, { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider }, { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId }, opts.loginInstructions, { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId });\n if (!loggedIn) {\n logger.warn('Stagehand login failed \u2014 trying Skyvern vision fallback');\n await onProgress?.(14, 'Trying vision fallback');\n const skyvernResult = await skyvernFallback({\n taskDescription: `Log in to ${opts.appUrl} using username \"${opts.credentials.username}\" and navigate to the main dashboard.`,\n url: opts.appUrl,\n credentials: opts.credentials,\n }, opts.skyvernConfig);\n if (skyvernResult === 'failed') {\n throw new Error(\n 'Login failed on both Stagehand (DOM) and Skyvern (vision). ' +\n 'Check credentials. For CAPTCHA/SSO sites, set SKYVERN_API_URL + SKYVERN_API_KEY.'\n );\n }\n }\n await onProgress?.(18, 'Logged in');\n } else {\n await onProgress?.(18, 'No auth needed');\n }\n\n // Step 2: Crawl\n // If we just logged in (via credentials or session-fallback), capture and persist the new\n // session state so the next crawl reuses it without logging in again.\n if (didLogin) {\n try {\n const freshState = await playwrightBrowser!.contexts()[0]?.storageState();\n if (freshState) {\n await AppBrain.saveCrawlConfig(opts.tenantId, opts.projectId, { storageState: JSON.stringify(freshState) });\n logger.info('Fresh session state captured and saved after credential login');\n await onProgress?.(19, 'Session saved \u2014 will reuse on next crawl');\n }\n } catch (e) {\n logger.warn({ err: e }, 'Could not save refreshed session state \u2014 crawl will continue');\n }\n // Wait for SPA router to complete the post-login redirect before seeding the queue.\n // Without this, Next.js/React apps queue the login URL instead of the dashboard URL.\n await waitForURLChange(page, opts.appUrl);\n }\n const origin = new URL(page.url()).origin;\n const maxScreens = opts.maxScreens ?? Infinity;\n const segmentSize = opts.segmentSize ?? 9_999_999; // effectively unlimited \u2014 segments only exist for checkpointing reliability\n // selective = exact-URL-only mode (recrawl selected screens, no link discovery)\n const selective = !!(opts.selectiveUrls && opts.selectiveUrls.length > 0);\n\n // Mark all screens for this project as active \u2014 post-crawl we'll diff which ones weren't re-discovered.\n if (!selective) {\n await AppBrain.prepareForRecrawl(opts.tenantId, opts.projectId, opts.jobId);\n await AppBrain.clearFlows(opts.tenantId, opts.projectId);\n }\n // Canonicalize URL for dedup: strip tracking params + normalize dynamic ID segments.\n // Prevents /projects/cuid1 and /projects/cuid2 from being queued as separate screens.\n const canonicalize = (raw: string): string => {\n try {\n const u = new URL(raw);\n // Treat www and non-www as the same host \u2014 most sites redirect one to the other\n // but internal links may be inconsistent, causing duplicate crawl entries otherwise.\n u.hostname = u.hostname.replace(/^www\\./, '');\n // Strip params that don't change page content\n [\n 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'ref', 'source', '_gl', 'fbclid', 'gclid',\n 'ts', 'timestamp', 'cache', 'cacheBust', 'cache_bust', '_', 'nonce', 'session', 'sid',\n // App content/state params \u2014 these change the content rendered within the same\n // page template (a playground example, a search query, a tab selection) but do NOT\n // represent structurally distinct pages. Not stripping them causes URL explosion:\n // every unique ?cmd=DSN-XXXXX&example=... or ?q=foo is queued as a new screen.\n 'cmd', 'example', 'query', 'q', 'search', 'keyword', 'keywords',\n 'tab', 'view', 'mode', 'sort', 'order', 'direction', 'orderby',\n 'page', 'p', 'offset', 'limit', 'per_page', 'size', 'rows',\n // Export format params \u2014 same endpoint, different output format, not a new screen\n 'format', 'output', 'export_format', 'download_format', 'fileformat', 'file_format',\n // WooCommerce / e-commerce action params\n 'add-to-cart', 'add_to_wishlist', 'quantity', 'wc-ajax',\n 'min_price', 'max_price', 'removed_item', 'restore', 'remove_item',\n 'undo_item', 'coupon_code', 'apply_coupon', 'added-to-cart',\n 'wc_error', 'wc_notice', 'wc_notice_type', 'update_cart',\n 'proceed', '_wpnonce', 'post_type', 'product_cat',\n // WooCommerce facet/layered-nav filter params \u2014 each combination generates a unique URL\n // but all render the same template; not stripping these causes infinite URL explosion\n // (N filter options \u00D7 M values = exponential queue growth)\n 'filter_color', 'filter_colour', 'filter_size', 'filter_brand', 'filter_category',\n 'filter_rating', 'filter_stock_status', 'filter_pa_color', 'filter_pa_size',\n 'filter_pa_brand', 'filter_pa_material', 'filter_pa_weight', 'filter_pa_style',\n 'filter_pa_gender', 'filter_pa_age', 'filter_pa_type', 'filter_pa_pattern',\n 'query_type_color', 'query_type_size', 'query_type_brand', 'query_type_pa_color',\n 'query_type_pa_size', 'query_type_pa_brand', 'in_stock', 'on_sale',\n // Shopify facet filters\n 'sort_by', 'constraint', 'filter.p.tag', 'filter.v.price.gte', 'filter.v.price.lte',\n 'filter.p.m.global.color', 'filter.p.m.global.size',\n ].forEach(p => u.searchParams.delete(p));\n // Strip any remaining filter_* / query_type_* / filter.* params (WooCommerce/Shopify facets)\n for (const key of Array.from(u.searchParams.keys())) {\n if (/^filter[._]|^query_type_/i.test(key)) u.searchParams.delete(key);\n }\n u.searchParams.sort();\n // Normalize dynamic segments globally: UUIDs, CUIDs, long numeric IDs,\n // and hyphenated numeric record IDs under any parent route.\n u.pathname = u.pathname\n .replace(/\\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?=\\/|$)/gi, '/{id}')\n .replace(/\\/c[a-z0-9]{20,}(?=\\/|$)/g, '/{id}')\n .replace(/\\/\\d{4,}(?=\\/|$)/g, '/{id}')\n // Hyphenated numeric IDs: digits-digits (e.g. 0-9638, 12-4567). Not UUIDs (hex only).\n .replace(/\\/\\d+-\\d+(?=\\/|$)/g, '/{id}')\n .replace(/\\/+$/, '') || '/';\n // Hash-routed SPAs put the actual route in the fragment (\"#/dashboard\",\n // \"#!/settings\") \u2014 keep it so distinct routes dedup separately instead\n // of every hash-route collapsing onto one canonical (hashless) URL.\n if (!/^#!?\\//.test(u.hash)) u.hash = '';\n return u.toString();\n } catch { return raw; }\n };\n\n const gitInfo = getGitInfo();\n\n const visited = new Map<string, string>(); // key = canonical URL\n const crawlWarnings: string[] = []; // non-fatal step failures surfaced in job result\n // Pre-populate from a previous failed job so already-captured URLs are skipped\n if (opts.skipUrls?.length) {\n for (const u of opts.skipUrls) visited.set(canonicalize(u), 'skipped');\n }\n // Pre-auth public pages already captured above \u2014 mark visited so BFS (post-auth)\n // doesn't overwrite them with authenticated redirects showing app content instead.\n for (const u of preAuthPublicCaptured) visited.set(canonicalize(u), 'pre-auth');\n let checkpointSuccessCount = 0;\n let maxSeenTotal = 0; // track high-water mark so progress % never goes backwards\n let lastEmittedPct = 20; // floor above auth-discovery + login phases (max ~19%)\n const crawlLoopStart = Date.now();\n // Global crawl timeout \u2014 prevent BFS from hanging indefinitely on large apps.\n // Default 2 hours; override via CRAWL_GLOBAL_TIMEOUT_MS env var.\n const CRAWL_GLOBAL_TIMEOUT_MS = parseInt(process.env.CRAWL_GLOBAL_TIMEOUT_MS ?? '') || 2 * 60 * 60 * 1000;\n const isCrawlTimedOut = () => (Date.now() - crawlLoopStart) >= CRAWL_GLOBAL_TIMEOUT_MS;\n const startUrl = page.url();\n // Resume from previous segment's pending queue if provided\n const resumeUrls = opts.resumeUrls ?? [];\n // Sitemap-discovered URLs are additional seeds (not a replacement for\n // link-following) \u2014 merged in below unless this is a selective\n // (\"crawl only these URLs\") run or a resumed segment, matching how\n // GraphQL auto-introspection \u2014 fire-and-forget, stored in crawl metadata\n const gqlIntrospectionPromise = (async () => {\n const gqlEndpoints = guessGraphQLEndpoints(opts.appUrl);\n for (const ep of gqlEndpoints) {\n const result = await introspectGraphQL(ep, { timeoutMs: 5_000 }).catch(() => null);\n if (result?.schema) {\n logger.info({ endpoint: ep, typeCount: result.schema.types.length }, '[crawler] GraphQL schema discovered');\n return result;\n }\n }\n return null;\n })();\n\n // seedUrls itself works. Best-effort: discoverSitemapUrls() never throws.\n const sitemapUrls = (opts.useSitemap && !selective && resumeUrls.length === 0)\n ? await discoverSitemapUrls(opts.appUrl, opts.sitemapUrl)\n : [];\n // Filter bad URLs out of resumeUrls (generated dynamic routes from prior segments)\n const filteredResumeUrls = resumeUrls.filter(u => {\n try { return !isGeneratedDynamicPath(new URL(u).pathname); } catch { return true; }\n });\n const seedUrls = selective\n ? opts.selectiveUrls!\n : filteredResumeUrls.length > 0\n ? filteredResumeUrls\n : [\n startUrl,\n // User-configured seed URLs added to queue; link discovery still runs from each.\n ...(opts.startUrls ?? []).filter((u) => canonicalize(u) !== canonicalize(startUrl)),\n ...sitemapUrls.filter((u) => canonicalize(u) !== canonicalize(startUrl)),\n ];\n const queued = new Set<string>(seedUrls.map(canonicalize));\n const queue = new CrawlFrontier(opts.traversalStrategy ?? 'BFS', seedUrls, opts.bestFirstKeywords, opts.urlFilter, opts.includePatterns, opts.excludePatterns);\n // Selective recrawl: block all link-discovery pushes so BFS only visits the requested URLs.\n // Constructor seeding already ran above \u2014 this no-op override fires only for BFS-loop discoveries.\n if (selective) {\n queue.push = () => {};\n }\n const deduplicator = new ContentDeduplicator(parseFloat(process.env.CRAWLER_DEDUP_THRESHOLD ?? '') || 0.88);\n const deadLinkTracker = new DeadLinkTracker();\n const redirectRegistry = new RedirectRegistry();\n // Re-seed from previously-discovered screens so deep routes found by AI link\n // discovery in prior crawls aren't lost when a recrawl starts from scratch.\n // Doc 41 Option D: orphan-classified screens (no inbound nav edges) get a BEST_FIRST\n // score boost via parentElements:0 so they're visited early in the next crawl.\n // Only applies to full recrawls (not selective runs or segment resumptions).\n if (!selective && resumeUrls.length === 0) {\n try {\n const priorMap = projectForProfile ?? await AppBrain.getProjectMap(opts.tenantId, opts.projectId);\n const orphanReport = await AppBrain.getOrphanScreens(opts.tenantId, opts.projectId).catch(() => null);\n const orphanIdSet = new Set<string>(\n (orphanReport?.screens ?? [])\n .filter((s: any) => s.classification !== 'REACHABLE')\n .map((s: any) => s.id as string),\n );\n // Snapshot queued set BEFORE filter so canonical dedup works correctly during filter.\n // Without this, multiple prior screens with the same canonical (e.g. playground?cmd=X1,\n // playground?cmd=X2 \u2192 same canonical) all pass the filter since queued isn't updated yet.\n const seenReseedCanon = new Set<string>(queued);\n const priorScreens = (priorMap?.screens ?? [])\n .filter((s: any) => s.status !== 'PENDING_REMOVAL')\n .filter((s: any) => {\n const u = s.url as string | null;\n if (!u) return false;\n try {\n const { pathname } = new URL(u);\n const stripWww = (h: string) => h.replace(/^www\\./i, '').toLowerCase();\n if (stripWww(new URL(u).hostname) !== stripWww(new URL(startUrl).hostname)) return false;\n // Don't re-seed generated dynamic routes \u2014 they produce duplicate templates.\n // Exception: seed path patterns explicitly declared by the caller.\n if (isGeneratedDynamicPath(pathname) && !_activeSeedPatterns.some(re => re.test(pathname))) return false;\n // Don't re-seed API/export/download paths \u2014 they were misidentified as screens.\n if (!isUsefulNavigationUrl(u, startUrl)) return false;\n // Canonical dedup: mark seen immediately during filter so duplicates are caught.\n const canon = canonicalize(u);\n if (seenReseedCanon.has(canon)) return false;\n seenReseedCanon.add(canon);\n return true;\n } catch { return false; }\n });\n let orphanSeedCount = 0;\n for (const s of priorScreens) {\n const u = s.url as string;\n queued.add(canonicalize(u));\n const isOrphan = orphanIdSet.has(s.id as string);\n queue.push(u, isOrphan ? { parentElements: 0 } : undefined);\n if (isOrphan) orphanSeedCount++;\n }\n if (priorScreens.length > 0) {\n logger.info(\n { count: priorScreens.length, orphanBoosted: orphanSeedCount },\n '[crawler] re-seeded prior screen URLs from DB',\n );\n }\n } catch (err) {\n logger.warn({ err: String(err) }, '[crawler] non-fatal: could not load prior screen URLs for re-seeding');\n }\n }\n // G11: Pre-auth sitemap discovery \u2014 capture public pages before session injection.\n // Many apps have marketing/pricing/docs pages only reachable without auth.\n // We fetch the sitemap, visit each URL, and screenshot pages that DON'T redirect to login.\n if (opts.useSitemap !== false) {\n const g11SitemapUrls: string[] = [];\n const sitemapCandidates = [\n `${opts.appUrl.replace(/\\/$/, '')}/sitemap.xml`,\n `${opts.appUrl.replace(/\\/$/, '')}/sitemap_index.xml`,\n `${opts.appUrl.replace(/\\/$/, '')}/robots.txt`,\n ];\n const LOGIN_REDIRECT_PATH = /\\/(login|signin|sign-in|auth|log-in)(\\/|$|\\?)/i;\n\n try {\n for (const candidate of sitemapCandidates) {\n try {\n const resp = await fetch(candidate, { signal: AbortSignal.timeout(8_000) }).catch(() => null);\n if (!resp?.ok) continue;\n const text = await resp.text();\n if (candidate.endsWith('robots.txt')) {\n const sitemapLines = text.split('\\n').filter((l: string) => l.toLowerCase().startsWith('sitemap:'));\n for (const line of sitemapLines) {\n const u = line.split(':').slice(1).join(':').trim();\n if (u) sitemapCandidates.push(u);\n }\n continue;\n }\n const locs = text.match(/<loc>([^<]+)<\\/loc>/gi) ?? [];\n for (const loc of locs) {\n const u = loc.replace(/<\\/?loc>/gi, '').trim();\n if (u.startsWith('http')) g11SitemapUrls.push(u);\n }\n if (g11SitemapUrls.length > 0) break;\n } catch { /* try next candidate */ }\n }\n\n if (g11SitemapUrls.length > 0) {\n logger.info({ count: g11SitemapUrls.length }, '[crawler] G11: sitemap discovered public URL candidates');\n const sitemapOrigin = new URL(opts.appUrl).origin;\n let sitemapCaptured = 0;\n for (const sUrl of g11SitemapUrls) {\n if (isCrawlTimedOut()) break;\n try {\n const u = new URL(sUrl);\n if (u.origin !== sitemapOrigin) continue;\n if (API_PATH_RE.test(u.pathname) || EXPORT_PATH_RE.test(u.pathname) || DOWNLOAD_EXT_RE.test(u.pathname)) continue;\n await page.goto(sUrl, { waitUntil: 'domcontentloaded', timeout: 12_000 });\n await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => { });\n await waitForStableDOM(page);\n const landedUrl = page.url();\n if (LOGIN_REDIRECT_PATH.test(new URL(landedUrl).pathname)) {\n const canon = canonicalize(sUrl);\n if (!queued.has(canon)) { queued.add(canon); queue.push(sUrl); }\n logger.info({ url: sUrl }, '[crawler] G11: sitemap URL requires auth \u2014 added to BFS queue');\n continue;\n }\n const pagePath = u.pathname.replace(/^\\//, '') || 'home';\n const pageName = pagePath.split('/').map((s: string) => s.charAt(0).toUpperCase() + s.slice(1)).join(' ') || 'Home';\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `sitemap-preauth-${sitemapCaptured}.png`);\n await waitForScreenshotReady(page);\n await page.screenshot({ path: shotPath, fullPage: true }).catch(() => { });\n const pubScreen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, pageName, sUrl, opts.jobId, 'SITEMAP').catch(() => null);\n if (pubScreen) {\n const sitemapCloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, pubScreen.id, shotPath, pubScreen.version, 'DESKTOP', sitemapCloudUrl).catch(() => { });\n // GAP 2: DOM snapshot for G11 pre-auth sitemap path\n const sitemapDom = await capturePageHtml(page);\n if (sitemapDom) {\n const sitemapDomPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(sitemapDomPath, sitemapDom, 'utf8');\n const sitemapDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(sitemapDomPath)}`;\n const sitemapDomCloud = await uploadToCloud(sitemapDomPath, sitemapDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, pubScreen.id, sitemapDomPath, sitemapDomCloud).catch(() => {});\n }\n logger.info({ url: sUrl, name: pageName }, '[crawler] G11: captured public sitemap page');\n }\n sitemapCaptured++;\n } catch (sitemapPageErr) {\n logger.warn({ url: sUrl, err: String(sitemapPageErr) }, '[crawler] G11: sitemap page failed \u2014 skipping');\n }\n }\n logger.info({ captured: sitemapCaptured }, '[crawler] G11: pre-auth sitemap capture complete');\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => { });\n await waitForStableDOM(page);\n }\n } catch (sitemapErr) {\n logger.warn({ err: String(sitemapErr) }, '[crawler] G11: pre-auth sitemap discovery failed \u2014 continuing');\n }\n }\n\n // Discovery-method tracking for orphan-page detection (see AppBrain.getOrphanScreens):\n // the entry point is never an \"orphan\" candidate; anything else in the initial seed\n // batch is a configured seed URL (sitemap-discovered URLs included), not something\n // reached by following a link.\n const canonicalEntryUrl = canonicalize(startUrl);\n const canonicalSitemapUrls = new Set(sitemapUrls.map(canonicalize));\n const canonicalSeedUrls = new Set(seedUrls.map(canonicalize));\n const discoveryMethodFor = (url: string): 'ENTRY_POINT' | 'SEED_URL' | 'SITEMAP' | 'LINK_FOLLOW' => {\n const c = canonicalize(url);\n if (c === canonicalEntryUrl) return 'ENTRY_POINT';\n if (canonicalSitemapUrls.has(c)) return 'SITEMAP';\n if (canonicalSeedUrls.has(c)) return 'SEED_URL';\n return 'LINK_FOLLOW';\n };\n const edges: Array<{ fromUrl: string; toUrl: string }> = [];\n const pendingTransitions: Array<{ fromScreenId: string; elementMeaning: string; targetUrl: string }> = [];\n const pendingSummaryWrites: Promise<void>[] = [];\n const discovered: Array<{\n url: string; screenId?: string; elements?: number;\n elementFacts?: Array<{ meaning: string; role: string; expectedData?: string }>;\n screenshotPath?: string; version?: number; error?: string;\n }> = [];\n const performanceMetrics: PerformanceMetric[] = [];\n const seenDomHashes = new Set<string>(opts.knownDomHashes ?? []);\n\n // Legal/policy-only pages \u2014 no interactive elements worth testing; skip to prevent noise\n // NOTE: /about, /contact, /careers, /help are intentionally NOT skipped \u2014 they have\n // real test targets (contact forms, job apply forms, help search, team content)\n const skipPathExtra = process.env.CRAWL_SKIP_PATH_EXTRA\n ? process.env.CRAWL_SKIP_PATH_EXTRA.split(',').map((p) => p.trim()).filter(Boolean)\n : [];\n const SKIP_PATH = skipPathExtra.length > 0\n ? new RegExp(`/(terms|privacy|dpa|legal|cookie-policy|changelog|blog|imprint|gdpr|compliance|acceptable-use|security-policy|press|sitemap|${skipPathExtra.join('|')})([-/]|$)`, 'i')\n : /\\/(terms|privacy|dpa|legal|cookie-policy|changelog|blog|imprint|gdpr|compliance|acceptable-use|security-policy|press|sitemap)([-/]|$)/i;\n const segIdx = opts.segmentIndex ?? 1;\n\n const robotsCache = opts.respectRobotsTxt ? new RobotsCache() : null;\n // AutoThrottle state \u2014 exponential moving average of navigation latency\n let avgNavMs = 0;\n let navCount = 0;\n // Rate-limit circuit breaker: after 5 consecutive AI errors (429), skip AI for 3 screens then retry\n // (was: 3 errors \u2192 skip 10 screens \u2014 too aggressive for Nvidia NIM which rate-limits quickly)\n let aiErrorStreak = 0;\n let aiSkipCount = 0;\n const aiMinElements = parseInt(process.env.CRAWL_AI_LINK_MIN_ELEMENTS ?? '') || 5;\n let aiRateLimitWarned = false;\n // Hard guard: total URLs attempted (including skips) capped at maxScreens * 4\n // to prevent infinite-URL-explosion from WooCommerce/Shopify facet filter combos\n // that slip through canonicalize() if any new filter param type is encountered.\n let totalAttemptsThisSegment = 0;\n const maxAttempts = Math.max(segmentSize * 4, 200);\n // Count consecutive login-wall redirects \u2014 if too many, abort early (auth-wall site, no creds)\n let loginWallRedirectCount = 0;\n const LOGIN_WALL_ABORT_THRESHOLD = Math.max(8, Math.ceil(segmentSize * 0.4));\n\n let pendingSessionRestore: (() => Promise<void>) | null = null;\n\n // F10: Parallel lite-worker browser tabs \u2014 pull from shared queue while main loop runs.\n // Each worker uses a fresh Playwright page from the same browser context so it shares\n // cookies/session with the main page. DOM-only extraction (no Stagehand AI).\n // Default 5 = 3-5\u00D7 crawl throughput on a single browser context. Set CRAWL_PAGE_PARALLELISM=1 to disable.\n const CRAWL_PAGE_PARALLELISM = Math.max(1, parseInt(process.env.CRAWL_PAGE_PARALLELISM ?? '5', 10));\n\n async function runLiteWorker(workerPage: any): Promise<void> {\n while (queue.length > 0 && visited.size < maxScreens && visited.size < segmentSize) {\n if (opts.abortSignal?.aborted) break;\n if (isCrawlTimedOut()) break;\n if (++totalAttemptsThisSegment > maxAttempts) break;\n\n const url = queue.shift();\n if (!url) break;\n\n const canonUrl = canonicalize(url);\n if (visited.has(canonUrl)) continue;\n\n try {\n const { pathname } = new URL(url);\n if (SKIP_PATH.test(pathname) || (isGeneratedDynamicPath(pathname) && !_activeSeedPatterns.some(re => re.test(pathname)))) continue;\n // Skip API/export paths \u2014 these return data files, not navigable pages\n if (API_PATH_RE.test(pathname) || EXPORT_PATH_RE.test(pathname) || DOWNLOAD_EXT_RE.test(pathname)) continue;\n } catch { continue; }\n\n // Claim URL before first await \u2014 prevents duplicate processing across parallel workers\n visited.set(canonUrl, '_pending_');\n\n try {\n const navErr = await workerPage.goto(url, { waitUntil: 'domcontentloaded', timeout: tuning.navTimeoutMs }).then(() => null as null, (e: any) => e);\n if (navErr && /timeout/i.test(String((navErr as any)?.message ?? navErr))) {\n await workerPage.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 }).catch(() => {});\n }\n\n // Wait for SPA JS to render components before extracting elements or running soft-404 check.\n // domcontentloaded fires before JS executes \u2014 networkidle ensures React/Vue/Angular hydration.\n await workerPage.waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => {});\n // Wait for DOM to stop mutating (React/Vue render cycles) before element extraction.\n await waitForStableDOM(workerPage, 6_000, 400).catch(() => {});\n // Dismiss cookie banners / GDPR overlays so underlying elements are accessible.\n await dismissOverlays(workerPage).catch(() => {});\n\n // Auth wall detection: if navigation redirected to a login page, skip this URL.\n // Lite worker cannot re-authenticate (no Stagehand access) \u2014 mark and skip.\n const lwCurrentUrl = workerPage.url();\n const lwPath = (() => { try { return new URL(lwCurrentUrl).pathname.toLowerCase(); } catch { return ''; } })();\n const lwIsAuthWall = /^\\/(login|signin|sign-in|auth|authenticate|session\\/new|account\\/login|user\\/login)/.test(lwPath) && lwCurrentUrl !== url;\n const lwHasLoginForm = lwIsAuthWall ? false : await workerPage.evaluate(() => {\n const inputs = document.querySelectorAll('input[type=\"password\"]');\n return inputs.length > 0;\n }).catch(() => false);\n if (lwIsAuthWall) {\n logger.warn({ url, landed: lwCurrentUrl }, '[lite-worker] auth wall detected \u2014 queuing for main worker re-auth');\n visited.set(canonUrl, '_auth_wall_');\n if (!revisitQueue.includes(url)) revisitQueue.push(url);\n continue;\n }\n // lwHasLoginForm (direct sign-in/register page): process normally \u2014 capture the form elements.\n // Do NOT add to revisitQueue; P3a cannot do anything useful with a login page revisit.\n\n // Soft-404 detection for lite-worker: skip SPA catch-all URLs that mirror homepage\n if (homeFingerprintElemCount >= 0 && url !== startUrl) {\n const wTitle = await workerPage.title().catch(() => '');\n if (wTitle === homeFingerprintTitle && wTitle !== '') {\n const wElemCount = await workerPage.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"]').length\n ).catch(() => -1);\n if (wElemCount >= 0 && wElemCount === homeFingerprintElemCount) {\n console.log(`[lite-worker] skip ${url} \u2014 soft-404 (homepage fingerprint match)`);\n visited.set(canonUrl, '_soft404_');\n continue;\n }\n }\n }\n\n const pathParts = new URL(url).pathname.split('/').filter(Boolean);\n const name = pathParts.map((p: string) => p.charAt(0).toUpperCase() + p.slice(1).replace(/[-_]/g, ' ')).join(' \u2014 ') || 'Home';\n\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, name, url, opts.jobId, discoveryMethodFor(url));\n visited.set(canonUrl, screen.id);\n\n // Inline auth-wall detection: PHP/legacy apps render session-expired content without URL redirect.\n // URL-redirect case (lwIsAuthWall above) is handled by main BFS via revisitQueue.\n\n const lwBodyText = await workerPage.evaluate(() => (document as any).body?.innerText ?? '').catch(() => '');\n if (INLINE_AUTH_WALL_RE.test(lwBodyText)) {\n logger.warn({ url, screenId: screen.id }, '[lite-worker] Inline session-expired content detected \u2014 marking requiresAuth');\n AppBrain.updateScreenRequiresAuth(opts.tenantId, screen.id, true).catch(() => {});\n visited.set(canonUrl, '_auth_wall_');\n if (!revisitQueue.includes(url)) revisitQueue.push(url);\n continue;\n }\n\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `${screen.id}-desktop-v${screen.version}.png`);\n\n let liteElements = await domFallbackElements(workerPage).catch(() => [] as Awaited<ReturnType<typeof domFallbackElements>>);\n if (liteElements.length === 0) {\n // domFallbackElements returned nothing \u2014 try broader visible-element selector as last resort.\n liteElements = await workerPage.evaluate(() => {\n const sel = 'button,a[href],input,select,textarea,[role],[tabindex=\"0\"],[onclick],[data-action]';\n return Array.from(document.querySelectorAll(sel))\n .filter((el: any) => el.offsetParent !== null)\n .slice(0, 150)\n .map((el: any) => ({\n meaning: el.getAttribute('aria-label') || el.textContent?.trim().slice(0, 100) || el.tagName.toLowerCase(),\n role: el.getAttribute('role') || el.tagName.toLowerCase(),\n expectedData: null, notes: null, boundingRect: null, ariaState: null, parentLandmark: null,\n }));\n }).catch(() => []) as any[];\n }\n const [elements] = await Promise.all([\n Promise.resolve(liteElements),\n workerPage.screenshot({ path: shotPath, fullPage: true })\n .then(async () => {\n const cloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`);\n return (AppBrain.saveScreenshot as any)(opts.tenantId, opts.projectId, screen.id, shotPath, screen.version, 'DESKTOP', cloudUrl);\n })\n .catch(() => {}),\n ]);\n\n // GAP 1: DOM snapshot for lite-worker path\n const lwDom = await capturePageHtml(workerPage);\n if (lwDom) {\n const lwDomPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(lwDomPath, lwDom, 'utf8');\n const lwDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(lwDomPath)}`;\n const lwDomCloud = await uploadToCloud(lwDomPath, lwDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, lwDomPath, lwDomCloud).catch(() => {});\n }\n\n // Nav-link pass \u2014 merged into main save cycle so clearScreenElements covers them too.\n // extractElements (main BFS) never runs for lite-worker screens, so nav/footer roles\n // must be captured here. Running before clear+save prevents additive accumulation.\n const _navEls = await (workerPage.evaluate as any)(() => {\n if (typeof (globalThis as any).__name === 'undefined') (globalThis as any).__name = (fn: any) => fn;\n const seen = new Set<string>();\n const items: Array<{meaning: string; role: string; notes: string}> = [];\n function isV(el: Element) {\n const s = window.getComputedStyle(el);\n return s.display !== 'none' && s.visibility !== 'hidden' && s.opacity !== '0';\n }\n // Wide nav selector: covers semantic nav, ARIA, header links, sidebar (aside/[role=complementary]),\n // and common class-based sidebars used by admin/dashboard pages.\n const NAV_SEL = [\n 'nav a', '[role=\"navigation\"] a', 'header a', 'footer nav a',\n '[aria-label*=\"navigation\" i] a', '[aria-label*=\"sidebar\" i] a',\n 'aside a', '[role=\"complementary\"] a',\n '[class*=\"sidebar\" i] a', '[class*=\"side-nav\" i] a', '[class*=\"sidenav\" i] a',\n '[class*=\"nav-menu\" i] a', '[class*=\"navmenu\" i] a', '[data-nav] a',\n ].join(', ');\n document.querySelectorAll(NAV_SEL).forEach((a: any) => {\n if (!isV(a)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n const href = a.href ?? '';\n if (!label || !href || /^(javascript:|#$)/i.test(href)) return;\n let landmark = 'Site Navigation';\n let cur: any = a.parentElement;\n while (cur) {\n const t = cur.tagName?.toLowerCase();\n const r = cur.getAttribute?.('role')?.toLowerCase();\n const cl = (cur.className ?? '').toLowerCase();\n if (t === 'header' || r === 'banner') { landmark = 'Header'; break; }\n if (t === 'footer' || r === 'contentinfo') { landmark = 'Footer'; break; }\n if (t === 'aside' || r === 'complementary' || cl.includes('sidebar') || cl.includes('sidenav') || cl.includes('side-nav')) { landmark = 'Sidebar'; break; }\n if (t === 'nav' || r === 'navigation') { landmark = cur.getAttribute('aria-label')?.trim() || 'Site Navigation'; break; }\n cur = cur.parentElement;\n }\n const key = `nav|${label.toLowerCase()}|${href}`;\n if (!seen.has(key)) { seen.add(key); items.push({ meaning: label, role: 'nav-link', notes: JSON.stringify({ href: href.slice(0, 150), landmark }) }); }\n });\n let fc = 0;\n document.querySelectorAll('footer a, [role=\"contentinfo\"] a, [class*=\"footer\" i] a').forEach((a: any) => {\n if (fc >= 20 || !isV(a)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n const href = a.href ?? '';\n if (!label || !href) return;\n const key = `footer|${label.toLowerCase()}|${href}`;\n if (!seen.has(key)) { seen.add(key); items.push({ meaning: label, role: 'footer-link', notes: JSON.stringify({ href: href.slice(0, 150) }) }); fc++; }\n });\n // Grandparent-grouping fallback: detects sidebar navigation where each link is\n // individually wrapped (e.g. <div class=\"flex\"><a>link</a></div> \u00D7 many siblings).\n // Runs ALWAYS (not gated on 0 results) so header links don't block sidebar detection.\n // Deduped against hrefs already captured by the semantic pass above.\n {\n const navHrefsSeen = new Set<string>();\n for (const it of items) {\n try { const h = JSON.parse(it.notes ?? '{}').href; if (h) navHrefsSeen.add(h); } catch { /* skip */ }\n }\n const gpGroups = new Map<Element, Array<{label: string; href: string}>>();\n document.querySelectorAll('a[href]').forEach((a: any) => {\n if (!isV(a)) return;\n const href = a.href ?? '';\n if (!href || /^(javascript:|#$|mailto:|tel:)/i.test(href) || navHrefsSeen.has(href)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n if (!label || label.length > 40) return;\n const parent = a.parentElement;\n const gp = parent?.parentElement;\n if (!parent || !gp) return;\n // Only match when parent wraps exactly 1 anchor \u2014 the sidebar <div><a> pattern\n if (parent.querySelectorAll('a').length !== 1) return;\n const gpTag = gp.tagName.toLowerCase();\n if (['body', 'html', 'form'].includes(gpTag)) return;\n const arr = gpGroups.get(gp) ?? [];\n arr.push({ label, href });\n gpGroups.set(gp, arr);\n });\n for (const [, links] of gpGroups.entries()) {\n if (links.length >= 4) {\n for (const { label, href } of links) {\n const k = `cluster|${label.toLowerCase()}|${href}`;\n if (!seen.has(k)) { seen.add(k); items.push({ meaning: label, role: 'nav-link', notes: JSON.stringify({ href: href.slice(0, 150), landmark: 'Sidebar' }) }); }\n }\n }\n }\n }\n return items;\n }).catch(() => [] as any[]);\n\n const allElements = [\n ...elements,\n ..._navEls.map((ne: any) => ({ ...ne, expectedData: undefined, boundingRect: undefined, ariaState: undefined, parentLandmark: undefined })),\n ];\n\n // Persist lite-worker elements to DB \u2014 without this, 80% of screens have 0 DB elements.\n if (allElements.length > 0) {\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, screen.id).catch(() => {});\n for (let _ei = 0; _ei < allElements.length; _ei += 2) {\n const _batch = allElements.slice(_ei, _ei + 2);\n await Promise.all(_batch.map((el: any) =>\n AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => {})\n ));\n }\n logger.info({ url, screenId: screen.id, elements: elements.length, navLinks: _navEls.length }, '[lite-worker] screen captured');\n } else if (!revisitQueue.includes(url)) {\n // 0-element: queue for main BFS re-visit with full Stagehand AI extraction\n logger.warn({ url, screenId: screen.id }, '[lite-worker] 0 elements \u2014 queued for P3a revisit');\n revisitQueue.push(url);\n }\n\n // Non-mutating probes for lite-worker screens: shadow DOM, a11y tree, service worker.\n // Awaited with 15s total timeout \u2014 these are read-only and safe on the shared worker page.\n if (screen?.id) {\n const [shadowRes, a11yRes, swRes] = await Promise.race([\n Promise.allSettled([\n crawlShadowDom(workerPage),\n crawlAccessibilityTree(workerPage),\n inspectServiceWorker(workerPage),\n ]),\n new Promise<PromiseSettledResult<never>[]>((resolve) =>\n setTimeout(() => resolve([\n { status: 'rejected' as const, reason: 'timeout' },\n { status: 'rejected' as const, reason: 'timeout' },\n { status: 'rejected' as const, reason: 'timeout' },\n ]), 15_000)\n ),\n ]);\n const litePayload: Record<string, unknown> = { screenId: screen.id, url };\n if (shadowRes.status === 'fulfilled' && shadowRes.value && (shadowRes.value as any).shadowHostCount > 0)\n litePayload.shadowDom = shadowRes.value;\n if (a11yRes.status === 'fulfilled' && a11yRes.value)\n litePayload.accessibilityTree = a11yRes.value;\n if (swRes.status === 'fulfilled' && (swRes.value as any).supported)\n litePayload.serviceWorker = swRes.value;\n if (Object.keys(litePayload).length > 2) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'PER_SCREEN_PROBES', payload: litePayload,\n }).catch(() => {});\n }\n }\n\n const nextLinks: string[] = await (workerPage.evaluate as any)((originStr: string) => {\n return Array.from(document.querySelectorAll('a[href],[data-href]'))\n .map((a: any) => {\n const raw = a.getAttribute('href') || a.getAttribute('data-href') || '';\n try { return new URL(raw, window.location.href).href; }\n catch { return ''; }\n })\n .filter((h: string) => {\n if (!h) return false;\n try {\n const u = new URL(h);\n if (u.origin !== originStr) return false;\n // Keep hash-router paths (#/route, #!/route) but drop plain fragment anchors (#section)\n if (u.hash && !u.hash.startsWith('#/') && !u.hash.startsWith('#!/')) return false;\n return true;\n } catch { return false; }\n })\n .slice(0, 200);\n }, origin).catch(() => []);\n\n for (const link of nextLinks) {\n if (!isUsefulNavigationUrl(link, origin)) continue;\n const cLink = canonicalize(link);\n if (!visited.has(cLink) && !queued.has(cLink)) {\n queued.add(cLink);\n queue.push(link);\n edges.push({ fromUrl: url, toUrl: link });\n }\n }\n\n discovered.push({ url, screenId: screen.id, elements: elements.length, elementFacts: elements, screenshotPath: shotPath, version: screen.version });\n // Lite workers also advance the progress bar \u2014 without this 4/5 workers are invisible.\n const lwEffMax = isFinite(maxScreens) ? Math.min(visited.size + queue.length, maxScreens * 3) : visited.size + queue.length;\n maxSeenTotal = Math.max(maxSeenTotal, lwEffMax);\n const lwRawPct = 20 + Math.round(Math.min(57, (visited.size / Math.max(1, maxSeenTotal)) * 57));\n const lwPct = Math.max(lastEmittedPct, lwRawPct);\n lastEmittedPct = lwPct;\n await onProgress?.(lwPct, `Crawling screens (${visited.size} mapped, ${queue.length} pending)`).catch(() => {});\n } catch (err: any) {\n logger.warn({ url, err: err?.message ?? String(err) }, '[lite-worker] URL processing failed');\n discovered.push({ url, error: err?.message ?? String(err) });\n }\n }\n }\n\n const liteWorkerPromises: Promise<void>[] = [];\n if (CRAWL_PAGE_PARALLELISM > 1 && playwrightBrowser && !opts.discoveryMode) {\n const pwCtx = playwrightBrowser.contexts()[0];\n for (let i = 1; i < CRAWL_PAGE_PARALLELISM; i++) {\n const wp = await pwCtx.newPage();\n await wp.addInitScript(() => { Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); }).catch(() => {});\n wp.setDefaultTimeout(tuning.defaultTimeoutMs || 45_000);\n liteWorkerPromises.push(runLiteWorker(wp).finally(() => wp.close().catch(() => {})));\n }\n }\n\n while (queue.length > 0 && visited.size < maxScreens && visited.size < segmentSize) {\n if (pendingSessionRestore) {\n await pendingSessionRestore();\n pendingSessionRestore = null;\n }\n if (++totalAttemptsThisSegment > maxAttempts) {\n logger.warn({ maxAttempts, visited: visited.size, queued: queue.length }, '[crawler] attempt cap reached \u2014 stopping to prevent URL explosion');\n break;\n }\n if (opts.abortSignal?.aborted) {\n logger.info('Abort signal received \u2014 stopping crawl');\n throw new Error('CRAWL_ABORTED');\n }\n if (isCrawlTimedOut()) {\n const elapsedMin = Math.round((Date.now() - crawlLoopStart) / 60_000);\n logger.warn({ elapsedMin, visited: visited.size, queued: queue.length }, '[crawler] Global timeout reached \u2014 stopping BFS to prevent runaway crawl');\n await onProgress?.(89, `Crawl timeout after ${elapsedMin}min \u2014 ${visited.size} pages captured`).catch(() => {});\n break;\n }\n // AutoThrottle: delay next request proportional to avg navigation latency\n if (opts.autoThrottle && navCount > 0) {\n const delayMs = Math.min(5_000, Math.max(0, avgNavMs * 0.5));\n if (delayMs > 100) await page.waitForTimeout(delayMs).catch(() => { });\n }\n\n const url = queue.shift()!;\n const canonUrl = canonicalize(url);\n const apiObservationStartIndex = capturedApiEndpoints.length;\n\n // Skip if already visited (canonical match \u2014 catches ID-parameterized duplicates)\n if (visited.has(canonUrl)) continue;\n // Claim immediately before any await \u2014 prevents lite workers from picking up the same URL\n // concurrently while this iteration is suspended (race that causes repeated visits).\n visited.set(canonUrl, '_pending_');\n logger.info({ url, visited: visited.size, queued: queue.length, segment: `${visited.size}/${segmentSize}` }, '[crawler] visiting URL');\n\n // robots.txt compliance \u2014 skip disallowed URLs\n if (robotsCache && !await robotsCache.isAllowed(url)) {\n logger.info({ url }, '[crawler] robots.txt: skipping disallowed URL');\n continue;\n }\n\n // Skip content/legal pages \u2014 they have no interactive form elements worth testing\n try {\n const { pathname } = new URL(url);\n if (SKIP_PATH.test(pathname)) {\n console.log(`[crawler] skip content page: ${url}`);\n continue;\n }\n // Generated ID-like path segments are usually fallback IDs or entity\n // records. They flood the catalog with duplicate page templates, so\n // skip them before screenshots or screen creation.\n // Exception: seed path patterns declared by the caller bypass this guard.\n if (isGeneratedDynamicPath(pathname) && !_activeSeedPatterns.some(re => re.test(pathname))) {\n console.log(`[crawler] skip generated dynamic route: ${url}`);\n continue;\n }\n // Skip API/export/download paths \u2014 navigating to these triggers file downloads.\n // The main BFS uses Stagehand's context which has no route interception.\n if (API_PATH_RE.test(pathname) || EXPORT_PATH_RE.test(pathname) || DOWNLOAD_EXT_RE.test(pathname)) {\n console.log(`[crawler] skip API/export/download path: ${url}`);\n visited.set(canonUrl, '_skipped_api_');\n continue;\n }\n } catch { /* invalid url, let it fall through */ }\n\n try {\n // Security headers \u2014 capture from first document response via CDP.\n // Stagehand V3's page proxy only supports the 'console' event (page.on throws for others).\n // We hook directly into the underlying CDP session's Network.responseReceived event instead.\n let securityHeaders: Record<string, string | null> | null = null;\n let httpStatus: number | null = null;\n const urlBase = url.replace(/[?#].*/, '');\n const cdpSession: any = (page as any).mainSession ?? (page as any)._session ?? null;\n const secHeadersCdp = (evt: any) => {\n if (securityHeaders) return;\n try {\n const responseUrl: string = evt?.response?.url ?? '';\n if (!responseUrl.startsWith(urlBase)) return;\n httpStatus = evt?.response?.status ?? null;\n const headers: Record<string, string> = {};\n // CDP headers come as array of {name, value} objects\n for (const h of (evt?.response?.headers ?? [])) headers[h.name.toLowerCase()] = h.value;\n securityHeaders = {\n csp: headers['content-security-policy'] ?? headers['content-security-policy-report-only'] ?? null,\n hsts: headers['strict-transport-security'] ?? null,\n xContentType: headers['x-content-type-options'] ?? null,\n xFrame: headers['x-frame-options'] ?? null,\n referrer: headers['referrer-policy'] ?? null,\n };\n } catch { /* non-fatal */ }\n };\n if (cdpSession?.on) cdpSession.on('Network.responseReceived', secHeadersCdp);\n\n const wsDetector = attachWebSocketDetector(cdpSession);\n\n if (url !== page.url()) {\n // LCP/CLS observers are registered via the addInitScript above, which\n // re-runs automatically on this navigation \u2014 nothing to do here.\n const navStart = Date.now();\n // Track redirect hops during this navigation\n const redirectHops: Array<{ from: string; to: string; statusCode: number }> = [];\n const onRedirectResponse = (res: any) => {\n const st = res.status();\n if (st >= 300 && st < 400) {\n redirectHops.push({ from: res.url(), to: res.headers()['location'] ?? '', statusCode: st });\n } else if (st >= 400) {\n deadLinkTracker.record(res.url(), st, { sourceUrl: url });\n }\n };\n rawPage.on('response', onRedirectResponse);\n\n // Session Isolation: Clear session before crawling public auth routes\n const AUTH_PATH_REGEX = /\\/(login|register|signup|sign-in|sign-up|forgot-password|reset-password)([-/]|$)/i;\n const isAuthRoute = AUTH_PATH_REGEX.test(new URL(url).pathname);\n const browserCtx = playwrightBrowser?.contexts()[0];\n \n if (isAuthRoute && browserCtx) {\n const currentState = await browserCtx.storageState();\n const hasSession = (currentState.cookies?.length ?? 0) > 0 ||\n currentState.origins?.some((o: any) => (o.localStorage?.length ?? 0) > 0);\n if (hasSession) {\n pendingSessionRestore = async () => {\n const ctx = playwrightBrowser?.contexts()[0];\n if (ctx) {\n await ctx.addCookies(currentState.cookies);\n await rawPage.evaluate((origins: any) => {\n for (const entry of (origins ?? [])) {\n if (window.location.origin === entry.origin) {\n for (const item of entry.localStorage) {\n try { localStorage.setItem(item.name, item.value); } catch {}\n }\n }\n }\n }, currentState.origins).catch(() => {});\n logger.info('[crawler] restored session state after public auth route');\n }\n };\n await browserCtx.clearCookies();\n await rawPage.evaluate(() => {\n try { localStorage.clear(); sessionStorage.clear(); } catch {}\n }).catch(() => {});\n logger.info({ url }, '[crawler] temporarily cleared session for public auth route');\n }\n }\n\n // Try fast 15 s first; only escalate to 30 s on timeout so happy-path pages don't wait\n const navErr15 = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: tuning.navTimeoutMs }).then(() => null, (e: any) => e);\n if (navErr15) {\n if (/timeout/i.test(String(navErr15?.message ?? navErr15))) {\n await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 }).catch((navErr: any) => {\n logger.warn({ url, err: navErr?.message ?? String(navErr) }, '[crawler] navigation failed \u2014 skipping');\n });\n } else {\n logger.warn({ url, err: navErr15?.message ?? String(navErr15) }, '[crawler] navigation failed \u2014 skipping');\n }\n }\n rawPage.off('response', onRedirectResponse);\n if (redirectHops.length > 0) {\n const isCircularRedirect = new Set(redirectHops.map(h => h.from)).size < redirectHops.length;\n redirectRegistry.register({\n originalUrl: url, finalUrl: page.url(),\n hops: redirectHops.map((h, i) => ({ ...h, durationMs: i === 0 ? Date.now() - navStart : 0 })),\n isCircular: isCircularRedirect,\n hopCount: redirectHops.length,\n totalDurationMs: Date.now() - navStart,\n });\n if (isCircularRedirect) {\n logger.warn({ url, hops: redirectHops.map(h => h.from) }, '[crawler] circular redirect detected \u2014 skipping URL');\n continue;\n }\n }\n // Update exponential moving average for AutoThrottle\n const navMs = Date.now() - navStart;\n navCount++;\n avgNavMs = avgNavMs + (navMs - avgNavMs) / navCount;\n }\n // chrome-error:// = TCP/HTTP connection failed (IP block, DNS failure, etc.)\n // Skip immediately \u2014 don't screenshot, don't trigger Skyvern, just move on.\n if (page.url().startsWith('chrome-error://')) {\n console.warn(`[crawler] connection failed for ${url} \u2014 skipping (chrome-error page)`);\n continue;\n }\n // Full page-ready sequence:\n // 1. load \u2014 waits for initial page load (faster than networkidle; XHR handled by waitForStableDOM)\n // 2. DOM stability \u2014 waits for React/Vue hydration to finish mutating the DOM\n // 3. Modal capture \u2014 screenshot app dialogs BEFORE dismissal (they are testable UI states)\n // 4. Overlay dismissal \u2014 removes cookie banners/modals before element extraction\n // 5. Lazy-load scroll \u2014 triggers IntersectionObserver for off-screen images/components\n await (rawPage ?? page).waitForLoadState('load', { timeout: 8_000 }).catch(() => { });\n await waitForStableDOM(page, 8_000, 400, rawPage ?? undefined);\n // If DOM is sparse after stability check (< 15 interactive elements), SPA may still be\n // fetching data \u2014 skeleton is DOM-stable but empty. Extra networkidle pass catches it.\n const sparseCheck = await (rawPage ?? page).evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"],[aria-label]').length\n ).catch(() => 99);\n if (sparseCheck < 15) {\n await (rawPage ?? page).waitForLoadState('networkidle', { timeout: 6_000 }).catch(() => {});\n await waitForStableDOM(page, 4_000, 300, rawPage ?? undefined);\n }\n // Wait for SPA auth-check / loading spinners to resolve before screenshotting.\n // SPAs often show a \"Checking authentication...\" or \"Loading...\" state after networkidle\n // while client-side auth verifies tokens. waitForStableDOM catches DOM mutations but\n // returns as soon as the spinner DOM is stable \u2014 this catches the spinner itself.\n // Stagehand V3 proxy may not expose waitForFunction \u2014 use try/catch, not .catch(),\n // because calling an undefined method throws synchronously before a Promise is created.\n try {\n const spinnerPage = rawPage ?? page;\n if (typeof spinnerPage.waitForFunction === 'function') {\n await spinnerPage.waitForFunction(() => {\n const body = document.body;\n if (!body) return true;\n const text = body.innerText?.toLowerCase() ?? '';\n // Text-based loading indicators\n if (\n text.includes('checking authentication') ||\n text.includes('checking auth') ||\n text.includes('authenticating') ||\n text.includes('verifying session') ||\n text.includes('please wait') ||\n text.includes('loading data') ||\n (text.includes('loading') && text.length < 200)\n ) return false;\n // ARIA-based: aria-busy on any visible element\n const busyEl = body.querySelector('[aria-busy=\"true\"]');\n if (busyEl && (busyEl as HTMLElement).offsetParent !== null) return false;\n // Data attributes: React Query / SWR / TanStack in-flight indicators\n if (body.querySelector('[data-loading=\"true\"],[data-pending=\"true\"],[data-fetching=\"true\"]')) return false;\n // Indeterminate progress bars\n if (body.querySelector('progress:not([value])')) return false;\n // Common CSS class patterns for loading skeletons\n const skeleton = body.querySelector('.skeleton,.skeleton-loader,.shimmer,.pulse-loader,.content-loader');\n if (skeleton && (skeleton as HTMLElement).offsetParent !== null) return false;\n return true;\n }, { timeout: 12_000 });\n }\n } catch { /* timed out or unsupported \u2014 screenshot whatever is there */ }\n\n if (!opts.discoveryMode) {\n // Capture app-generated modals BEFORE dismissing \u2014 cookie/GDPR banners excluded.\n try {\n const appModalVisible = await page.evaluate(() => {\n const dialogs = Array.from(document.querySelectorAll('[role=\"dialog\"], [role=\"alertdialog\"], [aria-modal=\"true\"]'));\n return dialogs.some((el: any) => {\n const text = (el.textContent ?? '').toLowerCase();\n const isCookieBanner = /(cookie|consent|gdpr|privacy policy|accept all|we use cookies)/i.test(text);\n const isVisible = el.offsetParent !== null || el.style.display !== 'none';\n return isVisible && !isCookieBanner;\n });\n }).catch(() => false);\n if (appModalVisible) {\n const modalHash = url.replace(/[^a-z0-9]/gi, '').slice(-12);\n const modalShotPath = path.join(opts.screenshotDir ?? '/tmp', `modal-${modalHash}.png`);\n await page.screenshot({ path: modalShotPath, fullPage: false }).catch(() => { });\n const modalName = await (rawPage ?? page).evaluate(() => {\n const h = document.querySelector('[role=\"dialog\"] h1,[role=\"dialog\"] h2,[role=\"dialog\"] [role=\"heading\"]');\n return h?.textContent?.trim() ?? 'Modal';\n }).catch(() => 'Modal');\n const modalScreen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, modalName, url, opts.jobId, discoveryMethodFor(url)).catch(() => null);\n if (modalScreen) {\n const modalCloudUrl = await uploadToCloud(modalShotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(modalShotPath)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, modalScreen.id, modalShotPath, modalScreen.version, 'DESKTOP', modalCloudUrl).catch(() => { });\n // GAP 3: DOM snapshot for modal/dialog capture\n const modalDom = await capturePageHtml(page);\n if (modalDom) {\n const modalDomPath = modalShotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(modalDomPath, modalDom, 'utf8');\n const modalDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(modalDomPath)}`;\n const modalDomCloud = await uploadToCloud(modalDomPath, modalDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, modalScreen.id, modalDomPath, modalDomCloud).catch(() => {});\n }\n // Extract elements from the modal BEFORE it is dismissed \u2014 use CDP path via rawPage\n const modalElements = await domFallbackElements(page, rawPage ?? undefined).catch(() => []);\n for (const el of modalElements) {\n AppBrain.saveElement(opts.tenantId, opts.projectId, modalScreen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => {});\n }\n logger.info({ url, name: modalName, elementCount: modalElements.length }, '[crawler] captured app modal before dismiss');\n }\n }\n } catch { /* non-fatal */ }\n await dismissOverlays(page);\n // Enhanced infinite scroll \u2014 handles lazy-load, infinite lists, and virtual scrollers\n await infiniteScrollToBottom(page, { maxScrolls: 30, scrollDelay: 350, stabilizeMs: 500 }, rawPage ?? undefined).catch(() => { });\n }\n if (cdpSession?.off) cdpSession.off('Network.responseReceived', secHeadersCdp);\n wsDetector.detach();\n\n // 429 Rate-limit \u2014 exponential backoff with jitter before continuing\n if (httpStatus === 429) {\n const backoffMs = Math.min(60_000, 1_000 * Math.pow(2, Math.min(navCount, 6)));\n logger.warn({ url, httpStatus, backoffMs }, '[crawler] 429 rate-limited \u2014 backing off');\n await new Promise(r => setTimeout(r, backoffMs + Math.random() * 1_000));\n }\n\n // Skip pages that returned an HTTP 4xx/5xx response \u2014 SPAs normally return 200 for all routes,\n // so a real HTTP error means the server knows this URL is invalid.\n if (httpStatus !== null && httpStatus >= 400) {\n logger.info({ url, httpStatus }, '[crawler] skip \u2014 server returned HTTP error');\n continue;\n }\n\n // \u2500\u2500 Mid-crawl session expiry detection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Only trigger re-auth when the app REDIRECTED us away from the intended URL.\n // If we intentionally navigate to /session-expired or /login \u2014 save it as a screen (it's\n // a real page worth testing: messaging, recovery buttons, error UX, etc.).\n const BFS_ERROR_PATH = /\\/(session-expired|expired|unauthorized|forbidden|401|403|logout|logged-out)(\\/|$|\\?)/i;\n const BFS_LOGIN_PATH = /\\/(login|signin|sign-in|auth|log-in|sso|account\\/login)(\\/|$|\\?)/i;\n const landedUrl = page.url();\n const weWantedThisPage = BFS_ERROR_PATH.test(new URL(url).pathname) || BFS_LOGIN_PATH.test(new URL(url).pathname);\n const redirectedToError = !weWantedThisPage && (\n BFS_ERROR_PATH.test(new URL(landedUrl).pathname) || BFS_LOGIN_PATH.test(new URL(landedUrl).pathname)\n );\n if (redirectedToError) {\n // Track login-wall redirects: if the site sends every URL to /login without credentials,\n // abort early rather than burning all maxAttempts on the same login page.\n if (BFS_LOGIN_PATH.test(new URL(landedUrl).pathname)) {\n loginWallRedirectCount++;\n if (!opts.credentials && loginWallRedirectCount >= LOGIN_WALL_ABORT_THRESHOLD) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: {\n url, landed: landedUrl,\n reason: `Login wall detected: ${loginWallRedirectCount} consecutive URLs redirected to login. Add credentials in project settings to crawl authenticated pages.`,\n },\n }).catch(() => {});\n // Checkpoint remaining queue so job-queue can auto-requeue the pending URLs\n await opts.onCheckpoint?.(\n Array.from(visited.entries()).filter(([_k, v]) => v !== '_pending_').map(([k]) => k),\n queue.filter((u: string) => !visited.has(canonicalize(u)))\n ).catch(() => {});\n throw new Error(`[AUTH_FAILURE] Login wall detected: ${loginWallRedirectCount} URLs redirected to the login page. Add credentials in project settings and retry the crawl.`);\n }\n }\n // We asked for /dashboard but landed on /session-expired \u2014 session expired mid-crawl.\n logger.warn({ requested: url, landed: landedUrl }, '[crawler] Mid-crawl redirect to auth/error \u2014 attempting re-auth');\n let reauthed = false;\n if (opts.credentials) {\n reauthed = await loginWithStagehand(\n stagehand, opts.credentials, opts.appUrl,\n { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider },\n { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId },\n undefined,\n { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId },\n ).catch(() => false);\n if (reauthed) {\n logger.info({ url }, '[crawler] Re-auth succeeded \u2014 retrying URL');\n await page.goto(url, { waitUntil: 'domcontentloaded' }).catch(() => { });\n await (rawPage ?? page).waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => { });\n await waitForStableDOM(page, 8_000, 400, rawPage ?? undefined);\n const afterReauthUrl = page.url();\n if (BFS_ERROR_PATH.test(new URL(afterReauthUrl).pathname) || BFS_LOGIN_PATH.test(new URL(afterReauthUrl).pathname)) {\n logger.warn({ url }, '[crawler] Still redirecting after re-auth \u2014 skipping this URL');\n continue;\n }\n } else {\n logger.warn({ url }, '[crawler] Re-auth failed \u2014 stopping BFS (session unrecoverable)');\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: { url, landed: landedUrl, reason: 'Re-authentication failed. Session is unrecoverable. Re-capture the session in project settings and retry the crawl.' },\n }).catch(() => { });\n // Checkpoint remaining queue before aborting so job-queue can auto-requeue\n await opts.onCheckpoint?.(\n Array.from(visited.entries()).filter(([_k, v]) => v !== '_pending_').map(([k]) => k),\n queue.filter((u: string) => !visited.has(canonicalize(u)))\n ).catch(() => {});\n throw new Error('[AUTH_FAILURE] Re-authentication failed. Session is unrecoverable. Re-capture the session in project settings and retry the crawl.');\n }\n } else {\n // Discovery mode: skip auth-required URLs and continue discovering other links.\n // Throwing here aborts the entire BFS \u2014 in discovery mode we want to continue\n // visiting other queued URLs (e.g. sitemap seeds) that may not require auth.\n if (opts.discoveryMode) {\n logger.info({ url, landed: landedUrl }, '[discover] skipping auth-required URL \u2014 no credentials, continuing BFS');\n continue;\n }\n logger.warn('[crawler] Session expired mid-crawl, no credentials to recover \u2014 skipping URL');\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: { url, landed: landedUrl, reason: 'Session expired and no credentials are configured. Add credentials in project settings and re-capture the session.' },\n }).catch(() => { });\n // Checkpoint remaining queue before aborting so job-queue can auto-requeue\n await opts.onCheckpoint?.(\n Array.from(visited.entries()).filter(([_k, v]) => v !== '_pending_').map(([k]) => k),\n queue.filter((u: string) => !visited.has(canonicalize(u)))\n ).catch(() => {});\n throw new Error('[AUTH_FAILURE] Session expired and no credentials are configured. Add credentials in project settings and re-capture the session.');\n }\n }\n // If weWantedThisPage (intentional /login, /session-expired, /404 navigation) \u2014\n // fall through and save it as a real screen. Error pages are legitimate test targets.\n if (!redirectedToError && landedUrl !== url) {\n logger.info({ requested: url, landed: landedUrl }, '[crawler] navigated with redirect');\n }\n // Successful non-login page visit: reset the consecutive login-wall counter\n if (!redirectedToError) loginWallRedirectCount = 0;\n\n // Discovery mode fast-path: record URL + extract DOM links only; skip screenshots/DB/AI.\n // IMPORTANT: DOM hash dedup is intentionally DISABLED in discovery mode \u2014 SPAs use identical\n // page shells for every route, so hashing would skip all pages after the first one.\n if (opts.discoveryMode) {\n visited.set(canonicalize(url), url); // key=canonical for dedup; value=original URL returned to caller\n\n // \u2500\u2500 SPA hydration wait \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // 'domcontentloaded' fires before JS executes, so shadow DOM doesn't exist yet.\n // Wait for network idle to ensure JS bundles are downloaded + executed,\n // then add a brief buffer for component rendering (setTimeout/rAF-deferred work).\n await (rawPage ?? page).waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => { });\n await page.waitForTimeout(500).catch(() => { });\n\n // \u2500\u2500 Link extraction \u2014 three approaches, merged \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // 1. Playwright native locator (auto-pierces shadow DOM in Playwright 1.20+)\n // Works universally for React, Vue, Angular, Polymer, Lit, Stencil, FAST.\n // 2. BFS shadow DOM traversal via evaluate() \u2014 catches any gaps from approach 1.\n // 3. SPA route manifests (Next.js __NEXT_DATA__, React Router registries).\n const rawLinksSet = new Set<string>();\n const addLink = (h: string) => {\n if (!h || h === '#' || h.startsWith('javascript:') || h.startsWith('mailto:') || h.startsWith('tel:')) return;\n try {\n const href = new URL(h, origin).toString();\n if (isUsefulNavigationUrl(href, origin)) rawLinksSet.add(href);\n } catch {\n // ignore malformed links\n }\n };\n\n // 1\uFE0F\u20E3 Playwright locator \u2014 shadow-DOM-piercing (primary approach)\n const pwPage = rawPage ?? page;\n await pwPage.locator('a[href]').evaluateAll((anchors: Element[]) =>\n anchors.map((a: any) => a.href || a.getAttribute('href') || '')\n ).then((hrefs: string[]) => hrefs.forEach(addLink)).catch(() => { });\n\n await pwPage.locator('[data-href],[data-url],[data-link]').evaluateAll((els: Element[]) =>\n els.map((el: any) => el.dataset?.href || el.dataset?.url || el.dataset?.link || '')\n ).then((hrefs: string[]) => hrefs.forEach(addLink)).catch(() => { });\n\n await pwPage.locator('[href]:not(a):not(link):not(base):not(script):not(style)').evaluateAll((els: Element[]) =>\n els.map((el: any) => el.getAttribute('href') || '')\n ).then((hrefs: string[]) => hrefs.forEach(addLink)).catch(() => { });\n\n const playwrightCount = rawLinksSet.size;\n console.log(`[discover] playwright-locator found ${playwrightCount} links for ${url}`);\n\n // 2\uFE0F\u20E3 BFS shadow DOM evaluate \u2014 fallback / complement for stubborn SPAs\n // Runs regardless so it can catch elements the locator misses.\n const evalPage = rawPage ?? page;\n await evalPage.evaluate((o: string) => {\n try {\n const hrefs: string[] = [];\n const add = (h: string) => {\n if (h && h !== '#' && !h.startsWith('javascript:') && !h.startsWith('mailto:') && !h.startsWith('tel:')) {\n if (h.startsWith(o) || h.startsWith('/')) hrefs.push(h);\n }\n };\n const queue: any[] = [document];\n const seenRoots = new WeakSet<any>();\n seenRoots.add(document);\n let shadowRootsFound = 0;\n while (queue.length > 0) {\n const root: any = queue.shift();\n if (!root) continue;\n try {\n root.querySelectorAll('a[href]').forEach((a: any) => add(a.href || a.getAttribute('href') || ''));\n root.querySelectorAll('[data-href],[data-url],[data-link]').forEach((el: any) => {\n add((el.dataset && (el.dataset.href || el.dataset.url || el.dataset.link)) || '');\n });\n root.querySelectorAll('[href]:not(a):not(link):not(base):not(script):not(style)').forEach((el: any) => {\n const h = el.getAttribute('href') || '';\n if (h && !h.startsWith('#')) add(h);\n });\n root.querySelectorAll('*').forEach((el: any) => {\n try {\n if (el.shadowRoot && !seenRoots.has(el.shadowRoot)) {\n seenRoots.add(el.shadowRoot);\n queue.push(el.shadowRoot);\n shadowRootsFound++;\n }\n } catch (_) { /* closed shadow root \u2014 skip */ }\n });\n } catch (_) { /* element threw \u2014 skip */ }\n }\n return { hrefs, shadowRootsFound };\n } catch { return { hrefs: [] as string[], shadowRootsFound: 0 }; }\n }, origin).then((result: any) => {\n (result?.hrefs ?? []).forEach(addLink);\n if (result?.shadowRootsFound > 0) {\n console.log(`[discover] bfs found ${result.shadowRootsFound} shadow roots, added ${rawLinksSet.size - playwrightCount} extra links for ${url}`);\n }\n }).catch(() => { });\n\n // 3\uFE0F\u20E3 SPA route manifests\n await evalPage.evaluate(() => {\n const routes: string[] = [];\n try {\n const nd = (window as any).__NEXT_DATA__;\n if (nd?.page) routes.push(nd.page);\n } catch (_) { /* non-fatal */ }\n try {\n const w = window as any;\n const rr = w.__reactRouterRoutes || (w.__reactRouterManifest?.routes);\n if (rr) {\n const collect = (r: any) => {\n if (r?.path && r.path !== '*') routes.push(r.path.startsWith('/') ? r.path : '/' + r.path);\n if (r?.children) r.children.forEach(collect);\n };\n (Array.isArray(rr) ? rr : Object.values(rr)).forEach(collect);\n }\n } catch (_) { /* non-fatal */ }\n return routes;\n }).then((routes: any[]) => {\n (routes ?? []).forEach(p => {\n try { addLink(new URL(p, origin).href); } catch { /* ignore */ }\n });\n }).catch(() => { });\n\n const rawLinks = Array.from(rawLinksSet);\n console.log(`[discover] ${url} \u2192 rawLinks=${rawLinks.length} origin=${origin} pageUrl=${page.url()}`);\n if (rawLinks.length > 0) console.log(`[discover] sample links: ${rawLinks.slice(0, 5).join(' | ')}`);\n let newlyQueued = 0;\n for (const link of rawLinks) {\n try {\n const resolved = link.startsWith('/') ? `${origin}${link}` : link;\n const u = new URL(resolved);\n // Keep hash-router fragments (#/route, #!/route) \u2014 strip plain anchors (#section)\n if (!/^#!?\\//.test(u.hash)) u.hash = '';\n const clean = u.toString();\n if (!isUsefulNavigationUrl(clean, origin)) continue;\n // Dedup: use canonical form to avoid crawling 1000 product detail pages separately\n const norm = canonicalize(clean);\n if (!visited.has(norm) && !queued.has(norm)) { queued.add(norm); queue.push(clean); newlyQueued++; }\n } catch { /* ignore malformed */ }\n }\n if (newlyQueued > 0) console.log(`[discover] queued ${newlyQueued} new URLs, queue size=${queue.length}`);\n const pct = 10 + Math.round((visited.size / Math.max(1, opts.maxScreens ?? 1000)) * 80);\n await onProgress?.(Math.min(pct, 89), `Discovered ${visited.size} URLs\u2026`);\n // Stream partial results to caller so they can be persisted/shown incrementally\n if (opts.onUrlsDiscovered) {\n await opts.onUrlsDiscovered(Array.from(visited.values())).catch(() => { });\n }\n continue;\n }\n\n // Normal crawl mode: DOM hash dedup \u2014 detect duplicate-structure pages (SPA 404s, template clones).\n // Skip dedup when hash is empty (computeDomHash failed) \u2014 two failed-hash pages would\n // incorrectly match each other and the second would be silently dropped.\n const preDomHash = await computeDomHash(page);\n if (preDomHash !== '' && seenDomHashes.has(preDomHash)) {\n console.log(`[crawler] skip ${url} \u2014 duplicate DOM structure (same content as prior page)`);\n continue;\n }\n const pageTitle = await page.title().catch(() => '');\n if (/\\b(not found|404|page not found|this page could not be found)\\b/i.test(pageTitle)) {\n console.log(`[crawler] skip ${url} \u2014 error page detected (title: \"${pageTitle}\")`);\n seenDomHashes.add(preDomHash); // register so future 404 pages also hit hash-dedup\n continue;\n }\n // Soft-404: SPA catch-all routes return 200 but render identical homepage content.\n // Skip any non-homepage URL whose title + interactive element count matches the homepage.\n if (homeFingerprintElemCount >= 0 && url !== startUrl && pageTitle === homeFingerprintTitle && pageTitle !== '') {\n const pElemCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"]').length\n ).catch(() => -1);\n if (pElemCount >= 0 && pElemCount === homeFingerprintElemCount) {\n console.log(`[crawler] skip ${url} \u2014 soft-404 (homepage fingerprint match, title=\"${pageTitle}\" elems=${pElemCount})`);\n seenDomHashes.add(preDomHash);\n continue;\n }\n }\n // Do NOT add real pages to seenDomHashes \u2014 server-rendered sites (WooCommerce, WordPress)\n // use the same template for many legitimate pages; registering the hash would skip them all.\n\n // Collect Navigation Timing + Paint Timing immediately after DOM stable.\n // LCP/CLS come from the buffered PerformanceObservers registered in the\n // init script above (the synchronous timeline never holds LCP entries).\n const rawPerf = await page.evaluate(() => {\n const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined;\n const paints = performance.getEntriesByType('paint');\n // Prefer pre-registered observer value (window.__zetaLCP) over buffered entries.\n // Buffered entries are often empty if the observer wasn't registered before navigation.\n const lcpFromObserver: number | null = (window as any).__zetaLCP ?? null;\n const lcpEntries = performance.getEntriesByType('largest-contentful-paint');\n const lcpFromEntries = lcpEntries.length > 0\n ? Math.round((lcpEntries[lcpEntries.length - 1] as any).startTime)\n : undefined;\n // @ts-ignore \u2014 stashed by the CLS init script\n // @ts-ignore \u2014 stashed by the web-vitals init script\n const stashedLcp: number | null = (window as any).__zetaLCP ?? null;\n // @ts-ignore\n const stashedCls: number | undefined = (window as any).__zetaCLS;\n return {\n ttfb: nav ? Math.round(nav.responseStart - nav.fetchStart) : undefined,\n fcp: paints.find(p => p.name === 'first-contentful-paint')?.startTime\n ? Math.round(paints.find(p => p.name === 'first-contentful-paint')!.startTime)\n : undefined,\n lcp: lcpFromObserver != null ? Math.round(lcpFromObserver) : lcpFromEntries,\n cls: typeof stashedCls === 'number' ? Math.round(stashedCls * 1000) / 1000 : undefined,\n };\n }).catch(() => null);\n\n // Accessibility audit via axe-core (WCAG 2.0 A/AA + best-practice)\n const a11yResult = await (async () => {\n try {\n const _require = createRequire(import.meta.url);\n const axePath = _require.resolve('axe-core');\n // page.evaluate() with script content bypasses CSP (DevTools Runtime.evaluate).\n // page.addScriptTag({ path }) is blocked by strict-CSP on many production sites.\n const axeContent = readFileSync(axePath, 'utf8');\n await page.evaluate(axeContent);\n const result = await page.evaluate(async () => {\n return (window as any).axe.run(document, {\n runOnly: { type: 'tag', values: ['wcag2a', 'wcag2aa', 'best-practice'] },\n resultTypes: ['violations'],\n });\n });\n // Full violation objects for DB storage (Phase 4.4)\n const violations = result.violations.map((v: any) => ({\n impact: v.impact as string,\n rule: v.id as string,\n description: v.description as string,\n // First offending node's outer HTML (truncated later in saveA11yViolations)\n nodeHtml: (v.nodes?.[0]?.html as string | undefined) ?? undefined,\n wcagTags: (v.tags as string[]).filter((t: string) => t.startsWith('wcag') || t.startsWith('best-')),\n }));\n const criticalCount = violations.filter((v: any) => v.impact === 'critical').length;\n return { violations, violationCount: violations.length, criticalCount };\n } catch (err) {\n logger.warn({ err: String((err as any)?.message ?? err) }, '[crawler] axe-core a11y audit failed (non-fatal)');\n return null;\n }\n })();\n const a11yScore = a11yResult\n ? Math.max(0, 100 - (a11yResult.criticalCount * 20) - ((a11yResult.violationCount - a11yResult.criticalCount) * 5))\n : null;\n\n\n // Screen name strategy (SPA-aware):\n // 1. Title with page-specific segment (e.g. \"Dashboard | ZeTA\")\n // 2. aria-current=\"page\" active nav item (reliable for SPAs)\n // 3. Page-specific headings that are NOT the brand name\n // 4. URL path segments (skipping cuid/UUIDs/numerics)\n const name = await (async () => {\n let brandName = '';\n\n // Compute reliable URL path-based name \u2014 skip cuid/UUID/numeric segments\n let pathName = 'Home';\n try {\n const u = new URL(url);\n const hostname = u.hostname.replace(/^www\\./, '').split('.')[0]!.toLowerCase();\n const allSegs = u.pathname.split('/').filter(Boolean);\n const IS_ID = (s: string) =>\n /^\\d+$/.test(s) || // numeric\n /^[0-9a-f]{8,}$/i.test(s) || // hex id\n /^[a-z]{1,2}[0-9a-z]{20,}$/i.test(s); // cuid/cuid2 (e.g. cm...)\n\n const readable = allSegs\n .filter((s) => !IS_ID(s))\n .map((s) => s.charAt(0).toUpperCase() + s.slice(1).replace(/[-_]/g, ' '));\n\n if (readable.length > 0) {\n const last = readable[readable.length - 1]!;\n const GENERIC = ['edit', 'new', 'create', 'view', 'show', 'index', 'detail', 'details'];\n if (GENERIC.includes(last.toLowerCase()) && readable.length > 1) {\n pathName = `${readable[readable.length - 2]} \u00B7 ${last}`;\n } else {\n pathName = last;\n }\n } else if (allSegs.length > 0) {\n // All segments were IDs \u2014 use the last non-trivial one\n const lastSeg = allSegs[allSegs.length - 1]!;\n pathName = lastSeg.slice(0, 8).toUpperCase();\n }\n\n // Append significant query params\n const SIG_PARAMS = ['product_cat', 'category', 'cat', 'type', 'tag', 'brand', 'filter', 'tab', 'section', 'view', 'play', 'mode', 'id', 'page'];\n const paramSuffix = SIG_PARAMS\n .map((p) => { const v = u.searchParams.get(p); return v ? ` \u00B7 ${v.replace(/[-_]/g, ' ').replace(/\\b\\w/g, (c) => c.toUpperCase())}` : ''; })\n .find(Boolean) ?? '';\n pathName = pathName + paramSuffix;\n\n // Detect brand name from hostname for later comparisons\n brandName = hostname;\n } catch { /* fall through */ }\n\n // 1. Document title \u2014 use only if it has a page-specific segment\n try {\n const title = await page.title();\n if (title && title.length > 0 && title.length < 120) {\n const parts = title.split(/\\s*[|\u2014\\-\u2013\u00B7]\\s*/);\n // Store brand candidate (usually last segment)\n if (parts.length > 1) brandName = (parts[parts.length - 1] ?? brandName).trim().toLowerCase();\n\n if (parts.length > 1) {\n // \"Dashboard | ZeTA\" \u2192 \"Dashboard\"\n const candidate = parts[0].trim();\n if (candidate.length > 2 && !/^\\d[\\d\\s]*$/.test(candidate)) return candidate;\n }\n // Single-segment title \u2014 only use if multi-word, not brand-name-like, and not the generic SPA app title\n const candidate = parts[0].trim();\n const isBrand = candidate.split(/\\s+/).length === 1 &&\n (candidate.toLowerCase().includes(brandName) || candidate.toLowerCase() === brandName);\n const isSiteGenericTitle = homeFingerprintTitle !== '' && candidate === homeFingerprintTitle;\n if (!isBrand && !isSiteGenericTitle && candidate.split(/\\s+/).length > 1 && !/^\\d[\\d\\s]*$/.test(candidate)) {\n return candidate;\n }\n }\n } catch { /* fall through */ }\n\n // 2. Active nav item \u2014 SPAs set aria-current=\"page\" on the active route link\n try {\n const activeNav = await page.locator('[aria-current=\"page\"]').first().textContent({ timeout: tuning.defaultTimeoutMs }).catch(() => null);\n if (activeNav) {\n const t = activeNav.trim();\n if (t.length > 1 && t.length < 60 && t.toLowerCase() !== brandName) return t;\n }\n } catch { /* fall through */ }\n\n // 3. Page-specific heading \u2014 skip if it's just the brand name\n try {\n const selectors = [\n 'main h1', '[role=\"main\"] h1', '.page-title', '.page-header h1', '.content h1',\n 'main h2', '[role=\"main\"] h2', '.page-header h2',\n ];\n for (const sel of selectors) {\n const h = await page.locator(sel).first().textContent({ timeout: tuning.defaultTimeoutMs }).catch(() => null);\n if (!h) continue;\n const t = h.trim();\n if (t.length < 2 || t.length > 80) continue;\n // Skip if it's the brand name (exact or contains hostname)\n if (t.toLowerCase() === brandName) continue;\n if (brandName && t.toLowerCase().replace(/\\s/g, '').includes(brandName.replace(/\\s/g, ''))) continue;\n return t;\n }\n } catch { /* fall through */ }\n\n // Safety: if the only candidate is the brand/hostname, fall back to URL path.\n try {\n const hostname = new URL(url).hostname.replace(/^www\\./, '').split('.')[0]!.toLowerCase();\n if (pathName !== 'Home' || name.toLowerCase() === hostname || name.toLowerCase().replace(/\\s/g, '') === hostname) {\n // name is still brand-name-equivalent \u2014 use URL-derived pathName\n if (name.toLowerCase() === hostname || name.toLowerCase().replace(/\\s/g, '') === hostname) {\n return pathName;\n }\n }\n } catch { /* ignore */ }\n\n return pathName;\n })();\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, name, url, opts.jobId, discoveryMethodFor(url));\n visited.set(canonicalize(url), screen.id);\n\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `${screen.id}-desktop-v${screen.version}.png`);\n\n // Wait for skeleton loaders / aria-busy spinners to resolve before screenshotting and analysis.\n // Stagehand V3 proxy does NOT support page.waitForFunction \u2014 use page.evaluate polling instead.\n await (async () => {\n const deadline = Date.now() + 4_000;\n while (Date.now() < deadline) {\n const ready = await page.evaluate(() => {\n const busy = document.querySelectorAll('[aria-busy=\"true\"], [data-loading=\"true\"]');\n const skeletons = document.querySelectorAll('.skeleton, [class*=\"skeleton\"], [class*=\"Skeleton\"]');\n return busy.length === 0 && skeletons.length === 0;\n }).catch(() => true); // if evaluate fails, assume ready\n if (ready) break;\n await new Promise(r => setTimeout(r, 200));\n }\n })();\n\n // Fire-and-forget per-page analyses \u2014 non-blocking, failures silently swallowed.\n // screen is now declared; page still has current page state and is fully hydrated.\n void (async () => {\n const screenId = screen.id;\n const [seoR, contrastR, flagsR, langR, formsR, a11yManualR] = await Promise.allSettled([\n checkSeo(page, url),\n auditColorContrast(page, url),\n detectFeatureFlags(page, url),\n detectLanguage(page, url),\n detectForms(page),\n auditAccessibility(page, url),\n ]);\n const base = { screenId, jobId: opts.jobId };\n if (seoR.status === 'fulfilled')\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'SEO_CHECK', payload: seoR.value }).catch(() => { });\n if (contrastR.status === 'fulfilled' && (contrastR.value as any).issues?.length)\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'COLOR_CONTRAST', payload: contrastR.value }).catch(() => { });\n if (flagsR.status === 'fulfilled' && (flagsR.value as any).flags?.length)\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'FEATURE_FLAGS', payload: flagsR.value }).catch(() => { });\n if (langR.status === 'fulfilled')\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'LANGUAGE_DETECTION', payload: langR.value }).catch(() => { });\n if (formsR.status === 'fulfilled' && Array.isArray(formsR.value) && formsR.value.length)\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'FORMS_DETECTED', payload: { forms: formsR.value } }).catch(() => { });\n if (a11yManualR.status === 'fulfilled' && (a11yManualR.value as any).violations?.length)\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, { ...base, type: 'A11Y_MANUAL_AUDIT', payload: a11yManualR.value }).catch(() => { });\n })();\n\n // Freeze all CSS animations/transitions so screenshots are stable across runs\n try { await page.addStyleTag({ content: '*, *::before, *::after { animation-duration: 0s !important; animation-delay: 0s !important; transition-duration: 0s !important; transition-delay: 0s !important; animation-play-state: paused !important; animation-fill-mode: both !important; }' }); } catch { /* Stagehand proxy may not expose addStyleTag */ }\n // Freeze JS-driven animations (requestAnimationFrame loops, setInterval animations)\n await page.evaluate(() => {\n try {\n const noop = () => 0;\n Object.defineProperty(window, 'requestAnimationFrame', { value: noop, configurable: true });\n Object.defineProperty(window, 'cancelAnimationFrame', { value: noop, configurable: true });\n } catch { /* property may not be configurable */ }\n }).catch(() => { });\n\n // Replay-first: check for a cached link-discovery recipe before calling AI Stagehand\n const canonUrl = canonicalize(url);\n const linkRecipe = await AppBrain.getActionRecipe(\n opts.tenantId, opts.projectId, new URL(url).hostname, `link-discovery:${canonUrl}`\n ).catch(() => null);\n const cachedLinks: string[] | null = (linkRecipe && (linkRecipe as any).successRate >= 0.7)\n ? (((linkRecipe as any).steps as any[])\n .map((s: any) => s.href)\n .filter((href: string | undefined): href is string => !!href && isUsefulNavigationUrl(href, origin)))\n : null;\n if (cachedLinks) {\n logger.info({ url, cachedCount: cachedLinks.length }, '[crawler] link-discovery: using cached recipe \u2014 AI will still run and merge');\n }\n\n // Emit progress now \u2014 navigation done, page stable.\n // Use the same visited-count formula as the post-capture block so progress\n // advances on EVERY URL visit (not just on successful screen saves).\n {\n const effMax = isFinite(maxScreens) ? Math.min(visited.size + queue.length, maxScreens * 3) : visited.size + queue.length;\n maxSeenTotal = Math.max(maxSeenTotal, effMax);\n const rawPrePct = 20 + Math.round(Math.min(57, (visited.size / Math.max(1, maxSeenTotal)) * 57));\n const preCapturePct = Math.max(lastEmittedPct, rawPrePct);\n lastEmittedPct = preCapturePct;\n await onProgress?.(preCapturePct, `Crawling ${visited.size} of ~${visited.size + queue.length} \u00B7 ${(() => { try { return new URL(url).pathname || '/'; } catch { return '/'; } })()}`);\n }\n\n await waitForScreenshotReady(page, rawPage ?? undefined);\n\n // P3a: Async content detection \u2014 count AFTER networkidle+lazy-load so lazy-fetched content\n // is included. Previously captured before waitForScreenshotReady which caused AI skip logic\n // to see skeleton element counts instead of real populated counts.\n const preDomCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"],[onclick],[aria-label]').length\n ).catch(() => 0);\n await onProgress?.(lastEmittedPct, `Capturing ${(() => { try { return new URL(url).pathname || '/'; } catch { return '/'; } })()}`);\n\n // FM-4: capture device pixel ratio for coordinate scaling in element highlighting\n const pageDpr: number = await (rawPage ?? page).evaluate(() => window.devicePixelRatio ?? 1).catch(() => 1);\n\n // Extract elements first so we can highlight them in the screenshot\n const elements = await extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined).catch((err: any) => {\n console.error('[crawler] extractElements failed:', err);\n return [] as Awaited<ReturnType<typeof extractElements>>;\n });\n\n // Inject bounding boxes for the screenshot\n await page.evaluate((elems: any[]) => {\n const container = document.createElement('div');\n container.id = '__zeta_element_highlights';\n container.style.position = 'absolute';\n container.style.top = '0';\n container.style.left = '0';\n container.style.width = '100%';\n container.style.height = '100%';\n container.style.pointerEvents = 'none';\n container.style.zIndex = '2147483647';\n \n elems.forEach((el, index) => {\n if (!el.boundingRect) return;\n const rect = el.boundingRect;\n const box = document.createElement('div');\n box.style.position = 'absolute';\n box.style.left = (rect.x + window.scrollX) + 'px';\n box.style.top = (rect.y + window.scrollY) + 'px';\n box.style.width = rect.width + 'px';\n box.style.height = rect.height + 'px';\n box.style.border = '2px solid rgba(255, 0, 0, 0.8)';\n box.style.backgroundColor = 'rgba(255, 0, 0, 0.1)';\n box.style.boxSizing = 'border-box';\n \n const label = document.createElement('div');\n label.textContent = el.role || 'element';\n label.style.position = 'absolute';\n label.style.top = '-16px';\n label.style.left = '-2px';\n label.style.backgroundColor = 'rgba(255, 0, 0, 0.9)';\n label.style.color = '#FFF';\n label.style.fontSize = '10px';\n label.style.padding = '2px 4px';\n label.style.borderRadius = '2px';\n label.style.whiteSpace = 'nowrap';\n label.style.fontFamily = 'monospace';\n box.appendChild(label);\n \n container.appendChild(box);\n });\n document.body.appendChild(container);\n }, elements).catch(() => {});\n\n // Parallelize: screenshot + link discovery + AT capture\n const [, nextLinks, atElements] = await Promise.all([\n page.screenshot({ path: shotPath, fullPage: true })\n .then(async () => {\n const cloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`);\n return (AppBrain.saveScreenshot as any)(opts.tenantId, opts.projectId, screen.id, shotPath, screen.version, 'DESKTOP', cloudUrl, pageDpr);\n })\n .catch((err: any) => console.error('[crawler] page.screenshot failed:', err)),\n // Always run AI link discovery (even when cache exists) \u2014 cache is merged in, not used as a replacement.\n // Skipping AI when cache exists was a bug: stale cache from broken crawls permanently blocked discovery.\n // Note: preDomCount < aiMinElements guard removed \u2014 it was backwards: sparse pages (SPAs) need AI most.\n discoverLinks(stagehand, origin, page, linkLLM ?? undefined, aiSkipCount > 0, rawPage ?? undefined)\n .then((metas) => {\n // Persist nav-graph edges fire-and-forget\n if (metas.length > 0) {\n AppBrain.saveDiscoveredLinks(opts.tenantId, opts.projectId, screen.id, metas.map((m) => ({\n href: m.url, text: m.text, landmark: m.landmark, linkType: 'NAV_LINK', source: m.source, jobId: opts.jobId,\n }))).catch(() => {});\n }\n return metas.map(m => m.url);\n })\n .then((freshLinks) => {\n if (aiSkipCount > 0) aiSkipCount--;\n aiErrorStreak = 0;\n const freshUrls = freshLinks;\n const merged = (cachedLinks ? Array.from(new Set([...cachedLinks, ...freshUrls])) : freshUrls)\n .filter((href) => isUsefulNavigationUrl(href, origin));\n logger.info({ url, domLinks: freshLinks.length, cached: cachedLinks?.length ?? 0, merged: merged.length }, '[crawler] link-discovery: result');\n // Always persist fresh recipe so stale cache gets overwritten with new AI discoveries\n if (merged.length > 0) {\n AppBrain.saveActionRecipe(opts.tenantId, opts.projectId, {\n domain: new URL(url).hostname,\n purpose: `link-discovery:${canonUrl}`,\n fingerprint: sha256(canonUrl),\n steps: merged.map((href) => ({ action: 'link', href })),\n successRate: 0.8,\n }).catch(() => { });\n }\n return merged;\n })\n .catch((err: any) => {\n const fallback: string[] = (err?.domLinks ?? []).map((l: DiscoveredLinkMeta) => l.url);\n if (err?.isRateLimit) {\n aiErrorStreak++;\n if (aiErrorStreak >= 5) { aiSkipCount = 3; aiErrorStreak = 0; logger.warn('[crawler] 5 consecutive AI rate limits \u2014 pausing AI link discovery for next 3 screens then retrying'); }\n if (!aiRateLimitWarned) {\n aiRateLimitWarned = true;\n onProgress?.(20, 'AI quota exhausted \u2014 falling back to DOM-only link discovery').catch(() => { });\n }\n }\n return fallback;\n }),\n readScreen(rawPage ?? page).catch(() => [] as Awaited<ReturnType<typeof readScreen>>),\n ]);\n\n // Cleanup highlights\n await page.evaluate(() => {\n const container = document.getElementById('__zeta_element_highlights');\n if (container) container.remove();\n }).catch(() => {});\n logger.info({ url, screenId: screen.id, version: screen.version, elements: elements.length, links: nextLinks.length, atSample: atElements.slice(0, 3).map((a: any) => a.label) }, '[crawler] screen captured');\n console.log('[crawler] AT:', JSON.stringify(atElements.slice(0, 5)));\n // Fire-and-forget keyboard-nav probe \u2014 records Tab sequence and focus-indicator issues per screen\n probeKeyboardNav(page).then((kbResult) => {\n if (kbResult.focusableCount > 0) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id, jobId: opts.jobId, type: 'KEYBOARD_NAV', payload: kbResult,\n }).catch(() => { });\n }\n }).catch(() => { });\n\n // Per-screen probes: split read-only (awaited, safe on main page) vs mutating (isolated page).\n // READ-ONLY probes are awaited before BFS navigates \u2014 DOM must reflect current screen.\n // MUTATING probes (dropdowns/CRUD/filters/advanced) open a fresh page to isolate state changes.\n {\n // Resolve browser context from rawPage (actual Playwright page, not Stagehand proxy).\n const safeContext: import('playwright').BrowserContext | null =\n typeof (rawPage as any)?.context === 'function'\n ? (rawPage as any).context()\n : typeof (page as any)?.context === 'function'\n ? (page as any).context()\n : playwrightBrowser?.contexts()[0] ?? null;\n\n // --- Read-only probes: awaited with 25s timeout, never mutate page state ---\n const roTimeout = new Promise<PromiseSettledResult<never>[]>((resolve) =>\n setTimeout(() => resolve([\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n ]), 25_000)\n );\n const [nestedCtxRes, shadowRes, a11yRes, perfRes, swRes] = await Promise.race([\n Promise.allSettled([\n crawlNestedContexts(rawPage ?? page, safeContext, url),\n crawlShadowDom(rawPage ?? page),\n crawlAccessibilityTree(rawPage ?? page),\n collectPerfMetrics(rawPage ?? page, url),\n inspectServiceWorker(rawPage ?? page),\n ]),\n roTimeout,\n ]);\n\n const roPayload: Record<string, unknown> = { screenId: screen.id, url };\n if (nestedCtxRes.status === 'fulfilled' && nestedCtxRes.value && (nestedCtxRes.value as any).totalContextsFound > 0)\n roPayload.nestedContexts = nestedCtxRes.value;\n if (shadowRes.status === 'fulfilled' && shadowRes.value && (shadowRes.value as any).shadowHostCount > 0)\n roPayload.shadowDom = shadowRes.value;\n if (a11yRes.status === 'fulfilled' && a11yRes.value)\n roPayload.accessibilityTree = a11yRes.value;\n if (perfRes.status === 'fulfilled' && (perfRes.value as any).requestCount > 0)\n roPayload.performance = perfRes.value;\n if (swRes.status === 'fulfilled' && (swRes.value as any).supported)\n roPayload.serviceWorker = swRes.value;\n if (Object.keys(roPayload).length > 2) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'PER_SCREEN_PROBES', payload: roPayload,\n }).catch(() => {});\n }\n\n // --- Mutating probes (interactive): isolated page, fire-and-forget, only when interactive ---\n if (screen?.id && opts.interactive !== false && safeContext) {\n void (async () => {\n let probePage: import('playwright').Page | null = null;\n try {\n // Cap concurrent probe pages: if too many already open, skip to prevent resource exhaustion.\n const openProbePages = safeContext.pages().length;\n if (openProbePages > 8) {\n logger.warn({ url, openProbePages }, '[crawler] probe page cap reached \u2014 skipping mutating probes for this screen');\n return;\n }\n probePage = await safeContext.newPage();\n await probePage.goto(url, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => {});\n await probePage.waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => {});\n await waitForStableDOM(probePage as any, 4_000, 400).catch(() => {});\n\n const muTimeout = new Promise<PromiseSettledResult<never>[]>((resolve) =>\n setTimeout(() => resolve([\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n { status: 'rejected' as const, reason: 'probe-timeout' },\n ]), 60_000)\n );\n const [dropEnumRes, crudRes, filterRes, advancedRes] = await Promise.race([\n Promise.allSettled([\n enumerateDropdowns(probePage),\n probeCrudFlows(probePage, name),\n crawlFiltersAndPagination(probePage),\n probeAdvancedUI(probePage),\n ]),\n muTimeout,\n ]);\n\n const muPayload: Record<string, unknown> = { screenId: screen.id, url };\n if (dropEnumRes.status === 'fulfilled' && (dropEnumRes.value as any).totalOptionsFound > 0)\n muPayload.dropdowns = dropEnumRes.value;\n if (crudRes.status === 'fulfilled' && ((crudRes.value as any).flows?.length > 0 || (crudRes.value as any).toastsObserved?.length > 0))\n muPayload.crudFlows = crudRes.value;\n if (filterRes.status === 'fulfilled' && (filterRes.value as any).filters?.length > 0)\n muPayload.filtersAndPagination = filterRes.value;\n if (advancedRes.status === 'fulfilled' && advancedRes.value &&\n ((advancedRes.value as any).datePickers?.length > 0 || (advancedRes.value as any).sliders?.length > 0 ||\n (advancedRes.value as any).typeaheads?.length > 0 || (advancedRes.value as any).dragDrop?.library !== 'none'))\n muPayload.advancedUI = advancedRes.value;\n if (Object.keys(muPayload).length > 2) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'PER_SCREEN_PROBES_MUTATING', payload: muPayload,\n }).catch(() => {});\n }\n } catch {\n // non-fatal \u2014 probe failures must not block BFS\n } finally {\n await probePage?.close().catch(() => {});\n }\n })();\n }\n }\n\n // Inline auth-wall detection: PHP/legacy apps render session-expired content\n // without changing the URL, bypassing all URL-path-based guards above.\n const INLINE_AUTH_WALL_RE = /your login session (was|has been) expired|session (has )?expired[^.]*click|please (log ?in|sign ?in) to continue|you (are|were) logged out|your session has timed out/i;\n const pageBodyText = await page.evaluate(() => (document as any).body?.innerText ?? '').catch(() => '');\n if (INLINE_AUTH_WALL_RE.test(pageBodyText)) {\n logger.warn({ url, screenId: screen.id }, '[crawler] Inline session-expired content detected \u2014 skipping DOM snapshot, marking requiresAuth');\n AppBrain.updateScreenRequiresAuth(opts.tenantId, screen.id, true).catch(() => {});\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id, jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: { url, reason: 'Inline session-expired page rendered without URL redirect. Re-authenticate and re-crawl.' },\n }).catch(() => {});\n } else {\n\n // Capture DOM snapshot for structural analysis, and extract Markdown/text\n // content from the same DOM (crawl4AI-parity text output) \u2014 no extra fetch.\n try {\n const domContent = await capturePageHtml(page);\n if (!domContent) {\n logger.warn({ url, screenId: screen.id }, '[crawler] markdown extraction skipped: DOM snapshot unavailable');\n } else {\n const domPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(domPath, domContent, 'utf8');\n // Upload DOM snapshot to cloud alongside PNG, then persist both paths\n (async () => {\n const domKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(domPath)}`;\n const domCloudUrl = await uploadToCloud(domPath, domKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, domPath, domCloudUrl).catch(() => {});\n })();\n\n // Supplement markdown with iFrame and Shadow DOM content\n const [iframeContent, shadowContent] = await Promise.all([\n extractIframeContent(page).catch(() => []),\n pierceShadowDom(page).catch(() => ''),\n ]);\n const supplemental = [\n ...iframeContent.map((f: any) => f.markdown).filter(Boolean),\n shadowContent,\n ].join('\\n\\n').trim();\n\n const extracted = extractMarkdown(\n supplemental ? domContent + '\\n<!-- iframe/shadow -->\\n' + supplemental.slice(0, 3_000) : domContent,\n url\n );\n let fitMarkdown: string | undefined;\n if (extracted) {\n const mdPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.md');\n fitMarkdown = buildFitMarkdown(extracted.markdown, [\n ...domainProfile.importantScreenPatterns,\n ...domainProfile.workflowGoals,\n ...(opts.bestFirstKeywords ?? []),\n ]);\n const { text: scrubbed, scrubbed: hadPii } = scrubPii(extracted.markdown);\n if (hadPii) logger.info({ url }, '[crawler] PII detected and redacted from markdown');\n const dedupResult = deduplicator.check(url, scrubbed);\n if (dedupResult.isDuplicate) {\n logger.info({ url, similarUrl: dedupResult.similarUrl, score: dedupResult.similarityScore }, '[crawler] near-duplicate page skipped');\n }\n await fs.writeFile(mdPath, scrubbed, 'utf8');\n\n // Generate a one-sentence AI summary from the markdown \u2014 fire-and-forget\n const summaryPromise = (async () => {\n try {\n const llmCfg = await getCachedCrawlLLM(opts.tenantId);\n if (!llmCfg) return undefined;\n const snippet = extracted.markdown.slice(0, 1200);\n // Skip LLM when content is too thin \u2014 output would be useless\n if (snippet.trim().length < 80) return undefined;\n const summarySeed = deterministicSeed(`${opts.tenantId}:${opts.projectId ?? ''}:page-summary:${url}`);\n const { text, usage } = await askTracked(\n 'You are a QA analyst. Output ONLY a single complete sentence (no preamble, no quotes) describing what this screen does or shows. Be specific. Stop after the first sentence.',\n `Screen: \"${name}\"\\nURL: ${url}\\n\\nContent:\\n${snippet}`,\n llmCfg,\n 200,\n undefined,\n { temperature: 0, seed: summarySeed },\n );\n if (usage) {\n recordLLMCall({\n tenantId: opts.tenantId,\n projectId: opts.projectId,\n jobId: opts.jobId,\n agentType: 'crawl_summary',\n label: `page_summary:${name}`,\n usage,\n }).catch(() => { });\n }\n // Keep only the first sentence if the LLM returned multiple\n const clean = text.trim().replace(/^[\"']|[\"']$/g, '');\n const firstSentence = clean.match(/^[^.!?]+[.!?]/)?.[0] ?? clean;\n return firstSentence.trim();\n } catch { return undefined; }\n })();\n\n AppBrain.updateScreenMarkdown(opts.tenantId, opts.projectId, screen.id, {\n markdownPath: mdPath,\n markdownMethod: extracted.method,\n markdownWordCount: extracted.wordCount,\n markdown: fitMarkdown ?? extracted.markdown,\n heading: extracted.title || name,\n }).catch((err: any) => console.warn('[crawler] markdown extraction save failed:', err));\n\n pendingSummaryWrites.push(\n summaryPromise.then((aiSummary) => {\n if (aiSummary) AppBrain.updateScreenAiSummary(opts.tenantId, screen.id, aiSummary).catch((e: any) => {\n logger.warn({ screenId: screen.id, err: String(e?.message ?? e) }, '[crawler] aiSummary DB save failed');\n });\n }).catch((e: any) => {\n logger.warn({ screenId: screen.id, err: String(e?.message ?? e) }, '[crawler] aiSummary generation failed');\n })\n );\n }\n\n const structuredJson = summarizeStructuredElements(atElements);\n const artifact = buildCrawlArtifactEnvelope({\n tenantId: opts.tenantId,\n projectId: opts.projectId,\n jobId: opts.jobId,\n url,\n canonicalUrl: canonicalize(url),\n screenId: screen.id,\n screenshotPath: shotPath,\n domPath,\n domContent,\n markdown: extracted?.markdown,\n fitMarkdown,\n accessibilityElements: atElements,\n structuredJson,\n evidence: [\n { type: 'domain_profile', payload: { industry: domainProfile.industry, confidence: domainProfile.confidence } },\n { type: 'engine_route', payload: routeDecision },\n { type: 'screen_fingerprints', payload: { urlCanonicalHash: sha256(canonicalize(url)) } },\n ],\n });\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id,\n jobId: opts.jobId,\n type: 'SCREEN_ARTIFACT_ENVELOPE',\n payload: artifact,\n }).catch((err: any) => console.warn('[crawler] artifact evidence save failed:', err?.message ?? err));\n }\n } catch (err: any) {\n logger.warn({ url, screenId: screen.id, err: String(err?.message ?? err) }, '[crawler] markdown extraction failed');\n }\n } // end: inline auth-wall else\n\n // Persist a11y score + individual violations \u2014 fire-and-forget, non-fatal\n if (a11yScore !== null) {\n AppBrain.updateScreenA11y(opts.tenantId, screen.id, { a11yScore })\n .catch((err: any) => console.warn('[crawler] a11y score update failed:', err));\n }\n if (a11yResult !== null && a11yResult.violations.length > 0) {\n AppBrain.saveA11yViolations(opts.tenantId, opts.projectId, screen.id, a11yResult.violations, opts.jobId)\n .catch((err: any) => console.warn('[crawler] a11y violations save failed:', err));\n }\n\n // DOM hash was registered before saveScreen \u2014 no action needed here.\n\n // Build a role\u2192selectorHint lookup from AT data so fingerprints can include tag hints\n const atByRole = new Map<string, string>();\n for (const at of atElements) {\n if (!atByRole.has(at.role)) atByRole.set(at.role, at.selectorHint);\n }\n\n // Auto-create DESKTOP visual baseline on first crawl (no-op on recrawls)\n AppBrain.autoCreateVisualBaseline(opts.tenantId, opts.projectId, screen.id, 'DESKTOP', shotPath, gitInfo.branch, gitInfo.commit || undefined)\n .catch(() => { });\n\n // Phase 2: compute element hash for stale-test detection\n const newElementHash = computeElementHash(elements);\n AppBrain.updateElementHash(opts.tenantId, screen.id, newElementHash, (screen as any).elementHash ?? null)\n .catch((err: any) => console.warn('[crawler] element hash update failed:', err));\n\n // Phase 3: perceptual screenshot diff \u2014 non-blocking\n if (screen.version > 1) {\n (async () => {\n try {\n const prevShot = await AppBrain.getPreviousScreenshotPath(opts.tenantId, screen.id, screen.version - 1);\n if (prevShot) {\n const { screenshotDiffPercent } = await import('./phash.js');\n const { pHashDistance, changeLevel } = await screenshotDiffPercent(prevShot, shotPath);\n await AppBrain.saveScreenDiff(opts.tenantId, opts.projectId, screen.id, screen.version - 1, screen.version, pHashDistance, changeLevel);\n }\n } catch (err) {\n console.warn('[crawler] pHash diff skipped:', err);\n }\n })();\n }\n\n // VisualDiff pipeline \u2014 compare against approved baseline (not previous screenshot)\n if (screen.version > 1) {\n (async () => {\n try {\n const baseline = await AppBrain.getVisualBaselineForDiff(opts.tenantId, screen.id, 'DESKTOP', gitInfo.branch);\n if (baseline && baseline.storagePath !== shotPath) {\n // Resolve baseline file path \u2014 local copy may have been rotated; fall back to cloud download\n let baselinePath: string = baseline.storagePath;\n let tempBaselinePath: string | null = null;\n const localExists = await fs.access(baseline.storagePath).then(() => true, () => false);\n if (!localExists) {\n if (baseline.cloudUrl) {\n try {\n const resp = await fetch(baseline.cloudUrl);\n if (resp.ok) {\n const buf = Buffer.from(await resp.arrayBuffer());\n tempBaselinePath = `${shotPath}.baseline-tmp.png`;\n await fs.writeFile(tempBaselinePath, buf);\n baselinePath = tempBaselinePath;\n logger.info({ screenId: screen.id }, '[crawler] VisualDiff baseline downloaded from cloud storage');\n } else {\n logger.warn({ screenId: screen.id, status: resp.status }, '[crawler] VisualDiff skipped \u2014 baseline cloud fetch returned non-200');\n return;\n }\n } catch (dlErr) {\n logger.warn({ screenId: screen.id, err: String(dlErr) }, '[crawler] VisualDiff skipped \u2014 baseline cloud download failed');\n return;\n }\n } else {\n logger.warn({ screenId: screen.id }, '[crawler] VisualDiff skipped \u2014 baseline not on disk and no cloudUrl available');\n return;\n }\n }\n try {\n const { screenshotDiffPercent, gridLayoutDiff } = await import('./phash.js');\n const [{ pHashDistance, changeLevel }, layoutChanges, elementShifts] = await Promise.all([\n screenshotDiffPercent(baselinePath, shotPath, baseline.ignoredRegions),\n gridLayoutDiff(baselinePath, shotPath, baseline.ignoredRegions),\n AppBrain.computeElementLayoutDiff(opts.tenantId, screen.id, 'DESKTOP'),\n ]);\n let verdict = pHashVerdict(pHashDistance, changeLevel, [\n ...layoutChanges,\n ...elementShifts.map((s) => ({ location: 'element', severity: s.severity, description: s.description })),\n ]);\n\n // pHash is a cheap, always-on filter; only spend an LLM call on the\n // screens it flags as worth a closer look. It also can't tell\n // meaningful UI changes apart from anti-aliasing/font-rendering noise,\n // which is exactly what Visual AI comparison exists to filter out.\n if (verdict.changeType === 'SIGNIFICANT' || verdict.changeType === 'CRITICAL') {\n try {\n const regions = baseline.ignoredRegions ?? [];\n // Same mask the pHash passes already applied \u2014 otherwise a\n // manually-masked region (timestamp, ad banner, live counter)\n // still reaches the AI verdict unmasked and can get flagged.\n const [baselineBuffer, newBuffer] = regions.length > 0\n ? await (async () => {\n const { applyMask } = await import('./phash.js');\n return Promise.all([applyMask(baselinePath, regions), applyMask(shotPath, regions)]);\n })()\n : await Promise.all([\n fs.readFile(baselinePath),\n fs.readFile(shotPath),\n ]);\n const aiResult = await aiVisualCompare({\n baselineImageBase64: baselineBuffer.toString('base64'),\n newImageBase64: newBuffer.toString('base64'),\n screenName: screen.name,\n screenPurpose: 'Application screen captured during automated crawl',\n tenantId: opts.tenantId,\n projectId: opts.projectId,\n });\n verdict = mergeAiVisualVerdict(verdict, aiResult, screen.name);\n } catch (aiErr) {\n logger.warn({ screenId: screen.id, err: String(aiErr) }, '[crawler] AI visual compare failed, keeping pHash-only verdict');\n }\n }\n\n let { changeType, recommendation, changes: allChanges, bugReportDraft, aiSummary } = verdict;\n\n // R7: Apply per-project visual diff threshold \u2014 suppress diffs below the threshold\n if (changeType !== 'NONE') {\n try {\n const project = await AppBrain.getProject(opts.tenantId, opts.projectId);\n const threshold = (project as any)?.visualDiffThreshold ?? null;\n if (threshold !== null && pHashDistance < threshold) {\n changeType = 'NONE';\n }\n } catch { /* non-fatal \u2014 use verdict as-is */ }\n }\n\n if (changeType !== 'NONE') {\n let newScreenshotCloudUrl: string | undefined;\n let diffImageCloudUrl: string | undefined;\n try {\n const { getTenantStorageConfig, uploadScreenshotToTenantStorage, buildArtifactKey } = await import('@detiq/app-brain');\n const storageCfg = await getTenantStorageConfig(opts.tenantId).catch(() => null);\n if (storageCfg) {\n const key = buildArtifactKey(opts.tenantId, opts.projectId, 'visual-diffs', `${screen.id}-v${screen.version}.png`, storageCfg.prefix);\n newScreenshotCloudUrl = await uploadScreenshotToTenantStorage(storageCfg, shotPath, key);\n\n // R5: Generate and upload pixelmatch diff image (changed pixels in red)\n try {\n const { generatePixelmatchDiff } = await import('./phash.js');\n const diffBuffer = await generatePixelmatchDiff(baselinePath, shotPath, baseline.ignoredRegions ?? []);\n const diffTmpPath = `${shotPath}.diff.png`;\n await fs.writeFile(diffTmpPath, diffBuffer);\n const diffKey = buildArtifactKey(opts.tenantId, opts.projectId, 'visual-diffs', `${screen.id}-v${screen.version}-diff.png`, storageCfg.prefix);\n diffImageCloudUrl = await uploadScreenshotToTenantStorage(storageCfg, diffTmpPath, diffKey);\n fs.unlink(diffTmpPath).catch(() => {});\n } catch (diffErr) {\n logger.warn({ screenId: screen.id, err: String(diffErr) }, '[crawler] pixelmatch diff generation failed, skipping');\n }\n }\n } catch { /* non-fatal \u2014 falls back to local path */ }\n await AppBrain.saveVisualDiff(opts.tenantId, {\n baselineId: baseline.id,\n newScreenshotPath: shotPath,\n newScreenshotCloudUrl,\n diffImageCloudUrl,\n diffScore: pHashDistance,\n changeType,\n changes: allChanges,\n recommendation,\n bugReportDraft,\n aiSummary,\n });\n }\n } finally {\n if (tempBaselinePath) fs.unlink(tempBaselinePath).catch(() => {});\n }\n }\n } catch (err: any) {\n console.warn('[crawler] VisualDiff pipeline failed:', err);\n }\n })();\n }\n\n const linkMappings = await extractLinkMappings(page, origin);\n\n // Auth-wall guard: check if the page drifted to a login/error URL during the async\n // element extraction window (30-90s). If so, the `elements` array contains login-page\n // elements \u2014 saving them would corrupt the screen's element catalog.\n const postExtractUrl = (() => { try { return page.url(); } catch { return url; } })();\n const postExtractParsed = (() => { try { return new URL(postExtractUrl); } catch { return new URL(url); } })();\n const driftedToAuthWall = !weWantedThisPage && (\n BFS_LOGIN_PATH.test(postExtractParsed.pathname) || BFS_ERROR_PATH.test(postExtractParsed.pathname)\n );\n if (driftedToAuthWall) {\n logger.warn({ url, postExtractUrl }, '[crawler] Page drifted to auth wall during element extraction \u2014 skipping element save to prevent login-page element contamination');\n AppBrain.updateScreenRequiresAuth(opts.tenantId, screen.id, true).catch(() => {});\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id,\n jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: { url, landed: postExtractUrl, reason: 'Session expired during element extraction. Re-capture session and re-crawl this page.' },\n }).catch(() => {});\n } else {\n if (elements.length === 0) {\n // Extraction returned nothing \u2014 keep existing elements rather than wiping them.\n // Causes: page.evaluate failure, contentFallbackElements threw, SPA not yet hydrated.\n logger.warn({ url, screenId: screen.id }, '[crawler] extractElements returned 0 \u2014 preserving existing elements to avoid data loss');\n // Queue for re-visit with longer wait \u2014 SPA content may not have hydrated yet\n if (!revisitQueue.includes(url)) {\n revisitQueue.push(url);\n logger.info({ url }, '[crawler] 0-element page queued for re-visit with extended hydration wait');\n }\n } else {\n // Clear existing elements before re-saving \u2014 prevents duplicates on re-crawl\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, screen.id).catch(() => {});\n // Batch element saves: 2 concurrent DB writes (4 caused pool saturation at 5 workers)\n for (let _ei = 0; _ei < elements.length; _ei += 2) {\n const _batch = elements.slice(_ei, _ei + 2);\n await Promise.all(_batch.map(async (el: any) => {\n const saved = await AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark);\n // Populate ElementFingerprint \u2014 fire-and-forget, failures are non-fatal\n const label = el.meaning;\n const role = el.role ?? 'unknown';\n const selectorHint = atByRole.get(role) ?? role;\n const selectors = [\n { type: 'role-label', value: `${role}:${label}`, confidence: 0.9 },\n { type: 'aria-label', value: label, confidence: 0.85 },\n { type: 'tag-hint', value: selectorHint, confidence: 0.6 },\n ];\n await AppBrain.saveElementFingerprint(opts.tenantId, opts.projectId, (saved as any).id, selectors).catch(console.warn);\n }));\n }\n } // end inner else: elements.length > 0\n for (const lm of linkMappings) {\n const safety = assessActionSafety(lm.label, domainProfile);\n if (!safety.allowed) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id,\n jobId: opts.jobId,\n type: 'ACTION_BLOCKED_BY_SAFETY_POLICY',\n payload: { label: lm.label, href: lm.href, decision: safety, profile: domainProfile.industry },\n }).catch(() => { });\n continue;\n }\n pendingTransitions.push({ fromScreenId: screen.id, elementMeaning: lm.label, targetUrl: lm.href });\n AppBrain.saveActionRecipe(opts.tenantId, opts.projectId, {\n domain: new URL(url).hostname,\n purpose: `navigate:${lm.label}`,\n fingerprint: sha256(`${canonicalize(url)}:${lm.label}:${canonicalize(lm.href)}`),\n steps: [{ action: 'click', label: lm.label, targetUrl: lm.href, fromUrl: url }],\n successRate: 0.5,\n }).catch(() => { });\n\n if (!selective) {\n try {\n const targetPath = new URL(lm.href).pathname;\n const canonLmHref = canonicalize(lm.href);\n if (\n !SKIP_PATH.test(targetPath) &&\n isUsefulNavigationUrl(lm.href, origin) &&\n !queued.has(canonLmHref) &&\n !visited.has(canonLmHref) &&\n queued.size < maxScreens * 3\n ) {\n if (robotsCache && !await robotsCache.isAllowed(lm.href)) continue;\n queued.add(canonLmHref);\n queue.push(lm.href, { parentElements: elements.length });\n edges.push({ fromUrl: url, toUrl: lm.href });\n logger.info({ fromUrl: url, newUrl: lm.href, label: lm.label, queueSize: queue.length }, '[crawler] anchor mapping added to queue');\n }\n } catch { /* ignore invalid link mapping */ }\n }\n }\n if (!selective) {\n for (const href of nextLinks) {\n edges.push({ fromUrl: url, toUrl: href });\n // Skip WooCommerce/e-commerce action URLs \u2014 these are AJAX/form actions that render\n // the same page template with a compare widget; they are not distinct page routes.\n // They would all get queued (different `id` param = different canonical URL), navigated,\n // found \"duplicate DOM\", and burn through totalAttemptsThisSegment without any gain.\n try {\n const hrefParams = new URL(href).searchParams;\n const actionVal = hrefParams.get('action') ?? '';\n if (/^yith-|^wc-|^vc_|^elementor/.test(actionVal)) continue;\n } catch { /* invalid URL, let it fall through */ }\n const canonHref = canonicalize(href);\n if (!queued.has(canonHref) && !visited.has(canonHref) && queued.size < maxScreens * 3) {\n // Don't flood the queue with generated ID-like route segments.\n try {\n const hrefPath = new URL(href).pathname;\n if (isGeneratedDynamicPath(hrefPath) && !_activeSeedPatterns.some(re => re.test(hrefPath))) continue;\n } catch { /* ignore invalid URLs */ }\n if (robotsCache && !await robotsCache.isAllowed(href)) continue;\n queued.add(canonHref);\n queue.push(href, { parentElements: elements.length }); // navigate to actual URL, dedup by canonical\n logger.info({ newUrl: href, queueSize: queue.length }, '[crawler] new URL added to queue');\n }\n }\n logger.info({ fromUrl: url, discovered: nextLinks.length, queueAfter: queue.length, visitedSoFar: visited.size }, '[crawler] link processing done');\n\n // Harvest SPA routes captured via history.pushState/replaceState interception\n try {\n const jsRoutes = await page.evaluate(() => {\n const routes = (window as any).__zetaDiscoveredRoutes ?? [];\n (window as any).__zetaDiscoveredRoutes = [];\n return routes as string[];\n }).catch(() => [] as string[]);\n for (const route of jsRoutes) {\n try {\n const abs = route.startsWith('http') ? route : `${origin}${route.startsWith('/') ? '' : '/'}${route}`;\n const canonRoute = canonicalize(abs);\n if (!queued.has(canonRoute) && !visited.has(canonRoute)) {\n queued.add(canonRoute);\n queue.push(abs);\n logger.info({ route: abs }, '[crawler] history.pushState: discovered SPA route');\n }\n } catch { /* ignore invalid routes */ }\n }\n } catch { /* non-fatal */ }\n\n // P3a: Post-extraction DOM count \u2014 detect async-loaded content.\n // Only check sparse pages (preDomCount < 25) where async widgets are likely.\n // If DOM grew significantly during AI extraction, re-visit later with networkidle.\n const asyncContentCheckMinDom = parseInt(process.env.CRAWLER_ASYNC_CONTENT_MIN_DOM ?? '') || 25;\n if (preDomCount < asyncContentCheckMinDom && !revisitQueue.includes(url)) {\n try {\n const postDomCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"],[onclick],[aria-label]').length\n ).catch(() => 0);\n const asyncGrowthRatio = parseFloat(process.env.CRAWLER_ASYNC_GROWTH_RATIO ?? '') || 1.3;\n const asyncGrowthFloor = parseInt(process.env.CRAWLER_ASYNC_GROWTH_FLOOR ?? '') || 4;\n if (postDomCount > preDomCount * asyncGrowthRatio + asyncGrowthFloor) {\n revisitQueue.push(url);\n logger.info({ url, preDomCount, postDomCount }, '[P3a] Async content detected \u2014 scheduled for re-visit');\n }\n } catch { /* non-fatal */ }\n }\n\n // P2: Static JS router detection \u2014 scan bundle for declared client-side routes.\n // Only run on first 5 pages (bundle is the same across pages; scanning every page is wasteful).\n if (visited.size <= (parseInt(process.env.CRAWLER_SPA_ROUTER_DETECT_LIMIT ?? '') || 5)) {\n try {\n const jsDetectedRoutes = await detectJsRoutes(page, origin);\n for (const route of jsDetectedRoutes) {\n const canonRoute = canonicalize(route);\n if (isUsefulNavigationUrl(route, origin) && !queued.has(canonRoute) && !visited.has(canonRoute) && queued.size < maxScreens * 3) {\n queued.add(canonRoute);\n queue.push(route, { parentElements: elements.length });\n logger.info({ route }, '[P2] JS router: discovered route added to queue');\n }\n }\n } catch { /* non-fatal */ }\n }\n\n // P4: Drain XHR-discovered page URL candidates (accumulated by network-observer callback).\n // These are relative paths extracted from JSON API response bodies.\n for (const relPath of [...xhrDiscoveredPaths]) {\n xhrDiscoveredPaths.delete(relPath);\n try {\n const abs = `${origin}${relPath}`;\n const canon = canonicalize(abs);\n if (isUsefulNavigationUrl(abs, origin) && !queued.has(canon) && !visited.has(canon) && queued.size < maxScreens * 3) {\n queued.add(canon);\n queue.push(abs);\n logger.info({ url: abs }, '[P4] XHR: page URL from JSON response added to queue');\n }\n } catch { /* ignore invalid paths */ }\n }\n\n // Gap 5: Skyvern URL-discovery bootstrap for pages that defeat DOM link extraction.\n // Triggered per-page when: zero DOM links found + fewer than 5 elements (dead-end / canvas page).\n // Skyvern returns URLs it discovered \u2192 added to queue for ZeTa's own BFS crawl (not saved directly).\n // ZeTa does all actual crawling \u2014 Skyvern is only a URL-discovery override layer.\n if (!selective && nextLinks.length === 0 && elements.length < (parseInt(process.env.CRAWL_SKYVERN_PAGE_MIN_ELEMENTS ?? '') || 5) && opts.skyvernConfig) {\n try {\n logger.info({ url }, 'Gap 5: thin page detected \u2014 asking Skyvern to discover navigation URLs');\n const skyvernNav = await skyvernNavigate(\n url,\n ['Find and return all navigation links, menu items, and page URLs accessible from this screen'],\n opts.skyvernConfig,\n );\n for (const skyvernUrl of skyvernNav.visitedUrls) {\n const canonSkyvernUrl = canonicalize(skyvernUrl);\n if (!queued.has(canonSkyvernUrl) && !visited.has(canonSkyvernUrl) && queued.size < maxScreens * 3) {\n logger.info({ url: skyvernUrl }, 'Gap 5: Skyvern-discovered URL added to ZeTa crawl queue');\n queued.add(canonSkyvernUrl);\n queue.push(skyvernUrl); // ZeTa will crawl this normally\n // Wire the KAG edge so the Skyvern-discovered page isn't flagged as an orphan\n pendingTransitions.push({ fromScreenId: screen.id, elementMeaning: 'Skyvern-discovered link', targetUrl: skyvernUrl });\n }\n }\n } catch { /* non-fatal \u2014 Skyvern unavailable */ }\n }\n }\n } // end auth-wall guard else\n\n if (rawPerf) {\n performanceMetrics.push({ url, screenName: name, ...rawPerf });\n }\n\n const screenApiEndpoints = capturedApiEndpoints.slice(apiObservationStartIndex);\n if (screenApiEndpoints.length > 0) {\n AppBrain.saveApiEndpointObservations(opts.tenantId, opts.projectId, screen.id, screenApiEndpoints)\n .then(() => AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id,\n jobId: opts.jobId,\n type: 'API_ENDPOINT_OBSERVATIONS',\n payload: { endpoints: screenApiEndpoints },\n }))\n .catch((err: any) => console.warn('[crawler] API endpoint observation save failed:', err?.message ?? err));\n }\n\n // Persist performance snapshot (web vitals + optional Lighthouse) \u2014 fire-and-forget\n if (opts.jobId && (rawPerf || process.env.ENABLE_LIGHTHOUSE)) {\n (async () => {\n try {\n const lhScores = await runLighthouse(url);\n await AppBrain.savePerformanceSnapshot(opts.tenantId, screen.id, opts.jobId!, {\n lcp: rawPerf?.lcp,\n fcp: rawPerf?.fcp,\n cls: rawPerf?.cls,\n ttfb: rawPerf?.ttfb,\n viewport: opts.viewport ?? 'DESKTOP',\n ...(lhScores ? {\n lighthousePerf: lhScores.perf,\n lighthouseA11y: lhScores.a11y,\n lighthouseSEO: lhScores.seo,\n lighthouseBP: lhScores.bp,\n lighthouseReport: lhScores.report,\n } : {}),\n });\n } catch (perfErr) {\n console.warn('[crawler] savePerformanceSnapshot failed (non-fatal):', perfErr);\n }\n })();\n }\n\n discovered.push({ url, screenId: screen.id, elements: elements.length, elementFacts: elements, screenshotPath: shotPath, version: screen.version });\n // Progress: 20% baseline + up to 60% across discovered screens.\n // Cap maxSeenTotal at maxScreens * 3 so unbounded link discovery does not\n // collapse the denominator and freeze progress in the 20-22% band.\n const effectiveMax = isFinite(maxScreens) ? Math.min(visited.size + queue.length, maxScreens * 3) : visited.size + queue.length;\n maxSeenTotal = Math.max(maxSeenTotal, effectiveMax);\n const rawPct = 20 + Math.round(Math.min(60, (visited.size / Math.max(1, maxSeenTotal)) * 60));\n const clampedPct = Math.max(lastEmittedPct, rawPct);\n lastEmittedPct = clampedPct;\n await onProgress?.(clampedPct, `Crawling screens (${visited.size} mapped, ${queue.length} pending)`);\n logger.info({ name, elements: elements.length }, 'Screen crawled');\n // Checkpoint every 10 successes so a failed job can be resumed from close to where it stopped\n if (++checkpointSuccessCount % 5 === 0) {\n await opts.onCheckpoint?.(\n Array.from(visited.entries()).filter(([_k, v]) => v !== '_pending_').map(([k]) => k),\n queue.filter(u => !visited.has(canonicalize(u)))\n );\n }\n } catch (err: any) {\n logger.warn({ url, err: err?.message ?? String(err), stack: err?.stack?.split('\\n').slice(0, 5).join(' | ') }, 'Screen crawl failed');\n discovered.push({ url, error: err?.message ?? String(err) });\n }\n }\n\n // Wait for any lite workers still processing URLs from the shared queue\n if (liteWorkerPromises.length > 0) await Promise.all(liteWorkerPromises);\n\n // Discovery mode: return collected URLs and skip all post-crawl analysis phases.\n // Use visited.values() (original URLs) not .keys() (canonical forms with /{id} placeholders).\n // Filter out sentinel strings (_pending_, _auth_wall_, _soft404_, etc.) that mark\n // in-progress or skipped entries \u2014 only keep actual http(s) URLs.\n if (opts.discoveryMode) {\n return {\n discoveredUrls: Array.from(visited.values()).filter((v: string) => v.startsWith('http')),\n screensFound: 0,\n screensErrored: 0,\n screensSkippedToNextSegment: 0,\n isPartial: false,\n discovered: [],\n apiEndpoints: [],\n performanceMetrics: [],\n pendingUrls: [],\n segmentIndex: segIdx,\n hasMoreSegments: false,\n domHashes: Array.from(seenDomHashes),\n };\n }\n\n // Gap 5: Skyvern post-crawl top-up for canvas/non-DOM apps where total screens < 10.\n // Skyvern discovers URLs \u2192 ZeTa's own BFS crawl processes each one normally.\n // Skyvern is ONLY a URL-discovery layer here \u2014 it does NOT save screens directly.\n // Use only successfully-saved screens (screenId present), not total discovered including errors.\n const successfulScreenCount = discovered.filter(d => d.screenId).length;\n const skyvernMinScreens = parseInt(process.env.CRAWL_SKYVERN_MIN_SCREENS ?? '') || 10;\n if (!selective && successfulScreenCount < skyvernMinScreens && opts.skyvernConfig) {\n await onProgress?.(78, 'Few screens found \u2014 using Skyvern to discover additional navigation URLs');\n const currentUrl = page.url();\n const skyvernNav = await skyvernNavigate(\n currentUrl,\n [\n 'Explore the main navigation and visit each top-level section',\n 'Click any sidebar or top menu items to discover sub-pages',\n ],\n opts.skyvernConfig,\n );\n const skyvernUrls = skyvernNav.visitedUrls.filter((u) => !visited.has(canonicalize(u)));\n if (skyvernUrls.length > 0) {\n logger.info({ count: skyvernUrls.length }, 'Gap 5: Skyvern found new URLs \u2014 processing with ZeTa native crawler');\n // Process each URL with ZeTa's own Playwright-based extraction\n for (const skyvernUrl of skyvernUrls) {\n if (isCrawlTimedOut() || visited.size >= maxScreens) break;\n try {\n await page.goto(skyvernUrl, { waitUntil: 'domcontentloaded', timeout: 20000 });\n await new Promise<void>(r => setTimeout(r, 1500));\n const skyvernName = new URL(skyvernUrl).pathname.split('/').filter(Boolean).pop() ?? 'Screen';\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, skyvernName, skyvernUrl, opts.jobId, 'SKYVERN_AI');\n const shotPath = `${opts.screenshotDir ?? '/tmp'}/${screen.id}-v${screen.version}.png`;\n await waitForScreenshotReady(page, rawPage ?? undefined);\n await page.screenshot({ path: shotPath, fullPage: true });\n const skyvernCloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, screen.id, shotPath, screen.version, 'DESKTOP', skyvernCloudUrl);\n // GAP 7: DOM snapshot for Skyvern primary URLs\n const skyvernDom = await capturePageHtml(page);\n if (skyvernDom) {\n const skyvernDomPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(skyvernDomPath, skyvernDom, 'utf8');\n const skyvernDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(skyvernDomPath)}`;\n const skyvernDomCloud = await uploadToCloud(skyvernDomPath, skyvernDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, skyvernDomPath, skyvernDomCloud).catch(() => {});\n }\n const [elems, links, linkMappings] = await Promise.all([\n extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined),\n discoverLinks(stagehand, origin, page, linkLLM ?? undefined, aiSkipCount > 0, rawPage ?? undefined).then((metas) => {\n if (metas.length > 0) {\n AppBrain.saveDiscoveredLinks(opts.tenantId, opts.projectId, screen.id, metas.map((m) => ({\n href: m.url, text: m.text, landmark: m.landmark, linkType: 'NAV_LINK', source: m.source, jobId: opts.jobId,\n }))).catch(() => {});\n }\n return metas.map(m => m.url);\n }),\n extractLinkMappings(page, origin),\n ]);\n for (const el of elems) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => { });\n }\n visited.set(canonicalize(skyvernUrl), screen.id);\n discovered.push({ url: skyvernUrl, screenId: screen.id, elements: elems.length, version: screen.version });\n // Wire KAG element->screen transitions for this Skyvern-discovered page too \u2014\n // without this, any page only ever reached via Skyvern always looks orphaned\n // (zero inbound edges) even when a real DOM link exists elsewhere pointing to it.\n for (const lm of linkMappings) {\n pendingTransitions.push({ fromScreenId: screen.id, elementMeaning: lm.label, targetUrl: lm.href });\n }\n // Also enqueue links Skyvern page found for further ZeTa crawling\n for (const link of links) {\n const href = link;\n const c = canonicalize(href);\n if (isUsefulNavigationUrl(href, origin) && !queued.has(c) && !visited.has(c)) { queued.add(c); queue.push(href); }\n }\n } catch (err) {\n logger.warn({ url: skyvernUrl, err: String(err) }, 'Gap 5: ZeTa crawl of Skyvern URL failed');\n }\n }\n // Drain any newly queued URLs from Skyvern pages\n while (queue.length > 0 && visited.size < maxScreens && !isCrawlTimedOut()) {\n const href = queue.shift()!;\n const canonHref = canonicalize(href);\n if (visited.has(canonHref)) continue;\n if (!isUsefulNavigationUrl(href, origin)) continue;\n try {\n await page.goto(href, { waitUntil: 'domcontentloaded', timeout: 20000 });\n await new Promise<void>(r => setTimeout(r, 1000));\n const nm = new URL(href).pathname.split('/').filter(Boolean).pop() ?? 'Screen';\n const sc = await AppBrain.saveScreen(opts.tenantId, opts.projectId, nm, href, opts.jobId, 'SKYVERN_AI');\n const sp = `${opts.screenshotDir ?? '/tmp'}/${sc.id}-v${sc.version}.png`;\n await waitForScreenshotReady(page, rawPage ?? undefined);\n await page.screenshot({ path: sp, fullPage: true });\n const skyvernDrainCloudUrl = await uploadToCloud(sp, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(sp)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, sc.id, sp, sc.version, 'DESKTOP', skyvernDrainCloudUrl);\n // GAP 8: DOM snapshot for Skyvern drain-queue URLs\n const skyvernDrainDom = await capturePageHtml(page);\n if (skyvernDrainDom) {\n const skyvernDrainDomPath = sp.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(skyvernDrainDomPath, skyvernDrainDom, 'utf8');\n const skyvernDrainDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(skyvernDrainDomPath)}`;\n const skyvernDrainDomCloud = await uploadToCloud(skyvernDrainDomPath, skyvernDrainDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, sc.id, skyvernDrainDomPath, skyvernDrainDomCloud).catch(() => {});\n }\n const [elems2, linkMappings2] = await Promise.all([\n extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined),\n extractLinkMappings(page, origin),\n ]);\n for (const el of elems2) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, sc.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => { });\n }\n visited.set(canonHref, sc.id);\n discovered.push({ url: href, screenId: sc.id, elements: elems2.length, version: sc.version });\n for (const lm of linkMappings2) {\n pendingTransitions.push({ fromScreenId: sc.id, elementMeaning: lm.label, targetUrl: lm.href });\n }\n } catch { /* non-fatal */ }\n }\n }\n }\n\n if (pendingSessionRestore) {\n await pendingSessionRestore();\n pendingSessionRestore = null;\n }\n\n // P1: URL Pattern LLM Completion \u2014 post-crawl LLM prediction of undiscovered URLs.\n // Single LLM call predicts missing routes from discovered URL patterns, HEAD-validates each.\n // Saves URL_CANDIDATES evidence so the ActivityDrawer shows what was found.\n try {\n const { runUrlPatternCompletion } = await import('./url-pattern-completer.js');\n const llmCfgForPatterns = await getCachedCrawlLLM(opts.tenantId);\n const urlPatternCandidates = await runUrlPatternCompletion(\n Array.from(visited.keys()),\n opts.appUrl,\n llmCfgForPatterns,\n );\n if (urlPatternCandidates.length > 0) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'URL_CANDIDATES',\n payload: {\n candidates: urlPatternCandidates,\n hits: urlPatternCandidates.filter(c => c.status === 'hit').length,\n total: urlPatternCandidates.length,\n },\n }).catch(() => { });\n logger.info(\n { hits: urlPatternCandidates.filter(c => c.status === 'hit').length, total: urlPatternCandidates.length },\n '[P1] URL pattern completion saved to evidence',\n );\n }\n } catch (err) {\n const msg = String(err);\n logger.warn({ err: msg }, '[P1] URL pattern completion failed \u2014 non-fatal, continuing');\n crawlWarnings.push(`url-completer skipped: ${msg.includes('401') || msg.toLowerCase().includes('api key') || msg.toLowerCase().includes('authentication') ? 'LLM API key invalid or missing' : msg}`);\n }\n\n // P3a: Async content re-visit \u2014 revisit pages where DOM grew significantly during extraction.\n // Uses networkidle wait + longer stability period to capture fully-loaded dashboard content.\n if (revisitQueue.length > 0) {\n await onProgress?.(79, `Re-visiting ${revisitQueue.length} page(s) with async content\u2026`);\n logger.info({ count: revisitQueue.length }, '[P3a] Starting async content re-visit pass');\n for (const revisitUrl of revisitQueue.slice(0, 20)) { // cap at 20 re-visits; also guard global timeout\n if (isCrawlTimedOut()) break;\n const rawScreenId = visited.get(canonicalize(revisitUrl));\n // Auth-wall pages are stored as '_auth_wall_' \u2014 not a real screen ID.\n // Navigate with the authenticated main page; it will redirect to the real content.\n const isAuthWallRevisit = rawScreenId === '_auth_wall_';\n if (!rawScreenId) continue;\n try {\n await page.goto(revisitUrl, { waitUntil: 'networkidle', timeout: 25_000 });\n await new Promise<void>(r => setTimeout(r, 2_000));\n await waitForScreenshotReady(page, rawPage ?? undefined);\n\n // After navigation, check where we actually landed (auth may redirect)\n const landedUrl = (rawPage ?? page).url?.() ?? revisitUrl;\n const landedCanon = canonicalize(landedUrl);\n let existingScreenId = isAuthWallRevisit\n ? (visited.get(landedCanon) ?? null) // use screen at redirected URL if known\n : rawScreenId;\n\n // If auth-wall redirect landed on an unvisited page, save it as a new screen\n if (isAuthWallRevisit && (!existingScreenId || existingScreenId.startsWith('_')) && !visited.has(landedCanon)) {\n const pathParts = new URL(landedUrl).pathname.split('/').filter(Boolean);\n const screenName = pathParts.map((p: string) => p.charAt(0).toUpperCase() + p.slice(1).replace(/[-_]/g, ' ')).join(' \u2014 ') || 'Home';\n const newScreen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, screenName, landedUrl, opts.jobId, 'LINK_FOLLOW').catch(() => null);\n if (newScreen) {\n visited.set(landedCanon, newScreen.id);\n existingScreenId = newScreen.id;\n }\n }\n\n if (!existingScreenId || existingScreenId.startsWith('_')) {\n logger.warn({ url: revisitUrl, landed: landedUrl }, '[P3a] Re-visit skipped \u2014 could not resolve screen ID');\n continue;\n }\n\n const shotPath2 = `${opts.screenshotDir ?? '/tmp'}/${existingScreenId}-revisit.png`;\n await page.screenshot({ path: shotPath2, fullPage: true });\n const p3aCloudUrl = await uploadToCloud(shotPath2, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath2)}`).catch(() => undefined);\n await (AppBrain.saveScreenshot as any)(opts.tenantId, opts.projectId, existingScreenId, shotPath2, 1, 'DESKTOP', p3aCloudUrl).catch(() => {});\n // GAP 10: DOM snapshot for P3a auth-wall revisit\n const p3aDom = await capturePageHtml(page);\n if (p3aDom) {\n const p3aDomPath = shotPath2.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(p3aDomPath, p3aDom, 'utf8');\n const p3aDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(p3aDomPath)}`;\n const p3aDomCloud = await uploadToCloud(p3aDomPath, p3aDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, existingScreenId, p3aDomPath, p3aDomCloud).catch(() => {});\n }\n // Re-extract elements with the async-loaded content now visible\n const revisitElements = await extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined).catch(() => []);\n if (revisitElements.length > 0) {\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, existingScreenId).catch(() => {});\n for (const el of revisitElements) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, existingScreenId, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => { });\n }\n } else {\n // P3a got 0 elements \u2014 check if it's an inline session-expired page.\n const p3aBodyText = await page.evaluate(() => (document as any).body?.innerText ?? '').catch(() => '');\n if (INLINE_AUTH_WALL_RE.test(p3aBodyText)) {\n logger.warn({ url: revisitUrl, screenId: existingScreenId }, '[P3a] Re-visit got 0 elements \u2014 inline session-expired content, marking requiresAuth');\n AppBrain.updateScreenRequiresAuth(opts.tenantId, existingScreenId, true).catch(() => {});\n }\n }\n // Harvest any new links revealed by async content\n const revisitLinks = await discoverLinks(stagehand, origin, page, linkLLM ?? undefined, false, rawPage ?? undefined)\n .then((metas) => {\n if (metas.length > 0) {\n AppBrain.saveDiscoveredLinks(opts.tenantId, opts.projectId, existingScreenId, metas.map((m) => ({\n href: m.url, text: m.text, landmark: m.landmark, linkType: 'NAV_LINK', source: m.source, jobId: opts.jobId,\n }))).catch(() => {});\n }\n return metas.map(m => m.url);\n })\n .catch(() => []);\n for (const href of revisitLinks) {\n const canon = canonicalize(href);\n if (isUsefulNavigationUrl(href, origin) && !queued.has(canon) && !visited.has(canon) && queued.size < maxScreens * 3) {\n queued.add(canon);\n queue.push(href);\n }\n }\n logger.info({ url: revisitUrl, landed: landedUrl, elements: revisitElements.length, newLinks: revisitLinks.length }, '[P3a] Re-visit complete');\n } catch (err) {\n logger.warn({ url: revisitUrl, err: String(err) }, '[P3a] Re-visit failed \u2014 non-fatal');\n }\n }\n }\n\n // P3b: Extended BFS \u2014 process any links discovered during P3a revisit pass.\n // Without this, auth-wall pages redirect to real app pages, AI discovers new links,\n // but those links are pushed to queue and NEVER processed (main BFS already exited).\n if (queue.length > 0 && visited.size < maxScreens) {\n const p3bCount = Math.min(queue.length, maxScreens - visited.size);\n logger.info({ newLinks: p3bCount }, '[P3b] Extended BFS \u2014 processing links discovered during revisit pass');\n await onProgress?.(82, `Extended crawl: ${p3bCount} newly discovered page(s)\u2026`);\n while (queue.length > 0 && visited.size < maxScreens && visited.size < segmentSize) {\n if (isCrawlTimedOut()) break;\n const href = queue.shift();\n if (!href) break;\n const canonHref = canonicalize(href);\n if (visited.has(canonHref)) continue;\n if (!isUsefulNavigationUrl(href, origin)) continue;\n visited.set(canonHref, '_pending_');\n try {\n await page.goto(href, { waitUntil: 'networkidle', timeout: 25_000 }).catch(() => {});\n await waitForScreenshotReady(page, rawPage ?? undefined);\n const pathParts = new URL(href).pathname.split('/').filter(Boolean);\n const nm = pathParts.map((p: string) => p.charAt(0).toUpperCase() + p.slice(1).replace(/[-_]/g, ' ')).join(' \u2014 ') || 'Home';\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, nm, href, opts.jobId, 'LINK_FOLLOW');\n visited.set(canonHref, screen.id);\n const sp = `${opts.screenshotDir ?? '/tmp'}/${screen.id}-v${screen.version}.png`;\n await page.screenshot({ path: sp, fullPage: true }).catch(() => {});\n const cloudUrl3 = await uploadToCloud(sp, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(sp)}`).catch(() => '');\n await (AppBrain.saveScreenshot as any)(opts.tenantId, opts.projectId, screen.id, sp, screen.version, 'DESKTOP', cloudUrl3).catch(() => {});\n // GAP 6: DOM snapshot for P3b extended BFS\n const p3bDom = await capturePageHtml(page);\n if (p3bDom) {\n const p3bDomPath = sp.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(p3bDomPath, p3bDom, 'utf8');\n const p3bDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(p3bDomPath)}`;\n const p3bDomCloud = await uploadToCloud(p3bDomPath, p3bDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, p3bDomPath, p3bDomCloud).catch(() => {});\n }\n const [p3bElems, p3bLinks] = await Promise.all([\n extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined).catch(() => []),\n discoverLinks(stagehand, origin, page, linkLLM ?? undefined, aiSkipCount > 0, rawPage ?? undefined)\n .then((metas) => {\n if (metas.length > 0) {\n AppBrain.saveDiscoveredLinks(opts.tenantId, opts.projectId, screen.id, metas.map((m) => ({\n href: m.url, text: m.text, landmark: m.landmark, linkType: 'NAV_LINK', source: m.source, jobId: opts.jobId,\n }))).catch(() => {});\n }\n return metas.map(m => m.url);\n })\n .catch(() => []),\n ]);\n if (p3bElems.length > 0) {\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, screen.id).catch(() => {});\n for (let _ei3 = 0; _ei3 < p3bElems.length; _ei3 += 2) {\n const _b3 = p3bElems.slice(_ei3, _ei3 + 2);\n await Promise.all(_b3.map((el: any) =>\n AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => {})\n ));\n }\n }\n for (const link of p3bLinks) {\n const c = canonicalize(link);\n if (isUsefulNavigationUrl(link, origin) && !queued.has(c) && !visited.has(c) && queued.size < maxScreens * 3) {\n queued.add(c); queue.push(link);\n }\n }\n discovered.push({ url: href, screenId: screen.id, elements: p3bElems.length, version: screen.version });\n logger.info({ url: href, elements: p3bElems.length, newLinks: p3bLinks.length }, '[P3b] Extended BFS screen captured');\n } catch (err) {\n logger.warn({ url: href, err: String(err) }, '[P3b] Extended BFS URL failed');\n visited.set(canonHref, '_error_');\n }\n }\n }\n\n // P6: Gap Pass \u2014 LLM gap analysis on discovered screens to find structurally missing pages.\n // Runs after P3a re-visits so the gap analysis has the most complete screen list possible.\n // Confirmed gap URLs (HEAD=200) are visited directly with the existing browser.\n if (visited.size >= (parseInt(process.env.CRAWLER_GAP_PASS_MIN_SCREENS ?? '') || 3)) {\n try {\n await onProgress?.(80, 'Running gap analysis\u2026');\n const llmCfgForGap = await getCachedCrawlLLM(opts.tenantId);\n const discoveredForGap = Array.from(visited.entries()).map(([url, screenId]) => {\n const d = discovered.find(dd => dd.screenId === screenId);\n return { url, name: d ? (new URL(url).pathname.split('/').filter(Boolean).pop() ?? 'screen') : undefined, elements: d?.elements };\n });\n const gapCandidates = await runGapAnalysis(discoveredForGap, opts.appUrl, llmCfgForGap);\n const confirmedGaps = gapCandidates.filter(g => g.confirmedUrl && !visited.has(canonicalize(g.confirmedUrl!)));\n\n if (confirmedGaps.length > 0) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'URL_CANDIDATES',\n payload: {\n source: 'gap-pass',\n candidates: gapCandidates.map(g => ({ url: g.confirmedUrl ?? g.urlPatterns[0], confidence: g.confidence, reason: g.rationale, status: g.confirmedUrl ? 'hit' : 'miss' })),\n hits: confirmedGaps.length,\n total: gapCandidates.length,\n },\n }).catch(() => { });\n logger.info({ confirmed: confirmedGaps.length, total: gapCandidates.length }, '[P6] Gap pass: visiting confirmed gap URLs');\n\n // Visit each confirmed gap URL with the existing browser (depth=1, no link traversal)\n const gapLoginPattern = /\\/(login|signin|sign-in|auth|log-in)(\\/|$|\\?)/i;\n for (const gap of confirmedGaps.slice(0, parseInt(process.env.CRAWLER_GAP_PASS_MAX_VISITS ?? '') || 25)) {\n if (isCrawlTimedOut() || visited.size >= maxScreens) break;\n const gapUrl = gap.confirmedUrl!;\n try {\n await page.goto(gapUrl, { waitUntil: 'domcontentloaded', timeout: 20_000 });\n // Skip if session expired \u2014 don't save a login-page screenshot as the gap result\n if (gapLoginPattern.test(page.url())) {\n logger.warn({ gapUrl, landed: page.url() }, '[P6] Gap URL redirected to login \u2014 skipping');\n continue;\n }\n await new Promise<void>(r => setTimeout(r, 1_500));\n const gapName = gap.category;\n const gapScreen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, gapName, gapUrl, opts.jobId, 'ENTRY_POINT');\n const gapShot = `${opts.screenshotDir ?? '/tmp'}/${gapScreen.id}-v${gapScreen.version}.png`;\n await waitForScreenshotReady(page, rawPage ?? undefined);\n await page.screenshot({ path: gapShot, fullPage: true });\n const gapCloudUrl = await uploadToCloud(gapShot, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(gapShot)}`).catch(() => undefined);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, gapScreen.id, gapShot, gapScreen.version, 'DESKTOP', gapCloudUrl);\n // GAP 9: DOM snapshot for P6 gap-pass\n const gapDom = await capturePageHtml(page);\n if (gapDom) {\n const gapDomPath = gapShot.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(gapDomPath, gapDom, 'utf8');\n const gapDomKey = `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(gapDomPath)}`;\n const gapDomCloud = await uploadToCloud(gapDomPath, gapDomKey).catch(() => undefined);\n AppBrain.updateScreenDomSnapshot(opts.tenantId, gapScreen.id, gapDomPath, gapDomCloud).catch(() => {});\n }\n const [gapElems, gapLinks, gapLinkMaps] = await Promise.all([\n extractElements(stagehand, page, elementLLM ?? undefined, rawPage ?? undefined).catch(() => []),\n discoverLinks(stagehand, origin, page, linkLLM ?? undefined, false, rawPage ?? undefined)\n .then((metas) => {\n if (metas.length > 0) {\n AppBrain.saveDiscoveredLinks(opts.tenantId, opts.projectId, gapScreen.id, metas.map((m) => ({\n href: m.url, text: m.text, landmark: m.landmark, linkType: 'NAV_LINK', source: m.source, jobId: opts.jobId,\n }))).catch(() => {});\n }\n return metas.map(m => m.url);\n })\n .catch(() => []),\n extractLinkMappings(page, origin).catch(() => []),\n ]);\n for (const el of gapElems) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, gapScreen.id, el.meaning, el.role, el.expectedData, el.notes, undefined, true, el.boundingRect, el.ariaState, el.parentLandmark).catch(() => { });\n }\n if (gapElems.length === 0) {\n const gapBodyText = await page.evaluate(() => (document as any).body?.innerText ?? '').catch(() => '');\n if (INLINE_AUTH_WALL_RE.test(gapBodyText)) {\n logger.warn({ url: gapUrl, screenId: gapScreen.id }, '[P6] Gap URL got 0 elements \u2014 inline session-expired content, marking requiresAuth');\n AppBrain.updateScreenRequiresAuth(opts.tenantId, gapScreen.id, true).catch(() => {});\n }\n }\n visited.set(canonicalize(gapUrl), gapScreen.id);\n discovered.push({ url: gapUrl, screenId: gapScreen.id, elements: gapElems.length, version: gapScreen.version });\n for (const lm of gapLinkMaps) {\n pendingTransitions.push({ fromScreenId: gapScreen.id, elementMeaning: lm.label, targetUrl: lm.href });\n }\n // Enqueue gap page's links for further crawl (within maxScreens budget)\n for (const href of gapLinks) {\n const canon = canonicalize(href);\n if (isUsefulNavigationUrl(href, origin) && !queued.has(canon) && !visited.has(canon) && queued.size < maxScreens * 3) {\n queued.add(canon); queue.push(href);\n }\n }\n logger.info({ url: gapUrl, elements: gapElems.length, category: gap.category }, '[P6] Gap URL captured');\n } catch (err) {\n logger.warn({ url: gapUrl, err: String(err) }, '[P6] Gap URL visit failed \u2014 non-fatal');\n }\n }\n } else {\n logger.info({ total: gapCandidates.length }, '[P6] Gap pass: no confirmed gaps found');\n }\n } catch (err) {\n const msg = String(err);\n logger.warn({ err: msg }, '[P6] Gap pass failed \u2014 non-fatal, continuing');\n crawlWarnings.push(`gap-analysis skipped: ${msg.includes('401') || msg.toLowerCase().includes('api key') || msg.toLowerCase().includes('authentication') ? 'LLM API key invalid or missing' : msg}`);\n }\n }\n\n // After crawl: mark screens not re-discovered as PENDING_REMOVAL (non-destructive diff)\n // Only run if crawl actually found screens \u2014 0 discovered means failed/aborted run, not evidence of removal\n if (!selective && visited.size > 0) {\n // Only pass canonical URLs of screens that were actually visited (saveScreen called).\n // Exclude marker strings (_skipped_api_, _pending_, _soft404_, pre-auth, skipped)\n // so that skipped API/export paths don't pollute the discoveredSet and prevent removal\n // of old API-path screens from previous crawls.\n const VISIT_MARKER_RE = /^_|^pre-auth$|^skipped$/;\n const discoveredUrls = Array.from(visited.entries())\n .filter(([, v]) => typeof v === 'string' && !VISIT_MARKER_RE.test(v))\n .map(([k]) => k);\n await AppBrain.markRemovedScreens(opts.tenantId, opts.projectId, discoveredUrls, opts.jobId);\n }\n\n // Step 3: Save flows\n await onProgress?.(82, 'Saving app map');\n for (const edge of edges) {\n const fromId = visited.get(canonicalize(edge.fromUrl));\n const toId = visited.get(canonicalize(edge.toUrl));\n if (fromId && toId && fromId !== toId) {\n await AppBrain.saveFlow(opts.tenantId, opts.projectId, `${edge.fromUrl} -> ${edge.toUrl}`, fromId, toId);\n }\n }\n\n // Step 4: Wire KAG element-level transitions\n // For each <a href> link captured from each screen, resolve the href to a visited screenId\n // and store transitionsToScreenId on the matching element.\n await onProgress?.(84, 'Wiring navigation graph (KAG)');\n // Secondary index: pathname \u2192 [canonicalUrl, ...] for subset-param fuzzy matching.\n // A link to /product?id=5 should resolve to a page visited at /product?id=5&session=abc\n // even though their canonical forms differ (session param not in the strip list).\n const visitedByPath = new Map<string, string[]>();\n for (const [canonUrl] of visited) {\n try {\n const p = new URL(canonUrl).pathname;\n const arr = visitedByPath.get(p);\n if (arr) arr.push(canonUrl); else visitedByPath.set(p, [canonUrl]);\n } catch { /* invalid canonical \u2014 skip */ }\n }\n for (const pt of pendingTransitions) {\n let toScreenId = visited.get(canonicalize(pt.targetUrl));\n if (!toScreenId) {\n // Fuzzy fallback: find a visited URL at the same pathname whose params are a superset\n // of the link's params (handles extra session/tracking params on the visited side).\n try {\n const targetCanon = new URL(canonicalize(pt.targetUrl));\n const candidates = visitedByPath.get(targetCanon.pathname) ?? [];\n for (const cand of candidates) {\n const candUrl = new URL(cand);\n let allMatch = true;\n for (const [k, v] of targetCanon.searchParams) {\n if (candUrl.searchParams.get(k) !== v) { allMatch = false; break; }\n }\n if (allMatch) { toScreenId = visited.get(cand); break; }\n }\n } catch { /* non-fatal */ }\n }\n if (toScreenId && toScreenId !== pt.fromScreenId) {\n await AppBrain.setElementTransition(opts.tenantId, pt.fromScreenId, pt.elementMeaning, toScreenId).catch(() => { });\n await AppBrain.saveScreenTransition(opts.tenantId, opts.projectId, {\n fromScreenId: pt.fromScreenId,\n toScreenId,\n action: {\n type: 'click',\n label: pt.elementMeaning,\n targetUrl: pt.targetUrl,\n source: 'crawl-link-mapping',\n },\n confidence: 0.8,\n jobId: opts.jobId,\n }).catch(() => { });\n }\n }\n const transitionCount = pendingTransitions.filter(pt => {\n if (visited.get(canonicalize(pt.targetUrl))) return true;\n try {\n const tc = new URL(canonicalize(pt.targetUrl));\n return (visitedByPath.get(tc.pathname) ?? []).some(cand => {\n const cu = new URL(cand);\n for (const [k, v] of tc.searchParams) { if (cu.searchParams.get(k) !== v) return false; }\n return true;\n });\n } catch { return false; }\n }).length;\n logger.info({ transitionCount }, 'KAG: wired element\u2192screen transitions');\n\n // Navigation graph: resolve DiscoveredLink.toScreenId by matching href \u2192 visited screen IDs.\n // Build a raw-href \u2192 screenId map using both canonical and pathname-based lookups.\n if (opts.jobId) {\n const hrefToScreenId = new Map<string, string>();\n for (const [canonUrl, screenId] of visited) {\n if (screenId && screenId !== '_pending_' && screenId !== '_error_') {\n hrefToScreenId.set(canonUrl, screenId);\n try {\n const u = new URL(canonUrl);\n hrefToScreenId.set(u.href, screenId);\n // Also index by origin+pathname so links with extra query params still resolve\n hrefToScreenId.set(u.origin + u.pathname, screenId);\n hrefToScreenId.set(u.origin + u.pathname.replace(/\\/$/, ''), screenId);\n } catch { /* skip */ }\n }\n }\n AppBrain.resolveDiscoveredLinkTargets(opts.tenantId, opts.projectId, opts.jobId, hrefToScreenId).catch(() => {});\n }\n\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'WORKFLOW_GRAPH_SUMMARY',\n payload: {\n transitionCount,\n screenCount: visited.size,\n profile: domainProfile.industry,\n },\n }).catch(() => { });\n\n if (capturedApiEndpoints.length > 0) {\n logger.info({ count: capturedApiEndpoints.length }, 'Captured unique API endpoint patterns');\n }\n\n if (visited.size >= 5) {\n await onProgress?.(90, `App map saved \u00B7 ${visited.size} screens, ${edges.length} flows wired`);\n }\n\n // P5: Export session cookies BEFORE session health check so we can reuse them even if\n // the main browser session is stale. The cookie jar stays valid for fresh browser contexts\n // even when the CDP-connected Stagehand page shows a redirect to /login.\n let mainStorageState: any;\n try {\n mainStorageState = await playwrightBrowser!.contexts()[0]?.storageState();\n } catch { /* non-fatal */ }\n\n // P5: Orphan page auth re-verify \u2014 confirm session is still alive before tail-end viewport pass.\n // The main BFS can span many minutes; the session may have expired by the time we reach here.\n // If expired, attempt re-auth via Stagehand before proceeding.\n // Creative resilience: even if the main browser is dead, we still run the viewport pass using\n // the exported cookie jar \u2014 fresh browsers are often accepted by servers even after CDP session loss.\n let sessionAliveForViewports = true;\n try {\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 15_000 });\n const sessionCheckUrl = page.url();\n const loginKeywords = /login|signin|sign-in|\\/auth[/?#]/i;\n if (loginKeywords.test(sessionCheckUrl)) {\n logger.warn({ landed: sessionCheckUrl }, '[P5] Session expired before viewport pass \u2014 attempting re-auth');\n let reauthed = false;\n if (opts.credentials) {\n reauthed = await loginWithStagehand(\n stagehand, opts.credentials, opts.appUrl,\n { apiKey: opts.captchaSolverApiKey, provider: opts.captchaSolverProvider },\n { apiKey: opts.mailslurpApiKey, inboxId: opts.mailslurpInboxId },\n undefined,\n { tenantId: opts.tenantId, projectId: opts.projectId, jobId: opts.jobId },\n ).catch(() => false);\n }\n if (reauthed) {\n // Refresh cookie jar with newly authenticated session\n try { mainStorageState = await playwrightBrowser!.contexts()[0]?.storageState(); } catch { /* keep prior */ }\n logger.info('[P5] Re-auth succeeded \u2014 proceeding with viewport pass');\n } else {\n sessionAliveForViewports = false;\n const hasCookies = (mainStorageState?.cookies?.length ?? 0) > 0;\n logger.warn({ landed: sessionCheckUrl, hasCookies }, '[P5] Re-auth failed \u2014 will attempt viewport pass with exported cookies');\n if (!hasCookies) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'AUTH_FAILURE',\n payload: {\n url: opts.appUrl,\n landed: sessionCheckUrl,\n reason: 'Session expired before mobile/tablet viewport pass and re-auth failed. Re-capture the session in project settings.',\n },\n }).catch(() => { });\n }\n }\n } else {\n logger.info({ url: sessionCheckUrl }, '[P5] Session alive \u2014 proceeding with viewport pass');\n }\n } catch (err) {\n logger.warn({ err: String(err) }, '[P5] Session health check navigation failed \u2014 proceeding with viewport pass anyway');\n }\n\n // Step 5: Multi-viewport pass \u2014 screenshot + DOM element extraction at each device profile.\n // Only DESKTOP (the main crawl above) runs Stagehand AI navigation and link discovery.\n // Mobile/tablet viewports navigate to already-discovered screens and re-extract elements\n // with their viewport-specific bounding rects.\n //\n // IMPORTANT: We launch a fresh Playwright browser per viewport profile instead of calling\n // playwrightBrowser.newContext() on the CDP-connected instance. CDP-connected browsers\n // share the DevTools session with Stagehand and cannot reliably set device emulation\n // (isMobile, hasTouch, viewport, deviceScaleFactor) on new contexts \u2014 the flags are\n // silently ignored, so screenshots come out at desktop dimensions regardless of profile.\n const extraProfiles = (opts.deviceProfiles ?? []).filter((p) => p !== 'DESKTOP');\n // Run the viewport pass even when the main session is dead, as long as we exported cookies \u2014\n // fresh browsers often authenticate successfully with the saved cookie jar.\n const hasExportedAuth = (mainStorageState?.cookies?.length ?? 0) > 0;\n if ((sessionAliveForViewports || hasExportedAuth) && extraProfiles.length > 0 && discovered.length > 0) {\n const { devices, chromium: pwChromium } = await import('playwright');\n const DEVICE_MAP: Record<string, any> = {\n // Override viewport heights: Playwright's device descriptors use viewport-minus-browser-chrome\n // (659 for iPhone 15, ~980 for iPad Pro 11). Override to full logical screen dimensions so\n // screenshots match what users see on device and mobile-detection scripts pass.\n MOBILE_PORTRAIT: { ...devices['iPhone 15'], viewport: { width: 393, height: 852 } },\n TABLET: { ...devices['iPad Pro 11'], viewport: { width: 834, height: 1194 } },\n };\n\n for (const profile of extraProfiles) {\n const deviceConfig = DEVICE_MAP[profile];\n if (!deviceConfig) continue;\n await onProgress?.(95, `Capturing ${profile} screenshots + elements\u2026`);\n\n // Launch a dedicated browser for this viewport \u2014 no CDP sharing\n let mobileBrowser: import('playwright').Browser | null = null;\n try {\n mobileBrowser = await pwChromium.launch({\n headless: true,\n executablePath,\n args: chromeArgs,\n });\n const mobileCtx = await mobileBrowser.newContext({\n ...deviceConfig,\n ignoreHTTPSErrors: true,\n ...(mainStorageState ? { storageState: mainStorageState } : {}),\n });\n mobileCtx.on('download', (dl: any) => { dl.cancel().catch(() => {}); });\n const mobilePage = await mobileCtx.newPage();\n\n for (const disc of discovered) {\n if (isCrawlTimedOut()) break;\n if (!disc.screenId) continue;\n try {\n await mobilePage.goto(disc.url, { waitUntil: 'domcontentloaded', timeout: 20_000 });\n await mobilePage.waitForLoadState('networkidle', { timeout: 8_000 }).catch(() => { });\n await dismissOverlays(mobilePage);\n try { await mobilePage.addStyleTag({ content: '*, *::before, *::after { animation-duration: 0s !important; transition-duration: 0s !important; }' }); } catch { /* ignore */ }\n // mobilePage is a real Playwright page \u2014 pass it as rawPage so CDP wheel events\n // trigger virtual scrollers (react-window / TanStack Virtual) at mobile viewports.\n await infiniteScrollToBottom(mobilePage, { maxScrolls: 20, scrollDelay: 300, stabilizeMs: 400 }, mobilePage).catch(() => { });\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `${disc.screenId}-${profile.toLowerCase()}-v${disc.version}.png`);\n await waitForScreenshotReady(mobilePage, mobilePage);\n // Screenshot and DOM element extraction run in parallel\n const [, vpElements] = await Promise.all([\n mobilePage.screenshot({ path: shotPath, fullPage: true }),\n domFallbackElements(mobilePage, mobilePage),\n ]);\n const cloudUrl = await uploadToCloud(shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`);\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, disc.screenId, shotPath, disc.version!, profile, cloudUrl);\n AppBrain.autoCreateVisualBaseline(opts.tenantId, opts.projectId, disc.screenId, profile, shotPath, gitInfo.branch, gitInfo.commit || undefined).catch(() => { });\n // Save viewport-specific element records (bounding rects differ per viewport)\n for (const el of vpElements) {\n AppBrain.saveElement(\n opts.tenantId, opts.projectId, disc.screenId,\n el.meaning, el.role, el.expectedData, el.notes,\n undefined, true, el.boundingRect, el.ariaState, el.parentLandmark,\n profile,\n ).catch(() => { });\n }\n } catch (err) {\n logger.warn({ profile, url: disc.url, err: String(err) }, `[P5] ${profile} screenshot failed \u2014 skipping screen`);\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n screenId: disc.screenId,\n type: 'VIEWPORT_SCREENSHOT_FAILURE',\n payload: { profile, url: disc.url, reason: String(err) },\n }).catch(() => { });\n }\n }\n await mobilePage.close().catch(() => { });\n await mobileCtx.close().catch(() => { });\n } catch (profileErr) {\n logger.warn({ profile, err: String(profileErr) }, `[P5] ${profile} browser launch failed`);\n } finally {\n await mobileBrowser?.close().catch(() => { });\n }\n }\n }\n\n // Step 6: Interactive probe \u2014 always-on (C-06) to capture real validation errors, toasts, and modals.\n // Previously gated on opts.interactive or sparse crawls; now unconditional for accurate expected-result generation.\n const shouldRunInteractiveProbe = true;\n if (shouldRunInteractiveProbe) {\n await onProgress?.(88, 'Running interactive probe (capturing real errors & modals)');\n const probeInputs = discovered\n .filter((d) => d.screenId)\n .map((d) => ({ url: d.url, screenId: d.screenId!, elements: d.elementFacts ?? [] }));\n await probeAllScreens(page, opts.tenantId, opts.projectId, probeInputs, onProgress, opts.jobId);\n }\n\n // Step 7: End-of-crawl state graph coverage report.\n // Per-screen probes (dropdown, CRUD, filter, DnD, nested-contexts, shadow-DOM,\n // accessibility-tree, performance, service-worker) run per-screen inside the BFS\n // loop above and are saved as PER_SCREEN_PROBES evidence.\n try {\n await onProgress?.(90, 'Generating state graph coverage report');\n // Populate stateGraph from discovered screens + BFS edges (previously always empty).\n const stateGraph = new ScreenTransitionGraph();\n const now = new Date().toISOString();\n for (const d of discovered) {\n if (!d.screenId || !d.url) continue;\n const hashVal = simHash32(d.url);\n stateGraph.addState({\n id: d.screenId,\n url: d.url,\n normalizedUrl: d.url,\n title: d.url,\n interactiveElementCount: d.elements ?? 0,\n domFingerprint: hashVal.toString(16).padStart(8, '0'),\n simHashValue: hashVal,\n visitedAt: now,\n });\n }\n // Wire transitions from BFS edges\n for (const edge of edges) {\n const fromId = visited.get(canonicalize(edge.fromUrl));\n const toId = visited.get(canonicalize(edge.toUrl));\n if (fromId && toId && fromId !== '_pending_' && fromId !== '_error_' &&\n toId !== '_pending_' && toId !== '_error_') {\n stateGraph.addTransition(fromId, toId, 'navigate', edge.toUrl, now);\n }\n }\n const coveragePayload: Record<string, unknown> = {\n stateGraph: stateGraph.getCoverageReport(),\n totalScreensCrawled: discovered.filter(d => !!d.screenId).length,\n };\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'CRAWL_COVERAGE_REPORT',\n payload: coveragePayload,\n }).catch(() => { });\n } catch (extErr) {\n logger.warn({ err: String(extErr) }, '[coverage-report] non-fatal error');\n }\n\n await onProgress?.(97, 'Running post-crawl analysis');\n\n // \u2500\u2500 Per-crawl summaries (fire-and-forget, non-blocking) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const successScreens = discovered.filter(d => !!d.screenId);\n ; (async () => {\n try {\n // 1. Sitemap XML\n if (successScreens.length > 0) {\n const sitemapUrls = screensToSitemapUrls(successScreens.map(d => ({ url: d.url })));\n const sitemapPath = path.join(opts.screenshotDir ?? '/tmp', 'sitemap.xml');\n await writeSitemap(sitemapUrls, sitemapPath);\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'SITEMAP_WRITTEN', payload: { path: sitemapPath, urlCount: sitemapUrls.length },\n }).catch(() => { });\n }\n\n // 2. OpenAPI spec from captured API endpoints\n if (capturedApiEndpoints.length > 0) {\n const spec = generateOpenApiSpec(capturedApiEndpoints, { title: `${opts.projectId} API`, version: '1.0.0' });\n const yamlStr = specToYaml(spec);\n const specPath = path.join(opts.screenshotDir ?? '/tmp', 'openapi.yaml');\n await fs.writeFile(specPath, yamlStr, 'utf8');\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'OPENAPI_SPEC', payload: { path: specPath, endpointCount: capturedApiEndpoints.length },\n }).catch(() => { });\n }\n\n // 3. Dead link summary\n const deadStats = deadLinkTracker.stats();\n if (deadStats.total > 0) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'DEAD_LINKS', payload: { ...deadStats, links: deadLinkTracker.getDeadLinks() },\n }).catch(() => { });\n }\n\n // 4. Redirect chain summary\n const redirectStats = redirectRegistry.stats();\n if (redirectStats.withRedirects > 0) {\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'REDIRECT_CHAINS', payload: { ...redirectStats, problematic: redirectRegistry.getProblematic() },\n }).catch(() => { });\n }\n\n // 5. Playwright test generation (first 5 screens as sample)\n if (successScreens.length > 0) {\n const sampleScreens = successScreens.slice(0, 5).map(d => ({\n id: d.screenId!, url: d.url, name: d.url,\n }));\n const playwrightScript = generatePlaywrightTest(sampleScreens);\n const testPath = path.join(opts.screenshotDir ?? '/tmp', 'generated.spec.ts');\n await fs.writeFile(testPath, playwrightScript, 'utf8');\n AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId, type: 'PLAYWRIGHT_TEST_GENERATED', payload: { path: testPath, screenCount: sampleScreens.length },\n }).catch(() => { });\n }\n\n // 6. Webhook notification (if configured on project)\n const webhookUrl = (opts as any).webhookUrl;\n if (webhookUrl) {\n const notifier = new WebhookNotifier({ url: webhookUrl, secret: (opts as any).webhookSecret });\n await notifier.notify('crawl.completed', opts.jobId ?? '', opts.projectId, opts.tenantId, {\n screensFound: successScreens.length,\n apiEndpoints: capturedApiEndpoints.length,\n deadLinks: deadLinkTracker.stats().total,\n }).catch(() => { });\n }\n } catch { /* post-crawl analysis is non-fatal */ }\n })();\n\n await onProgress?.(98, 'Finalizing');\n // Remaining queue = URLs discovered but not yet crawled due to segment limit\n const wasTimeout = isCrawlTimedOut();\n const pendingUrls = queue.filter((u) => !visited.has(canonicalize(u)));\n // All fully-processed URLs (exclude '_pending_' entries interrupted by timeout/abort)\n const visitedUrls = Array.from(visited.entries())\n .filter(([_k, v]) => v !== '_pending_')\n .map(([k]) => k);\n const hasMoreSegments = pendingUrls.length > 0;\n if (wasTimeout && pendingUrls.length > 0) {\n const elapsedMin = Math.round((Date.now() - crawlLoopStart) / 60_000);\n crawlWarnings.push(`global-timeout: crawl stopped after ${elapsedMin} minutes with ${pendingUrls.length} URLs remaining`);\n }\n const screensSucceeded = discovered.filter(d => !!d.screenId).length;\n const screensErrored = discovered.filter(d => !!d.error && !d.screenId).length;\n\n // Drain pending AI summary writes before marking the job done \u2014 ensures descriptions\n // are visible immediately after crawl completes. Cap wait at 30 s per screen, 60 s total.\n if (pendingSummaryWrites.length > 0) {\n await Promise.race([\n Promise.allSettled(pendingSummaryWrites),\n new Promise<void>((resolve) => setTimeout(resolve, Math.min(60_000, pendingSummaryWrites.length * 3_000))),\n ]);\n }\n\n // Detect systematic element/link extraction failure across all screens\n if (screensSucceeded >= 3) {\n const screensWithElements = discovered.filter(d => (d.elements ?? 0) > 0 && d.screenId).length;\n if (screensWithElements === 0) {\n crawlWarnings.push(\n `element-extraction: 0 elements found across all ${screensSucceeded} screens \u2014 ` +\n `DOM evaluate may be failing (check server logs for \"page.evaluate threw\" warnings)`,\n );\n }\n }\n\n return {\n screensFound: screensSucceeded, // successful captures only (not errors)\n screensErrored, // pages visited but failed to capture\n screensSkippedToNextSegment: pendingUrls.length,\n isPartial: hasMoreSegments, // true = more segments auto-queued\n discovered,\n apiEndpoints: capturedApiEndpoints,\n performanceMetrics,\n pendingUrls, // feed into next segment's resumeUrls\n visitedUrls, // all fully-processed URLs for skipUrls in continuation\n wasTimeout, // true when global timeout triggered the BFS break\n segmentIndex: segIdx, // which segment this was\n hasMoreSegments,\n domHashes: Array.from(seenDomHashes), // carry forward to next segment to avoid re-screenshotting\n crawlWarnings: crawlWarnings.length > 0 ? crawlWarnings : undefined,\n };\n } finally {\n // Log accumulated Stagehand LLM usage (extract/act/observe calls) to cost ledger.\n if (stagehandPromptTokens > 0 || stagehandCompletionTokens > 0) {\n const totalTokens = stagehandPromptTokens + stagehandCompletionTokens;\n const shProvider = stagehandModel.includes('/') ? stagehandModel.split('/')[0] : configuredProvider || 'openai';\n const shModel = stagehandModel.includes('/') ? stagehandModel.split('/').slice(1).join('/') : stagehandModel;\n const shUsage = {\n provider: shProvider,\n model: shModel,\n promptTokens: stagehandPromptTokens,\n completionTokens: stagehandCompletionTokens,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n totalTokens,\n };\n recordLLMCall({\n tenantId: opts.tenantId,\n projectId: opts.projectId,\n jobId: opts.jobId,\n agentType: 'crawl_stagehand',\n label: 'stagehand_browser_actions',\n usage: { ...shUsage, estimatedCostUsd: estimateCost(shUsage, `${shProvider}/${shModel}`) },\n }).catch(() => { });\n }\n await playwrightBrowser?.close().catch(() => { });\n await stagehand.close().catch(() => { });\n await chromeProc.close().catch(() => { });\n }\n}\n\n// Elements whose meanings indicate UI state toggles or noise \u2014 filtered from both DOM and AI results.\nconst ELEMENT_NOISE = /^(cookie|consent|privacy|accept|decline|dismiss|close|copy|\u00A9|v\\d|switch to (dark|light)|dark mode|light mode|toggle (dark|light|theme)|theme (toggle|switch)|share|tweet|follow|subscribe to newsletter|skip to|back to top|\\s*$)/i;\n\nasync function extractElements(stagehand: Stagehand, page: any, llmCfg?: { provider: string; model: string; apiKey?: string; baseUrl?: string } | null, rawPage?: any): Promise<Array<{ meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number>; ariaState?: Record<string, string>; parentLandmark?: string }>> {\n // llmCfg reserved for per-task model selection (future: create task-scoped Stagehand)\n // DOM-first: fast, no LLM cost, covers server-rendered and most SPAs.\n // Threshold >= 2 so a lone dark-mode button doesn't suppress AI fallback for rich pages.\n // rawPage: real Playwright CDP page used for page.evaluate() \u2014 avoids Stagehand's proxy\n // re-bundling the function with esbuild (which injects __name, breaking browser eval).\n const domElements = await domFallbackElements(page, rawPage).catch((err: any) => {\n console.warn('[crawler] domFallbackElements failed (page context issue or DOM error):', err?.message ?? err);\n return [] as Array<{ meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number>; ariaState?: Record<string, string>; parentLandmark?: string }>;\n });\n\n // FM-8: extract interactive elements from visible same-origin iframes\n const iframeElements: typeof domElements = [];\n try {\n const iframes = page.frames ? page.frames() : [];\n for (const frame of iframes) {\n if (frame === page.mainFrame?.()) continue; // skip main frame\n const iframeUrl: string = await frame.url().catch(() => '');\n if (!iframeUrl || iframeUrl === 'about:blank' || iframeUrl.startsWith('javascript:')) continue;\n const frameEls = await domFallbackElements(frame).catch(() => []);\n // Tag iframe elements with source context\n for (const el of frameEls.slice(0, 30)) {\n iframeElements.push({ ...el, notes: el.notes ? `${el.notes} [in iframe]` : '[in iframe]' });\n }\n }\n } catch { /* iframes may be cross-origin or inaccessible \u2014 skip silently */ }\n\n // FM-7: reveal dynamic elements \u2014 click/hover trigger elements that show dropdowns or modals\n // Only run when base DOM found elements (not on blank pages) to avoid spurious interactions.\n let dynamicElements: typeof domElements = [];\n if (domElements.length > 0) {\n try {\n dynamicElements = await page.evaluate(() => {\n const out: { meaning: string; role: string; notes: string }[] = [];\n const seen = new Set<string>();\n // Look for select/combobox/listbox that aren't already captured as interactive elements\n const triggers = document.querySelectorAll<HTMLElement>('[role=\"combobox\"],[role=\"listbox\"] [role=\"option\"],[aria-haspopup]');\n triggers.forEach((el) => {\n const label = (el.getAttribute('aria-label') || el.textContent?.trim() || '').slice(0, 80);\n if (!label || seen.has(label)) return;\n // Don't duplicate what's already captured\n const role = el.getAttribute('role') ?? el.tagName.toLowerCase();\n seen.add(label);\n out.push({ meaning: label, role, notes: '[dynamic/revealed]' });\n });\n return out.slice(0, 30);\n }).catch(() => []);\n } catch { dynamicElements = []; }\n }\n\n // Always capture content elements (headings, meta, cards, nav, FAQ) regardless of interactive count.\n // Previously this was fallback-only; now both paths run together so static sections are\n // always visible to the test generator even on pages with forms.\n const contentElements = await contentFallbackElements(page).catch((err: any) => {\n console.warn('[crawler] contentFallbackElements failed (page context issue):', err?.message ?? err);\n return [] as Array<{ meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number> }>;\n });\n\n // Cross-source text deduplication: strips wrapper phrases like \"Button to expand '...' details\"\n // and \"... FAQ button\" so duplicate FAQ buttons from DOM + content sources are collapsed.\n const crossSourceDedup = <T extends { meaning: string; role: string }>(arr: T[]): T[] => {\n const stripPhrases = (s: string) => s\n .replace(/^button to expand ['\"]?|['\"]?\\s*details$/gi, '')\n .replace(/\\s+(faq\\s*)?button$/i, '')\n .replace(/^button:\\s*/i, '')\n .toLowerCase().trim().slice(0, 80);\n const ROLE_PRIORITY: Record<string, number> = { 'faq-question': 10, 'faq-answer': 9, 'h1': 8, 'h2': 7, 'h3': 6, 'h4': 5, 'heading': 8, button: 3, a: 2 };\n const normMap = new Map<string, number>();\n const result: T[] = [];\n for (const el of arr) {\n const norm = stripPhrases(el.meaning);\n if (!norm) { result.push(el); continue; }\n const existingIdx = normMap.get(norm);\n if (existingIdx === undefined) { normMap.set(norm, result.length); result.push(el); }\n else {\n const exPri = ROLE_PRIORITY[result[existingIdx].role] ?? 1;\n const thisPri = ROLE_PRIORITY[el.role] ?? 1;\n if (thisPri > exPri) result[existingIdx] = el;\n }\n }\n return result;\n };\n\n if (domElements.length >= 2) return crossSourceDedup([...domElements, ...iframeElements, ...dynamicElements, ...contentElements]);\n\n // Static/marketing page \u2014 no interactive widgets; use content elements.\n if (contentElements.length > 0) return crossSourceDedup([...domElements, ...contentElements]);\n\n // AI fallback: DOM found nothing or only noise \u2014 try AI (pure SPA, shadow DOM, canvas-based).\n try {\n const extracted = await Promise.race([\n stagehand.extract(\n 'Extract ONLY the meaningful form and action elements on this page \u2014 inputs, selects, textareas, and action buttons. ' +\n 'For each: a clear human-readable purpose (e.g. \"Email address input\", \"Submit password reset button\"), ' +\n 'its role (button/input/select/checkbox/textarea), and for inputs the expected data type ' +\n '(valid_email/password/phone/date/search_term/text). ' +\n 'SKIP: navigation links, header/footer links, cookie banners, theme toggles (dark mode/light mode), ' +\n 'social share buttons, version strings, decorative elements, any button inside a nav or header. ' +\n 'Focus ONLY on main content forms and primary action buttons. Return at most 20 elements.',\n ElementSchema as any\n ),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 30_000)),\n ]);\n if (!extracted) return domElements;\n // Apply noise filter to AI results \u2014 AI doesn't always follow skip instructions\n const filtered = (extracted as any).elements.filter((e: any) => !ELEMENT_NOISE.test(e.meaning ?? ''));\n return filtered.slice(0, 40);\n } catch {\n return domElements;\n }\n}\n\nasync function discoverLinks(stagehand: Stagehand, origin: string, page: any, llmCfg?: { provider: string; model: string; apiKey?: string; baseUrl?: string } | null, skipAi = false, rawPage?: any): Promise<DiscoveredLinkMeta[]> {\n // Expand collapsed nav menus (hamburger, aria-haspopup, Radix closed triggers) so hidden routes\n // become part of the DOM before querying. This catches SPA nav dropdowns that only render on click.\n const navExpanded = await expandNavMenus(page);\n\n // DOM-first: <a href> links \u2014 standard apps. AI supplements when DOM coverage is < 20 unique links.\n // Threshold of 20 (not 8) because nav sidebars quickly provide 8+ links while missing deep content URLs.\n const domLinks = await domFallbackLinks(page, origin, rawPage);\n\n // Interact with tabs, carousels, and accordions to reveal hidden content and discover more links.\n // interactAndCollectLinks returns string[] \u2014 convert to DiscoveredLinkMeta[] with source INTERACTIVE.\n const interactiveRaw = await interactAndCollectLinks(page, origin);\n const interactiveLinks: DiscoveredLinkMeta[] = interactiveRaw.map((url) => ({ url, source: 'INTERACTIVE' as const }));\n\n // Dismiss any opened menus so page is clean for screenshot/element extraction after this call.\n if (navExpanded) {\n page.keyboard?.press('Escape').catch(() => { });\n await page.evaluate(() => {\n // Also click any currently-open triggers to close them (toggle pattern)\n document.querySelectorAll<HTMLElement>('[aria-expanded=\"true\"],[data-state=\"open\"],[data-headlessui-state=\"open\"]').forEach(el => {\n try { el.click(); } catch { /* ignore */ }\n });\n }).catch(() => { });\n }\n\n // Deduplicate by URL \u2014 DOM wins over INTERACTIVE for metadata richness.\n const seenUrls = new Set<string>();\n const allDomLinks: DiscoveredLinkMeta[] = [];\n for (const link of [...domLinks, ...interactiveLinks]) {\n if (!seenUrls.has(link.url)) {\n seenUrls.add(link.url);\n allDomLinks.push(link);\n }\n }\n\n if (allDomLinks.length >= 50 || skipAi) return allDomLinks;\n\n // AI complement: DOM found fewer than 50 unique links \u2014 SPA likely has JS-router pages not in <a href>.\n // Always merge DOM + AI so we never lose already-discovered links.\n // 12s timeout: allows 1 OpenAI retry (4.8s delay) but bails before the 2nd retry wastes more time.\n try {\n const extracted = await Promise.race([\n stagehand.extract(\n `Find all in-app navigation links for this application (origin: ${origin}). ` +\n 'Include: main nav, sidebar, content links, feature pages, settings pages. ' +\n 'Exclude: logout, sign out, delete, external sites, anchor-only links (#), mailto:, javascript:.',\n LinksSchema as any\n ),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 12_000)),\n ]);\n if (!extracted) return allDomLinks;\n const { links } = extracted as any;\n const currentUrl: string = page.url?.() ?? '';\n const aiLinks: DiscoveredLinkMeta[] = links\n .map((href: string) => {\n try { const u = new URL(href, currentUrl); if (!/^#!?\\//.test(u.hash)) u.hash = ''; return u.toString(); }\n catch { return null; }\n })\n .filter((u: string | null): u is string => {\n if (!u) return false;\n return isUsefulNavigationUrl(u, origin);\n })\n .map((url: string) => ({ url, source: 'AI' as const }));\n\n // Always merge DOM + AI \u2014 AI complements, never replaces. Dedup by URL.\n const merged: DiscoveredLinkMeta[] = [...allDomLinks];\n const mergedUrls = new Set(merged.map((l) => l.url));\n for (const link of aiLinks) {\n if (!mergedUrls.has(link.url) && isUsefulNavigationUrl(link.url, origin)) {\n mergedUrls.add(link.url);\n merged.push(link);\n }\n }\n return merged.filter((l) => isUsefulNavigationUrl(l.url, origin));\n } catch (err: any) {\n // Detect OpenAI rate-limit errors \u2014 signal caller via thrown special error so circuit breaker can trip\n const is429 = err?.status === 429 || String(err?.message ?? '').includes('429') || String(err?.message ?? '').includes('rate limit');\n if (is429) throw Object.assign(new Error('RATE_LIMITED'), { isRateLimit: true, domLinks: allDomLinks });\n return allDomLinks;\n }\n}\n\nexport async function domFallbackElements(page: any, rawPage?: any): Promise<Array<{ meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number>; ariaState?: Record<string, string>; parentLandmark?: string }>> {\n // Named function so we can .toString() it for CDP Runtime.evaluate fallback\n function _browserEval() {\n const out: { meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number>; ariaState?: Record<string, string>; parentLandmark?: string }[] = [];\n const seen = new Set<string>();\n // UI chrome noise: cookie banners, theme toggles, version strings, social/share buttons\n const noise = /^(cookie|consent|privacy|accept|decline|dismiss|close|copy|\u00A9|v\\d|switch to (dark|light)|dark mode|light mode|toggle (dark|light|theme)|theme (toggle|switch)|share|tweet|follow|subscribe to newsletter|skip to|back to top|\\s*$)/i;\n\n const querySelectorAllDeep = (root: any, selector: string): Element[] => {\n const results: Element[] = [];\n const queue: any[] = [root];\n while (queue.length > 0) {\n const current = queue.shift();\n Array.from(current.querySelectorAll(selector)).forEach((el: any) => results.push(el));\n current.querySelectorAll('*').forEach((el: any) => {\n if (el.shadowRoot) queue.push(el.shadowRoot);\n });\n }\n return results;\n };\n\n // Expanded selector \u2014 all interactive ARIA roles + native form elements + rich editors + bare nav links\n const selector = 'input:not([type=hidden]),select,textarea,button,a[href],[role=\"button\"],[role=\"checkbox\"],[role=\"radio\"],[role=\"combobox\"],[role=\"slider\"],[role=\"spinbutton\"],[role=\"switch\"],[role=\"tab\"],[role=\"dialog\"],[role=\"alertdialog\"],[role=\"menu\"],[role=\"menuitem\"],[role=\"menuitemcheckbox\"],[role=\"menuitemradio\"],[role=\"listbox\"],[role=\"option\"],[role=\"treeitem\"],[role=\"searchbox\"],[role=\"gridcell\"],[role=\"link\"],[contenteditable=\"true\"]';\n\n querySelectorAllDeep(document, selector).forEach((el: any) => {\n const style = window.getComputedStyle(el);\n // Enhanced actionability checks\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0' || style.pointerEvents === 'none') return;\n if (el.hasAttribute('inert') || el.getAttribute('aria-disabled') === 'true') return;\n\n const rect = el.getBoundingClientRect();\n const hasAccessibleLabel = !!(el.getAttribute('aria-label') || el.getAttribute('aria-labelledby'));\n if (rect.width === 0 && rect.height === 0 && !hasAccessibleLabel) return;\n\n // Skip elements inside 3rd-party chat widgets, cookie banners, floating overlays \u2014 these appear on EVERY page\n if (el.closest('[id*=\"intercom\"],[class*=\"intercom-\"],[id*=\"crisp\"],[class*=\"crisp-\"],[id*=\"freshchat\"],[id*=\"freshdesk\"],[id*=\"drift\"],[class*=\"drift-\"],[id*=\"hubspot-\"],[class*=\"hs-chat\"],[class*=\"hs-widget\"],[id*=\"tawk\"],[class*=\"tawk-\"],[id*=\"chat-widget\"],[class*=\"chat-widget\"],[class*=\"chatbot\"],[id*=\"zopim\"],[id*=\"ze-snippet\"],[class*=\"cookie-banner\"],[class*=\"cookie-consent\"],[class*=\"gdpr-banner\"],[id*=\"cookie-law\"],[class*=\"cookie-law\"],[id*=\"popup-form\"],[class*=\"popup-form\"],[class*=\"floating-form\"],[class*=\"sticky-cta\"],[id*=\"wm-ipp\"],[class*=\"wm-ipp\"]')) return;\n\n const tag = el.tagName.toLowerCase();\n const ariaRole = el.getAttribute('role');\n const isActionEl = tag === 'button' || tag === 'a' || ariaRole === 'button';\n\n // Skip plain anchor links inside <footer> only \u2014 footer chrome (sitemap, legal links) has no test value.\n // Header nav links ARE test targets (SPA primary navigation lives in <header>) \u2014 do NOT skip.\n // Do NOT skip <nav> elements: SPA dashboard sidebars live in <nav> and are primary test targets.\n if (tag === 'a') {\n let p = el.parentElement;\n while (p) {\n if (p.tagName?.toLowerCase() === 'footer') return;\n p = p.parentElement;\n }\n }\n\n // Label resolution: explicit <label for>, implicit wrapping <label>, aria-label, placeholder\n let labelText = '';\n if (el.id) {\n const linkedLabel = document.querySelector(`label[for=\"${el.id}\"]`);\n if (linkedLabel) labelText = linkedLabel.textContent?.trim() || '';\n }\n // Implicit label: input is a child of <label> (no for= attribute needed)\n if (!labelText) {\n const wrappingLabel = el.closest('label');\n if (wrappingLabel) {\n const clone = wrappingLabel.cloneNode(true) as Element;\n clone.querySelectorAll('input,select,textarea,button').forEach((c: any) => c.remove());\n labelText = clone.textContent?.replace(/\\s+/g, ' ').trim() || '';\n }\n }\n\n const label = (\n el.getAttribute('aria-label') ||\n el.getAttribute('placeholder') ||\n labelText ||\n el.innerText?.replace(/\\s+/g, ' ').trim() ||\n el.getAttribute('name') ||\n ''\n ).slice(0, 80);\n\n if (!label || noise.test(label) || label.length > 70) return;\n\n const role = tag === 'input' ? (el.type || 'text') : el.hasAttribute('contenteditable') ? 'rich-text' : (ariaRole || tag);\n const key = `${role}:${label.toLowerCase()}`;\n if (seen.has(key)) return;\n seen.add(key);\n\n let expectedData: string | undefined;\n if (tag === 'input') {\n if (el.type === 'email' || /email/i.test(label)) expectedData = 'valid_email';\n else if (el.type === 'password' || /password/i.test(label)) expectedData = 'password';\n else if (el.type === 'tel' || /phone|mobile/i.test(label)) expectedData = 'phone';\n else if (el.type === 'date' || /\\bdate\\b/i.test(label)) expectedData = 'date';\n else if (/\\b(code|otp|token)\\b/i.test(label)) expectedData = 'one_time_code';\n else if (/\\b(search|query)\\b/i.test(label)) expectedData = 'search_term';\n else if (el.type === 'number' || /\\b(amount|quantity|count|age|year)\\b/i.test(label)) expectedData = 'number';\n else if (el.type === 'url' || /\\b(url|website|link)\\b/i.test(label)) expectedData = 'url';\n else if (el.type === 'file') expectedData = 'file';\n }\n\n // Multi-Attribute Identity\n const attrs: Record<string, string> = {};\n if (el.id) attrs.id = el.id;\n if (el.name) attrs.name = el.name;\n if (el.getAttribute('data-testid')) attrs['data-testid'] = el.getAttribute('data-testid');\n\n // HTML5 validation attributes \u2014 ground test boundary values in real constraints\n if (tag === 'input' || tag === 'textarea') {\n if (el.required) attrs.required = 'true';\n if (el.pattern) attrs.pattern = el.pattern;\n if (el.minLength > 0) attrs.minLength = String(el.minLength);\n if (el.maxLength > 0 && el.maxLength < 524288) attrs.maxLength = String(el.maxLength);\n if (el.min !== '') attrs.min = String(el.min);\n if (el.max !== '') attrs.max = String(el.max);\n if (el.step && el.step !== 'any') attrs.step = String(el.step);\n if (el.accept) attrs.accept = el.accept;\n if (el.multiple) attrs.multiple = 'true';\n if (el.readOnly) attrs.readOnly = 'true';\n if (el.disabled) attrs.disabled = 'true';\n if (el.autocomplete && el.autocomplete !== 'on') attrs.autocomplete = el.autocomplete;\n }\n // CSS class hint \u2014 first component-library class for COMPONENT file detection\n const cssClass = (el.className || '')\n .split(' ')\n .map((c: string) => c.trim())\n .find((c: string) => c.length > 2 && !/^(true|false|active|disabled|hidden|visible)$/i.test(c));\n if (cssClass) attrs.cssClass = cssClass;\n\n // GAP 4: Select option enumeration \u2014 test generator knows valid values\n if (tag === 'select' && el.options?.length > 0 && el.options.length <= 60) {\n const opts = Array.from(el.options).map((o: any) => {\n const entry: Record<string, any> = { v: o.value, l: o.text.trim() };\n if (o.selected) entry.s = true;\n return entry;\n }).filter((o: any) => o.l);\n if (opts.length > 0) attrs.selectOptions = JSON.stringify(opts);\n }\n\n // GAP 6: aria-describedby help text \u2014 captures real constraint text (e.g. \"min 8 chars\")\n const describedById = el.getAttribute('aria-describedby');\n if (describedById) {\n const helpEl = document.getElementById(describedById.split(' ')[0]);\n const helpText = helpEl?.textContent?.trim().slice(0, 200);\n if (helpText) attrs.helpText = helpText;\n }\n\n // GAP 1: Form grouping \u2014 inputs/buttons tagged with their containing form\n const form = el.closest('form');\n if (form) {\n if ((form as any).id) attrs.formId = (form as any).id;\n const formAction = form.getAttribute('action');\n if (formAction && !formAction.startsWith('javascript:')) attrs.formAction = formAction.slice(0, 120);\n const formMethod = (form as any).method;\n if (formMethod) attrs.formMethod = formMethod.toUpperCase();\n }\n const fieldset = el.closest('fieldset');\n if (fieldset) {\n const legendText = fieldset.querySelector('legend')?.textContent?.trim().slice(0, 60);\n if (legendText) attrs.fieldsetGroup = legendText;\n }\n\n // GAP 7: Button classification \u2014 type + destructive intent\n if (tag === 'button' || ariaRole === 'button') {\n if (el.type && el.type !== 'button') attrs.buttonType = el.type; // submit | reset\n if (/\\b(delete|remove|destroy|revoke|clear|reset|discard|cancel)\\b/i.test(label)) attrs.isDestructive = 'true';\n }\n\n // ARIA state snapshot \u2014 promoted to first-class field (Phase 1)\n const stateMap: Record<string, string> = {};\n const ariaExpanded = el.getAttribute('aria-expanded');\n const ariaChecked = el.getAttribute('aria-checked');\n const ariaPressed = el.getAttribute('aria-pressed');\n const ariaSelected = el.getAttribute('aria-selected');\n const ariaInvalid = el.getAttribute('aria-invalid');\n const ariaCurrent = el.getAttribute('aria-current');\n if (ariaExpanded !== null) stateMap.expanded = ariaExpanded;\n if (ariaChecked !== null) stateMap.checked = ariaChecked;\n if (ariaPressed !== null) stateMap.pressed = ariaPressed;\n if (ariaSelected !== null) stateMap.selected = ariaSelected;\n if (ariaInvalid && ariaInvalid !== 'false') stateMap.invalid = ariaInvalid;\n if (ariaCurrent) stateMap.current = ariaCurrent;\n if (el.getAttribute('aria-required') === 'true' && !attrs.required) stateMap.required = 'true';\n\n // Parent landmark \u2014 promoted to first-class field (Phase 1)\n const getRegion = (node: any): string | undefined => {\n let p = node.parentElement;\n while (p && p !== document.body) {\n const ptag = p.tagName?.toLowerCase();\n const prole = p.getAttribute?.('role');\n if (prole === 'dialog' || prole === 'alertdialog') return 'modal';\n if (prole === 'main' || ptag === 'main') return 'main';\n if (prole === 'complementary' || ptag === 'aside') return 'aside';\n if (prole === 'navigation' || ptag === 'nav') return 'nav';\n if (prole === 'banner' || ptag === 'header') return 'header';\n if (prole === 'contentinfo' || ptag === 'footer') return 'footer';\n p = p.parentElement;\n }\n return undefined;\n };\n const parentLandmark = getRegion(el);\n\n // GAP 8: Rich text editor detection\n if (el.hasAttribute('contenteditable')) {\n const cls = ((el.className || '') + ' ' + (el.getAttribute('data-type') || '')).toLowerCase();\n const editorType = cls.includes('tiptap') || cls.includes('prosemirror') ? 'tiptap' :\n cls.includes('cm-') || cls.includes('codemirror') ? 'codemirror' :\n (window as any).Quill ? 'quill' :\n typeof (window as any).monaco !== 'undefined' ? 'monaco' : 'contenteditable';\n attrs.editorType = editorType;\n }\n\n const notes = Object.keys(attrs).length > 0 ? JSON.stringify(attrs) : undefined;\n const boundingRect = {\n x: Math.round(rect.x), y: Math.round(rect.y),\n width: Math.round(rect.width), height: Math.round(rect.height),\n top: Math.round(rect.top), left: Math.round(rect.left),\n right: Math.round(rect.right), bottom: Math.round(rect.bottom),\n };\n out.push({\n meaning: label, role, expectedData, notes,\n boundingRect,\n ariaState: Object.keys(stateMap).length > 0 ? stateMap : undefined,\n parentLandmark: parentLandmark ?? undefined,\n });\n });\n\n // Form fields first, then buttons\n const priority = (e: typeof out[0]) =>\n ['email', 'password', 'text', 'tel', 'date', 'number', 'select', 'textarea', 'url', 'file'].includes(e.role) ? 0 : 1;\n out.sort((a, b) => priority(a) - priority(b));\n return out; // Cap removed\n }\n // CDP Runtime.evaluate bypasses Playwright's isolated world entirely.\n // The \"__name is not defined\" error comes from Playwright's own UtilityScript being absent\n // from the isolated world (destroyed by navigation events in Stagehand's CDP session).\n // Solution: when rawPage (a real Playwright Page) is available, use CDP Runtime.evaluate\n // as the PRIMARY path \u2014 no isolated world needed, no __name dependency.\n //\n // esbuild injects __name() calls for named arrow-function constants inside _browserEval\n // (e.g. querySelectorAllDeep). When _browserEval.toString() is sent to the browser,\n // the browser throws \"ReferenceError: __name is not defined\". Fix: prepend a tiny\n // __name polyfill that just returns the function (name-setting is non-critical).\n const _browserEvalStr = `(function(){const __name=(fn,n)=>{try{Object.defineProperty(fn,'name',{value:n,configurable:true})}catch(e){}return fn};return(${_browserEval.toString()})()})();`;\n\n if (rawPage && typeof rawPage.context === 'function') {\n try {\n const ctx = rawPage.context();\n if (typeof ctx?.newCDPSession === 'function') {\n const cdp = await ctx.newCDPSession(rawPage);\n try {\n const evalResult = await cdp.send('Runtime.evaluate', {\n expression: _browserEvalStr,\n returnByValue: true,\n awaitPromise: false,\n });\n if (evalResult?.exceptionDetails) {\n console.warn('[crawler] domFallbackElements CDP primary error:', evalResult.exceptionDetails?.exception?.description ?? evalResult.exceptionDetails?.text);\n } else if (Array.isArray(evalResult?.result?.value)) {\n return (evalResult.result.value as any[]).map((e: any) => ({ ...e, isInteractive: true }));\n }\n } finally {\n cdp.detach().catch(() => {});\n }\n }\n } catch (cdpPrimaryErr: any) {\n console.warn('[crawler] domFallbackElements CDP primary failed, trying page.evaluate:', cdpPrimaryErr?.message ?? String(cdpPrimaryErr));\n }\n }\n\n // Fallback: pass the pre-serialized string expression so esbuild's __name() wrapper\n // for nested named functions never reaches the browser (Function.prototype.toString\n // returns the source including __name() calls for any nested named arrow constants).\n // Playwright accepts a JS expression string directly \u2014 no isolated-world __name leakage.\n const evalPage = rawPage ?? page;\n const _doEvaluate = (): Promise<any> => evalPage.evaluate(_browserEvalStr as any);\n let result: any[];\n try {\n result = await _doEvaluate();\n } catch (err1: any) {\n // Second attempt after a brief wait \u2014 isolated world may need a tick to settle\n await new Promise<void>(r => setTimeout(r, 500));\n try {\n result = await _doEvaluate();\n } catch (err2: any) {\n console.warn('[crawler] domFallbackElements page.evaluate threw (attempt 2):', err2?.message ?? String(err2));\n return [];\n }\n }\n return (result ?? []).map((e: any) => ({ ...e, isInteractive: true }));\n}\n\n/** Capture content anatomy for EVERY page \u2014 not just static ones.\n * Headings, meta tags, cards, chips, FAQ items, nav/footer structure, section text.\n * Previously fallback-only; now always runs alongside domFallbackElements so\n * the test generator sees ALL page content, not just interactive widgets. */\nasync function contentFallbackElements(page: any): Promise<Array<{ meaning: string; role: string; expectedData?: string; notes?: string; boundingRect?: Record<string, number> }>> {\n return page.evaluate(() => {\n const out: { meaning: string; role: string; notes?: string; boundingRect?: Record<string, number> }[] = [];\n const seen = new Set<string>();\n const captureRect = (el: Element): Record<string, number> | undefined => {\n try {\n const r = el.getBoundingClientRect();\n if (r.width === 0 && r.height === 0) return undefined;\n return { x: r.x, y: r.y, width: r.width, height: r.height, top: r.top, right: r.right, bottom: r.bottom, left: r.left };\n } catch { return undefined; }\n };\n const addUniq = (item: { meaning: string; role: string; notes?: string }, el?: Element) => {\n const key = `${item.role}:${item.meaning.toLowerCase().slice(0, 60)}`;\n if (!seen.has(key) && item.meaning.trim().length > 1) {\n seen.add(key);\n out.push(el ? { ...item, boundingRect: captureRect(el) } : item);\n }\n };\n const isVisible = (el: Element) => {\n const s = window.getComputedStyle(el);\n return s.display !== 'none' && s.visibility !== 'hidden' && s.opacity !== '0' && (el as HTMLElement).offsetParent !== null;\n };\n\n // 1. Page-level meta (title, description, og:, canonical)\n const title = document.title?.trim();\n if (title) addUniq({ meaning: title, role: 'page-title', notes: JSON.stringify({ tag: 'title' }) });\n const desc = document.querySelector('meta[name=\"description\"]')?.getAttribute('content')?.trim();\n if (desc) addUniq({ meaning: desc, role: 'meta-description', notes: JSON.stringify({ tag: 'meta[name=description]' }) });\n const ogTitle = document.querySelector('meta[property=\"og:title\"]')?.getAttribute('content')?.trim();\n if (ogTitle) addUniq({ meaning: ogTitle, role: 'og-title', notes: JSON.stringify({ tag: 'meta[property=og:title]' }) });\n const canonical = document.querySelector('link[rel=\"canonical\"]')?.getAttribute('href')?.trim();\n if (canonical) addUniq({ meaning: canonical, role: 'canonical-url', notes: JSON.stringify({ tag: 'link[rel=canonical]' }) });\n\n // 2. All headings h1\u2013h6 \u2014 full page structure\n document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach((h: any) => {\n if (!isVisible(h)) return;\n const text = h.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 100);\n if (text) addUniq({ meaning: text, role: h.tagName.toLowerCase(), notes: JSON.stringify({ level: h.tagName }) }, h);\n });\n\n // 3. FAQ / accordion \u2014 <details>/<summary>, ARIA pattern, and class-name scan\n document.querySelectorAll('details, [data-state=\"closed\"], [data-state=\"open\"]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const summary = el.tagName === 'DETAILS'\n ? el.querySelector('summary')\n : el.querySelector('[class*=\"trigger\" i], [class*=\"header\" i], [class*=\"question\" i], [class*=\"title\" i]') ?? el;\n const qText = summary?.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 120);\n if (qText && qText.length > 3) {\n addUniq({ meaning: qText, role: 'faq-question', notes: JSON.stringify({ expanded: el.hasAttribute('open') || el.getAttribute('data-state') === 'open' }) });\n }\n // Answer: for <details> it's the non-summary child; for React accordions try both child content and next sibling\n const contentEl = el.tagName === 'DETAILS'\n ? Array.from(el.children).find((c: any) => c.tagName !== 'SUMMARY')\n : (el.querySelector('[class*=\"content\" i], [class*=\"answer\" i], [class*=\"panel\" i], [class*=\"body\" i]:not(body)') ?? el.nextElementSibling);\n if (contentEl) {\n const aText = (contentEl as any).textContent?.replace(/\\s+/g, ' ').trim().slice(0, 200);\n if (aText && aText.length > 5 && aText !== qText) addUniq({ meaning: aText, role: 'faq-answer', notes: JSON.stringify({ question: qText }) });\n }\n });\n // 3b. FAQ by class-name container scan \u2014 catches sites without ARIA or data-state attributes\n document.querySelectorAll('[class*=\"faq\" i]:not(script):not(style):not(nav), [id*=\"faq\" i]:not(script):not(style)').forEach((container: any) => {\n if (!isVisible(container)) return;\n const qEls = container.querySelectorAll('[class*=\"question\" i], [class*=\"trigger\" i], summary, dt, [class*=\"heading\" i]');\n const aEls = container.querySelectorAll('[class*=\"answer\" i], [class*=\"content\" i]:not(main):not(article), [class*=\"panel\" i], dd');\n qEls.forEach((q: any) => {\n const qText = q.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 120);\n if (qText && qText.length > 3) addUniq({ meaning: qText, role: 'faq-question', notes: JSON.stringify({ source: 'class-faq' }) });\n });\n aEls.forEach((a: any) => {\n const aText = a.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 200);\n if (aText && aText.length > 5) addUniq({ meaning: aText, role: 'faq-answer', notes: JSON.stringify({ source: 'class-faq' }) });\n });\n });\n\n // 4. Card and chip content (component-library agnostic)\n document.querySelectorAll('[class*=\"card\" i]:not(nav):not(header):not(footer), [class*=\"chip\" i], [class*=\"badge\" i], [class*=\"tag\" i], [class*=\"pill\" i]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 150);\n if (text && text.length > 2 && text.length < 200) addUniq({ meaning: text, role: 'content-card' }, el);\n });\n\n // 5. Feature / service list items inside main content (capped per category)\n const mainContent = document.querySelector('main, [role=\"main\"], article') ?? document.body;\n let listItemCount = 0;\n mainContent.querySelectorAll('li').forEach((li: any) => {\n if (listItemCount >= 50) return;\n if (!isVisible(li)) return;\n const text = li.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 150);\n if (text && text.length > 3 && text.length < 200) { addUniq({ meaning: text, role: 'list-item' }, li); listItemCount++; }\n });\n\n // 6. First paragraph in each section (key descriptive copy)\n mainContent.querySelectorAll('section > p:first-of-type, article > p:first-of-type, [class*=\"section\" i] > p:first-of-type').forEach((p: any) => {\n if (!isVisible(p)) return;\n const text = p.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 250);\n if (text && text.length > 10) addUniq({ meaning: text, role: 'section-paragraph' }, p);\n });\n\n // 7. CTA section text (standalone paragraphs near buttons that aren't form fields)\n document.querySelectorAll('[class*=\"cta\" i] p, [class*=\"call-to-action\" i] p, section:not(form) > p').forEach((p: any) => {\n if (!isVisible(p)) return;\n const text = p.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 300);\n if (text && text.length > 10 && text.length < 400) addUniq({ meaning: text, role: 'cta-section' });\n });\n\n // 8. Navigation links \u2014 explicitly captured (excluded from interactive element selector)\n // Use a lighter visibility check: skip offsetParent because nav is often inside a responsive\n // container (e.g. hidden lg:grid) that may be display:none at the crawler's viewport,\n // causing offsetParent to be null even though the link exists in the page's nav structure.\n const isNavVisible = (el: Element) => {\n const s = window.getComputedStyle(el);\n return s.display !== 'none' && s.visibility !== 'hidden' && s.opacity !== '0';\n };\n const navSel = [\n 'nav a', '[role=\"navigation\"] a', 'header a', 'header nav a', 'footer nav a',\n '[aria-label*=\"navigation\" i] a', '[aria-label*=\"menu\" i] a', '[aria-label*=\"sidebar\" i] a',\n 'aside a', '[role=\"complementary\"] a',\n '[class*=\"sidebar\" i] a', '[class*=\"side-nav\" i] a', '[class*=\"sidenav\" i] a',\n '[class*=\"nav-menu\" i] a', '[class*=\"navmenu\" i] a', '[data-nav] a',\n ].join(', ');\n const navLinksFoundCount = { n: 0 };\n document.querySelectorAll(navSel).forEach((a: any) => {\n if (!isNavVisible(a)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n const href = a.href;\n if (!label || !href || /^(javascript:|#$)/i.test(href)) return;\n let landmark = 'Site Navigation';\n let el: any = a.parentElement;\n while (el) {\n const tag = el.tagName?.toLowerCase();\n const role = el.getAttribute?.('role')?.toLowerCase();\n const cl = (el.className ?? '').toLowerCase();\n if (tag === 'header' || role === 'banner') { landmark = 'Header'; break; }\n if (tag === 'footer' || role === 'contentinfo') { landmark = 'Footer'; break; }\n if (tag === 'aside' || role === 'complementary' || cl.includes('sidebar') || cl.includes('sidenav') || cl.includes('side-nav')) { landmark = 'Sidebar'; break; }\n if (tag === 'nav' || role === 'navigation') {\n const directLabel = el.getAttribute('aria-label')?.trim() ?? '';\n const labelId = el.getAttribute('aria-labelledby');\n const referencedLabel = labelId ? (document.getElementById(labelId)?.textContent?.trim() ?? '') : '';\n landmark = directLabel || referencedLabel || 'Site Navigation';\n break;\n }\n el = el.parentElement;\n }\n addUniq({ meaning: label, role: 'nav-link', notes: JSON.stringify({ href: href.slice(0, 150), landmark }) });\n navLinksFoundCount.n++;\n });\n // Grandparent-grouping fallback: detects sidebar navigation where each link is individually\n // wrapped (e.g. <div class=\"flex\"><a>link</a></div> \u00D7 many siblings). Runs ALWAYS so header\n // links don't block sidebar detection. Deduped against hrefs already in the semantic pass.\n {\n const navHrefsAlready = new Set<string>();\n for (const item of out) {\n if (item.role === 'nav-link') {\n try { const h = JSON.parse(item.notes ?? '{}').href; if (h) navHrefsAlready.add(h); } catch { /* skip */ }\n }\n }\n const gpGroups2 = new Map<Element, Array<{label: string; href: string}>>();\n document.querySelectorAll('a[href]').forEach((a: any) => {\n if (!isNavVisible(a)) return;\n const href = a.href ?? '';\n if (!href || /^(javascript:|#$|mailto:|tel:)/i.test(href) || navHrefsAlready.has(href)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n if (!label || label.length > 40) return;\n const parent = a.parentElement;\n const gp = parent?.parentElement;\n if (!parent || !gp) return;\n if (parent.querySelectorAll('a').length !== 1) return;\n const gpTag = gp.tagName.toLowerCase();\n if (['body', 'html', 'form'].includes(gpTag)) return;\n const arr = gpGroups2.get(gp) ?? [];\n arr.push({ label, href });\n gpGroups2.set(gp, arr);\n });\n for (const [, links] of gpGroups2.entries()) {\n if (links.length >= 4) {\n for (const { label, href } of links) {\n addUniq({ meaning: label, role: 'nav-link', notes: JSON.stringify({ href: href.slice(0, 150), landmark: 'Sidebar' }) });\n }\n }\n }\n }\n\n // 9. Breadcrumb items\n document.querySelectorAll('[aria-label*=\"breadcrumb\" i] a, [class*=\"breadcrumb\" i] a, nav[aria-label*=\"breadcrumb\" i] a').forEach((a: any) => {\n const label = a.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 60);\n const href = a.href;\n if (label) addUniq({ meaning: label, role: 'breadcrumb-item', notes: JSON.stringify({ href: href?.slice(0, 150) }) });\n });\n\n // 10. Footer links and contact info (capped at 25)\n // Matches semantic <footer>, ARIA contentinfo, and common div/section footer patterns\n let footerLinkCount = 0;\n const footerEls = new Set<Element>();\n document.querySelectorAll('footer, [role=\"contentinfo\"], [class*=\"footer\" i]:not(script):not(style):not(nav), [id*=\"footer\" i]:not(script):not(style)').forEach((f: any) => footerEls.add(f));\n const footerLinks: Element[] = [];\n footerEls.forEach((f) => f.querySelectorAll('a').forEach((a: Element) => footerLinks.push(a)));\n // Deduplicate links that appear in multiple matched footer containers\n const seenFooterHrefs = new Set<string>();\n footerLinks.filter((a: any) => {\n const href = a.href ?? '';\n if (seenFooterHrefs.has(href)) return false;\n seenFooterHrefs.add(href);\n return true;\n }).forEach((a: any) => {\n if (footerLinkCount >= 25) return;\n if (!isVisible(a)) return;\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 60);\n const href = a.href ?? '';\n if (!label) return;\n if (/^mailto:/i.test(href)) {\n addUniq({ meaning: label || href, role: 'footer-contact', notes: JSON.stringify({ href }) }); footerLinkCount++;\n } else if (/^tel:/i.test(href)) {\n addUniq({ meaning: label || href, role: 'footer-contact', notes: JSON.stringify({ href }) }); footerLinkCount++;\n } else if (label.length > 0) {\n addUniq({ meaning: label, role: 'footer-link', notes: JSON.stringify({ href: href.slice(0, 150) }) }); footerLinkCount++;\n }\n });\n\n // 11. All image types \u2014 img tags (with or without alt), picture/source, CSS background-image, lazy-load patterns\n let imgCount = 0;\n // Lighter visibility check for images: skip only display:none or visibility:hidden.\n // Do NOT check offsetParent (fails for position:fixed heroes) or opacity (kills fade-in animations).\n const isImgVisible = (el: any) => {\n const s = window.getComputedStyle(el);\n return s.display !== 'none' && s.visibility !== 'hidden';\n };\n // 11a. <img> \u2014 both with and without alt (capped at 20)\n document.querySelectorAll('img').forEach((img: any) => {\n if (imgCount >= 20) return;\n if (!isImgVisible(img)) return;\n const alt = img.getAttribute('alt')?.trim().slice(0, 80) ?? '';\n const src = (img.getAttribute('src') || img.getAttribute('data-src') || img.getAttribute('data-lazy-src') || img.getAttribute('data-original') || '').slice(0, 120);\n // Also grab first URL from srcset (Next.js Image component uses srcset directly on <img>)\n const srcsetFirst = img.getAttribute('srcset')?.split(',')[0]?.trim().split(' ')[0]?.slice(0, 120) ?? '';\n const resolvedSrc = src || srcsetFirst;\n if (!resolvedSrc && !alt) return;\n const label = alt || resolvedSrc.split('/').pop()?.split('?')[0]?.slice(0, 60) || 'Image';\n addUniq({ meaning: label, role: alt ? 'image' : 'image-no-alt', notes: JSON.stringify({ src: resolvedSrc, alt, hasAlt: !!alt }) });\n imgCount++;\n });\n // 11b. <picture> / <source srcset> \u2014 responsive images\n document.querySelectorAll('picture source[srcset]').forEach((src: any) => {\n if (imgCount >= 25) return;\n const srcset = src.getAttribute('srcset')?.split(',')[0]?.trim().split(' ')[0]?.slice(0, 120) ?? '';\n const media = src.getAttribute('media') ?? '';\n if (srcset) { addUniq({ meaning: `Responsive image${media ? ' (' + media + ')' : ''}: ${srcset.split('/').pop()?.split('?')[0] ?? ''}`, role: 'picture-source', notes: JSON.stringify({ srcset: srcset.slice(0, 150), media }) }); imgCount++; }\n });\n // 11c. CSS background-image via inline style and computed style (capped at 15)\n let bgCount = 0;\n document.querySelectorAll('[style*=\"background-image\"], [style*=\"background:\"]').forEach((el: any) => {\n if (bgCount >= 15) return;\n if (!isImgVisible(el)) return;\n const style = el.getAttribute('style') ?? '';\n const match = style.match(/url\\(['\"]?([^'\")\\s]+)['\"]?\\)/i);\n if (match) {\n const url = match[1].slice(0, 120);\n const role = el.tagName.toLowerCase();\n const context = (el.getAttribute('aria-label') || el.getAttribute('title') || el.className.split(' ').find((c: string) => c.length > 3 && !['true','false'].includes(c)) || '').slice(0, 60);\n addUniq({ meaning: context || `BG image on <${role}>: ${url.split('/').pop()?.split('?')[0] ?? url}`, role: 'bg-image', notes: JSON.stringify({ url, element: role, context }) });\n bgCount++;\n }\n });\n // 11d. Computed background-image on key visual elements (expanded class list)\n document.querySelectorAll('[class*=\"hero\" i], [class*=\"banner\" i], [class*=\"cover\" i], [class*=\"header-bg\" i], [class*=\"card\" i]:not(nav), [class*=\"feature\" i], [class*=\"service\" i], [class*=\"about\" i], [class*=\"team\" i], section').forEach((el: any) => {\n if (bgCount >= 15) return;\n if (!isImgVisible(el)) return;\n try {\n const computed = window.getComputedStyle(el).backgroundImage;\n if (computed && computed !== 'none' && computed.includes('url(')) {\n const match = computed.match(/url\\(['\"]?([^'\")\\s]+)['\"]?\\)/i);\n if (match) {\n const url = match[1].slice(0, 120);\n const tag = el.tagName.toLowerCase();\n const cls = Array.from(el.classList as DOMTokenList).find((c: any) => typeof c === 'string' && c.length > 3 && !/^(true|false|active|visible)$/.test(c)) ?? '';\n addUniq({ meaning: `CSS bg image on .${cls || tag}: ${url.split('/').pop()?.split('?')[0] ?? url}`, role: 'bg-image', notes: JSON.stringify({ url, cssClass: cls, element: tag }) });\n bgCount++;\n }\n }\n } catch { /* getComputedStyle not always available */ }\n });\n // 11e. Lazy-load data attribute patterns (data-bg, data-background, data-lazy)\n document.querySelectorAll('[data-bg], [data-background], [data-background-image]').forEach((el: any) => {\n if (bgCount >= 15) return;\n if (!isVisible(el)) return;\n const url = (el.getAttribute('data-bg') || el.getAttribute('data-background') || el.getAttribute('data-background-image') || '').slice(0, 120);\n if (url) { addUniq({ meaning: `Lazy BG image: ${url.split('/').pop()?.split('?')[0] ?? url}`, role: 'bg-image', notes: JSON.stringify({ url, pattern: 'data-bg' }) }); bgCount++; }\n });\n\n // 12. Content links outside nav/header/footer (capped at 40)\n const navTags = new Set(['nav', 'header', 'footer']);\n let contentLinkCount = 0;\n document.querySelectorAll('a[href]').forEach((a: any) => {\n if (contentLinkCount >= 40) return;\n if (!isVisible(a)) return;\n let p = a.parentElement;\n while (p) { if (navTags.has(p.tagName?.toLowerCase())) return; p = p.parentElement; }\n const label = (a.getAttribute('aria-label') || a.textContent?.replace(/\\s+/g, ' ').trim() || '').slice(0, 80);\n const href = a.href;\n if (label && href && !/^(#$|javascript:|mailto:|tel:)/i.test(href)) {\n const isExternal = !href.includes(location.hostname);\n addUniq({ meaning: label, role: isExternal ? 'external-link' : 'internal-link', notes: JSON.stringify({ href: href.slice(0, 120) }) });\n contentLinkCount++;\n }\n });\n\n // 13. Animated / interactive content markers\n const hasAnimation = !!document.querySelector('[class*=\"animate\"], [class*=\"motion\"], [class*=\"transition\"], [class*=\"scroll-\"], [data-aos], [data-scroll]');\n if (hasAnimation) addUniq({ meaning: 'CSS animations / scroll effects detected on page', role: 'animation-layer', notes: JSON.stringify({ detected: true }) });\n if (document.querySelector('video')) addUniq({ meaning: 'Video element present', role: 'video', notes: JSON.stringify({ count: document.querySelectorAll('video').length }) });\n if (document.querySelector('canvas')) addUniq({ meaning: 'Canvas element present', role: 'canvas' });\n\n // C-07: Section structure as named semantic units\n document.querySelectorAll('main section, article section, [role=\"main\"] section').forEach((el: any) => {\n if (!isVisible(el)) return;\n const heading = el.querySelector('h1,h2,h3,h4')?.textContent?.trim() ?? '';\n const itemCount = el.querySelectorAll('li, [class*=\"card\" i], [class*=\"chip\" i]').length;\n const paragraphs = el.querySelectorAll('p').length;\n const meaning = heading || `Section (${itemCount} items)`;\n if (meaning) addUniq({ meaning, role: 'page-section', notes: JSON.stringify({ heading, itemCount, paragraphs, id: el.id || el.getAttribute('data-section') }) });\n });\n\n // 14. Extended meta tags (og:description, og:image, twitter card)\n const ogDesc = document.querySelector('meta[property=\"og:description\"]')?.getAttribute('content')?.trim();\n if (ogDesc) addUniq({ meaning: ogDesc, role: 'og-description', notes: JSON.stringify({ tag: 'meta[property=og:description]' }) });\n const ogImage = document.querySelector('meta[property=\"og:image\"]')?.getAttribute('content')?.trim();\n if (ogImage) addUniq({ meaning: ogImage, role: 'og-image', notes: JSON.stringify({ tag: 'meta[property=og:image]', src: ogImage }) });\n const twitterTitle = document.querySelector('meta[name=\"twitter:title\"]')?.getAttribute('content')?.trim();\n if (twitterTitle) addUniq({ meaning: twitterTitle, role: 'twitter-title', notes: JSON.stringify({ tag: 'meta[name=twitter:title]' }) });\n const twitterDesc = document.querySelector('meta[name=\"twitter:description\"]')?.getAttribute('content')?.trim();\n if (twitterDesc) addUniq({ meaning: twitterDesc, role: 'twitter-description', notes: JSON.stringify({ tag: 'meta[name=twitter:description]' }) });\n const jsonFonts: string[] = [];\n document.querySelectorAll('link[rel=\"preload\"][as=\"font\"], link[href*=\"fonts.googleapis\"]').forEach((l: any) => {\n const url = l.href?.slice(0, 120);\n if (url) jsonFonts.push(url);\n });\n if (jsonFonts.length) addUniq({ meaning: `Font imports: ${jsonFonts.length} font file(s)`, role: 'font-stack', notes: JSON.stringify({ fonts: jsonFonts.slice(0, 5) }) });\n\n // 15. JSON-LD structured data \u2014 extract FAQ answers, deliverables, tech stack, metrics\n document.querySelectorAll('script[type=\"application/ld+json\"], script[class*=\"tsr\"]').forEach((s: any) => {\n try {\n const data = JSON.parse(s.textContent ?? '{}');\n const items = Array.isArray(data) ? data : [data];\n for (const item of items) {\n // FAQ answers from JSON-LD (often NOT rendered in collapsed accordions)\n const faqArr = item.mainEntity ?? item.faqs ?? item.questions ?? item.faq ?? [];\n (Array.isArray(faqArr) ? faqArr : []).forEach((f: any) => {\n const q = f.name ?? f.question ?? '';\n const a = f.acceptedAnswer?.text ?? f.answer ?? '';\n if (q) addUniq({ meaning: String(q).slice(0, 150), role: 'faq-question', notes: JSON.stringify({ source: 'json-ld' }) });\n if (a) addUniq({ meaning: String(a).slice(0, 200), role: 'faq-answer', notes: JSON.stringify({ question: String(q).slice(0, 80), source: 'json-ld' }) });\n });\n // Deliverables with descriptions\n const deliverables = item.deliverables ?? item.services ?? item.offerings ?? [];\n (Array.isArray(deliverables) ? deliverables : []).forEach((d: any) => {\n const title = d.title ?? d.name ?? '';\n const desc = d.description ?? d.desc ?? '';\n if (title) addUniq({ meaning: `${title}${desc ? ': ' + desc.slice(0, 120) : ''}`, role: 'deliverable', notes: JSON.stringify({ title, description: String(desc).slice(0, 200) }) });\n });\n // Tech stack items\n const stack = item.stack ?? item.technologies ?? item.tools ?? [];\n (Array.isArray(stack) ? stack : []).forEach((tool: any) => {\n const name = typeof tool === 'string' ? tool : (tool.name ?? '');\n if (name) addUniq({ meaning: name, role: 'tech-stack-item', notes: JSON.stringify({ source: 'json-ld' }) });\n });\n // Outcome/metric cards\n const outcomes = item.outcomes ?? item.metrics ?? item.stats ?? [];\n (Array.isArray(outcomes) ? outcomes : []).forEach((m: any) => {\n const metric = m.metric ?? m.value ?? '';\n const label = m.label ?? m.name ?? '';\n if (metric && label) addUniq({ meaning: `${metric} \u2014 ${label}`, role: 'metric-card', notes: JSON.stringify({ metric, label }) });\n });\n // Features list\n const features = item.features ?? item.capabilities ?? [];\n (Array.isArray(features) ? features : []).forEach((f: any) => {\n const name = typeof f === 'string' ? f : (f.name ?? '');\n if (name) addUniq({ meaning: name, role: 'feature-badge', notes: JSON.stringify({ source: 'json-ld' }) });\n });\n // HowTo steps (tutorials, guides, recipes)\n if (item['@type'] === 'HowTo' || item['@type'] === 'Recipe') {\n const steps = item.step ?? item.steps ?? [];\n (Array.isArray(steps) ? steps : []).forEach((step: any, idx: number) => {\n const text = step.text ?? step.description ?? (typeof step === 'string' ? step : '');\n const name = step.name ?? `Step ${idx + 1}`;\n if (text) addUniq({ meaning: `${name}: ${String(text).slice(0, 200)}`, role: 'howto-step', notes: JSON.stringify({ stepIndex: idx + 1, name }) });\n });\n }\n // BreadcrumbList \u2014 page hierarchy for navigation test generation\n if (item['@type'] === 'BreadcrumbList') {\n const crumbs = item.itemListElement ?? [];\n (Array.isArray(crumbs) ? crumbs : []).forEach((crumb: any) => {\n const name = crumb.name ?? crumb.item?.name ?? '';\n const url = crumb.item?.['@id'] ?? crumb.item ?? '';\n if (name) addUniq({ meaning: name, role: 'breadcrumb-item', notes: JSON.stringify({ position: crumb.position, url }) });\n });\n }\n // Event details (conference, webinar, workshop)\n if (item['@type'] === 'Event') {\n const name = item.name ?? '';\n const startDate = item.startDate ?? '';\n const location = item.location?.name ?? item.location?.address?.streetAddress ?? '';\n if (name) addUniq({ meaning: name, role: 'event-name', notes: JSON.stringify({ startDate, location, source: 'json-ld' }) });\n }\n // JobPosting \u2014 for job boards and career pages\n if (item['@type'] === 'JobPosting') {\n const title = item.title ?? '';\n const desc = item.description ?? '';\n const employer = item.hiringOrganization?.name ?? '';\n if (title) addUniq({ meaning: `${title}${employer ? ' at ' + employer : ''}`, role: 'job-posting', notes: JSON.stringify({ description: String(desc).slice(0, 200) }) });\n }\n // Review / AggregateRating \u2014 for product and service pages\n if (item['@type'] === 'Review') {\n const body = item.reviewBody ?? '';\n const rating = item.reviewRating?.ratingValue ?? '';\n const author = item.author?.name ?? '';\n if (body) addUniq({ meaning: String(body).slice(0, 200), role: 'review-text', notes: JSON.stringify({ rating, author }) });\n }\n }\n } catch { /* non-fatal \u2014 malformed JSON-LD */ }\n });\n\n // 16. Tab panels \u2014 capture visible and aria-labeled panels (process steps, tabbed content)\n document.querySelectorAll('[role=\"tabpanel\"], [data-state=\"active\"][id*=\"panel\"], [id*=\"panel\"][aria-labelledby]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const heading = el.querySelector('h2, h3, h4')?.textContent?.trim() ?? '';\n const desc = el.querySelector('p')?.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 200) ?? '';\n const badges = Array.from(el.querySelectorAll('[class*=\"badge\" i], [class*=\"tag\" i], [class*=\"pill\" i], [class*=\"chip\" i], [class*=\"rounded-full\" i]')).map((b: any) => b.textContent?.trim()).filter(Boolean).slice(0, 8);\n const meaning = heading || desc;\n if (meaning) addUniq({ meaning: meaning.slice(0, 150), role: 'tab-panel', notes: JSON.stringify({ heading, description: desc, badges, panelId: el.id }) });\n });\n\n // 17. FAQ accordion: aria-controls pattern \u2014 find answer panel via aria-controls attribute\n // Include both aria-expanded buttons and plain aria-controls (some FAQ components omit aria-expanded)\n document.querySelectorAll('[aria-controls]').forEach((btn: any) => {\n if (!isVisible(btn)) return;\n const panelId = btn.getAttribute('aria-controls');\n if (!panelId) return;\n const panel = document.getElementById(panelId);\n if (!panel) return;\n const qText = btn.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 120);\n // Read panel text even if hidden (accordion may be collapsed)\n const aText = panel.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 200);\n if (qText && qText.length > 3) addUniq({ meaning: qText, role: 'faq-question', notes: JSON.stringify({ panelId, expanded: btn.getAttribute('aria-expanded') }) });\n if (aText && aText.length > 5 && aText !== qText) addUniq({ meaning: aText, role: 'faq-answer', notes: JSON.stringify({ question: qText?.slice(0, 80), source: 'aria-controls' }) });\n });\n\n // 18. Tech stack / tool pills \u2014 monospace pill elements outside nav/footer\n const mainEl = document.querySelector('main, [role=\"main\"], article') ?? document.body;\n mainEl.querySelectorAll('[class*=\"mono\" i]:not(code):not(pre), [class*=\"pill\" i]:not(nav), [class*=\"chip\" i]:not(nav), [class*=\"tag\" i]:not(nav), [class*=\"badge\" i]:not(nav)').forEach((el: any) => {\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 60);\n if (text && text.length > 1 && text.length < 60 && !text.includes(' ')) {\n // Single-word or hyphenated tool name\n addUniq({ meaning: text, role: 'tech-stack-item', notes: JSON.stringify({ source: 'dom-pill' }) });\n } else if (text && text.length > 1 && text.length < 40) {\n addUniq({ meaning: text, role: 'feature-badge', notes: JSON.stringify({ source: 'dom-pill' }) });\n }\n });\n\n // 19. Related/linked service cards in main content (cards with links to other pages)\n mainEl.querySelectorAll('a[href][class*=\"card\" i], [class*=\"card\" i] a[href], [class*=\"service\" i][href], a[class*=\"service\" i]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const anchor = el.tagName === 'A' ? el : el.querySelector('a');\n if (!anchor) return;\n const href = anchor.href;\n if (!href || /^(#|javascript:|mailto:|tel:)/i.test(href)) return;\n const heading = el.querySelector('h2, h3, h4')?.textContent?.trim() ?? '';\n const desc = el.querySelector('p')?.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 120) ?? '';\n const label = anchor.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 80) ?? '';\n const meaning = heading || label || 'Linked card';\n if (meaning && meaning !== 'Linked card' || (heading && desc)) {\n addUniq({ meaning: `${heading || meaning}${desc ? ': ' + desc : ''}`.slice(0, 180), role: 'service-card', notes: JSON.stringify({ href: href.slice(0, 150), heading, description: desc }) });\n }\n });\n\n // 20. Metric/outcome cards \u2014 structured numeric data cards\n mainEl.querySelectorAll('[class*=\"metric\" i], [class*=\"outcome\" i], [class*=\"stat\" i], [class*=\"kpi\" i]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 100);\n if (text && text.length > 2 && text.length < 120) addUniq({ meaning: text, role: 'metric-card', notes: JSON.stringify({ source: 'dom-class' }) });\n });\n\n // 21. Screen-reader-only headings (sr-only) \u2014 accessibility landmarks hidden from visual view\n document.querySelectorAll('.sr-only, [class*=\"sr-only\" i], [class*=\"visually-hidden\" i]').forEach((el: any) => {\n const tag = el.tagName?.toLowerCase() ?? '';\n if (!/^h[1-6]$/.test(tag)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 100);\n if (text) addUniq({ meaning: text, role: `${tag}-sr-only`, notes: JSON.stringify({ srOnly: true, tag }) });\n });\n\n // 22. CSS custom property (design token) detection\n // Step 1: enumerate :root / html rules from all same-origin stylesheets\n try {\n const cssTokens: Record<string, string> = {};\n const rootStyle = window.getComputedStyle(document.documentElement);\n // Enumerate from stylesheets (catches ALL custom properties, not just a hardcoded list)\n try {\n for (let si = 0; si < document.styleSheets.length; si++) {\n try {\n const sheet = document.styleSheets[si];\n const rules = sheet.cssRules;\n for (let ri = 0; ri < rules.length; ri++) {\n const rule = rules[ri] as any;\n if (rule.selectorText === ':root' || rule.selectorText === 'html' || rule.selectorText === ':root, html') {\n const style = rule.style;\n for (let pi = 0; pi < style.length; pi++) {\n const prop = style[pi];\n if (prop.startsWith('--') && Object.keys(cssTokens).length < 30) {\n const val = style.getPropertyValue(prop).trim();\n if (val) cssTokens[prop] = val.slice(0, 60);\n }\n }\n }\n }\n } catch { /* cross-origin sheet, skip */ }\n }\n } catch { /* no styleSheets access */ }\n // Step 2: fall back to computed value probe with common framework naming schemes\n // Covers: plain CSS, Tailwind v4, Bootstrap, Material UI, Shadcn/ui, custom brands\n const probePrefixes = ['', '--color-', '--bs-', '--brand-', '--clr-', '--theme-', '--md-sys-color-'];\n const probeNames = ['primary', 'secondary', 'accent', 'background', 'foreground', 'surface', 'text', 'muted', 'border', 'ring', 'card', 'destructive', 'warning', 'success'];\n const probeFonts = ['--font-sans', '--font-mono', '--font-display', '--font-heading', '--font-body', '--font-family-base'];\n for (const pfx of probePrefixes) {\n for (const name of probeNames) {\n const v = `${pfx}${name}`;\n if (!cssTokens[v]) {\n const val = rootStyle.getPropertyValue(v).trim();\n if (val) cssTokens[v] = val.slice(0, 60);\n }\n }\n }\n for (const v of probeFonts) {\n if (!cssTokens[v]) {\n const val = rootStyle.getPropertyValue(v).trim();\n if (val) cssTokens[v] = val.slice(0, 60);\n }\n }\n if (Object.keys(cssTokens).length > 0) {\n const limited = Object.fromEntries(Object.entries(cssTokens).slice(0, 25));\n addUniq({ meaning: `Design tokens: ${Object.keys(limited).join(', ')}`, role: 'design-tokens', notes: JSON.stringify(limited) });\n }\n } catch { /* computed styles not available */ }\n\n // 23. Data tables \u2014 headers + row count (critical for business/admin pages)\n document.querySelectorAll('table').forEach((table: any) => {\n if (!isVisible(table)) return;\n const headers = Array.from(table.querySelectorAll('thead th, thead td, tr:first-child th')).map((th: any) => th.textContent?.trim()).filter(Boolean).slice(0, 8);\n const rowCount = table.querySelectorAll('tbody tr').length;\n if (headers.length > 0) addUniq({ meaning: `Table: ${headers.join(' \u00B7 ')}`, role: 'data-table', notes: JSON.stringify({ headers, rowCount }) });\n });\n\n // 24. Definition lists \u2014 term/description pairs (used for specs, glossaries, FAQs, metadata)\n document.querySelectorAll('dl').forEach((dl: any) => {\n if (!isVisible(dl)) return;\n const terms = Array.from(dl.querySelectorAll('dt')).map((dt: any) => dt.textContent?.trim()).filter(Boolean).slice(0, 10);\n if (terms.length > 0) addUniq({ meaning: `Definition list: ${terms.slice(0, 4).join(', ')}`, role: 'definition-list', notes: JSON.stringify({ terms: terms.slice(0, 10) }) });\n });\n\n // 25. Blockquotes / testimonials / reviews / pull quotes\n let quoteCount = 0;\n document.querySelectorAll('blockquote, [class*=\"testimonial\" i], [class*=\"review\" i]:not(script), [class*=\"quote\" i]:not([class*=\"icon\"]), [class*=\"pullquote\" i]').forEach((el: any) => {\n if (quoteCount >= 10) return;\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 200);\n const author = el.querySelector('[class*=\"author\" i], [class*=\"name\" i], cite')?.textContent?.trim().slice(0, 60) ?? '';\n if (text && text.length > 20) { addUniq({ meaning: `${text.slice(0, 160)}${author ? ' \u2014 ' + author : ''}`, role: 'testimonial', notes: JSON.stringify({ author }) }); quoteCount++; }\n });\n\n // 26. Alert / notice / notification banners (non-interactive, but key content for test assertions)\n document.querySelectorAll('[role=\"alert\"], [role=\"status\"], [role=\"banner\"]:not(header), .alert, .notice, .notification, .warning-banner, .error-banner, .success-banner, [class*=\"alert-\" i]:not(button), [class*=\"toast\" i]:not(button), [class*=\"snackbar\" i]').forEach((el: any) => {\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 150);\n if (text && text.length > 5) addUniq({ meaning: text, role: 'alert-banner', notes: JSON.stringify({ ariaRole: el.getAttribute('role') }) }, el);\n });\n\n // 27. Pricing / plan cards \u2014 structured pricing content\n let pricingCount = 0;\n document.querySelectorAll('[class*=\"pricing\" i], [class*=\"plan\" i]:not(main):not(article), [class*=\"tier\" i]:not(nav), [class*=\"package\" i]:not(script)').forEach((el: any) => {\n if (pricingCount >= 8) return;\n if (!isVisible(el)) return;\n const name = el.querySelector('h2,h3,h4,[class*=\"plan-name\" i],[class*=\"tier-name\" i]')?.textContent?.trim().slice(0, 60) ?? '';\n const price = el.querySelector('[class*=\"price\" i],[class*=\"amount\" i]')?.textContent?.trim().slice(0, 40) ?? '';\n if (name || price) { addUniq({ meaning: `${name || 'Plan'}${price ? ': ' + price : ''}`, role: 'pricing-plan', notes: JSON.stringify({ planName: name, price }) }); pricingCount++; }\n });\n\n // 28. Pagination \u2014 page navigation for multi-page content\n const paginationEl = document.querySelector('[role=\"navigation\"][aria-label*=\"paginat\" i], [class*=\"pagination\" i], [aria-label*=\"paginat\" i]');\n if (paginationEl && isVisible(paginationEl)) {\n const pages = Array.from(paginationEl.querySelectorAll('a, button')).map((p: any) => p.textContent?.trim()).filter(Boolean).slice(0, 10);\n if (pages.length > 0) addUniq({ meaning: `Pagination: ${pages.join(', ')}`, role: 'pagination', notes: JSON.stringify({ pages }) });\n }\n\n // 29. Code blocks / pre blocks \u2014 critical for developer documentation pages\n let codeCount = 0;\n document.querySelectorAll('pre code, [class*=\"code-block\" i], [class*=\"highlight\" i] pre').forEach((el: any) => {\n if (codeCount >= 5) return;\n if (!isVisible(el)) return;\n const lang = el.getAttribute('class')?.match(/language-(\\w+)/)?.[1] ?? '';\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 100);\n if (text && text.length > 10) { addUniq({ meaning: `Code example${lang ? ' (' + lang + ')' : ''}: ${text.slice(0, 80)}`, role: 'code-block', notes: JSON.stringify({ language: lang }) }); codeCount++; }\n });\n\n // 30. Dropdown / select menu items exposed via ARIA listbox/option\n let dropdownCount = 0;\n document.querySelectorAll('[role=\"listbox\"] [role=\"option\"], [role=\"option\"]:not([role=\"listbox\"] *)').forEach((el: any) => {\n if (dropdownCount >= 20) return;\n if (!isVisible(el)) return;\n const text = el.textContent?.trim().slice(0, 80);\n if (text) { addUniq({ meaning: text, role: 'dropdown-option', notes: JSON.stringify({ selected: el.getAttribute('aria-selected') }) }); dropdownCount++; }\n });\n\n // 31. Timeline / process steps (common on landing pages)\n let timelineCount = 0;\n document.querySelectorAll('[class*=\"timeline\" i] li, [class*=\"timeline\" i] [class*=\"step\" i], [class*=\"process\" i] li, [class*=\"steps\" i] li').forEach((el: any) => {\n if (timelineCount >= 10) return;\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 150);\n if (text && text.length > 5) { addUniq({ meaning: text, role: 'timeline-step', notes: JSON.stringify({ source: 'dom-class' }) }); timelineCount++; }\n });\n\n // 32. Team members / person cards \u2014 social proof and about pages\n let teamCount = 0;\n document.querySelectorAll('[class*=\"team-member\" i], [class*=\"team-card\" i], [class*=\"person-card\" i], [class*=\"bio\" i][class*=\"card\" i]').forEach((el: any) => {\n if (teamCount >= 10) return;\n if (!isVisible(el)) return;\n const name = el.querySelector('[class*=\"name\" i], h3, h4')?.textContent?.trim().slice(0, 60) ?? '';\n const role = el.querySelector('[class*=\"role\" i], [class*=\"title\" i], [class*=\"position\" i]')?.textContent?.trim().slice(0, 60) ?? '';\n if (name) { addUniq({ meaning: `${name}${role ? ' \u2014 ' + role : ''}`, role: 'team-member', notes: JSON.stringify({ name, role }) }); teamCount++; }\n });\n\n // 33. Video embeds \u2014 YouTube, Vimeo, Wistia, Loom iframes (src is readable even cross-origin)\n document.querySelectorAll('iframe').forEach((iframe: any) => {\n const src = iframe.getAttribute('src') || iframe.getAttribute('data-src') || '';\n const title = iframe.getAttribute('title') || iframe.getAttribute('aria-label') || '';\n if (!src) return;\n if (/youtube\\.com\\/embed|youtu\\.be\\/|youtube-nocookie\\.com/i.test(src)) {\n const videoId = src.match(/\\/embed\\/([^/?&]+)/)?.[1] ?? '';\n addUniq({ meaning: title || `YouTube video${videoId ? ' (ID: ' + videoId + ')' : ''}`, role: 'video-embed', notes: JSON.stringify({ platform: 'youtube', src: src.slice(0, 200), title, videoId }) });\n } else if (/vimeo\\.com\\/video\\//i.test(src)) {\n const videoId = src.match(/video\\/(\\d+)/)?.[1] ?? '';\n addUniq({ meaning: title || `Vimeo video${videoId ? ' (ID: ' + videoId + ')' : ''}`, role: 'video-embed', notes: JSON.stringify({ platform: 'vimeo', src: src.slice(0, 200), title, videoId }) });\n } else if (/wistia\\.com|loom\\.com|dailymotion\\.com|twitch\\.tv|brightcove\\.com/i.test(src)) {\n const platform = /wistia/.test(src) ? 'wistia' : /loom/.test(src) ? 'loom' : /dailymotion/.test(src) ? 'dailymotion' : /twitch/.test(src) ? 'twitch' : 'brightcove';\n addUniq({ meaning: title || `${platform} video`, role: 'video-embed', notes: JSON.stringify({ platform, src: src.slice(0, 200), title }) });\n } else if (/maps\\.google\\.com|google\\.com\\/maps\\/embed/i.test(src)) {\n const q = new URLSearchParams(src.split('?')[1] ?? '').get('q') ?? new URLSearchParams(src.split('?')[1] ?? '').get('query') ?? '';\n addUniq({ meaning: title || `Google Maps${q ? ': ' + decodeURIComponent(q).slice(0, 80) : ''}`, role: 'map-embed', notes: JSON.stringify({ provider: 'google', src: src.slice(0, 200), query: q }) });\n } else if (/openstreetmap\\.org|mapbox\\.com|here\\.com|maps\\.apple\\.com/i.test(src)) {\n const provider = /openstreetmap/.test(src) ? 'OpenStreetMap' : /mapbox/.test(src) ? 'Mapbox' : /here\\.com/.test(src) ? 'HERE Maps' : 'Apple Maps';\n addUniq({ meaning: title || `${provider} embed`, role: 'map-embed', notes: JSON.stringify({ provider, src: src.slice(0, 200), title }) });\n }\n });\n\n // 34. SVG content \u2014 only meaningful SVGs (have title/aria-label AND are large enough to be illustrations)\n document.querySelectorAll('svg').forEach((svg: any) => {\n if (!isVisible(svg)) return;\n const titleEl = svg.querySelector('title');\n const label = svg.getAttribute('aria-label')?.trim() || titleEl?.textContent?.trim() || '';\n if (!label) return;\n const rect = svg.getBoundingClientRect();\n if (rect.width < 48 && rect.height < 48) return; // Skip icon-size SVGs\n addUniq({ meaning: label.slice(0, 100), role: 'svg-image', notes: JSON.stringify({ width: Math.round(rect.width), height: Math.round(rect.height) }) });\n });\n\n // 35. Animated counters \u2014 read data-target/data-count BEFORE animation completes\n let counterCount = 0;\n document.querySelectorAll('[data-count],[data-target],[data-to],[data-countup],[class*=\"counter\" i]:not(button),[class*=\"count-up\" i],[class*=\"odometer\" i]').forEach((el: any) => {\n if (counterCount >= 15) return;\n if (!isVisible(el)) return;\n const targetVal = el.getAttribute('data-count') || el.getAttribute('data-target') || el.getAttribute('data-to') || el.getAttribute('data-countup') || '';\n const currentText = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 40) ?? '';\n const contextLabel = el.closest('[class*=\"stat\" i],[class*=\"metric\" i],[class*=\"kpi\" i],[class*=\"counter-item\" i]')?.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 80) ?? '';\n const value = targetVal || currentText;\n if (value && value !== '0') {\n addUniq({ meaning: contextLabel.slice(0, 100) || `Counter: ${value}`, role: 'animated-counter', notes: JSON.stringify({ targetValue: targetVal, displayedValue: currentText }) });\n counterCount++;\n }\n });\n\n // 36. Client / partner logos \u2014 distinguish from generic images\n let logoCount = 0;\n document.querySelectorAll('[class*=\"client\" i] img,[class*=\"partner\" i] img,[class*=\"logo-grid\" i] img,[class*=\"clients-\" i] img,[class*=\"brand-logo\" i] img,[class*=\"trust-logo\" i] img,[class*=\"sponsor\" i] img').forEach((img: any) => {\n if (logoCount >= 20) return;\n if (!isVisible(img)) return;\n const alt = img.getAttribute('alt')?.trim().slice(0, 60) ?? '';\n const src = (img.getAttribute('src') || img.getAttribute('data-src') || '').slice(0, 120);\n if (!alt && !src) return;\n addUniq({ meaning: alt || src.split('/').pop()?.split('?')[0]?.slice(0, 50) || 'Client logo', role: 'client-logo', notes: JSON.stringify({ alt, src, hasAlt: !!alt }) });\n logoCount++;\n });\n\n // 37. Awards / certifications / trust badges\n let awardCount = 0;\n document.querySelectorAll('[class*=\"award\" i],[class*=\"certif\" i]:not(script):not(link),[class*=\"accredit\" i],[class*=\"trust-badge\" i],[class*=\"recognition\" i],[class*=\"badge\" i][class*=\"award\" i]').forEach((el: any) => {\n if (awardCount >= 10) return;\n if (!isVisible(el)) return;\n const text = el.textContent?.replace(/\\s+/g, ' ').trim().slice(0, 80);\n const imgEl = el.querySelector('img');\n const label = text || imgEl?.getAttribute('alt')?.trim() || '';\n if (label && label.length > 2) { addUniq({ meaning: label, role: 'award-badge', notes: JSON.stringify({ hasImage: !!imgEl }) }); awardCount++; }\n });\n\n // 38. A/B testing detection \u2014 captures active experiments (not variant content)\n try {\n const abTools: string[] = [];\n if ((window as any).optimizely || (window as any).Optimizely) abTools.push('Optimizely');\n if ((window as any).VWO || (window as any)._vwo_code) abTools.push('VWO');\n if ((window as any).__ABTasty || (window as any).ABTasty) abTools.push('AB Tasty');\n if (document.querySelector('script[src*=\"optimize.js\"]')) abTools.push('Google Optimize');\n if ((window as any).splitbee) abTools.push('Splitbee');\n if ((window as any).__GROWTHBOOK__ || document.querySelector('script[src*=\"growthbook\"]')) abTools.push('GrowthBook');\n if ((window as any).Kameleoon) abTools.push('Kameleoon');\n if (abTools.length > 0) {\n const optExp = (window as any).optimizely?.get?.('state')?.getActiveExperimentIds?.() ?? [];\n addUniq({ meaning: `A/B testing: ${abTools.join(', ')}${optExp.length ? ' (' + optExp.length + ' active experiments)' : ''}`, role: 'ab-test-layer', notes: JSON.stringify({ tools: abTools, activeExperiments: optExp.slice(0, 10) }) });\n }\n } catch { /* best-effort */ }\n\n // 39. Geo / personalization detection\n try {\n const signals: string[] = [];\n if ((window as any).__geo || (window as any).__country || (window as any).__region) signals.push('window geo globals');\n if (document.querySelector('[data-geo],[data-country],[data-region],[data-locale]')) signals.push('data-geo DOM attributes');\n const ipScripts = Array.from(document.querySelectorAll('script[src]')).filter((s: any) => /ipinfo|maxmind|ipstack|ipgeolocation/i.test(s.getAttribute('src') ?? '')).length;\n if (ipScripts > 0) signals.push('IP geolocation script');\n if ((window as any).Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone) signals.push(`timezone: ${(window as any).Intl.DateTimeFormat().resolvedOptions().timeZone}`);\n if (signals.length > 1) {\n addUniq({ meaning: `Personalization/geo signals: ${signals.join('; ')}`, role: 'personalization-layer', notes: JSON.stringify({ signals }) });\n }\n } catch { /* best-effort */ }\n\n // 40. Hover-revealed content \u2014 read DOM text of CSS-hidden children on hover triggers\n let hoverCount = 0;\n document.querySelectorAll('[class*=\"group\"]:not(nav):not(ul):not(ol),[class*=\"hover-trigger\" i],[data-hover],[class*=\"has-dropdown\" i]').forEach((trigger: any) => {\n if (hoverCount >= 8) return;\n if (!isVisible(trigger)) return;\n const hiddenChildren = Array.from(trigger.querySelectorAll('[class*=\"group-hover\"],[class*=\"hover-content\" i],[class*=\"dropdown-menu\" i],[class*=\"submenu\" i]')).filter((c: any) => {\n try { const s = window.getComputedStyle(c); return s.display === 'none' || s.visibility === 'hidden' || parseFloat(s.opacity) < 0.1; } catch { return false; }\n });\n for (const child of hiddenChildren.slice(0, 3)) {\n const text = (child as any).textContent?.replace(/\\s+/g, ' ').trim().slice(0, 150);\n if (text && text.length > 3) {\n addUniq({ meaning: text, role: 'hover-content', notes: JSON.stringify({ triggerClass: (trigger.className?.toString() ?? '').slice(0, 60) }) });\n hoverCount++;\n }\n }\n });\n\n return out.slice(0, 400); // Per-category caps above; raised global cap to 400 for new categories\n }).then((elems: any[]) => elems.map((e: any) => ({ ...e, isInteractive: false }))).catch(() => []);\n}\n\n/**\n * Click through tabs, advance carousels, open accordions \u2014 collect links that only appear\n * inside those interactive panels. Does not navigate away from the current page.\n */\nasync function interactAndCollectLinks(page: any, origin: string): Promise<string[]> {\n const collected = new Set<string>();\n const sleep = (ms: number) => new Promise<void>(r => setTimeout(r, ms));\n\n const collectCurrentLinks = async () => {\n const links: string[] = await page.evaluate((origin: string) => {\n const out: string[] = [];\n const logout = /logout|log out|sign out|delete/i;\n document.querySelectorAll<HTMLAnchorElement>('a[href]').forEach(a => {\n if (logout.test(a.textContent ?? '')) return;\n try {\n const u = new URL(a.href);\n if (u.origin === origin) { if (u.hash && !/^#!?\\//.test(u.hash)) u.hash = ''; out.push(u.toString()); }\n } catch { /* ignore */ }\n });\n return out;\n }, origin).catch(() => []);\n links.forEach(l => collected.add(l));\n };\n\n try {\n // \u2500\u2500 Tabs: click each tab individually, collect links from revealed panel \u2500\u2500\n const tabCount: number = await page.evaluate(() =>\n document.querySelectorAll('[role=\"tab\"]').length\n ).catch(() => 0);\n\n for (let i = 0; i < Math.min(tabCount, 30); i++) {\n try {\n const clicked = await page.evaluate((idx: number) => {\n const tabs = document.querySelectorAll<HTMLElement>('[role=\"tab\"]');\n const tab = tabs[idx];\n if (!tab) return false;\n const s = window.getComputedStyle(tab);\n const r = tab.getBoundingClientRect();\n if (s.display === 'none' || r.width < 4 || r.height < 4) return false;\n tab.click();\n return true;\n }, i).catch(() => false);\n if (clicked) {\n await sleep(350);\n await collectCurrentLinks();\n }\n } catch { /* skip */ }\n }\n\n // \u2500\u2500 Carousels: advance next button up to 8 times, collect links each slide \u2500\u2500\n const carouselNextSel = [\n 'button[aria-label*=\"next\" i]', 'button[aria-label*=\"forward\" i]',\n 'button[aria-label*=\"right\" i]', '[data-direction=\"next\"]',\n '[class*=\"carousel\" i] button[class*=\"next\" i]',\n '[class*=\"slider\" i] button[class*=\"next\" i]',\n ].join(', ');\n\n for (let i = 0; i < 8; i++) {\n const advanced: boolean = await page.evaluate((sel: string) => {\n const btn = document.querySelector<HTMLElement>(sel);\n if (!btn) return false;\n const s = window.getComputedStyle(btn);\n const r = btn.getBoundingClientRect();\n if (s.display === 'none' || r.width < 4 || r.height < 4) return false;\n btn.click();\n return true;\n }, carouselNextSel).catch(() => false);\n if (!advanced) break;\n await sleep(300);\n await collectCurrentLinks();\n }\n\n // \u2500\u2500 Accordions / disclosure panels: open collapsed sections \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const accordionCount: number = await page.evaluate(() =>\n document.querySelectorAll('details:not([open]) > summary, [data-state=\"closed\"] > button, [aria-expanded=\"false\"][class*=\"accordion\" i]').length\n ).catch(() => 0);\n\n for (let i = 0; i < Math.min(accordionCount, 20); i++) {\n try {\n await page.evaluate((idx: number) => {\n const items = document.querySelectorAll<HTMLElement>(\n 'details:not([open]) > summary, [data-state=\"closed\"] > button, [aria-expanded=\"false\"][class*=\"accordion\" i]'\n );\n const el = items[idx];\n if (el) { try { el.click(); } catch { /* ignore */ } }\n }, i).catch(() => { });\n await sleep(250);\n await collectCurrentLinks();\n } catch { /* skip */ }\n }\n } catch { /* best-effort */ }\n\n return Array.from(collected);\n}\n\n/** Click collapsed nav triggers (hamburger menus, aria-haspopup buttons, Radix/Headless UI toggles)\n * to reveal routes that only exist in the DOM after user interaction.\n * Returns true if anything was clicked so caller can dismiss afterward. */\nasync function expandNavMenus(page: any): Promise<boolean> {\n try {\n const clicked = await page.evaluate(() => {\n const isVisible = (el: HTMLElement) => {\n const s = window.getComputedStyle(el);\n if (s.display === 'none' || s.visibility === 'hidden' || parseFloat(s.opacity) < 0.1) return false;\n const r = el.getBoundingClientRect();\n return r.width > 4 && r.height > 4;\n };\n const inBadContext = (el: HTMLElement) => {\n let p = el.parentElement;\n while (p) {\n const tag = p.tagName?.toLowerCase();\n const role = p.getAttribute('role') ?? '';\n if (['table', 'select'].includes(tag ?? '') ||\n ['dialog', 'alertdialog', 'combobox', 'listbox', 'grid', 'treegrid'].includes(role)) return true;\n p = p.parentElement;\n }\n return false;\n };\n const targets = new Set<HTMLElement>();\n // aria-haspopup: canonical menu-trigger pattern\n document.querySelectorAll<HTMLElement>('[aria-haspopup]:not([aria-expanded=\"true\"])').forEach(el => {\n if (isVisible(el) && !inBadContext(el)) targets.add(el);\n });\n // aria-expanded=false: collapsed nav sections\n document.querySelectorAll<HTMLElement>('[aria-expanded=\"false\"]').forEach(el => {\n if ((el.tagName === 'BUTTON' || el.getAttribute('role') === 'button') && isVisible(el) && !inBadContext(el)) targets.add(el);\n });\n // Radix UI / Headless UI closed triggers\n document.querySelectorAll<HTMLElement>('[data-state=\"closed\"],[data-headlessui-state=\"closed\"]').forEach(el => {\n if ((el.tagName === 'BUTTON' || el.getAttribute('role') === 'button') && isVisible(el) && !inBadContext(el)) targets.add(el);\n });\n let count = 0;\n targets.forEach(el => { try { (el as HTMLElement).click(); count++; } catch { /* ignore */ } });\n return count;\n });\n if (clicked > 0) await new Promise(r => setTimeout(r, 500));\n\n // \u2500\u2500 Hover sweep: reveal CSS :hover dropdown menus \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Pure CSS hover menus need real mouse moves \u2014 JS click alone won't trigger :hover\n try {\n const navHandles = await page.$$(\n 'nav > ul > li, nav > li, header > ul > li, header > nav > ul > li, ' +\n '[role=\"navigation\"] > ul > li, [role=\"menubar\"] > [role=\"menuitem\"], ' +\n '[class*=\"nav\"] > ul > li, [class*=\"menu\"] > li'\n ).catch(() => [] as any[]);\n for (const h of (navHandles as any[]).slice(0, 40)) {\n try { await h.hover({ force: true, timeout: 600 }); await page.waitForTimeout(280); } catch { /* skip invisible */ }\n }\n if ((navHandles as any[]).length > 0) {\n await page.mouse.move(2, 2); // dismiss hover state\n await page.waitForTimeout(150);\n }\n } catch { /* non-fatal */ }\n\n return (clicked as number) > 0;\n } catch { return false; }\n}\n\nasync function domFallbackLinks(page: any, origin: string, rawPage?: any): Promise<DiscoveredLinkMeta[]> {\n // Named function so .toString() gives the raw function body for CDP evaluation.\n // esbuild wraps nested named arrow-function constants with __name() \u2014 prepend a\n // tiny polyfill so the browser has it when we serialize this function as a string.\n // IMPORTANT: _linkEval is serialized to a string via .toString() and evaluated in the\n // browser via CDP. It CANNOT contain TypeScript types or Node.js imports.\n function _linkEval(originStr: string) {\n const logout = /logout|log out|sign out|delete/i;\n const isRouteHash = (hash: string) => /^#!?\\//.test(hash);\n const seen = new Map();\n const add = (rawHref: string, textContent: string) => {\n if (logout.test(textContent)) return;\n if (!rawHref) return;\n if (rawHref.startsWith('#') && !isRouteHash(rawHref)) return;\n if (rawHref.startsWith('mailto:') || rawHref.startsWith('javascript:')) return;\n try {\n const u = new URL(rawHref, location.href);\n if (!isRouteHash(u.hash)) u.hash = '';\n if (new URL(u).origin === originStr) seen.set(u.toString(), (textContent || '').trim().slice(0, 120));\n } catch { /* ignore */ }\n };\n const allRoots: Array<Document | ShadowRoot> = [document];\n const rootSeen = new WeakSet<Document | ShadowRoot>();\n rootSeen.add(document);\n while (allRoots.length > 0) {\n const root = allRoots.shift();\n if (!root) continue;\n try {\n root.querySelectorAll('a[href]').forEach((a) => add((a as HTMLAnchorElement).href || a.getAttribute('href') || '', a.textContent || ''));\n root.querySelectorAll('[href]:not(a):not(link):not(base):not(script)').forEach((el) => {\n add(el.getAttribute('href') || '', el.textContent || '');\n });\n root.querySelectorAll('[data-href]').forEach((el) => {\n add(el.getAttribute('data-href') || '', el.textContent || '');\n });\n // Form[action] GET forms: JSP/MVC apps navigate via form submissions (not anchor links)\n root.querySelectorAll('form[action]').forEach((form) => {\n const method = (form.getAttribute('method') || 'get').toLowerCase();\n if (method !== 'post') add(form.getAttribute('action') || '', form.getAttribute('aria-label') || '');\n });\n root.querySelectorAll('*').forEach((el) => {\n try {\n if (el.shadowRoot && !rootSeen.has(el.shadowRoot)) {\n rootSeen.add(el.shadowRoot);\n allRoots.push(el.shadowRoot);\n }\n } catch (_) { /* closed/cross-origin shadow root */ }\n });\n } catch (_) { /* element threw \u2014 skip root */ }\n }\n return Array.from(seen.entries()).map(([url, text]) => ({ url, text }));\n }\n\n function inferLandmark(url: string): string | undefined {\n const p = url.toLowerCase();\n if (p.includes('/auth') || p.includes('/login') || p.includes('/register')) return 'nav';\n return undefined;\n }\n\n function toMeta(raw: Array<{ url: string; text: string }>): DiscoveredLinkMeta[] {\n return raw.map(({ url, text }) => ({\n url,\n text: text || undefined,\n landmark: inferLandmark(url),\n source: 'DOM' as const,\n }));\n }\n\n const _linkEvalStr = `(function(){const __name=(fn,n)=>{try{Object.defineProperty(fn,'name',{value:n,configurable:true})}catch(e){}return fn};return(${_linkEval.toString()})(${JSON.stringify(origin)})})();`;\n\n // CDP primary \u2014 bypasses Stagehand isolated world entirely\n if (rawPage && typeof rawPage.context === 'function') {\n try {\n const ctx = rawPage.context();\n if (typeof ctx?.newCDPSession === 'function') {\n const cdp = await ctx.newCDPSession(rawPage);\n try {\n const evalResult = await cdp.send('Runtime.evaluate', {\n expression: _linkEvalStr,\n returnByValue: true,\n awaitPromise: false,\n });\n if (!evalResult?.exceptionDetails && Array.isArray(evalResult?.result?.value)) {\n return toMeta(evalResult.result.value as Array<{ url: string; text: string }>);\n }\n if (evalResult?.exceptionDetails) {\n console.warn('[crawler] domFallbackLinks CDP error:', evalResult.exceptionDetails?.exception?.description ?? evalResult.exceptionDetails?.text);\n }\n } finally {\n cdp.detach().catch(() => {});\n }\n }\n } catch (cdpErr: any) {\n console.warn('[crawler] domFallbackLinks CDP failed:', cdpErr?.message ?? String(cdpErr));\n }\n }\n\n // Fallback: pass string expression so esbuild __name wrapper never reaches browser\n const evalPage = rawPage ?? page;\n return (evalPage.evaluate(_linkEvalStr as any) as Promise<Array<{ url: string; text: string }>>).then(toMeta).catch((err: any) => {\n console.warn('[crawler] domFallbackLinks page.evaluate threw:', err?.message ?? String(err));\n return [];\n });\n}\n\n/** Extract label\u2192href pairs for all in-app anchor links \u2014 used to seed KAG element transitions. */\nasync function extractLinkMappings(page: any, origin: string): Promise<Array<{ label: string; href: string }>> {\n return page.evaluate((origin: string) => {\n const logout = /logout|log out|sign out|delete/i;\n return Array.from(document.querySelectorAll('a[href]'))\n .filter((a: any) => !logout.test(a.textContent ?? ''))\n .map((a: any) => {\n const label = (\n a.getAttribute('aria-label') ||\n a.textContent?.replace(/\\s+/g, ' ').trim() ||\n a.getAttribute('title') ||\n ''\n ).slice(0, 80);\n const href = (() => { try { const u = new URL(a.href); if (!/^#!?\\//.test(u.hash)) u.hash = ''; return u.toString(); } catch { return ''; } })();\n return { label, href };\n })\n .filter(({ label, href }: { label: string; href: string }) =>\n label.length > 2 && href.length > 0 &&\n (() => { try { return new URL(href).origin === origin; } catch { return false; } })()\n );\n }, origin).catch(() => []);\n}\n\n/** \n * Computes a structural hash of the DOM to detect repeating screens/components.\n * Strips out text and focuses only on the sequence of semantic/form tags.\n */\nasync function computeDomHash(page: any): Promise<string> {\n return page.evaluate(() => {\n let hashStr = '';\n const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);\n let node;\n while ((node = walker.nextNode())) {\n const el = node as HTMLElement;\n // Only include structural/semantic tags that matter for UI layouts\n if (/^(MAIN|SECTION|NAV|FORM|INPUT|SELECT|TEXTAREA|BUTTON|TABLE|TR|TD|TH|UL|LI|A|H1|H2|H3)$/.test(el.tagName)) {\n // Count structural nesting depth \u2014 distinguishes modal dialogs (deeply nested)\n // from top-level nav/forms (shallow), preventing false duplicate matches.\n let depth = 0;\n let parent = el.parentElement;\n while (parent) {\n if (/^(MAIN|SECTION|NAV|FORM|INPUT|SELECT|TEXTAREA|BUTTON|TABLE|TR|TD|TH|UL|LI|A|H1|H2|H3)$/.test(parent.tagName)) depth++;\n parent = parent.parentElement;\n }\n hashStr += el.tagName + depth + '|';\n }\n }\n // Very simple hashing function (djb2 style)\n let hash = 5381;\n for (let i = 0; i < hashStr.length; i++) {\n hash = (hash * 33) ^ hashStr.charCodeAt(i);\n }\n return (hash >>> 0).toString(16);\n }).catch(() => '');\n}\n\nasync function waitForURLChange(page: any, fromUrl: string, timeout = 10_000): Promise<void> {\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const current = page.url();\n try {\n const from = new URL(fromUrl);\n const now = new URL(current);\n if (now.pathname !== from.pathname || now.origin !== from.origin) return;\n } catch {\n if (current !== fromUrl) return;\n }\n await new Promise(r => setTimeout(r, 200));\n }\n // Timed out \u2014 proceed with current URL (may still be login page)\n}\n\n/**\n * Dismiss common overlay patterns (cookie banners, GDPR consent, chat widgets, newsletter modals)\n * before element extraction \u2014 prevents banner elements from polluting the element model.\n */\nasync function dismissOverlays(page: any): Promise<void> {\n const selectors = [\n // OneTrust / CookieBot / TrustArc (most common GDPR banners)\n '#onetrust-accept-btn-handler',\n '#accept-cookie-consent',\n '.cc-btn.cc-allow',\n '[data-cookiebanner] button',\n '[id*=\"cookie-accept\"]',\n '[class*=\"cookie-accept\"]',\n '[id*=\"cookieAccept\"]',\n '[class*=\"cookieAccept\"]',\n 'button[aria-label*=\"Accept cookies\" i]',\n 'button[aria-label*=\"Accept all\" i]',\n 'button[title*=\"Accept\" i][class*=\"cookie\" i]',\n // Intercom / Drift / HubSpot chat\n '[class*=\"intercom-close\"]',\n '#hubspot-messages-iframe-container [aria-label*=\"close\" i]',\n // Generic overlay close buttons\n '[role=\"dialog\"] button[aria-label=\"Close\" i]',\n '[role=\"dialog\"] button[aria-label=\"Dismiss\" i]',\n // Newsletter popups\n 'button[class*=\"modal-close\"]',\n 'button[class*=\"popup-close\"]',\n '[class*=\"newsletter\"] button[class*=\"close\"]',\n ];\n for (const sel of selectors) {\n try {\n const el = page.locator(sel).first();\n if (await el.isVisible({ timeout: 300 }).catch(() => false)) {\n await el.click({ timeout: 500, force: true }).catch(() => { });\n }\n } catch { /* overlay not present \u2014 skip */ }\n }\n // Brief settle after dismissals \u2014 Node.js timer, no dependency on page.waitForTimeout proxy\n await new Promise<void>(r => setTimeout(r, 300));\n}\n\n/**\n * Scroll the full page height to trigger IntersectionObserver-based lazy loads\n * (images, components, infinite-scroll content). Scrolls back to top before capture.\n */\nasync function scrollToTriggerLazyLoad(page: any, rawPage?: any): Promise<void> {\n const evalPage = rawPage ?? page;\n try {\n // Scroll the full page in viewport-sized steps.\n // window.scrollTo handles standard scroll containers and triggers IntersectionObserver.\n const { scrollHeight, innerHeight, innerWidth } = await evalPage.evaluate(() => ({\n scrollHeight: Math.min(document.body.scrollHeight, 12_000),\n innerHeight: window.innerHeight || 800,\n innerWidth: window.innerWidth || 1280,\n })).catch(() => ({ scrollHeight: 0, innerHeight: 800, innerWidth: 1280 }));\n\n if (scrollHeight > innerHeight) {\n // CDP wheel events trigger virtual scrollers (react-window / TanStack Virtual / AG Grid)\n // which ignore window.scrollTo but listen on their own container via wheel events.\n let cdp: any = null;\n if (rawPage && typeof rawPage.context === 'function') {\n try {\n const ctx = rawPage.context();\n if (typeof ctx?.newCDPSession === 'function') cdp = await ctx.newCDPSession(rawPage);\n } catch { cdp = null; }\n }\n\n const step = Math.max(innerHeight, 400);\n for (let y = step; y < scrollHeight; y += step) {\n await evalPage.evaluate((pos: number) => window.scrollTo(0, pos), y).catch(() => {});\n if (cdp) {\n await cdp.send('Input.dispatchMouseEvent', {\n type: 'mouseWheel',\n x: Math.floor(innerWidth / 2),\n y: Math.floor(innerHeight / 2),\n deltaX: 0,\n deltaY: step,\n modifiers: 0,\n }).catch(() => {});\n }\n // Node.js-side wait \u2014 does NOT depend on page.waitForTimeout (Stagehand proxy may lack it)\n await new Promise<void>(r => setTimeout(r, 150));\n }\n // Scroll back to top\n await evalPage.evaluate(() => window.scrollTo(0, 0)).catch(() => {});\n if (cdp) cdp.detach().catch(() => {});\n }\n\n // Let lazy-triggered content render before extraction\n await new Promise<void>(r => setTimeout(r, 400));\n // Wait for networkidle: IntersectionObserver fires on scroll but async data fetches\n // (React Query, SWR, Apollo) triggered by it may still be in-flight. networkidle ensures\n // all XHR/fetch requests spawned by the scroll complete before DOM stability check.\n const scrollWaitPage = rawPage ?? page;\n if (typeof scrollWaitPage.waitForLoadState === 'function') {\n await scrollWaitPage.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => {});\n }\n // Re-check DOM stability (shadow-piercing) after scroll-triggered mutations + data fetches\n await waitForStableDOM(page, 4_000, 500, rawPage);\n } catch { /* scroll failed \u2014 non-fatal, proceed */ }\n}\n\nasync function waitForStableDOM(page: any, maxWait = 8_000, stabilityMs = 400, rawPage?: any): Promise<void> {\n const evalPage = rawPage ?? page; // prefer rawPage \u2014 avoids Stagehand proxy + __name isolated-world issues\n const deadline = Date.now() + maxWait;\n let lastCount = -1;\n let stableAt = 0;\n let evalErrors = 0;\n while (Date.now() < deadline) {\n const count: number = await evalPage.evaluate(() => {\n // Shadow-piercing counter: querySelectorAll('*') only counts light-DOM elements;\n // shadow roots are separate trees. Counting both ensures changes inside web components\n // (e.g. Material UI, Lit, Shoelace) reset the stability timer correctly.\n let c = 0;\n const visit = (root: Document | ShadowRoot) => {\n const els = root.querySelectorAll('*');\n c += els.length;\n els.forEach((el: any) => { if (el.shadowRoot) visit(el.shadowRoot); });\n };\n visit(document);\n return c;\n }).catch(() => -1);\n if (count === -1) {\n // evaluate failed (isolated world broken) \u2014 after 3 consecutive failures, wait stabilityMs and bail\n if (++evalErrors >= 3) {\n await new Promise(r => setTimeout(r, stabilityMs));\n return;\n }\n } else {\n evalErrors = 0;\n if (count !== lastCount) {\n lastCount = count;\n stableAt = Date.now();\n } else if (Date.now() - stableAt >= stabilityMs) {\n return;\n }\n }\n await new Promise(r => setTimeout(r, 100));\n }\n // Timed out \u2014 DOM may still be loading, proceed anyway\n}\n\nasync function waitForScreenshotReady(page: any, rawPage?: any): Promise<void> {\n const hardDeadline = Date.now() + 30_000;\n const withHardCap = <T>(p: Promise<T>): Promise<T | void> =>\n Promise.race([p, new Promise<void>((resolve) => setTimeout(resolve, Math.max(0, hardDeadline - Date.now())))]);\n // Use rawPage for load-state waits \u2014 Stagehand proxy may not expose waitForLoadState\n const waitPage = rawPage ?? page;\n const evalPage = rawPage ?? page;\n try {\n await withHardCap(waitPage.waitForLoadState('domcontentloaded', { timeout: 5_000 }).catch(() => { }));\n await withHardCap(waitPage.waitForLoadState('networkidle', { timeout: 12_000 }).catch(() => { }));\n await withHardCap(evalPage.evaluate(() => {\n if (document.readyState === 'complete') return true;\n return new Promise<boolean>((resolve) => {\n const done = () => resolve(true);\n window.addEventListener('load', done, { once: true });\n setTimeout(done, 4_000);\n });\n }).catch(() => { }));\n await withHardCap(evalPage.evaluate(async () => {\n const fonts = (document as any).fonts;\n if (fonts?.ready) await fonts.ready;\n }).catch(() => { }));\n await withHardCap(scrollToTriggerLazyLoad(rawPage ?? page, rawPage));\n await withHardCap(waitForStableDOM(page, 4_000, 700, rawPage));\n await withHardCap(evalPage.evaluate(async () => {\n const pending = Array.from(document.images).filter((img) => !img.complete);\n if (pending.length === 0) return;\n await Promise.race([\n Promise.all(pending.map((img) => new Promise<void>((resolve) => {\n img.addEventListener('load', () => resolve(), { once: true });\n img.addEventListener('error', () => resolve(), { once: true });\n }))),\n new Promise<void>((resolve) => setTimeout(resolve, 4_000)),\n ]);\n }).catch(() => { }));\n await withHardCap(waitForStableDOM(page, 2_000, 500, rawPage));\n } catch { /* readiness is best-effort; never fail the crawl for a continuously mutating page */ }\n}\n\nasync function hasMeaningfulAuthOrPublicState(page: any, requestedUrl: string): Promise<boolean> {\n const pathLooksRelevant = (() => {\n try {\n const pathname = new URL(page.url?.() ?? requestedUrl).pathname;\n return AUTH_PATH_RE.test(pathname) || PUBLIC_PATH_RE.test(pathname);\n } catch {\n return false;\n }\n })();\n\n const domState = await page.evaluate(() => {\n const text = (document.body?.innerText ?? '').toLowerCase();\n const inputs = Array.from(document.querySelectorAll('input')) as HTMLInputElement[];\n const hasPassword = inputs.some((i) => i.type === 'password');\n const hasIdentityInput = inputs.some((i) => {\n const meta = `${i.type} ${i.name} ${i.id} ${i.placeholder} ${i.autocomplete}`.toLowerCase();\n return /(email|username|user|login|phone|otp|code|password)/.test(meta);\n });\n const hasAuthCopy = /(sign in|log in|login|sign up|create account|register|forgot password|reset password|verify email|one-time|otp|continue with email)/i.test(text);\n const hasPublicNav = /(pricing|contact|features|documentation|docs|about|privacy|terms)/i.test(text);\n // Soft-404: page says \"not found\" / \"404\" with no real auth form\n const isSoft404 = !hasPassword && !hasIdentityInput &&\n /(page not found|404|this page (could not|doesn'?t) (be found|exist)|we couldn'?t find|no longer exists|been moved|doesn'?t exist)/i.test(text);\n return { hasPassword, hasIdentityInput, hasAuthCopy, hasPublicNav, isSoft404 };\n }).catch(() => ({ hasPassword: false, hasIdentityInput: false, hasAuthCopy: false, hasPublicNav: false, isSoft404: false }));\n\n // Soft-404 with no auth form \u2014 path match alone is not enough\n if (domState.isSoft404) return false;\n\n const domLooksRelevant = domState.hasPassword || domState.hasIdentityInput || domState.hasAuthCopy || domState.hasPublicNav;\n return pathLooksRelevant || domLooksRelevant;\n}\n\nasync function discoverAuthCandidates(page: any, origin: string): Promise<{\n links: Array<{ href: string; label: string; flowType: AuthFlowType }>;\n clicks: Array<{ selector: string; label: string; flowType: AuthFlowType }>;\n}> {\n return page.evaluate((siteOrigin: string) => {\n type BrowserFlowType = 'public' | 'login' | 'register' | 'password_reset' | 'verification' | 'invite' | 'session_recovery';\n const authTextRe = /(sign\\s*in|log\\s*in|login|sign\\s*up|signup|register|create account|forgot password|reset password|use email|continue with email|back to login|verify|invite|get started|start free trial)/i;\n const skipTextRe = /(logout|log out|sign out|delete|remove|discard|cancel subscription|payment|billing)/i;\n const authPathRe = /\\/(login|log-in|signin|sign-in|auth|oauth|sso|account\\/login|user\\/login|app\\/login|register|signup|sign-up|create-account|forgot|reset|password|verify-email|invite)(\\/|$|\\?)/i;\n const publicPathRe = /\\/($|pricing|contact|about|help|docs|features|security|privacy|terms)(\\/|$|\\?)/i;\n const sameSiteBrowser = (href: string) => {\n try {\n const u = new URL(href, location.href);\n const s = new URL(siteOrigin);\n const strip = (h: string) => h.replace(/^www\\./i, '');\n return strip(u.hostname) === strip(s.hostname);\n } catch {\n return false;\n }\n };\n const flowTypeFor = (value: string): BrowserFlowType => {\n const v = value.toLowerCase();\n if (/(forgot|reset|password)/.test(v)) return 'password_reset';\n if (/(register|signup|sign up|create account|join)/.test(v)) return 'register';\n if (/(verify|verification|otp|mfa|2fa|invite)/.test(v)) return v.includes('invite') ? 'invite' : 'verification';\n if (/(session-expired|expired|unauthorized|forbidden|401|403|logout|logged-out)/.test(v)) return 'session_recovery';\n if (/(login|log in|signin|sign in|auth|sso|oauth)/.test(v)) return 'login';\n return 'public';\n };\n const textOf = (el: Element) => (\n el.textContent ||\n el.getAttribute('aria-label') ||\n el.getAttribute('title') ||\n el.getAttribute('placeholder') ||\n ''\n ).replace(/\\s+/g, ' ').trim();\n const isVisible = (el: Element) => {\n const rect = (el as HTMLElement).getBoundingClientRect?.();\n const style = window.getComputedStyle(el as HTMLElement);\n return !!rect && rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';\n };\n const links = new Map<string, { href: string; label: string; flowType: BrowserFlowType }>();\n const addHref = (hrefRaw: string | null, labelRaw: string) => {\n if (!hrefRaw || /^(javascript|mailto|tel):/i.test(hrefRaw)) return;\n let href = '';\n try { href = new URL(hrefRaw, location.href).toString(); } catch { return; }\n if (!sameSiteBrowser(href)) return;\n const u = new URL(href);\n const label = labelRaw || u.pathname;\n if (skipTextRe.test(label) || skipTextRe.test(u.pathname)) return;\n if (!authTextRe.test(label) && !authPathRe.test(u.pathname) && !publicPathRe.test(u.pathname)) return;\n const key = `${u.origin}${u.pathname.replace(/\\/$/, '') || '/'}${u.search}`;\n if (!links.has(key)) links.set(key, { href, label, flowType: flowTypeFor(`${label} ${u.pathname}`) });\n };\n\n const walk = (root: Document | ShadowRoot) => {\n root.querySelectorAll('a[href]').forEach((el) => addHref((el as HTMLAnchorElement).href || el.getAttribute('href'), textOf(el)));\n root.querySelectorAll('[data-href],[data-url],[data-link]').forEach((el: any) => addHref(el.dataset?.href || el.dataset?.url || el.dataset?.link || '', textOf(el)));\n root.querySelectorAll('*').forEach((el: any) => { if (el.shadowRoot) walk(el.shadowRoot); });\n };\n walk(document);\n\n const clicks: Array<{ selector: string; label: string; flowType: BrowserFlowType }> = [];\n const clickEls = Array.from(document.querySelectorAll('button,[role=\"button\"],a:not([href]),[data-state],[aria-haspopup]')) as HTMLElement[];\n let idx = 0;\n for (const el of clickEls) {\n if (clicks.length >= 12) break;\n if (!isVisible(el)) continue;\n const label = textOf(el);\n if (!label || !authTextRe.test(label) || skipTextRe.test(label)) continue;\n const type = (el.getAttribute('type') || '').toLowerCase();\n const inCredentialForm = !!el.closest('form')?.querySelector('input[type=\"password\"],input[type=\"email\"],input[name*=\"user\" i],input[name*=\"email\" i]');\n const submitLike = type === 'submit' || /^(login|log in|sign in|continue)$/i.test(label);\n // Avoid submitting empty login forms. Links/buttons that change auth state, such as\n // \"Forgot password\" or \"Create account\", are safe to click even inside the form.\n if (inCredentialForm && submitLike && !/(forgot|reset|register|sign up|create account|back to login|use email)/i.test(label)) continue;\n const attr = `zeta-auth-${idx++}`;\n el.setAttribute('data-zeta-auth-discovery-id', attr);\n clicks.push({ selector: `[data-zeta-auth-discovery-id=\"${attr}\"]`, label, flowType: flowTypeFor(label) });\n }\n\n return { links: Array.from(links.values()).slice(0, 32), clicks };\n }, origin).catch(() => ({ links: [], clicks: [] }));\n}\n\nasync function captureAuthDiscoveryScreen(\n page: any,\n opts: AuthDiscoveryOptions,\n requestedUrl: string,\n source: AuthDiscoverySource,\n ordinal: number,\n trigger?: { label?: string; flowType?: AuthFlowType; sameUrlState?: boolean },\n): Promise<{ captured: boolean; finalUrl: string; flowType: AuthFlowType }> {\n const finalUrl = page.url?.() ?? requestedUrl;\n if (finalUrl.startsWith('chrome-error://')) return { captured: false, finalUrl, flowType: 'public' };\n if (!(await hasMeaningfulAuthOrPublicState(page, requestedUrl))) {\n return { captured: false, finalUrl, flowType: flowTypeForUrlOrText(`${requestedUrl} ${finalUrl} ${trigger?.label ?? ''}`) };\n }\n\n const flowType = trigger?.flowType ?? flowTypeForUrlOrText(`${requestedUrl} ${finalUrl} ${trigger?.label ?? ''}`);\n const title = await page.title().catch(() => '');\n const baseName = title?.trim() && !/^(untitled|about:blank)$/i.test(title.trim())\n ? title.trim().slice(0, 72)\n : titleFromUrl(finalUrl);\n const prefix = flowType === 'public' ? 'Public' : `Auth ${flowType.replace('_', ' ')}`;\n const name = `${prefix} \u00B7 ${trigger?.label ? trigger.label.slice(0, 48) : baseName}`.replace(/\\s+/g, ' ');\n const screenUrl = trigger?.sameUrlState\n ? `${finalUrl.split('#')[0]}#zeta-auth-flow=${compactSlug(trigger.label ?? `${flowType}-${ordinal}`)}`\n : finalUrl;\n const shotPath = path.join(opts.screenshotDir ?? '/tmp', `auth-discovery-${opts.jobId ?? 'run'}-${ordinal}.png`);\n\n await waitForScreenshotReady(page);\n await page.screenshot({ path: shotPath, fullPage: true }).catch(() => { });\n const screen = await AppBrain.saveScreen(opts.tenantId, opts.projectId, name, screenUrl, opts.jobId, source === 'entry' ? 'ENTRY_POINT' : 'SEED_URL').catch(() => null);\n if (!screen) return { captured: false, finalUrl, flowType };\n let authCloudUrl: string | undefined;\n if (opts.storageConfig && existsSyncFs(shotPath)) {\n try {\n const { uploadScreenshotToTenantStorage } = await import('@detiq/app-brain');\n authCloudUrl = await uploadScreenshotToTenantStorage(opts.storageConfig as any, shotPath, `${opts.tenantId}/${opts.projectId}/screenshots/${path.basename(shotPath)}`);\n } catch { /* non-fatal */ }\n }\n if (existsSyncFs(shotPath)) {\n await AppBrain.saveScreenshot(opts.tenantId, opts.projectId, screen.id, shotPath, screen.version, 'DESKTOP', authCloudUrl).catch(() => { });\n }\n // GAP 11: DOM snapshot for auth-discovery phase\n const authDomContent = await capturePageHtml(page);\n if (authDomContent && opts.screenshotDir) {\n const authDomPath = shotPath.replace(/\\.(png|jpg|jpeg)$/i, '.dom.html');\n await fs.writeFile(authDomPath, authDomContent, 'utf8');\n let authDomCloudUrl: string | undefined;\n if (opts.storageConfig) {\n try {\n const { uploadScreenshotToTenantStorage } = await import('@detiq/app-brain');\n authDomCloudUrl = await uploadScreenshotToTenantStorage(opts.storageConfig as any, authDomPath, `${opts.tenantId}/${opts.projectId}/dom-snapshots/${path.basename(authDomPath)}`);\n } catch { /* non-fatal */ }\n }\n await AppBrain.updateScreenDomSnapshot(opts.tenantId, screen.id, authDomPath, authDomCloudUrl).catch(() => {});\n }\n // Extract and save interactive elements (inputs, buttons, links) for this auth-discovery screen.\n // Without this, login pages and auth flows always show 0 elements in Crawl Captures.\n const authDiscoveryElements = await readScreen(page).catch(() => [] as Awaited<ReturnType<typeof readScreen>>);\n if (authDiscoveryElements.length > 0) {\n await AppBrain.clearScreenElements(opts.tenantId, opts.projectId, screen.id).catch(() => {});\n for (const el of authDiscoveryElements) {\n await AppBrain.saveElement(opts.tenantId, opts.projectId, screen.id, el.label, el.role, el.expectedData, undefined, undefined, true, undefined, undefined, undefined).catch(() => {});\n }\n logger.info({ screenId: screen.id, elements: authDiscoveryElements.length }, '[crawler] auth-discovery: saved elements');\n }\n await AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n screenId: screen.id,\n jobId: opts.jobId,\n type: 'AUTH_DISCOVERY',\n payload: {\n requestedUrl,\n finalUrl,\n screenUrl,\n authState: flowType === 'public' ? 'logged_out' : 'auth_flow',\n flowType,\n source,\n triggerLabel: trigger?.label ?? null,\n },\n }).catch(() => { });\n logger.info({ requestedUrl, finalUrl, screenUrl, flowType, source }, '[crawler] auth-discovery: captured screen');\n return { captured: true, finalUrl, flowType };\n}\n\nasync function runAuthDiscoveryPhase(\n page: any,\n opts: AuthDiscoveryOptions,\n origin: string,\n onProgress?: AuthDiscoveryProgress,\n): Promise<{ captured: number; discoveredUrls: string[] }> {\n const tuning = await getCrawlTuning();\n const queue: Array<{ url: string; source: AuthDiscoverySource }> = [];\n const queued = new Set<string>();\n const capturedKeys = new Set<string>();\n const discoveredUrls = new Set<string>();\n const enqueue = (url: string, source: AuthDiscoverySource) => {\n if (!shouldSeedAuthDiscoveryUrl(url, origin)) return;\n const key = normalizeAuthUrl(url);\n if (queued.has(key) || queue.length >= AUTH_DISCOVERY_MAX_QUEUE) return;\n queued.add(key);\n queue.push({ url, source });\n };\n\n enqueue(opts.appUrl, 'entry');\n for (const p of AUTH_DISCOVERY_PATHS) {\n try { enqueue(new URL(p, origin).toString(), 'seed_path'); } catch { /* ignore bad seed */ }\n }\n\n // Capture homepage DOM fingerprint for soft-404 detection.\n // SPA catch-all sites return 200 for every path but render identical content.\n // If a seeded path produces the same element count + title as the homepage, it's\n // a phantom route \u2014 skip it so auth paths don't pollute the discovered URL list.\n let homeTitle = '';\n let homeElemCount = -1;\n try {\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => null);\n await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => { });\n homeTitle = await page.title().catch(() => '');\n homeElemCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"]').length\n ).catch(() => -1);\n } catch { /* best-effort */ }\n\n let captured = 0;\n let ordinal = 0;\n await onProgress?.(10, 'Discovering public and auth flows');\n\n while (queue.length > 0 && captured < AUTH_DISCOVERY_MAX_SCREENS) {\n const current = queue.shift()!;\n const _authPct = 10 + Math.round((captured / AUTH_DISCOVERY_MAX_SCREENS) * 7);\n const _authPath = current.url.replace(/^https?:\\/\\/[^/]+/, '') || '/';\n await onProgress?.(_authPct, `Auth discovery \u00B7 ${_authPath} \u00B7 ${captured} found`);\n try {\n const response = await page.goto(current.url, { waitUntil: 'domcontentloaded', timeout: tuning.navTimeoutMs }).catch(() => null);\n if (response && response.status && response.status() >= 400) continue;\n await page.waitForLoadState('networkidle', { timeout: 6_000 }).catch(() => { });\n await waitForStableDOM(page);\n await acceptCookieConsent(page, { waitMs: 400 }).catch(() => { });\n\n // Soft-404 detection: SPA returns 200 for unknown paths but renders homepage.\n // Skip if title + element count match the homepage fingerprint exactly.\n if (current.source === 'seed_path' && homeElemCount >= 0) {\n const pageTitle = await page.title().catch(() => '');\n const elemCount = await page.evaluate(() =>\n document.querySelectorAll('button,a,input,select,textarea,[role=\"button\"]').length\n ).catch(() => -1);\n if (pageTitle === homeTitle && elemCount === homeElemCount) continue;\n }\n\n const finalUrl = page.url?.() ?? current.url;\n\n // Skip auth seed paths that redirect to a non-auth URL \u2014 the page captured would be the\n // post-login destination (e.g. dashboard) not the actual auth screen.\n if (current.source === 'seed_path' && finalUrl !== current.url) {\n try {\n const origPath = new URL(current.url).pathname;\n const finalPath = new URL(finalUrl).pathname;\n const isAuthSeed = /login|sign-?in|signin|auth|sso|forgot-?password|reset-?password|2fa|mfa/i.test(origPath);\n if (isAuthSeed && finalPath !== origPath) continue;\n } catch { /* non-parseable URL \u2014 allow capture */ }\n }\n\n const captureKey = normalizeAuthUrl(finalUrl);\n if (!capturedKeys.has(captureKey)) {\n const result = await captureAuthDiscoveryScreen(page, opts, current.url, current.source, ordinal++);\n if (result.captured) {\n captured++;\n capturedKeys.add(captureKey);\n discoveredUrls.add(result.finalUrl);\n }\n }\n\n const candidates = await discoverAuthCandidates(page, origin);\n for (const link of candidates.links) enqueue(link.href, 'page_link');\n\n const baseUrlForClicks = finalUrl;\n const clickLimit = Math.min(candidates.clicks.length, AUTH_DISCOVERY_MAX_CLICKS_PER_PAGE);\n for (let i = 0; i < clickLimit && captured < AUTH_DISCOVERY_MAX_SCREENS; i++) {\n await page.goto(baseUrlForClicks, { waitUntil: 'domcontentloaded', timeout: 12_000 }).catch(() => { });\n await page.waitForLoadState('networkidle', { timeout: 4_000 }).catch(() => { });\n await waitForStableDOM(page);\n const freshCandidates = await discoverAuthCandidates(page, origin);\n const click = freshCandidates.clicks[i];\n if (!click) continue;\n const beforeUrl = page.url?.() ?? baseUrlForClicks;\n await page.locator(click.selector).first().click({ timeout: 4_000 }).catch(() => { });\n await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => { });\n await waitForStableDOM(page);\n const afterUrl = page.url?.() ?? beforeUrl;\n const sameUrlState = normalizeAuthUrl(beforeUrl) === normalizeAuthUrl(afterUrl);\n const stateKey = sameUrlState\n ? `${normalizeAuthUrl(afterUrl)}::${compactSlug(click.label)}`\n : normalizeAuthUrl(afterUrl);\n if (capturedKeys.has(stateKey)) continue;\n const result = await captureAuthDiscoveryScreen(page, opts, beforeUrl, 'auth_click', ordinal++, {\n label: click.label,\n flowType: click.flowType,\n sameUrlState,\n });\n if (result.captured) {\n captured++;\n capturedKeys.add(stateKey);\n discoveredUrls.add(result.finalUrl);\n const nested = await discoverAuthCandidates(page, origin);\n for (const link of nested.links) enqueue(link.href, 'page_link');\n }\n }\n } catch (err) {\n logger.warn({ url: current.url, err: String((err as Error)?.message ?? err) }, '[crawler] auth-discovery: URL failed \u2014 skipping');\n }\n }\n\n await page.goto(opts.appUrl, { waitUntil: 'domcontentloaded', timeout: 15_000 }).catch(() => { });\n await waitForStableDOM(page).catch(() => { });\n await AppBrain.saveCrawlEvidence(opts.tenantId, opts.projectId, {\n jobId: opts.jobId,\n type: 'AUTH_DISCOVERY_SUMMARY',\n payload: { captured, discoveredUrls: Array.from(discoveredUrls), maxScreens: AUTH_DISCOVERY_MAX_SCREENS },\n }).catch(() => { });\n logger.info({ captured, discovered: discoveredUrls.size }, '[crawler] auth-discovery: phase complete');\n return { captured, discoveredUrls: Array.from(discoveredUrls) };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["queue", "candidate", "canonUrl", "INLINE_AUTH_WALL_RE", "sitemapUrls", "selector", "title", "desc", "location", "origin"]
|
|
7
7
|
}
|