mcp-scraper 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -5
- package/dist/bin/api-server.cjs +2417 -648
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +3 -3
- package/dist/bin/browser-agent-stdio-server.cjs +1 -1
- package/dist/bin/browser-agent-stdio-server.cjs.map +1 -1
- package/dist/bin/browser-agent-stdio-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +1276 -0
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -0
- package/dist/bin/mcp-scraper-cli.d.cts +1 -0
- package/dist/bin/mcp-scraper-cli.d.ts +1 -0
- package/dist/bin/mcp-scraper-cli.js +476 -0
- package/dist/bin/mcp-scraper-cli.js.map +1 -0
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs +69 -14
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.js +3 -3
- package/dist/bin/mcp-scraper-install.cjs +5 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +5 -1
- package/dist/bin/mcp-scraper-install.js.map +1 -1
- package/dist/bin/mcp-stdio-server.cjs +69 -14
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/bin/paa-harvest.cjs +42 -6
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +1 -1
- package/dist/{chunk-3TF6UT2P.js → chunk-5E6KJC26.js} +2 -2
- package/dist/{chunk-D4CJBZBY.js → chunk-7GCCOT3M.js} +372 -1
- package/dist/chunk-7GCCOT3M.js.map +1 -0
- package/dist/chunk-BJDCPCIE.js +7 -0
- package/dist/chunk-BJDCPCIE.js.map +1 -0
- package/dist/{chunk-MY3S7EX7.js → chunk-CQTAKXBN.js} +43 -7
- package/dist/chunk-CQTAKXBN.js.map +1 -0
- package/dist/chunk-L6IS63WS.js +869 -0
- package/dist/chunk-L6IS63WS.js.map +1 -0
- package/dist/{chunk-IQOCZGJJ.js → chunk-ROS67BNV.js} +5 -5
- package/dist/{chunk-7SI6XIR3.js → chunk-XAY5U67D.js} +70 -15
- package/dist/chunk-XAY5U67D.js.map +1 -0
- package/dist/{db-YWCNHBLH.js → db-BVHYI57K.js} +38 -2
- package/dist/index.cjs +42 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{server-RIKRBDOI.js → server-BKJ7LULQ.js} +818 -394
- package/dist/server-BKJ7LULQ.js.map +1 -0
- package/dist/{worker-NAKGTIF5.js → worker-TDJQ6TH3.js} +8 -8
- package/docs/mcp-tool-quality-spec.md +3 -1
- package/docs/specs/agent-ready-seo-packet-spec.md +237 -0
- package/docs/specs/cli-agent-wiring-spec.md +203 -0
- package/docs/specs/deferred-work-spec.md +12 -0
- package/docs/specs/local-competitive-audit-spec.md +312 -0
- package/docs/specs/scheduled-workflows-api-spec.md +304 -0
- package/docs/specs/seo-cli-growth-roadmap-spec.md +179 -0
- package/docs/specs/seo-workflow-runner-and-reports-spec.md +241 -0
- package/package.json +3 -2
- package/dist/chunk-7SI6XIR3.js.map +0 -1
- package/dist/chunk-D4CJBZBY.js.map +0 -1
- package/dist/chunk-IZE5UW7Y.js +0 -7
- package/dist/chunk-IZE5UW7Y.js.map +0 -1
- package/dist/chunk-MY3S7EX7.js.map +0 -1
- package/dist/server-RIKRBDOI.js.map +0 -1
- /package/dist/{chunk-3TF6UT2P.js.map → chunk-5E6KJC26.js.map} +0 -0
- /package/dist/{chunk-IQOCZGJJ.js.map → chunk-ROS67BNV.js.map} +0 -0
- /package/dist/{db-YWCNHBLH.js.map → db-BVHYI57K.js.map} +0 -0
- /package/dist/{worker-NAKGTIF5.js.map → worker-TDJQ6TH3.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/harvest-timeout.ts","../src/mcp/paa-mcp-server.ts","../src/mcp/mcp-response-formatter.ts","../src/mcp/mcp-tool-schemas.ts","../src/mcp/rank-tracker-blueprint.ts","../src/mcp/http-mcp-tool-executor.ts"],"sourcesContent":["export const VERCEL_FUNCTION_MAX_MS = 300_000\n\nexport const CLIENT_OVER_SERVER_MARGIN_MS = 15_000\n\nexport interface HarvestTimeoutBudget {\n serverMs: number\n clientMs: number\n}\n\nexport function harvestTimeoutBudget(maxQuestions: number, serpOnly = false): HarvestTimeoutBudget {\n const requested = Number.isFinite(maxQuestions) && maxQuestions > 0 ? Math.trunc(maxQuestions) : 30\n let serverMs: number\n if (serpOnly || requested <= 50) serverMs = 110_000\n else if (requested <= 100) serverMs = 180_000\n else if (requested <= 150) serverMs = 240_000\n else serverMs = 280_000\n const clientMs = Math.min(serverMs + CLIENT_OVER_SERVER_MARGIN_MS, VERCEL_FUNCTION_MAX_MS - 5_000)\n return { serverMs, clientMs }\n}\n","import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { readdirSync, readFileSync, statSync } from 'node:fs'\nimport { basename, join } from 'node:path'\nimport type { IMcpToolExecutor } from './IMcpToolExecutor.js'\nimport { PACKAGE_VERSION } from '../version.js'\nimport { outputBaseDir } from './mcp-response-formatter.js'\nimport {\n HarvestPaaInputSchema,\n SearchSerpInputSchema,\n ExtractUrlInputSchema,\n HarvestPaaOutputSchema,\n SearchSerpOutputSchema,\n ExtractUrlOutputSchema,\n ExtractSiteOutputSchema,\n MapsPlaceIntelOutputSchema,\n CreditsInfoOutputSchema,\n MapSiteUrlsInputSchema,\n MapSiteUrlsOutputSchema,\n ExtractSiteInputSchema,\n YoutubeHarvestInputSchema,\n YoutubeHarvestOutputSchema,\n YoutubeTranscribeInputSchema,\n FacebookPageIntelInputSchema,\n FacebookPageIntelOutputSchema,\n FacebookAdSearchInputSchema,\n FacebookAdSearchOutputSchema,\n FacebookAdTranscribeInputSchema,\n MapsPlaceIntelInputSchema,\n MapsSearchInputSchema,\n MapsSearchOutputSchema,\n DirectoryWorkflowInputSchema,\n DirectoryWorkflowOutputSchema,\n RankTrackerBlueprintInputSchema,\n RankTrackerBlueprintOutputSchema,\n CreditsInfoInputSchema,\n} from './mcp-tool-schemas.js'\nimport { buildRankTrackerBlueprint } from './rank-tracker-blueprint.js'\nimport {\n formatHarvestPaa,\n formatSearchSerp,\n formatExtractUrl,\n formatMapSiteUrls,\n formatExtractSite,\n formatYoutubeHarvest,\n formatYoutubeTranscribe,\n formatFacebookPageIntel,\n formatFacebookAdSearch,\n formatFacebookAdTranscribe,\n formatMapsPlaceIntel,\n formatMapsSearch,\n formatDirectoryWorkflow,\n formatCreditsInfo,\n} from './mcp-response-formatter.js'\n\nexport interface BuildMcpServerOptions {\n savesReportsLocally?: boolean\n}\n\nexport function liveWebToolAnnotations(title: string) {\n return {\n title,\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n }\n}\n\nfunction localPlanningToolAnnotations(title: string) {\n return {\n title,\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n }\n}\n\nfunction listSavedReports(): Array<{ filename: string; mtimeMs: number }> {\n try {\n const dir = outputBaseDir()\n return readdirSync(dir)\n .filter(f => f.endsWith('.md'))\n .map(f => ({ filename: f, mtimeMs: statSync(join(dir, f)).mtimeMs }))\n .sort((a, b) => b.mtimeMs - a.mtimeMs)\n .slice(0, 100)\n } catch {\n return []\n }\n}\n\nfunction registerSavedReportResources(server: McpServer): void {\n server.registerResource(\n 'saved-report',\n new ResourceTemplate('report://{filename}', {\n list: () => ({\n resources: listSavedReports().map(r => ({\n uri: `report://${encodeURIComponent(r.filename)}`,\n name: r.filename,\n mimeType: 'text/markdown',\n })),\n }),\n }),\n {\n title: 'Saved MCP Scraper Reports',\n description: 'Markdown research reports saved by previous MCP Scraper tool calls. Read a report to reuse prior research without re-scraping or spending credits.',\n mimeType: 'text/markdown',\n },\n async (uri, variables) => {\n const requested = Array.isArray(variables.filename) ? variables.filename[0] : variables.filename\n const filename = basename(decodeURIComponent(String(requested ?? '')))\n if (!filename.endsWith('.md')) throw new Error('Only saved .md reports can be read')\n const text = readFileSync(join(outputBaseDir(), filename), 'utf8')\n return { contents: [{ uri: uri.href, mimeType: 'text/markdown', text }] }\n },\n )\n}\n\nexport function buildPaaExtractorMcpServer(\n executor: IMcpToolExecutor,\n options: BuildMcpServerOptions = {},\n): McpServer {\n const server = new McpServer({ name: 'mcp-scraper', version: PACKAGE_VERSION })\n registerPaaExtractorMcpTools(server, executor, options)\n return server\n}\n\nexport function registerPaaExtractorMcpTools(\n server: McpServer,\n executor: IMcpToolExecutor,\n options: BuildMcpServerOptions = {},\n): void {\n const savesReports = options.savesReportsLocally !== false\n const reportNote = savesReports\n ? ' Saves a full Markdown report locally.'\n : ' Reports are returned inline; no files are saved on this hosted endpoint.'\n const withReportNote = (description: string) => `${description}${reportNote}`\n\n if (savesReports) registerSavedReportResources(server)\n\n server.registerTool('harvest_paa', {\n title: 'Google PAA + SERP Harvest',\n description: withReportNote('Best default tool for Google search research. Extracts People Also Ask questions plus answers/source URLs, organic SERP, local pack when present, entity IDs (CID/GCID/KG MID), and AI Overview. Infer the user language: split topic from location (e.g. \"best hvac company in Denver CO\" => query \"best hvac company\", location \"Denver, CO\", gl \"us\", hl \"en\"). For US local SERPs, leave proxyMode as location so the service uses fresh residential proxy IDs across retries and rejects wrong-location evidence instead of returning a bad market. Use maxQuestions 30 normally, 100-200 for \"full\", \"deep\", \"all\", or comprehensive research. Deep harvests above 100 questions can run for several minutes with no interim progress — warn the user before starting one and keep maxQuestions at or below 100 unless they explicitly want a deep harvest. Credits are charged by extracted question; unused request hold is refunded.'),\n inputSchema: HarvestPaaInputSchema,\n outputSchema: HarvestPaaOutputSchema,\n annotations: liveWebToolAnnotations('Google PAA + SERP Harvest'),\n }, async (input) => formatHarvestPaa(await executor.harvestPaa(input), input))\n\n server.registerTool('search_serp', {\n title: 'Google SERP Lookup',\n description: withReportNote('Fast Google SERP lookup without PAA expansion. Use when the user asks for rankings, organic results, local pack, quick SERP, or positions. Split topic from location and infer gl/hl from the user request. For US city/state rankings, keep proxyMode as location and pass proxyZip when a city-center ZIP is known; location mode uses fresh residential proxy IDs and retries CAPTCHA, proxy tunnel failures, and wrong-location evidence before returning.'),\n inputSchema: SearchSerpInputSchema,\n outputSchema: SearchSerpOutputSchema,\n annotations: liveWebToolAnnotations('Google SERP Lookup'),\n }, async (input) => formatSearchSerp(await executor.searchSerp(input), input))\n\n server.registerTool('extract_url', {\n title: 'Single URL Extract',\n description: withReportNote('Extract structured data from one public URL: page content as Markdown, heading structure, JSON-LD schema, entity details, NAP score, metadata, and missing schema fields. Use when the user provides a single URL or asks to inspect/scrape one page.'),\n inputSchema: ExtractUrlInputSchema,\n outputSchema: ExtractUrlOutputSchema,\n annotations: liveWebToolAnnotations('Single URL Extract'),\n }, async (input) => formatExtractUrl(await executor.extractUrl(input), input))\n\n server.registerTool('map_site_urls', {\n title: 'Site URL Map',\n description: withReportNote('Map/crawl a public website to build a URL inventory with HTTP status codes, broken links, redirects, and site scope. Use before extract_site for audits or when the user asks for a sitemap/URL inventory.'),\n inputSchema: MapSiteUrlsInputSchema,\n outputSchema: MapSiteUrlsOutputSchema,\n annotations: liveWebToolAnnotations('Site URL Map'),\n }, async (input) => formatMapSiteUrls(await executor.mapSiteUrls(input), input))\n\n server.registerTool('extract_site', {\n title: 'Multi-Page Site Extract',\n description: withReportNote('Run multi-page extraction across a public website. Returns per-page titles, H1s, metadata, headings, schema/entity data, canonical URLs, and content. Use for website audits, competitor audits, and full-site extraction.'),\n inputSchema: ExtractSiteInputSchema,\n outputSchema: ExtractSiteOutputSchema,\n annotations: liveWebToolAnnotations('Multi-Page Site Extract'),\n }, async (input) => formatExtractSite(await executor.extractSite(input), input))\n\n server.registerTool('youtube_harvest', {\n title: 'YouTube Video Harvest',\n description: withReportNote('Harvest YouTube video metadata by search query or channel handle/ID/URL. Use mode \"search\" for keyword/topic requests and mode \"channel\" for @handles, channel IDs, or channel URLs. Returns titles, views, dates, durations, URLs, thumbnails, and videoIds for follow-up transcription.'),\n inputSchema: YoutubeHarvestInputSchema,\n outputSchema: YoutubeHarvestOutputSchema,\n annotations: liveWebToolAnnotations('YouTube Video Harvest'),\n }, async (input) => formatYoutubeHarvest(await executor.youtubeHarvest(input), input))\n\n server.registerTool('youtube_transcribe', {\n title: 'YouTube Transcription',\n description: withReportNote('Fetch and transcribe captions from a YouTube video. Returns full transcript, timestamped chunks, and word count. Pass a videoId from youtube_harvest results or infer it from a YouTube URL if the user provided one.'),\n inputSchema: YoutubeTranscribeInputSchema,\n annotations: liveWebToolAnnotations('YouTube Transcription'),\n }, async (input) => formatYoutubeTranscribe(await executor.youtubeTranscribe(input), input))\n\n server.registerTool('facebook_page_intel', {\n title: 'Facebook Advertiser Ad Intel',\n description: withReportNote('Harvest ads from a Facebook advertiser. Returns ad copy, headlines, CTAs, creative type, status, landing URLs, and video URLs ready for transcription. Accepts pageId, libraryId, or a brand/advertiser name as query. Use after facebook_ad_search when possible.'),\n inputSchema: FacebookPageIntelInputSchema,\n outputSchema: FacebookPageIntelOutputSchema,\n annotations: liveWebToolAnnotations('Facebook Advertiser Ad Intel'),\n }, async (input) => formatFacebookPageIntel(await executor.facebookPageIntel(input), input))\n\n server.registerTool('facebook_ad_search', {\n title: 'Facebook Ad Library Search',\n description: withReportNote('Search Facebook Ad Library by brand, advertiser, competitor, niche, or keyword. Returns advertisers with ad counts and library IDs. Use to discover competitors, then pass libraryId to facebook_page_intel.'),\n inputSchema: FacebookAdSearchInputSchema,\n outputSchema: FacebookAdSearchOutputSchema,\n annotations: liveWebToolAnnotations('Facebook Ad Library Search'),\n }, async (input) => formatFacebookAdSearch(await executor.facebookAdSearch(input), input))\n\n server.registerTool('facebook_ad_transcribe', {\n title: 'Facebook Ad Transcription',\n description: 'Transcribe audio from a Facebook ad video. Returns full transcript and timestamped chunks. Use the videoUrl value from facebook_page_intel results.',\n inputSchema: FacebookAdTranscribeInputSchema,\n annotations: liveWebToolAnnotations('Facebook Ad Transcription'),\n }, async (input) => formatFacebookAdTranscribe(await executor.facebookAdTranscribe(input), input))\n\n server.registerTool('maps_place_intel', {\n title: 'Google Maps Business Profile Details',\n description: withReportNote('Extract Google Maps business intelligence for one known/named business: rating, review count, category, address, phone, website, hours, booking URL, review histogram, review topics, about attributes, entity IDs, and optional review cards. Do not use this for category searches, local market prospect lists, or requests for multiple GMB/GBP profiles; use maps_search first for those. Split business name from location (e.g. \"Elite Roofing Denver CO\" => businessName \"Elite Roofing\", location \"Denver, CO\"). Pass includeReviews true when the user asks for reviews/customer pain.'),\n inputSchema: MapsPlaceIntelInputSchema,\n outputSchema: MapsPlaceIntelOutputSchema,\n annotations: liveWebToolAnnotations('Google Maps Business Profile Details'),\n }, async (input) => formatMapsPlaceIntel(await executor.mapsPlaceIntel(input), input))\n\n server.registerTool('maps_search', {\n title: 'Google Maps Business Search',\n description: withReportNote('Search Google Maps for multiple businesses/profiles by category, niche, keyword, or local market. Use this when the user asks for several Google Business Profiles, GMBs, GBPs, leads, prospects, competitors, or \"more than the 3-pack.\" For US city/state Maps searches, keep proxyMode as location so the browser service can create a fresh residential proxy ID for that market; pass proxyZip only when a specific ZIP or city-center ZIP is known. Returns up to 50 candidates with names, place URLs, CIDs when available, ratings, review counts, and profile metadata. Default maxResults is 10; maximum is 50. Use maps_place_intel afterward only when a selected business needs full details and reviews.'),\n inputSchema: MapsSearchInputSchema,\n outputSchema: MapsSearchOutputSchema,\n annotations: liveWebToolAnnotations('Google Maps Business Search'),\n }, async (input) => formatMapsSearch(await executor.mapsSearch(input), input))\n\n server.registerTool('directory_workflow', {\n title: 'Directory Workflow: Markets + Maps',\n description: withReportNote('Build directory/prospecting datasets by selecting US city markets from the free Census Population Estimates city/place dataset, optionally joining configured US ZIPS/Lead Magician ZIP groups, then running Google Maps business searches for each city in parallel. Use this when the user wants \"all cities over 100k population in a state\", \"build a directory CSV\", \"find markets then get Maps data\", or similar location-database + Maps workflows. Set minPopulation, state, query, maxResultsPerCity, and concurrency. Use concurrency up to 5 for parallel city sessions. Keep proxyMode as location so each city can use a fresh residential proxy ID when the browser service is available; retryable city failures use fresh proxies across attempts. Saved CSV rows include source_location, result_position, business_name, review_stars, category, address, phone, hours_status, website_url, directions_url, place_url, cid, cid_decimal, city population, and ZIP groups. This workflow captures star ratings from Maps list cards, not profile review counts; use maps_place_intel only when a selected profile needs deeper review details. For local Lead Magician ZIP enrichment, set MCP_SCRAPER_USZIPS_CSV_PATH on the API server or pass usZipsCsvPath only in local/test mode.'),\n inputSchema: DirectoryWorkflowInputSchema,\n outputSchema: DirectoryWorkflowOutputSchema,\n annotations: liveWebToolAnnotations('Directory Workflow: Markets + Maps'),\n }, async (input) => formatDirectoryWorkflow(await executor.directoryWorkflow(input), input))\n\n server.registerTool('rank_tracker_blueprint', {\n title: 'Rank Tracker Blueprint Builder',\n description: 'Generate a build-ready database, cron/heartbeat, ingestion, metrics, and AI implementation prompt for a rank tracker powered by MCP Scraper. Supports Maps rankings through directory_workflow/maps_search, organic rankings through search_serp, AI Overview citation tracking, and People Also Ask source presence tracking. This tool is local planning only; it does not call the web or spend credits.',\n inputSchema: RankTrackerBlueprintInputSchema,\n outputSchema: RankTrackerBlueprintOutputSchema,\n annotations: localPlanningToolAnnotations('Rank Tracker Blueprint Builder'),\n }, async (input) => buildRankTrackerBlueprint(input))\n\n server.registerTool('credits_info', {\n title: 'MCP Scraper Credits & Costs',\n description: 'Answer questions about MCP Scraper credits: current credit balance, what a specific tool/action costs, the full cost table, and optionally recent credit ledger entries. Does not expose payment methods or credit card information.',\n inputSchema: CreditsInfoInputSchema,\n outputSchema: CreditsInfoOutputSchema,\n annotations: {\n title: 'MCP Scraper Credits & Costs',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n }, async (input) => formatCreditsInfo(await executor.creditsInfo(input), input))\n\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { sanitizeVendorName } from '../errors.js'\n\nlet reportSavingEnabled = true\n\nexport function configureReportSaving(enabled: boolean): void {\n reportSavingEnabled = enabled\n}\n\nfunction sanitizeVendorText(text: string): string {\n return sanitizeVendorName(\n text\n .replace(/kernel_session_id/gi, 'browser_session_id')\n .replace(/kernel_delete_succeeded/gi, 'session_cleanup_succeeded')\n .replace(/kernel_delete_started/gi, 'session_cleanup_started')\n .replace(/kernel_delete_error/gi, 'session_cleanup_error')\n .replace(/kernelSessionId/g, 'browserSessionId')\n .replace(/kernelProxyId/g, 'proxyId')\n .replace(/KERNEL_API_KEY/g, 'BROWSER_SERVICE_API_KEY')\n .replace(/\"kernel\"\\s*:/gi, '\"browserRuntime\":'),\n )\n}\n\nfunction slugifyReportName(input: string): string {\n return input\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 80) || 'mcp-scraper-report'\n}\n\nfunction reportTitle(full: string): string {\n const title = full.split('\\n').find(line => line.startsWith('# '))\n return title?.replace(/^#\\s+/, '').trim() || 'MCP Scraper Report'\n}\n\nexport function outputBaseDir(): string {\n return process.env.MCP_SCRAPER_OUTPUT_DIR?.trim() || join(homedir(), 'Downloads', 'mcp-scraper')\n}\n\nfunction saveFullReport(full: string): string | null {\n if (!reportSavingEnabled || process.env.MCP_SCRAPER_SAVE_REPORTS === 'false') return null\n const outDir = outputBaseDir()\n try {\n mkdirSync(outDir, { recursive: true })\n const stamp = new Date().toISOString().replace(/[:.]/g, '-')\n const file = join(outDir, `${stamp}-${slugifyReportName(reportTitle(full))}.md`)\n writeFileSync(file, full, 'utf8')\n return file\n } catch {\n return null\n }\n}\n\nfunction persistScreenshotLocally(base64: string, url: string): string | null {\n if (!reportSavingEnabled || process.env.MCP_SCRAPER_SAVE_REPORTS === 'false') return null\n try {\n const dir = join(outputBaseDir(), 'screenshots')\n mkdirSync(dir, { recursive: true })\n const stamp = new Date().toISOString().replace(/[:.]/g, '-')\n const slug = url.replace(/^https?:\\/\\//, '').replace(/[^a-z0-9]+/gi, '-').replace(/^-+|-+$/g, '').slice(0, 60)\n const filePath = join(dir, `${stamp}-${slug}.png`)\n writeFileSync(filePath, Buffer.from(base64, 'base64'))\n return filePath\n } catch {\n return null\n }\n}\n\nfunction oneBlock(content: string): CallToolResult {\n const filePath = saveFullReport(content)\n const text = filePath ? `${content}\\n\\n📄 Saved: \\`${filePath}\\`` : content\n return { content: [{ type: 'text', text }] }\n}\n\nexport function passthrough(raw: CallToolResult): CallToolResult {\n return raw\n}\n\nfunction checkInsufficientBalance(raw: CallToolResult): CallToolResult | null {\n const first = raw.content.find(b => b.type === 'text')\n const text = first?.type === 'text' ? first.text : ''\n try {\n const body = JSON.parse(text || '{}') as Record<string, unknown>\n if (body.error === 'insufficient_balance') {\n return {\n isError: true,\n content: [{\n type: 'text',\n text: `Insufficient credits. Balance: ${body.balance_credits} credits. This call requires ${body.required_credits} credits. Top up at ${body.topup_url}`,\n }],\n }\n }\n } catch { }\n return null\n}\n\nfunction formatStructuredError(body: Record<string, unknown>, fallback: string): string {\n if (body.error === 'insufficient_balance') {\n return `Insufficient credits. Balance: ${body.balance_credits} credits. This call requires ${body.required_credits} credits. Top up at ${body.topup_url}`\n }\n if (body.error === 'mcp_request_timeout') {\n return typeof body.message === 'string' ? body.message : 'MCP Scraper request timed out and was cancelled.'\n }\n if (typeof body.error_code === 'string') {\n const message = typeof body.error === 'string'\n ? body.error\n : typeof body.message === 'string'\n ? body.message\n : fallback\n const retryable = body.retryable === true ? ' Retryable: yes.' : ''\n return `${body.error_code}: ${message}${retryable}${errorAttemptsSection(body)}`\n }\n if (typeof body.error === 'string') return body.error\n return fallback || 'Tool error'\n}\n\nfunction parseData(raw: CallToolResult): { data: Record<string, unknown> } | { error: string } {\n const first = raw.content.find(b => b.type === 'text')\n const text = first?.type === 'text' ? first.text : ''\n try {\n const parsed = JSON.parse(text || '{}') as Record<string, unknown>\n if (raw.isError || parsed.error || parsed.error_code) return { error: sanitizeVendorText(formatStructuredError(parsed, text)) }\n const data = (parsed.result as Record<string, unknown>) ?? parsed\n return { data }\n } catch {\n if (raw.isError) return { error: sanitizeVendorText(text || 'Tool error') }\n return { error: 'Failed to parse tool response' }\n }\n}\n\nfunction entityIdsSection(ids?: { kgIds?: string[]; cids?: string[]; gcids?: string[] }): string {\n if (!ids) return ''\n const lines: string[] = []\n if (ids.kgIds?.length) lines.push(`- **Knowledge Graph MID:** ${ids.kgIds.join(', ')}`)\n if (ids.cids?.length) lines.push(`- **CID:** ${ids.cids.join(', ')}`)\n if (ids.gcids?.length) lines.push(`- **GCID:** ${ids.gcids.join(', ')}`)\n return lines.length ? `\\n## Entity IDs\\n${lines.join('\\n')}` : ''\n}\n\nfunction truncate(s: string | null | undefined, max: number): string {\n if (!s) return ''\n return s.length > max ? s.slice(0, max) + '…' : s\n}\n\nexport function cell(s: string | null | undefined): string {\n return String(s ?? '')\n .replace(/\\r?\\n+/g, ' ')\n .replace(/\\|/g, '\\\\|')\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\nfunction debugSection(debug: any): string {\n if (!debug || typeof debug !== 'object') return ''\n const request = debug.request ?? {}\n const browser = debug.browser ?? {}\n const kernel = browser.browserRuntime ?? browser.kernel ?? {}\n const network = browser.networkLocation ?? {}\n const nav = browser.serpNavigation ?? {}\n const proxyResolution = kernel.proxyResolution ?? {}\n const locationEvidence = debug.locationEvidence\n const candidates = Array.isArray(locationEvidence?.candidates)\n ? locationEvidence.candidates.slice(0, 4).map((c: any) => `${c.city}, ${c.regionCode} (${c.count})`).join(', ')\n : ''\n const lines = [\n '\\n## Debug',\n `- Proxy mode: ${request.proxyMode ?? kernel.proxyMode ?? 'unknown'} · requested proxy: ${kernel.requestedProxyIdPresent === true ? `yes (${kernel.requestedProxyIdSuffix ?? 'redacted'})` : 'no'}`,\n `- Proxy resolution: ${proxyResolution.source ?? 'unknown'}${proxyResolution.target ? ` · ${proxyResolution.target.level ?? 'city'} ${proxyResolution.target.city}, ${proxyResolution.target.state}` : ''}${proxyResolution.error ? ` · ${truncate(proxyResolution.error, 180)}` : ''}`,\n `- Browser session: ${kernel.sessionId ?? 'unknown'} · retrieved proxy: ${kernel.retrievedProxyIdPresent === true ? `yes (${kernel.retrievedProxyIdSuffix ?? 'redacted'})` : kernel.retrievedProxyIdPresent === false ? 'no' : 'unknown'}`,\n `- Browser IP geo: ${[network.ip, network.city, network.region, network.country].filter(Boolean).join(' · ') || network.error || 'unknown'}`,\n `- Google URL: ${truncate(nav.requestedUrl, 240) || 'unknown'}`,\n `- Final URL: ${truncate(nav.finalUrl, 240) || 'unknown'} · CAPTCHA: ${nav.captchaDetected === true ? 'yes' : nav.captchaDetected === false ? 'no' : 'unknown'} · redirected: ${nav.redirected === true ? 'yes' : nav.redirected === false ? 'no' : 'unknown'}`,\n ]\n if (locationEvidence) {\n lines.push(`- Location evidence: ${locationEvidence.status}${locationEvidence.expected ? ` · expected ${locationEvidence.expected.city}${locationEvidence.expected.regionCode ? `, ${locationEvidence.expected.regionCode}` : ''}` : ''}${candidates ? ` · candidates ${candidates}` : ''}`)\n }\n return sanitizeVendorText(lines.join('\\n'))\n}\n\nfunction errorAttemptsSection(body: Record<string, unknown>): string {\n const attempts = Array.isArray(body.attempts) ? body.attempts as Array<Record<string, any>> : []\n if (attempts.length === 0) return ''\n const lines = attempts.slice(0, 5).map((attempt) => {\n const debug = attempt.debug ?? {}\n const browser = debug.browser ?? {}\n const kernel = browser.browserRuntime ?? browser.kernel ?? {}\n const proxyResolution = kernel.proxyResolution ?? {}\n const network = browser.networkLocation ?? {}\n const nav = browser.serpNavigation ?? {}\n const geo = [network.ip, network.city, network.region].filter(Boolean).join(' / ') || 'geo unknown'\n const sessionId = attempt.browser_session_id ?? attempt.kernel_session_id ?? kernel.sessionId ?? 'unknown'\n const cleanupSucceeded = attempt.session_cleanup_succeeded ?? attempt.kernel_delete_succeeded\n return `- Attempt ${attempt.attempt_number ?? '?'}: ${attempt.outcome ?? attempt.status ?? 'unknown'} · session ${sessionId} · proxy ${debug.request?.proxyMode ?? kernel.proxyMode ?? 'unknown'}${proxyResolution.source ? `/${proxyResolution.source}` : ''} · ${geo} · CAPTCHA ${nav.captchaDetected === true ? 'yes' : nav.captchaDetected === false ? 'no' : 'unknown'} · cleanup ${cleanupSucceeded === true ? 'yes' : cleanupSucceeded === false ? 'no' : 'unknown'}`\n })\n return `\\n\\nAttempts:\\n${lines.join('\\n')}`\n}\n\ninterface FlatRow { question: string; answer?: string; source_site?: string; source_title?: string }\ninterface OrganicResult { position: number; title: string; url: string; domain: string; snippet?: string | null }\ninterface AIOverview { detected: boolean; text?: string | null }\ninterface HarvestDiagnostics { completionStatus?: string; debug?: unknown }\n\nexport function formatHarvestPaa(\n raw: CallToolResult,\n input: { query: string; maxQuestions?: number; location?: string },\n): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data\n\n const flat = (d.flat as FlatRow[]) ?? []\n const organic = (d.organicResults as OrganicResult[]) ?? []\n const entityIds = d.entityIds as { kgIds?: string[]; cids?: string[]; gcids?: string[] } | undefined\n const aiOvw = d.aiOverview as AIOverview | undefined\n const diagnostics = d.diagnostics as HarvestDiagnostics | undefined\n const durationMs = (d.stats as { durationMs?: number } | undefined)?.durationMs\n\n const paaRows = flat.map((r, i) =>\n `| ${i + 1} | ${cell(r.question)} | ${cell(truncate(r.answer, 120))} | ${cell(r.source_title || r.source_site || '')} |`,\n ).join('\\n')\n\n const paaTable = flat.length\n ? `## People Also Ask (${flat.length} questions)\\n| # | Question | Answer | Source |\\n|---|----------|--------|--------|\\n${paaRows}`\n : '## People Also Ask\\n*Google did not return a People Also Ask block for this query/location. SERP data was extracted successfully when available.*'\n\n const serpRows = organic.map(r =>\n `| ${r.position} | ${cell(r.title)} | [${cell(r.domain)}](${r.url}) | ${cell(truncate(r.snippet, 100))} |`,\n ).join('\\n')\n\n const serpTable = organic.length\n ? `\\n## Organic Results (${organic.length})\\n| # | Title | URL | Snippet |\\n|---|-------|-----|----------|\\n${serpRows}`\n : ''\n\n const aiSection = aiOvw?.detected && aiOvw.text\n ? `\\n## AI Overview\\n> ${truncate(aiOvw.text, 600)}`\n : ''\n\n const statsLine = durationMs\n ? `\\n## Stats\\n- Status: ${diagnostics?.completionStatus ?? (flat.length ? 'paa_found' : 'no_paa')} · Questions: ${flat.length} · Duration: ${(durationMs / 1000).toFixed(1)}s`\n : ''\n\n const tips = `\\n---\\n💡 **Tips**\\n- Max questions: \\`maxQuestions: 200\\` (current: ${input.maxQuestions ?? 30})\\n- Organic results only: use \\`search_serp\\`\\n- Dig into a result: use \\`extract_url\\` on any organic URL`\n\n const full = `# PAA Report: \"${input.query}\"${input.location ? ` · ${input.location}` : ''}\\n\\n${paaTable}${serpTable}${entityIdsSection(entityIds)}${aiSection}${statsLine}${debugSection(diagnostics?.debug)}${tips}`\n\n return {\n ...oneBlock(full),\n structuredContent: {\n query: input.query,\n location: input.location ?? null,\n questionCount: flat.length,\n completionStatus: diagnostics?.completionStatus ?? null,\n questions: flat.map(r => ({\n question: String(r.question ?? ''),\n answer: r.answer ?? null,\n sourceTitle: r.source_title ?? null,\n sourceSite: r.source_site ?? null,\n })),\n organicResults: organic.map(r => ({\n position: Number(r.position) || 0,\n title: String(r.title ?? ''),\n url: String(r.url ?? ''),\n domain: String(r.domain ?? ''),\n snippet: r.snippet ?? null,\n })),\n aiOverview: aiOvw ? { detected: aiOvw.detected === true, text: aiOvw.text ?? null } : null,\n entityIds: entityIds\n ? { kgIds: entityIds.kgIds ?? [], cids: entityIds.cids ?? [], gcids: entityIds.gcids ?? [] }\n : null,\n durationMs: durationMs ?? null,\n },\n }\n}\n\ninterface LocalBusiness { position: number; name: string; rating?: string | null; reviewCount?: string | null; websiteUrl?: string | null }\n\nexport function formatSearchSerp(\n raw: CallToolResult,\n input: { query: string; location?: string },\n): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data\n\n const organic = (d.organicResults as OrganicResult[]) ?? []\n const localPack = (d.localPack as LocalBusiness[]) ?? []\n const entityIds = d.entityIds as { kgIds?: string[]; cids?: string[]; gcids?: string[] } | undefined\n const aiOvw = d.aiOverview as AIOverview | undefined\n const diagnostics = d.diagnostics as HarvestDiagnostics | undefined\n\n const serpRows = organic.map(r =>\n `| ${r.position} | ${cell(r.title)} | [${cell(r.domain)}](${r.url}) | ${cell(truncate(r.snippet, 100))} |`,\n ).join('\\n')\n\n const serpTable = organic.length\n ? `## Organic Results (${organic.length})\\n| # | Title | URL | Snippet |\\n|---|-------|-----|----------|\\n${serpRows}`\n : '## Organic Results\\n*None found*'\n\n const localRows = localPack.map(b =>\n `| ${b.position} | ${cell(b.name)} | ${b.rating ?? '—'} (${b.reviewCount ?? '0'}) | ${b.websiteUrl ? `[link](${b.websiteUrl})` : '—'} |`,\n ).join('\\n')\n\n const localSection = localPack.length\n ? `\\n## Local Pack (${localPack.length})\\n| # | Name | Rating | Website |\\n|---|------|--------|---------|\\n${localRows}`\n : ''\n\n const aiSection = aiOvw?.detected && aiOvw.text\n ? `\\n## AI Overview\\n> ${truncate(aiOvw.text, 600)}`\n : ''\n\n const tips = `\\n---\\n💡 **Tips**\\n- Get PAA questions: use \\`harvest_paa\\` for this query\\n- Scrape any result: use \\`extract_url\\`\\n- Business entity IDs (CID/GCID/KG MID) shown above if found`\n\n const full = `# SERP Report: \"${input.query}\"${input.location ? ` · ${input.location}` : ''}\\n\\n${serpTable}${localSection}${entityIdsSection(entityIds)}${aiSection}${debugSection(diagnostics?.debug)}${tips}`\n\n return {\n ...oneBlock(full),\n structuredContent: {\n query: input.query,\n location: input.location ?? null,\n organicResults: organic.map(r => ({\n position: Number(r.position) || 0,\n title: String(r.title ?? ''),\n url: String(r.url ?? ''),\n domain: String(r.domain ?? ''),\n snippet: r.snippet ?? null,\n })),\n localPack: localPack.map(b => ({\n position: Number(b.position) || 0,\n name: String(b.name ?? ''),\n rating: b.rating ?? null,\n reviewCount: b.reviewCount ?? null,\n websiteUrl: b.websiteUrl ?? null,\n })),\n aiOverview: aiOvw ? { detected: aiOvw.detected === true, text: aiOvw.text ?? null } : null,\n entityIds: entityIds\n ? { kgIds: entityIds.kgIds ?? [], cids: entityIds.cids ?? [], gcids: entityIds.gcids ?? [] }\n : null,\n },\n }\n}\n\ninterface Heading { level: number; text: string }\ninterface KpoResult {\n entityName?: string | null; type?: string[]; napScore?: number\n address?: string | null; phone?: string | null; email?: string | null\n sameAs?: string[]; missingFields?: string[]; faqCount?: number\n}\n\nexport function formatExtractUrl(raw: CallToolResult, input: { url: string }): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data\n\n const url = (d.url as string) ?? input.url\n const title = (d.title as string | null) ?? 'Untitled'\n const headings = (d.headings as Heading[]) ?? []\n const kpo = d.kpo as KpoResult | undefined\n const bodyMd = (d.bodyMarkdown as string | null) ?? ''\n const schema = d.schema as unknown[]\n const screenshotMeta = d.screenshot as { base64: string; sizeBytes: number; device: string } | null | undefined\n const screenshotPath = screenshotMeta?.base64 ? persistScreenshotLocally(screenshotMeta.base64, url) : null\n const branding = d.branding as { colorScheme: string | null; colors: Record<string, string | null>; fonts: Record<string, string | null>; assets: Record<string, string | null> } | null | undefined\n const media = d.media as { outputDir: string | null; assets: unknown[]; filteredCount: number; totalFound: number } | null | undefined\n\n const h1Lines = headings.filter(h => h.level === 1).map(h => `- ${h.text}`).join('\\n')\n const h2Lines = headings.filter(h => h.level === 2).map(h => ` - ${h.text}`).join('\\n')\n const headingSection = (h1Lines || h2Lines)\n ? `\\n## Heading Structure\\n${[h1Lines, h2Lines].filter(Boolean).join('\\n')}`\n : ''\n\n const kpoSection = kpo ? [\n `\\n## Entity / Schema`,\n kpo.entityName ? `- **Entity:** ${kpo.entityName}` : '',\n kpo.type?.length ? `- **@type:** ${kpo.type.join(', ')}` : '',\n kpo.napScore !== undefined ? `- **NAP Score:** ${kpo.napScore}/5` : '',\n kpo.address ? `- **Address:** ${kpo.address}` : '',\n kpo.phone ? `- **Phone:** ${kpo.phone}` : '',\n kpo.email ? `- **Email:** ${kpo.email}` : '',\n kpo.faqCount ? `- **FAQ items:** ${kpo.faqCount}` : '',\n kpo.sameAs?.length ? `- **sameAs:** ${kpo.sameAs.slice(0, 5).join(', ')}` : '',\n kpo.missingFields?.length ? `\\n**Missing schema fields:** ${kpo.missingFields.slice(0, 5).join(', ')}` : '',\n ].filter(Boolean).join('\\n') : ''\n\n const bodySection = bodyMd\n ? `\\n## Page Content\\n${bodyMd.slice(0, 3000)}${bodyMd.length > 3000 ? '\\n\\n*(truncated)*' : ''}`\n : ''\n\n const screenshotSection = screenshotMeta\n ? `\\n## Screenshot\\n- **File:** ${screenshotPath ?? '(returned inline only — disk write unavailable in this environment)'}\\n- **Size:** ${(screenshotMeta.sizeBytes / 1024).toFixed(1)} KB\\n- **Device:** ${screenshotMeta.device}`\n : ''\n\n const brandingSection = branding\n ? [\n `\\n## Branding`,\n branding.colorScheme ? `- **Color scheme:** ${branding.colorScheme}` : '',\n `- **Colors:**${Object.entries(branding.colors ?? {}).filter(([,v]) => v).map(([k,v]) => ` ${k}=${v}`).join(',') || ' (none extracted)'}`,\n `- **Fonts:**${Object.entries(branding.fonts ?? {}).filter(([,v]) => v).map(([k,v]) => ` ${k}=${v}`).join(',') || ' (none extracted)'}`,\n branding.assets?.logo ? `- **Logo:** ${branding.assets.logo}` : '',\n branding.assets?.favicon ? `- **Favicon:** ${branding.assets.favicon}` : '',\n ].filter(Boolean).join('\\n')\n : ''\n\n const mediaSection = media\n ? [\n `\\n## Media Assets`,\n `- **Found:** ${media.totalFound} total, ${media.filteredCount} filtered (ads/noise), ${media.assets.length} downloaded`,\n media.outputDir ? `- **Saved to:** ${media.outputDir}` : '',\n ].filter(Boolean).join('\\n')\n : ''\n\n const schemaCount = Array.isArray(schema) ? schema.length : 0\n const tips = `\\n---\\n💡 **Tips**\\n- Crawl entire site: use \\`extract_site\\`\\n- Map all URLs: use \\`map_site_urls\\`\\n- ${schemaCount} JSON-LD schema block(s) detected`\n\n const full = `# URL Extract: ${url}\\n**${title}**\\n${headingSection}${kpoSection}${brandingSection}${bodySection}${screenshotSection}${mediaSection}${tips}`\n\n const textResult = oneBlock(full)\n const structuredContent = {\n url,\n title: (d.title as string | null) ?? null,\n headings: headings.map(h => ({ level: Number(h.level) || 0, text: String(h.text ?? '') })),\n schemaBlockCount: schemaCount,\n entityName: kpo?.entityName ?? null,\n entityTypes: kpo?.type ?? [],\n napScore: kpo?.napScore ?? null,\n missingSchemaFields: kpo?.missingFields ?? [],\n screenshotSaved: screenshotPath ?? null,\n }\n\n if (screenshotMeta?.base64) {\n return {\n content: [\n ...(textResult.content),\n { type: 'image', data: screenshotMeta.base64, mimeType: 'image/png' },\n ],\n structuredContent,\n }\n }\n\n return { ...textResult, structuredContent }\n}\n\ninterface DiscoveredUrl { url: string; status: number | null }\ninterface SpiderResult { startUrl: string; urls: DiscoveredUrl[]; totalFound: number; durationMs: number; truncated: boolean }\n\nexport function formatMapSiteUrls(raw: CallToolResult, input: { url: string }): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data as unknown as SpiderResult\n\n const urls = d.urls ?? []\n const ok = urls.filter(u => (u.status ?? 0) >= 200 && (u.status ?? 0) < 300)\n const broken = urls.filter(u => u.status !== null && u.status >= 400)\n const redirects = urls.filter(u => u.status !== null && u.status >= 300 && u.status < 400)\n\n const urlRows = urls.slice(0, 200).map((u, i) => `| ${i + 1} | ${u.url} | ${u.status ?? '—'} |`).join('\\n')\n\n const full = [\n `# URL Map: ${input.url}`,\n `**${d.totalFound} URLs** · ${(d.durationMs / 1000).toFixed(1)}s${d.truncated ? ' · *truncated*' : ''}`,\n `\\n## Summary\\n- ✅ 2xx: ${ok.length}\\n- 🔀 3xx: ${redirects.length}\\n- ❌ 4xx+: ${broken.length}`,\n `\\n## URL Inventory\\n| # | URL | Status |\\n|---|-----|--------|\\n${urlRows}`,\n broken.length ? `\\n## Broken URLs\\n${broken.map(u => `- ${u.url} (${u.status})`).join('\\n')}` : '',\n `\\n---\\n💡 **Tips**\\n- Extract content from all pages: use \\`extract_site\\`\\n- Scrape a single page: use \\`extract_url\\``,\n ].filter(Boolean).join('\\n')\n\n return {\n ...oneBlock(full),\n structuredContent: {\n startUrl: d.startUrl ?? input.url,\n totalFound: d.totalFound ?? urls.length,\n truncated: d.truncated === true,\n okCount: ok.length,\n redirectCount: redirects.length,\n brokenCount: broken.length,\n urls: urls.map(u => ({ url: u.url, status: u.status ?? null })),\n durationMs: d.durationMs ?? 0,\n },\n }\n}\n\ninterface SitePageResult { url: string; title?: string | null; kpo?: KpoResult; schema?: unknown[] }\ninterface ExtractSiteResult { pages: SitePageResult[]; durationMs?: number }\n\nexport function formatExtractSite(raw: CallToolResult, input: { url: string }): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data as unknown as ExtractSiteResult\n\n const pages = d.pages ?? []\n\n const pageRows = pages.map((p, i) => {\n const schemaInfo = p.kpo?.type?.join(', ') ?? (Array.isArray(p.schema) && p.schema.length ? `${p.schema.length} block(s)` : '—')\n return `| ${i + 1} | ${cell(p.title ?? 'Untitled')} | ${p.url} | ${schemaInfo} |`\n }).join('\\n')\n\n const full = [\n `# Site Extract: ${input.url}`,\n `**${pages.length} pages** · ${(((d.durationMs ?? 0)) / 1000).toFixed(1)}s`,\n `\\n## Pages\\n| # | Title | URL | Schema |\\n|---|-------|-----|--------|\\n${pageRows}`,\n `\\n---\\n💡 **Tips**\\n- Map URLs first: use \\`map_site_urls\\`\\n- Inspect a single page: use \\`extract_url\\``,\n ].join('\\n')\n\n return {\n ...oneBlock(full),\n structuredContent: {\n url: input.url,\n pageCount: pages.length,\n pages: pages.map(p => ({\n url: String(p.url ?? ''),\n title: p.title ?? null,\n schemaTypes: p.kpo?.type ?? [],\n })),\n durationMs: d.durationMs ?? 0,\n },\n }\n}\n\ninterface YTVideo { videoId: string; title: string; channelName: string; views?: string | null; duration?: string | null; url: string }\ninterface YTHarvestResult { videos: YTVideo[]; channelMeta?: { title?: string; subscriberCount?: string | null } | null; stats: { durationMs: number } }\n\nexport function formatYoutubeHarvest(\n raw: CallToolResult,\n input: { mode: string; query?: string; channelHandle?: string },\n): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data as unknown as YTHarvestResult\n\n const videos = d.videos ?? []\n const label = input.mode === 'channel' ? (input.channelHandle ?? 'channel') : `\"${input.query ?? ''}\"`\n\n const videoRows = videos.map((v, i) =>\n `| ${i + 1} | ${cell(truncate(v.title, 70))} | ${cell(v.channelName)} | ${v.views ?? '—'} | ${v.duration ?? '—'} | \\`${v.videoId}\\` |`,\n ).join('\\n')\n\n const channelSection = d.channelMeta\n ? `\\n## Channel\\n- **Name:** ${d.channelMeta.title ?? '—'}\\n- **Subscribers:** ${d.channelMeta.subscriberCount ?? '—'}`\n : ''\n\n const full = [\n `# YouTube Harvest: ${label}`,\n `**${videos.length} videos** · ${(d.stats.durationMs / 1000).toFixed(1)}s`,\n channelSection,\n `\\n## Videos\\n| # | Title | Channel | Views | Duration | Video ID |\\n|---|-------|---------|-------|----------|----------|\\n${videoRows}`,\n `\\n---\\n💡 **Tips**\\n- Transcribe a video: use \\`youtube_transcribe\\` with the \\`videoId\\` above\\n- Switch mode: \\`mode: \"channel\"\\` with \\`channelHandle\\` or \\`mode: \"search\"\\` with \\`query\\``,\n ].filter(Boolean).join('\\n')\n\n return {\n ...oneBlock(full),\n structuredContent: {\n mode: input.mode,\n videoCount: videos.length,\n channel: d.channelMeta\n ? { title: d.channelMeta.title ?? null, subscriberCount: d.channelMeta.subscriberCount ?? null }\n : null,\n videos: videos.map(v => ({\n videoId: String(v.videoId ?? ''),\n title: String(v.title ?? ''),\n channelName: v.channelName ?? null,\n views: v.views ?? null,\n duration: v.duration ?? null,\n url: v.url ?? null,\n })),\n },\n }\n}\n\ninterface TranscriptChunk { timestamp: [number, number]; text: string }\ninterface TranscriptResult { text: string; chunks?: TranscriptChunk[]; durationMs?: number }\n\nexport function formatYoutubeTranscribe(raw: CallToolResult, input: { videoId: string }): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data as unknown as TranscriptResult\n\n const text = d.text ?? ''\n const chunks = d.chunks ?? []\n const durSec = d.durationMs ? (d.durationMs / 1000).toFixed(0) : '—'\n\n const chunkRows = chunks.slice(0, 50).map(c => {\n const sec = Number.isFinite(c.timestamp[0]) ? Math.floor(c.timestamp[0]) : 0\n const mm = String(Math.floor(sec / 60)).padStart(2, '0')\n const ss = String(sec % 60).padStart(2, '0')\n return `| ${mm}:${ss} | ${cell(truncate(c.text, 120))} |`\n }).join('\\n')\n\n const full = [\n `# YouTube Transcript: \\`${input.videoId}\\``,\n `**Duration:** ${durSec}s · **${text.split(' ').length} words**`,\n `\\n## Full Transcript\\n${text}`,\n chunks.length ? `\\n## Timestamped Chunks\\n| Time | Text |\\n|------|------|\\n${chunkRows}` : '',\n `\\n---\\n💡 Harvest more from this channel: use \\`youtube_harvest\\` with \\`mode: \"channel\"\\``,\n ].filter(Boolean).join('\\n')\n\n return oneBlock(full)\n}\n\ninterface FbAd {\n libraryId?: string; status?: string; creativeType?: string\n headline?: string | null; primaryText?: string | null; cta?: string | null\n startDate?: string | null; videoUrl?: string | null; variations?: number\n}\ninterface FbPageResult {\n advertiserName?: string | null\n summary: { totalAds: number; activeCount: number; videoCount: number; imageCount: number }\n ads: FbAd[]\n}\n\nexport function formatFacebookPageIntel(\n raw: CallToolResult,\n input: { pageId?: string; libraryId?: string; query?: string },\n): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data as unknown as FbPageResult\n\n const advertiser = d.advertiserName ?? input.query ?? input.pageId ?? input.libraryId ?? 'Advertiser'\n const ads = d.ads ?? []\n const s = d.summary ?? { totalAds: 0, activeCount: 0, videoCount: 0, imageCount: 0 }\n\n const adBlocks = ads.map((ad, i) => [\n `### Ad ${i + 1}${ad.libraryId ? ` · \\`${ad.libraryId}\\`` : ''} — ${ad.status ?? '—'} · ${ad.creativeType ?? '—'} · ${ad.startDate ?? '—'}`,\n ad.headline ? `**Headline:** ${ad.headline}` : '',\n ad.primaryText ? `**Copy:** ${truncate(ad.primaryText, 200)}` : '',\n ad.cta ? `**CTA:** ${ad.cta}` : '',\n ad.videoUrl ? `**Video URL:** \\`${ad.videoUrl}\\`` : '',\n ad.variations ? `**Variations:** ${ad.variations}` : '',\n ].filter(Boolean).join('\\n')).join('\\n\\n---\\n\\n')\n\n const full = [\n `# Facebook Ad Intel: ${advertiser}`,\n `**${s.totalAds} ads** · ${s.activeCount} active · ${s.videoCount} video · ${s.imageCount} image`,\n `\\n${adBlocks}`,\n `\\n---\\n💡 **Tips**\\n- Transcribe video ads: use \\`facebook_ad_transcribe\\` with the \\`videoUrl\\` above\\n- Find other advertisers: use \\`facebook_ad_search\\``,\n ].filter(Boolean).join('\\n')\n\n return {\n ...oneBlock(full),\n structuredContent: {\n advertiserName: d.advertiserName ?? null,\n totalAds: s.totalAds ?? 0,\n activeCount: s.activeCount ?? 0,\n videoCount: s.videoCount ?? 0,\n imageCount: s.imageCount ?? 0,\n ads: ads.map(ad => ({\n libraryId: ad.libraryId ?? null,\n status: ad.status ?? null,\n creativeType: ad.creativeType ?? null,\n headline: ad.headline ?? null,\n cta: ad.cta ?? null,\n startDate: ad.startDate ?? null,\n videoUrl: ad.videoUrl ?? null,\n variations: typeof ad.variations === 'number' ? ad.variations : null,\n })),\n },\n }\n}\n\ninterface FbAdvertiserResult { name?: string; pageName?: string; adCount?: number; libraryId?: string; sampleLibraryId?: string }\ninterface FbSearchResult { results?: FbAdvertiserResult[]; advertisers?: FbAdvertiserResult[] }\n\nexport function formatFacebookAdSearch(raw: CallToolResult, input: { query: string }): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data as unknown as FbSearchResult\n\n const advertisers = d.results ?? d.advertisers ?? []\n\n const rows = advertisers.map((a, i) =>\n `| ${i + 1} | ${cell(a.pageName ?? a.name)} | ${a.adCount ?? '—'} | \\`${a.sampleLibraryId ?? a.libraryId ?? '—'}\\` |`,\n ).join('\\n')\n\n const full = [\n `# Facebook Ad Library Search: \"${input.query}\"`,\n `**${advertisers.length} advertisers found**`,\n `\\n## Advertisers\\n| # | Name | Ad Count | Library ID |\\n|---|------|----------|------------|\\n${rows}`,\n `\\n---\\n💡 **Tips**\\n- Scan all ads: use \\`facebook_page_intel\\` with \\`libraryId\\`\\n- Or pass the advertiser name as \\`query\\` in \\`facebook_page_intel\\``,\n ].join('\\n')\n\n return {\n ...oneBlock(full),\n structuredContent: {\n query: input.query,\n advertiserCount: advertisers.length,\n advertisers: advertisers.map(a => ({\n name: a.pageName ?? a.name ?? null,\n adCount: typeof a.adCount === 'number' ? a.adCount : null,\n libraryId: a.sampleLibraryId ?? a.libraryId ?? null,\n })),\n },\n }\n}\n\ninterface MapsReviewCard { author: string | null; stars: string | null; date: string | null; text: string | null }\ntype ReviewsStatus = 'collected' | 'none_exist' | 'unavailable' | 'not_requested'\ninterface MapsHistogramEntry { stars: number; count: string }\ninterface MapsTopicEntry { label: string; count: string }\ninterface MapsAboutEntry { section: string; attribute: string }\ninterface MapsSearchBusiness {\n position: number\n name: string\n placeUrl: string\n cid: string | null\n cidDecimal: string | null\n rating: string | null\n reviewCount: string | null\n category: string | null\n address: string | null\n phone: string | null\n hoursStatus: string | null\n websiteUrl: string | null\n directionsUrl: string | null\n metadata: string[]\n}\ninterface DirectoryWorkflowCity {\n city: string\n state: string\n location: string\n cityKey: string\n censusName: string\n population: number\n populationYear: number\n zips: string[]\n counties: string[]\n status: 'ok' | 'empty' | 'failed'\n error: string | null\n resultCount: number\n durationMs: number\n results: MapsSearchBusiness[]\n}\ninterface CreditCostEntry { key: string; label: string; credits: number; unit: string; notes?: string }\ninterface CreditLedgerEntry { amount_mc: number; operation: string; description: string | null; created_at: string }\n\nexport function formatCreditsInfo(raw: CallToolResult, input: { item?: string; includeLedger?: boolean }): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data as Record<string, unknown>\n\n const balance = d.balance_credits as number | undefined\n const costs = (d.costs as CreditCostEntry[] | undefined) ?? []\n const matched = d.matched_cost as CreditCostEntry | null\n const ledger = (d.ledger as CreditLedgerEntry[] | undefined) ?? []\n\n const costRows = costs.map(c => {\n const notes = c.notes ? ` ${c.notes}` : ''\n return `| ${c.label} | ${c.credits} | ${c.unit}${notes} |`\n }).join('\\n')\n\n const ledgerRows = ledger.map(row => {\n const credits = row.amount_mc / 1000\n return `| ${row.created_at} | ${row.operation} | ${credits} | ${row.description ?? ''} |`\n }).join('\\n')\n\n const matchedSection = matched\n ? `\\n## Matched Cost\\n**${matched.label}:** ${matched.credits} credits ${matched.unit}${matched.notes ? `\\n\\n${matched.notes}` : ''}`\n : input.item\n ? `\\n## Matched Cost\\nNo exact cost match found for \"${input.item}\". See the full cost table below.`\n : ''\n\n const full = [\n `# Credits`,\n `**Balance:** ${balance ?? 'unknown'} credits`,\n matchedSection,\n costs.length ? `\\n## Cost Table\\n| Item | Credits | Unit |\\n|------|---------|------|\\n${costRows}` : '',\n ledger.length ? `\\n## Recent Ledger\\n| Date | Operation | Credits | Description |\\n|------|-----------|---------|-------------|\\n${ledgerRows}` : '',\n ].filter(Boolean).join('\\n')\n\n return {\n ...oneBlock(full),\n structuredContent: {\n balanceCredits: typeof balance === 'number' ? balance : null,\n matchedCost: matched\n ? { label: matched.label, credits: matched.credits, unit: matched.unit, notes: matched.notes ?? null }\n : null,\n costs: costs.map(c => ({\n key: c.key,\n label: c.label,\n credits: c.credits,\n unit: c.unit,\n notes: c.notes ?? null,\n })),\n ledger: ledger.map(row => ({\n createdAt: String(row.created_at ?? ''),\n operation: String(row.operation ?? ''),\n credits: row.amount_mc / 1000,\n description: row.description ?? null,\n })),\n },\n }\n}\n\nexport function formatMapsSearch(\n raw: CallToolResult,\n input: { query: string; location?: string; maxResults?: number },\n): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data as Record<string, unknown>\n const results = (d.results as MapsSearchBusiness[]) ?? []\n const normalizedResults = results.map(result => ({\n ...result,\n phone: result.phone ?? null,\n hoursStatus: result.hoursStatus ?? null,\n }))\n const searchQuery = (d.searchQuery as string | undefined) ?? [input.query, input.location].filter(Boolean).join(' ')\n const requestedMax = (d.requestedMaxResults as number | undefined) ?? input.maxResults ?? 10\n const durationMs = d.durationMs as number | undefined\n\n const rows = results.map((r) => {\n const rating = [r.rating, r.reviewCount ? `(${r.reviewCount})` : null].filter(Boolean).join(' ')\n return `| ${r.position} | ${cell(r.name)} | ${cell(r.category)} | ${cell(rating)} | ${cell(r.address)} | ${r.cidDecimal ? `\\`${r.cidDecimal}\\`` : '—'} | ${r.websiteUrl ? `[site](${r.websiteUrl})` : '—'} | [maps](${r.placeUrl}) |`\n }).join('\\n')\n\n const metadataSection = results.length\n ? `\\n## Candidate Metadata\\n${results.map(r => {\n const meta = r.metadata?.length ? r.metadata.slice(0, 8).map(m => ` - ${m}`).join('\\n') : ' - none'\n return `### ${r.position}. ${r.name}\\n${meta}`\n }).join('\\n\\n')}`\n : ''\n\n const full = [\n `# Google Maps Search: \"${searchQuery}\"`,\n `**Returned:** ${results.length} profile candidate${results.length === 1 ? '' : 's'} · **Requested max:** ${requestedMax} · **Limit:** 50`,\n `\\n## Results\\n| # | Name | Category | Rating | Address | CID | Website | Maps |\\n|---|------|----------|--------|---------|-----|---------|------|\\n${rows}`,\n metadataSection,\n `\\n---\\n💡 **Next step:** use \\`maps_place_intel\\` with a selected business name and location to hydrate full hours, phone, review topics, and optional review cards.`,\n durationMs != null ? `\\n*Extracted in ${(durationMs / 1000).toFixed(1)}s*` : null,\n ].filter(Boolean).join('\\n')\n\n return {\n ...oneBlock(full),\n structuredContent: {\n query: d.query,\n location: d.location ?? null,\n searchQuery: d.searchQuery,\n searchUrl: d.searchUrl,\n extractedAt: d.extractedAt,\n requestedMaxResults: requestedMax,\n resultCount: results.length,\n results: normalizedResults,\n durationMs: durationMs ?? 0,\n },\n }\n}\n\nexport function formatDirectoryWorkflow(\n raw: CallToolResult,\n input: { query: string; state?: string; minPopulation?: number; maxResultsPerCity?: number },\n): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data as Record<string, unknown>\n const cities = ((d.cities as DirectoryWorkflowCity[]) ?? []).map(city => ({\n ...city,\n results: city.results.map(result => ({\n ...result,\n phone: result.phone ?? null,\n hoursStatus: result.hoursStatus ?? null,\n })),\n }))\n const warnings = (d.warnings as string[] | undefined) ?? []\n const csvPath = (d.csvPath as string | null | undefined) ?? null\n const totalResultCount = (d.totalResultCount as number | undefined) ?? cities.reduce((sum, city) => sum + city.resultCount, 0)\n const durationMs = d.durationMs as number | undefined\n\n const marketRows = cities.map((city) => {\n const zips = city.zips?.length ? city.zips.slice(0, 8).join(' ') + (city.zips.length > 8 ? ` +${city.zips.length - 8}` : '') : '—'\n return `| ${cell(city.city)} | ${city.population.toLocaleString()} | ${city.zips?.length ?? 0} | ${city.resultCount} | ${city.status} | ${cell(zips)} |`\n }).join('\\n')\n\n const businessRows = cities\n .flatMap(city => city.results.slice(0, 3).map(result => ({ city, result })))\n .map(({ city, result }) => {\n const rating = [result.rating, result.reviewCount ? `(${result.reviewCount})` : null].filter(Boolean).join(' ')\n return `| ${cell(city.city)} | ${result.position} | ${cell(result.name)} | ${cell(result.category)} | ${cell(rating)} | ${result.websiteUrl ? `[site](${result.websiteUrl})` : '—'} | [maps](${result.placeUrl}) |`\n }).join('\\n')\n\n const warningText = warnings.length ? `\\n## Warnings\\n${warnings.map(w => `- ${w}`).join('\\n')}` : ''\n const csvText = csvPath ? `\\n**CSV:** \\`${csvPath}\\`` : ''\n const full = [\n `# Directory Workflow: ${input.query}`,\n `**Markets:** ${cities.length} · **Maps results:** ${totalResultCount} · **State:** ${d.state ?? input.state ?? 'US'} · **Population threshold:** ${d.minPopulation ?? input.minPopulation ?? 100000}`,\n csvText,\n `\\n## Markets\\n| City | Population | ZIPs | Maps Results | Status | ZIP Sample |\\n|---|---:|---:|---:|---|---|\\n${marketRows}`,\n businessRows ? `\\n## Top Candidates By City\\n| City | # | Name | Category | Rating | Website | Maps |\\n|---|---:|---|---|---|---|---|\\n${businessRows}` : null,\n warningText,\n `\\n## Sources\\n- Population: ${d.censusSourceUrl ?? 'Census Population Estimates Program'}\\n- ZIP groups: ${d.usZipsSourcePath ?? 'not configured'}`,\n durationMs != null ? `\\n*Completed in ${(durationMs / 1000).toFixed(1)}s*` : null,\n ].filter(Boolean).join('\\n')\n\n return {\n ...oneBlock(full),\n structuredContent: {\n query: d.query,\n state: d.state,\n minPopulation: d.minPopulation,\n populationYear: d.populationYear,\n maxResultsPerCity: d.maxResultsPerCity,\n concurrency: d.concurrency,\n censusSourceUrl: d.censusSourceUrl,\n usZipsSourcePath: d.usZipsSourcePath ?? null,\n warnings,\n extractedAt: d.extractedAt,\n selectedCityCount: d.selectedCityCount,\n totalResultCount,\n csvPath,\n cities,\n durationMs: durationMs ?? 0,\n },\n }\n}\n\nexport function formatMapsPlaceIntel(\n raw: CallToolResult,\n input: { businessName: string; location: string; includeReviews?: boolean },\n): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data as Record<string, unknown>\n\n const name = (d.name as string | null) ?? input.businessName\n const rating = d.rating as string | null\n const reviewCount = d.reviewCount as string | null\n const category = d.category as string | null\n const address = d.address as string | null\n const phone = d.phoneDisplay as string | null\n const website = d.website as string | null\n const hoursSummary = d.hoursSummary as string | null\n const plusCode = d.plusCode as string | null\n const bookingUrl = d.bookingUrl as string | null\n const kgmid = d.kgmid as string | null\n const cidDecimal = d.cidDecimal as string | null\n const cidUrl = d.cidUrl as string | null\n const lat = d.lat as number | null\n const lng = d.lng as number | null\n const durationMs = d.durationMs as number | null\n\n const histogram = (d.reviewHistogram as MapsHistogramEntry[]) ?? []\n const topics = (d.reviewTopics as MapsTopicEntry[]) ?? []\n const about = (d.aboutAttributes as MapsAboutEntry[]) ?? []\n const reviews = (d.reviews as MapsReviewCard[]) ?? []\n const reviewsStatus = (d.reviewsStatus as ReviewsStatus | undefined) ?? 'not_requested'\n\n const hoursTable = (d.hoursTable as Array<{ day: string; hours: string }>) ?? []\n\n const ratingLine = [rating, reviewCount ? `(${reviewCount} reviews)` : null].filter(Boolean).join(' ')\n\n const basicLines = [\n address ? `- **Address:** ${address}` : null,\n phone ? `- **Phone:** ${phone}` : null,\n website ? `- **Website:** ${website}` : null,\n hoursSummary ? `- **Hours:** ${hoursSummary}` : null,\n plusCode ? `- **Plus Code:** ${plusCode}` : null,\n bookingUrl ? `- **Book:** ${bookingUrl}` : null,\n ].filter(Boolean).join('\\n')\n\n const hoursSection = hoursTable.length\n ? `\\n## Hours\\n| Day | Hours |\\n|-----|-------|\\n${hoursTable.map(r => `| ${r.day} | ${r.hours} |`).join('\\n')}`\n : ''\n\n const histSection = histogram.length\n ? `\\n## Rating Distribution\\n| Stars | Count |\\n|-------|-------|\\n${histogram.map(r => `| ${'★'.repeat(r.stars)}${'☆'.repeat(5 - r.stars)} | ${r.count} |`).join('\\n')}`\n : ''\n\n const topicsSection = topics.length\n ? `\\n## Review Topics\\n${topics.map(t => `- **${t.label}:** ${t.count} mentions`).join('\\n')}`\n : ''\n\n const aboutBySection: Record<string, string[]> = {}\n for (const a of about) {\n if (!aboutBySection[a.section]) aboutBySection[a.section] = []\n aboutBySection[a.section].push(a.attribute)\n }\n const aboutSection = Object.keys(aboutBySection).length\n ? `\\n## About\\n${Object.entries(aboutBySection).map(([s, attrs]) => `**${s}**\\n${attrs.map(a => `- ${a}`).join('\\n')}`).join('\\n\\n')}`\n : ''\n\n const entitySection = [\n kgmid ? `- **KGMID:** \\`${kgmid}\\`` : null,\n cidDecimal ? `- **CID:** \\`${cidDecimal}\\`` : null,\n cidUrl ? `- **Maps CID URL:** ${cidUrl}` : null,\n lat != null && lng != null ? `- **Coordinates:** ${lat}, ${lng}` : null,\n ].filter(Boolean).join('\\n')\n\n const reviewsSection = (() => {\n if (reviewsStatus === 'not_requested') return ''\n if (reviewsStatus === 'unavailable') return '\\n## Reviews\\n> Reviews could not be retrieved this run — retry with `includeReviews: true`.'\n if (reviewsStatus === 'none_exist') return '\\n## Reviews\\n*This business has no reviews on Google Maps.*'\n if (reviews.length === 0) return '\\n## Reviews\\n*0 reviews collected.*'\n return `\\n## Reviews (${reviews.length})\\n${reviews.map((r, i) => {\n const starsN = parseInt(r.stars ?? '0')\n const stars = '★'.repeat(starsN) + '☆'.repeat(5 - starsN)\n return `### ${i + 1}. ${r.author ?? 'Anonymous'} — ${stars}\\n*${r.date ?? ''}*\\n\\n${r.text ?? ''}`\n }).join('\\n\\n')}`\n })()\n\n const full = [\n `# ${name}`,\n category ? `*${category}*` : null,\n ratingLine ? `\\n**Rating:** ${ratingLine}` : null,\n basicLines ? `\\n${basicLines}` : null,\n hoursSection,\n histSection,\n topicsSection,\n aboutSection,\n entitySection ? `\\n## Entity IDs\\n${entitySection}` : null,\n reviewsSection,\n durationMs != null ? `\\n---\\n*Extracted in ${(durationMs / 1000).toFixed(1)}s*` : null,\n ].filter(Boolean).join('\\n')\n\n return {\n ...oneBlock(full),\n structuredContent: {\n name,\n rating: rating ?? null,\n reviewCount: reviewCount ?? null,\n category: category ?? null,\n address: address ?? null,\n phone: phone ?? null,\n website: website ?? null,\n hoursSummary: hoursSummary ?? null,\n bookingUrl: bookingUrl ?? null,\n kgmid: kgmid ?? null,\n cidDecimal: cidDecimal ?? null,\n cidUrl: cidUrl ?? null,\n lat: lat ?? null,\n lng: lng ?? null,\n reviewsStatus,\n reviewsCollected: reviews.length,\n reviewTopics: topics.map(t => ({ label: String(t.label ?? ''), count: String(t.count ?? '') })),\n },\n }\n}\n\nexport function formatFacebookAdTranscribe(raw: CallToolResult, input: { videoUrl: string }): CallToolResult {\n const parsed = parseData(raw)\n if ('error' in parsed) return { content: [{ type: 'text', text: parsed.error }], isError: true }\n const d = parsed.data as unknown as TranscriptResult\n\n const text = d.text ?? ''\n const chunks = d.chunks ?? []\n const durSec = d.durationMs ? (d.durationMs / 1000).toFixed(0) : '—'\n\n const chunkRows = chunks.slice(0, 50).map(c => {\n const sec = Number.isFinite(c.timestamp[0]) ? Math.floor(c.timestamp[0]) : 0\n const mm = String(Math.floor(sec / 60)).padStart(2, '0')\n const ss = String(sec % 60).padStart(2, '0')\n return `| ${mm}:${ss} | ${cell(truncate(c.text, 120))} |`\n }).join('\\n')\n\n const full = [\n `# Facebook Ad Transcript`,\n `**Duration:** ${durSec}s · **${text.split(' ').length} words**`,\n `\\n## Full Transcript\\n${text}`,\n chunks.length ? `\\n## Timestamped Chunks\\n| Time | Text |\\n|------|------|\\n${chunkRows}` : '',\n `\\n---\\n💡 Get more ads from this advertiser: use \\`facebook_page_intel\\``,\n ].filter(Boolean).join('\\n')\n\n return oneBlock(full)\n}\n","import { z } from 'zod'\n\nexport const HarvestPaaInputSchema = {\n query: z.string().min(1).describe('Core search topic only. If the user says \"best hvac company in Denver CO\", use query=\"best hvac company\" and location=\"Denver, CO\". Do not include the location in query when it can be separated.'),\n location: z.string().optional().describe('City, region, or country for geo-targeted results, inferred from the user request when present, e.g. \"Denver, CO\", \"Tokyo, Japan\", \"London, UK\".'),\n maxQuestions: z.number().int().min(1).max(200).default(30).describe('Number of PAA questions to extract. Default 30. Maximum 200. Use 10 for quick probes, 30 for normal research, 100-200 when the user asks for everything/full/deep research. Larger harvests get a longer server time budget (151-200 questions → up to 280s). Credits are charged by extracted question; unused request hold is refunded.'),\n gl: z.string().length(2).default('us').describe('Google country code inferred from location or user language. Examples: United States us, United Kingdom gb, Japan jp, Canada ca, Australia au.'),\n hl: z.string().default('en').describe('Google interface/content language inferred from the user request. Use en unless the user asks for another language or locale.'),\n device: z.enum(['desktop', 'mobile']).default('desktop').describe('SERP device context. Use desktop by default; use mobile only when the user asks for mobile rankings.'),\n proxyMode: z.enum(['location', 'configured', 'none']).default('location').describe('Proxy targeting mode. Use location by default for US city/state SERPs; it creates a fresh residential proxy ID per attempt and retries CAPTCHA, proxy tunnel failure, and wrong-location evidence before returning. Use configured only for the static configured proxy. Use none only for direct-network debugging.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting. Use when the user gives a specific ZIP or when city-center targeting needs to be forced. With proxyMode location this ZIP is used for each fresh proxy attempt.'),\n debug: z.boolean().default(false).describe('Include sanitized browser/session/location diagnostics in the response. Use true when debugging localization, CAPTCHA, or proxy behavior.'),\n}\nexport type HarvestPaaInput = z.infer<ReturnType<typeof z.object<typeof HarvestPaaInputSchema>>>\n\nexport const ExtractUrlInputSchema = {\n url: z.string().url().describe('Public http/https URL to extract. Use this when the user provides one specific page URL.'),\n screenshot: z.boolean().default(false).describe('Also capture a full-page screenshot of the URL. Saved to ~/Downloads/mcp-scraper/screenshots/ and returned inline. Use when the user asks to see or capture the page visually.'),\n screenshotDevice: z.enum(['desktop', 'mobile']).default('desktop').describe('Viewport for screenshot. desktop = 1440×900. mobile = 390×844. Default desktop.'),\n extractBranding: z.boolean().default(false).describe('Extract brand colors, fonts, logo, and favicon using a rendered browser session. Returns colorScheme (light/dark), colors (primary/accent/background/text/heading as hex), fonts (heading/body family names), and assets (logo URL, favicon URL). Use when the user asks about brand colors, site theme, or brand assets.'),\n downloadMedia: z.boolean().default(false).describe('Extract and download all page media (images, video, audio) to ~/Downloads/mcp-scraper/media/. Ad networks, tracking pixels, and noise URLs are filtered automatically. Use when the user asks to download or harvest assets from a page.'),\n mediaTypes: z.array(z.enum(['image', 'video', 'audio'])).default(['image', 'video', 'audio']).describe('Which media types to download. Default all three.'),\n allowLocal: z.boolean().default(false).describe('Allow localhost and private-network URLs. For local development only.'),\n}\nexport type ExtractUrlInput = z.infer<ReturnType<typeof z.object<typeof ExtractUrlInputSchema>>>\n\nexport const MapSiteUrlsInputSchema = {\n url: z.string().url().describe('Public website URL or domain to crawl for internal URLs. Use before extract_site when the user asks to audit/map/crawl a site.'),\n maxUrls: z.number().int().min(1).max(500).optional().describe('Maximum URLs to discover. Use 100 for normal maps, higher when the user asks for a full inventory.'),\n}\nexport type MapSiteUrlsInput = z.infer<ReturnType<typeof z.object<typeof MapSiteUrlsInputSchema>>>\n\nexport const ExtractSiteInputSchema = {\n url: z.string().url().describe('Public website URL or domain to extract across multiple pages. Use when the user asks for a site audit, website crawl, or full-site content/schema extraction.'),\n maxPages: z.number().int().min(1).max(50).optional().describe('Maximum pages to extract. Use 50 when the user asks for full results or a complete crawl within MCP limits.'),\n}\nexport type ExtractSiteInput = z.infer<ReturnType<typeof z.object<typeof ExtractSiteInputSchema>>>\n\nexport const YoutubeHarvestInputSchema = {\n mode: z.enum(['search', 'channel']).describe('Use search for topic/keyword requests. Use channel when the user provides @handle, channel ID, or channel URL.'),\n query: z.string().optional().describe('Required when mode is search. The YouTube search topic in the user’s words.'),\n channelHandle: z.string().optional().describe('YouTube channel handle, channel ID, or URL. Examples: @mkbhd, UC..., https://youtube.com/@mkbhd.'),\n maxVideos: z.number().int().min(1).max(500).default(50).describe('Number of videos to return. Default 50. Increase when user asks for full channel/history.'),\n}\nexport type YoutubeHarvestInput = z.infer<ReturnType<typeof z.object<typeof YoutubeHarvestInputSchema>>>\n\nexport const YoutubeTranscribeInputSchema = {\n videoId: z.string().min(1).describe('YouTube video ID, e.g. dQw4w9WgXcQ'),\n}\nexport type YoutubeTranscribeInput = z.infer<ReturnType<typeof z.object<typeof YoutubeTranscribeInputSchema>>>\n\nexport const FacebookPageIntelInputSchema = {\n pageId: z.string().optional(),\n libraryId: z.string().optional(),\n query: z.string().optional().describe('Advertiser or brand name when pageId/libraryId is not known. One of pageId, libraryId, or query is required.'),\n maxAds: z.number().int().min(1).max(200).default(50),\n country: z.string().length(2).default('US'),\n}\nexport type FacebookPageIntelInput = z.infer<ReturnType<typeof z.object<typeof FacebookPageIntelInputSchema>>>\n\nexport const FacebookAdSearchInputSchema = {\n query: z.string().min(1).describe('Advertiser, brand, competitor, niche, or keyword to search in Facebook Ad Library.'),\n country: z.string().length(2).default('US'),\n maxResults: z.number().int().min(1).max(20).default(10),\n}\nexport type FacebookAdSearchInput = z.infer<ReturnType<typeof z.object<typeof FacebookAdSearchInputSchema>>>\n\nexport const FacebookAdTranscribeInputSchema = {\n videoUrl: z.string().url().describe('Facebook CDN video URL from a facebook_page_intel result'),\n}\nexport type FacebookAdTranscribeInput = z.infer<ReturnType<typeof z.object<typeof FacebookAdTranscribeInputSchema>>>\n\nexport const MapsPlaceIntelInputSchema = {\n businessName: z.string().min(1).describe('Business name only. If user says \"Elite Roofing Denver CO\", use businessName=\"Elite Roofing\" and location=\"Denver, CO\".'),\n location: z.string().min(1).describe('City/region/country where the business should be searched, e.g. \"Denver, CO\". Infer from the user request when possible.'),\n gl: z.string().length(2).default('us').describe('Google country code inferred from location.'),\n hl: z.string().length(2).default('en').describe('Language inferred from user request.'),\n includeReviews: z.boolean().default(false).describe('Whether to fetch individual review cards'),\n maxReviews: z.number().int().min(1).max(500).default(50).describe('Max review cards to return (requires includeReviews: true)'),\n}\nexport type MapsPlaceIntelInput = z.infer<ReturnType<typeof z.object<typeof MapsPlaceIntelInputSchema>>>\n\nexport const MapsSearchInputSchema = {\n query: z.string().min(1).describe('Business category, niche, keyword, or search term. If the user says \"roofers in Denver CO\", use query=\"roofers\" and location=\"Denver, CO\". Do not put the location here when it can be separated.'),\n location: z.string().optional().describe('City, region, country, or service area for the Maps search, e.g. \"Denver, CO\". Infer from the user request when present.'),\n gl: z.string().length(2).default('us').describe('Google country code inferred from location.'),\n hl: z.string().length(2).default('en').describe('Language inferred from user request.'),\n maxResults: z.number().int().min(1).max(50).default(10).describe('Number of Google Maps business/profile candidates to return. Default 10. Maximum 50. Use 10 unless the user asks for more.'),\n proxyMode: z.enum(['location', 'configured', 'none']).default('location').describe('Proxy targeting mode. Use location by default for US city/state Maps searches; it creates a fresh residential proxy ID when the browser service is available. Use configured for the server proxy ID, and none only for local direct-network debugging.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting. Use when the user gives a specific ZIP or city-center ZIP.'),\n debug: z.boolean().default(false).describe('Include sanitized browser/proxy diagnostics when debugging Maps localization, CAPTCHA, or proxy behavior.'),\n}\nexport type MapsSearchInput = z.infer<ReturnType<typeof z.object<typeof MapsSearchInputSchema>>>\n\nexport const DirectoryWorkflowInputSchema = {\n query: z.string().min(1).describe('Business category, niche, or keyword to search on Google Maps for every selected market, e.g. roofers, dentists, med spas. Do not include the city here.'),\n state: z.string().min(2).default('TN').describe('US state abbreviation or state name used to select Census places, e.g. TN or Tennessee.'),\n minPopulation: z.number().int().min(0).default(100000).describe('Minimum Census place population for market selection. Use 100000 for \"cities above 100k population\".'),\n populationYear: z.number().int().min(2020).max(2025).default(2025).describe('Census population estimate year from the 2020-2025 Population Estimates Program city/place dataset.'),\n maxCities: z.number().int().min(1).max(100).default(25).describe('Maximum number of markets to process after sorting by population descending.'),\n maxResultsPerCity: z.number().int().min(1).max(50).default(50).describe('Google Maps business/profile candidates to collect for each city. Maximum 50.'),\n concurrency: z.number().int().min(1).max(5).default(5).describe('How many city Maps searches to run in parallel. Use 5 for broad directory batches unless debugging.'),\n includeZipGroups: z.boolean().default(true).describe('Attach ZIP groups from a configured US ZIPS CSV when available. Set MCP_SCRAPER_USZIPS_CSV_PATH on the API server or pass usZipsCsvPath in local/test mode.'),\n usZipsCsvPath: z.string().optional().describe('Local/test-only path to a US ZIPS CSV with state_abbr, zipcode, county, city columns, such as Lead Magician tools/analytics/data/uszips.csv. Deployed APIs should use MCP_SCRAPER_USZIPS_CSV_PATH instead.'),\n saveCsv: z.boolean().default(true).describe('Save a directory-ready CSV to the MCP Scraper output directory and return its path. CSV rows include source_location, result_position, business_name, review_stars, category, address, phone, hours_status, website_url, directions_url, place_url, CID fields, population, and ZIP groups.'),\n proxyMode: z.enum(['location', 'configured', 'none']).default('location').describe('Proxy targeting mode for every city Maps search. Use location by default for US city/state batches; it creates fresh residential proxy IDs when the browser service is available. Use configured for the server proxy ID, and none only for local direct-network debugging.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional ZIP override for proxy targeting. Normally omit it so each city can use its Lead Magician ZIP group or city/state location.'),\n debug: z.boolean().default(false).describe('Include sanitized browser/proxy diagnostics in each Maps browser session when supported.'),\n}\nexport type DirectoryWorkflowInput = z.infer<ReturnType<typeof z.object<typeof DirectoryWorkflowInputSchema>>>\n\nexport const RankTrackerModeSchema = z.enum(['maps', 'organic', 'ai_overview', 'paa'])\nexport type RankTrackerMode = z.infer<typeof RankTrackerModeSchema>\n\nexport const RankTrackerBlueprintInputSchema = {\n projectName: z.string().min(1).optional().describe('Optional name for the rank tracker project, client, or campaign.'),\n targetDomain: z.string().min(1).optional().describe('Primary domain to track in organic results, AI Overview citations, and PAA sources, e.g. example.com.'),\n targetBusinessName: z.string().min(1).optional().describe('Primary Google Business Profile or brand/business name to match in Maps results. Required for reliable Maps rank tracking.'),\n trackingModes: z.array(RankTrackerModeSchema).min(1).max(4).default(['maps', 'organic', 'ai_overview', 'paa']).describe('Rank tracker surfaces to build. maps uses directory_workflow/maps_search. organic uses search_serp. ai_overview uses search_serp/harvest_paa. paa uses harvest_paa source presence.'),\n keywords: z.array(z.string().min(1)).max(200).default([]).describe('Seed keywords or service queries to track. Leave empty when the downstream AI should create the keyword table from user input.'),\n locations: z.array(z.string().min(1)).max(100).default([]).describe('Markets, cities, ZIPs, or service areas to track. Use city/state strings like Denver, CO for localized SERP and Maps checks.'),\n competitors: z.array(z.string().min(1)).max(100).default([]).describe('Optional competitor domains or business names to persist as comparison targets.'),\n database: z.enum(['postgres', 'neon', 'supabase', 'sqlite', 'mysql']).default('postgres').describe('Database family the downstream AI should target when generating migrations.'),\n scheduleCadence: z.enum(['daily', 'weekly', 'monthly', 'custom']).default('weekly').describe('Default recurring rank check cadence for the generated cron/heartbeat plan.'),\n customCron: z.string().min(1).optional().describe('Cron expression to use when scheduleCadence is custom.'),\n timezone: z.string().min(1).default('UTC').describe('IANA timezone for scheduled rank checks, e.g. America/Denver.'),\n includeCron: z.boolean().default(true).describe('Include a cron or heartbeat worker plan. Keep true for production rank trackers.'),\n includeDashboard: z.boolean().default(true).describe('Include dashboard/reporting requirements in the generated prompt.'),\n includeAlerts: z.boolean().default(true).describe('Include alert rules for rank movement and SERP feature gains/losses.'),\n notes: z.string().max(4000).optional().describe('Extra product, client, stack, or hosting requirements to include in the implementation prompt.'),\n}\nexport type RankTrackerBlueprintInput = z.infer<ReturnType<typeof z.object<typeof RankTrackerBlueprintInputSchema>>>\n\nconst NullableString = z.string().nullable()\n\nexport const MapsSearchOutputSchema = {\n query: z.string(),\n location: z.string().nullable(),\n searchQuery: z.string(),\n searchUrl: z.string().url(),\n extractedAt: z.string(),\n requestedMaxResults: z.number().int().min(1).max(50),\n resultCount: z.number().int().min(0).max(50),\n results: z.array(z.object({\n position: z.number().int().min(1),\n name: z.string(),\n placeUrl: z.string().url(),\n cid: NullableString,\n cidDecimal: NullableString,\n rating: NullableString,\n reviewCount: NullableString,\n category: NullableString,\n address: NullableString,\n phone: NullableString,\n hoursStatus: NullableString,\n websiteUrl: NullableString,\n directionsUrl: NullableString,\n metadata: z.array(z.string()),\n })),\n durationMs: z.number().int().min(0),\n}\n\nconst DirectoryMapsBusinessOutput = z.object({\n position: z.number().int().min(1),\n name: z.string(),\n placeUrl: z.string().url(),\n cid: NullableString,\n cidDecimal: NullableString,\n rating: NullableString,\n reviewCount: NullableString,\n category: NullableString,\n address: NullableString,\n phone: NullableString,\n hoursStatus: NullableString,\n websiteUrl: NullableString,\n directionsUrl: NullableString,\n metadata: z.array(z.string()),\n})\n\nexport const DirectoryWorkflowOutputSchema = {\n query: z.string(),\n state: z.string(),\n minPopulation: z.number().int().min(0),\n populationYear: z.number().int().min(2020).max(2025),\n maxResultsPerCity: z.number().int().min(1).max(50),\n concurrency: z.number().int().min(1).max(5),\n censusSourceUrl: z.string().url(),\n usZipsSourcePath: NullableString,\n warnings: z.array(z.string()),\n extractedAt: z.string(),\n selectedCityCount: z.number().int().min(0),\n totalResultCount: z.number().int().min(0),\n csvPath: NullableString,\n cities: z.array(z.object({\n city: z.string(),\n state: z.string(),\n location: z.string(),\n cityKey: z.string(),\n censusName: z.string(),\n population: z.number().int().min(0),\n populationYear: z.number().int().min(2020).max(2025),\n zips: z.array(z.string()),\n counties: z.array(z.string()),\n status: z.enum(['ok', 'empty', 'failed']),\n error: NullableString,\n resultCount: z.number().int().min(0),\n durationMs: z.number().int().min(0),\n results: z.array(DirectoryMapsBusinessOutput),\n })),\n durationMs: z.number().int().min(0),\n}\n\nconst RankTrackerToolPlanOutput = z.object({\n tool: z.string(),\n purpose: z.string(),\n})\n\nconst RankTrackerTableOutput = z.object({\n name: z.string(),\n purpose: z.string(),\n keyColumns: z.array(z.string()),\n})\n\nconst RankTrackerCronJobOutput = z.object({\n name: z.string(),\n purpose: z.string(),\n modes: z.array(RankTrackerModeSchema),\n recommendedTools: z.array(z.string()),\n})\n\nexport const RankTrackerBlueprintOutputSchema = {\n projectName: z.string(),\n targetDomain: NullableString,\n targetBusinessName: NullableString,\n trackingModes: z.array(RankTrackerModeSchema),\n database: z.string(),\n recommendedTools: z.array(RankTrackerToolPlanOutput),\n tables: z.array(RankTrackerTableOutput),\n cron: z.object({\n enabled: z.boolean(),\n cadence: z.string(),\n expression: z.string(),\n timezone: z.string(),\n jobs: z.array(RankTrackerCronJobOutput),\n }),\n metrics: z.array(z.string()),\n implementationPrompt: z.string(),\n}\n\nconst OrganicResultOutput = z.object({\n position: z.number().int(),\n title: z.string(),\n url: z.string(),\n domain: z.string(),\n snippet: NullableString,\n})\n\nconst AiOverviewOutput = z.object({\n detected: z.boolean(),\n text: NullableString,\n}).nullable()\n\nconst EntityIdsOutput = z.object({\n kgIds: z.array(z.string()),\n cids: z.array(z.string()),\n gcids: z.array(z.string()),\n}).nullable()\n\nexport const HarvestPaaOutputSchema = {\n query: z.string(),\n location: NullableString,\n questionCount: z.number().int().min(0),\n completionStatus: NullableString,\n questions: z.array(z.object({\n question: z.string(),\n answer: NullableString,\n sourceTitle: NullableString,\n sourceSite: NullableString,\n })),\n organicResults: z.array(OrganicResultOutput),\n aiOverview: AiOverviewOutput,\n entityIds: EntityIdsOutput,\n durationMs: z.number().min(0).nullable(),\n}\n\nexport const SearchSerpOutputSchema = {\n query: z.string(),\n location: NullableString,\n organicResults: z.array(OrganicResultOutput),\n localPack: z.array(z.object({\n position: z.number().int(),\n name: z.string(),\n rating: NullableString,\n reviewCount: NullableString,\n websiteUrl: NullableString,\n })),\n aiOverview: AiOverviewOutput,\n entityIds: EntityIdsOutput,\n}\n\nexport const ExtractUrlOutputSchema = {\n url: z.string(),\n title: NullableString,\n headings: z.array(z.object({\n level: z.number().int(),\n text: z.string(),\n })),\n schemaBlockCount: z.number().int().min(0),\n entityName: NullableString,\n entityTypes: z.array(z.string()),\n napScore: z.number().nullable(),\n missingSchemaFields: z.array(z.string()),\n screenshotSaved: NullableString,\n}\n\nexport const ExtractSiteOutputSchema = {\n url: z.string(),\n pageCount: z.number().int().min(0),\n pages: z.array(z.object({\n url: z.string(),\n title: NullableString,\n schemaTypes: z.array(z.string()),\n })),\n durationMs: z.number().min(0),\n}\n\nexport const MapsPlaceIntelOutputSchema = {\n name: z.string(),\n rating: NullableString,\n reviewCount: NullableString,\n category: NullableString,\n address: NullableString,\n phone: NullableString,\n website: NullableString,\n hoursSummary: NullableString,\n bookingUrl: NullableString,\n kgmid: NullableString,\n cidDecimal: NullableString,\n cidUrl: NullableString,\n lat: z.number().nullable(),\n lng: z.number().nullable(),\n reviewsStatus: z.string(),\n reviewsCollected: z.number().int().min(0),\n reviewTopics: z.array(z.object({\n label: z.string(),\n count: z.string(),\n })),\n}\n\nexport const CreditsInfoOutputSchema = {\n balanceCredits: z.number().nullable(),\n matchedCost: z.object({\n label: z.string(),\n credits: z.number(),\n unit: z.string(),\n notes: NullableString,\n }).nullable(),\n costs: z.array(z.object({\n key: z.string(),\n label: z.string(),\n credits: z.number(),\n unit: z.string(),\n notes: NullableString,\n })),\n ledger: z.array(z.object({\n createdAt: z.string(),\n operation: z.string(),\n credits: z.number(),\n description: NullableString,\n })),\n}\n\nexport const MapSiteUrlsOutputSchema = {\n startUrl: z.string(),\n totalFound: z.number().int().min(0),\n truncated: z.boolean(),\n okCount: z.number().int().min(0),\n redirectCount: z.number().int().min(0),\n brokenCount: z.number().int().min(0),\n urls: z.array(z.object({\n url: z.string(),\n status: z.number().int().nullable(),\n })),\n durationMs: z.number().min(0),\n}\n\nexport const YoutubeHarvestOutputSchema = {\n mode: z.string(),\n videoCount: z.number().int().min(0),\n channel: z.object({\n title: NullableString,\n subscriberCount: NullableString,\n }).nullable(),\n videos: z.array(z.object({\n videoId: z.string(),\n title: z.string(),\n channelName: NullableString,\n views: NullableString,\n duration: NullableString,\n url: NullableString,\n })),\n}\n\nexport const FacebookAdSearchOutputSchema = {\n query: z.string(),\n advertiserCount: z.number().int().min(0),\n advertisers: z.array(z.object({\n name: NullableString,\n adCount: z.number().int().nullable(),\n libraryId: NullableString,\n })),\n}\n\nexport const FacebookPageIntelOutputSchema = {\n advertiserName: NullableString,\n totalAds: z.number().int().min(0),\n activeCount: z.number().int().min(0),\n videoCount: z.number().int().min(0),\n imageCount: z.number().int().min(0),\n ads: z.array(z.object({\n libraryId: NullableString,\n status: NullableString,\n creativeType: NullableString,\n headline: NullableString,\n cta: NullableString,\n startDate: NullableString,\n videoUrl: NullableString,\n variations: z.number().int().nullable(),\n })),\n}\n\nexport const CreditsInfoInputSchema = {\n item: z.string().optional().describe('Optional tool, action, or feature to look up, e.g. \"maps reviews\", \"extract_url\", or \"YouTube transcription\"'),\n includeLedger: z.boolean().default(false).describe('Whether to include recent credit ledger entries'),\n}\nexport type CreditsInfoInput = z.infer<ReturnType<typeof z.object<typeof CreditsInfoInputSchema>>>\n\nexport const SearchSerpInputSchema = {\n query: z.string().min(1).describe('Core search topic only. Separate location when possible. If user says \"best dentist in Brooklyn NY serp\", use query=\"best dentist\" and location=\"Brooklyn, NY\".'),\n location: z.string().optional().describe('City, region, or country for geo-targeted results, inferred from user request when present.'),\n gl: z.string().length(2).default('us').describe('Google country code inferred from location or user language.'),\n hl: z.string().default('en').describe('Google interface/content language inferred from user request.'),\n device: z.enum(['desktop', 'mobile']).default('desktop').describe('SERP device context. Use desktop by default; use mobile only when the user asks for mobile rankings.'),\n proxyMode: z.enum(['location', 'configured', 'none']).default('location').describe('Proxy targeting mode. Use location by default for US city/state SERPs; it creates a fresh residential proxy ID per attempt and retries CAPTCHA, proxy tunnel failure, and wrong-location evidence before returning. Use configured only for the static configured proxy. Use none only for direct-network debugging.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting. Use when the user gives a specific ZIP or when city-center targeting needs to be forced. With proxyMode location this ZIP is used for each fresh proxy attempt.'),\n debug: z.boolean().default(false).describe('Include sanitized browser/session/location diagnostics in the response. Use true when debugging localization, CAPTCHA, or proxy behavior.'),\n pages: z.number().int().min(1).max(2).default(1).describe('Number of result pages to fetch (1–2)'),\n}\nexport type SearchSerpInput = z.infer<ReturnType<typeof z.object<typeof SearchSerpInputSchema>>>\n\nexport const CaptureSerpSnapshotInputSchema = {\n query: z.string().min(1).describe('Core search query to capture as a structured SERP Intelligence snapshot. Separate the place into location when the user gives a city, region, country, or ZIP.'),\n location: z.string().optional().describe('City, region, country, or service area used for localized Google results. MCP Scraper records location evidence; UULE alone is not proof of localization.'),\n gl: z.string().length(2).default('us').describe('Google country code inferred from the requested market, e.g. us, gb, ca, au.'),\n hl: z.string().default('en').describe('Google interface/content language inferred from the user request.'),\n device: z.enum(['desktop', 'mobile']).default('desktop').describe('SERP device context. Use mobile only when the user asks for mobile rankings or mobile SERP evidence.'),\n proxyMode: z.enum(['location', 'configured', 'none']).default('location').describe('Proxy behavior for capture. Use location for localized US residential evidence; it creates a fresh proxy ID per attempt and retries CAPTCHA, proxy tunnel failure, and wrong-location evidence before returning. Use configured only for the static residential proxy, and none only for direct-network debugging.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting when a precise city-center or ZIP proxy is needed. With proxyMode location this ZIP is used for each fresh proxy attempt.'),\n pages: z.number().int().min(1).max(2).default(1).describe('Number of Google result pages to capture. Use 1 normally and 2 only when the user needs deeper ranking evidence.'),\n debug: z.boolean().default(false).describe('Include sanitized browser, proxy, and location diagnostics. Use true when debugging localization, CAPTCHA, proxy selection, or capture reliability.'),\n includePageSnapshots: z.boolean().default(false).describe('Also capture ranking-page snapshots for selected SERP URLs through the same product capture path.'),\n pageSnapshotLimit: z.number().int().min(0).max(10).default(0).describe('Maximum ranking-page snapshots to capture when includePageSnapshots is true. Use 0 when only SERP evidence is needed.'),\n}\nexport type CaptureSerpSnapshotInput = z.infer<ReturnType<typeof z.object<typeof CaptureSerpSnapshotInputSchema>>>\n\nexport const ScreenshotInputSchema = {\n url: z.string().url().describe('URL to capture as a full-page screenshot. Use http or https. Pass allowLocal: true to capture localhost or private-network URLs during development.'),\n device: z.enum(['desktop', 'mobile']).default('desktop').describe('Viewport profile. desktop = 1440×900. mobile = 390×844. Use desktop by default; use mobile when the user asks for a mobile view.'),\n allowLocal: z.boolean().default(false).describe('Allow localhost and private-network URLs (127.x, 192.168.x, 10.x, etc.). For local development only — not for production use.'),\n}\nexport type ScreenshotInput = z.infer<ReturnType<typeof z.object<typeof ScreenshotInputSchema>>>\n\nexport const CaptureSerpPageSnapshotsInputSchema = {\n urls: z.array(z.string().url()).min(1).max(25).describe('Public HTTP/HTTPS URLs to capture as SERP Intelligence page snapshots. Do not pass localhost, private IPs, file URLs, or internal admin URLs.'),\n targets: z.array(z.object({\n url: z.string().url().describe('Public HTTP/HTTPS URL to capture.'),\n sourceKind: z.enum(['organic', 'ai_citation', 'local_pack_website', 'configured_target', 'site_subject']).default('configured_target').describe('Why this page is being captured for SERP Intelligence evidence.'),\n sourcePosition: z.number().int().min(1).optional().describe('Ranking or citation position when the page came from SERP evidence.'),\n }).strict()).min(1).max(25).optional().describe('Structured page snapshot targets. Use this instead of urls when source kind or position should be preserved.'),\n maxConcurrency: z.number().int().min(1).max(5).default(2).describe('Parallel page captures. Use 2 normally; higher values can increase proxy/browser pressure.'),\n timeoutMs: z.number().int().min(1_000).max(60_000).default(15_000).describe('Per-page capture timeout in milliseconds. Increase for slow pages; timeout artifacts are returned as structured capture failures.'),\n debug: z.boolean().default(false).describe('Include sanitized browser/proxy diagnostics for page snapshot debugging. Use true for capture, network, or proxy troubleshooting.'),\n}\nexport type CaptureSerpPageSnapshotsInput = z.infer<ReturnType<typeof z.object<typeof CaptureSerpPageSnapshotsInputSchema>>>\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { RankTrackerBlueprintInput, RankTrackerMode } from './mcp-tool-schemas.js'\n\ntype ToolPlan = {\n tool: string\n purpose: string\n}\n\ntype TablePlan = {\n name: string\n purpose: string\n keyColumns: string[]\n}\n\ntype CronJobPlan = {\n name: string\n purpose: string\n modes: RankTrackerMode[]\n recommendedTools: string[]\n}\n\ntype RankTrackerBlueprint = {\n projectName: string\n targetDomain: string | null\n targetBusinessName: string | null\n trackingModes: RankTrackerMode[]\n database: string\n recommendedTools: ToolPlan[]\n tables: TablePlan[]\n cron: {\n enabled: boolean\n cadence: string\n expression: string\n timezone: string\n jobs: CronJobPlan[]\n }\n metrics: string[]\n implementationPrompt: string\n}\n\nconst DEFAULT_MODES: RankTrackerMode[] = ['maps', 'organic', 'ai_overview', 'paa']\n\nfunction normalizeDomain(value?: string): string | null {\n const trimmed = value?.trim()\n if (!trimmed) return null\n try {\n const url = new URL(trimmed.includes('://') ? trimmed : `https://${trimmed}`)\n return url.hostname.replace(/^www\\./, '').toLowerCase()\n } catch {\n return trimmed.replace(/^https?:\\/\\//, '').replace(/^www\\./, '').split('/')[0]?.toLowerCase() || trimmed\n }\n}\n\nfunction uniqueModes(input?: RankTrackerMode[]): RankTrackerMode[] {\n const modes = input?.length ? input : DEFAULT_MODES\n return [...new Set(modes)]\n}\n\nfunction cronExpression(cadence: RankTrackerBlueprintInput['scheduleCadence'], customCron?: string): string {\n if (cadence === 'daily') return '15 6 * * *'\n if (cadence === 'monthly') return '15 6 1 * *'\n if (cadence === 'custom') return customCron?.trim() || 'CUSTOM_CRON_EXPRESSION_REQUIRED'\n return '15 6 * * 1'\n}\n\nfunction includes(modes: RankTrackerMode[], mode: RankTrackerMode): boolean {\n return modes.includes(mode)\n}\n\nfunction buildToolPlan(modes: RankTrackerMode[]): ToolPlan[] {\n const plans: ToolPlan[] = []\n const push = (tool: string, purpose: string) => {\n if (!plans.some((plan) => plan.tool === tool)) plans.push({ tool, purpose })\n }\n\n push('credits_info', 'Check account balance and rates before scheduling recurring rank checks.')\n\n if (includes(modes, 'maps')) {\n push('directory_workflow', 'Seed or refresh city-by-city Maps datasets when building local market coverage.')\n push('maps_search', 'Run recurring Google Maps category checks for each keyword and location.')\n push('maps_place_intel', 'Hydrate selected target or competitor GBP details when profile-level evidence is needed.')\n }\n if (includes(modes, 'organic')) {\n push('search_serp', 'Capture localized organic rankings, local pack data, and AI Overview status without PAA expansion.')\n }\n if (includes(modes, 'ai_overview')) {\n push('search_serp', 'Capture quick AI Overview detection and organic context for each tracked query.')\n push('harvest_paa', 'Use when AI Overview text, PAA context, or source-level evidence needs deeper capture.')\n }\n if (includes(modes, 'paa')) {\n push('harvest_paa', 'Capture People Also Ask questions, answers, and source sites for PAA presence tracking.')\n }\n\n return plans\n}\n\nfunction buildTables(modes: RankTrackerMode[], includeDashboard: boolean, includeAlerts: boolean, hasCompetitors: boolean): TablePlan[] {\n const tables: TablePlan[] = [\n {\n name: 'rank_tracker_projects',\n purpose: 'One row per client, campaign, or tracked property.',\n keyColumns: ['id', 'name', 'target_domain', 'target_business_name', 'database_mode', 'timezone', 'created_at'],\n },\n {\n name: 'rank_tracker_targets',\n purpose: 'Normalized target identities and match rules for domains, URLs, business names, CIDs, and competitors.',\n keyColumns: ['id', 'project_id', 'kind', 'value', 'display_name', 'match_rules_json', 'active'],\n },\n {\n name: 'rank_tracker_keywords',\n purpose: 'Tracked keywords or service queries, separated from location so calls can localize correctly.',\n keyColumns: ['id', 'project_id', 'keyword', 'intent', 'tags_json', 'active'],\n },\n {\n name: 'rank_tracker_locations',\n purpose: 'Markets, cities, ZIPs, country/language settings, and proxy targeting hints.',\n keyColumns: ['id', 'project_id', 'label', 'gl', 'hl', 'proxy_zip', 'device', 'active'],\n },\n {\n name: 'rank_tracker_runs',\n purpose: 'Heartbeat table for every scheduled or manual rank check batch.',\n keyColumns: ['id', 'project_id', 'scheduled_for', 'started_at', 'completed_at', 'status', 'idempotency_key', 'error_message'],\n },\n ]\n\n if (includes(modes, 'organic')) {\n tables.push({\n name: 'rank_tracker_organic_results',\n purpose: 'SERP organic result rows from search_serp, including target-domain matches and competitor rows.',\n keyColumns: ['id', 'run_id', 'keyword_id', 'location_id', 'device', 'position', 'title', 'url', 'domain', 'is_target'],\n })\n }\n\n if (includes(modes, 'maps')) {\n tables.push({\n name: 'rank_tracker_maps_results',\n purpose: 'Google Maps result rows from maps_search and directory_workflow, including GBP identity fields.',\n keyColumns: ['id', 'run_id', 'keyword_id', 'location_id', 'position', 'business_name', 'place_url', 'cid', 'website_url', 'rating', 'review_count', 'is_target'],\n })\n tables.push({\n name: 'rank_tracker_market_seeds',\n purpose: 'Directory workflow city, population, ZIP-group, and market seed records used to build local tracking coverage.',\n keyColumns: ['id', 'project_id', 'query', 'city', 'state', 'population', 'zip_group_json', 'last_seeded_run_id'],\n })\n }\n\n if (includes(modes, 'ai_overview')) {\n tables.push({\n name: 'rank_tracker_ai_overviews',\n purpose: 'AI Overview detection, text snapshot, citation domains, and target citation status per query/location.',\n keyColumns: ['id', 'run_id', 'keyword_id', 'location_id', 'detected', 'target_cited', 'cited_domains_json', 'overview_text'],\n })\n }\n\n if (includes(modes, 'paa')) {\n tables.push({\n name: 'rank_tracker_paa_sources',\n purpose: 'People Also Ask questions, answers, and source sites, with target source presence flags.',\n keyColumns: ['id', 'run_id', 'keyword_id', 'location_id', 'question', 'answer', 'source_title', 'source_site', 'target_present'],\n })\n }\n\n if (hasCompetitors) {\n tables.push({\n name: 'rank_tracker_competitor_snapshots',\n purpose: 'Per-run competitor visibility summaries across organic, Maps, AI Overview, and PAA surfaces.',\n keyColumns: ['id', 'run_id', 'target_id', 'surface', 'best_position', 'presence_count', 'share_of_surface'],\n })\n }\n\n if (includeDashboard) {\n tables.push({\n name: 'rank_tracker_daily_metrics',\n purpose: 'Rollup table for dashboard charts, trend lines, and share-of-visibility summaries.',\n keyColumns: ['id', 'project_id', 'metric_date', 'keyword_id', 'location_id', 'surface', 'metric_name', 'metric_value'],\n })\n }\n\n if (includeAlerts) {\n tables.push({\n name: 'rank_tracker_alert_events',\n purpose: 'Deduplicated gain/loss events for rank movement, Maps top 3, AI Overview citations, and PAA source presence.',\n keyColumns: ['id', 'project_id', 'run_id', 'surface', 'severity', 'event_key', 'message', 'created_at', 'acknowledged_at'],\n })\n }\n\n return tables\n}\n\nfunction buildCronJobs(modes: RankTrackerMode[], includeDashboard: boolean, includeAlerts: boolean): CronJobPlan[] {\n const jobs: CronJobPlan[] = [\n {\n name: 'rank-tracker-dispatch',\n purpose: 'Find due keyword/location/mode combinations, create a rank_tracker_runs row, and enqueue idempotent work items.',\n modes,\n recommendedTools: ['credits_info'],\n },\n ]\n\n if (includes(modes, 'maps')) {\n jobs.push({\n name: 'maps-rank-check',\n purpose: 'Run maps_search per keyword/location and optionally directory_workflow for market seed refreshes.',\n modes: ['maps'],\n recommendedTools: ['maps_search', 'directory_workflow', 'maps_place_intel'],\n })\n }\n\n if (includes(modes, 'organic') || includes(modes, 'ai_overview')) {\n jobs.push({\n name: 'serp-rank-check',\n purpose: 'Run search_serp per keyword/location/device and persist organic ranks, local pack, and AI Overview status.',\n modes: modes.filter((mode) => mode === 'organic' || mode === 'ai_overview'),\n recommendedTools: ['search_serp'],\n })\n }\n\n if (includes(modes, 'paa') || includes(modes, 'ai_overview')) {\n jobs.push({\n name: 'paa-ai-evidence-check',\n purpose: 'Run harvest_paa for PAA source presence and deeper AI Overview/PAA evidence where needed.',\n modes: modes.filter((mode) => mode === 'paa' || mode === 'ai_overview'),\n recommendedTools: ['harvest_paa'],\n })\n }\n\n if (includeDashboard) {\n jobs.push({\n name: 'rank-tracker-rollups',\n purpose: 'Aggregate raw rows into daily metrics for charts, comparison tables, and trend lines.',\n modes,\n recommendedTools: [],\n })\n }\n\n if (includeAlerts) {\n jobs.push({\n name: 'rank-tracker-alerts',\n purpose: 'Compare latest run against prior snapshots and emit deduplicated visibility gain/loss events.',\n modes,\n recommendedTools: [],\n })\n }\n\n return jobs\n}\n\nfunction buildMetrics(modes: RankTrackerMode[], includeDashboard: boolean, includeAlerts: boolean): string[] {\n const metrics: string[] = ['run_success_rate', 'last_successful_run_at', 'stale_keyword_location_count']\n\n if (includes(modes, 'maps')) {\n metrics.push('maps_best_position', 'maps_top_3_presence', 'maps_target_found', 'maps_competitor_count_above_target')\n }\n if (includes(modes, 'organic')) {\n metrics.push('organic_best_position', 'organic_top_3_presence', 'organic_top_10_presence', 'organic_best_url')\n }\n if (includes(modes, 'ai_overview')) {\n metrics.push('ai_overview_detected', 'target_ai_overview_cited', 'ai_overview_citation_domain_count')\n }\n if (includes(modes, 'paa')) {\n metrics.push('paa_question_count', 'target_paa_source_count', 'paa_presence_rate', 'paa_source_domains')\n }\n if (includeDashboard) metrics.push('share_of_visibility', 'position_delta_7d', 'position_delta_30d')\n if (includeAlerts) metrics.push('visibility_gain_events', 'visibility_loss_events')\n\n return metrics\n}\n\nfunction listOrPlaceholder(values: string[] | undefined, fallback: string): string {\n const clean = values?.map((value) => value.trim()).filter(Boolean) ?? []\n if (!clean.length) return fallback\n return clean.map((value) => `- ${value}`).join('\\n')\n}\n\nfunction buildPrompt(\n input: RankTrackerBlueprintInput,\n modes: RankTrackerMode[],\n tools: ToolPlan[],\n tables: TablePlan[],\n jobs: CronJobPlan[],\n metrics: string[],\n expression: string,\n targetDomain: string | null,\n targetBusinessName: string | null,\n): string {\n const keywords = listOrPlaceholder(input.keywords, '- TODO: add tracked keywords')\n const locations = listOrPlaceholder(input.locations, '- TODO: add tracked markets/locations')\n const competitors = listOrPlaceholder(input.competitors, '- Optional: add competitor domains or GBP names')\n const notes = input.notes?.trim() || 'No extra implementation notes.'\n\n return [\n 'You are building a production rank tracker powered by MCP Scraper. Create the database migrations, scheduled worker, ingestion functions, and dashboard/query layer described below.',\n '',\n `Project: ${input.projectName || 'MCP Scraper Rank Tracker'}`,\n `Target domain: ${targetDomain || 'TODO_TARGET_DOMAIN'}`,\n `Target business/GBP name: ${targetBusinessName || 'TODO_TARGET_BUSINESS_NAME'}`,\n `Database target: ${input.database || 'postgres'}`,\n `Tracking modes: ${modes.join(', ')}`,\n '',\n 'Seed keywords:',\n keywords,\n '',\n 'Seed locations:',\n locations,\n '',\n 'Competitors:',\n competitors,\n '',\n 'MCP Scraper calls to use:',\n tools.map((tool) => `- ${tool.tool}: ${tool.purpose}`).join('\\n'),\n '',\n 'Database tables to create:',\n tables.map((table) => `- ${table.name}: ${table.keyColumns.join(', ')}`).join('\\n'),\n '',\n 'Scheduler and heartbeat requirements:',\n `- Use cron expression \"${expression}\" in timezone \"${input.timezone || 'UTC'}\" unless the user changes cadence.`,\n '- Every scheduled batch must insert or update rank_tracker_runs before calling MCP tools.',\n '- Use idempotency_key = project_id + keyword_id + location_id + mode + device + scheduled_date.',\n '- Mark runs as running, succeeded, failed, or skipped; persist error_message on failures.',\n '- Run MCP calls sequentially by default because accounts have one concurrency slot unless the user bought more.',\n '- Retry retryable upstream failures with backoff, but do not duplicate rows for the same idempotency key.',\n '',\n 'Mode-specific ingestion rules:',\n '- maps: Use directory_workflow to seed/refresh market coverage and maps_search for recurring keyword/location rank checks. Match the target by targetBusinessName, website domain, CID, and place URL when available.',\n '- organic: Use search_serp and persist every organic result row. Compute the best targetDomain position and best ranking URL per keyword/location/device.',\n '- ai_overview: Use search_serp for quick detection and harvest_paa when deeper text/source evidence is needed. Track detected, overview_text, cited domains, and whether targetDomain is cited.',\n '- paa: Use harvest_paa and persist each question/source pair. Track whether sourceSite or answer/source evidence matches targetDomain, then compute PAA presence rate.',\n '',\n 'Metrics to expose:',\n metrics.map((metric) => `- ${metric}`).join('\\n'),\n '',\n 'Alert requirements:',\n input.includeAlerts\n ? '- Emit deduplicated alert_events when target gains/loses Maps top 3, organic top 10, AI Overview citation, or PAA source presence.'\n : '- Alerts are out of scope for this build unless the user asks for them.',\n '',\n 'Dashboard requirements:',\n input.includeDashboard\n ? '- Build views for latest position by keyword/location, trend deltas, competitors above target, AI Overview citations, and PAA source wins/losses.'\n : '- Dashboard is out of scope for this build unless the user asks for it.',\n '',\n 'Extra notes:',\n notes,\n ].join('\\n')\n}\n\nexport function buildRankTrackerBlueprint(input: RankTrackerBlueprintInput): CallToolResult {\n const trackingModes = uniqueModes(input.trackingModes)\n const targetDomain = normalizeDomain(input.targetDomain)\n const targetBusinessName = input.targetBusinessName?.trim() || null\n const projectName = input.projectName?.trim() || 'MCP Scraper Rank Tracker'\n const database = input.database || 'postgres'\n const expression = cronExpression(input.scheduleCadence || 'weekly', input.customCron)\n const tools = buildToolPlan(trackingModes)\n const tables = buildTables(trackingModes, input.includeDashboard !== false, input.includeAlerts !== false, Boolean(input.competitors?.length))\n const jobs = input.includeCron === false ? [] : buildCronJobs(trackingModes, input.includeDashboard !== false, input.includeAlerts !== false)\n const metrics = buildMetrics(trackingModes, input.includeDashboard !== false, input.includeAlerts !== false)\n const implementationPrompt = buildPrompt(input, trackingModes, tools, tables, jobs, metrics, expression, targetDomain, targetBusinessName)\n\n const blueprint: RankTrackerBlueprint = {\n projectName,\n targetDomain,\n targetBusinessName,\n trackingModes,\n database,\n recommendedTools: tools,\n tables,\n cron: {\n enabled: input.includeCron !== false,\n cadence: input.scheduleCadence || 'weekly',\n expression: input.includeCron === false ? 'disabled' : expression,\n timezone: input.timezone || 'UTC',\n jobs,\n },\n metrics,\n implementationPrompt,\n }\n\n const text = [\n `# ${projectName}`,\n '',\n 'Rank tracker build blueprint generated from MCP Scraper tool capabilities.',\n '',\n '## Modes',\n trackingModes.map((mode) => `- ${mode}`).join('\\n'),\n '',\n '## Recommended MCP Tools',\n tools.map((tool) => `- \\`${tool.tool}\\` - ${tool.purpose}`).join('\\n'),\n '',\n '## Database Tables',\n tables.map((table) => `- \\`${table.name}\\` - ${table.purpose}`).join('\\n'),\n '',\n '## Cron / Heartbeat',\n blueprint.cron.enabled\n ? `- Cadence: ${blueprint.cron.cadence}\\n- Cron: \\`${blueprint.cron.expression}\\`\\n- Timezone: ${blueprint.cron.timezone}\\n- Jobs: ${jobs.map((job) => job.name).join(', ')}`\n : '- Disabled by input. Still create rank_tracker_runs for manual runs.',\n '',\n '## Implementation Prompt',\n '```text',\n implementationPrompt,\n '```',\n ].join('\\n')\n\n return {\n content: [{ type: 'text', text }],\n structuredContent: blueprint,\n }\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { IMcpToolExecutor, ISerpIntelligenceToolExecutor } from './IMcpToolExecutor.js'\nimport { harvestTimeoutBudget } from '../harvest-timeout.js'\nimport type {\n HarvestPaaInput,\n SearchSerpInput,\n ExtractUrlInput,\n MapSiteUrlsInput,\n ExtractSiteInput,\n YoutubeHarvestInput,\n YoutubeTranscribeInput,\n FacebookPageIntelInput,\n FacebookAdSearchInput,\n FacebookAdTranscribeInput,\n MapsPlaceIntelInput,\n MapsSearchInput,\n DirectoryWorkflowInput,\n CreditsInfoInput,\n CaptureSerpSnapshotInput,\n CaptureSerpPageSnapshotsInput,\n} from './mcp-tool-schemas.js'\n\nexport class HttpMcpToolExecutor implements IMcpToolExecutor, ISerpIntelligenceToolExecutor {\n private readonly baseUrl: string\n private readonly apiKey: string\n private readonly timeoutMs: number\n private readonly httpTimeoutOverrideMs: number | null\n private readonly serpIntelligenceTimeoutMs: number\n\n constructor(baseUrl: string, apiKey: string) {\n this.baseUrl = baseUrl.replace(/\\/$/, '')\n this.apiKey = apiKey\n const rawOverride = process.env.MCP_SCRAPER_HTTP_TIMEOUT_MS\n const parsedOverride = rawOverride === undefined ? NaN : Number(rawOverride)\n this.httpTimeoutOverrideMs = Number.isFinite(parsedOverride) && parsedOverride > 0 ? parsedOverride : null\n this.timeoutMs = this.httpTimeoutOverrideMs ?? 110_000\n const configuredSerpIntelligenceTimeoutMs = Number(process.env.MCP_SCRAPER_SERP_INTELLIGENCE_HTTP_TIMEOUT_MS ?? this.timeoutMs)\n this.serpIntelligenceTimeoutMs = Number.isFinite(configuredSerpIntelligenceTimeoutMs) && configuredSerpIntelligenceTimeoutMs > 0\n ? configuredSerpIntelligenceTimeoutMs\n : this.timeoutMs\n }\n\n private async call(path: string, body: Record<string, unknown>, timeoutMs = this.timeoutMs): Promise<CallToolResult> {\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey,\n },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(timeoutMs),\n })\n const data = await res.json()\n if (!res.ok) {\n return { content: [{ type: 'text', text: JSON.stringify(data) }], isError: true }\n }\n return { content: [{ type: 'text', text: JSON.stringify(data) }] }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (err instanceof DOMException && err.name === 'TimeoutError') {\n return {\n content: [{\n type: 'text',\n text: JSON.stringify({\n error: 'mcp_request_timeout',\n error_type: 'timeout',\n retryable: true,\n path,\n timeoutMs,\n message: `MCP Scraper request exceeded ${Math.round(timeoutMs / 1000)}s and was cancelled. Retry with fewer results or use the async API for deep harvests.`,\n }),\n }],\n isError: true,\n }\n }\n return { content: [{ type: 'text', text: msg }], isError: true }\n }\n }\n\n harvestPaa(input: HarvestPaaInput): Promise<CallToolResult> {\n const timeoutMs = this.httpTimeoutOverrideMs ?? harvestTimeoutBudget(input.maxQuestions ?? 30).clientMs\n return this.call('/harvest/sync', input as Record<string, unknown>, timeoutMs)\n }\n\n searchSerp(input: SearchSerpInput): Promise<CallToolResult> {\n const timeoutMs = this.httpTimeoutOverrideMs ?? harvestTimeoutBudget(0, true).clientMs\n return this.call('/harvest/sync', { ...input, serpOnly: true } as Record<string, unknown>, timeoutMs)\n }\n\n extractUrl(input: ExtractUrlInput): Promise<CallToolResult> {\n return this.call('/extract-url', input as Record<string, unknown>)\n }\n\n mapSiteUrls(input: MapSiteUrlsInput): Promise<CallToolResult> {\n return this.call('/map-urls', input as Record<string, unknown>)\n }\n\n extractSite(input: ExtractSiteInput): Promise<CallToolResult> {\n return this.call('/extract-site', input as Record<string, unknown>)\n }\n\n youtubeHarvest(input: YoutubeHarvestInput): Promise<CallToolResult> {\n return this.call('/youtube/harvest', input as Record<string, unknown>)\n }\n\n youtubeTranscribe(input: YoutubeTranscribeInput): Promise<CallToolResult> {\n return this.call('/youtube/transcribe', input as Record<string, unknown>)\n }\n\n facebookPageIntel(input: FacebookPageIntelInput): Promise<CallToolResult> {\n return this.call('/facebook/page-intel', input as Record<string, unknown>)\n }\n\n facebookAdSearch(input: FacebookAdSearchInput): Promise<CallToolResult> {\n return this.call('/facebook/search', input as Record<string, unknown>)\n }\n\n facebookAdTranscribe(input: FacebookAdTranscribeInput): Promise<CallToolResult> {\n return this.call('/facebook/transcribe', input as Record<string, unknown>)\n }\n\n mapsPlaceIntel(input: MapsPlaceIntelInput): Promise<CallToolResult> {\n return this.call('/maps/place', input as Record<string, unknown>)\n }\n\n mapsSearch(input: MapsSearchInput): Promise<CallToolResult> {\n return this.call('/maps/search', input as Record<string, unknown>)\n }\n\n directoryWorkflow(input: DirectoryWorkflowInput): Promise<CallToolResult> {\n const cityCount = typeof input.maxCities === 'number' ? input.maxCities : 25\n const concurrency = typeof input.concurrency === 'number' && input.concurrency > 0 ? input.concurrency : 5\n const timeoutMs = this.httpTimeoutOverrideMs ?? Math.min(900_000, Math.max(180_000, Math.ceil(cityCount / concurrency) * 120_000))\n return this.call('/directory/run', input as Record<string, unknown>, timeoutMs)\n }\n\n creditsInfo(input: CreditsInfoInput): Promise<CallToolResult> {\n return this.call('/billing/credits', input as Record<string, unknown>)\n }\n\n captureSerpSnapshot(input: CaptureSerpSnapshotInput): Promise<CallToolResult> {\n return this.call('/serp-intelligence/capture', input as Record<string, unknown>, this.serpIntelligenceTimeoutMs)\n }\n\n captureSerpPageSnapshots(input: CaptureSerpPageSnapshotsInput): Promise<CallToolResult> {\n return this.call('/serp-intelligence/page-snapshots', input as Record<string, unknown>, this.serpIntelligenceTimeoutMs)\n }\n\n}\n"],"mappings":"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","names":["join","join"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api/db.ts"],"sourcesContent":["import { createClient, type Client } from '@libsql/client/http'\nimport { createHash, randomBytes, randomUUID, scryptSync, timingSafeEqual } from 'node:crypto'\nimport { z } from 'zod'\n\nconst DB_URL = process.env.TURSO_DATABASE_URL ?? 'file:./paa-api.db'\nconst DB_TOKEN = process.env.TURSO_AUTH_TOKEN\n\nlet _db: Client | null = null\nlet _rateLimitSchemaReady = false\n\nexport function getDb(): Client {\n if (!_db) _db = createClient({ url: DB_URL, authToken: DB_TOKEN })\n return _db\n}\n\nexport async function migrate(): Promise<void> {\n const db = getDb()\n await db.execute(`\n CREATE TABLE IF NOT EXISTS users (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n email TEXT UNIQUE NOT NULL,\n name TEXT,\n api_key TEXT UNIQUE NOT NULL,\n password_hash TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n active INTEGER NOT NULL DEFAULT 1\n )\n `)\n await db.execute(`\n CREATE TABLE IF NOT EXISTS jobs (\n id TEXT PRIMARY KEY,\n user_id INTEGER NOT NULL REFERENCES users(id),\n status TEXT NOT NULL DEFAULT 'pending',\n query TEXT NOT NULL,\n options TEXT NOT NULL,\n callback_url TEXT,\n result TEXT,\n error TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n started_at TEXT,\n completed_at TEXT\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS jobs_user_id ON jobs(user_id)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS jobs_status ON jobs(status)`)\n await db.execute(`\n CREATE TABLE IF NOT EXISTS harvest_attempts (\n id TEXT PRIMARY KEY,\n job_id TEXT NOT NULL REFERENCES jobs(id),\n user_id INTEGER NOT NULL REFERENCES users(id),\n attempt_number INTEGER NOT NULL,\n max_attempts INTEGER NOT NULL,\n query TEXT NOT NULL,\n location TEXT,\n max_questions INTEGER NOT NULL,\n status TEXT NOT NULL,\n outcome TEXT,\n kernel_session_id TEXT,\n question_count INTEGER,\n duration_ms INTEGER,\n error TEXT,\n will_retry INTEGER,\n kernel_delete_started INTEGER NOT NULL DEFAULT 0,\n kernel_delete_succeeded INTEGER,\n kernel_delete_error TEXT,\n browser_close_succeeded INTEGER,\n browser_close_error TEXT,\n debug_json TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n completed_at TEXT,\n UNIQUE(job_id, attempt_number)\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS harvest_attempts_job_id ON harvest_attempts(job_id)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS harvest_attempts_user_created_at ON harvest_attempts(user_id, created_at DESC)`)\n try { await db.execute(`ALTER TABLE harvest_attempts ADD COLUMN debug_json TEXT`) } catch {}\n try { await db.execute(`ALTER TABLE users ADD COLUMN password_hash TEXT`) } catch {}\n try { await db.execute(`ALTER TABLE users ADD COLUMN key_active INTEGER NOT NULL DEFAULT 1`) } catch {}\n\n await db.execute(`\n CREATE TABLE IF NOT EXISTS kpo_jobs (\n id TEXT PRIMARY KEY,\n user_id INTEGER NOT NULL REFERENCES users(id),\n status TEXT NOT NULL,\n entity_name TEXT NOT NULL,\n entity_type TEXT NOT NULL,\n url TEXT,\n request TEXT NOT NULL,\n result TEXT,\n error TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`\n CREATE TABLE IF NOT EXISTS kpo_phase_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n job_id TEXT NOT NULL REFERENCES kpo_jobs(id),\n phase TEXT NOT NULL,\n output TEXT NOT NULL,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS kpo_jobs_user_id ON kpo_jobs(user_id)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS kpo_jobs_status ON kpo_jobs(status)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS kpo_phase_log_job_id ON kpo_phase_log(job_id)`)\n try { await db.execute(`ALTER TABLE users ADD COLUMN stripe_customer_id TEXT`) } catch {}\n try { await db.execute(`ALTER TABLE users ADD COLUMN balance_mc INTEGER NOT NULL DEFAULT 0`) } catch {}\n try { await db.execute(`ALTER TABLE users ADD COLUMN extra_concurrency_slots INTEGER NOT NULL DEFAULT 0`) } catch {}\n try { await db.execute(`ALTER TABLE users ADD COLUMN concurrency_stripe_sub_id TEXT`) } catch {}\n await db.execute(`\n CREATE TABLE IF NOT EXISTS ledger (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n user_id INTEGER NOT NULL REFERENCES users(id),\n amount_mc INTEGER NOT NULL,\n operation TEXT NOT NULL,\n description TEXT,\n stripe_pi TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS ledger_user_id ON ledger(user_id)`)\n await db.execute(`\n CREATE TABLE IF NOT EXISTS free_credit_refreshes (\n user_id INTEGER NOT NULL REFERENCES users(id),\n month TEXT NOT NULL,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (user_id, month)\n )\n `)\n await db.execute(`\n CREATE TABLE IF NOT EXISTS site_audit_jobs (\n id TEXT PRIMARY KEY,\n user_id INTEGER,\n status TEXT DEFAULT 'pending',\n client_domain TEXT,\n session_path TEXT,\n request TEXT,\n result TEXT,\n error TEXT,\n created_at TEXT DEFAULT (datetime('now')),\n updated_at TEXT DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`\n CREATE TABLE IF NOT EXISTS site_audit_phase_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n job_id TEXT REFERENCES site_audit_jobs(id),\n phase TEXT,\n completed_at TEXT DEFAULT (datetime('now')),\n output_summary TEXT\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS site_audit_jobs_user_id ON site_audit_jobs(user_id)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS site_audit_jobs_status ON site_audit_jobs(status)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS site_audit_phase_log_job_id ON site_audit_phase_log(job_id)`)\n await db.execute(`\n CREATE TABLE IF NOT EXISTS password_reset_tokens (\n token TEXT PRIMARY KEY,\n user_id INTEGER NOT NULL REFERENCES users(id),\n expires_at TEXT NOT NULL,\n used INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS prt_user_id ON password_reset_tokens(user_id)`)\n await db.execute(`\n CREATE TABLE IF NOT EXISTS rate_limits (\n scope TEXT NOT NULL,\n key_hash TEXT NOT NULL,\n window_start INTEGER NOT NULL,\n count INTEGER NOT NULL DEFAULT 0,\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (scope, key_hash, window_start)\n )\n `)\n await db.execute(`\n CREATE TABLE IF NOT EXISTS request_events (\n id TEXT PRIMARY KEY,\n user_id INTEGER NOT NULL REFERENCES users(id),\n source TEXT NOT NULL,\n status TEXT NOT NULL,\n query TEXT NOT NULL,\n location TEXT,\n result_count INTEGER,\n result TEXT,\n error TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS request_events_user_created_at ON request_events(user_id, created_at DESC)`)\n await db.execute(`\n CREATE TABLE IF NOT EXISTS stripe_events (\n event_id TEXT PRIMARY KEY,\n processed_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n}\n\nexport async function recordStripeEvent(eventId: string): Promise<boolean> {\n const res = await getDb().execute({\n sql: 'INSERT OR IGNORE INTO stripe_events (event_id) VALUES (?)',\n args: [eventId],\n })\n return res.rowsAffected > 0\n}\n\nexport async function stripeEventAlreadyProcessed(eventId: string): Promise<boolean> {\n const res = await getDb().execute({\n sql: 'SELECT 1 FROM stripe_events WHERE event_id = ? LIMIT 1',\n args: [eventId],\n })\n return res.rows.length > 0\n}\n\nexport function generateApiKey(): string {\n return 'sk_' + randomBytes(24).toString('hex')\n}\n\nexport interface User {\n id: number\n email: string\n name: string | null\n api_key: string\n key_active: number\n password_hash: string | null\n created_at: string\n active: number\n stripe_customer_id: string | null\n balance_mc: number\n extra_concurrency_slots: number\n concurrency_stripe_sub_id: string | null\n}\n\nexport function hashPassword(password: string): string {\n const salt = randomBytes(16).toString('hex')\n const hash = scryptSync(password, salt, 64)\n return `${salt}:${hash.toString('hex')}`\n}\n\nexport function verifyPassword(password: string, stored: string): boolean {\n const [salt, hash] = stored.split(':')\n const hashBuf = Buffer.from(hash, 'hex')\n const derived = scryptSync(password, salt, 64)\n return timingSafeEqual(hashBuf, derived)\n}\n\nfunction rowToUser(row: Record<string, unknown>): User {\n return {\n id: Number(row.id),\n email: String(row.email),\n name: row.name != null ? String(row.name) : null,\n api_key: String(row.api_key),\n key_active: Number(row.key_active ?? 1),\n password_hash: row.password_hash != null ? String(row.password_hash) : null,\n created_at: String(row.created_at),\n active: Number(row.active),\n stripe_customer_id: row.stripe_customer_id != null ? String(row.stripe_customer_id) : null,\n balance_mc: Number(row.balance_mc ?? 0),\n extra_concurrency_slots: Number(row.extra_concurrency_slots ?? 0),\n concurrency_stripe_sub_id: row.concurrency_stripe_sub_id != null ? String(row.concurrency_stripe_sub_id) : null,\n }\n}\n\nexport async function getUserByEmail(email: string): Promise<User | undefined> {\n const res = await getDb().execute({ sql: 'SELECT * FROM users WHERE email = ? AND active = 1', args: [email] })\n return res.rows[0] ? rowToUser(res.rows[0] as unknown as Record<string, unknown>) : undefined\n}\n\nexport async function getUserByApiKey(api_key: string): Promise<User | undefined> {\n const res = await getDb().execute({ sql: 'SELECT * FROM users WHERE api_key = ? AND active = 1 AND key_active = 1', args: [api_key] })\n return res.rows[0] ? rowToUser(res.rows[0] as unknown as Record<string, unknown>) : undefined\n}\n\nexport async function getUserById(id: number | bigint): Promise<User | undefined> {\n const res = await getDb().execute({ sql: 'SELECT * FROM users WHERE id = ? AND active = 1', args: [id] })\n return res.rows[0] ? rowToUser(res.rows[0] as unknown as Record<string, unknown>) : undefined\n}\n\nexport async function setPassword(id: number | bigint, password: string): Promise<void> {\n await getDb().execute({ sql: 'UPDATE users SET password_hash = ? WHERE id = ?', args: [hashPassword(password), id] })\n}\n\nexport async function getUserStats(userId: number | bigint): Promise<{ total: number; done: number; failed: number; totalQuestions: number; lastUsed: string | null }> {\n const db = getDb()\n const [totR, doneR, failR, tqR, luR] = await Promise.all([\n db.execute({ sql: 'SELECT COUNT(*) as n FROM jobs WHERE user_id = ?', args: [userId] }),\n db.execute({ sql: \"SELECT COUNT(*) as n FROM jobs WHERE user_id = ? AND status = 'done'\", args: [userId] }),\n db.execute({ sql: \"SELECT COUNT(*) as n FROM jobs WHERE user_id = ? AND status = 'failed'\", args: [userId] }),\n db.execute({ sql: \"SELECT COALESCE(SUM(json_extract(result, '$.totalQuestions')), 0) as n FROM jobs WHERE user_id = ? AND status = 'done'\", args: [userId] }),\n db.execute({ sql: 'SELECT MAX(created_at) as t FROM jobs WHERE user_id = ?', args: [userId] }),\n ])\n return {\n total: Number(totR.rows[0]?.n ?? 0),\n done: Number(doneR.rows[0]?.n ?? 0),\n failed: Number(failR.rows[0]?.n ?? 0),\n totalQuestions: Number(tqR.rows[0]?.n ?? 0),\n lastUsed: luR.rows[0]?.t != null ? String(luR.rows[0].t) : null,\n }\n}\n\nexport async function createUser(email: string, name?: string, password?: string, stripeCustomerId?: string): Promise<{ id: number | bigint; email: string; name?: string; api_key: string; password?: string }> {\n const db = getDb()\n const api_key = generateApiKey()\n const plainPassword = password ?? randomBytes(6).toString('hex')\n const password_hash = hashPassword(plainPassword)\n const result = await db.execute({\n sql: 'INSERT INTO users (email, name, api_key, password_hash, stripe_customer_id) VALUES (?, ?, ?, ?, ?)',\n args: [email, name ?? null, api_key, password_hash, stripeCustomerId ?? null],\n })\n return { id: result.lastInsertRowid!, email, name, api_key, password: plainPassword }\n}\n\nexport async function checkRateLimit(\n scope: string,\n key: string,\n limit: number,\n windowSeconds: number,\n): Promise<{ allowed: boolean; count: number; remaining: number; resetSeconds: number }> {\n const nowSeconds = Math.floor(Date.now() / 1000)\n const windowStart = Math.floor(nowSeconds / windowSeconds) * windowSeconds\n const keyHash = createHash('sha256').update(key).digest('hex')\n const db = getDb()\n\n if (!_rateLimitSchemaReady) {\n await db.execute(`\n CREATE TABLE IF NOT EXISTS rate_limits (\n scope TEXT NOT NULL,\n key_hash TEXT NOT NULL,\n window_start INTEGER NOT NULL,\n count INTEGER NOT NULL DEFAULT 0,\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (scope, key_hash, window_start)\n )\n `)\n _rateLimitSchemaReady = true\n }\n\n await db.execute({\n sql: `\n INSERT INTO rate_limits (scope, key_hash, window_start, count)\n VALUES (?, ?, ?, 1)\n ON CONFLICT(scope, key_hash, window_start)\n DO UPDATE SET count = count + 1, updated_at = datetime('now')\n `,\n args: [scope, keyHash, windowStart],\n })\n\n const res = await db.execute({\n sql: 'SELECT count FROM rate_limits WHERE scope = ? AND key_hash = ? AND window_start = ?',\n args: [scope, keyHash, windowStart],\n })\n const count = Number(res.rows[0]?.count ?? 1)\n return {\n allowed: count <= limit,\n count,\n remaining: Math.max(0, limit - count),\n resetSeconds: Math.max(1, windowStart + windowSeconds - nowSeconds),\n }\n}\n\nexport async function createPasswordResetToken(userId: number | bigint): Promise<string> {\n const token = randomBytes(32).toString('hex')\n const tokenHash = createHash('sha256').update(token).digest('hex')\n const expiresAt = new Date(Date.now() + 60 * 60 * 1000).toISOString()\n await getDb().execute({\n sql: 'INSERT INTO password_reset_tokens (token, user_id, expires_at) VALUES (?, ?, ?)',\n args: [tokenHash, userId, expiresAt],\n })\n return token\n}\n\nexport async function consumePasswordResetToken(token: string): Promise<number | null> {\n const db = getDb()\n const tokenHash = createHash('sha256').update(token).digest('hex')\n const res = await db.execute({\n sql: \"SELECT user_id, expires_at, used FROM password_reset_tokens WHERE token = ?\",\n args: [tokenHash],\n })\n const row = res.rows[0]\n if (!row) return null\n if (Number(row.used)) return null\n if (new Date(String(row.expires_at)) < new Date()) return null\n await db.execute({ sql: 'UPDATE password_reset_tokens SET used = 1 WHERE token = ?', args: [tokenHash] })\n return Number(row.user_id)\n}\n\nexport async function rotateApiKey(userId: number | bigint): Promise<string> {\n const newKey = generateApiKey()\n await getDb().execute({ sql: 'UPDATE users SET api_key = ?, key_active = 1 WHERE id = ?', args: [newKey, userId] })\n return newKey\n}\n\nexport async function revokeApiKey(userId: number | bigint): Promise<void> {\n await getDb().execute({ sql: 'UPDATE users SET key_active = 0 WHERE id = ?', args: [userId] })\n}\n\nexport async function listUsers(): Promise<Omit<User, 'api_key'>[]> {\n const res = await getDb().execute('SELECT id, email, name, created_at, active FROM users ORDER BY created_at DESC')\n return res.rows.map(r => rowToUser({ ...r as unknown as Record<string, unknown>, api_key: '', key_active: 1 }))\n}\n\nexport async function deactivateUser(id: number): Promise<void> {\n await getDb().execute({ sql: 'UPDATE users SET active = 0 WHERE id = ?', args: [id] })\n}\n\ninterface RawJob {\n id: string\n user_id: number\n status: string\n query: string\n options: string\n callback_url: string | null\n result: string | null\n error: string | null\n created_at: string\n started_at: string | null\n completed_at: string | null\n}\n\nexport interface Job {\n id: string\n user_id: number\n status: string\n query: string\n options: Record<string, unknown>\n callback_url: string | null\n result: unknown | null\n error: string | null\n created_at: string\n started_at: string | null\n completed_at: string | null\n}\n\nexport interface HarvestAttemptLog {\n id: string\n job_id: string\n user_id: number\n attempt_number: number\n max_attempts: number\n query: string\n location: string | null\n max_questions: number\n status: string\n outcome: string | null\n kernel_session_id: string | null\n question_count: number | null\n duration_ms: number | null\n error: string | null\n will_retry: boolean | null\n kernel_delete_started: boolean\n kernel_delete_succeeded: boolean | null\n kernel_delete_error: string | null\n browser_close_succeeded: boolean | null\n browser_close_error: string | null\n debug: unknown | null\n created_at: string\n completed_at: string | null\n}\n\nexport interface StartHarvestAttemptInput {\n jobId: string\n userId: number | bigint\n attemptNumber: number\n maxAttempts: number\n query: string\n location: string | null\n maxQuestions: number\n startedAt: string\n}\n\nexport interface FinishHarvestAttemptInput {\n jobId: string\n attemptNumber: number\n outcome: string\n kernelSessionId: string | null\n questionCount: number\n durationMs: number\n error: string | null\n willRetry: boolean\n kernelDeleteStarted: boolean\n kernelDeleteSucceeded: boolean | null\n kernelDeleteError: string | null\n browserCloseSucceeded: boolean | null\n browserCloseError: string | null\n debug: unknown | null\n completedAt: string\n}\n\nfunction rowToRawJob(row: Record<string, unknown>): RawJob {\n return {\n id: String(row.id),\n user_id: Number(row.user_id),\n status: String(row.status),\n query: String(row.query),\n options: String(row.options),\n callback_url: row.callback_url != null ? String(row.callback_url) : null,\n result: row.result != null ? String(row.result) : null,\n error: row.error != null ? String(row.error) : null,\n created_at: String(row.created_at),\n started_at: row.started_at != null ? String(row.started_at) : null,\n completed_at: row.completed_at != null ? String(row.completed_at) : null,\n }\n}\n\nfunction nullableBoolean(value: unknown): boolean | null {\n return value == null ? null : Number(value) === 1\n}\n\nfunction parseNullableJson(value: unknown): unknown | null {\n if (value == null) return null\n try {\n return JSON.parse(String(value)) as unknown\n } catch {\n return null\n }\n}\n\nfunction rowToHarvestAttemptLog(row: Record<string, unknown>): HarvestAttemptLog {\n return {\n id: String(row.id),\n job_id: String(row.job_id),\n user_id: Number(row.user_id),\n attempt_number: Number(row.attempt_number),\n max_attempts: Number(row.max_attempts),\n query: String(row.query),\n location: row.location != null ? String(row.location) : null,\n max_questions: Number(row.max_questions),\n status: String(row.status),\n outcome: row.outcome != null ? String(row.outcome) : null,\n kernel_session_id: row.kernel_session_id != null ? String(row.kernel_session_id) : null,\n question_count: row.question_count != null ? Number(row.question_count) : null,\n duration_ms: row.duration_ms != null ? Number(row.duration_ms) : null,\n error: row.error != null ? String(row.error) : null,\n will_retry: nullableBoolean(row.will_retry),\n kernel_delete_started: Number(row.kernel_delete_started ?? 0) === 1,\n kernel_delete_succeeded: nullableBoolean(row.kernel_delete_succeeded),\n kernel_delete_error: row.kernel_delete_error != null ? String(row.kernel_delete_error) : null,\n browser_close_succeeded: nullableBoolean(row.browser_close_succeeded),\n browser_close_error: row.browser_close_error != null ? String(row.browser_close_error) : null,\n debug: parseNullableJson(row.debug_json),\n created_at: String(row.created_at),\n completed_at: row.completed_at != null ? String(row.completed_at) : null,\n }\n}\n\nfunction deserialize(raw: RawJob): Job {\n return {\n ...raw,\n options: JSON.parse(raw.options) as Record<string, unknown>,\n result: raw.result ? JSON.parse(raw.result) : null,\n }\n}\n\nexport async function createJob(userId: number | bigint, query: string, options: object, callbackUrl?: string): Promise<string> {\n const id = randomUUID()\n await getDb().execute({\n sql: 'INSERT INTO jobs (id, user_id, query, options, callback_url) VALUES (?, ?, ?, ?, ?)',\n args: [id, userId, query, JSON.stringify(options), callbackUrl ?? null],\n })\n return id\n}\n\nexport async function createRunningJob(userId: number | bigint, query: string, options: object): Promise<string> {\n const id = randomUUID()\n await getDb().execute({\n sql: `INSERT INTO jobs (id, user_id, query, options, status, started_at) VALUES (?, ?, ?, ?, 'running', datetime('now'))`,\n args: [id, userId, query, JSON.stringify(options)],\n })\n return id\n}\n\nexport async function startHarvestAttempt(input: StartHarvestAttemptInput): Promise<void> {\n await getDb().execute({\n sql: `\n INSERT INTO harvest_attempts (\n id, job_id, user_id, attempt_number, max_attempts, query, location, max_questions, status, created_at\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'running', ?)\n ON CONFLICT(job_id, attempt_number) DO UPDATE SET\n status = 'running',\n created_at = excluded.created_at,\n completed_at = NULL,\n outcome = NULL,\n error = NULL,\n debug_json = NULL\n `,\n args: [\n randomUUID(),\n input.jobId,\n input.userId,\n input.attemptNumber,\n input.maxAttempts,\n input.query,\n input.location,\n input.maxQuestions,\n input.startedAt,\n ],\n })\n}\n\nexport async function finishHarvestAttempt(input: FinishHarvestAttemptInput): Promise<void> {\n await getDb().execute({\n sql: `\n UPDATE harvest_attempts SET\n status = 'finished',\n outcome = ?,\n kernel_session_id = ?,\n question_count = ?,\n duration_ms = ?,\n error = ?,\n will_retry = ?,\n kernel_delete_started = ?,\n kernel_delete_succeeded = ?,\n kernel_delete_error = ?,\n browser_close_succeeded = ?,\n browser_close_error = ?,\n debug_json = ?,\n completed_at = ?\n WHERE job_id = ? AND attempt_number = ?\n `,\n args: [\n input.outcome,\n input.kernelSessionId,\n input.questionCount,\n input.durationMs,\n input.error,\n input.willRetry ? 1 : 0,\n input.kernelDeleteStarted ? 1 : 0,\n input.kernelDeleteSucceeded == null ? null : input.kernelDeleteSucceeded ? 1 : 0,\n input.kernelDeleteError,\n input.browserCloseSucceeded == null ? null : input.browserCloseSucceeded ? 1 : 0,\n input.browserCloseError,\n input.debug == null ? null : JSON.stringify(input.debug),\n input.completedAt,\n input.jobId,\n input.attemptNumber,\n ],\n })\n}\n\nexport async function listHarvestAttempts(jobId: string, userId?: number | bigint): Promise<HarvestAttemptLog[]> {\n const res = userId == null\n ? await getDb().execute({\n sql: `SELECT * FROM harvest_attempts WHERE job_id = ? ORDER BY attempt_number ASC`,\n args: [jobId],\n })\n : await getDb().execute({\n sql: `\n SELECT ha.*\n FROM harvest_attempts ha\n INNER JOIN jobs j ON j.id = ha.job_id\n WHERE ha.job_id = ? AND j.user_id = ?\n ORDER BY ha.attempt_number ASC\n `,\n args: [jobId, userId],\n })\n return res.rows.map(r => rowToHarvestAttemptLog(r as unknown as Record<string, unknown>))\n}\n\nexport async function getJob(id: string, userId?: number | bigint): Promise<Job | undefined> {\n const db = getDb()\n const res = userId\n ? await db.execute({ sql: 'SELECT * FROM jobs WHERE id = ? AND user_id = ?', args: [id, userId] })\n : await db.execute({ sql: 'SELECT * FROM jobs WHERE id = ?', args: [id] })\n return res.rows[0] ? deserialize(rowToRawJob(res.rows[0] as unknown as Record<string, unknown>)) : undefined\n}\n\nexport async function listJobs(userId: number | bigint): Promise<Job[]> {\n const res = await getDb().execute({ sql: 'SELECT * FROM jobs WHERE user_id = ? ORDER BY created_at DESC LIMIT 50', args: [userId] })\n return res.rows.map(r => deserialize(rowToRawJob(r as unknown as Record<string, unknown>)))\n}\n\nexport interface RequestEvent {\n id: string\n user_id: number\n source: string\n status: string\n query: string\n location: string | null\n result_count: number | null\n result: unknown | null\n error: string | null\n created_at: string\n}\n\nfunction rowToRequestEvent(row: Record<string, unknown>): RequestEvent {\n const rawResult = row.result != null ? String(row.result) : null\n return {\n id: String(row.id),\n user_id: Number(row.user_id),\n source: String(row.source),\n status: String(row.status),\n query: String(row.query),\n location: row.location != null ? String(row.location) : null,\n result_count: row.result_count != null ? Number(row.result_count) : null,\n result: rawResult ? JSON.parse(rawResult) : null,\n error: row.error != null ? String(row.error) : null,\n created_at: String(row.created_at),\n }\n}\n\nexport async function logRequestEvent(input: {\n userId: number | bigint\n source: string\n status: 'done' | 'failed'\n query: string\n location?: string | null\n resultCount?: number | null\n result?: unknown\n error?: string | null\n}): Promise<string> {\n const id = randomUUID()\n await getDb().execute({\n sql: `\n INSERT INTO request_events (id, user_id, source, status, query, location, result_count, result, error)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `,\n args: [\n id,\n input.userId,\n input.source,\n input.status,\n input.query,\n input.location ?? null,\n input.resultCount ?? null,\n input.result != null ? JSON.stringify(input.result) : null,\n input.error ?? null,\n ],\n })\n return id\n}\n\nexport async function listRequestEvents(userId: number | bigint, limit = 100): Promise<RequestEvent[]> {\n const res = await getDb().execute({\n sql: `\n SELECT id, user_id, source, status, query, location, result_count, result, error, created_at\n FROM request_events\n WHERE user_id = ?\n ORDER BY created_at DESC\n LIMIT ?\n `,\n args: [userId, limit],\n })\n return res.rows.map(r => rowToRequestEvent(r as unknown as Record<string, unknown>))\n}\n\nexport async function countActiveUsers(): Promise<number> {\n const res = await getDb().execute(`SELECT COUNT(*) as n FROM users WHERE active = 1`)\n return Number(res.rows[0]?.n ?? 0)\n}\n\nexport async function countActiveJobsForUser(userId: number | bigint): Promise<number> {\n const res = await getDb().execute({\n sql: `SELECT COUNT(*) as n FROM jobs WHERE user_id = ? AND (status = 'pending' OR (status = 'running' AND started_at > datetime('now', '-10 minutes')))`,\n args: [userId],\n })\n return Number(res.rows[0]?.n ?? 0)\n}\n\nexport async function claimPendingJob(): Promise<RawJob | undefined> {\n const db = getDb()\n const res = await db.execute(`SELECT * FROM jobs WHERE status = 'pending' ORDER BY created_at LIMIT 1`)\n const job = res.rows[0] ? rowToRawJob(res.rows[0] as unknown as Record<string, unknown>) : undefined\n if (!job) return undefined\n const upd = await db.execute({\n sql: `UPDATE jobs SET status = 'running', started_at = datetime('now') WHERE id = ? AND status = 'pending'`,\n args: [job.id],\n })\n return upd.rowsAffected === 0 ? undefined : { ...job, status: 'running' }\n}\n\nexport async function completeJob(id: string, result: object): Promise<void> {\n await getDb().execute({ sql: `UPDATE jobs SET status = 'done', result = ?, completed_at = datetime('now') WHERE id = ?`, args: [JSON.stringify(result), id] })\n}\n\nexport async function failJob(id: string, error: string): Promise<void> {\n await getDb().execute({ sql: `UPDATE jobs SET status = 'failed', error = ?, completed_at = datetime('now') WHERE id = ?`, args: [error, id] })\n}\n\nexport async function cancelJob(id: string, reason: string): Promise<void> {\n await getDb().execute({ sql: `UPDATE jobs SET status = 'cancelled', error = ?, completed_at = datetime('now') WHERE id = ?`, args: [reason, id] })\n}\n\nexport interface KpoJobRow {\n id: string\n user_id: number\n status: string\n entity_name: string\n entity_type: string\n url: string | null\n request: string\n result: string | null\n error: string | null\n created_at: string\n updated_at: string\n}\n\nexport interface KpoPhaseLogRow {\n id: number\n job_id: string\n phase: string\n output: string\n created_at: string\n}\n\nfunction rowToKpoJob(row: Record<string, unknown>): KpoJobRow {\n return {\n id: String(row.id),\n user_id: Number(row.user_id),\n status: String(row.status),\n entity_name: String(row.entity_name),\n entity_type: String(row.entity_type),\n url: row.url != null ? String(row.url) : null,\n request: String(row.request),\n result: row.result != null ? String(row.result) : null,\n error: row.error != null ? String(row.error) : null,\n created_at: String(row.created_at),\n updated_at: String(row.updated_at),\n }\n}\n\nfunction rowToKpoPhaseLog(row: Record<string, unknown>): KpoPhaseLogRow {\n return {\n id: Number(row.id),\n job_id: String(row.job_id),\n phase: String(row.phase),\n output: String(row.output),\n created_at: String(row.created_at),\n }\n}\n\nexport async function createKpoJob(jobId: string, userId: number, entityName: string, entityType: string, request: object, url?: string): Promise<void> {\n await getDb().execute({\n sql: `INSERT INTO kpo_jobs (id, user_id, status, entity_name, entity_type, url, request) VALUES (?, ?, 'pending', ?, ?, ?, ?)`,\n args: [jobId, userId, entityName, entityType, url ?? null, JSON.stringify(request)],\n })\n}\n\nexport async function claimPendingKpoJob(): Promise<KpoJobRow | null> {\n const db = getDb()\n const upd = await db.execute(\n `UPDATE kpo_jobs SET status='running', updated_at=datetime('now') WHERE id = (SELECT id FROM kpo_jobs WHERE status='pending' ORDER BY created_at ASC LIMIT 1) RETURNING *`\n )\n if (upd.rowsAffected === 0) return null\n return upd.rows[0] ? rowToKpoJob(upd.rows[0] as unknown as Record<string, unknown>) : null\n}\n\nexport async function getKpoJob(jobId: string): Promise<KpoJobRow | null> {\n const res = await getDb().execute({ sql: `SELECT * FROM kpo_jobs WHERE id = ?`, args: [jobId] })\n return res.rows[0] ? rowToKpoJob(res.rows[0] as unknown as Record<string, unknown>) : null\n}\n\nexport async function updateKpoJobState(jobId: string, status: string): Promise<void> {\n await getDb().execute({ sql: `UPDATE kpo_jobs SET status = ?, updated_at = datetime('now') WHERE id = ?`, args: [status, jobId] })\n}\n\nexport async function completeKpoJob(jobId: string, result: object): Promise<void> {\n await getDb().execute({ sql: `UPDATE kpo_jobs SET status = 'done', result = ?, updated_at = datetime('now') WHERE id = ?`, args: [JSON.stringify(result), jobId] })\n}\n\nexport async function failKpoJob(jobId: string, error: string): Promise<void> {\n await getDb().execute({ sql: `UPDATE kpo_jobs SET status = 'failed', error = ?, updated_at = datetime('now') WHERE id = ?`, args: [error, jobId] })\n}\n\nexport async function logKpoPhaseComplete(jobId: string, phase: string, output: unknown): Promise<void> {\n await getDb().execute({\n sql: `INSERT INTO kpo_phase_log (job_id, phase, output) VALUES (?, ?, ?)`,\n args: [jobId, phase, JSON.stringify(output)],\n })\n}\n\nexport async function getKpoPhaseLog(jobId: string): Promise<KpoPhaseLogRow[]> {\n const res = await getDb().execute({ sql: `SELECT * FROM kpo_phase_log WHERE job_id = ? ORDER BY created_at ASC`, args: [jobId] })\n return res.rows.map(r => rowToKpoPhaseLog(r as unknown as Record<string, unknown>))\n}\n\nexport async function listKpoJobs(userId?: number): Promise<KpoJobRow[]> {\n const res = userId != null\n ? await getDb().execute({ sql: `SELECT * FROM kpo_jobs WHERE user_id = ? ORDER BY created_at DESC LIMIT 50`, args: [userId] })\n : await getDb().execute(`SELECT * FROM kpo_jobs ORDER BY created_at DESC LIMIT 50`)\n return res.rows.map(r => rowToKpoJob(r as unknown as Record<string, unknown>))\n}\n\nexport async function getUserByStripeCustomerId(customerId: string): Promise<User | undefined> {\n const res = await getDb().execute({\n sql: 'SELECT * FROM users WHERE stripe_customer_id = ? AND active = 1',\n args: [customerId],\n })\n return res.rows[0] ? rowToUser(res.rows[0] as unknown as Record<string, unknown>) : undefined\n}\n\nexport async function setStripeCustomerId(userId: number, customerId: string): Promise<void> {\n await getDb().execute({\n sql: 'UPDATE users SET stripe_customer_id = ? WHERE id = ?',\n args: [customerId, userId],\n })\n}\n\nexport async function setExtraConcurrencySlots(userId: number, slots: number): Promise<void> {\n await getDb().execute({\n sql: 'UPDATE users SET extra_concurrency_slots = ? WHERE id = ?',\n args: [Math.max(0, slots), userId],\n })\n}\n\nexport async function setConcurrencySubId(userId: number, subId: string | null): Promise<void> {\n await getDb().execute({\n sql: 'UPDATE users SET concurrency_stripe_sub_id = ? WHERE id = ?',\n args: [subId, userId],\n })\n}\n\nexport async function creditMc(\n userId: number,\n mc: number,\n operation: string,\n description?: string,\n stripePaymentIntent?: string,\n): Promise<number> {\n const db = getDb()\n await db.batch([\n { sql: 'UPDATE users SET balance_mc = balance_mc + ? WHERE id = ?', args: [mc, userId] },\n { sql: 'INSERT INTO ledger (user_id, amount_mc, operation, description, stripe_pi) VALUES (?, ?, ?, ?, ?)', args: [userId, mc, operation, description ?? null, stripePaymentIntent ?? null] },\n ], 'write')\n const res = await db.execute({ sql: 'SELECT balance_mc FROM users WHERE id = ?', args: [userId] })\n return Number(res.rows[0]?.balance_mc ?? 0)\n}\n\nexport async function ledgerExistsForOperation(userId: number, operation: string): Promise<boolean> {\n const res = await getDb().execute({\n sql: 'SELECT 1 FROM ledger WHERE user_id = ? AND operation = ? LIMIT 1',\n args: [userId, operation],\n })\n return res.rows.length > 0\n}\n\nexport async function claimMonthlyFreeRefresh(userId: number, month: string): Promise<boolean> {\n const res = await getDb().execute({\n sql: 'INSERT OR IGNORE INTO free_credit_refreshes (user_id, month) VALUES (?, ?)',\n args: [userId, month],\n })\n return res.rowsAffected > 0\n}\n\nexport async function debitMc(\n userId: number,\n mc: number,\n operation: string,\n description?: string,\n): Promise<{ ok: boolean; balance_mc: number }> {\n const db = getDb()\n const upd = await db.execute({\n sql: 'UPDATE users SET balance_mc = balance_mc - ? WHERE id = ? AND balance_mc >= ?',\n args: [mc, userId, mc],\n })\n if (upd.rowsAffected === 0) {\n const res = await db.execute({ sql: 'SELECT balance_mc FROM users WHERE id = ?', args: [userId] })\n return { ok: false, balance_mc: Number(res.rows[0]?.balance_mc ?? 0) }\n }\n await db.execute({\n sql: 'INSERT INTO ledger (user_id, amount_mc, operation, description) VALUES (?, ?, ?, ?)',\n args: [userId, -mc, operation, description ?? null],\n })\n const res = await db.execute({ sql: 'SELECT balance_mc FROM users WHERE id = ?', args: [userId] })\n return { ok: true, balance_mc: Number(res.rows[0]?.balance_mc ?? 0) }\n}\n\nexport async function getLedger(userId: number, limit = 50): Promise<LedgerRow[]> {\n const res = await getDb().execute({\n sql: 'SELECT * FROM ledger WHERE user_id = ? ORDER BY created_at DESC LIMIT ?',\n args: [userId, limit],\n })\n return res.rows.map(r => ({\n id: Number(r.id),\n user_id: Number(r.user_id),\n amount_mc: Number(r.amount_mc),\n operation: String(r.operation),\n description: r.description != null ? String(r.description) : null,\n stripe_pi: r.stripe_pi != null ? String(r.stripe_pi) : null,\n created_at: String(r.created_at),\n }))\n}\n\nexport async function ledgerExistsForStripePI(stripePI: string): Promise<boolean> {\n const res = await getDb().execute({\n sql: 'SELECT 1 FROM ledger WHERE stripe_pi = ? LIMIT 1',\n args: [stripePI],\n })\n return res.rows.length > 0\n}\n\nexport async function reconcileBalanceMc(userId: number | bigint): Promise<number> {\n const db = getDb()\n const res = await db.execute({\n sql: 'SELECT COALESCE(SUM(amount_mc), 0) AS balance_mc FROM ledger WHERE user_id = ?',\n args: [userId],\n })\n const balanceMc = Number(res.rows[0]?.balance_mc ?? 0)\n await db.execute({\n sql: 'UPDATE users SET balance_mc = ? WHERE id = ? AND balance_mc != ?',\n args: [balanceMc, userId, balanceMc],\n })\n return balanceMc\n}\n\nexport interface LedgerRow {\n id: number\n user_id: number\n amount_mc: number\n operation: string\n description: string | null\n stripe_pi: string | null\n created_at: string\n}\n\nexport const SiteAuditJobRowSchema = z.object({\n id: z.string(),\n user_id: z.number(),\n status: z.string().default('pending'),\n client_domain: z.string(),\n session_path: z.string(),\n request: z.string(),\n result: z.string().nullable(),\n error: z.string().nullable(),\n created_at: z.string(),\n updated_at: z.string(),\n});\nexport type SiteAuditJobRow = z.infer<typeof SiteAuditJobRowSchema>;\n\nexport const SiteAuditPhaseLogRowSchema = z.object({\n id: z.number(),\n job_id: z.string(),\n phase: z.string(),\n completed_at: z.string(),\n output_summary: z.string(),\n});\nexport type SiteAuditPhaseLogRow = z.infer<typeof SiteAuditPhaseLogRowSchema>;\n"],"mappings":"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","names":["res"]}
|