@robot-resources/scraper 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  > Context compression for AI agents. Fetch → Extract → Convert pipeline without LLM dependency.
11
11
 
12
- Reduces web page tokens by 70-80% for AI agent consumption. 3-tier fetch with auto-fallback, BFS multi-page crawl, robots.txt compliance.
12
+ Median 91% token reduction for AI agent consumption (verified across 41 page types). 3-tier fetch with auto-fallback, BFS multi-page crawl, robots.txt compliance.
13
13
 
14
14
  ## Installation
15
15
 
@@ -205,11 +205,16 @@ try {
205
205
 
206
206
  ## Token Reduction
207
207
 
208
- | Page Type | HTML Tokens | Markdown Tokens | Reduction |
209
- |-----------|-------------|-----------------|-----------|
210
- | News article | ~15,000 | ~3,000 | 80% |
211
- | Documentation | ~12,000 | ~2,500 | 79% |
212
- | Blog post | ~8,000 | ~1,800 | 77% |
208
+ Verified across 41 pages (March 2026):
209
+
210
+ | Page Type | HTML Tokens | Scraper Tokens | Reduction |
211
+ |-----------|-------------|----------------|-----------|
212
+ | Landing pages & SPAs | ~237,000 | ~380 | 99% |
213
+ | GitHub repositories | ~110,000 | ~479 | 99% |
214
+ | API reference (MDN) | ~55,000 | ~6,349 | 88% |
215
+ | Wikipedia articles | ~187,000 | ~42,039 | 77% |
216
+ | Blog posts & essays | ~20,000 | ~15,639 | 22-92% |
217
+ | **Median across all types** | | | **91%** |
213
218
 
214
219
  ## Requirements
215
220
 
package/bin/setup.js CHANGED
@@ -1,15 +1,36 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * robot-resources-scraper — Setup wizard for @robot-resources/scraper.
4
+ * robot-resources-scraper — CLI for @robot-resources/scraper.
5
5
  *
6
- * Triggered via `npx @robot-resources/scraper`.
7
- * Offers optional GitHub login and shows usage instructions.
6
+ * Usage:
7
+ * npx @robot-resources/scraper <url> → compressed markdown to stdout
8
+ * npx @robot-resources/scraper <url> --json → full result as JSON
9
+ * npx @robot-resources/scraper <url> --mode fast → specific fetch mode
10
+ * npx @robot-resources/scraper → show usage & setup info
8
11
  */
9
12
 
10
- import { readFileSync, writeFileSync, copyFileSync, mkdirSync, existsSync } from "node:fs";
13
+ import { readFileSync } from "node:fs";
11
14
  import { homedir } from "node:os";
12
- import { join } from "node:path";
15
+ import { join, dirname } from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+
18
+ // ─── Arg parsing (zero deps) ────────────────────────────────────────────────
19
+
20
+ const args = process.argv.slice(2);
21
+ let url = null;
22
+ let mode = "auto";
23
+ let timeout = undefined;
24
+ let json = false;
25
+ let help = false;
26
+
27
+ for (let i = 0; i < args.length; i++) {
28
+ if (args[i] === "--mode" && args[i + 1]) { mode = args[++i]; continue; }
29
+ if (args[i] === "--timeout" && args[i + 1]) { timeout = Number(args[++i]); continue; }
30
+ if (args[i] === "--json") { json = true; continue; }
31
+ if (args[i] === "--help" || args[i] === "-h") { help = true; continue; }
32
+ if (!url && /^https?:\/\//.test(args[i])) { url = args[i]; continue; }
33
+ }
13
34
 
14
35
  // ─── ANSI helpers ────────────────────────────────────────────────────────────
15
36
 
@@ -23,113 +44,82 @@ const c = {
23
44
  blue: "\x1b[34m",
24
45
  };
25
46
 
26
- function success(msg) { console.log(` ${c.green}✓${c.reset} ${msg}`); }
27
- function step(msg) { console.log(` ${c.cyan}→${c.reset} ${msg}`); }
28
- function info(msg) { console.log(` ${c.dim}${msg}${c.reset}`); }
29
- function warn(msg) { console.log(` ${c.yellow}!${c.reset} ${msg}`); }
30
-
31
- // ─── Config helpers (inline — no external deps for this bin) ─────────────────
47
+ // ─── Config helpers ──────────────────────────────────────────────────────────
32
48
 
33
- const CONFIG_DIR = join(homedir(), ".robot-resources");
34
- const CONFIG_FILE = join(CONFIG_DIR, "config.json");
49
+ const CONFIG_FILE = join(homedir(), ".robot-resources", "config.json");
35
50
 
36
51
  function readConfig() {
37
52
  try { return JSON.parse(readFileSync(CONFIG_FILE, "utf-8")); }
38
53
  catch { return {}; }
39
54
  }
40
55
 
41
- // ─── MCP auto-config ─────────────────────────────────────────────────────────
42
-
43
- const MCP_KEY = "robot-resources-scraper";
44
- const MCP_ENTRY = { command: "npx", args: ["-y", "@robot-resources/scraper-mcp"] };
45
-
46
- function detectAgents() {
47
- const home = homedir();
48
- const agents = [
49
- {
50
- name: "Claude Desktop",
51
- configPath: process.platform === "darwin"
52
- ? join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json")
53
- : join(home, ".config", "Claude", "claude_desktop_config.json"),
54
- },
55
- { name: "Cursor", configPath: join(home, ".cursor", "mcp.json") },
56
- ];
57
- return agents.filter((a) => existsSync(a.configPath) || existsSync(join(a.configPath, "..")));
58
- }
56
+ // ─── Scrape mode: URL provided ──────────────────────────────────────────────
59
57
 
60
- function configureAgentMCP() {
61
- const agents = detectAgents();
62
- const results = [];
63
-
64
- for (const agent of agents) {
65
- try {
66
- let config;
67
- try { config = JSON.parse(readFileSync(agent.configPath, "utf-8")); }
68
- catch { config = {}; }
69
-
70
- config.mcpServers = config.mcpServers || {};
71
- if (config.mcpServers[MCP_KEY]) {
72
- results.push({ name: agent.name, action: "exists" });
73
- continue;
74
- }
75
-
76
- // Backup before modifying
77
- if (existsSync(agent.configPath)) {
78
- copyFileSync(agent.configPath, `${agent.configPath}.bak`);
79
- }
80
-
81
- config.mcpServers[MCP_KEY] = MCP_ENTRY;
82
- mkdirSync(join(agent.configPath, ".."), { recursive: true });
83
- writeFileSync(agent.configPath, JSON.stringify(config, null, 2) + "\n");
84
- results.push({ name: agent.name, action: "added" });
85
- } catch (err) {
86
- results.push({ name: agent.name, action: "error", reason: err.message });
87
- }
58
+ async function runScrape(targetUrl, opts) {
59
+ const { scrape } = await import("@robot-resources/scraper");
60
+ const result = await scrape(targetUrl, {
61
+ mode: opts.mode,
62
+ timeout: opts.timeout,
63
+ });
64
+
65
+ if (opts.json) {
66
+ process.stdout.write(JSON.stringify(result) + "\n");
67
+ } else {
68
+ process.stdout.write(result.markdown + "\n");
88
69
  }
89
- return results;
90
70
  }
91
71
 
92
- // ─── Main ────────────────────────────────────────────────────────────────────
72
+ // ─── Usage mode: no URL ─────────────────────────────────────────────────────
73
+
74
+ function showUsage() {
75
+ const __dirname = dirname(fileURLToPath(import.meta.url));
76
+ const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
93
77
 
94
- async function main() {
95
- console.log(`\n ${c.blue}${c.bold}██ Robot Resources — Scraper Setup${c.reset}\n`);
78
+ console.log(`\n ${c.blue}${c.bold}██ Robot Resources — Scraper v${pkg.version}${c.reset}\n`);
96
79
 
97
- // Step 1: Auth status
80
+ // Auth status
98
81
  const config = readConfig();
99
82
  if (config.api_key) {
100
- success(`Logged in as ${config.user_name || config.user_email || "unknown"}`);
83
+ console.log(` ${c.green}✓${c.reset} Logged in as ${config.user_name || config.user_email || "unknown"}`);
101
84
  } else {
102
- info("Not logged in. Scraper works without login.");
103
- info(`To enable telemetry, run: ${c.cyan}npx robot-resources${c.reset}`);
85
+ console.log(` ${c.dim}Not logged in. Scraper works without login.${c.reset}`);
86
+ console.log(` ${c.dim}To enable telemetry, run: ${c.cyan}npx robot-resources${c.reset}`);
104
87
  }
105
88
 
106
- // Step 2: MCP auto-config
107
- console.log("");
108
- step("Configuring MCP in detected agents...");
89
+ // CLI usage
90
+ console.log(`\n ${c.blue}${c.bold}── Command Line ──${c.reset}\n`);
91
+ console.log(` ${c.cyan}npx @robot-resources/scraper ${c.dim}<url>${c.reset} Compressed markdown`);
92
+ console.log(` ${c.cyan}npx @robot-resources/scraper ${c.dim}<url>${c.cyan} --json${c.reset} Full result as JSON`);
93
+ console.log(` ${c.cyan}npx @robot-resources/scraper ${c.dim}<url>${c.cyan} --mode stealth${c.reset} Stealth fetch mode`);
94
+ console.log(` ${c.cyan}npx @robot-resources/scraper ${c.dim}<url>${c.cyan} --timeout 15000${c.reset} Custom timeout (ms)`);
109
95
 
110
- const mcpResults = configureAgentMCP();
111
- if (mcpResults.length === 0) {
112
- info("No supported agents detected (Claude Desktop, Cursor)");
113
- } else {
114
- for (const r of mcpResults) {
115
- if (r.action === "added") success(`${r.name}: scraper MCP configured`);
116
- else if (r.action === "exists") success(`${r.name}: already configured`);
117
- else warn(`${r.name}: ${r.reason || r.action}`);
118
- }
119
- }
120
-
121
- // Step 3: Usage
122
- console.log(`\n ${c.blue}${c.bold}── Ready ──${c.reset}\n`);
123
- console.log(" Use as a library:");
96
+ // Library usage
97
+ console.log(`\n ${c.blue}${c.bold}── As a Library ──${c.reset}\n`);
124
98
  console.log(` ${c.dim}import { scrape } from '@robot-resources/scraper';${c.reset}`);
125
99
  console.log(` ${c.dim}const result = await scrape('https://example.com');${c.reset}`);
126
- console.log("");
127
- console.log(" Use via MCP (already configured above):");
128
- console.log(` ${c.dim}Your agent can call scraper_compress_url(url)${c.reset}`);
100
+
101
+ // MCP usage (generic, not agent-specific)
102
+ console.log(`\n ${c.blue}${c.bold}── Via MCP ──${c.reset}\n`);
103
+ console.log(` ${c.dim}Add to your agent's MCP config:${c.reset}`);
104
+ console.log(` ${c.dim}{${c.reset}`);
105
+ console.log(` ${c.dim} "mcpServers": {${c.reset}`);
106
+ console.log(` ${c.dim} "scraper": {${c.reset}`);
107
+ console.log(` ${c.dim} "command": "npx",${c.reset}`);
108
+ console.log(` ${c.dim} "args": ["-y", "@robot-resources/scraper-mcp"]${c.reset}`);
109
+ console.log(` ${c.dim} }${c.reset}`);
110
+ console.log(` ${c.dim} }${c.reset}`);
111
+ console.log(` ${c.dim}}${c.reset}`);
112
+
129
113
  console.log("");
130
114
  }
131
115
 
132
- main().catch((err) => {
133
- console.error(`\n Setup failed: ${err.message}\n`);
134
- process.exit(1);
135
- });
116
+ // ─── Main ────────────────────────────────────────────────────────────────────
117
+
118
+ if (url && !help) {
119
+ runScrape(url, { mode, timeout, json }).catch((err) => {
120
+ process.stderr.write(`Error: ${err.message}\n`);
121
+ process.exit(1);
122
+ });
123
+ } else {
124
+ showUsage();
125
+ }
package/dist/index.cjs CHANGED
@@ -947,6 +947,7 @@ async function scrape(url, options = {}) {
947
947
  maxRetries: options.maxRetries,
948
948
  userAgent: options.userAgent
949
949
  });
950
+ const originalTokenCount = estimateTokens(fetchResult.html);
950
951
  const extractResult = await extractContent(fetchResult);
951
952
  const convertResult = await convertToMarkdown(extractResult);
952
953
  const result = {
@@ -961,6 +962,7 @@ async function scrape(url, options = {}) {
961
962
  reportScraperEvent({
962
963
  url,
963
964
  tokenCount: convertResult.tokenCount,
965
+ originalTokenCount,
964
966
  title: extractResult.title,
965
967
  latencyMs: Date.now() - startTime,
966
968
  success: true
@@ -970,6 +972,7 @@ async function scrape(url, options = {}) {
970
972
  reportScraperEvent({
971
973
  url,
972
974
  tokenCount: 0,
975
+ originalTokenCount: 0,
973
976
  latencyMs: Date.now() - startTime,
974
977
  success: false,
975
978
  error: err instanceof Error ? err.message : String(err)
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/fetch.ts","../src/fetch-stealth.ts","../src/fetch-render.ts","../src/extract.ts","../src/convert.ts","../src/robots.ts","../src/sitemap.ts","../src/fetch-mode.ts","../src/crawl.ts","../src/telemetry.ts","../src/index.ts"],"names":["DEFAULT_TIMEOUT","DEFAULT_MAX_RETRIES","BASE_BACKOFF_MS","isValidUrl","isRetryableStatus","sleep","getBackoffDelay","parseHTML","Readability","TurndownService","robotsParser","DEFAULT_TIMEOUT_MS","DEFAULT_TTL_MS","cache","join","homedir","readFileSync"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Layer 1: Fetch\n * HTTP fetching with smart headers and retries\n */\n\nimport type { FetchResult } from './types.js';\n\nconst USER_AGENTS = [\n 'Mozilla/5.0 (compatible; ScraperBot/1.0; +https://scraper.robotresources.ai)',\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n];\n\nconst DEFAULT_TIMEOUT = 10000;\nconst DEFAULT_MAX_RETRIES = 3;\nconst BASE_BACKOFF_MS = 1000;\n\nexport interface FetchOptions {\n timeout?: number;\n maxRetries?: number;\n userAgent?: string;\n}\n\n/**\n * Error class for fetch-related errors\n */\nexport class FetchError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly retryable: boolean = false\n ) {\n super(message);\n this.name = 'FetchError';\n }\n}\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nfunction getRandomUserAgent(): string {\n return USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];\n}\n\nfunction buildHeaders(userAgent?: string): Record<string, string> {\n return {\n 'User-Agent': userAgent || getRandomUserAgent(),\n Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n 'Accept-Language': 'en-US,en;q=0.9',\n 'Accept-Encoding': 'gzip, deflate',\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n };\n}\n\nfunction headersToObject(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key.toLowerCase()] = value;\n });\n return result;\n}\n\nfunction isRetryableStatus(status: number): boolean {\n return status >= 500 && status < 600;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction getBackoffDelay(attempt: number): number {\n return BASE_BACKOFF_MS * Math.pow(2, attempt);\n}\n\nasync function fetchWithTimeout(\n url: string,\n headers: Record<string, string>,\n timeout: number\n): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers,\n signal: controller.signal,\n redirect: 'follow',\n });\n return response;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new FetchError('Request timeout', undefined, true);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\n/**\n * Fetch URL content with smart headers and retry logic\n */\nexport async function fetchUrl(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const {\n timeout = DEFAULT_TIMEOUT,\n maxRetries = DEFAULT_MAX_RETRIES,\n userAgent,\n } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n const headers = buildHeaders(userAgent);\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await fetchWithTimeout(url, headers, timeout);\n\n if (!response.ok) {\n const statusCode = response.status;\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (isRetryableStatus(statusCode)) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n }\n\n const html = await response.text();\n const responseHeaders = headersToObject(response.headers);\n\n return {\n html,\n url: response.url,\n statusCode: response.status,\n headers: responseHeaders,\n };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n const isRetryable =\n error instanceof FetchError\n ? error.retryable\n : !(error instanceof FetchError);\n\n const hasRetriesLeft = attempt < maxRetries;\n\n if (isRetryable && hasRetriesLeft) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n\n break;\n }\n }\n\n throw lastError || new FetchError('Unknown fetch error');\n}\n","/**\n * Layer 1b: Stealth Fetch\n * TLS fingerprint impersonation via impit (optional peer dependency)\n *\n * Uses Rust-based browser TLS fingerprinting to bypass anti-bot systems\n * (Cloudflare, Akamai, PerimeterX) without a full browser.\n *\n * Requires: npm install impit (Node >= 20)\n */\n\nimport type { FetchResult } from './types.js';\nimport { FetchError } from './fetch.js';\nimport type { FetchOptions } from './fetch.js';\n\nconst DEFAULT_TIMEOUT = 10000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst BASE_BACKOFF_MS = 1000;\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nfunction isRetryableStatus(status: number): boolean {\n return status >= 500 && status < 600;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction getBackoffDelay(attempt: number): number {\n return BASE_BACKOFF_MS * Math.pow(2, attempt);\n}\n\n/**\n * Fetch URL with browser TLS fingerprint impersonation.\n *\n * Uses impit (Apify) to produce Chrome-like JA3/JA4 fingerprints at the\n * TLS handshake level. This bypasses anti-bot systems that reject default\n * Node.js TLS signatures.\n *\n * impit is an optional peer dependency — if not installed, throws a clear\n * error message with install instructions.\n */\nexport async function fetchStealth(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const {\n timeout = DEFAULT_TIMEOUT,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n // Dynamic import — impit is an optional peer dependency\n let Impit: any;\n try {\n // @ts-expect-error impit is an optional peer dependency (not installed in dev)\n ({ Impit } = await import('impit'));\n } catch {\n throw new FetchError(\n 'impit is required for stealth mode. Install: npm install impit (requires Node >= 20)',\n undefined,\n false\n );\n }\n\n const client = new Impit({ browser: 'chrome' });\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await client.fetch(url, {\n signal: AbortSignal.timeout(timeout),\n });\n\n if (!response.ok) {\n const statusCode = response.status;\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (isRetryableStatus(statusCode)) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n }\n\n const html = await response.text();\n const headers: Record<string, string> = {};\n response.headers.forEach((value: string, key: string) => {\n headers[key] = value;\n });\n\n return {\n html,\n url: response.url ?? url,\n statusCode: response.status,\n headers,\n };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n const isRetryable =\n error instanceof FetchError\n ? error.retryable\n : !(error instanceof FetchError);\n\n const hasRetriesLeft = attempt < maxRetries;\n\n if (isRetryable && hasRetriesLeft) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n\n break;\n }\n }\n\n throw lastError || new FetchError('Unknown stealth fetch error');\n}\n","/**\n * Layer 1c: Render Fetch\n * Playwright headless browser for JS-rendered pages (optional peer dependency)\n *\n * Uses Chromium to fully render SPAs (React, Next.js, Vue) that return\n * empty/partial HTML to tiers 1 and 2. Extracts the fully rendered DOM.\n *\n * Requires: npm install playwright\n */\n\nimport type { FetchResult } from './types.js';\nimport { FetchError } from './fetch.js';\nimport type { FetchOptions } from './fetch.js';\n\nconst DEFAULT_TIMEOUT = 30000;\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\n/**\n * Fetch URL using a headless Chromium browser to render JavaScript.\n *\n * Launches a fresh browser per call (no shared state), navigates to the URL,\n * waits for network idle, then extracts the fully rendered HTML.\n *\n * Playwright is an optional peer dependency — if not installed, throws a clear\n * error message with install instructions.\n */\nexport async function fetchRender(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const { timeout = DEFAULT_TIMEOUT } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n // Dynamic import — Playwright is an optional peer dependency\n let chromium: any;\n try {\n // @ts-expect-error playwright is an optional peer dependency (not installed in dev)\n ({ chromium } = await import('playwright'));\n } catch {\n throw new FetchError(\n 'Playwright is required for render mode. Install: npm install playwright',\n undefined,\n false\n );\n }\n\n const browser = await chromium.launch({ headless: true });\n\n try {\n const page = await browser.newPage();\n\n // Auto-dismiss dialogs to prevent hanging\n page.on('dialog', (dialog: any) => dialog.dismiss());\n\n const response = await page.goto(url, {\n waitUntil: 'networkidle',\n timeout,\n });\n\n if (!response) {\n throw new FetchError(\n 'Navigation returned no response (about:blank or same-URL redirect)',\n undefined,\n false\n );\n }\n\n const statusCode = response.status();\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (statusCode >= 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n\n const html = await page.content();\n const headers: Record<string, string> = response.headers();\n\n return {\n html,\n url: page.url(),\n statusCode,\n headers,\n };\n } catch (error) {\n // Convert Playwright timeout errors to retryable FetchErrors\n if (error instanceof Error && error.name === 'TimeoutError') {\n throw new FetchError('Navigation timeout', undefined, true);\n }\n throw error;\n } finally {\n await browser.close();\n }\n}\n","/**\n * Layer 2: Extract\n * Content extraction using Readability\n */\n\nimport { Readability } from '@mozilla/readability';\nimport { parseHTML } from 'linkedom';\nimport type { FetchResult, ExtractResult } from './types.js';\n\n/**\n * Error class for extraction-related errors\n */\nexport class ExtractionError extends Error {\n constructor(\n message: string,\n public readonly code: string\n ) {\n super(message);\n this.name = 'ExtractionError';\n }\n}\n\n/**\n * Extract main content from HTML using Readability\n */\nexport async function extractContent(\n fetchResult: FetchResult\n): Promise<ExtractResult> {\n const { html } = fetchResult;\n\n if (!html || !html.trim()) {\n throw new ExtractionError('Empty HTML content', 'EMPTY_HTML');\n }\n\n const { document } = parseHTML(html);\n\n const reader = new Readability(document, {\n charThreshold: 50,\n });\n\n const article = reader.parse();\n\n if (!article || !article.content || article.content.trim().length < 20) {\n throw new ExtractionError(\n 'No content could be extracted from the page',\n 'NO_CONTENT'\n );\n }\n\n const result: ExtractResult = {\n content: cleanContent(article.content),\n title: article.title || extractFallbackTitle(document),\n author: article.byline || undefined,\n publishedAt: article.publishedTime || extractPublishedTime(document),\n siteName: article.siteName || extractSiteName(document),\n };\n\n return result;\n}\n\nfunction cleanContent(content: string): string {\n return content\n .replace(/>\\s+</g, '><')\n .replace(/\\s{2,}/g, ' ')\n .trim();\n}\n\nfunction extractFallbackTitle(document: Document): string | undefined {\n const ogTitle = document.querySelector('meta[property=\"og:title\"]');\n if (ogTitle) {\n const content = ogTitle.getAttribute('content');\n if (content) return content;\n }\n\n const titleEl = document.querySelector('title');\n if (titleEl && titleEl.textContent) {\n return titleEl.textContent.trim();\n }\n\n const h1 = document.querySelector('h1');\n if (h1 && h1.textContent) {\n return h1.textContent.trim();\n }\n\n return undefined;\n}\n\nfunction extractPublishedTime(document: Document): string | undefined {\n const ogTime = document.querySelector(\n 'meta[property=\"article:published_time\"]'\n );\n if (ogTime) {\n const content = ogTime.getAttribute('content');\n if (content) return content;\n }\n\n const schemaTime = document.querySelector('[itemprop=\"datePublished\"]');\n if (schemaTime) {\n const datetime = schemaTime.getAttribute('datetime');\n if (datetime) return datetime;\n const content = schemaTime.getAttribute('content');\n if (content) return content;\n }\n\n const timeEl = document.querySelector('time[datetime]');\n if (timeEl) {\n const datetime = timeEl.getAttribute('datetime');\n if (datetime) return datetime;\n }\n\n return undefined;\n}\n\nfunction extractSiteName(document: Document): string | undefined {\n const ogSiteName = document.querySelector('meta[property=\"og:site_name\"]');\n if (ogSiteName) {\n const content = ogSiteName.getAttribute('content');\n if (content) return content;\n }\n\n const appName = document.querySelector('meta[name=\"application-name\"]');\n if (appName) {\n const content = appName.getAttribute('content');\n if (content) return content;\n }\n\n return undefined;\n}\n","/**\n * Layer 3: Convert\n * HTML to Markdown conversion\n */\n\nimport TurndownService from 'turndown';\nimport type { ExtractResult, ConvertResult } from './types.js';\n\nfunction createTurndownService(): TurndownService {\n const turndown = new TurndownService({\n headingStyle: 'atx',\n hr: '---',\n bulletListMarker: '-',\n codeBlockStyle: 'fenced',\n fence: '```',\n emDelimiter: '*',\n strongDelimiter: '**',\n linkStyle: 'inlined',\n });\n\n turndown.remove(['script', 'style', 'noscript', 'iframe']);\n\n turndown.addRule('removeEmpty', {\n filter: (node) => {\n if (node.nodeType === 1) {\n const text = node.textContent || '';\n const isEmptyBlock =\n text.trim() === '' &&\n !['IMG', 'BR', 'HR', 'INPUT'].includes(node.nodeName);\n return isEmptyBlock;\n }\n return false;\n },\n replacement: () => '',\n });\n\n turndown.addRule('fencedCodeBlock', {\n filter: (node, options) => {\n return (\n options.codeBlockStyle === 'fenced' &&\n node.nodeName === 'PRE' &&\n node.firstChild !== null &&\n node.firstChild.nodeName === 'CODE'\n );\n },\n replacement: (_content, node, options) => {\n const codeNode = node.firstChild as Element;\n const code = codeNode.textContent || '';\n\n const className = codeNode.getAttribute('class') || '';\n const langMatch = className.match(/language-(\\w+)/);\n const lang = langMatch ? langMatch[1] : '';\n\n const fence = options.fence || '```';\n return `\\n\\n${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n },\n });\n\n turndown.addRule('strikethrough', {\n filter: ['del', 's'] as const,\n replacement: (content) => `~~${content}~~`,\n });\n\n return turndown;\n}\n\nlet turndownInstance: TurndownService | null = null;\n\nfunction getTurndown(): TurndownService {\n if (!turndownInstance) {\n turndownInstance = createTurndownService();\n }\n return turndownInstance;\n}\n\nfunction cleanMarkdown(markdown: string): string {\n return markdown\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/[ \\t]+$/gm, '')\n .replace(/^\\n+/, '')\n .replace(/\\n+$/, '')\n .trim();\n}\n\n/**\n * Convert extracted HTML to clean Markdown\n */\nexport async function convertToMarkdown(\n extractResult: ExtractResult\n): Promise<ConvertResult> {\n const { content } = extractResult;\n\n if (!content || !content.trim()) {\n return {\n markdown: '',\n tokenCount: 0,\n };\n }\n\n const turndown = getTurndown();\n let markdown = turndown.turndown(content);\n\n markdown = cleanMarkdown(markdown);\n\n const tokenCount = estimateTokens(markdown);\n\n return {\n markdown,\n tokenCount,\n };\n}\n\n/**\n * Content-aware token estimator.\n *\n * Segments text by content type and applies calibrated character-per-token\n * ratios derived from cl100k_base (GPT-4) empirical measurements.\n *\n * Ratios:\n * Code blocks — 3.2 chars/token (operators, camelCase split into subwords)\n * Inline code — 3.5 chars/token (variable names, short expressions)\n * URLs — 5.0 chars/token (path segments tokenize efficiently)\n * Prose — 4.3 chars/token (words, punctuation, markdown formatting)\n *\n * Accuracy: within ±15% of actual BPE tokenization for English content.\n */\nexport function estimateTokens(text: string): number {\n if (!text) return 0;\n\n let tokens = 0;\n let remaining = text;\n\n // Code blocks: operators, identifiers → ~3.2 chars per token\n remaining = remaining.replace(/```[\\s\\S]*?```/g, (match) => {\n tokens += Math.ceil(match.length / 3.2);\n return ' ';\n });\n\n // Inline code: variables, short expressions → ~3.5 chars per token\n remaining = remaining.replace(/`[^`]+`/g, (match) => {\n tokens += Math.ceil(match.length / 3.5);\n return ' ';\n });\n\n // URLs: path segments, punctuation splitting → ~5.0 chars per token\n remaining = remaining.replace(/https?:\\/\\/\\S+/g, (match) => {\n tokens += Math.ceil(match.length / 5.0);\n return ' ';\n });\n\n // Prose: words, punctuation, markdown formatting → ~4.3 chars per token\n const proseLength = remaining.replace(/\\s+/g, ' ').trim().length;\n if (proseLength > 0) {\n tokens += Math.ceil(proseLength / 4.3);\n }\n\n return Math.max(1, tokens);\n}\n","/**\n * robots.txt compliance layer\n *\n * Opt-in for single-page scraping (respectRobots option),\n * foundation for FTR-ORG-019 crawl mode where it becomes default.\n */\n\nimport robotsParser from 'robots-parser';\n\ninterface RobotsCacheEntry {\n parser: ReturnType<typeof robotsParser>;\n expiresAt: number;\n}\n\nconst DEFAULT_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst BOT_USER_AGENT = 'ScraperBot';\n\nconst cache = new Map<string, RobotsCacheEntry>();\n\nfunction getRobotsUrl(url: string): string {\n const parsed = new URL(url);\n return `${parsed.protocol}//${parsed.host}/robots.txt`;\n}\n\nasync function getRobotsParser(\n url: string,\n timeout: number = DEFAULT_TIMEOUT_MS\n): Promise<ReturnType<typeof robotsParser>> {\n const robotsUrl = getRobotsUrl(url);\n\n const cached = cache.get(robotsUrl);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.parser;\n }\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(robotsUrl, {\n signal: controller.signal,\n headers: { 'User-Agent': BOT_USER_AGENT },\n });\n\n clearTimeout(timeoutId);\n\n const text = response.ok ? await response.text() : '';\n const parser = robotsParser(robotsUrl, text);\n\n cache.set(robotsUrl, {\n parser,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n\n return parser;\n } catch {\n // Fail-open: if robots.txt is unreachable, allow everything\n const parser = robotsParser(robotsUrl, '');\n cache.set(robotsUrl, {\n parser,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n return parser;\n }\n}\n\n/**\n * Check if a URL is allowed by robots.txt.\n * Returns true if allowed or if robots.txt cannot be fetched (fail-open).\n */\nexport async function isAllowedByRobots(\n url: string,\n timeout?: number\n): Promise<boolean> {\n const parser = await getRobotsParser(url, timeout);\n return parser.isAllowed(url, BOT_USER_AGENT) !== false;\n}\n\n/**\n * Extract Sitemap: URLs from robots.txt.\n * Returns empty array if no Sitemap directives or robots.txt unreachable (fail-open).\n * Reuses cached robots.txt parser.\n */\nexport async function getSitemapUrls(\n url: string,\n timeout?: number\n): Promise<string[]> {\n const parser = await getRobotsParser(url, timeout);\n return parser.getSitemaps();\n}\n\n/**\n * Extract Crawl-delay value from robots.txt for ScraperBot user agent.\n * Returns delay in seconds, or null if not specified or robots.txt unreachable (fail-open).\n * Reuses cached robots.txt parser.\n */\nexport async function getCrawlDelay(\n url: string,\n timeout?: number\n): Promise<number | null> {\n const parser = await getRobotsParser(url, timeout);\n const delay = parser.getCrawlDelay(BOT_USER_AGENT);\n return delay === undefined ? null : delay;\n}\n\n/**\n * Clear the robots.txt cache. Exported for testing.\n */\nexport function clearRobotsCache(): void {\n cache.clear();\n}\n","/**\n * Sitemap parser\n *\n * Fetches and parses sitemap.xml for crawl mode seed URLs.\n * Regex-based XML parsing — no XML parser dependency.\n * Handles sitemap index files with recursion limit.\n * Mirrors robots.ts fetch+cache+fail-open pattern.\n */\n\nconst DEFAULT_TIMEOUT_MS = 10000;\nconst DEFAULT_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst MAX_RECURSION_DEPTH = 2;\n\n/**\n * A single entry from a sitemap\n */\nexport interface SitemapEntry {\n /** URL from <loc> tag */\n loc: string;\n /** Last modification date from <lastmod> tag */\n lastmod?: string;\n /** Priority from <priority> tag (0.0 to 1.0) */\n priority?: number;\n}\n\ninterface SitemapCacheEntry {\n entries: SitemapEntry[];\n expiresAt: number;\n}\n\nconst cache = new Map<string, SitemapCacheEntry>();\n\n/**\n * Extract origin (protocol + host) from URL\n */\nfunction getOrigin(url: string): string {\n const parsed = new URL(url);\n return `${parsed.protocol}//${parsed.host}`;\n}\n\n/**\n * Check if XML contains a sitemap index\n */\nfunction isSitemapIndex(xml: string): boolean {\n return /<sitemapindex[\\s>]/i.test(xml);\n}\n\n/**\n * Extract sitemap URLs from a sitemap index\n * Handles namespace prefixes: <ns:loc>, <sitemap:loc>, etc.\n */\nfunction extractSitemapIndexUrls(xml: string): string[] {\n const urls: string[] = [];\n // Match <sitemap>...</sitemap> blocks, then extract <loc> from each\n const sitemapBlockRegex = /<(?:\\w+:)?sitemap\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?sitemap>/gi;\n let blockMatch;\n\n while ((blockMatch = sitemapBlockRegex.exec(xml)) !== null) {\n const block = blockMatch[1];\n const locMatch = /<(?:\\w+:)?loc\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?loc>/i.exec(block);\n if (locMatch) {\n const url = locMatch[1].trim();\n if (url) urls.push(url);\n }\n }\n\n return urls;\n}\n\n/**\n * Extract URL entries from a sitemap urlset\n * Handles namespace prefixes: <ns:url>, <ns:loc>, etc.\n */\nfunction extractUrlEntries(xml: string, origin: string): SitemapEntry[] {\n const entries: SitemapEntry[] = [];\n // Match <url>...</url> blocks\n const urlBlockRegex = /<(?:\\w+:)?url\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?url>/gi;\n let blockMatch;\n\n while ((blockMatch = urlBlockRegex.exec(xml)) !== null) {\n const block = blockMatch[1];\n\n // Extract <loc>\n const locMatch = /<(?:\\w+:)?loc\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?loc>/i.exec(block);\n if (!locMatch) continue;\n\n const loc = locMatch[1].trim();\n if (!loc) continue;\n\n // Same-origin filter\n try {\n if (getOrigin(loc) !== origin) continue;\n } catch {\n continue; // Invalid URL — skip\n }\n\n const entry: SitemapEntry = { loc };\n\n // Extract optional <lastmod>\n const lastmodMatch = /<(?:\\w+:)?lastmod\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?lastmod>/i.exec(block);\n if (lastmodMatch) {\n const lastmod = lastmodMatch[1].trim();\n if (lastmod) entry.lastmod = lastmod;\n }\n\n // Extract optional <priority>\n const priorityMatch = /<(?:\\w+:)?priority\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?priority>/i.exec(block);\n if (priorityMatch) {\n const priority = parseFloat(priorityMatch[1].trim());\n if (!isNaN(priority)) entry.priority = priority;\n }\n\n entries.push(entry);\n }\n\n return entries;\n}\n\n/**\n * Fetch sitemap XML with timeout\n */\nasync function fetchSitemapXml(\n url: string,\n timeout: number\n): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(url, {\n signal: controller.signal,\n headers: { 'User-Agent': 'ScraperBot/1.0' },\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) return null;\n\n return await response.text();\n } catch {\n return null; // Fail-open\n }\n}\n\n/**\n * Internal recursive parser with depth tracking\n */\nasync function parseSitemapInternal(\n url: string,\n origin: string,\n timeout: number,\n depth: number\n): Promise<SitemapEntry[]> {\n if (depth >= MAX_RECURSION_DEPTH) return [];\n\n const xml = await fetchSitemapXml(url, timeout);\n if (!xml) return [];\n\n // Check if this is a sitemap index\n if (isSitemapIndex(xml)) {\n const sitemapUrls = extractSitemapIndexUrls(xml);\n const allEntries: SitemapEntry[] = [];\n\n for (const sitemapUrl of sitemapUrls) {\n const entries = await parseSitemapInternal(\n sitemapUrl,\n origin,\n timeout,\n depth + 1\n );\n allEntries.push(...entries);\n }\n\n return allEntries;\n }\n\n // Regular sitemap — extract URL entries\n return extractUrlEntries(xml, origin);\n}\n\n/**\n * Parse a sitemap.xml and return URL entries.\n *\n * - Fetches the sitemap from the given URL\n * - Extracts <loc> URLs via regex (no XML parser dependency)\n * - Handles sitemap index files (recursive, max depth 2)\n * - Caches results per URL with 1-hour TTL\n * - Fail-open: returns empty array if sitemap is unreachable or invalid\n * - Filters to same-origin URLs only\n *\n * @param url - Full URL of the sitemap.xml\n * @param timeout - Fetch timeout in ms (default: 10000)\n * @returns Array of SitemapEntry objects\n */\nexport async function parseSitemap(\n url: string,\n timeout: number = DEFAULT_TIMEOUT_MS\n): Promise<SitemapEntry[]> {\n // Check cache\n const cached = cache.get(url);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.entries;\n }\n\n let origin: string;\n try {\n origin = getOrigin(url);\n } catch {\n return []; // Invalid URL — fail-open\n }\n\n const entries = await parseSitemapInternal(url, origin, timeout, 0);\n\n // Cache the result\n cache.set(url, {\n entries,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n\n return entries;\n}\n\n/**\n * Clear the sitemap cache. Exported for testing.\n */\nexport function clearSitemapCache(): void {\n cache.clear();\n}\n","/**\n * Mode-aware fetch routing with challenge detection.\n *\n * Shared between scrape() (index.ts) and crawl() (crawl.ts)\n * to avoid duplicating mode routing and challenge detection logic.\n */\n\nimport type { FetchResult, FetchMode } from './types.js';\nimport type { FetchOptions } from './fetch.js';\nimport { fetchUrl, FetchError } from './fetch.js';\nimport { fetchStealth } from './fetch-stealth.js';\nimport { fetchRender } from './fetch-render.js';\n\nconst CHALLENGE_MARKERS = [\n 'cf-browser-verification',\n 'Just a moment',\n '_cf_chl_opt',\n 'akamai-challenge',\n 'ak-challenge',\n];\n\n/**\n * Detect anti-bot challenge pages that return HTTP 200 but contain\n * challenge/verification HTML instead of real content.\n */\nexport function isChallengeResponse(fetchResult: FetchResult): boolean {\n return CHALLENGE_MARKERS.some(marker => fetchResult.html.includes(marker));\n}\n\n/**\n * Fetch a URL using the specified mode with auto-fallback support.\n *\n * Modes:\n * - 'fast': Tier 1 only (plain HTTP)\n * - 'stealth': Tier 2 only (TLS fingerprint)\n * - 'render': Tier 3 only (Playwright)\n * - 'auto': Fast first, fall back to stealth on 403 or challenge page\n */\nconst VALID_MODES: readonly string[] = ['fast', 'stealth', 'render', 'auto'];\n\nexport async function fetchWithMode(\n url: string,\n mode: FetchMode,\n options: FetchOptions,\n): Promise<FetchResult> {\n if (!VALID_MODES.includes(mode)) {\n throw new FetchError(\n `Invalid fetch mode: '${mode}'. Valid modes: ${VALID_MODES.join(', ')}`,\n undefined,\n false,\n );\n }\n\n if (mode === 'stealth') return fetchStealth(url, options);\n if (mode === 'render') return fetchRender(url, options);\n if (mode === 'fast') return fetchUrl(url, options);\n\n // auto: fast with fallback to stealth on 403 or challenge\n try {\n const result = await fetchUrl(url, options);\n if (isChallengeResponse(result)) {\n return fetchStealth(url, options);\n }\n return result;\n } catch (err) {\n if (err instanceof FetchError && err.statusCode === 403) {\n return fetchStealth(url, options);\n }\n throw err;\n }\n}\n","/**\n * Crawl: BFS multi-page orchestrator\n * TKT-SCRAPER-079: Crawl multiple pages from a starting URL\n *\n * Composes: sitemap seeding, robots.txt, link extraction, URL normalization,\n * depth/limit/filter constraints, concurrency, and scrape pipeline per page.\n */\n\nimport type {\n CrawlOptions,\n CrawlResult,\n CrawlPageResult,\n CrawlError,\n} from './types.js';\nimport { FetchError } from './fetch.js';\nimport { extractContent } from './extract.js';\nimport { convertToMarkdown } from './convert.js';\nimport { isAllowedByRobots, getCrawlDelay } from './robots.js';\nimport { parseSitemap } from './sitemap.js';\nimport { fetchWithMode } from './fetch-mode.js';\n\n// ============================================\n// URL utilities\n// ============================================\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nexport function normalizeUrl(url: string): string {\n try {\n const parsed = new URL(url);\n parsed.hash = '';\n let pathname = parsed.pathname;\n if (pathname.length > 1 && pathname.endsWith('/')) {\n pathname = pathname.slice(0, -1);\n }\n parsed.pathname = pathname;\n return parsed.toString();\n } catch {\n return url;\n }\n}\n\nconst SKIP_EXTENSIONS = new Set([\n '.pdf', '.jpg', '.jpeg', '.png', '.gif', '.svg', '.webp', '.ico',\n '.mp4', '.mp3', '.wav', '.avi',\n '.zip', '.tar', '.gz', '.rar',\n '.css', '.js', '.xml', '.json', '.woff', '.woff2', '.ttf', '.eot',\n]);\n\nexport function extractLinks(html: string, baseUrl: string): string[] {\n const links: string[] = [];\n let origin: string;\n try {\n origin = new URL(baseUrl).origin;\n } catch {\n return [];\n }\n\n const regex = /<a\\s+[^>]*href\\s*=\\s*[\"']([^\"']+)[\"'][^>]*>/gi;\n let match;\n while ((match = regex.exec(html)) !== null) {\n const href = match[1].trim();\n if (\n href.startsWith('mailto:') ||\n href.startsWith('tel:') ||\n href.startsWith('javascript:') ||\n href.startsWith('#')\n ) continue;\n\n try {\n const resolved = new URL(href, baseUrl);\n if (resolved.origin !== origin) continue;\n\n const ext = resolved.pathname.toLowerCase().match(/\\.\\w+$/)?.[0];\n if (ext && SKIP_EXTENSIONS.has(ext)) continue;\n\n links.push(normalizeUrl(resolved.toString()));\n } catch {\n // Invalid URL, skip\n }\n }\n\n return [...new Set(links)];\n}\n\n// ============================================\n// URL filtering\n// ============================================\n\nfunction matchGlob(url: string, pattern: string): boolean {\n const regex = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n .replace(/\\*\\*/g, '{{DOUBLESTAR}}')\n .replace(/\\*/g, '[^/]*')\n .replace(/\\{\\{DOUBLESTAR\\}\\}/g, '.*');\n return new RegExp(regex).test(url);\n}\n\nfunction matchesFilter(url: string, include?: string[], exclude?: string[]): boolean {\n if (exclude?.length) {\n for (const pattern of exclude) {\n if (matchGlob(url, pattern)) return false;\n }\n }\n if (include?.length) {\n return include.some(pattern => matchGlob(url, pattern));\n }\n return true;\n}\n\n// ============================================\n// Crawl\n// ============================================\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nexport async function crawl(options: CrawlOptions): Promise<CrawlResult> {\n const startTime = Date.now();\n\n const {\n url: startUrl,\n depth: maxDepth = 2,\n limit = 50,\n mode = 'auto',\n include,\n exclude,\n timeout,\n concurrency = 3,\n respectRobots = true,\n } = options;\n\n // Validation\n if (!isValidUrl(startUrl)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n if (maxDepth < 0) throw new FetchError('depth must be >= 0', undefined, false);\n if (limit < 1) throw new FetchError('limit must be >= 1', undefined, false);\n if (concurrency < 1) throw new FetchError('concurrency must be >= 1', undefined, false);\n if (timeout !== undefined && (timeout <= 0 || Number.isNaN(timeout))) {\n throw new FetchError('timeout must be a positive number', undefined, false);\n }\n\n const pages: CrawlPageResult[] = [];\n const errors: CrawlError[] = [];\n const visited = new Set<string>();\n let totalDiscovered = 0;\n let totalSkipped = 0;\n\n const normalizedStart = normalizeUrl(startUrl);\n const origin = new URL(startUrl).origin;\n\n // Robots.txt + crawl delay\n let crawlDelay: number | null = null;\n if (respectRobots) {\n crawlDelay = await getCrawlDelay(startUrl, timeout);\n const allowed = await isAllowedByRobots(startUrl, timeout);\n if (!allowed) {\n return {\n pages: [],\n totalDiscovered: 1,\n totalCrawled: 0,\n totalSkipped: 1,\n errors: [],\n duration: Date.now() - startTime,\n };\n }\n }\n\n // Seed: start URL + sitemap URLs\n const queue: Array<{ url: string; depth: number }> = [\n { url: normalizedStart, depth: 0 },\n ];\n\n if (maxDepth > 0) {\n try {\n const sitemapEntries = await parseSitemap(`${origin}/sitemap.xml`, timeout);\n const seen = new Set<string>([normalizedStart]);\n for (const entry of sitemapEntries) {\n const normalized = normalizeUrl(entry.loc);\n if (!seen.has(normalized)) {\n seen.add(normalized);\n queue.push({ url: normalized, depth: 1 });\n }\n }\n } catch (err) {\n console.debug(`[scraper] Sitemap unavailable for ${origin}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n totalDiscovered = queue.length;\n\n // BFS loop\n while (queue.length > 0 && pages.length < limit) {\n const batchSize = Math.min(concurrency, limit - pages.length, queue.length);\n const batch = queue.splice(0, batchSize);\n\n const tasks = batch.map(async ({ url, depth }) => {\n const normalized = normalizeUrl(url);\n\n if (visited.has(normalized)) {\n totalSkipped++;\n return;\n }\n visited.add(normalized);\n\n // URL filter check (start URL is exempt — it's the user's explicit seed)\n if (normalized !== normalizedStart && !matchesFilter(normalized, include, exclude)) {\n totalSkipped++;\n return;\n }\n\n // Per-URL robots check\n if (respectRobots) {\n const allowed = await isAllowedByRobots(url, timeout);\n if (!allowed) {\n totalSkipped++;\n return;\n }\n }\n\n try {\n const fetchResult = await fetchWithMode(url, mode, { timeout });\n const extractResult = await extractContent(fetchResult);\n const convertResult = await convertToMarkdown(extractResult);\n\n const pageResult: CrawlPageResult = {\n markdown: convertResult.markdown,\n tokenCount: convertResult.tokenCount,\n title: extractResult.title,\n author: extractResult.author,\n siteName: extractResult.siteName,\n publishedAt: extractResult.publishedAt,\n url: fetchResult.url,\n depth,\n };\n\n pages.push(pageResult);\n\n // Extract links for next depth level\n if (depth < maxDepth) {\n const links = extractLinks(fetchResult.html, fetchResult.url);\n for (const link of links) {\n if (!visited.has(link)) {\n queue.push({ url: link, depth: depth + 1 });\n totalDiscovered++;\n }\n }\n }\n } catch (err) {\n errors.push({\n url,\n error: err instanceof Error ? err.message : String(err),\n depth,\n });\n }\n });\n\n await Promise.allSettled(tasks);\n\n // Crawl delay between batches\n if (crawlDelay && crawlDelay > 0 && queue.length > 0) {\n await sleep(crawlDelay * 1000);\n }\n }\n\n return {\n pages,\n totalDiscovered,\n totalCrawled: pages.length,\n totalSkipped,\n errors,\n duration: Date.now() - startTime,\n };\n}\n","/**\n * Platform telemetry reporter for scraper.\n *\n * Reads the API key from ~/.robot-resources/config.json and sends\n * telemetry events to the RR platform API. Fire-and-forget — never\n * blocks the scrape() pipeline.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst CONFIG_PATH = join(homedir(), '.robot-resources', 'config.json');\nconst PLATFORM_URL = process.env.RR_PLATFORM_URL || 'https://api.robotresources.ai';\n\nlet apiKey: string | null = null;\nlet keyLoaded = false;\n\nfunction loadApiKey(): string | null {\n if (keyLoaded) return apiKey;\n keyLoaded = true;\n\n // Environment-level opt-out — checked before reading config\n if (process.env.RR_TELEMETRY === 'off') {\n return null;\n }\n\n try {\n const config = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));\n\n // Config-level opt-out\n if (config.telemetry === false) {\n return null;\n }\n\n apiKey = config.api_key || null;\n return apiKey;\n } catch {\n return null;\n }\n}\n\nexport interface ScraperTelemetryPayload {\n url: string;\n tokenCount: number;\n title?: string;\n latencyMs: number;\n success: boolean;\n error?: string;\n}\n\n/**\n * Report a scrape() call to the platform. Fire-and-forget.\n */\nexport function reportScraperEvent(payload: ScraperTelemetryPayload): void {\n const key = loadApiKey();\n if (!key) return;\n\n // Fire-and-forget — no await, catch silently\n fetch(`${PLATFORM_URL}/v1/telemetry`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${key}`,\n },\n body: JSON.stringify({\n product: 'scraper',\n event_type: payload.success ? 'compress' : 'error',\n payload,\n }),\n }).catch(() => {\n // Silent — telemetry must never break the pipeline\n });\n}\n","/**\n * scraper\n * Context compression for AI agents\n *\n * @packageDocumentation\n */\n\n// Re-export types\nexport type {\n FetchMode,\n ScrapeOptions,\n ScrapeResult,\n FetchResult,\n ExtractResult,\n ConvertResult,\n CrawlOptions,\n CrawlResult,\n CrawlPageResult,\n CrawlError,\n} from './types.js';\n\n// Re-export layers for advanced usage\nexport { fetchUrl, FetchError } from './fetch.js';\nexport { fetchStealth } from './fetch-stealth.js';\nexport { fetchRender } from './fetch-render.js';\nexport { extractContent, ExtractionError } from './extract.js';\nexport { convertToMarkdown, estimateTokens } from './convert.js';\nexport {\n isAllowedByRobots,\n clearRobotsCache,\n getSitemapUrls,\n getCrawlDelay,\n} from './robots.js';\nexport { parseSitemap, clearSitemapCache } from './sitemap.js';\nexport type { SitemapEntry } from './sitemap.js';\nexport { crawl, normalizeUrl, extractLinks } from './crawl.js';\nexport { isChallengeResponse, fetchWithMode } from './fetch-mode.js';\n\n// Import for composition\nimport type { ScrapeOptions, ScrapeResult, FetchMode } from './types.js';\nimport { FetchError } from './fetch.js';\nimport { extractContent } from './extract.js';\nimport { convertToMarkdown } from './convert.js';\nimport { isAllowedByRobots } from './robots.js';\nimport { reportScraperEvent } from './telemetry.js';\nimport { fetchWithMode } from './fetch-mode.js';\n\n/**\n * Compress web content for AI agents\n *\n * Pipeline: Fetch -> Extract -> Convert\n * No LLM dependency. Reduces tokens by 70-80%.\n *\n * @example\n * ```typescript\n * import { scrape } from '@robot-resources/scraper';\n *\n * const result = await scrape('https://example.com/article');\n * console.log(result.markdown);\n * console.log(result.tokenCount);\n * ```\n *\n * @param url - URL to fetch and compress\n * @param options - Optional configuration\n * @returns Compressed content with metadata\n */\nexport async function scrape(\n url: string,\n options: ScrapeOptions = {}\n): Promise<ScrapeResult> {\n const startTime = Date.now();\n\n const mode: FetchMode = options.mode ?? 'auto';\n\n // Validate timeout at public boundary (MCP has Zod, but SDK callers don't)\n if (options.timeout !== undefined && (options.timeout <= 0 || Number.isNaN(options.timeout))) {\n throw new FetchError('timeout must be a positive number', undefined, false);\n }\n\n try {\n // robots.txt check (opt-in, independent of mode)\n if (options.respectRobots) {\n const allowed = await isAllowedByRobots(url, options.timeout);\n if (!allowed) {\n throw new FetchError(`Blocked by robots.txt: ${url}`, undefined, false);\n }\n }\n\n // Layer 1: Fetch (mode-aware with auto-fallback)\n const fetchResult = await fetchWithMode(url, mode, {\n timeout: options.timeout,\n maxRetries: options.maxRetries,\n userAgent: options.userAgent,\n });\n\n // Layer 2: Extract\n const extractResult = await extractContent(fetchResult);\n\n // Layer 3: Convert\n const convertResult = await convertToMarkdown(extractResult);\n\n const result: ScrapeResult = {\n markdown: convertResult.markdown,\n tokenCount: convertResult.tokenCount,\n title: extractResult.title,\n author: extractResult.author,\n siteName: extractResult.siteName,\n publishedAt: extractResult.publishedAt,\n url: fetchResult.url,\n };\n\n // Report telemetry (fire-and-forget)\n reportScraperEvent({\n url,\n tokenCount: convertResult.tokenCount,\n title: extractResult.title,\n latencyMs: Date.now() - startTime,\n success: true,\n });\n\n return result;\n } catch (err) {\n // Report error telemetry (fire-and-forget)\n reportScraperEvent({\n url,\n tokenCount: 0,\n latencyMs: Date.now() - startTime,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n });\n\n throw err;\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/fetch.ts","../src/fetch-stealth.ts","../src/fetch-render.ts","../src/extract.ts","../src/convert.ts","../src/robots.ts","../src/sitemap.ts","../src/fetch-mode.ts","../src/crawl.ts","../src/telemetry.ts","../src/index.ts"],"names":["DEFAULT_TIMEOUT","DEFAULT_MAX_RETRIES","BASE_BACKOFF_MS","isValidUrl","isRetryableStatus","sleep","getBackoffDelay","parseHTML","Readability","TurndownService","robotsParser","DEFAULT_TIMEOUT_MS","DEFAULT_TTL_MS","cache","join","homedir","readFileSync"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Layer 1: Fetch\n * HTTP fetching with smart headers and retries\n */\n\nimport type { FetchResult } from './types.js';\n\nconst USER_AGENTS = [\n 'Mozilla/5.0 (compatible; ScraperBot/1.0; +https://scraper.robotresources.ai)',\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n];\n\nconst DEFAULT_TIMEOUT = 10000;\nconst DEFAULT_MAX_RETRIES = 3;\nconst BASE_BACKOFF_MS = 1000;\n\nexport interface FetchOptions {\n timeout?: number;\n maxRetries?: number;\n userAgent?: string;\n}\n\n/**\n * Error class for fetch-related errors\n */\nexport class FetchError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly retryable: boolean = false\n ) {\n super(message);\n this.name = 'FetchError';\n }\n}\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nfunction getRandomUserAgent(): string {\n return USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];\n}\n\nfunction buildHeaders(userAgent?: string): Record<string, string> {\n return {\n 'User-Agent': userAgent || getRandomUserAgent(),\n Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n 'Accept-Language': 'en-US,en;q=0.9',\n 'Accept-Encoding': 'gzip, deflate',\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n };\n}\n\nfunction headersToObject(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key.toLowerCase()] = value;\n });\n return result;\n}\n\nfunction isRetryableStatus(status: number): boolean {\n return status >= 500 && status < 600;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction getBackoffDelay(attempt: number): number {\n return BASE_BACKOFF_MS * Math.pow(2, attempt);\n}\n\nasync function fetchWithTimeout(\n url: string,\n headers: Record<string, string>,\n timeout: number\n): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers,\n signal: controller.signal,\n redirect: 'follow',\n });\n return response;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new FetchError('Request timeout', undefined, true);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\n/**\n * Fetch URL content with smart headers and retry logic\n */\nexport async function fetchUrl(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const {\n timeout = DEFAULT_TIMEOUT,\n maxRetries = DEFAULT_MAX_RETRIES,\n userAgent,\n } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n const headers = buildHeaders(userAgent);\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await fetchWithTimeout(url, headers, timeout);\n\n if (!response.ok) {\n const statusCode = response.status;\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (isRetryableStatus(statusCode)) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n }\n\n const html = await response.text();\n const responseHeaders = headersToObject(response.headers);\n\n return {\n html,\n url: response.url,\n statusCode: response.status,\n headers: responseHeaders,\n };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n const isRetryable =\n error instanceof FetchError\n ? error.retryable\n : !(error instanceof FetchError);\n\n const hasRetriesLeft = attempt < maxRetries;\n\n if (isRetryable && hasRetriesLeft) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n\n break;\n }\n }\n\n throw lastError || new FetchError('Unknown fetch error');\n}\n","/**\n * Layer 1b: Stealth Fetch\n * TLS fingerprint impersonation via impit (optional peer dependency)\n *\n * Uses Rust-based browser TLS fingerprinting to bypass anti-bot systems\n * (Cloudflare, Akamai, PerimeterX) without a full browser.\n *\n * Requires: npm install impit (Node >= 20)\n */\n\nimport type { FetchResult } from './types.js';\nimport { FetchError } from './fetch.js';\nimport type { FetchOptions } from './fetch.js';\n\nconst DEFAULT_TIMEOUT = 10000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst BASE_BACKOFF_MS = 1000;\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nfunction isRetryableStatus(status: number): boolean {\n return status >= 500 && status < 600;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction getBackoffDelay(attempt: number): number {\n return BASE_BACKOFF_MS * Math.pow(2, attempt);\n}\n\n/**\n * Fetch URL with browser TLS fingerprint impersonation.\n *\n * Uses impit (Apify) to produce Chrome-like JA3/JA4 fingerprints at the\n * TLS handshake level. This bypasses anti-bot systems that reject default\n * Node.js TLS signatures.\n *\n * impit is an optional peer dependency — if not installed, throws a clear\n * error message with install instructions.\n */\nexport async function fetchStealth(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const {\n timeout = DEFAULT_TIMEOUT,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n // Dynamic import — impit is an optional peer dependency\n let Impit: any;\n try {\n // @ts-expect-error impit is an optional peer dependency (not installed in dev)\n ({ Impit } = await import('impit'));\n } catch {\n throw new FetchError(\n 'impit is required for stealth mode. Install: npm install impit (requires Node >= 20)',\n undefined,\n false\n );\n }\n\n const client = new Impit({ browser: 'chrome' });\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await client.fetch(url, {\n signal: AbortSignal.timeout(timeout),\n });\n\n if (!response.ok) {\n const statusCode = response.status;\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (isRetryableStatus(statusCode)) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n }\n\n const html = await response.text();\n const headers: Record<string, string> = {};\n response.headers.forEach((value: string, key: string) => {\n headers[key] = value;\n });\n\n return {\n html,\n url: response.url ?? url,\n statusCode: response.status,\n headers,\n };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n const isRetryable =\n error instanceof FetchError\n ? error.retryable\n : !(error instanceof FetchError);\n\n const hasRetriesLeft = attempt < maxRetries;\n\n if (isRetryable && hasRetriesLeft) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n\n break;\n }\n }\n\n throw lastError || new FetchError('Unknown stealth fetch error');\n}\n","/**\n * Layer 1c: Render Fetch\n * Playwright headless browser for JS-rendered pages (optional peer dependency)\n *\n * Uses Chromium to fully render SPAs (React, Next.js, Vue) that return\n * empty/partial HTML to tiers 1 and 2. Extracts the fully rendered DOM.\n *\n * Requires: npm install playwright\n */\n\nimport type { FetchResult } from './types.js';\nimport { FetchError } from './fetch.js';\nimport type { FetchOptions } from './fetch.js';\n\nconst DEFAULT_TIMEOUT = 30000;\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\n/**\n * Fetch URL using a headless Chromium browser to render JavaScript.\n *\n * Launches a fresh browser per call (no shared state), navigates to the URL,\n * waits for network idle, then extracts the fully rendered HTML.\n *\n * Playwright is an optional peer dependency — if not installed, throws a clear\n * error message with install instructions.\n */\nexport async function fetchRender(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const { timeout = DEFAULT_TIMEOUT } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n // Dynamic import — Playwright is an optional peer dependency\n let chromium: any;\n try {\n // @ts-expect-error playwright is an optional peer dependency (not installed in dev)\n ({ chromium } = await import('playwright'));\n } catch {\n throw new FetchError(\n 'Playwright is required for render mode. Install: npm install playwright',\n undefined,\n false\n );\n }\n\n const browser = await chromium.launch({ headless: true });\n\n try {\n const page = await browser.newPage();\n\n // Auto-dismiss dialogs to prevent hanging\n page.on('dialog', (dialog: any) => dialog.dismiss());\n\n const response = await page.goto(url, {\n waitUntil: 'networkidle',\n timeout,\n });\n\n if (!response) {\n throw new FetchError(\n 'Navigation returned no response (about:blank or same-URL redirect)',\n undefined,\n false\n );\n }\n\n const statusCode = response.status();\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (statusCode >= 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n\n const html = await page.content();\n const headers: Record<string, string> = response.headers();\n\n return {\n html,\n url: page.url(),\n statusCode,\n headers,\n };\n } catch (error) {\n // Convert Playwright timeout errors to retryable FetchErrors\n if (error instanceof Error && error.name === 'TimeoutError') {\n throw new FetchError('Navigation timeout', undefined, true);\n }\n throw error;\n } finally {\n await browser.close();\n }\n}\n","/**\n * Layer 2: Extract\n * Content extraction using Readability\n */\n\nimport { Readability } from '@mozilla/readability';\nimport { parseHTML } from 'linkedom';\nimport type { FetchResult, ExtractResult } from './types.js';\n\n/**\n * Error class for extraction-related errors\n */\nexport class ExtractionError extends Error {\n constructor(\n message: string,\n public readonly code: string\n ) {\n super(message);\n this.name = 'ExtractionError';\n }\n}\n\n/**\n * Extract main content from HTML using Readability\n */\nexport async function extractContent(\n fetchResult: FetchResult\n): Promise<ExtractResult> {\n const { html } = fetchResult;\n\n if (!html || !html.trim()) {\n throw new ExtractionError('Empty HTML content', 'EMPTY_HTML');\n }\n\n const { document } = parseHTML(html);\n\n const reader = new Readability(document, {\n charThreshold: 50,\n });\n\n const article = reader.parse();\n\n if (!article || !article.content || article.content.trim().length < 20) {\n throw new ExtractionError(\n 'No content could be extracted from the page',\n 'NO_CONTENT'\n );\n }\n\n const result: ExtractResult = {\n content: cleanContent(article.content),\n title: article.title || extractFallbackTitle(document),\n author: article.byline || undefined,\n publishedAt: article.publishedTime || extractPublishedTime(document),\n siteName: article.siteName || extractSiteName(document),\n };\n\n return result;\n}\n\nfunction cleanContent(content: string): string {\n return content\n .replace(/>\\s+</g, '><')\n .replace(/\\s{2,}/g, ' ')\n .trim();\n}\n\nfunction extractFallbackTitle(document: Document): string | undefined {\n const ogTitle = document.querySelector('meta[property=\"og:title\"]');\n if (ogTitle) {\n const content = ogTitle.getAttribute('content');\n if (content) return content;\n }\n\n const titleEl = document.querySelector('title');\n if (titleEl && titleEl.textContent) {\n return titleEl.textContent.trim();\n }\n\n const h1 = document.querySelector('h1');\n if (h1 && h1.textContent) {\n return h1.textContent.trim();\n }\n\n return undefined;\n}\n\nfunction extractPublishedTime(document: Document): string | undefined {\n const ogTime = document.querySelector(\n 'meta[property=\"article:published_time\"]'\n );\n if (ogTime) {\n const content = ogTime.getAttribute('content');\n if (content) return content;\n }\n\n const schemaTime = document.querySelector('[itemprop=\"datePublished\"]');\n if (schemaTime) {\n const datetime = schemaTime.getAttribute('datetime');\n if (datetime) return datetime;\n const content = schemaTime.getAttribute('content');\n if (content) return content;\n }\n\n const timeEl = document.querySelector('time[datetime]');\n if (timeEl) {\n const datetime = timeEl.getAttribute('datetime');\n if (datetime) return datetime;\n }\n\n return undefined;\n}\n\nfunction extractSiteName(document: Document): string | undefined {\n const ogSiteName = document.querySelector('meta[property=\"og:site_name\"]');\n if (ogSiteName) {\n const content = ogSiteName.getAttribute('content');\n if (content) return content;\n }\n\n const appName = document.querySelector('meta[name=\"application-name\"]');\n if (appName) {\n const content = appName.getAttribute('content');\n if (content) return content;\n }\n\n return undefined;\n}\n","/**\n * Layer 3: Convert\n * HTML to Markdown conversion\n */\n\nimport TurndownService from 'turndown';\nimport type { ExtractResult, ConvertResult } from './types.js';\n\nfunction createTurndownService(): TurndownService {\n const turndown = new TurndownService({\n headingStyle: 'atx',\n hr: '---',\n bulletListMarker: '-',\n codeBlockStyle: 'fenced',\n fence: '```',\n emDelimiter: '*',\n strongDelimiter: '**',\n linkStyle: 'inlined',\n });\n\n turndown.remove(['script', 'style', 'noscript', 'iframe']);\n\n turndown.addRule('removeEmpty', {\n filter: (node) => {\n if (node.nodeType === 1) {\n const text = node.textContent || '';\n const isEmptyBlock =\n text.trim() === '' &&\n !['IMG', 'BR', 'HR', 'INPUT'].includes(node.nodeName);\n return isEmptyBlock;\n }\n return false;\n },\n replacement: () => '',\n });\n\n turndown.addRule('fencedCodeBlock', {\n filter: (node, options) => {\n return (\n options.codeBlockStyle === 'fenced' &&\n node.nodeName === 'PRE' &&\n node.firstChild !== null &&\n node.firstChild.nodeName === 'CODE'\n );\n },\n replacement: (_content, node, options) => {\n const codeNode = node.firstChild as Element;\n const code = codeNode.textContent || '';\n\n const className = codeNode.getAttribute('class') || '';\n const langMatch = className.match(/language-(\\w+)/);\n const lang = langMatch ? langMatch[1] : '';\n\n const fence = options.fence || '```';\n return `\\n\\n${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n },\n });\n\n turndown.addRule('strikethrough', {\n filter: ['del', 's'] as const,\n replacement: (content) => `~~${content}~~`,\n });\n\n return turndown;\n}\n\nlet turndownInstance: TurndownService | null = null;\n\nfunction getTurndown(): TurndownService {\n if (!turndownInstance) {\n turndownInstance = createTurndownService();\n }\n return turndownInstance;\n}\n\nfunction cleanMarkdown(markdown: string): string {\n return markdown\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/[ \\t]+$/gm, '')\n .replace(/^\\n+/, '')\n .replace(/\\n+$/, '')\n .trim();\n}\n\n/**\n * Convert extracted HTML to clean Markdown\n */\nexport async function convertToMarkdown(\n extractResult: ExtractResult\n): Promise<ConvertResult> {\n const { content } = extractResult;\n\n if (!content || !content.trim()) {\n return {\n markdown: '',\n tokenCount: 0,\n };\n }\n\n const turndown = getTurndown();\n let markdown = turndown.turndown(content);\n\n markdown = cleanMarkdown(markdown);\n\n const tokenCount = estimateTokens(markdown);\n\n return {\n markdown,\n tokenCount,\n };\n}\n\n/**\n * Content-aware token estimator.\n *\n * Segments text by content type and applies calibrated character-per-token\n * ratios derived from cl100k_base (GPT-4) empirical measurements.\n *\n * Ratios:\n * Code blocks — 3.2 chars/token (operators, camelCase split into subwords)\n * Inline code — 3.5 chars/token (variable names, short expressions)\n * URLs — 5.0 chars/token (path segments tokenize efficiently)\n * Prose — 4.3 chars/token (words, punctuation, markdown formatting)\n *\n * Accuracy: within ±15% of actual BPE tokenization for English content.\n */\nexport function estimateTokens(text: string): number {\n if (!text) return 0;\n\n let tokens = 0;\n let remaining = text;\n\n // Code blocks: operators, identifiers → ~3.2 chars per token\n remaining = remaining.replace(/```[\\s\\S]*?```/g, (match) => {\n tokens += Math.ceil(match.length / 3.2);\n return ' ';\n });\n\n // Inline code: variables, short expressions → ~3.5 chars per token\n remaining = remaining.replace(/`[^`]+`/g, (match) => {\n tokens += Math.ceil(match.length / 3.5);\n return ' ';\n });\n\n // URLs: path segments, punctuation splitting → ~5.0 chars per token\n remaining = remaining.replace(/https?:\\/\\/\\S+/g, (match) => {\n tokens += Math.ceil(match.length / 5.0);\n return ' ';\n });\n\n // Prose: words, punctuation, markdown formatting → ~4.3 chars per token\n const proseLength = remaining.replace(/\\s+/g, ' ').trim().length;\n if (proseLength > 0) {\n tokens += Math.ceil(proseLength / 4.3);\n }\n\n return Math.max(1, tokens);\n}\n","/**\n * robots.txt compliance layer\n *\n * Opt-in for single-page scraping (respectRobots option),\n * foundation for FTR-ORG-019 crawl mode where it becomes default.\n */\n\nimport robotsParser from 'robots-parser';\n\ninterface RobotsCacheEntry {\n parser: ReturnType<typeof robotsParser>;\n expiresAt: number;\n}\n\nconst DEFAULT_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst BOT_USER_AGENT = 'ScraperBot';\n\nconst cache = new Map<string, RobotsCacheEntry>();\n\nfunction getRobotsUrl(url: string): string {\n const parsed = new URL(url);\n return `${parsed.protocol}//${parsed.host}/robots.txt`;\n}\n\nasync function getRobotsParser(\n url: string,\n timeout: number = DEFAULT_TIMEOUT_MS\n): Promise<ReturnType<typeof robotsParser>> {\n const robotsUrl = getRobotsUrl(url);\n\n const cached = cache.get(robotsUrl);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.parser;\n }\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(robotsUrl, {\n signal: controller.signal,\n headers: { 'User-Agent': BOT_USER_AGENT },\n });\n\n clearTimeout(timeoutId);\n\n const text = response.ok ? await response.text() : '';\n const parser = robotsParser(robotsUrl, text);\n\n cache.set(robotsUrl, {\n parser,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n\n return parser;\n } catch {\n // Fail-open: if robots.txt is unreachable, allow everything\n const parser = robotsParser(robotsUrl, '');\n cache.set(robotsUrl, {\n parser,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n return parser;\n }\n}\n\n/**\n * Check if a URL is allowed by robots.txt.\n * Returns true if allowed or if robots.txt cannot be fetched (fail-open).\n */\nexport async function isAllowedByRobots(\n url: string,\n timeout?: number\n): Promise<boolean> {\n const parser = await getRobotsParser(url, timeout);\n return parser.isAllowed(url, BOT_USER_AGENT) !== false;\n}\n\n/**\n * Extract Sitemap: URLs from robots.txt.\n * Returns empty array if no Sitemap directives or robots.txt unreachable (fail-open).\n * Reuses cached robots.txt parser.\n */\nexport async function getSitemapUrls(\n url: string,\n timeout?: number\n): Promise<string[]> {\n const parser = await getRobotsParser(url, timeout);\n return parser.getSitemaps();\n}\n\n/**\n * Extract Crawl-delay value from robots.txt for ScraperBot user agent.\n * Returns delay in seconds, or null if not specified or robots.txt unreachable (fail-open).\n * Reuses cached robots.txt parser.\n */\nexport async function getCrawlDelay(\n url: string,\n timeout?: number\n): Promise<number | null> {\n const parser = await getRobotsParser(url, timeout);\n const delay = parser.getCrawlDelay(BOT_USER_AGENT);\n return delay === undefined ? null : delay;\n}\n\n/**\n * Clear the robots.txt cache. Exported for testing.\n */\nexport function clearRobotsCache(): void {\n cache.clear();\n}\n","/**\n * Sitemap parser\n *\n * Fetches and parses sitemap.xml for crawl mode seed URLs.\n * Regex-based XML parsing — no XML parser dependency.\n * Handles sitemap index files with recursion limit.\n * Mirrors robots.ts fetch+cache+fail-open pattern.\n */\n\nconst DEFAULT_TIMEOUT_MS = 10000;\nconst DEFAULT_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst MAX_RECURSION_DEPTH = 2;\n\n/**\n * A single entry from a sitemap\n */\nexport interface SitemapEntry {\n /** URL from <loc> tag */\n loc: string;\n /** Last modification date from <lastmod> tag */\n lastmod?: string;\n /** Priority from <priority> tag (0.0 to 1.0) */\n priority?: number;\n}\n\ninterface SitemapCacheEntry {\n entries: SitemapEntry[];\n expiresAt: number;\n}\n\nconst cache = new Map<string, SitemapCacheEntry>();\n\n/**\n * Extract origin (protocol + host) from URL\n */\nfunction getOrigin(url: string): string {\n const parsed = new URL(url);\n return `${parsed.protocol}//${parsed.host}`;\n}\n\n/**\n * Check if XML contains a sitemap index\n */\nfunction isSitemapIndex(xml: string): boolean {\n return /<sitemapindex[\\s>]/i.test(xml);\n}\n\n/**\n * Extract sitemap URLs from a sitemap index\n * Handles namespace prefixes: <ns:loc>, <sitemap:loc>, etc.\n */\nfunction extractSitemapIndexUrls(xml: string): string[] {\n const urls: string[] = [];\n // Match <sitemap>...</sitemap> blocks, then extract <loc> from each\n const sitemapBlockRegex = /<(?:\\w+:)?sitemap\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?sitemap>/gi;\n let blockMatch;\n\n while ((blockMatch = sitemapBlockRegex.exec(xml)) !== null) {\n const block = blockMatch[1];\n const locMatch = /<(?:\\w+:)?loc\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?loc>/i.exec(block);\n if (locMatch) {\n const url = locMatch[1].trim();\n if (url) urls.push(url);\n }\n }\n\n return urls;\n}\n\n/**\n * Extract URL entries from a sitemap urlset\n * Handles namespace prefixes: <ns:url>, <ns:loc>, etc.\n */\nfunction extractUrlEntries(xml: string, origin: string): SitemapEntry[] {\n const entries: SitemapEntry[] = [];\n // Match <url>...</url> blocks\n const urlBlockRegex = /<(?:\\w+:)?url\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?url>/gi;\n let blockMatch;\n\n while ((blockMatch = urlBlockRegex.exec(xml)) !== null) {\n const block = blockMatch[1];\n\n // Extract <loc>\n const locMatch = /<(?:\\w+:)?loc\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?loc>/i.exec(block);\n if (!locMatch) continue;\n\n const loc = locMatch[1].trim();\n if (!loc) continue;\n\n // Same-origin filter\n try {\n if (getOrigin(loc) !== origin) continue;\n } catch {\n continue; // Invalid URL — skip\n }\n\n const entry: SitemapEntry = { loc };\n\n // Extract optional <lastmod>\n const lastmodMatch = /<(?:\\w+:)?lastmod\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?lastmod>/i.exec(block);\n if (lastmodMatch) {\n const lastmod = lastmodMatch[1].trim();\n if (lastmod) entry.lastmod = lastmod;\n }\n\n // Extract optional <priority>\n const priorityMatch = /<(?:\\w+:)?priority\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?priority>/i.exec(block);\n if (priorityMatch) {\n const priority = parseFloat(priorityMatch[1].trim());\n if (!isNaN(priority)) entry.priority = priority;\n }\n\n entries.push(entry);\n }\n\n return entries;\n}\n\n/**\n * Fetch sitemap XML with timeout\n */\nasync function fetchSitemapXml(\n url: string,\n timeout: number\n): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(url, {\n signal: controller.signal,\n headers: { 'User-Agent': 'ScraperBot/1.0' },\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) return null;\n\n return await response.text();\n } catch {\n return null; // Fail-open\n }\n}\n\n/**\n * Internal recursive parser with depth tracking\n */\nasync function parseSitemapInternal(\n url: string,\n origin: string,\n timeout: number,\n depth: number\n): Promise<SitemapEntry[]> {\n if (depth >= MAX_RECURSION_DEPTH) return [];\n\n const xml = await fetchSitemapXml(url, timeout);\n if (!xml) return [];\n\n // Check if this is a sitemap index\n if (isSitemapIndex(xml)) {\n const sitemapUrls = extractSitemapIndexUrls(xml);\n const allEntries: SitemapEntry[] = [];\n\n for (const sitemapUrl of sitemapUrls) {\n const entries = await parseSitemapInternal(\n sitemapUrl,\n origin,\n timeout,\n depth + 1\n );\n allEntries.push(...entries);\n }\n\n return allEntries;\n }\n\n // Regular sitemap — extract URL entries\n return extractUrlEntries(xml, origin);\n}\n\n/**\n * Parse a sitemap.xml and return URL entries.\n *\n * - Fetches the sitemap from the given URL\n * - Extracts <loc> URLs via regex (no XML parser dependency)\n * - Handles sitemap index files (recursive, max depth 2)\n * - Caches results per URL with 1-hour TTL\n * - Fail-open: returns empty array if sitemap is unreachable or invalid\n * - Filters to same-origin URLs only\n *\n * @param url - Full URL of the sitemap.xml\n * @param timeout - Fetch timeout in ms (default: 10000)\n * @returns Array of SitemapEntry objects\n */\nexport async function parseSitemap(\n url: string,\n timeout: number = DEFAULT_TIMEOUT_MS\n): Promise<SitemapEntry[]> {\n // Check cache\n const cached = cache.get(url);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.entries;\n }\n\n let origin: string;\n try {\n origin = getOrigin(url);\n } catch {\n return []; // Invalid URL — fail-open\n }\n\n const entries = await parseSitemapInternal(url, origin, timeout, 0);\n\n // Cache the result\n cache.set(url, {\n entries,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n\n return entries;\n}\n\n/**\n * Clear the sitemap cache. Exported for testing.\n */\nexport function clearSitemapCache(): void {\n cache.clear();\n}\n","/**\n * Mode-aware fetch routing with challenge detection.\n *\n * Shared between scrape() (index.ts) and crawl() (crawl.ts)\n * to avoid duplicating mode routing and challenge detection logic.\n */\n\nimport type { FetchResult, FetchMode } from './types.js';\nimport type { FetchOptions } from './fetch.js';\nimport { fetchUrl, FetchError } from './fetch.js';\nimport { fetchStealth } from './fetch-stealth.js';\nimport { fetchRender } from './fetch-render.js';\n\nconst CHALLENGE_MARKERS = [\n 'cf-browser-verification',\n 'Just a moment',\n '_cf_chl_opt',\n 'akamai-challenge',\n 'ak-challenge',\n];\n\n/**\n * Detect anti-bot challenge pages that return HTTP 200 but contain\n * challenge/verification HTML instead of real content.\n */\nexport function isChallengeResponse(fetchResult: FetchResult): boolean {\n return CHALLENGE_MARKERS.some(marker => fetchResult.html.includes(marker));\n}\n\n/**\n * Fetch a URL using the specified mode with auto-fallback support.\n *\n * Modes:\n * - 'fast': Tier 1 only (plain HTTP)\n * - 'stealth': Tier 2 only (TLS fingerprint)\n * - 'render': Tier 3 only (Playwright)\n * - 'auto': Fast first, fall back to stealth on 403 or challenge page\n */\nconst VALID_MODES: readonly string[] = ['fast', 'stealth', 'render', 'auto'];\n\nexport async function fetchWithMode(\n url: string,\n mode: FetchMode,\n options: FetchOptions,\n): Promise<FetchResult> {\n if (!VALID_MODES.includes(mode)) {\n throw new FetchError(\n `Invalid fetch mode: '${mode}'. Valid modes: ${VALID_MODES.join(', ')}`,\n undefined,\n false,\n );\n }\n\n if (mode === 'stealth') return fetchStealth(url, options);\n if (mode === 'render') return fetchRender(url, options);\n if (mode === 'fast') return fetchUrl(url, options);\n\n // auto: fast with fallback to stealth on 403 or challenge\n try {\n const result = await fetchUrl(url, options);\n if (isChallengeResponse(result)) {\n return fetchStealth(url, options);\n }\n return result;\n } catch (err) {\n if (err instanceof FetchError && err.statusCode === 403) {\n return fetchStealth(url, options);\n }\n throw err;\n }\n}\n","/**\n * Crawl: BFS multi-page orchestrator\n * TKT-SCRAPER-079: Crawl multiple pages from a starting URL\n *\n * Composes: sitemap seeding, robots.txt, link extraction, URL normalization,\n * depth/limit/filter constraints, concurrency, and scrape pipeline per page.\n */\n\nimport type {\n CrawlOptions,\n CrawlResult,\n CrawlPageResult,\n CrawlError,\n} from './types.js';\nimport { FetchError } from './fetch.js';\nimport { extractContent } from './extract.js';\nimport { convertToMarkdown } from './convert.js';\nimport { isAllowedByRobots, getCrawlDelay } from './robots.js';\nimport { parseSitemap } from './sitemap.js';\nimport { fetchWithMode } from './fetch-mode.js';\n\n// ============================================\n// URL utilities\n// ============================================\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nexport function normalizeUrl(url: string): string {\n try {\n const parsed = new URL(url);\n parsed.hash = '';\n let pathname = parsed.pathname;\n if (pathname.length > 1 && pathname.endsWith('/')) {\n pathname = pathname.slice(0, -1);\n }\n parsed.pathname = pathname;\n return parsed.toString();\n } catch {\n return url;\n }\n}\n\nconst SKIP_EXTENSIONS = new Set([\n '.pdf', '.jpg', '.jpeg', '.png', '.gif', '.svg', '.webp', '.ico',\n '.mp4', '.mp3', '.wav', '.avi',\n '.zip', '.tar', '.gz', '.rar',\n '.css', '.js', '.xml', '.json', '.woff', '.woff2', '.ttf', '.eot',\n]);\n\nexport function extractLinks(html: string, baseUrl: string): string[] {\n const links: string[] = [];\n let origin: string;\n try {\n origin = new URL(baseUrl).origin;\n } catch {\n return [];\n }\n\n const regex = /<a\\s+[^>]*href\\s*=\\s*[\"']([^\"']+)[\"'][^>]*>/gi;\n let match;\n while ((match = regex.exec(html)) !== null) {\n const href = match[1].trim();\n if (\n href.startsWith('mailto:') ||\n href.startsWith('tel:') ||\n href.startsWith('javascript:') ||\n href.startsWith('#')\n ) continue;\n\n try {\n const resolved = new URL(href, baseUrl);\n if (resolved.origin !== origin) continue;\n\n const ext = resolved.pathname.toLowerCase().match(/\\.\\w+$/)?.[0];\n if (ext && SKIP_EXTENSIONS.has(ext)) continue;\n\n links.push(normalizeUrl(resolved.toString()));\n } catch {\n // Invalid URL, skip\n }\n }\n\n return [...new Set(links)];\n}\n\n// ============================================\n// URL filtering\n// ============================================\n\nfunction matchGlob(url: string, pattern: string): boolean {\n const regex = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n .replace(/\\*\\*/g, '{{DOUBLESTAR}}')\n .replace(/\\*/g, '[^/]*')\n .replace(/\\{\\{DOUBLESTAR\\}\\}/g, '.*');\n return new RegExp(regex).test(url);\n}\n\nfunction matchesFilter(url: string, include?: string[], exclude?: string[]): boolean {\n if (exclude?.length) {\n for (const pattern of exclude) {\n if (matchGlob(url, pattern)) return false;\n }\n }\n if (include?.length) {\n return include.some(pattern => matchGlob(url, pattern));\n }\n return true;\n}\n\n// ============================================\n// Crawl\n// ============================================\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nexport async function crawl(options: CrawlOptions): Promise<CrawlResult> {\n const startTime = Date.now();\n\n const {\n url: startUrl,\n depth: maxDepth = 2,\n limit = 50,\n mode = 'auto',\n include,\n exclude,\n timeout,\n concurrency = 3,\n respectRobots = true,\n } = options;\n\n // Validation\n if (!isValidUrl(startUrl)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n if (maxDepth < 0) throw new FetchError('depth must be >= 0', undefined, false);\n if (limit < 1) throw new FetchError('limit must be >= 1', undefined, false);\n if (concurrency < 1) throw new FetchError('concurrency must be >= 1', undefined, false);\n if (timeout !== undefined && (timeout <= 0 || Number.isNaN(timeout))) {\n throw new FetchError('timeout must be a positive number', undefined, false);\n }\n\n const pages: CrawlPageResult[] = [];\n const errors: CrawlError[] = [];\n const visited = new Set<string>();\n let totalDiscovered = 0;\n let totalSkipped = 0;\n\n const normalizedStart = normalizeUrl(startUrl);\n const origin = new URL(startUrl).origin;\n\n // Robots.txt + crawl delay\n let crawlDelay: number | null = null;\n if (respectRobots) {\n crawlDelay = await getCrawlDelay(startUrl, timeout);\n const allowed = await isAllowedByRobots(startUrl, timeout);\n if (!allowed) {\n return {\n pages: [],\n totalDiscovered: 1,\n totalCrawled: 0,\n totalSkipped: 1,\n errors: [],\n duration: Date.now() - startTime,\n };\n }\n }\n\n // Seed: start URL + sitemap URLs\n const queue: Array<{ url: string; depth: number }> = [\n { url: normalizedStart, depth: 0 },\n ];\n\n if (maxDepth > 0) {\n try {\n const sitemapEntries = await parseSitemap(`${origin}/sitemap.xml`, timeout);\n const seen = new Set<string>([normalizedStart]);\n for (const entry of sitemapEntries) {\n const normalized = normalizeUrl(entry.loc);\n if (!seen.has(normalized)) {\n seen.add(normalized);\n queue.push({ url: normalized, depth: 1 });\n }\n }\n } catch (err) {\n console.debug(`[scraper] Sitemap unavailable for ${origin}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n totalDiscovered = queue.length;\n\n // BFS loop\n while (queue.length > 0 && pages.length < limit) {\n const batchSize = Math.min(concurrency, limit - pages.length, queue.length);\n const batch = queue.splice(0, batchSize);\n\n const tasks = batch.map(async ({ url, depth }) => {\n const normalized = normalizeUrl(url);\n\n if (visited.has(normalized)) {\n totalSkipped++;\n return;\n }\n visited.add(normalized);\n\n // URL filter check (start URL is exempt — it's the user's explicit seed)\n if (normalized !== normalizedStart && !matchesFilter(normalized, include, exclude)) {\n totalSkipped++;\n return;\n }\n\n // Per-URL robots check\n if (respectRobots) {\n const allowed = await isAllowedByRobots(url, timeout);\n if (!allowed) {\n totalSkipped++;\n return;\n }\n }\n\n try {\n const fetchResult = await fetchWithMode(url, mode, { timeout });\n const extractResult = await extractContent(fetchResult);\n const convertResult = await convertToMarkdown(extractResult);\n\n const pageResult: CrawlPageResult = {\n markdown: convertResult.markdown,\n tokenCount: convertResult.tokenCount,\n title: extractResult.title,\n author: extractResult.author,\n siteName: extractResult.siteName,\n publishedAt: extractResult.publishedAt,\n url: fetchResult.url,\n depth,\n };\n\n pages.push(pageResult);\n\n // Extract links for next depth level\n if (depth < maxDepth) {\n const links = extractLinks(fetchResult.html, fetchResult.url);\n for (const link of links) {\n if (!visited.has(link)) {\n queue.push({ url: link, depth: depth + 1 });\n totalDiscovered++;\n }\n }\n }\n } catch (err) {\n errors.push({\n url,\n error: err instanceof Error ? err.message : String(err),\n depth,\n });\n }\n });\n\n await Promise.allSettled(tasks);\n\n // Crawl delay between batches\n if (crawlDelay && crawlDelay > 0 && queue.length > 0) {\n await sleep(crawlDelay * 1000);\n }\n }\n\n return {\n pages,\n totalDiscovered,\n totalCrawled: pages.length,\n totalSkipped,\n errors,\n duration: Date.now() - startTime,\n };\n}\n","/**\n * Platform telemetry reporter for scraper.\n *\n * Reads the API key from ~/.robot-resources/config.json and sends\n * telemetry events to the RR platform API. Fire-and-forget — never\n * blocks the scrape() pipeline.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst CONFIG_PATH = join(homedir(), '.robot-resources', 'config.json');\nconst PLATFORM_URL = process.env.RR_PLATFORM_URL || 'https://api.robotresources.ai';\n\nlet apiKey: string | null = null;\nlet keyLoaded = false;\n\nfunction loadApiKey(): string | null {\n if (keyLoaded) return apiKey;\n keyLoaded = true;\n\n // Environment-level opt-out — checked before reading config\n if (process.env.RR_TELEMETRY === 'off') {\n return null;\n }\n\n try {\n const config = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));\n\n // Config-level opt-out\n if (config.telemetry === false) {\n return null;\n }\n\n apiKey = config.api_key || null;\n return apiKey;\n } catch {\n return null;\n }\n}\n\nexport interface ScraperTelemetryPayload {\n url: string;\n tokenCount: number;\n originalTokenCount?: number;\n title?: string;\n latencyMs: number;\n success: boolean;\n error?: string;\n}\n\n/**\n * Report a scrape() call to the platform. Fire-and-forget.\n */\nexport function reportScraperEvent(payload: ScraperTelemetryPayload): void {\n const key = loadApiKey();\n if (!key) return;\n\n // Fire-and-forget — no await, catch silently\n fetch(`${PLATFORM_URL}/v1/telemetry`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${key}`,\n },\n body: JSON.stringify({\n product: 'scraper',\n event_type: payload.success ? 'compress' : 'error',\n payload,\n }),\n }).catch(() => {\n // Silent — telemetry must never break the pipeline\n });\n}\n","/**\n * scraper\n * Context compression for AI agents\n *\n * @packageDocumentation\n */\n\n// Re-export types\nexport type {\n FetchMode,\n ScrapeOptions,\n ScrapeResult,\n FetchResult,\n ExtractResult,\n ConvertResult,\n CrawlOptions,\n CrawlResult,\n CrawlPageResult,\n CrawlError,\n} from './types.js';\n\n// Re-export layers for advanced usage\nexport { fetchUrl, FetchError } from './fetch.js';\nexport { fetchStealth } from './fetch-stealth.js';\nexport { fetchRender } from './fetch-render.js';\nexport { extractContent, ExtractionError } from './extract.js';\nexport { convertToMarkdown, estimateTokens } from './convert.js';\nexport {\n isAllowedByRobots,\n clearRobotsCache,\n getSitemapUrls,\n getCrawlDelay,\n} from './robots.js';\nexport { parseSitemap, clearSitemapCache } from './sitemap.js';\nexport type { SitemapEntry } from './sitemap.js';\nexport { crawl, normalizeUrl, extractLinks } from './crawl.js';\nexport { isChallengeResponse, fetchWithMode } from './fetch-mode.js';\n\n// Import for composition\nimport type { ScrapeOptions, ScrapeResult, FetchMode } from './types.js';\nimport { FetchError } from './fetch.js';\nimport { extractContent } from './extract.js';\nimport { convertToMarkdown, estimateTokens } from './convert.js';\nimport { isAllowedByRobots } from './robots.js';\nimport { reportScraperEvent } from './telemetry.js';\nimport { fetchWithMode } from './fetch-mode.js';\n\n/**\n * Compress web content for AI agents\n *\n * Pipeline: Fetch -> Extract -> Convert\n * No LLM dependency. Median 91% token reduction.\n *\n * @example\n * ```typescript\n * import { scrape } from '@robot-resources/scraper';\n *\n * const result = await scrape('https://example.com/article');\n * console.log(result.markdown);\n * console.log(result.tokenCount);\n * ```\n *\n * @param url - URL to fetch and compress\n * @param options - Optional configuration\n * @returns Compressed content with metadata\n */\nexport async function scrape(\n url: string,\n options: ScrapeOptions = {}\n): Promise<ScrapeResult> {\n const startTime = Date.now();\n\n const mode: FetchMode = options.mode ?? 'auto';\n\n // Validate timeout at public boundary (MCP has Zod, but SDK callers don't)\n if (options.timeout !== undefined && (options.timeout <= 0 || Number.isNaN(options.timeout))) {\n throw new FetchError('timeout must be a positive number', undefined, false);\n }\n\n try {\n // robots.txt check (opt-in, independent of mode)\n if (options.respectRobots) {\n const allowed = await isAllowedByRobots(url, options.timeout);\n if (!allowed) {\n throw new FetchError(`Blocked by robots.txt: ${url}`, undefined, false);\n }\n }\n\n // Layer 1: Fetch (mode-aware with auto-fallback)\n const fetchResult = await fetchWithMode(url, mode, {\n timeout: options.timeout,\n maxRetries: options.maxRetries,\n userAgent: options.userAgent,\n });\n\n // Measure original token count before extraction/conversion\n const originalTokenCount = estimateTokens(fetchResult.html);\n\n // Layer 2: Extract\n const extractResult = await extractContent(fetchResult);\n\n // Layer 3: Convert\n const convertResult = await convertToMarkdown(extractResult);\n\n const result: ScrapeResult = {\n markdown: convertResult.markdown,\n tokenCount: convertResult.tokenCount,\n title: extractResult.title,\n author: extractResult.author,\n siteName: extractResult.siteName,\n publishedAt: extractResult.publishedAt,\n url: fetchResult.url,\n };\n\n // Report telemetry (fire-and-forget)\n reportScraperEvent({\n url,\n tokenCount: convertResult.tokenCount,\n originalTokenCount,\n title: extractResult.title,\n latencyMs: Date.now() - startTime,\n success: true,\n });\n\n return result;\n } catch (err) {\n // Report error telemetry (fire-and-forget)\n reportScraperEvent({\n url,\n tokenCount: 0,\n originalTokenCount: 0,\n latencyMs: Date.now() - startTime,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n });\n\n throw err;\n }\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -353,7 +353,7 @@ declare function fetchWithMode(url: string, mode: FetchMode, options: FetchOptio
353
353
  * Compress web content for AI agents
354
354
  *
355
355
  * Pipeline: Fetch -> Extract -> Convert
356
- * No LLM dependency. Reduces tokens by 70-80%.
356
+ * No LLM dependency. Median 91% token reduction.
357
357
  *
358
358
  * @example
359
359
  * ```typescript
package/dist/index.d.ts CHANGED
@@ -353,7 +353,7 @@ declare function fetchWithMode(url: string, mode: FetchMode, options: FetchOptio
353
353
  * Compress web content for AI agents
354
354
  *
355
355
  * Pipeline: Fetch -> Extract -> Convert
356
- * No LLM dependency. Reduces tokens by 70-80%.
356
+ * No LLM dependency. Median 91% token reduction.
357
357
  *
358
358
  * @example
359
359
  * ```typescript
package/dist/index.js CHANGED
@@ -940,6 +940,7 @@ async function scrape(url, options = {}) {
940
940
  maxRetries: options.maxRetries,
941
941
  userAgent: options.userAgent
942
942
  });
943
+ const originalTokenCount = estimateTokens(fetchResult.html);
943
944
  const extractResult = await extractContent(fetchResult);
944
945
  const convertResult = await convertToMarkdown(extractResult);
945
946
  const result = {
@@ -954,6 +955,7 @@ async function scrape(url, options = {}) {
954
955
  reportScraperEvent({
955
956
  url,
956
957
  tokenCount: convertResult.tokenCount,
958
+ originalTokenCount,
957
959
  title: extractResult.title,
958
960
  latencyMs: Date.now() - startTime,
959
961
  success: true
@@ -963,6 +965,7 @@ async function scrape(url, options = {}) {
963
965
  reportScraperEvent({
964
966
  url,
965
967
  tokenCount: 0,
968
+ originalTokenCount: 0,
966
969
  latencyMs: Date.now() - startTime,
967
970
  success: false,
968
971
  error: err instanceof Error ? err.message : String(err)
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/fetch.ts","../src/fetch-stealth.ts","../src/fetch-render.ts","../src/extract.ts","../src/convert.ts","../src/robots.ts","../src/sitemap.ts","../src/fetch-mode.ts","../src/crawl.ts","../src/telemetry.ts","../src/index.ts"],"names":["DEFAULT_TIMEOUT","DEFAULT_MAX_RETRIES","BASE_BACKOFF_MS","isValidUrl","isRetryableStatus","sleep","getBackoffDelay","DEFAULT_TIMEOUT_MS","DEFAULT_TTL_MS","cache"],"mappings":";;;;;;;;;AAOA,IAAM,WAAA,GAAc;AAAA,EAClB,8EAAA;AAAA,EACA,iHAAA;AAAA,EACA,uHAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,eAAA,GAAkB,GAAA;AACxB,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,eAAA,GAAkB,GAAA;AAWjB,IAAM,UAAA,GAAN,cAAyB,KAAA,CAAM;AAAA,EACpC,WAAA,CACE,OAAA,EACgB,UAAA,EACA,SAAA,GAAqB,KAAA,EACrC;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AAHG,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AACA,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AAGhB,IAAA,IAAA,CAAK,IAAA,GAAO,YAAA;AAAA,EACd;AACF;AAEA,SAAS,WAAW,GAAA,EAAsB;AACxC,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAC1B,IAAA,OAAO,MAAA,CAAO,QAAA,KAAa,OAAA,IAAW,MAAA,CAAO,QAAA,KAAa,QAAA;AAAA,EAC5D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,SAAS,kBAAA,GAA6B;AACpC,EAAA,OAAO,WAAA,CAAY,KAAK,KAAA,CAAM,IAAA,CAAK,QAAO,GAAI,WAAA,CAAY,MAAM,CAAC,CAAA;AACnE;AAEA,SAAS,aAAa,SAAA,EAA4C;AAChE,EAAA,OAAO;AAAA,IACL,YAAA,EAAc,aAAa,kBAAA,EAAmB;AAAA,IAC9C,MAAA,EAAQ,iEAAA;AAAA,IACR,iBAAA,EAAmB,gBAAA;AAAA,IACnB,iBAAA,EAAmB,eAAA;AAAA,IACnB,UAAA,EAAY,YAAA;AAAA,IACZ,eAAA,EAAiB;AAAA,GACnB;AACF;AAEA,SAAS,gBAAgB,OAAA,EAA0C;AACjE,EAAA,MAAM,SAAiC,EAAC;AACxC,EAAA,OAAA,CAAQ,OAAA,CAAQ,CAAC,KAAA,EAAO,GAAA,KAAQ;AAC9B,IAAA,MAAA,CAAO,GAAA,CAAI,WAAA,EAAa,CAAA,GAAI,KAAA;AAAA,EAC9B,CAAC,CAAA;AACD,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,kBAAkB,MAAA,EAAyB;AAClD,EAAA,OAAO,MAAA,IAAU,OAAO,MAAA,GAAS,GAAA;AACnC;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAEA,SAAS,gBAAgB,OAAA,EAAyB;AAChD,EAAA,OAAO,eAAA,GAAkB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,CAAA;AAC9C;AAEA,eAAe,gBAAA,CACb,GAAA,EACA,OAAA,EACA,OAAA,EACmB;AACnB,EAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,EAAA,MAAM,YAAY,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,OAAO,CAAA;AAE9D,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAChC,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA;AAAA,MACA,QAAQ,UAAA,CAAW,MAAA;AAAA,MACnB,QAAA,EAAU;AAAA,KACX,CAAA;AACD,IAAA,OAAO,QAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,KAAA,YAAiB,KAAA,IAAS,KAAA,CAAM,IAAA,KAAS,YAAA,EAAc;AACzD,MAAA,MAAM,IAAI,UAAA,CAAW,iBAAA,EAAmB,MAAA,EAAW,IAAI,CAAA;AAAA,IACzD;AACA,IAAA,MAAM,KAAA;AAAA,EACR,CAAA,SAAE;AACA,IAAA,YAAA,CAAa,SAAS,CAAA;AAAA,EACxB;AACF;AAKA,eAAsB,QAAA,CACpB,GAAA,EACA,OAAA,GAAwB,EAAC,EACH;AACtB,EAAA,MAAM;AAAA,IACJ,OAAA,GAAU,eAAA;AAAA,IACV,UAAA,GAAa,mBAAA;AAAA,IACb;AAAA,GACF,GAAI,OAAA;AAEJ,EAAA,IAAI,CAAC,UAAA,CAAW,GAAG,CAAA,EAAG;AACpB,IAAA,MAAM,IAAI,UAAA,CAAW,aAAA,EAAe,MAAA,EAAW,KAAK,CAAA;AAAA,EACtD;AAEA,EAAA,MAAM,OAAA,GAAU,aAAa,SAAS,CAAA;AACtC,EAAA,IAAI,SAAA,GAA0B,IAAA;AAE9B,EAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,UAAA,EAAY,OAAA,EAAA,EAAW;AACtD,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,SAAS,OAAO,CAAA;AAE7D,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,MAAM,aAAa,QAAA,CAAS,MAAA;AAE5B,QAAA,IAAI,UAAA,IAAc,GAAA,IAAO,UAAA,GAAa,GAAA,EAAK;AACzC,UAAA,MAAM,IAAI,UAAA,CAAW,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAA,EAAI,YAAY,KAAK,CAAA;AAAA,QAC9D;AAEA,QAAA,IAAI,iBAAA,CAAkB,UAAU,CAAA,EAAG;AACjC,UAAA,MAAM,IAAI,UAAA,CAAW,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAA,EAAI,YAAY,IAAI,CAAA;AAAA,QAC7D;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,MAAA,MAAM,eAAA,GAAkB,eAAA,CAAgB,QAAA,CAAS,OAAO,CAAA;AAExD,MAAA,OAAO;AAAA,QACL,IAAA;AAAA,QACA,KAAK,QAAA,CAAS,GAAA;AAAA,QACd,YAAY,QAAA,CAAS,MAAA;AAAA,QACrB,OAAA,EAAS;AAAA,OACX;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,SAAA,GAAY,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAEpE,MAAA,MAAM,cACJ,KAAA,YAAiB,UAAA,GACb,KAAA,CAAM,SAAA,GACN,EAAE,KAAA,YAAiB,UAAA,CAAA;AAEzB,MAAA,MAAM,iBAAiB,OAAA,GAAU,UAAA;AAEjC,MAAA,IAAI,eAAe,cAAA,EAAgB;AACjC,QAAA,MAAM,KAAA,GAAQ,gBAAgB,OAAO,CAAA;AACrC,QAAA,MAAM,MAAM,KAAK,CAAA;AACjB,QAAA;AAAA,MACF;AAEA,MAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,IAAa,IAAI,UAAA,CAAW,qBAAqB,CAAA;AACzD;;;AChKA,IAAMA,gBAAAA,GAAkB,GAAA;AACxB,IAAMC,oBAAAA,GAAsB,CAAA;AAC5B,IAAMC,gBAAAA,GAAkB,GAAA;AAExB,SAASC,YAAW,GAAA,EAAsB;AACxC,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAC1B,IAAA,OAAO,MAAA,CAAO,QAAA,KAAa,OAAA,IAAW,MAAA,CAAO,QAAA,KAAa,QAAA;AAAA,EAC5D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,SAASC,mBAAkB,MAAA,EAAyB;AAClD,EAAA,OAAO,MAAA,IAAU,OAAO,MAAA,GAAS,GAAA;AACnC;AAEA,SAASC,OAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAEA,SAASC,iBAAgB,OAAA,EAAyB;AAChD,EAAA,OAAOJ,gBAAAA,GAAkB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,CAAA;AAC9C;AAYA,eAAsB,YAAA,CACpB,GAAA,EACA,OAAA,GAAwB,EAAC,EACH;AACtB,EAAA,MAAM;AAAA,IACJ,OAAA,GAAUF,gBAAAA;AAAA,IACV,UAAA,GAAaC;AAAA,GACf,GAAI,OAAA;AAEJ,EAAA,IAAI,CAACE,WAAAA,CAAW,GAAG,CAAA,EAAG;AACpB,IAAA,MAAM,IAAI,UAAA,CAAW,aAAA,EAAe,MAAA,EAAW,KAAK,CAAA;AAAA,EACtD;AAGA,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AAEF,IAAA,CAAC,EAAE,KAAA,EAAM,GAAI,MAAM,OAAO,OAAO,CAAA;AAAA,EACnC,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,sFAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,SAAS,IAAI,KAAA,CAAM,EAAE,OAAA,EAAS,UAAU,CAAA;AAC9C,EAAA,IAAI,SAAA,GAA0B,IAAA;AAE9B,EAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,UAAA,EAAY,OAAA,EAAA,EAAW;AACtD,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,KAAA,CAAM,GAAA,EAAK;AAAA,QACvC,MAAA,EAAQ,WAAA,CAAY,OAAA,CAAQ,OAAO;AAAA,OACpC,CAAA;AAED,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,MAAM,aAAa,QAAA,CAAS,MAAA;AAE5B,QAAA,IAAI,UAAA,IAAc,GAAA,IAAO,UAAA,GAAa,GAAA,EAAK;AACzC,UAAA,MAAM,IAAI,UAAA,CAAW,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAA,EAAI,YAAY,KAAK,CAAA;AAAA,QAC9D;AAEA,QAAA,IAAIC,kBAAAA,CAAkB,UAAU,CAAA,EAAG;AACjC,UAAA,MAAM,IAAI,UAAA,CAAW,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAA,EAAI,YAAY,IAAI,CAAA;AAAA,QAC7D;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,MAAA,MAAM,UAAkC,EAAC;AACzC,MAAA,QAAA,CAAS,OAAA,CAAQ,OAAA,CAAQ,CAAC,KAAA,EAAe,GAAA,KAAgB;AACvD,QAAA,OAAA,CAAQ,GAAG,CAAA,GAAI,KAAA;AAAA,MACjB,CAAC,CAAA;AAED,MAAA,OAAO;AAAA,QACL,IAAA;AAAA,QACA,GAAA,EAAK,SAAS,GAAA,IAAO,GAAA;AAAA,QACrB,YAAY,QAAA,CAAS,MAAA;AAAA,QACrB;AAAA,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,SAAA,GAAY,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAEpE,MAAA,MAAM,cACJ,KAAA,YAAiB,UAAA,GACb,KAAA,CAAM,SAAA,GACN,EAAE,KAAA,YAAiB,UAAA,CAAA;AAEzB,MAAA,MAAM,iBAAiB,OAAA,GAAU,UAAA;AAEjC,MAAA,IAAI,eAAe,cAAA,EAAgB;AACjC,QAAA,MAAM,KAAA,GAAQE,iBAAgB,OAAO,CAAA;AACrC,QAAA,MAAMD,OAAM,KAAK,CAAA;AACjB,QAAA;AAAA,MACF;AAEA,MAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,IAAa,IAAI,UAAA,CAAW,6BAA6B,CAAA;AACjE;;;ACnHA,IAAML,gBAAAA,GAAkB,GAAA;AAExB,SAASG,YAAW,GAAA,EAAsB;AACxC,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAC1B,IAAA,OAAO,MAAA,CAAO,QAAA,KAAa,OAAA,IAAW,MAAA,CAAO,QAAA,KAAa,QAAA;AAAA,EAC5D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAWA,eAAsB,WAAA,CACpB,GAAA,EACA,OAAA,GAAwB,EAAC,EACH;AACtB,EAAA,MAAM,EAAE,OAAA,GAAUH,gBAAAA,EAAgB,GAAI,OAAA;AAEtC,EAAA,IAAI,CAACG,WAAAA,CAAW,GAAG,CAAA,EAAG;AACpB,IAAA,MAAM,IAAI,UAAA,CAAW,aAAA,EAAe,MAAA,EAAW,KAAK,CAAA;AAAA,EACtD;AAGA,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AAEF,IAAA,CAAC,EAAE,QAAA,EAAS,GAAI,MAAM,OAAO,YAAY,CAAA;AAAA,EAC3C,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,yEAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,UAAU,MAAM,QAAA,CAAS,OAAO,EAAE,QAAA,EAAU,MAAM,CAAA;AAExD,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,OAAA,EAAQ;AAGnC,IAAA,IAAA,CAAK,GAAG,QAAA,EAAU,CAAC,MAAA,KAAgB,MAAA,CAAO,SAAS,CAAA;AAEnD,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,IAAA,CAAK,GAAA,EAAK;AAAA,MACpC,SAAA,EAAW,aAAA;AAAA,MACX;AAAA,KACD,CAAA;AAED,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,MAAM,IAAI,UAAA;AAAA,QACR,oEAAA;AAAA,QACA,KAAA,CAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAEA,IAAA,MAAM,UAAA,GAAa,SAAS,MAAA,EAAO;AAEnC,IAAA,IAAI,UAAA,IAAc,GAAA,IAAO,UAAA,GAAa,GAAA,EAAK;AACzC,MAAA,MAAM,IAAI,UAAA,CAAW,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAA,EAAI,YAAY,KAAK,CAAA;AAAA,IAC9D;AAEA,IAAA,IAAI,cAAc,GAAA,EAAK;AACrB,MAAA,MAAM,IAAI,UAAA,CAAW,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAA,EAAI,YAAY,IAAI,CAAA;AAAA,IAC7D;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,OAAA,EAAQ;AAChC,IAAA,MAAM,OAAA,GAAkC,SAAS,OAAA,EAAQ;AAEzD,IAAA,OAAO;AAAA,MACL,IAAA;AAAA,MACA,GAAA,EAAK,KAAK,GAAA,EAAI;AAAA,MACd,UAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,SAAS,KAAA,EAAO;AAEd,IAAA,IAAI,KAAA,YAAiB,KAAA,IAAS,KAAA,CAAM,IAAA,KAAS,cAAA,EAAgB;AAC3D,MAAA,MAAM,IAAI,UAAA,CAAW,oBAAA,EAAsB,MAAA,EAAW,IAAI,CAAA;AAAA,IAC5D;AACA,IAAA,MAAM,KAAA;AAAA,EACR,CAAA,SAAE;AACA,IAAA,MAAM,QAAQ,KAAA,EAAM;AAAA,EACtB;AACF;AC9FO,IAAM,eAAA,GAAN,cAA8B,KAAA,CAAM;AAAA,EACzC,WAAA,CACE,SACgB,IAAA,EAChB;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AAFG,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAGhB,IAAA,IAAA,CAAK,IAAA,GAAO,iBAAA;AAAA,EACd;AACF;AAKA,eAAsB,eACpB,WAAA,EACwB;AACxB,EAAA,MAAM,EAAE,MAAK,GAAI,WAAA;AAEjB,EAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,IAAA,CAAK,MAAK,EAAG;AACzB,IAAA,MAAM,IAAI,eAAA,CAAgB,oBAAA,EAAsB,YAAY,CAAA;AAAA,EAC9D;AAEA,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,SAAA,CAAU,IAAI,CAAA;AAEnC,EAAA,MAAM,MAAA,GAAS,IAAI,WAAA,CAAY,QAAA,EAAU;AAAA,IACvC,aAAA,EAAe;AAAA,GAChB,CAAA;AAED,EAAA,MAAM,OAAA,GAAU,OAAO,KAAA,EAAM;AAE7B,EAAA,IAAI,CAAC,OAAA,IAAW,CAAC,OAAA,CAAQ,OAAA,IAAW,QAAQ,OAAA,CAAQ,IAAA,EAAK,CAAE,MAAA,GAAS,EAAA,EAAI;AACtE,IAAA,MAAM,IAAI,eAAA;AAAA,MACR,6CAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,GAAwB;AAAA,IAC5B,OAAA,EAAS,YAAA,CAAa,OAAA,CAAQ,OAAO,CAAA;AAAA,IACrC,KAAA,EAAO,OAAA,CAAQ,KAAA,IAAS,oBAAA,CAAqB,QAAQ,CAAA;AAAA,IACrD,MAAA,EAAQ,QAAQ,MAAA,IAAU,MAAA;AAAA,IAC1B,WAAA,EAAa,OAAA,CAAQ,aAAA,IAAiB,oBAAA,CAAqB,QAAQ,CAAA;AAAA,IACnE,QAAA,EAAU,OAAA,CAAQ,QAAA,IAAY,eAAA,CAAgB,QAAQ;AAAA,GACxD;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,aAAa,OAAA,EAAyB;AAC7C,EAAA,OAAO,OAAA,CACJ,QAAQ,QAAA,EAAU,IAAI,EACtB,OAAA,CAAQ,SAAA,EAAW,GAAG,CAAA,CACtB,IAAA,EAAK;AACV;AAEA,SAAS,qBAAqB,QAAA,EAAwC;AACpE,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,2BAA2B,CAAA;AAClE,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,YAAA,CAAa,SAAS,CAAA;AAC9C,IAAA,IAAI,SAAS,OAAO,OAAA;AAAA,EACtB;AAEA,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAC9C,EAAA,IAAI,OAAA,IAAW,QAAQ,WAAA,EAAa;AAClC,IAAA,OAAO,OAAA,CAAQ,YAAY,IAAA,EAAK;AAAA,EAClC;AAEA,EAAA,MAAM,EAAA,GAAK,QAAA,CAAS,aAAA,CAAc,IAAI,CAAA;AACtC,EAAA,IAAI,EAAA,IAAM,GAAG,WAAA,EAAa;AACxB,IAAA,OAAO,EAAA,CAAG,YAAY,IAAA,EAAK;AAAA,EAC7B;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,qBAAqB,QAAA,EAAwC;AACpE,EAAA,MAAM,SAAS,QAAA,CAAS,aAAA;AAAA,IACtB;AAAA,GACF;AACA,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,YAAA,CAAa,SAAS,CAAA;AAC7C,IAAA,IAAI,SAAS,OAAO,OAAA;AAAA,EACtB;AAEA,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,aAAA,CAAc,4BAA4B,CAAA;AACtE,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,MAAM,QAAA,GAAW,UAAA,CAAW,YAAA,CAAa,UAAU,CAAA;AACnD,IAAA,IAAI,UAAU,OAAO,QAAA;AACrB,IAAA,MAAM,OAAA,GAAU,UAAA,CAAW,YAAA,CAAa,SAAS,CAAA;AACjD,IAAA,IAAI,SAAS,OAAO,OAAA;AAAA,EACtB;AAEA,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,gBAAgB,CAAA;AACtD,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,YAAA,CAAa,UAAU,CAAA;AAC/C,IAAA,IAAI,UAAU,OAAO,QAAA;AAAA,EACvB;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,gBAAgB,QAAA,EAAwC;AAC/D,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,aAAA,CAAc,+BAA+B,CAAA;AACzE,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,MAAM,OAAA,GAAU,UAAA,CAAW,YAAA,CAAa,SAAS,CAAA;AACjD,IAAA,IAAI,SAAS,OAAO,OAAA;AAAA,EACtB;AAEA,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,+BAA+B,CAAA;AACtE,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,YAAA,CAAa,SAAS,CAAA;AAC9C,IAAA,IAAI,SAAS,OAAO,OAAA;AAAA,EACtB;AAEA,EAAA,OAAO,MAAA;AACT;ACvHA,SAAS,qBAAA,GAAyC;AAChD,EAAA,MAAM,QAAA,GAAW,IAAI,eAAA,CAAgB;AAAA,IACnC,YAAA,EAAc,KAAA;AAAA,IACd,EAAA,EAAI,KAAA;AAAA,IACJ,gBAAA,EAAkB,GAAA;AAAA,IAClB,cAAA,EAAgB,QAAA;AAAA,IAChB,KAAA,EAAO,KAAA;AAAA,IACP,WAAA,EAAa,GAAA;AAAA,IACb,eAAA,EAAiB,IAAA;AAAA,IACjB,SAAA,EAAW;AAAA,GACZ,CAAA;AAED,EAAA,QAAA,CAAS,OAAO,CAAC,QAAA,EAAU,OAAA,EAAS,UAAA,EAAY,QAAQ,CAAC,CAAA;AAEzD,EAAA,QAAA,CAAS,QAAQ,aAAA,EAAe;AAAA,IAC9B,MAAA,EAAQ,CAAC,IAAA,KAAS;AAChB,MAAA,IAAI,IAAA,CAAK,aAAa,CAAA,EAAG;AACvB,QAAA,MAAM,IAAA,GAAO,KAAK,WAAA,IAAe,EAAA;AACjC,QAAA,MAAM,YAAA,GACJ,IAAA,CAAK,IAAA,EAAK,KAAM,MAChB,CAAC,CAAC,KAAA,EAAO,IAAA,EAAM,IAAA,EAAM,OAAO,CAAA,CAAE,QAAA,CAAS,KAAK,QAAQ,CAAA;AACtD,QAAA,OAAO,YAAA;AAAA,MACT;AACA,MAAA,OAAO,KAAA;AAAA,IACT,CAAA;AAAA,IACA,aAAa,MAAM;AAAA,GACpB,CAAA;AAED,EAAA,QAAA,CAAS,QAAQ,iBAAA,EAAmB;AAAA,IAClC,MAAA,EAAQ,CAAC,IAAA,EAAM,OAAA,KAAY;AACzB,MAAA,OACE,OAAA,CAAQ,cAAA,KAAmB,QAAA,IAC3B,IAAA,CAAK,QAAA,KAAa,KAAA,IAClB,IAAA,CAAK,UAAA,KAAe,IAAA,IACpB,IAAA,CAAK,UAAA,CAAW,QAAA,KAAa,MAAA;AAAA,IAEjC,CAAA;AAAA,IACA,WAAA,EAAa,CAAC,QAAA,EAAU,IAAA,EAAM,OAAA,KAAY;AACxC,MAAA,MAAM,WAAW,IAAA,CAAK,UAAA;AACtB,MAAA,MAAM,IAAA,GAAO,SAAS,WAAA,IAAe,EAAA;AAErC,MAAA,MAAM,SAAA,GAAY,QAAA,CAAS,YAAA,CAAa,OAAO,CAAA,IAAK,EAAA;AACpD,MAAA,MAAM,SAAA,GAAY,SAAA,CAAU,KAAA,CAAM,gBAAgB,CAAA;AAClD,MAAA,MAAM,IAAA,GAAO,SAAA,GAAY,SAAA,CAAU,CAAC,CAAA,GAAI,EAAA;AAExC,MAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,KAAA;AAC/B,MAAA,OAAO;;AAAA,EAAO,KAAK,GAAG,IAAI;AAAA,EAAK,IAAI;AAAA,EAAK,KAAK;;AAAA,CAAA;AAAA,IAC/C;AAAA,GACD,CAAA;AAED,EAAA,QAAA,CAAS,QAAQ,eAAA,EAAiB;AAAA,IAChC,MAAA,EAAQ,CAAC,KAAA,EAAO,GAAG,CAAA;AAAA,IACnB,WAAA,EAAa,CAAC,OAAA,KAAY,CAAA,EAAA,EAAK,OAAO,CAAA,EAAA;AAAA,GACvC,CAAA;AAED,EAAA,OAAO,QAAA;AACT;AAEA,IAAI,gBAAA,GAA2C,IAAA;AAE/C,SAAS,WAAA,GAA+B;AACtC,EAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,IAAA,gBAAA,GAAmB,qBAAA,EAAsB;AAAA,EAC3C;AACA,EAAA,OAAO,gBAAA;AACT;AAEA,SAAS,cAAc,QAAA,EAA0B;AAC/C,EAAA,OAAO,SACJ,OAAA,CAAQ,SAAA,EAAW,MAAM,CAAA,CACzB,QAAQ,WAAA,EAAa,EAAE,CAAA,CACvB,OAAA,CAAQ,QAAQ,EAAE,CAAA,CAClB,QAAQ,MAAA,EAAQ,EAAE,EAClB,IAAA,EAAK;AACV;AAKA,eAAsB,kBACpB,aAAA,EACwB;AACxB,EAAA,MAAM,EAAE,SAAQ,GAAI,aAAA;AAEpB,EAAA,IAAI,CAAC,OAAA,IAAW,CAAC,OAAA,CAAQ,MAAK,EAAG;AAC/B,IAAA,OAAO;AAAA,MACL,QAAA,EAAU,EAAA;AAAA,MACV,UAAA,EAAY;AAAA,KACd;AAAA,EACF;AAEA,EAAA,MAAM,WAAW,WAAA,EAAY;AAC7B,EAAA,IAAI,QAAA,GAAW,QAAA,CAAS,QAAA,CAAS,OAAO,CAAA;AAExC,EAAA,QAAA,GAAW,cAAc,QAAQ,CAAA;AAEjC,EAAA,MAAM,UAAA,GAAa,eAAe,QAAQ,CAAA;AAE1C,EAAA,OAAO;AAAA,IACL,QAAA;AAAA,IACA;AAAA,GACF;AACF;AAgBO,SAAS,eAAe,IAAA,EAAsB;AACnD,EAAA,IAAI,CAAC,MAAM,OAAO,CAAA;AAElB,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,IAAI,SAAA,GAAY,IAAA;AAGhB,EAAA,SAAA,GAAY,SAAA,CAAU,OAAA,CAAQ,iBAAA,EAAmB,CAAC,KAAA,KAAU;AAC1D,IAAA,MAAA,IAAU,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,GAAG,CAAA;AACtC,IAAA,OAAO,GAAA;AAAA,EACT,CAAC,CAAA;AAGD,EAAA,SAAA,GAAY,SAAA,CAAU,OAAA,CAAQ,UAAA,EAAY,CAAC,KAAA,KAAU;AACnD,IAAA,MAAA,IAAU,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,GAAG,CAAA;AACtC,IAAA,OAAO,GAAA;AAAA,EACT,CAAC,CAAA;AAGD,EAAA,SAAA,GAAY,SAAA,CAAU,OAAA,CAAQ,iBAAA,EAAmB,CAAC,KAAA,KAAU;AAC1D,IAAA,MAAA,IAAU,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,CAAG,CAAA;AACtC,IAAA,OAAO,GAAA;AAAA,EACT,CAAC,CAAA;AAGD,EAAA,MAAM,cAAc,SAAA,CAAU,OAAA,CAAQ,QAAQ,GAAG,CAAA,CAAE,MAAK,CAAE,MAAA;AAC1D,EAAA,IAAI,cAAc,CAAA,EAAG;AACnB,IAAA,MAAA,IAAU,IAAA,CAAK,IAAA,CAAK,WAAA,GAAc,GAAG,CAAA;AAAA,EACvC;AAEA,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,MAAM,CAAA;AAC3B;AC/IA,IAAM,cAAA,GAAiB,KAAK,EAAA,GAAK,GAAA;AACjC,IAAM,kBAAA,GAAqB,GAAA;AAC3B,IAAM,cAAA,GAAiB,YAAA;AAEvB,IAAM,KAAA,uBAAY,GAAA,EAA8B;AAEhD,SAAS,aAAa,GAAA,EAAqB;AACzC,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAC1B,EAAA,OAAO,CAAA,EAAG,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK,OAAO,IAAI,CAAA,WAAA,CAAA;AAC3C;AAEA,eAAe,eAAA,CACb,GAAA,EACA,OAAA,GAAkB,kBAAA,EACwB;AAC1C,EAAA,MAAM,SAAA,GAAY,aAAa,GAAG,CAAA;AAElC,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,GAAA,CAAI,SAAS,CAAA;AAClC,EAAA,IAAI,MAAA,IAAU,MAAA,CAAO,SAAA,GAAY,IAAA,CAAK,KAAI,EAAG;AAC3C,IAAA,OAAO,MAAA,CAAO,MAAA;AAAA,EAChB;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,YAAY,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,OAAO,CAAA;AAE9D,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,SAAA,EAAW;AAAA,MACtC,QAAQ,UAAA,CAAW,MAAA;AAAA,MACnB,OAAA,EAAS,EAAE,YAAA,EAAc,cAAA;AAAe,KACzC,CAAA;AAED,IAAA,YAAA,CAAa,SAAS,CAAA;AAEtB,IAAA,MAAM,OAAO,QAAA,CAAS,EAAA,GAAK,MAAM,QAAA,CAAS,MAAK,GAAI,EAAA;AACnD,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,SAAA,EAAW,IAAI,CAAA;AAE3C,IAAA,KAAA,CAAM,IAAI,SAAA,EAAW;AAAA,MACnB,MAAA;AAAA,MACA,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,KACzB,CAAA;AAED,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AAEN,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,SAAA,EAAW,EAAE,CAAA;AACzC,IAAA,KAAA,CAAM,IAAI,SAAA,EAAW;AAAA,MACnB,MAAA;AAAA,MACA,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,KACzB,CAAA;AACD,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAMA,eAAsB,iBAAA,CACpB,KACA,OAAA,EACkB;AAClB,EAAA,MAAM,MAAA,GAAS,MAAM,eAAA,CAAgB,GAAA,EAAK,OAAO,CAAA;AACjD,EAAA,OAAO,MAAA,CAAO,SAAA,CAAU,GAAA,EAAK,cAAc,CAAA,KAAM,KAAA;AACnD;AAOA,eAAsB,cAAA,CACpB,KACA,OAAA,EACmB;AACnB,EAAA,MAAM,MAAA,GAAS,MAAM,eAAA,CAAgB,GAAA,EAAK,OAAO,CAAA;AACjD,EAAA,OAAO,OAAO,WAAA,EAAY;AAC5B;AAOA,eAAsB,aAAA,CACpB,KACA,OAAA,EACwB;AACxB,EAAA,MAAM,MAAA,GAAS,MAAM,eAAA,CAAgB,GAAA,EAAK,OAAO,CAAA;AACjD,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,aAAA,CAAc,cAAc,CAAA;AACjD,EAAA,OAAO,KAAA,KAAU,SAAY,IAAA,GAAO,KAAA;AACtC;AAKO,SAAS,gBAAA,GAAyB;AACvC,EAAA,KAAA,CAAM,KAAA,EAAM;AACd;;;ACtGA,IAAMI,mBAAAA,GAAqB,GAAA;AAC3B,IAAMC,eAAAA,GAAiB,KAAK,EAAA,GAAK,GAAA;AACjC,IAAM,mBAAA,GAAsB,CAAA;AAmB5B,IAAMC,MAAAA,uBAAY,GAAA,EAA+B;AAKjD,SAAS,UAAU,GAAA,EAAqB;AACtC,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAC1B,EAAA,OAAO,CAAA,EAAG,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK,OAAO,IAAI,CAAA,CAAA;AAC3C;AAKA,SAAS,eAAe,GAAA,EAAsB;AAC5C,EAAA,OAAO,qBAAA,CAAsB,KAAK,GAAG,CAAA;AACvC;AAMA,SAAS,wBAAwB,GAAA,EAAuB;AACtD,EAAA,MAAM,OAAiB,EAAC;AAExB,EAAA,MAAM,iBAAA,GAAoB,2DAAA;AAC1B,EAAA,IAAI,UAAA;AAEJ,EAAA,OAAA,CAAQ,UAAA,GAAa,iBAAA,CAAkB,IAAA,CAAK,GAAG,OAAO,IAAA,EAAM;AAC1D,IAAA,MAAM,KAAA,GAAQ,WAAW,CAAC,CAAA;AAC1B,IAAA,MAAM,QAAA,GAAW,kDAAA,CAAmD,IAAA,CAAK,KAAK,CAAA;AAC9E,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,MAAM,GAAA,GAAM,QAAA,CAAS,CAAC,CAAA,CAAE,IAAA,EAAK;AAC7B,MAAA,IAAI,GAAA,EAAK,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA;AAAA,IACxB;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAMA,SAAS,iBAAA,CAAkB,KAAa,MAAA,EAAgC;AACtE,EAAA,MAAM,UAA0B,EAAC;AAEjC,EAAA,MAAM,aAAA,GAAgB,mDAAA;AACtB,EAAA,IAAI,UAAA;AAEJ,EAAA,OAAA,CAAQ,UAAA,GAAa,aAAA,CAAc,IAAA,CAAK,GAAG,OAAO,IAAA,EAAM;AACtD,IAAA,MAAM,KAAA,GAAQ,WAAW,CAAC,CAAA;AAG1B,IAAA,MAAM,QAAA,GAAW,kDAAA,CAAmD,IAAA,CAAK,KAAK,CAAA;AAC9E,IAAA,IAAI,CAAC,QAAA,EAAU;AAEf,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,CAAC,CAAA,CAAE,IAAA,EAAK;AAC7B,IAAA,IAAI,CAAC,GAAA,EAAK;AAGV,IAAA,IAAI;AACF,MAAA,IAAI,SAAA,CAAU,GAAG,CAAA,KAAM,MAAA,EAAQ;AAAA,IACjC,CAAA,CAAA,MAAQ;AACN,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAsB,EAAE,GAAA,EAAI;AAGlC,IAAA,MAAM,YAAA,GAAe,0DAAA,CAA2D,IAAA,CAAK,KAAK,CAAA;AAC1F,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,MAAM,OAAA,GAAU,YAAA,CAAa,CAAC,CAAA,CAAE,IAAA,EAAK;AACrC,MAAA,IAAI,OAAA,QAAe,OAAA,GAAU,OAAA;AAAA,IAC/B;AAGA,IAAA,MAAM,aAAA,GAAgB,4DAAA,CAA6D,IAAA,CAAK,KAAK,CAAA;AAC7F,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,MAAM,WAAW,UAAA,CAAW,aAAA,CAAc,CAAC,CAAA,CAAE,MAAM,CAAA;AACnD,MAAA,IAAI,CAAC,KAAA,CAAM,QAAQ,CAAA,QAAS,QAAA,GAAW,QAAA;AAAA,IACzC;AAEA,IAAA,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,EACpB;AAEA,EAAA,OAAO,OAAA;AACT;AAKA,eAAe,eAAA,CACb,KACA,OAAA,EACwB;AACxB,EAAA,IAAI;AACF,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,YAAY,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,OAAO,CAAA;AAE9D,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAChC,QAAQ,UAAA,CAAW,MAAA;AAAA,MACnB,OAAA,EAAS,EAAE,YAAA,EAAc,gBAAA;AAAiB,KAC3C,CAAA;AAED,IAAA,YAAA,CAAa,SAAS,CAAA;AAEtB,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,IAAA;AAEzB,IAAA,OAAO,MAAM,SAAS,IAAA,EAAK;AAAA,EAC7B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAKA,eAAe,oBAAA,CACb,GAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACyB;AACzB,EAAA,IAAI,KAAA,IAAS,mBAAA,EAAqB,OAAO,EAAC;AAE1C,EAAA,MAAM,GAAA,GAAM,MAAM,eAAA,CAAgB,GAAA,EAAK,OAAO,CAAA;AAC9C,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,EAAC;AAGlB,EAAA,IAAI,cAAA,CAAe,GAAG,CAAA,EAAG;AACvB,IAAA,MAAM,WAAA,GAAc,wBAAwB,GAAG,CAAA;AAC/C,IAAA,MAAM,aAA6B,EAAC;AAEpC,IAAA,KAAA,MAAW,cAAc,WAAA,EAAa;AACpC,MAAA,MAAM,UAAU,MAAM,oBAAA;AAAA,QACpB,UAAA;AAAA,QACA,MAAA;AAAA,QACA,OAAA;AAAA,QACA,KAAA,GAAQ;AAAA,OACV;AACA,MAAA,UAAA,CAAW,IAAA,CAAK,GAAG,OAAO,CAAA;AAAA,IAC5B;AAEA,IAAA,OAAO,UAAA;AAAA,EACT;AAGA,EAAA,OAAO,iBAAA,CAAkB,KAAK,MAAM,CAAA;AACtC;AAgBA,eAAsB,YAAA,CACpB,GAAA,EACA,OAAA,GAAkBF,mBAAAA,EACO;AAEzB,EAAA,MAAM,MAAA,GAASE,MAAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAC5B,EAAA,IAAI,MAAA,IAAU,MAAA,CAAO,SAAA,GAAY,IAAA,CAAK,KAAI,EAAG;AAC3C,IAAA,OAAO,MAAA,CAAO,OAAA;AAAA,EAChB;AAEA,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,UAAU,GAAG,CAAA;AAAA,EACxB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,UAAU,MAAM,oBAAA,CAAqB,GAAA,EAAK,MAAA,EAAQ,SAAS,CAAC,CAAA;AAGlE,EAAAA,MAAAA,CAAM,IAAI,GAAA,EAAK;AAAA,IACb,OAAA;AAAA,IACA,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAID;AAAA,GACzB,CAAA;AAED,EAAA,OAAO,OAAA;AACT;AAKO,SAAS,iBAAA,GAA0B;AACxC,EAAAC,OAAM,KAAA,EAAM;AACd;;;ACtNA,IAAM,iBAAA,GAAoB;AAAA,EACxB,yBAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,kBAAA;AAAA,EACA;AACF,CAAA;AAMO,SAAS,oBAAoB,WAAA,EAAmC;AACrE,EAAA,OAAO,kBAAkB,IAAA,CAAK,CAAA,MAAA,KAAU,YAAY,IAAA,CAAK,QAAA,CAAS,MAAM,CAAC,CAAA;AAC3E;AAWA,IAAM,WAAA,GAAiC,CAAC,MAAA,EAAQ,SAAA,EAAW,UAAU,MAAM,CAAA;AAE3E,eAAsB,aAAA,CACpB,GAAA,EACA,IAAA,EACA,OAAA,EACsB;AACtB,EAAA,IAAI,CAAC,WAAA,CAAY,QAAA,CAAS,IAAI,CAAA,EAAG;AAC/B,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,wBAAwB,IAAI,CAAA,gBAAA,EAAmB,WAAA,CAAY,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,MACrE,MAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,IAAI,IAAA,KAAS,SAAA,EAAW,OAAO,YAAA,CAAa,KAAK,OAAO,CAAA;AACxD,EAAA,IAAI,IAAA,KAAS,QAAA,EAAU,OAAO,WAAA,CAAY,KAAK,OAAO,CAAA;AACtD,EAAA,IAAI,IAAA,KAAS,MAAA,EAAQ,OAAO,QAAA,CAAS,KAAK,OAAO,CAAA;AAGjD,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,GAAA,EAAK,OAAO,CAAA;AAC1C,IAAA,IAAI,mBAAA,CAAoB,MAAM,CAAA,EAAG;AAC/B,MAAA,OAAO,YAAA,CAAa,KAAK,OAAO,CAAA;AAAA,IAClC;AACA,IAAA,OAAO,MAAA;AAAA,EACT,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,GAAA,YAAe,UAAA,IAAc,GAAA,CAAI,UAAA,KAAe,GAAA,EAAK;AACvD,MAAA,OAAO,YAAA,CAAa,KAAK,OAAO,CAAA;AAAA,IAClC;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AACF;;;AC7CA,SAASN,YAAW,GAAA,EAAsB;AACxC,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAC1B,IAAA,OAAO,MAAA,CAAO,QAAA,KAAa,OAAA,IAAW,MAAA,CAAO,QAAA,KAAa,QAAA;AAAA,EAC5D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEO,SAAS,aAAa,GAAA,EAAqB;AAChD,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAC1B,IAAA,MAAA,CAAO,IAAA,GAAO,EAAA;AACd,IAAA,IAAI,WAAW,MAAA,CAAO,QAAA;AACtB,IAAA,IAAI,SAAS,MAAA,GAAS,CAAA,IAAK,QAAA,CAAS,QAAA,CAAS,GAAG,CAAA,EAAG;AACjD,MAAA,QAAA,GAAW,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,CAAA,CAAE,CAAA;AAAA,IACjC;AACA,IAAA,MAAA,CAAO,QAAA,GAAW,QAAA;AAClB,IAAA,OAAO,OAAO,QAAA,EAAS;AAAA,EACzB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,GAAA;AAAA,EACT;AACF;AAEA,IAAM,eAAA,uBAAsB,GAAA,CAAI;AAAA,EAC9B,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS,MAAA;AAAA,EAC1D,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EACxB,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,MAAA;AAAA,EACvB,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS,OAAA;AAAA,EAAS,QAAA;AAAA,EAAU,MAAA;AAAA,EAAQ;AAC7D,CAAC,CAAA;AAEM,SAAS,YAAA,CAAa,MAAc,OAAA,EAA2B;AACpE,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAI,GAAA,CAAI,OAAO,CAAA,CAAE,MAAA;AAAA,EAC5B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,KAAA,GAAQ,+CAAA;AACd,EAAA,IAAI,KAAA;AACJ,EAAA,OAAA,CAAQ,KAAA,GAAQ,KAAA,CAAM,IAAA,CAAK,IAAI,OAAO,IAAA,EAAM;AAC1C,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA,EAAK;AAC3B,IAAA,IACE,IAAA,CAAK,UAAA,CAAW,SAAS,CAAA,IACzB,KAAK,UAAA,CAAW,MAAM,CAAA,IACtB,IAAA,CAAK,WAAW,aAAa,CAAA,IAC7B,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,EACnB;AAEF,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,IAAA,EAAM,OAAO,CAAA;AACtC,MAAA,IAAI,QAAA,CAAS,WAAW,MAAA,EAAQ;AAEhC,MAAA,MAAM,GAAA,GAAM,SAAS,QAAA,CAAS,WAAA,GAAc,KAAA,CAAM,QAAQ,IAAI,CAAC,CAAA;AAC/D,MAAA,IAAI,GAAA,IAAO,eAAA,CAAgB,GAAA,CAAI,GAAG,CAAA,EAAG;AAErC,MAAA,KAAA,CAAM,IAAA,CAAK,YAAA,CAAa,QAAA,CAAS,QAAA,EAAU,CAAC,CAAA;AAAA,IAC9C,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,KAAK,CAAC,CAAA;AAC3B;AAMA,SAAS,SAAA,CAAU,KAAa,OAAA,EAA0B;AACxD,EAAA,MAAM,QAAQ,OAAA,CACX,OAAA,CAAQ,mBAAA,EAAqB,MAAM,EACnC,OAAA,CAAQ,OAAA,EAAS,gBAAgB,CAAA,CACjC,QAAQ,KAAA,EAAO,OAAO,CAAA,CACtB,OAAA,CAAQ,uBAAuB,IAAI,CAAA;AACtC,EAAA,OAAO,IAAI,MAAA,CAAO,KAAK,CAAA,CAAE,KAAK,GAAG,CAAA;AACnC;AAEA,SAAS,aAAA,CAAc,GAAA,EAAa,OAAA,EAAoB,OAAA,EAA6B;AACnF,EAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,IAAA,KAAA,MAAW,WAAW,OAAA,EAAS;AAC7B,MAAA,IAAI,SAAA,CAAU,GAAA,EAAK,OAAO,CAAA,EAAG,OAAO,KAAA;AAAA,IACtC;AAAA,EACF;AACA,EAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,IAAA,OAAO,QAAQ,IAAA,CAAK,CAAA,OAAA,KAAW,SAAA,CAAU,GAAA,EAAK,OAAO,CAAC,CAAA;AAAA,EACxD;AACA,EAAA,OAAO,IAAA;AACT;AAMA,SAASE,OAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACvD;AAEA,eAAsB,MAAM,OAAA,EAA6C;AACvE,EAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,EAAA,MAAM;AAAA,IACJ,GAAA,EAAK,QAAA;AAAA,IACL,OAAO,QAAA,GAAW,CAAA;AAAA,IAClB,KAAA,GAAQ,EAAA;AAAA,IACR,IAAA,GAAO,MAAA;AAAA,IACP,OAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAA,GAAc,CAAA;AAAA,IACd,aAAA,GAAgB;AAAA,GAClB,GAAI,OAAA;AAGJ,EAAA,IAAI,CAACF,WAAAA,CAAW,QAAQ,CAAA,EAAG;AACzB,IAAA,MAAM,IAAI,UAAA,CAAW,aAAA,EAAe,MAAA,EAAW,KAAK,CAAA;AAAA,EACtD;AACA,EAAA,IAAI,WAAW,CAAA,EAAG,MAAM,IAAI,UAAA,CAAW,oBAAA,EAAsB,QAAW,KAAK,CAAA;AAC7E,EAAA,IAAI,QAAQ,CAAA,EAAG,MAAM,IAAI,UAAA,CAAW,oBAAA,EAAsB,QAAW,KAAK,CAAA;AAC1E,EAAA,IAAI,cAAc,CAAA,EAAG,MAAM,IAAI,UAAA,CAAW,0BAAA,EAA4B,QAAW,KAAK,CAAA;AACtF,EAAA,IAAI,YAAY,MAAA,KAAc,OAAA,IAAW,KAAK,MAAA,CAAO,KAAA,CAAM,OAAO,CAAA,CAAA,EAAI;AACpE,IAAA,MAAM,IAAI,UAAA,CAAW,mCAAA,EAAqC,MAAA,EAAW,KAAK,CAAA;AAAA,EAC5E;AAEA,EAAA,MAAM,QAA2B,EAAC;AAClC,EAAA,MAAM,SAAuB,EAAC;AAC9B,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,IAAI,eAAA,GAAkB,CAAA;AACtB,EAAA,IAAI,YAAA,GAAe,CAAA;AAEnB,EAAA,MAAM,eAAA,GAAkB,aAAa,QAAQ,CAAA;AAC7C,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,QAAQ,CAAA,CAAE,MAAA;AAGjC,EAAA,IAAI,UAAA,GAA4B,IAAA;AAChC,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,UAAA,GAAa,MAAM,aAAA,CAAc,QAAA,EAAU,OAAO,CAAA;AAClD,IAAA,MAAM,OAAA,GAAU,MAAM,iBAAA,CAAkB,QAAA,EAAU,OAAO,CAAA;AACzD,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO;AAAA,QACL,OAAO,EAAC;AAAA,QACR,eAAA,EAAiB,CAAA;AAAA,QACjB,YAAA,EAAc,CAAA;AAAA,QACd,YAAA,EAAc,CAAA;AAAA,QACd,QAAQ,EAAC;AAAA,QACT,QAAA,EAAU,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,OACzB;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,KAAA,GAA+C;AAAA,IACnD,EAAE,GAAA,EAAK,eAAA,EAAiB,KAAA,EAAO,CAAA;AAAE,GACnC;AAEA,EAAA,IAAI,WAAW,CAAA,EAAG;AAChB,IAAA,IAAI;AACF,MAAA,MAAM,iBAAiB,MAAM,YAAA,CAAa,CAAA,EAAG,MAAM,gBAAgB,OAAO,CAAA;AAC1E,MAAA,MAAM,IAAA,mBAAO,IAAI,GAAA,CAAY,CAAC,eAAe,CAAC,CAAA;AAC9C,MAAA,KAAA,MAAW,SAAS,cAAA,EAAgB;AAClC,QAAA,MAAM,UAAA,GAAa,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA;AACzC,QAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,UAAU,CAAA,EAAG;AACzB,UAAA,IAAA,CAAK,IAAI,UAAU,CAAA;AACnB,UAAA,KAAA,CAAM,KAAK,EAAE,GAAA,EAAK,UAAA,EAAY,KAAA,EAAO,GAAG,CAAA;AAAA,QAC1C;AAAA,MACF;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,kCAAA,EAAqC,MAAM,CAAA,EAAA,EAAK,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA,CAAE,CAAA;AAAA,IAClH;AAAA,EACF;AAEA,EAAA,eAAA,GAAkB,KAAA,CAAM,MAAA;AAGxB,EAAA,OAAO,KAAA,CAAM,MAAA,GAAS,CAAA,IAAK,KAAA,CAAM,SAAS,KAAA,EAAO;AAC/C,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,CAAI,WAAA,EAAa,QAAQ,KAAA,CAAM,MAAA,EAAQ,MAAM,MAAM,CAAA;AAC1E,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,MAAA,CAAO,CAAA,EAAG,SAAS,CAAA;AAEvC,IAAA,MAAM,QAAQ,KAAA,CAAM,GAAA,CAAI,OAAO,EAAE,GAAA,EAAK,OAAM,KAAM;AAChD,MAAA,MAAM,UAAA,GAAa,aAAa,GAAG,CAAA;AAEnC,MAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA,EAAG;AAC3B,QAAA,YAAA,EAAA;AACA,QAAA;AAAA,MACF;AACA,MAAA,OAAA,CAAQ,IAAI,UAAU,CAAA;AAGtB,MAAA,IAAI,eAAe,eAAA,IAAmB,CAAC,cAAc,UAAA,EAAY,OAAA,EAAS,OAAO,CAAA,EAAG;AAClF,QAAA,YAAA,EAAA;AACA,QAAA;AAAA,MACF;AAGA,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,MAAM,OAAA,GAAU,MAAM,iBAAA,CAAkB,GAAA,EAAK,OAAO,CAAA;AACpD,QAAA,IAAI,CAAC,OAAA,EAAS;AACZ,UAAA,YAAA,EAAA;AACA,UAAA;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,cAAc,MAAM,aAAA,CAAc,KAAK,IAAA,EAAM,EAAE,SAAS,CAAA;AAC9D,QAAA,MAAM,aAAA,GAAgB,MAAM,cAAA,CAAe,WAAW,CAAA;AACtD,QAAA,MAAM,aAAA,GAAgB,MAAM,iBAAA,CAAkB,aAAa,CAAA;AAE3D,QAAA,MAAM,UAAA,GAA8B;AAAA,UAClC,UAAU,aAAA,CAAc,QAAA;AAAA,UACxB,YAAY,aAAA,CAAc,UAAA;AAAA,UAC1B,OAAO,aAAA,CAAc,KAAA;AAAA,UACrB,QAAQ,aAAA,CAAc,MAAA;AAAA,UACtB,UAAU,aAAA,CAAc,QAAA;AAAA,UACxB,aAAa,aAAA,CAAc,WAAA;AAAA,UAC3B,KAAK,WAAA,CAAY,GAAA;AAAA,UACjB;AAAA,SACF;AAEA,QAAA,KAAA,CAAM,KAAK,UAAU,CAAA;AAGrB,QAAA,IAAI,QAAQ,QAAA,EAAU;AACpB,UAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,WAAA,CAAY,IAAA,EAAM,YAAY,GAAG,CAAA;AAC5D,UAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,YAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA,EAAG;AACtB,cAAA,KAAA,CAAM,KAAK,EAAE,GAAA,EAAK,MAAM,KAAA,EAAO,KAAA,GAAQ,GAAG,CAAA;AAC1C,cAAA,eAAA,EAAA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,GAAA,EAAK;AACZ,QAAA,MAAA,CAAO,IAAA,CAAK;AAAA,UACV,GAAA;AAAA,UACA,OAAO,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAAA,UACtD;AAAA,SACD,CAAA;AAAA,MACH;AAAA,IACF,CAAC,CAAA;AAED,IAAA,MAAM,OAAA,CAAQ,WAAW,KAAK,CAAA;AAG9B,IAAA,IAAI,UAAA,IAAc,UAAA,GAAa,CAAA,IAAK,KAAA,CAAM,SAAS,CAAA,EAAG;AACpD,MAAA,MAAME,MAAAA,CAAM,aAAa,GAAI,CAAA;AAAA,IAC/B;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,eAAA;AAAA,IACA,cAAc,KAAA,CAAM,MAAA;AAAA,IACpB,YAAA;AAAA,IACA,MAAA;AAAA,IACA,QAAA,EAAU,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,GACzB;AACF;AC9QA,IAAM,WAAA,GAAc,IAAA,CAAK,OAAA,EAAQ,EAAG,oBAAoB,aAAa,CAAA;AACrE,IAAM,YAAA,GAAe,OAAA,CAAQ,GAAA,CAAI,eAAA,IAAmB,+BAAA;AAEpD,IAAI,MAAA,GAAwB,IAAA;AAC5B,IAAI,SAAA,GAAY,KAAA;AAEhB,SAAS,UAAA,GAA4B;AACnC,EAAA,IAAI,WAAW,OAAO,MAAA;AACtB,EAAA,SAAA,GAAY,IAAA;AAGZ,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,YAAA,KAAiB,KAAA,EAAO;AACtC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,SAAS,IAAA,CAAK,KAAA,CAAM,YAAA,CAAa,WAAA,EAAa,OAAO,CAAC,CAAA;AAG5D,IAAA,IAAI,MAAA,CAAO,cAAc,KAAA,EAAO;AAC9B,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAA,GAAS,OAAO,OAAA,IAAW,IAAA;AAC3B,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAcO,SAAS,mBAAmB,OAAA,EAAwC;AACzE,EAAA,MAAM,MAAM,UAAA,EAAW;AACvB,EAAA,IAAI,CAAC,GAAA,EAAK;AAGV,EAAA,KAAA,CAAM,CAAA,EAAG,YAAY,CAAA,aAAA,CAAA,EAAiB;AAAA,IACpC,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS;AAAA,MACP,cAAA,EAAgB,kBAAA;AAAA,MAChB,aAAA,EAAe,UAAU,GAAG,CAAA;AAAA,KAC9B;AAAA,IACA,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,MACnB,OAAA,EAAS,SAAA;AAAA,MACT,UAAA,EAAY,OAAA,CAAQ,OAAA,GAAU,UAAA,GAAa,OAAA;AAAA,MAC3C;AAAA,KACD;AAAA,GACF,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,EAEf,CAAC,CAAA;AACH;;;ACPA,eAAsB,MAAA,CACpB,GAAA,EACA,OAAA,GAAyB,EAAC,EACH;AACvB,EAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,EAAA,MAAM,IAAA,GAAkB,QAAQ,IAAA,IAAQ,MAAA;AAGxC,EAAA,IAAI,OAAA,CAAQ,OAAA,KAAY,MAAA,KAAc,OAAA,CAAQ,OAAA,IAAW,KAAK,MAAA,CAAO,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,CAAA,EAAI;AAC5F,IAAA,MAAM,IAAI,UAAA,CAAW,mCAAA,EAAqC,MAAA,EAAW,KAAK,CAAA;AAAA,EAC5E;AAEA,EAAA,IAAI;AAEF,IAAA,IAAI,QAAQ,aAAA,EAAe;AACzB,MAAA,MAAM,OAAA,GAAU,MAAM,iBAAA,CAAkB,GAAA,EAAK,QAAQ,OAAO,CAAA;AAC5D,MAAA,IAAI,CAAC,OAAA,EAAS;AACZ,QAAA,MAAM,IAAI,UAAA,CAAW,CAAA,uBAAA,EAA0B,GAAG,CAAA,CAAA,EAAI,QAAW,KAAK,CAAA;AAAA,MACxE;AAAA,IACF;AAGA,IAAA,MAAM,WAAA,GAAc,MAAM,aAAA,CAAc,GAAA,EAAK,IAAA,EAAM;AAAA,MACjD,SAAS,OAAA,CAAQ,OAAA;AAAA,MACjB,YAAY,OAAA,CAAQ,UAAA;AAAA,MACpB,WAAW,OAAA,CAAQ;AAAA,KACpB,CAAA;AAGD,IAAA,MAAM,aAAA,GAAgB,MAAM,cAAA,CAAe,WAAW,CAAA;AAGtD,IAAA,MAAM,aAAA,GAAgB,MAAM,iBAAA,CAAkB,aAAa,CAAA;AAE3D,IAAA,MAAM,MAAA,GAAuB;AAAA,MAC3B,UAAU,aAAA,CAAc,QAAA;AAAA,MACxB,YAAY,aAAA,CAAc,UAAA;AAAA,MAC1B,OAAO,aAAA,CAAc,KAAA;AAAA,MACrB,QAAQ,aAAA,CAAc,MAAA;AAAA,MACtB,UAAU,aAAA,CAAc,QAAA;AAAA,MACxB,aAAa,aAAA,CAAc,WAAA;AAAA,MAC3B,KAAK,WAAA,CAAY;AAAA,KACnB;AAGA,IAAA,kBAAA,CAAmB;AAAA,MACjB,GAAA;AAAA,MACA,YAAY,aAAA,CAAc,UAAA;AAAA,MAC1B,OAAO,aAAA,CAAc,KAAA;AAAA,MACrB,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAAA,MACxB,OAAA,EAAS;AAAA,KACV,CAAA;AAED,IAAA,OAAO,MAAA;AAAA,EACT,SAAS,GAAA,EAAK;AAEZ,IAAA,kBAAA,CAAmB;AAAA,MACjB,GAAA;AAAA,MACA,UAAA,EAAY,CAAA;AAAA,MACZ,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAAA,MACxB,OAAA,EAAS,KAAA;AAAA,MACT,OAAO,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG;AAAA,KACvD,CAAA;AAED,IAAA,MAAM,GAAA;AAAA,EACR;AACF","file":"index.js","sourcesContent":["/**\n * Layer 1: Fetch\n * HTTP fetching with smart headers and retries\n */\n\nimport type { FetchResult } from './types.js';\n\nconst USER_AGENTS = [\n 'Mozilla/5.0 (compatible; ScraperBot/1.0; +https://scraper.robotresources.ai)',\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n];\n\nconst DEFAULT_TIMEOUT = 10000;\nconst DEFAULT_MAX_RETRIES = 3;\nconst BASE_BACKOFF_MS = 1000;\n\nexport interface FetchOptions {\n timeout?: number;\n maxRetries?: number;\n userAgent?: string;\n}\n\n/**\n * Error class for fetch-related errors\n */\nexport class FetchError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly retryable: boolean = false\n ) {\n super(message);\n this.name = 'FetchError';\n }\n}\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nfunction getRandomUserAgent(): string {\n return USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];\n}\n\nfunction buildHeaders(userAgent?: string): Record<string, string> {\n return {\n 'User-Agent': userAgent || getRandomUserAgent(),\n Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n 'Accept-Language': 'en-US,en;q=0.9',\n 'Accept-Encoding': 'gzip, deflate',\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n };\n}\n\nfunction headersToObject(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key.toLowerCase()] = value;\n });\n return result;\n}\n\nfunction isRetryableStatus(status: number): boolean {\n return status >= 500 && status < 600;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction getBackoffDelay(attempt: number): number {\n return BASE_BACKOFF_MS * Math.pow(2, attempt);\n}\n\nasync function fetchWithTimeout(\n url: string,\n headers: Record<string, string>,\n timeout: number\n): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers,\n signal: controller.signal,\n redirect: 'follow',\n });\n return response;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new FetchError('Request timeout', undefined, true);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\n/**\n * Fetch URL content with smart headers and retry logic\n */\nexport async function fetchUrl(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const {\n timeout = DEFAULT_TIMEOUT,\n maxRetries = DEFAULT_MAX_RETRIES,\n userAgent,\n } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n const headers = buildHeaders(userAgent);\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await fetchWithTimeout(url, headers, timeout);\n\n if (!response.ok) {\n const statusCode = response.status;\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (isRetryableStatus(statusCode)) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n }\n\n const html = await response.text();\n const responseHeaders = headersToObject(response.headers);\n\n return {\n html,\n url: response.url,\n statusCode: response.status,\n headers: responseHeaders,\n };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n const isRetryable =\n error instanceof FetchError\n ? error.retryable\n : !(error instanceof FetchError);\n\n const hasRetriesLeft = attempt < maxRetries;\n\n if (isRetryable && hasRetriesLeft) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n\n break;\n }\n }\n\n throw lastError || new FetchError('Unknown fetch error');\n}\n","/**\n * Layer 1b: Stealth Fetch\n * TLS fingerprint impersonation via impit (optional peer dependency)\n *\n * Uses Rust-based browser TLS fingerprinting to bypass anti-bot systems\n * (Cloudflare, Akamai, PerimeterX) without a full browser.\n *\n * Requires: npm install impit (Node >= 20)\n */\n\nimport type { FetchResult } from './types.js';\nimport { FetchError } from './fetch.js';\nimport type { FetchOptions } from './fetch.js';\n\nconst DEFAULT_TIMEOUT = 10000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst BASE_BACKOFF_MS = 1000;\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nfunction isRetryableStatus(status: number): boolean {\n return status >= 500 && status < 600;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction getBackoffDelay(attempt: number): number {\n return BASE_BACKOFF_MS * Math.pow(2, attempt);\n}\n\n/**\n * Fetch URL with browser TLS fingerprint impersonation.\n *\n * Uses impit (Apify) to produce Chrome-like JA3/JA4 fingerprints at the\n * TLS handshake level. This bypasses anti-bot systems that reject default\n * Node.js TLS signatures.\n *\n * impit is an optional peer dependency — if not installed, throws a clear\n * error message with install instructions.\n */\nexport async function fetchStealth(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const {\n timeout = DEFAULT_TIMEOUT,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n // Dynamic import — impit is an optional peer dependency\n let Impit: any;\n try {\n // @ts-expect-error impit is an optional peer dependency (not installed in dev)\n ({ Impit } = await import('impit'));\n } catch {\n throw new FetchError(\n 'impit is required for stealth mode. Install: npm install impit (requires Node >= 20)',\n undefined,\n false\n );\n }\n\n const client = new Impit({ browser: 'chrome' });\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await client.fetch(url, {\n signal: AbortSignal.timeout(timeout),\n });\n\n if (!response.ok) {\n const statusCode = response.status;\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (isRetryableStatus(statusCode)) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n }\n\n const html = await response.text();\n const headers: Record<string, string> = {};\n response.headers.forEach((value: string, key: string) => {\n headers[key] = value;\n });\n\n return {\n html,\n url: response.url ?? url,\n statusCode: response.status,\n headers,\n };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n const isRetryable =\n error instanceof FetchError\n ? error.retryable\n : !(error instanceof FetchError);\n\n const hasRetriesLeft = attempt < maxRetries;\n\n if (isRetryable && hasRetriesLeft) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n\n break;\n }\n }\n\n throw lastError || new FetchError('Unknown stealth fetch error');\n}\n","/**\n * Layer 1c: Render Fetch\n * Playwright headless browser for JS-rendered pages (optional peer dependency)\n *\n * Uses Chromium to fully render SPAs (React, Next.js, Vue) that return\n * empty/partial HTML to tiers 1 and 2. Extracts the fully rendered DOM.\n *\n * Requires: npm install playwright\n */\n\nimport type { FetchResult } from './types.js';\nimport { FetchError } from './fetch.js';\nimport type { FetchOptions } from './fetch.js';\n\nconst DEFAULT_TIMEOUT = 30000;\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\n/**\n * Fetch URL using a headless Chromium browser to render JavaScript.\n *\n * Launches a fresh browser per call (no shared state), navigates to the URL,\n * waits for network idle, then extracts the fully rendered HTML.\n *\n * Playwright is an optional peer dependency — if not installed, throws a clear\n * error message with install instructions.\n */\nexport async function fetchRender(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const { timeout = DEFAULT_TIMEOUT } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n // Dynamic import — Playwright is an optional peer dependency\n let chromium: any;\n try {\n // @ts-expect-error playwright is an optional peer dependency (not installed in dev)\n ({ chromium } = await import('playwright'));\n } catch {\n throw new FetchError(\n 'Playwright is required for render mode. Install: npm install playwright',\n undefined,\n false\n );\n }\n\n const browser = await chromium.launch({ headless: true });\n\n try {\n const page = await browser.newPage();\n\n // Auto-dismiss dialogs to prevent hanging\n page.on('dialog', (dialog: any) => dialog.dismiss());\n\n const response = await page.goto(url, {\n waitUntil: 'networkidle',\n timeout,\n });\n\n if (!response) {\n throw new FetchError(\n 'Navigation returned no response (about:blank or same-URL redirect)',\n undefined,\n false\n );\n }\n\n const statusCode = response.status();\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (statusCode >= 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n\n const html = await page.content();\n const headers: Record<string, string> = response.headers();\n\n return {\n html,\n url: page.url(),\n statusCode,\n headers,\n };\n } catch (error) {\n // Convert Playwright timeout errors to retryable FetchErrors\n if (error instanceof Error && error.name === 'TimeoutError') {\n throw new FetchError('Navigation timeout', undefined, true);\n }\n throw error;\n } finally {\n await browser.close();\n }\n}\n","/**\n * Layer 2: Extract\n * Content extraction using Readability\n */\n\nimport { Readability } from '@mozilla/readability';\nimport { parseHTML } from 'linkedom';\nimport type { FetchResult, ExtractResult } from './types.js';\n\n/**\n * Error class for extraction-related errors\n */\nexport class ExtractionError extends Error {\n constructor(\n message: string,\n public readonly code: string\n ) {\n super(message);\n this.name = 'ExtractionError';\n }\n}\n\n/**\n * Extract main content from HTML using Readability\n */\nexport async function extractContent(\n fetchResult: FetchResult\n): Promise<ExtractResult> {\n const { html } = fetchResult;\n\n if (!html || !html.trim()) {\n throw new ExtractionError('Empty HTML content', 'EMPTY_HTML');\n }\n\n const { document } = parseHTML(html);\n\n const reader = new Readability(document, {\n charThreshold: 50,\n });\n\n const article = reader.parse();\n\n if (!article || !article.content || article.content.trim().length < 20) {\n throw new ExtractionError(\n 'No content could be extracted from the page',\n 'NO_CONTENT'\n );\n }\n\n const result: ExtractResult = {\n content: cleanContent(article.content),\n title: article.title || extractFallbackTitle(document),\n author: article.byline || undefined,\n publishedAt: article.publishedTime || extractPublishedTime(document),\n siteName: article.siteName || extractSiteName(document),\n };\n\n return result;\n}\n\nfunction cleanContent(content: string): string {\n return content\n .replace(/>\\s+</g, '><')\n .replace(/\\s{2,}/g, ' ')\n .trim();\n}\n\nfunction extractFallbackTitle(document: Document): string | undefined {\n const ogTitle = document.querySelector('meta[property=\"og:title\"]');\n if (ogTitle) {\n const content = ogTitle.getAttribute('content');\n if (content) return content;\n }\n\n const titleEl = document.querySelector('title');\n if (titleEl && titleEl.textContent) {\n return titleEl.textContent.trim();\n }\n\n const h1 = document.querySelector('h1');\n if (h1 && h1.textContent) {\n return h1.textContent.trim();\n }\n\n return undefined;\n}\n\nfunction extractPublishedTime(document: Document): string | undefined {\n const ogTime = document.querySelector(\n 'meta[property=\"article:published_time\"]'\n );\n if (ogTime) {\n const content = ogTime.getAttribute('content');\n if (content) return content;\n }\n\n const schemaTime = document.querySelector('[itemprop=\"datePublished\"]');\n if (schemaTime) {\n const datetime = schemaTime.getAttribute('datetime');\n if (datetime) return datetime;\n const content = schemaTime.getAttribute('content');\n if (content) return content;\n }\n\n const timeEl = document.querySelector('time[datetime]');\n if (timeEl) {\n const datetime = timeEl.getAttribute('datetime');\n if (datetime) return datetime;\n }\n\n return undefined;\n}\n\nfunction extractSiteName(document: Document): string | undefined {\n const ogSiteName = document.querySelector('meta[property=\"og:site_name\"]');\n if (ogSiteName) {\n const content = ogSiteName.getAttribute('content');\n if (content) return content;\n }\n\n const appName = document.querySelector('meta[name=\"application-name\"]');\n if (appName) {\n const content = appName.getAttribute('content');\n if (content) return content;\n }\n\n return undefined;\n}\n","/**\n * Layer 3: Convert\n * HTML to Markdown conversion\n */\n\nimport TurndownService from 'turndown';\nimport type { ExtractResult, ConvertResult } from './types.js';\n\nfunction createTurndownService(): TurndownService {\n const turndown = new TurndownService({\n headingStyle: 'atx',\n hr: '---',\n bulletListMarker: '-',\n codeBlockStyle: 'fenced',\n fence: '```',\n emDelimiter: '*',\n strongDelimiter: '**',\n linkStyle: 'inlined',\n });\n\n turndown.remove(['script', 'style', 'noscript', 'iframe']);\n\n turndown.addRule('removeEmpty', {\n filter: (node) => {\n if (node.nodeType === 1) {\n const text = node.textContent || '';\n const isEmptyBlock =\n text.trim() === '' &&\n !['IMG', 'BR', 'HR', 'INPUT'].includes(node.nodeName);\n return isEmptyBlock;\n }\n return false;\n },\n replacement: () => '',\n });\n\n turndown.addRule('fencedCodeBlock', {\n filter: (node, options) => {\n return (\n options.codeBlockStyle === 'fenced' &&\n node.nodeName === 'PRE' &&\n node.firstChild !== null &&\n node.firstChild.nodeName === 'CODE'\n );\n },\n replacement: (_content, node, options) => {\n const codeNode = node.firstChild as Element;\n const code = codeNode.textContent || '';\n\n const className = codeNode.getAttribute('class') || '';\n const langMatch = className.match(/language-(\\w+)/);\n const lang = langMatch ? langMatch[1] : '';\n\n const fence = options.fence || '```';\n return `\\n\\n${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n },\n });\n\n turndown.addRule('strikethrough', {\n filter: ['del', 's'] as const,\n replacement: (content) => `~~${content}~~`,\n });\n\n return turndown;\n}\n\nlet turndownInstance: TurndownService | null = null;\n\nfunction getTurndown(): TurndownService {\n if (!turndownInstance) {\n turndownInstance = createTurndownService();\n }\n return turndownInstance;\n}\n\nfunction cleanMarkdown(markdown: string): string {\n return markdown\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/[ \\t]+$/gm, '')\n .replace(/^\\n+/, '')\n .replace(/\\n+$/, '')\n .trim();\n}\n\n/**\n * Convert extracted HTML to clean Markdown\n */\nexport async function convertToMarkdown(\n extractResult: ExtractResult\n): Promise<ConvertResult> {\n const { content } = extractResult;\n\n if (!content || !content.trim()) {\n return {\n markdown: '',\n tokenCount: 0,\n };\n }\n\n const turndown = getTurndown();\n let markdown = turndown.turndown(content);\n\n markdown = cleanMarkdown(markdown);\n\n const tokenCount = estimateTokens(markdown);\n\n return {\n markdown,\n tokenCount,\n };\n}\n\n/**\n * Content-aware token estimator.\n *\n * Segments text by content type and applies calibrated character-per-token\n * ratios derived from cl100k_base (GPT-4) empirical measurements.\n *\n * Ratios:\n * Code blocks — 3.2 chars/token (operators, camelCase split into subwords)\n * Inline code — 3.5 chars/token (variable names, short expressions)\n * URLs — 5.0 chars/token (path segments tokenize efficiently)\n * Prose — 4.3 chars/token (words, punctuation, markdown formatting)\n *\n * Accuracy: within ±15% of actual BPE tokenization for English content.\n */\nexport function estimateTokens(text: string): number {\n if (!text) return 0;\n\n let tokens = 0;\n let remaining = text;\n\n // Code blocks: operators, identifiers → ~3.2 chars per token\n remaining = remaining.replace(/```[\\s\\S]*?```/g, (match) => {\n tokens += Math.ceil(match.length / 3.2);\n return ' ';\n });\n\n // Inline code: variables, short expressions → ~3.5 chars per token\n remaining = remaining.replace(/`[^`]+`/g, (match) => {\n tokens += Math.ceil(match.length / 3.5);\n return ' ';\n });\n\n // URLs: path segments, punctuation splitting → ~5.0 chars per token\n remaining = remaining.replace(/https?:\\/\\/\\S+/g, (match) => {\n tokens += Math.ceil(match.length / 5.0);\n return ' ';\n });\n\n // Prose: words, punctuation, markdown formatting → ~4.3 chars per token\n const proseLength = remaining.replace(/\\s+/g, ' ').trim().length;\n if (proseLength > 0) {\n tokens += Math.ceil(proseLength / 4.3);\n }\n\n return Math.max(1, tokens);\n}\n","/**\n * robots.txt compliance layer\n *\n * Opt-in for single-page scraping (respectRobots option),\n * foundation for FTR-ORG-019 crawl mode where it becomes default.\n */\n\nimport robotsParser from 'robots-parser';\n\ninterface RobotsCacheEntry {\n parser: ReturnType<typeof robotsParser>;\n expiresAt: number;\n}\n\nconst DEFAULT_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst BOT_USER_AGENT = 'ScraperBot';\n\nconst cache = new Map<string, RobotsCacheEntry>();\n\nfunction getRobotsUrl(url: string): string {\n const parsed = new URL(url);\n return `${parsed.protocol}//${parsed.host}/robots.txt`;\n}\n\nasync function getRobotsParser(\n url: string,\n timeout: number = DEFAULT_TIMEOUT_MS\n): Promise<ReturnType<typeof robotsParser>> {\n const robotsUrl = getRobotsUrl(url);\n\n const cached = cache.get(robotsUrl);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.parser;\n }\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(robotsUrl, {\n signal: controller.signal,\n headers: { 'User-Agent': BOT_USER_AGENT },\n });\n\n clearTimeout(timeoutId);\n\n const text = response.ok ? await response.text() : '';\n const parser = robotsParser(robotsUrl, text);\n\n cache.set(robotsUrl, {\n parser,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n\n return parser;\n } catch {\n // Fail-open: if robots.txt is unreachable, allow everything\n const parser = robotsParser(robotsUrl, '');\n cache.set(robotsUrl, {\n parser,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n return parser;\n }\n}\n\n/**\n * Check if a URL is allowed by robots.txt.\n * Returns true if allowed or if robots.txt cannot be fetched (fail-open).\n */\nexport async function isAllowedByRobots(\n url: string,\n timeout?: number\n): Promise<boolean> {\n const parser = await getRobotsParser(url, timeout);\n return parser.isAllowed(url, BOT_USER_AGENT) !== false;\n}\n\n/**\n * Extract Sitemap: URLs from robots.txt.\n * Returns empty array if no Sitemap directives or robots.txt unreachable (fail-open).\n * Reuses cached robots.txt parser.\n */\nexport async function getSitemapUrls(\n url: string,\n timeout?: number\n): Promise<string[]> {\n const parser = await getRobotsParser(url, timeout);\n return parser.getSitemaps();\n}\n\n/**\n * Extract Crawl-delay value from robots.txt for ScraperBot user agent.\n * Returns delay in seconds, or null if not specified or robots.txt unreachable (fail-open).\n * Reuses cached robots.txt parser.\n */\nexport async function getCrawlDelay(\n url: string,\n timeout?: number\n): Promise<number | null> {\n const parser = await getRobotsParser(url, timeout);\n const delay = parser.getCrawlDelay(BOT_USER_AGENT);\n return delay === undefined ? null : delay;\n}\n\n/**\n * Clear the robots.txt cache. Exported for testing.\n */\nexport function clearRobotsCache(): void {\n cache.clear();\n}\n","/**\n * Sitemap parser\n *\n * Fetches and parses sitemap.xml for crawl mode seed URLs.\n * Regex-based XML parsing — no XML parser dependency.\n * Handles sitemap index files with recursion limit.\n * Mirrors robots.ts fetch+cache+fail-open pattern.\n */\n\nconst DEFAULT_TIMEOUT_MS = 10000;\nconst DEFAULT_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst MAX_RECURSION_DEPTH = 2;\n\n/**\n * A single entry from a sitemap\n */\nexport interface SitemapEntry {\n /** URL from <loc> tag */\n loc: string;\n /** Last modification date from <lastmod> tag */\n lastmod?: string;\n /** Priority from <priority> tag (0.0 to 1.0) */\n priority?: number;\n}\n\ninterface SitemapCacheEntry {\n entries: SitemapEntry[];\n expiresAt: number;\n}\n\nconst cache = new Map<string, SitemapCacheEntry>();\n\n/**\n * Extract origin (protocol + host) from URL\n */\nfunction getOrigin(url: string): string {\n const parsed = new URL(url);\n return `${parsed.protocol}//${parsed.host}`;\n}\n\n/**\n * Check if XML contains a sitemap index\n */\nfunction isSitemapIndex(xml: string): boolean {\n return /<sitemapindex[\\s>]/i.test(xml);\n}\n\n/**\n * Extract sitemap URLs from a sitemap index\n * Handles namespace prefixes: <ns:loc>, <sitemap:loc>, etc.\n */\nfunction extractSitemapIndexUrls(xml: string): string[] {\n const urls: string[] = [];\n // Match <sitemap>...</sitemap> blocks, then extract <loc> from each\n const sitemapBlockRegex = /<(?:\\w+:)?sitemap\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?sitemap>/gi;\n let blockMatch;\n\n while ((blockMatch = sitemapBlockRegex.exec(xml)) !== null) {\n const block = blockMatch[1];\n const locMatch = /<(?:\\w+:)?loc\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?loc>/i.exec(block);\n if (locMatch) {\n const url = locMatch[1].trim();\n if (url) urls.push(url);\n }\n }\n\n return urls;\n}\n\n/**\n * Extract URL entries from a sitemap urlset\n * Handles namespace prefixes: <ns:url>, <ns:loc>, etc.\n */\nfunction extractUrlEntries(xml: string, origin: string): SitemapEntry[] {\n const entries: SitemapEntry[] = [];\n // Match <url>...</url> blocks\n const urlBlockRegex = /<(?:\\w+:)?url\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?url>/gi;\n let blockMatch;\n\n while ((blockMatch = urlBlockRegex.exec(xml)) !== null) {\n const block = blockMatch[1];\n\n // Extract <loc>\n const locMatch = /<(?:\\w+:)?loc\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?loc>/i.exec(block);\n if (!locMatch) continue;\n\n const loc = locMatch[1].trim();\n if (!loc) continue;\n\n // Same-origin filter\n try {\n if (getOrigin(loc) !== origin) continue;\n } catch {\n continue; // Invalid URL — skip\n }\n\n const entry: SitemapEntry = { loc };\n\n // Extract optional <lastmod>\n const lastmodMatch = /<(?:\\w+:)?lastmod\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?lastmod>/i.exec(block);\n if (lastmodMatch) {\n const lastmod = lastmodMatch[1].trim();\n if (lastmod) entry.lastmod = lastmod;\n }\n\n // Extract optional <priority>\n const priorityMatch = /<(?:\\w+:)?priority\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?priority>/i.exec(block);\n if (priorityMatch) {\n const priority = parseFloat(priorityMatch[1].trim());\n if (!isNaN(priority)) entry.priority = priority;\n }\n\n entries.push(entry);\n }\n\n return entries;\n}\n\n/**\n * Fetch sitemap XML with timeout\n */\nasync function fetchSitemapXml(\n url: string,\n timeout: number\n): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(url, {\n signal: controller.signal,\n headers: { 'User-Agent': 'ScraperBot/1.0' },\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) return null;\n\n return await response.text();\n } catch {\n return null; // Fail-open\n }\n}\n\n/**\n * Internal recursive parser with depth tracking\n */\nasync function parseSitemapInternal(\n url: string,\n origin: string,\n timeout: number,\n depth: number\n): Promise<SitemapEntry[]> {\n if (depth >= MAX_RECURSION_DEPTH) return [];\n\n const xml = await fetchSitemapXml(url, timeout);\n if (!xml) return [];\n\n // Check if this is a sitemap index\n if (isSitemapIndex(xml)) {\n const sitemapUrls = extractSitemapIndexUrls(xml);\n const allEntries: SitemapEntry[] = [];\n\n for (const sitemapUrl of sitemapUrls) {\n const entries = await parseSitemapInternal(\n sitemapUrl,\n origin,\n timeout,\n depth + 1\n );\n allEntries.push(...entries);\n }\n\n return allEntries;\n }\n\n // Regular sitemap — extract URL entries\n return extractUrlEntries(xml, origin);\n}\n\n/**\n * Parse a sitemap.xml and return URL entries.\n *\n * - Fetches the sitemap from the given URL\n * - Extracts <loc> URLs via regex (no XML parser dependency)\n * - Handles sitemap index files (recursive, max depth 2)\n * - Caches results per URL with 1-hour TTL\n * - Fail-open: returns empty array if sitemap is unreachable or invalid\n * - Filters to same-origin URLs only\n *\n * @param url - Full URL of the sitemap.xml\n * @param timeout - Fetch timeout in ms (default: 10000)\n * @returns Array of SitemapEntry objects\n */\nexport async function parseSitemap(\n url: string,\n timeout: number = DEFAULT_TIMEOUT_MS\n): Promise<SitemapEntry[]> {\n // Check cache\n const cached = cache.get(url);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.entries;\n }\n\n let origin: string;\n try {\n origin = getOrigin(url);\n } catch {\n return []; // Invalid URL — fail-open\n }\n\n const entries = await parseSitemapInternal(url, origin, timeout, 0);\n\n // Cache the result\n cache.set(url, {\n entries,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n\n return entries;\n}\n\n/**\n * Clear the sitemap cache. Exported for testing.\n */\nexport function clearSitemapCache(): void {\n cache.clear();\n}\n","/**\n * Mode-aware fetch routing with challenge detection.\n *\n * Shared between scrape() (index.ts) and crawl() (crawl.ts)\n * to avoid duplicating mode routing and challenge detection logic.\n */\n\nimport type { FetchResult, FetchMode } from './types.js';\nimport type { FetchOptions } from './fetch.js';\nimport { fetchUrl, FetchError } from './fetch.js';\nimport { fetchStealth } from './fetch-stealth.js';\nimport { fetchRender } from './fetch-render.js';\n\nconst CHALLENGE_MARKERS = [\n 'cf-browser-verification',\n 'Just a moment',\n '_cf_chl_opt',\n 'akamai-challenge',\n 'ak-challenge',\n];\n\n/**\n * Detect anti-bot challenge pages that return HTTP 200 but contain\n * challenge/verification HTML instead of real content.\n */\nexport function isChallengeResponse(fetchResult: FetchResult): boolean {\n return CHALLENGE_MARKERS.some(marker => fetchResult.html.includes(marker));\n}\n\n/**\n * Fetch a URL using the specified mode with auto-fallback support.\n *\n * Modes:\n * - 'fast': Tier 1 only (plain HTTP)\n * - 'stealth': Tier 2 only (TLS fingerprint)\n * - 'render': Tier 3 only (Playwright)\n * - 'auto': Fast first, fall back to stealth on 403 or challenge page\n */\nconst VALID_MODES: readonly string[] = ['fast', 'stealth', 'render', 'auto'];\n\nexport async function fetchWithMode(\n url: string,\n mode: FetchMode,\n options: FetchOptions,\n): Promise<FetchResult> {\n if (!VALID_MODES.includes(mode)) {\n throw new FetchError(\n `Invalid fetch mode: '${mode}'. Valid modes: ${VALID_MODES.join(', ')}`,\n undefined,\n false,\n );\n }\n\n if (mode === 'stealth') return fetchStealth(url, options);\n if (mode === 'render') return fetchRender(url, options);\n if (mode === 'fast') return fetchUrl(url, options);\n\n // auto: fast with fallback to stealth on 403 or challenge\n try {\n const result = await fetchUrl(url, options);\n if (isChallengeResponse(result)) {\n return fetchStealth(url, options);\n }\n return result;\n } catch (err) {\n if (err instanceof FetchError && err.statusCode === 403) {\n return fetchStealth(url, options);\n }\n throw err;\n }\n}\n","/**\n * Crawl: BFS multi-page orchestrator\n * TKT-SCRAPER-079: Crawl multiple pages from a starting URL\n *\n * Composes: sitemap seeding, robots.txt, link extraction, URL normalization,\n * depth/limit/filter constraints, concurrency, and scrape pipeline per page.\n */\n\nimport type {\n CrawlOptions,\n CrawlResult,\n CrawlPageResult,\n CrawlError,\n} from './types.js';\nimport { FetchError } from './fetch.js';\nimport { extractContent } from './extract.js';\nimport { convertToMarkdown } from './convert.js';\nimport { isAllowedByRobots, getCrawlDelay } from './robots.js';\nimport { parseSitemap } from './sitemap.js';\nimport { fetchWithMode } from './fetch-mode.js';\n\n// ============================================\n// URL utilities\n// ============================================\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nexport function normalizeUrl(url: string): string {\n try {\n const parsed = new URL(url);\n parsed.hash = '';\n let pathname = parsed.pathname;\n if (pathname.length > 1 && pathname.endsWith('/')) {\n pathname = pathname.slice(0, -1);\n }\n parsed.pathname = pathname;\n return parsed.toString();\n } catch {\n return url;\n }\n}\n\nconst SKIP_EXTENSIONS = new Set([\n '.pdf', '.jpg', '.jpeg', '.png', '.gif', '.svg', '.webp', '.ico',\n '.mp4', '.mp3', '.wav', '.avi',\n '.zip', '.tar', '.gz', '.rar',\n '.css', '.js', '.xml', '.json', '.woff', '.woff2', '.ttf', '.eot',\n]);\n\nexport function extractLinks(html: string, baseUrl: string): string[] {\n const links: string[] = [];\n let origin: string;\n try {\n origin = new URL(baseUrl).origin;\n } catch {\n return [];\n }\n\n const regex = /<a\\s+[^>]*href\\s*=\\s*[\"']([^\"']+)[\"'][^>]*>/gi;\n let match;\n while ((match = regex.exec(html)) !== null) {\n const href = match[1].trim();\n if (\n href.startsWith('mailto:') ||\n href.startsWith('tel:') ||\n href.startsWith('javascript:') ||\n href.startsWith('#')\n ) continue;\n\n try {\n const resolved = new URL(href, baseUrl);\n if (resolved.origin !== origin) continue;\n\n const ext = resolved.pathname.toLowerCase().match(/\\.\\w+$/)?.[0];\n if (ext && SKIP_EXTENSIONS.has(ext)) continue;\n\n links.push(normalizeUrl(resolved.toString()));\n } catch {\n // Invalid URL, skip\n }\n }\n\n return [...new Set(links)];\n}\n\n// ============================================\n// URL filtering\n// ============================================\n\nfunction matchGlob(url: string, pattern: string): boolean {\n const regex = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n .replace(/\\*\\*/g, '{{DOUBLESTAR}}')\n .replace(/\\*/g, '[^/]*')\n .replace(/\\{\\{DOUBLESTAR\\}\\}/g, '.*');\n return new RegExp(regex).test(url);\n}\n\nfunction matchesFilter(url: string, include?: string[], exclude?: string[]): boolean {\n if (exclude?.length) {\n for (const pattern of exclude) {\n if (matchGlob(url, pattern)) return false;\n }\n }\n if (include?.length) {\n return include.some(pattern => matchGlob(url, pattern));\n }\n return true;\n}\n\n// ============================================\n// Crawl\n// ============================================\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nexport async function crawl(options: CrawlOptions): Promise<CrawlResult> {\n const startTime = Date.now();\n\n const {\n url: startUrl,\n depth: maxDepth = 2,\n limit = 50,\n mode = 'auto',\n include,\n exclude,\n timeout,\n concurrency = 3,\n respectRobots = true,\n } = options;\n\n // Validation\n if (!isValidUrl(startUrl)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n if (maxDepth < 0) throw new FetchError('depth must be >= 0', undefined, false);\n if (limit < 1) throw new FetchError('limit must be >= 1', undefined, false);\n if (concurrency < 1) throw new FetchError('concurrency must be >= 1', undefined, false);\n if (timeout !== undefined && (timeout <= 0 || Number.isNaN(timeout))) {\n throw new FetchError('timeout must be a positive number', undefined, false);\n }\n\n const pages: CrawlPageResult[] = [];\n const errors: CrawlError[] = [];\n const visited = new Set<string>();\n let totalDiscovered = 0;\n let totalSkipped = 0;\n\n const normalizedStart = normalizeUrl(startUrl);\n const origin = new URL(startUrl).origin;\n\n // Robots.txt + crawl delay\n let crawlDelay: number | null = null;\n if (respectRobots) {\n crawlDelay = await getCrawlDelay(startUrl, timeout);\n const allowed = await isAllowedByRobots(startUrl, timeout);\n if (!allowed) {\n return {\n pages: [],\n totalDiscovered: 1,\n totalCrawled: 0,\n totalSkipped: 1,\n errors: [],\n duration: Date.now() - startTime,\n };\n }\n }\n\n // Seed: start URL + sitemap URLs\n const queue: Array<{ url: string; depth: number }> = [\n { url: normalizedStart, depth: 0 },\n ];\n\n if (maxDepth > 0) {\n try {\n const sitemapEntries = await parseSitemap(`${origin}/sitemap.xml`, timeout);\n const seen = new Set<string>([normalizedStart]);\n for (const entry of sitemapEntries) {\n const normalized = normalizeUrl(entry.loc);\n if (!seen.has(normalized)) {\n seen.add(normalized);\n queue.push({ url: normalized, depth: 1 });\n }\n }\n } catch (err) {\n console.debug(`[scraper] Sitemap unavailable for ${origin}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n totalDiscovered = queue.length;\n\n // BFS loop\n while (queue.length > 0 && pages.length < limit) {\n const batchSize = Math.min(concurrency, limit - pages.length, queue.length);\n const batch = queue.splice(0, batchSize);\n\n const tasks = batch.map(async ({ url, depth }) => {\n const normalized = normalizeUrl(url);\n\n if (visited.has(normalized)) {\n totalSkipped++;\n return;\n }\n visited.add(normalized);\n\n // URL filter check (start URL is exempt — it's the user's explicit seed)\n if (normalized !== normalizedStart && !matchesFilter(normalized, include, exclude)) {\n totalSkipped++;\n return;\n }\n\n // Per-URL robots check\n if (respectRobots) {\n const allowed = await isAllowedByRobots(url, timeout);\n if (!allowed) {\n totalSkipped++;\n return;\n }\n }\n\n try {\n const fetchResult = await fetchWithMode(url, mode, { timeout });\n const extractResult = await extractContent(fetchResult);\n const convertResult = await convertToMarkdown(extractResult);\n\n const pageResult: CrawlPageResult = {\n markdown: convertResult.markdown,\n tokenCount: convertResult.tokenCount,\n title: extractResult.title,\n author: extractResult.author,\n siteName: extractResult.siteName,\n publishedAt: extractResult.publishedAt,\n url: fetchResult.url,\n depth,\n };\n\n pages.push(pageResult);\n\n // Extract links for next depth level\n if (depth < maxDepth) {\n const links = extractLinks(fetchResult.html, fetchResult.url);\n for (const link of links) {\n if (!visited.has(link)) {\n queue.push({ url: link, depth: depth + 1 });\n totalDiscovered++;\n }\n }\n }\n } catch (err) {\n errors.push({\n url,\n error: err instanceof Error ? err.message : String(err),\n depth,\n });\n }\n });\n\n await Promise.allSettled(tasks);\n\n // Crawl delay between batches\n if (crawlDelay && crawlDelay > 0 && queue.length > 0) {\n await sleep(crawlDelay * 1000);\n }\n }\n\n return {\n pages,\n totalDiscovered,\n totalCrawled: pages.length,\n totalSkipped,\n errors,\n duration: Date.now() - startTime,\n };\n}\n","/**\n * Platform telemetry reporter for scraper.\n *\n * Reads the API key from ~/.robot-resources/config.json and sends\n * telemetry events to the RR platform API. Fire-and-forget — never\n * blocks the scrape() pipeline.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst CONFIG_PATH = join(homedir(), '.robot-resources', 'config.json');\nconst PLATFORM_URL = process.env.RR_PLATFORM_URL || 'https://api.robotresources.ai';\n\nlet apiKey: string | null = null;\nlet keyLoaded = false;\n\nfunction loadApiKey(): string | null {\n if (keyLoaded) return apiKey;\n keyLoaded = true;\n\n // Environment-level opt-out — checked before reading config\n if (process.env.RR_TELEMETRY === 'off') {\n return null;\n }\n\n try {\n const config = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));\n\n // Config-level opt-out\n if (config.telemetry === false) {\n return null;\n }\n\n apiKey = config.api_key || null;\n return apiKey;\n } catch {\n return null;\n }\n}\n\nexport interface ScraperTelemetryPayload {\n url: string;\n tokenCount: number;\n title?: string;\n latencyMs: number;\n success: boolean;\n error?: string;\n}\n\n/**\n * Report a scrape() call to the platform. Fire-and-forget.\n */\nexport function reportScraperEvent(payload: ScraperTelemetryPayload): void {\n const key = loadApiKey();\n if (!key) return;\n\n // Fire-and-forget — no await, catch silently\n fetch(`${PLATFORM_URL}/v1/telemetry`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${key}`,\n },\n body: JSON.stringify({\n product: 'scraper',\n event_type: payload.success ? 'compress' : 'error',\n payload,\n }),\n }).catch(() => {\n // Silent — telemetry must never break the pipeline\n });\n}\n","/**\n * scraper\n * Context compression for AI agents\n *\n * @packageDocumentation\n */\n\n// Re-export types\nexport type {\n FetchMode,\n ScrapeOptions,\n ScrapeResult,\n FetchResult,\n ExtractResult,\n ConvertResult,\n CrawlOptions,\n CrawlResult,\n CrawlPageResult,\n CrawlError,\n} from './types.js';\n\n// Re-export layers for advanced usage\nexport { fetchUrl, FetchError } from './fetch.js';\nexport { fetchStealth } from './fetch-stealth.js';\nexport { fetchRender } from './fetch-render.js';\nexport { extractContent, ExtractionError } from './extract.js';\nexport { convertToMarkdown, estimateTokens } from './convert.js';\nexport {\n isAllowedByRobots,\n clearRobotsCache,\n getSitemapUrls,\n getCrawlDelay,\n} from './robots.js';\nexport { parseSitemap, clearSitemapCache } from './sitemap.js';\nexport type { SitemapEntry } from './sitemap.js';\nexport { crawl, normalizeUrl, extractLinks } from './crawl.js';\nexport { isChallengeResponse, fetchWithMode } from './fetch-mode.js';\n\n// Import for composition\nimport type { ScrapeOptions, ScrapeResult, FetchMode } from './types.js';\nimport { FetchError } from './fetch.js';\nimport { extractContent } from './extract.js';\nimport { convertToMarkdown } from './convert.js';\nimport { isAllowedByRobots } from './robots.js';\nimport { reportScraperEvent } from './telemetry.js';\nimport { fetchWithMode } from './fetch-mode.js';\n\n/**\n * Compress web content for AI agents\n *\n * Pipeline: Fetch -> Extract -> Convert\n * No LLM dependency. Reduces tokens by 70-80%.\n *\n * @example\n * ```typescript\n * import { scrape } from '@robot-resources/scraper';\n *\n * const result = await scrape('https://example.com/article');\n * console.log(result.markdown);\n * console.log(result.tokenCount);\n * ```\n *\n * @param url - URL to fetch and compress\n * @param options - Optional configuration\n * @returns Compressed content with metadata\n */\nexport async function scrape(\n url: string,\n options: ScrapeOptions = {}\n): Promise<ScrapeResult> {\n const startTime = Date.now();\n\n const mode: FetchMode = options.mode ?? 'auto';\n\n // Validate timeout at public boundary (MCP has Zod, but SDK callers don't)\n if (options.timeout !== undefined && (options.timeout <= 0 || Number.isNaN(options.timeout))) {\n throw new FetchError('timeout must be a positive number', undefined, false);\n }\n\n try {\n // robots.txt check (opt-in, independent of mode)\n if (options.respectRobots) {\n const allowed = await isAllowedByRobots(url, options.timeout);\n if (!allowed) {\n throw new FetchError(`Blocked by robots.txt: ${url}`, undefined, false);\n }\n }\n\n // Layer 1: Fetch (mode-aware with auto-fallback)\n const fetchResult = await fetchWithMode(url, mode, {\n timeout: options.timeout,\n maxRetries: options.maxRetries,\n userAgent: options.userAgent,\n });\n\n // Layer 2: Extract\n const extractResult = await extractContent(fetchResult);\n\n // Layer 3: Convert\n const convertResult = await convertToMarkdown(extractResult);\n\n const result: ScrapeResult = {\n markdown: convertResult.markdown,\n tokenCount: convertResult.tokenCount,\n title: extractResult.title,\n author: extractResult.author,\n siteName: extractResult.siteName,\n publishedAt: extractResult.publishedAt,\n url: fetchResult.url,\n };\n\n // Report telemetry (fire-and-forget)\n reportScraperEvent({\n url,\n tokenCount: convertResult.tokenCount,\n title: extractResult.title,\n latencyMs: Date.now() - startTime,\n success: true,\n });\n\n return result;\n } catch (err) {\n // Report error telemetry (fire-and-forget)\n reportScraperEvent({\n url,\n tokenCount: 0,\n latencyMs: Date.now() - startTime,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n });\n\n throw err;\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/fetch.ts","../src/fetch-stealth.ts","../src/fetch-render.ts","../src/extract.ts","../src/convert.ts","../src/robots.ts","../src/sitemap.ts","../src/fetch-mode.ts","../src/crawl.ts","../src/telemetry.ts","../src/index.ts"],"names":["DEFAULT_TIMEOUT","DEFAULT_MAX_RETRIES","BASE_BACKOFF_MS","isValidUrl","isRetryableStatus","sleep","getBackoffDelay","DEFAULT_TIMEOUT_MS","DEFAULT_TTL_MS","cache"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Layer 1: Fetch\n * HTTP fetching with smart headers and retries\n */\n\nimport type { FetchResult } from './types.js';\n\nconst USER_AGENTS = [\n 'Mozilla/5.0 (compatible; ScraperBot/1.0; +https://scraper.robotresources.ai)',\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n];\n\nconst DEFAULT_TIMEOUT = 10000;\nconst DEFAULT_MAX_RETRIES = 3;\nconst BASE_BACKOFF_MS = 1000;\n\nexport interface FetchOptions {\n timeout?: number;\n maxRetries?: number;\n userAgent?: string;\n}\n\n/**\n * Error class for fetch-related errors\n */\nexport class FetchError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly retryable: boolean = false\n ) {\n super(message);\n this.name = 'FetchError';\n }\n}\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nfunction getRandomUserAgent(): string {\n return USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];\n}\n\nfunction buildHeaders(userAgent?: string): Record<string, string> {\n return {\n 'User-Agent': userAgent || getRandomUserAgent(),\n Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n 'Accept-Language': 'en-US,en;q=0.9',\n 'Accept-Encoding': 'gzip, deflate',\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n };\n}\n\nfunction headersToObject(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key.toLowerCase()] = value;\n });\n return result;\n}\n\nfunction isRetryableStatus(status: number): boolean {\n return status >= 500 && status < 600;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction getBackoffDelay(attempt: number): number {\n return BASE_BACKOFF_MS * Math.pow(2, attempt);\n}\n\nasync function fetchWithTimeout(\n url: string,\n headers: Record<string, string>,\n timeout: number\n): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers,\n signal: controller.signal,\n redirect: 'follow',\n });\n return response;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new FetchError('Request timeout', undefined, true);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\n/**\n * Fetch URL content with smart headers and retry logic\n */\nexport async function fetchUrl(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const {\n timeout = DEFAULT_TIMEOUT,\n maxRetries = DEFAULT_MAX_RETRIES,\n userAgent,\n } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n const headers = buildHeaders(userAgent);\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await fetchWithTimeout(url, headers, timeout);\n\n if (!response.ok) {\n const statusCode = response.status;\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (isRetryableStatus(statusCode)) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n }\n\n const html = await response.text();\n const responseHeaders = headersToObject(response.headers);\n\n return {\n html,\n url: response.url,\n statusCode: response.status,\n headers: responseHeaders,\n };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n const isRetryable =\n error instanceof FetchError\n ? error.retryable\n : !(error instanceof FetchError);\n\n const hasRetriesLeft = attempt < maxRetries;\n\n if (isRetryable && hasRetriesLeft) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n\n break;\n }\n }\n\n throw lastError || new FetchError('Unknown fetch error');\n}\n","/**\n * Layer 1b: Stealth Fetch\n * TLS fingerprint impersonation via impit (optional peer dependency)\n *\n * Uses Rust-based browser TLS fingerprinting to bypass anti-bot systems\n * (Cloudflare, Akamai, PerimeterX) without a full browser.\n *\n * Requires: npm install impit (Node >= 20)\n */\n\nimport type { FetchResult } from './types.js';\nimport { FetchError } from './fetch.js';\nimport type { FetchOptions } from './fetch.js';\n\nconst DEFAULT_TIMEOUT = 10000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst BASE_BACKOFF_MS = 1000;\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nfunction isRetryableStatus(status: number): boolean {\n return status >= 500 && status < 600;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction getBackoffDelay(attempt: number): number {\n return BASE_BACKOFF_MS * Math.pow(2, attempt);\n}\n\n/**\n * Fetch URL with browser TLS fingerprint impersonation.\n *\n * Uses impit (Apify) to produce Chrome-like JA3/JA4 fingerprints at the\n * TLS handshake level. This bypasses anti-bot systems that reject default\n * Node.js TLS signatures.\n *\n * impit is an optional peer dependency — if not installed, throws a clear\n * error message with install instructions.\n */\nexport async function fetchStealth(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const {\n timeout = DEFAULT_TIMEOUT,\n maxRetries = DEFAULT_MAX_RETRIES,\n } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n // Dynamic import — impit is an optional peer dependency\n let Impit: any;\n try {\n // @ts-expect-error impit is an optional peer dependency (not installed in dev)\n ({ Impit } = await import('impit'));\n } catch {\n throw new FetchError(\n 'impit is required for stealth mode. Install: npm install impit (requires Node >= 20)',\n undefined,\n false\n );\n }\n\n const client = new Impit({ browser: 'chrome' });\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await client.fetch(url, {\n signal: AbortSignal.timeout(timeout),\n });\n\n if (!response.ok) {\n const statusCode = response.status;\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (isRetryableStatus(statusCode)) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n }\n\n const html = await response.text();\n const headers: Record<string, string> = {};\n response.headers.forEach((value: string, key: string) => {\n headers[key] = value;\n });\n\n return {\n html,\n url: response.url ?? url,\n statusCode: response.status,\n headers,\n };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n const isRetryable =\n error instanceof FetchError\n ? error.retryable\n : !(error instanceof FetchError);\n\n const hasRetriesLeft = attempt < maxRetries;\n\n if (isRetryable && hasRetriesLeft) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n\n break;\n }\n }\n\n throw lastError || new FetchError('Unknown stealth fetch error');\n}\n","/**\n * Layer 1c: Render Fetch\n * Playwright headless browser for JS-rendered pages (optional peer dependency)\n *\n * Uses Chromium to fully render SPAs (React, Next.js, Vue) that return\n * empty/partial HTML to tiers 1 and 2. Extracts the fully rendered DOM.\n *\n * Requires: npm install playwright\n */\n\nimport type { FetchResult } from './types.js';\nimport { FetchError } from './fetch.js';\nimport type { FetchOptions } from './fetch.js';\n\nconst DEFAULT_TIMEOUT = 30000;\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\n/**\n * Fetch URL using a headless Chromium browser to render JavaScript.\n *\n * Launches a fresh browser per call (no shared state), navigates to the URL,\n * waits for network idle, then extracts the fully rendered HTML.\n *\n * Playwright is an optional peer dependency — if not installed, throws a clear\n * error message with install instructions.\n */\nexport async function fetchRender(\n url: string,\n options: FetchOptions = {}\n): Promise<FetchResult> {\n const { timeout = DEFAULT_TIMEOUT } = options;\n\n if (!isValidUrl(url)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n\n // Dynamic import — Playwright is an optional peer dependency\n let chromium: any;\n try {\n // @ts-expect-error playwright is an optional peer dependency (not installed in dev)\n ({ chromium } = await import('playwright'));\n } catch {\n throw new FetchError(\n 'Playwright is required for render mode. Install: npm install playwright',\n undefined,\n false\n );\n }\n\n const browser = await chromium.launch({ headless: true });\n\n try {\n const page = await browser.newPage();\n\n // Auto-dismiss dialogs to prevent hanging\n page.on('dialog', (dialog: any) => dialog.dismiss());\n\n const response = await page.goto(url, {\n waitUntil: 'networkidle',\n timeout,\n });\n\n if (!response) {\n throw new FetchError(\n 'Navigation returned no response (about:blank or same-URL redirect)',\n undefined,\n false\n );\n }\n\n const statusCode = response.status();\n\n if (statusCode >= 400 && statusCode < 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, false);\n }\n\n if (statusCode >= 500) {\n throw new FetchError(`HTTP ${statusCode}`, statusCode, true);\n }\n\n const html = await page.content();\n const headers: Record<string, string> = response.headers();\n\n return {\n html,\n url: page.url(),\n statusCode,\n headers,\n };\n } catch (error) {\n // Convert Playwright timeout errors to retryable FetchErrors\n if (error instanceof Error && error.name === 'TimeoutError') {\n throw new FetchError('Navigation timeout', undefined, true);\n }\n throw error;\n } finally {\n await browser.close();\n }\n}\n","/**\n * Layer 2: Extract\n * Content extraction using Readability\n */\n\nimport { Readability } from '@mozilla/readability';\nimport { parseHTML } from 'linkedom';\nimport type { FetchResult, ExtractResult } from './types.js';\n\n/**\n * Error class for extraction-related errors\n */\nexport class ExtractionError extends Error {\n constructor(\n message: string,\n public readonly code: string\n ) {\n super(message);\n this.name = 'ExtractionError';\n }\n}\n\n/**\n * Extract main content from HTML using Readability\n */\nexport async function extractContent(\n fetchResult: FetchResult\n): Promise<ExtractResult> {\n const { html } = fetchResult;\n\n if (!html || !html.trim()) {\n throw new ExtractionError('Empty HTML content', 'EMPTY_HTML');\n }\n\n const { document } = parseHTML(html);\n\n const reader = new Readability(document, {\n charThreshold: 50,\n });\n\n const article = reader.parse();\n\n if (!article || !article.content || article.content.trim().length < 20) {\n throw new ExtractionError(\n 'No content could be extracted from the page',\n 'NO_CONTENT'\n );\n }\n\n const result: ExtractResult = {\n content: cleanContent(article.content),\n title: article.title || extractFallbackTitle(document),\n author: article.byline || undefined,\n publishedAt: article.publishedTime || extractPublishedTime(document),\n siteName: article.siteName || extractSiteName(document),\n };\n\n return result;\n}\n\nfunction cleanContent(content: string): string {\n return content\n .replace(/>\\s+</g, '><')\n .replace(/\\s{2,}/g, ' ')\n .trim();\n}\n\nfunction extractFallbackTitle(document: Document): string | undefined {\n const ogTitle = document.querySelector('meta[property=\"og:title\"]');\n if (ogTitle) {\n const content = ogTitle.getAttribute('content');\n if (content) return content;\n }\n\n const titleEl = document.querySelector('title');\n if (titleEl && titleEl.textContent) {\n return titleEl.textContent.trim();\n }\n\n const h1 = document.querySelector('h1');\n if (h1 && h1.textContent) {\n return h1.textContent.trim();\n }\n\n return undefined;\n}\n\nfunction extractPublishedTime(document: Document): string | undefined {\n const ogTime = document.querySelector(\n 'meta[property=\"article:published_time\"]'\n );\n if (ogTime) {\n const content = ogTime.getAttribute('content');\n if (content) return content;\n }\n\n const schemaTime = document.querySelector('[itemprop=\"datePublished\"]');\n if (schemaTime) {\n const datetime = schemaTime.getAttribute('datetime');\n if (datetime) return datetime;\n const content = schemaTime.getAttribute('content');\n if (content) return content;\n }\n\n const timeEl = document.querySelector('time[datetime]');\n if (timeEl) {\n const datetime = timeEl.getAttribute('datetime');\n if (datetime) return datetime;\n }\n\n return undefined;\n}\n\nfunction extractSiteName(document: Document): string | undefined {\n const ogSiteName = document.querySelector('meta[property=\"og:site_name\"]');\n if (ogSiteName) {\n const content = ogSiteName.getAttribute('content');\n if (content) return content;\n }\n\n const appName = document.querySelector('meta[name=\"application-name\"]');\n if (appName) {\n const content = appName.getAttribute('content');\n if (content) return content;\n }\n\n return undefined;\n}\n","/**\n * Layer 3: Convert\n * HTML to Markdown conversion\n */\n\nimport TurndownService from 'turndown';\nimport type { ExtractResult, ConvertResult } from './types.js';\n\nfunction createTurndownService(): TurndownService {\n const turndown = new TurndownService({\n headingStyle: 'atx',\n hr: '---',\n bulletListMarker: '-',\n codeBlockStyle: 'fenced',\n fence: '```',\n emDelimiter: '*',\n strongDelimiter: '**',\n linkStyle: 'inlined',\n });\n\n turndown.remove(['script', 'style', 'noscript', 'iframe']);\n\n turndown.addRule('removeEmpty', {\n filter: (node) => {\n if (node.nodeType === 1) {\n const text = node.textContent || '';\n const isEmptyBlock =\n text.trim() === '' &&\n !['IMG', 'BR', 'HR', 'INPUT'].includes(node.nodeName);\n return isEmptyBlock;\n }\n return false;\n },\n replacement: () => '',\n });\n\n turndown.addRule('fencedCodeBlock', {\n filter: (node, options) => {\n return (\n options.codeBlockStyle === 'fenced' &&\n node.nodeName === 'PRE' &&\n node.firstChild !== null &&\n node.firstChild.nodeName === 'CODE'\n );\n },\n replacement: (_content, node, options) => {\n const codeNode = node.firstChild as Element;\n const code = codeNode.textContent || '';\n\n const className = codeNode.getAttribute('class') || '';\n const langMatch = className.match(/language-(\\w+)/);\n const lang = langMatch ? langMatch[1] : '';\n\n const fence = options.fence || '```';\n return `\\n\\n${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n },\n });\n\n turndown.addRule('strikethrough', {\n filter: ['del', 's'] as const,\n replacement: (content) => `~~${content}~~`,\n });\n\n return turndown;\n}\n\nlet turndownInstance: TurndownService | null = null;\n\nfunction getTurndown(): TurndownService {\n if (!turndownInstance) {\n turndownInstance = createTurndownService();\n }\n return turndownInstance;\n}\n\nfunction cleanMarkdown(markdown: string): string {\n return markdown\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/[ \\t]+$/gm, '')\n .replace(/^\\n+/, '')\n .replace(/\\n+$/, '')\n .trim();\n}\n\n/**\n * Convert extracted HTML to clean Markdown\n */\nexport async function convertToMarkdown(\n extractResult: ExtractResult\n): Promise<ConvertResult> {\n const { content } = extractResult;\n\n if (!content || !content.trim()) {\n return {\n markdown: '',\n tokenCount: 0,\n };\n }\n\n const turndown = getTurndown();\n let markdown = turndown.turndown(content);\n\n markdown = cleanMarkdown(markdown);\n\n const tokenCount = estimateTokens(markdown);\n\n return {\n markdown,\n tokenCount,\n };\n}\n\n/**\n * Content-aware token estimator.\n *\n * Segments text by content type and applies calibrated character-per-token\n * ratios derived from cl100k_base (GPT-4) empirical measurements.\n *\n * Ratios:\n * Code blocks — 3.2 chars/token (operators, camelCase split into subwords)\n * Inline code — 3.5 chars/token (variable names, short expressions)\n * URLs — 5.0 chars/token (path segments tokenize efficiently)\n * Prose — 4.3 chars/token (words, punctuation, markdown formatting)\n *\n * Accuracy: within ±15% of actual BPE tokenization for English content.\n */\nexport function estimateTokens(text: string): number {\n if (!text) return 0;\n\n let tokens = 0;\n let remaining = text;\n\n // Code blocks: operators, identifiers → ~3.2 chars per token\n remaining = remaining.replace(/```[\\s\\S]*?```/g, (match) => {\n tokens += Math.ceil(match.length / 3.2);\n return ' ';\n });\n\n // Inline code: variables, short expressions → ~3.5 chars per token\n remaining = remaining.replace(/`[^`]+`/g, (match) => {\n tokens += Math.ceil(match.length / 3.5);\n return ' ';\n });\n\n // URLs: path segments, punctuation splitting → ~5.0 chars per token\n remaining = remaining.replace(/https?:\\/\\/\\S+/g, (match) => {\n tokens += Math.ceil(match.length / 5.0);\n return ' ';\n });\n\n // Prose: words, punctuation, markdown formatting → ~4.3 chars per token\n const proseLength = remaining.replace(/\\s+/g, ' ').trim().length;\n if (proseLength > 0) {\n tokens += Math.ceil(proseLength / 4.3);\n }\n\n return Math.max(1, tokens);\n}\n","/**\n * robots.txt compliance layer\n *\n * Opt-in for single-page scraping (respectRobots option),\n * foundation for FTR-ORG-019 crawl mode where it becomes default.\n */\n\nimport robotsParser from 'robots-parser';\n\ninterface RobotsCacheEntry {\n parser: ReturnType<typeof robotsParser>;\n expiresAt: number;\n}\n\nconst DEFAULT_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst BOT_USER_AGENT = 'ScraperBot';\n\nconst cache = new Map<string, RobotsCacheEntry>();\n\nfunction getRobotsUrl(url: string): string {\n const parsed = new URL(url);\n return `${parsed.protocol}//${parsed.host}/robots.txt`;\n}\n\nasync function getRobotsParser(\n url: string,\n timeout: number = DEFAULT_TIMEOUT_MS\n): Promise<ReturnType<typeof robotsParser>> {\n const robotsUrl = getRobotsUrl(url);\n\n const cached = cache.get(robotsUrl);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.parser;\n }\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(robotsUrl, {\n signal: controller.signal,\n headers: { 'User-Agent': BOT_USER_AGENT },\n });\n\n clearTimeout(timeoutId);\n\n const text = response.ok ? await response.text() : '';\n const parser = robotsParser(robotsUrl, text);\n\n cache.set(robotsUrl, {\n parser,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n\n return parser;\n } catch {\n // Fail-open: if robots.txt is unreachable, allow everything\n const parser = robotsParser(robotsUrl, '');\n cache.set(robotsUrl, {\n parser,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n return parser;\n }\n}\n\n/**\n * Check if a URL is allowed by robots.txt.\n * Returns true if allowed or if robots.txt cannot be fetched (fail-open).\n */\nexport async function isAllowedByRobots(\n url: string,\n timeout?: number\n): Promise<boolean> {\n const parser = await getRobotsParser(url, timeout);\n return parser.isAllowed(url, BOT_USER_AGENT) !== false;\n}\n\n/**\n * Extract Sitemap: URLs from robots.txt.\n * Returns empty array if no Sitemap directives or robots.txt unreachable (fail-open).\n * Reuses cached robots.txt parser.\n */\nexport async function getSitemapUrls(\n url: string,\n timeout?: number\n): Promise<string[]> {\n const parser = await getRobotsParser(url, timeout);\n return parser.getSitemaps();\n}\n\n/**\n * Extract Crawl-delay value from robots.txt for ScraperBot user agent.\n * Returns delay in seconds, or null if not specified or robots.txt unreachable (fail-open).\n * Reuses cached robots.txt parser.\n */\nexport async function getCrawlDelay(\n url: string,\n timeout?: number\n): Promise<number | null> {\n const parser = await getRobotsParser(url, timeout);\n const delay = parser.getCrawlDelay(BOT_USER_AGENT);\n return delay === undefined ? null : delay;\n}\n\n/**\n * Clear the robots.txt cache. Exported for testing.\n */\nexport function clearRobotsCache(): void {\n cache.clear();\n}\n","/**\n * Sitemap parser\n *\n * Fetches and parses sitemap.xml for crawl mode seed URLs.\n * Regex-based XML parsing — no XML parser dependency.\n * Handles sitemap index files with recursion limit.\n * Mirrors robots.ts fetch+cache+fail-open pattern.\n */\n\nconst DEFAULT_TIMEOUT_MS = 10000;\nconst DEFAULT_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst MAX_RECURSION_DEPTH = 2;\n\n/**\n * A single entry from a sitemap\n */\nexport interface SitemapEntry {\n /** URL from <loc> tag */\n loc: string;\n /** Last modification date from <lastmod> tag */\n lastmod?: string;\n /** Priority from <priority> tag (0.0 to 1.0) */\n priority?: number;\n}\n\ninterface SitemapCacheEntry {\n entries: SitemapEntry[];\n expiresAt: number;\n}\n\nconst cache = new Map<string, SitemapCacheEntry>();\n\n/**\n * Extract origin (protocol + host) from URL\n */\nfunction getOrigin(url: string): string {\n const parsed = new URL(url);\n return `${parsed.protocol}//${parsed.host}`;\n}\n\n/**\n * Check if XML contains a sitemap index\n */\nfunction isSitemapIndex(xml: string): boolean {\n return /<sitemapindex[\\s>]/i.test(xml);\n}\n\n/**\n * Extract sitemap URLs from a sitemap index\n * Handles namespace prefixes: <ns:loc>, <sitemap:loc>, etc.\n */\nfunction extractSitemapIndexUrls(xml: string): string[] {\n const urls: string[] = [];\n // Match <sitemap>...</sitemap> blocks, then extract <loc> from each\n const sitemapBlockRegex = /<(?:\\w+:)?sitemap\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?sitemap>/gi;\n let blockMatch;\n\n while ((blockMatch = sitemapBlockRegex.exec(xml)) !== null) {\n const block = blockMatch[1];\n const locMatch = /<(?:\\w+:)?loc\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?loc>/i.exec(block);\n if (locMatch) {\n const url = locMatch[1].trim();\n if (url) urls.push(url);\n }\n }\n\n return urls;\n}\n\n/**\n * Extract URL entries from a sitemap urlset\n * Handles namespace prefixes: <ns:url>, <ns:loc>, etc.\n */\nfunction extractUrlEntries(xml: string, origin: string): SitemapEntry[] {\n const entries: SitemapEntry[] = [];\n // Match <url>...</url> blocks\n const urlBlockRegex = /<(?:\\w+:)?url\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?url>/gi;\n let blockMatch;\n\n while ((blockMatch = urlBlockRegex.exec(xml)) !== null) {\n const block = blockMatch[1];\n\n // Extract <loc>\n const locMatch = /<(?:\\w+:)?loc\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?loc>/i.exec(block);\n if (!locMatch) continue;\n\n const loc = locMatch[1].trim();\n if (!loc) continue;\n\n // Same-origin filter\n try {\n if (getOrigin(loc) !== origin) continue;\n } catch {\n continue; // Invalid URL — skip\n }\n\n const entry: SitemapEntry = { loc };\n\n // Extract optional <lastmod>\n const lastmodMatch = /<(?:\\w+:)?lastmod\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?lastmod>/i.exec(block);\n if (lastmodMatch) {\n const lastmod = lastmodMatch[1].trim();\n if (lastmod) entry.lastmod = lastmod;\n }\n\n // Extract optional <priority>\n const priorityMatch = /<(?:\\w+:)?priority\\b[^>]*>([\\s\\S]*?)<\\/(?:\\w+:)?priority>/i.exec(block);\n if (priorityMatch) {\n const priority = parseFloat(priorityMatch[1].trim());\n if (!isNaN(priority)) entry.priority = priority;\n }\n\n entries.push(entry);\n }\n\n return entries;\n}\n\n/**\n * Fetch sitemap XML with timeout\n */\nasync function fetchSitemapXml(\n url: string,\n timeout: number\n): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(url, {\n signal: controller.signal,\n headers: { 'User-Agent': 'ScraperBot/1.0' },\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) return null;\n\n return await response.text();\n } catch {\n return null; // Fail-open\n }\n}\n\n/**\n * Internal recursive parser with depth tracking\n */\nasync function parseSitemapInternal(\n url: string,\n origin: string,\n timeout: number,\n depth: number\n): Promise<SitemapEntry[]> {\n if (depth >= MAX_RECURSION_DEPTH) return [];\n\n const xml = await fetchSitemapXml(url, timeout);\n if (!xml) return [];\n\n // Check if this is a sitemap index\n if (isSitemapIndex(xml)) {\n const sitemapUrls = extractSitemapIndexUrls(xml);\n const allEntries: SitemapEntry[] = [];\n\n for (const sitemapUrl of sitemapUrls) {\n const entries = await parseSitemapInternal(\n sitemapUrl,\n origin,\n timeout,\n depth + 1\n );\n allEntries.push(...entries);\n }\n\n return allEntries;\n }\n\n // Regular sitemap — extract URL entries\n return extractUrlEntries(xml, origin);\n}\n\n/**\n * Parse a sitemap.xml and return URL entries.\n *\n * - Fetches the sitemap from the given URL\n * - Extracts <loc> URLs via regex (no XML parser dependency)\n * - Handles sitemap index files (recursive, max depth 2)\n * - Caches results per URL with 1-hour TTL\n * - Fail-open: returns empty array if sitemap is unreachable or invalid\n * - Filters to same-origin URLs only\n *\n * @param url - Full URL of the sitemap.xml\n * @param timeout - Fetch timeout in ms (default: 10000)\n * @returns Array of SitemapEntry objects\n */\nexport async function parseSitemap(\n url: string,\n timeout: number = DEFAULT_TIMEOUT_MS\n): Promise<SitemapEntry[]> {\n // Check cache\n const cached = cache.get(url);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.entries;\n }\n\n let origin: string;\n try {\n origin = getOrigin(url);\n } catch {\n return []; // Invalid URL — fail-open\n }\n\n const entries = await parseSitemapInternal(url, origin, timeout, 0);\n\n // Cache the result\n cache.set(url, {\n entries,\n expiresAt: Date.now() + DEFAULT_TTL_MS,\n });\n\n return entries;\n}\n\n/**\n * Clear the sitemap cache. Exported for testing.\n */\nexport function clearSitemapCache(): void {\n cache.clear();\n}\n","/**\n * Mode-aware fetch routing with challenge detection.\n *\n * Shared between scrape() (index.ts) and crawl() (crawl.ts)\n * to avoid duplicating mode routing and challenge detection logic.\n */\n\nimport type { FetchResult, FetchMode } from './types.js';\nimport type { FetchOptions } from './fetch.js';\nimport { fetchUrl, FetchError } from './fetch.js';\nimport { fetchStealth } from './fetch-stealth.js';\nimport { fetchRender } from './fetch-render.js';\n\nconst CHALLENGE_MARKERS = [\n 'cf-browser-verification',\n 'Just a moment',\n '_cf_chl_opt',\n 'akamai-challenge',\n 'ak-challenge',\n];\n\n/**\n * Detect anti-bot challenge pages that return HTTP 200 but contain\n * challenge/verification HTML instead of real content.\n */\nexport function isChallengeResponse(fetchResult: FetchResult): boolean {\n return CHALLENGE_MARKERS.some(marker => fetchResult.html.includes(marker));\n}\n\n/**\n * Fetch a URL using the specified mode with auto-fallback support.\n *\n * Modes:\n * - 'fast': Tier 1 only (plain HTTP)\n * - 'stealth': Tier 2 only (TLS fingerprint)\n * - 'render': Tier 3 only (Playwright)\n * - 'auto': Fast first, fall back to stealth on 403 or challenge page\n */\nconst VALID_MODES: readonly string[] = ['fast', 'stealth', 'render', 'auto'];\n\nexport async function fetchWithMode(\n url: string,\n mode: FetchMode,\n options: FetchOptions,\n): Promise<FetchResult> {\n if (!VALID_MODES.includes(mode)) {\n throw new FetchError(\n `Invalid fetch mode: '${mode}'. Valid modes: ${VALID_MODES.join(', ')}`,\n undefined,\n false,\n );\n }\n\n if (mode === 'stealth') return fetchStealth(url, options);\n if (mode === 'render') return fetchRender(url, options);\n if (mode === 'fast') return fetchUrl(url, options);\n\n // auto: fast with fallback to stealth on 403 or challenge\n try {\n const result = await fetchUrl(url, options);\n if (isChallengeResponse(result)) {\n return fetchStealth(url, options);\n }\n return result;\n } catch (err) {\n if (err instanceof FetchError && err.statusCode === 403) {\n return fetchStealth(url, options);\n }\n throw err;\n }\n}\n","/**\n * Crawl: BFS multi-page orchestrator\n * TKT-SCRAPER-079: Crawl multiple pages from a starting URL\n *\n * Composes: sitemap seeding, robots.txt, link extraction, URL normalization,\n * depth/limit/filter constraints, concurrency, and scrape pipeline per page.\n */\n\nimport type {\n CrawlOptions,\n CrawlResult,\n CrawlPageResult,\n CrawlError,\n} from './types.js';\nimport { FetchError } from './fetch.js';\nimport { extractContent } from './extract.js';\nimport { convertToMarkdown } from './convert.js';\nimport { isAllowedByRobots, getCrawlDelay } from './robots.js';\nimport { parseSitemap } from './sitemap.js';\nimport { fetchWithMode } from './fetch-mode.js';\n\n// ============================================\n// URL utilities\n// ============================================\n\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nexport function normalizeUrl(url: string): string {\n try {\n const parsed = new URL(url);\n parsed.hash = '';\n let pathname = parsed.pathname;\n if (pathname.length > 1 && pathname.endsWith('/')) {\n pathname = pathname.slice(0, -1);\n }\n parsed.pathname = pathname;\n return parsed.toString();\n } catch {\n return url;\n }\n}\n\nconst SKIP_EXTENSIONS = new Set([\n '.pdf', '.jpg', '.jpeg', '.png', '.gif', '.svg', '.webp', '.ico',\n '.mp4', '.mp3', '.wav', '.avi',\n '.zip', '.tar', '.gz', '.rar',\n '.css', '.js', '.xml', '.json', '.woff', '.woff2', '.ttf', '.eot',\n]);\n\nexport function extractLinks(html: string, baseUrl: string): string[] {\n const links: string[] = [];\n let origin: string;\n try {\n origin = new URL(baseUrl).origin;\n } catch {\n return [];\n }\n\n const regex = /<a\\s+[^>]*href\\s*=\\s*[\"']([^\"']+)[\"'][^>]*>/gi;\n let match;\n while ((match = regex.exec(html)) !== null) {\n const href = match[1].trim();\n if (\n href.startsWith('mailto:') ||\n href.startsWith('tel:') ||\n href.startsWith('javascript:') ||\n href.startsWith('#')\n ) continue;\n\n try {\n const resolved = new URL(href, baseUrl);\n if (resolved.origin !== origin) continue;\n\n const ext = resolved.pathname.toLowerCase().match(/\\.\\w+$/)?.[0];\n if (ext && SKIP_EXTENSIONS.has(ext)) continue;\n\n links.push(normalizeUrl(resolved.toString()));\n } catch {\n // Invalid URL, skip\n }\n }\n\n return [...new Set(links)];\n}\n\n// ============================================\n// URL filtering\n// ============================================\n\nfunction matchGlob(url: string, pattern: string): boolean {\n const regex = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n .replace(/\\*\\*/g, '{{DOUBLESTAR}}')\n .replace(/\\*/g, '[^/]*')\n .replace(/\\{\\{DOUBLESTAR\\}\\}/g, '.*');\n return new RegExp(regex).test(url);\n}\n\nfunction matchesFilter(url: string, include?: string[], exclude?: string[]): boolean {\n if (exclude?.length) {\n for (const pattern of exclude) {\n if (matchGlob(url, pattern)) return false;\n }\n }\n if (include?.length) {\n return include.some(pattern => matchGlob(url, pattern));\n }\n return true;\n}\n\n// ============================================\n// Crawl\n// ============================================\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nexport async function crawl(options: CrawlOptions): Promise<CrawlResult> {\n const startTime = Date.now();\n\n const {\n url: startUrl,\n depth: maxDepth = 2,\n limit = 50,\n mode = 'auto',\n include,\n exclude,\n timeout,\n concurrency = 3,\n respectRobots = true,\n } = options;\n\n // Validation\n if (!isValidUrl(startUrl)) {\n throw new FetchError('Invalid URL', undefined, false);\n }\n if (maxDepth < 0) throw new FetchError('depth must be >= 0', undefined, false);\n if (limit < 1) throw new FetchError('limit must be >= 1', undefined, false);\n if (concurrency < 1) throw new FetchError('concurrency must be >= 1', undefined, false);\n if (timeout !== undefined && (timeout <= 0 || Number.isNaN(timeout))) {\n throw new FetchError('timeout must be a positive number', undefined, false);\n }\n\n const pages: CrawlPageResult[] = [];\n const errors: CrawlError[] = [];\n const visited = new Set<string>();\n let totalDiscovered = 0;\n let totalSkipped = 0;\n\n const normalizedStart = normalizeUrl(startUrl);\n const origin = new URL(startUrl).origin;\n\n // Robots.txt + crawl delay\n let crawlDelay: number | null = null;\n if (respectRobots) {\n crawlDelay = await getCrawlDelay(startUrl, timeout);\n const allowed = await isAllowedByRobots(startUrl, timeout);\n if (!allowed) {\n return {\n pages: [],\n totalDiscovered: 1,\n totalCrawled: 0,\n totalSkipped: 1,\n errors: [],\n duration: Date.now() - startTime,\n };\n }\n }\n\n // Seed: start URL + sitemap URLs\n const queue: Array<{ url: string; depth: number }> = [\n { url: normalizedStart, depth: 0 },\n ];\n\n if (maxDepth > 0) {\n try {\n const sitemapEntries = await parseSitemap(`${origin}/sitemap.xml`, timeout);\n const seen = new Set<string>([normalizedStart]);\n for (const entry of sitemapEntries) {\n const normalized = normalizeUrl(entry.loc);\n if (!seen.has(normalized)) {\n seen.add(normalized);\n queue.push({ url: normalized, depth: 1 });\n }\n }\n } catch (err) {\n console.debug(`[scraper] Sitemap unavailable for ${origin}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n totalDiscovered = queue.length;\n\n // BFS loop\n while (queue.length > 0 && pages.length < limit) {\n const batchSize = Math.min(concurrency, limit - pages.length, queue.length);\n const batch = queue.splice(0, batchSize);\n\n const tasks = batch.map(async ({ url, depth }) => {\n const normalized = normalizeUrl(url);\n\n if (visited.has(normalized)) {\n totalSkipped++;\n return;\n }\n visited.add(normalized);\n\n // URL filter check (start URL is exempt — it's the user's explicit seed)\n if (normalized !== normalizedStart && !matchesFilter(normalized, include, exclude)) {\n totalSkipped++;\n return;\n }\n\n // Per-URL robots check\n if (respectRobots) {\n const allowed = await isAllowedByRobots(url, timeout);\n if (!allowed) {\n totalSkipped++;\n return;\n }\n }\n\n try {\n const fetchResult = await fetchWithMode(url, mode, { timeout });\n const extractResult = await extractContent(fetchResult);\n const convertResult = await convertToMarkdown(extractResult);\n\n const pageResult: CrawlPageResult = {\n markdown: convertResult.markdown,\n tokenCount: convertResult.tokenCount,\n title: extractResult.title,\n author: extractResult.author,\n siteName: extractResult.siteName,\n publishedAt: extractResult.publishedAt,\n url: fetchResult.url,\n depth,\n };\n\n pages.push(pageResult);\n\n // Extract links for next depth level\n if (depth < maxDepth) {\n const links = extractLinks(fetchResult.html, fetchResult.url);\n for (const link of links) {\n if (!visited.has(link)) {\n queue.push({ url: link, depth: depth + 1 });\n totalDiscovered++;\n }\n }\n }\n } catch (err) {\n errors.push({\n url,\n error: err instanceof Error ? err.message : String(err),\n depth,\n });\n }\n });\n\n await Promise.allSettled(tasks);\n\n // Crawl delay between batches\n if (crawlDelay && crawlDelay > 0 && queue.length > 0) {\n await sleep(crawlDelay * 1000);\n }\n }\n\n return {\n pages,\n totalDiscovered,\n totalCrawled: pages.length,\n totalSkipped,\n errors,\n duration: Date.now() - startTime,\n };\n}\n","/**\n * Platform telemetry reporter for scraper.\n *\n * Reads the API key from ~/.robot-resources/config.json and sends\n * telemetry events to the RR platform API. Fire-and-forget — never\n * blocks the scrape() pipeline.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst CONFIG_PATH = join(homedir(), '.robot-resources', 'config.json');\nconst PLATFORM_URL = process.env.RR_PLATFORM_URL || 'https://api.robotresources.ai';\n\nlet apiKey: string | null = null;\nlet keyLoaded = false;\n\nfunction loadApiKey(): string | null {\n if (keyLoaded) return apiKey;\n keyLoaded = true;\n\n // Environment-level opt-out — checked before reading config\n if (process.env.RR_TELEMETRY === 'off') {\n return null;\n }\n\n try {\n const config = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));\n\n // Config-level opt-out\n if (config.telemetry === false) {\n return null;\n }\n\n apiKey = config.api_key || null;\n return apiKey;\n } catch {\n return null;\n }\n}\n\nexport interface ScraperTelemetryPayload {\n url: string;\n tokenCount: number;\n originalTokenCount?: number;\n title?: string;\n latencyMs: number;\n success: boolean;\n error?: string;\n}\n\n/**\n * Report a scrape() call to the platform. Fire-and-forget.\n */\nexport function reportScraperEvent(payload: ScraperTelemetryPayload): void {\n const key = loadApiKey();\n if (!key) return;\n\n // Fire-and-forget — no await, catch silently\n fetch(`${PLATFORM_URL}/v1/telemetry`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${key}`,\n },\n body: JSON.stringify({\n product: 'scraper',\n event_type: payload.success ? 'compress' : 'error',\n payload,\n }),\n }).catch(() => {\n // Silent — telemetry must never break the pipeline\n });\n}\n","/**\n * scraper\n * Context compression for AI agents\n *\n * @packageDocumentation\n */\n\n// Re-export types\nexport type {\n FetchMode,\n ScrapeOptions,\n ScrapeResult,\n FetchResult,\n ExtractResult,\n ConvertResult,\n CrawlOptions,\n CrawlResult,\n CrawlPageResult,\n CrawlError,\n} from './types.js';\n\n// Re-export layers for advanced usage\nexport { fetchUrl, FetchError } from './fetch.js';\nexport { fetchStealth } from './fetch-stealth.js';\nexport { fetchRender } from './fetch-render.js';\nexport { extractContent, ExtractionError } from './extract.js';\nexport { convertToMarkdown, estimateTokens } from './convert.js';\nexport {\n isAllowedByRobots,\n clearRobotsCache,\n getSitemapUrls,\n getCrawlDelay,\n} from './robots.js';\nexport { parseSitemap, clearSitemapCache } from './sitemap.js';\nexport type { SitemapEntry } from './sitemap.js';\nexport { crawl, normalizeUrl, extractLinks } from './crawl.js';\nexport { isChallengeResponse, fetchWithMode } from './fetch-mode.js';\n\n// Import for composition\nimport type { ScrapeOptions, ScrapeResult, FetchMode } from './types.js';\nimport { FetchError } from './fetch.js';\nimport { extractContent } from './extract.js';\nimport { convertToMarkdown, estimateTokens } from './convert.js';\nimport { isAllowedByRobots } from './robots.js';\nimport { reportScraperEvent } from './telemetry.js';\nimport { fetchWithMode } from './fetch-mode.js';\n\n/**\n * Compress web content for AI agents\n *\n * Pipeline: Fetch -> Extract -> Convert\n * No LLM dependency. Median 91% token reduction.\n *\n * @example\n * ```typescript\n * import { scrape } from '@robot-resources/scraper';\n *\n * const result = await scrape('https://example.com/article');\n * console.log(result.markdown);\n * console.log(result.tokenCount);\n * ```\n *\n * @param url - URL to fetch and compress\n * @param options - Optional configuration\n * @returns Compressed content with metadata\n */\nexport async function scrape(\n url: string,\n options: ScrapeOptions = {}\n): Promise<ScrapeResult> {\n const startTime = Date.now();\n\n const mode: FetchMode = options.mode ?? 'auto';\n\n // Validate timeout at public boundary (MCP has Zod, but SDK callers don't)\n if (options.timeout !== undefined && (options.timeout <= 0 || Number.isNaN(options.timeout))) {\n throw new FetchError('timeout must be a positive number', undefined, false);\n }\n\n try {\n // robots.txt check (opt-in, independent of mode)\n if (options.respectRobots) {\n const allowed = await isAllowedByRobots(url, options.timeout);\n if (!allowed) {\n throw new FetchError(`Blocked by robots.txt: ${url}`, undefined, false);\n }\n }\n\n // Layer 1: Fetch (mode-aware with auto-fallback)\n const fetchResult = await fetchWithMode(url, mode, {\n timeout: options.timeout,\n maxRetries: options.maxRetries,\n userAgent: options.userAgent,\n });\n\n // Measure original token count before extraction/conversion\n const originalTokenCount = estimateTokens(fetchResult.html);\n\n // Layer 2: Extract\n const extractResult = await extractContent(fetchResult);\n\n // Layer 3: Convert\n const convertResult = await convertToMarkdown(extractResult);\n\n const result: ScrapeResult = {\n markdown: convertResult.markdown,\n tokenCount: convertResult.tokenCount,\n title: extractResult.title,\n author: extractResult.author,\n siteName: extractResult.siteName,\n publishedAt: extractResult.publishedAt,\n url: fetchResult.url,\n };\n\n // Report telemetry (fire-and-forget)\n reportScraperEvent({\n url,\n tokenCount: convertResult.tokenCount,\n originalTokenCount,\n title: extractResult.title,\n latencyMs: Date.now() - startTime,\n success: true,\n });\n\n return result;\n } catch (err) {\n // Report error telemetry (fire-and-forget)\n reportScraperEvent({\n url,\n tokenCount: 0,\n originalTokenCount: 0,\n latencyMs: Date.now() - startTime,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n });\n\n throw err;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robot-resources/scraper",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Context compression for AI agents. Fetch -> Extract -> Convert pipeline without LLM dependency.",
5
5
  "author": "Robot Resources",
6
6
  "license": "MIT",