mcp-scraper 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/bin/api-server.cjs +917 -221
  2. package/dist/bin/api-server.cjs.map +1 -1
  3. package/dist/bin/api-server.js +2 -2
  4. package/dist/bin/mcp-scraper-cli.cjs +2 -1
  5. package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
  6. package/dist/bin/mcp-scraper-cli.js +3 -3
  7. package/dist/bin/mcp-scraper-install.cjs +1 -1
  8. package/dist/bin/mcp-scraper-install.cjs.map +1 -1
  9. package/dist/bin/mcp-scraper-install.js +1 -1
  10. package/dist/bin/mcp-stdio-server.cjs +64 -21
  11. package/dist/bin/mcp-stdio-server.cjs.map +1 -1
  12. package/dist/bin/mcp-stdio-server.js +3 -3
  13. package/dist/bin/paa-harvest.cjs +1 -0
  14. package/dist/bin/paa-harvest.cjs.map +1 -1
  15. package/dist/bin/paa-harvest.js +2 -2
  16. package/dist/{chunk-6TDUY7CA.js → chunk-4MFYMUIF.js} +25 -3
  17. package/dist/chunk-4MFYMUIF.js.map +1 -0
  18. package/dist/chunk-7HICT4GY.js +7 -0
  19. package/dist/chunk-7HICT4GY.js.map +1 -0
  20. package/dist/{chunk-NNEIXK5L.js → chunk-FUWZWKGO.js} +2 -2
  21. package/dist/{chunk-QUOZ3LZG.js → chunk-GFY6XHZS.js} +63 -21
  22. package/dist/chunk-GFY6XHZS.js.map +1 -0
  23. package/dist/{chunk-HBC4C75S.js → chunk-NJK5BTUK.js} +2 -2
  24. package/dist/{chunk-JOEZJL4I.js → chunk-NVUBFCJK.js} +2 -2
  25. package/dist/{chunk-BP27CZ5Q.js → chunk-XGIPATLV.js} +2 -1
  26. package/dist/chunk-XGIPATLV.js.map +1 -0
  27. package/dist/index.cjs +1 -0
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.js +2 -2
  30. package/dist/{server-U7V6DUSY.js → server-6IYQQK6X.js} +793 -210
  31. package/dist/server-6IYQQK6X.js.map +1 -0
  32. package/dist/{site-extract-repository-2MQBAOX5.js → site-extract-repository-4NVO5KQA.js} +3 -3
  33. package/dist/{worker-RVZXIALX.js → worker-7XRZNLKB.js} +4 -4
  34. package/package.json +2 -1
  35. package/dist/chunk-2ULBZRQQ.js +0 -7
  36. package/dist/chunk-2ULBZRQQ.js.map +0 -1
  37. package/dist/chunk-6TDUY7CA.js.map +0 -1
  38. package/dist/chunk-BP27CZ5Q.js.map +0 -1
  39. package/dist/chunk-QUOZ3LZG.js.map +0 -1
  40. package/dist/server-U7V6DUSY.js.map +0 -1
  41. /package/dist/{chunk-NNEIXK5L.js.map → chunk-FUWZWKGO.js.map} +0 -0
  42. /package/dist/{chunk-HBC4C75S.js.map → chunk-NJK5BTUK.js.map} +0 -0
  43. /package/dist/{chunk-JOEZJL4I.js.map → chunk-NVUBFCJK.js.map} +0 -0
  44. /package/dist/{site-extract-repository-2MQBAOX5.js.map → site-extract-repository-4NVO5KQA.js.map} +0 -0
  45. /package/dist/{worker-RVZXIALX.js.map → worker-7XRZNLKB.js.map} +0 -0
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  harvest
4
- } from "../chunk-HBC4C75S.js";
4
+ } from "../chunk-NJK5BTUK.js";
5
5
  import {
6
6
  browserServiceApiKey
7
7
  } from "../chunk-HPV4VOQX.js";
8
8
  import "../chunk-K443GQY5.js";
9
- import "../chunk-BP27CZ5Q.js";
9
+ import "../chunk-XGIPATLV.js";
10
10
  import "../chunk-M2S27J6Z.js";
11
11
  import "../chunk-FUVQR6GK.js";
12
12
 
@@ -21,7 +21,9 @@ var MC_COSTS = {
21
21
  instagram_transcribe: 50,
22
22
  browser_minute: 12e3,
23
23
  reddit_thread: 2e3,
24
- video_analysis: 666667
24
+ video_analysis: 666667,
25
+ trustpilot_reviews: 500,
26
+ trustpilot_review: 100
25
27
  };
26
28
  var MC_PER_BROWSER_MS = MC_COSTS.browser_minute / 6e4;
27
29
  function browserActiveCostMc(activeMs) {
@@ -195,6 +197,22 @@ var CREDIT_COST_CATALOG = [
195
197
  credits: mcToCredits(MC_COSTS.video_analysis),
196
198
  unit: "per 120 frames (max 480)",
197
199
  notes: "Full multi-lens video breakdown: samples frames across a video (up to 30 minutes), analyzes each with vision AI, transcribes the audio, then produces summary, pacing/energy, words-per-minute, topic outline, key points, hook analysis, visual style, and a how-to-replicate recipe with a quality-control pass. $1 per 120 frames requested (max 480 = $4); billed down automatically if the video cannot use the requested frames, and refunded fully if the run fails."
200
+ },
201
+ {
202
+ key: "trustpilot_reviews",
203
+ label: "Trustpilot review harvest",
204
+ aliases: ["trustpilot_reviews", "trustpilot", "trustpilot reviews"],
205
+ credits: mcToCredits(MC_COSTS.trustpilot_reviews),
206
+ unit: "per call",
207
+ notes: "Base lookup. Reviews billed separately per card at trustpilot_review rate. Refunded if no reviews are found."
208
+ },
209
+ {
210
+ key: "trustpilot_review",
211
+ label: "Trustpilot review card",
212
+ aliases: ["trustpilot_review", "trustpilot card"],
213
+ credits: mcToCredits(MC_COSTS.trustpilot_review),
214
+ unit: "per review card",
215
+ notes: "Charged per review actually extracted, billed down automatically if the balance runs out mid-page."
198
216
  }
199
217
  ];
200
218
  var CONCURRENCY_PRICE_ID = "price_1Ta1NRS8aAcsk3TGwsRnYbix";
@@ -301,7 +319,11 @@ var LedgerOperation = {
301
319
  VIDEO_ANALYSIS_REFUND: "video_analysis_refund",
302
320
  VIDEO_ANALYSIS_ADJUST: "video_analysis_adjust",
303
321
  MEMORY_AI: "memory_ai",
304
- MEMORY_AI_REFUND: "memory_ai_refund"
322
+ MEMORY_AI_REFUND: "memory_ai_refund",
323
+ TRUSTPILOT_REVIEWS: "trustpilot_reviews",
324
+ TRUSTPILOT_REVIEWS_REFUND: "trustpilot_reviews_refund",
325
+ TRUSTPILOT_REVIEW: "trustpilot_review",
326
+ TRUSTPILOT_REVIEW_REFUND: "trustpilot_review_refund"
305
327
  };
306
328
  var MEMORY_AI_MARGIN_MULTIPLE = 3;
307
329
  var MC_PER_USD = SUBSCRIPTION_TIERS["price_1TmiHRS8aAcsk3TGwmSNfNIa"].credits_mc / SUBSCRIPTION_TIERS["price_1TmiHRS8aAcsk3TGwmSNfNIa"].monthly_usd;
@@ -325,4 +347,4 @@ export {
325
347
  MEMORY_AI_MARGIN_MULTIPLE,
326
348
  MC_PER_USD
327
349
  };
328
- //# sourceMappingURL=chunk-6TDUY7CA.js.map
350
+ //# sourceMappingURL=chunk-4MFYMUIF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/rates.ts"],"sourcesContent":["export const MC_COSTS = {\n serp: 100,\n paa: 200,\n paa_base: 1_000,\n page_scrape: 100,\n url_map: 500,\n yt_channel: 200,\n yt_transcription: 200,\n fb_ad: 200,\n maps_search: 500,\n maps_place: 3_000,\n maps_review: 100,\n fb_search: 600,\n fb_transcribe: 200,\n google_ads_search: 600,\n google_ads_intel: 200,\n google_ads_transcribe: 200,\n instagram_profile: 400,\n instagram_media: 400,\n instagram_transcribe: 50,\n browser_minute: 12_000,\n reddit_thread: 2_000,\n video_analysis: 666_667,\n trustpilot_reviews: 500,\n trustpilot_review: 100,\n} as const\n\nexport type McCostKey = keyof typeof MC_COSTS\n\nexport const MC_PER_BROWSER_MS = MC_COSTS.browser_minute / 60_000\n\nexport function browserActiveCostMc(activeMs: number): number {\n return Math.round(activeMs * MC_PER_BROWSER_MS)\n}\n\nexport const BROWSER_OPEN_MIN_BALANCE_MC = 1_000\n\nexport const MC_PER_CREDIT = 1_000\n\nexport const CREDIT_COST_CATALOG: Array<{\n key: McCostKey\n label: string\n aliases: string[]\n credits: number\n unit: string\n notes?: string\n}> = [\n {\n key: 'serp',\n label: 'SERP search',\n aliases: ['search_serp', 'serp', 'google search', 'organic results'],\n credits: mcToCredits(MC_COSTS.serp),\n unit: 'per search',\n notes: 'Returns AI Overview, PAA snippet, videos, forums, and local pack.',\n },\n {\n key: 'paa',\n label: 'PAA harvest',\n aliases: ['harvest_paa', 'paa', 'people also ask', 'questions'],\n credits: mcToCredits(MC_COSTS.paa),\n unit: `per question (+${mcToCredits(MC_COSTS.paa_base)} credit base)`,\n notes: `Full SERP feature extraction. Billed ${mcToCredits(MC_COSTS.paa_base)} credit base + ${mcToCredits(MC_COSTS.paa)} per question actually returned (unused estimate refunded).`,\n },\n {\n key: 'page_scrape',\n label: 'Page crawl / extract',\n aliases: ['extract_url', 'extract_site', 'page scrape', 'url scrape', 'single page', 'site crawl'],\n credits: mcToCredits(MC_COSTS.page_scrape),\n unit: 'per page',\n notes: 'Applies to both single-URL extraction and per-page site crawls.',\n },\n {\n key: 'url_map',\n label: 'Site URL mapping',\n aliases: ['map_site_urls', 'url map', 'site map', 'crawl urls'],\n credits: mcToCredits(MC_COSTS.url_map),\n unit: 'per mapping operation',\n notes: 'Flat rate for the full /map-urls call regardless of URL count discovered.',\n },\n {\n key: 'yt_channel',\n label: 'YouTube search / channel harvest',\n aliases: ['youtube_harvest', 'youtube search', 'youtube channel', 'yt_channel'],\n credits: mcToCredits(MC_COSTS.yt_channel),\n unit: 'per call',\n },\n {\n key: 'yt_transcription',\n label: 'YouTube transcription',\n aliases: ['youtube_transcribe', 'youtube transcript', 'transcription', 'yt_transcription'],\n credits: mcToCredits(MC_COSTS.yt_transcription),\n unit: 'per minute',\n notes: 'A 5-minute hold is taken, then reconciled to actual video duration.',\n },\n {\n key: 'fb_ad',\n label: 'Facebook search / ad lookup',\n aliases: ['facebook_page_intel', 'facebook_ad_search', 'facebook_ad', 'facebook ads', 'fb ads'],\n credits: mcToCredits(MC_COSTS.fb_ad),\n unit: 'per call',\n },\n {\n key: 'maps_search',\n label: 'Maps business search',\n aliases: ['maps_search', 'google maps search', 'gmb search', 'gbp search', 'business profiles'],\n credits: mcToCredits(MC_COSTS.maps_search),\n unit: 'per search',\n notes: 'Returns up to 50 Google Maps business/profile candidates. Use maps_place_intel to hydrate selected businesses.',\n },\n {\n key: 'maps_place',\n label: 'Maps business lookup',\n aliases: ['maps_place_intel', 'google maps', 'maps place', 'place intel'],\n credits: mcToCredits(MC_COSTS.maps_place),\n unit: 'per business',\n notes: 'Base lookup. Reviews billed separately per card at maps_review rate.',\n },\n {\n key: 'maps_review',\n label: 'Maps review',\n aliases: ['maps_reviews', 'google reviews', 'review cards', 'reviews'],\n credits: mcToCredits(MC_COSTS.maps_review),\n unit: 'per review card',\n notes: 'Charged after extraction when includeReviews is true.',\n },\n {\n key: 'fb_search',\n label: 'Facebook ad library search',\n aliases: ['facebook_search', 'fb_search', 'fb ad search'],\n credits: mcToCredits(MC_COSTS.fb_search),\n unit: 'per search',\n notes: 'Browser automation to search Facebook Ads Library by keyword.',\n },\n {\n key: 'google_ads_search',\n label: 'Google Ads Transparency search',\n aliases: ['google_ads_search', 'google ads search', 'ads transparency search'],\n credits: mcToCredits(MC_COSTS.google_ads_search),\n unit: 'per search',\n notes: 'Browser automation to find advertisers in Google Ads Transparency Center by domain or name.',\n },\n {\n key: 'google_ads_intel',\n label: 'Google Ads Transparency advertiser intel',\n aliases: ['google_ads_page_intel', 'google ads intel', 'ads transparency intel'],\n credits: mcToCredits(MC_COSTS.google_ads_intel),\n unit: 'per call',\n notes: 'Lists and hydrates an advertiser\\'s creatives with image URLs and video references.',\n },\n {\n key: 'google_ads_transcribe',\n label: 'Google ad video transcription',\n aliases: ['google_ads_transcribe', 'google ad transcript'],\n credits: mcToCredits(MC_COSTS.google_ads_transcribe),\n unit: 'per minute',\n notes: 'A hold is taken, then reconciled to actual video duration.',\n },\n {\n key: 'fb_transcribe',\n label: 'Facebook video / ad transcription',\n aliases: ['facebook_transcribe', 'facebook_video_transcribe', 'fb_transcribe', 'fb ad transcript'],\n credits: mcToCredits(MC_COSTS.fb_transcribe),\n unit: 'per minute',\n notes: 'A hold is taken, then reconciled to actual video duration.',\n },\n {\n key: 'instagram_profile',\n label: 'Instagram profile content discovery',\n aliases: ['instagram_profile_content', 'instagram profile', 'instagram content list', 'ig profile'],\n credits: mcToCredits(MC_COSTS.instagram_profile),\n unit: 'per profile scan',\n notes: 'Browser extraction of public Instagram profile grid links. Complete history may require a logged-in profile.',\n },\n {\n key: 'instagram_media',\n label: 'Instagram media download',\n aliases: ['instagram_media_download', 'instagram reel download', 'instagram post download', 'ig media'],\n credits: mcToCredits(MC_COSTS.instagram_media),\n unit: 'per post or reel',\n notes: 'Extracts post text, image URLs, and reel audio/video tracks, with local downloads when the server can write files.',\n },\n {\n key: 'instagram_transcribe',\n label: 'Instagram media transcription',\n aliases: ['instagram transcript', 'instagram reel transcript', 'ig transcribe'],\n credits: mcToCredits(MC_COSTS.instagram_transcribe),\n unit: 'per call',\n notes: 'Whisper transcription of selected Instagram audio/video media via fal.ai.',\n },\n {\n key: 'browser_minute',\n label: 'Interactive browser session',\n aliases: ['browser_open', 'browser agent', 'browser_agent', 'live browser', 'browse', 'browser control', 'interactive browser'],\n credits: mcToCredits(MC_COSTS.browser_minute),\n unit: 'per minute of use',\n notes: 'Metered per minute of use for the whole time the browser session is open. Close the session to stop the meter; abandoned sessions are auto-closed after a short idle window.',\n },\n {\n key: 'reddit_thread',\n label: 'Reddit thread + comments',\n aliases: ['reddit', 'reddit_thread', 'reddit comments', 'subreddit', 'reddit post'],\n credits: mcToCredits(MC_COSTS.reddit_thread),\n unit: 'per thread',\n notes: 'Captures a Reddit post and its comment tree. Charged on success; refunded if the thread cannot be retrieved.',\n },\n {\n key: 'video_analysis',\n label: 'Video breakdown (frame-by-frame + transcript)',\n aliases: ['video_frame_analysis', 'video breakdown', 'video analysis', 'analyze video'],\n credits: mcToCredits(MC_COSTS.video_analysis),\n unit: 'per 120 frames (max 480)',\n notes: 'Full multi-lens video breakdown: samples frames across a video (up to 30 minutes), analyzes each with vision AI, transcribes the audio, then produces summary, pacing/energy, words-per-minute, topic outline, key points, hook analysis, visual style, and a how-to-replicate recipe with a quality-control pass. $1 per 120 frames requested (max 480 = $4); billed down automatically if the video cannot use the requested frames, and refunded fully if the run fails.',\n },\n {\n key: 'trustpilot_reviews',\n label: 'Trustpilot review harvest',\n aliases: ['trustpilot_reviews', 'trustpilot', 'trustpilot reviews'],\n credits: mcToCredits(MC_COSTS.trustpilot_reviews),\n unit: 'per call',\n notes: 'Base lookup. Reviews billed separately per card at trustpilot_review rate. Refunded if no reviews are found.',\n },\n {\n key: 'trustpilot_review',\n label: 'Trustpilot review card',\n aliases: ['trustpilot_review', 'trustpilot card'],\n credits: mcToCredits(MC_COSTS.trustpilot_review),\n unit: 'per review card',\n notes: 'Charged per review actually extracted, billed down automatically if the balance runs out mid-page.',\n },\n]\n\nexport const CONCURRENCY_PRICE_ID = 'price_1Ta1NRS8aAcsk3TGwsRnYbix'\n\nexport interface SubscriptionTier { tier: string; label: string; price_id: string; monthly_usd: number; credits_mc: number; concurrency: number; intro_coupon: string | null }\n\nexport const SUBSCRIPTION_TIERS: Record<string, SubscriptionTier> = {\n 'price_1TmiHRS8aAcsk3TGwmSNfNIa': { tier: 'starter', label: 'Starter', price_id: 'price_1TmiHRS8aAcsk3TGwmSNfNIa', monthly_usd: 12, credits_mc: 8_000_000, concurrency: 3, intro_coupon: 'mcp-starter-1dollar-intro-12' },\n 'price_1Tmg1nS8aAcsk3TGe8zcnGTM': { tier: 'growth', label: 'Growth', price_id: 'price_1Tmg1nS8aAcsk3TGe8zcnGTM', monthly_usd: 100, credits_mc: 80_000_000, concurrency: 10, intro_coupon: null },\n 'price_1Tmg1nS8aAcsk3TGsZw34iXS': { tier: 'scale', label: 'Scale', price_id: 'price_1Tmg1nS8aAcsk3TGsZw34iXS', monthly_usd: 250, credits_mc: 240_000_000, concurrency: 20, intro_coupon: null },\n}\n\nexport const SUBSCRIPTION_TIER_BY_KEY: Record<string, SubscriptionTier> = Object.fromEntries(\n Object.values(SUBSCRIPTION_TIERS).map(t => [t.tier, t]),\n)\nexport const CONCURRENCY_SLOT_PRICE_USD = 5\nexport const CONCURRENCY_SLOT_PRICE_CURRENCY = 'usd'\nexport const CONCURRENCY_SLOT_PRICE_INTERVAL = 'month'\nexport const CONCURRENCY_SLOT_PRICE_LABEL = '$5/month'\nexport const CONCURRENCY_SLOT_TERMINAL_COMMAND = 'npx -y -p mcp-scraper@latest mcp-scraper-cli billing concurrency checkout'\n\nexport function concurrencySlotBillingInfo() {\n const billingUrl = process.env.CONCURRENCY_BILLING_URL ?? 'https://mcpscraper.dev/billing'\n return {\n product: 'Extra concurrency slot',\n price_label: CONCURRENCY_SLOT_PRICE_LABEL,\n unit_amount_usd: CONCURRENCY_SLOT_PRICE_USD,\n currency: CONCURRENCY_SLOT_PRICE_CURRENCY,\n interval: CONCURRENCY_SLOT_PRICE_INTERVAL,\n billing_url: billingUrl,\n terminal_command: CONCURRENCY_SLOT_TERMINAL_COMMAND,\n terminal_command_with_api_key_env: `MCP_SCRAPER_API_KEY=sk_live_your_key ${CONCURRENCY_SLOT_TERMINAL_COMMAND}`,\n }\n}\n\nexport const FREE_SIGNUP_MC = 100_000\nexport const FREE_MONTHLY_REFRESH_MC = 250_000\n\nexport const BALANCE_PRICE_IDS: Record<string, number> = {\n 'price_1TZx6rS8aAcsk3TGNMc1Vgpo': 11_000_000,\n 'price_1TZx6sS8aAcsk3TGxgqB7khO': 27_500_000,\n 'price_1TZx6tS8aAcsk3TG8PnJqHlG': 60_500_000,\n 'price_1TZx6tS8aAcsk3TGNgRMpy0e': 121_000_000,\n}\n\nexport const BALANCE_PACK_LABELS: Record<string, string> = {\n 'price_1TZx6rS8aAcsk3TGNMc1Vgpo': '$10',\n 'price_1TZx6sS8aAcsk3TGxgqB7khO': '$25',\n 'price_1TZx6tS8aAcsk3TG8PnJqHlG': '$50',\n 'price_1TZx6tS8aAcsk3TGNgRMpy0e': '$100',\n}\n\nexport function mcToCredits(mc: number): number {\n return mc / MC_PER_CREDIT\n}\n\nexport function insufficientBalanceResponse(balanceMc: number, requiredMc: number) {\n const topupUrl = process.env.TOPUP_URL ?? 'https://mcpscraper.dev/billing'\n const balanceCredits = mcToCredits(balanceMc)\n const requiredCredits = mcToCredits(requiredMc)\n return {\n error: 'insufficient_balance',\n error_code: 'insufficient_balance' as const,\n message: `Insufficient credits. Balance: ${balanceCredits} credits. This call requires ${requiredCredits} credits. Top up at ${topupUrl}`,\n balance_credits: balanceCredits,\n required_credits: requiredCredits,\n topup_url: topupUrl,\n }\n}\n\nexport interface MemoryPlan {\n plan: 'pro' | 'team'\n label: string\n price_id: string\n interval: 'month' | 'year'\n monthly_usd: number\n quota_bytes: number\n}\n\nexport const MEMORY_FREE_QUOTA_BYTES = 0.01e9 * 1\n\nexport const MEMORY_PLANS: Record<string, MemoryPlan> = {\n 'price_1TnMSTS8aAcsk3TGBgiwuvqL': { plan: 'pro', label: 'Pro', price_id: 'price_1TnMSTS8aAcsk3TGBgiwuvqL', interval: 'month', monthly_usd: 19, quota_bytes: 5e9 },\n 'price_1TnMSTS8aAcsk3TGWBVU2agY': { plan: 'pro', label: 'Pro', price_id: 'price_1TnMSTS8aAcsk3TGWBVU2agY', interval: 'year', monthly_usd: 19, quota_bytes: 5e9 },\n}\n\nexport const MEMORY_PLAN_QUOTA: Record<string, number> = { free: MEMORY_FREE_QUOTA_BYTES, pro: 5e9, team: 50e9 }\n\nexport const MEMORY_MARGIN_MULTIPLE = 3\nexport const MEMORY_FREE_COST_CAP_USD = 1.0\nexport const MEMORY_PRO_COST_BUDGET_USD = 19 / MEMORY_MARGIN_MULTIPLE\n\nexport interface SchedulingPlan {\n price_id: string\n label: string\n interval: 'month'\n monthly_usd: number\n quota_per_period: number\n}\n\nexport const SCHEDULING_PLANS: Record<string, SchedulingPlan> = {\n 'price_1ToXcHS8aAcsk3TGf3cW7zHx': { price_id: 'price_1ToXcHS8aAcsk3TGf3cW7zHx', label: 'Scheduled Actions', interval: 'month', monthly_usd: 10, quota_per_period: 1000 },\n}\n\nexport const LedgerOperation = {\n TOPUP: 'topup',\n SUBSCRIPTION: 'subscription',\n SIGNUP_GRANT: 'signup_grant',\n MONTHLY_REFRESH: 'monthly_free_refresh',\n PAA: 'paa',\n PAA_REFUND: 'paa_refund',\n SERP: 'serp',\n REFUND: 'refund',\n TRANSCRIPTION: 'transcription',\n TRANSCRIPTION_HOLD: 'transcription_hold',\n TRANSCRIPTION_REFUND: 'transcription_refund',\n YT_CHANNEL: 'yt_channel',\n FB_AD: 'fb_ad',\n MAPS_SEARCH: 'maps_search',\n MAPS_PLACE: 'maps_place',\n MAPS_REVIEW: 'maps_review',\n MAPS_REVIEW_REFUND: 'maps_review_refund',\n EXTRACT_SITE: 'extract_site',\n EXTRACT_SITE_REFUND: 'extract_site_refund',\n EXTRACT_URL: 'page_scrape',\n URL_MAP: 'url_map',\n EXTRACT_SITE_HOLD: 'extract_site_hold',\n YT_CHANNEL_REFUND: 'yt_channel_refund',\n FB_AD_REFUND: 'fb_ad_refund',\n URL_MAP_REFUND: 'url_map_refund',\n FB_SEARCH: 'fb_search',\n FB_TRANSCRIBE: 'fb_transcribe',\n FB_SEARCH_REFUND: 'fb_search_refund',\n FB_TRANSCRIBE_REFUND: 'fb_transcribe_refund',\n GOOGLE_ADS_SEARCH: 'google_ads_search',\n GOOGLE_ADS_SEARCH_REFUND: 'google_ads_search_refund',\n GOOGLE_ADS_INTEL: 'google_ads_intel',\n GOOGLE_ADS_INTEL_REFUND: 'google_ads_intel_refund',\n GOOGLE_ADS_TRANSCRIBE: 'google_ads_transcribe',\n GOOGLE_ADS_TRANSCRIBE_REFUND: 'google_ads_transcribe_refund',\n INSTAGRAM_PROFILE: 'instagram_profile',\n INSTAGRAM_PROFILE_REFUND: 'instagram_profile_refund',\n INSTAGRAM_MEDIA: 'instagram_media',\n INSTAGRAM_MEDIA_REFUND:'instagram_media_refund',\n INSTAGRAM_TRANSCRIBE: 'instagram_transcribe',\n INSTAGRAM_TRANSCRIBE_REFUND: 'instagram_transcribe_refund',\n BROWSER_SESSION: 'browser_session',\n REDDIT_THREAD: 'reddit_thread',\n REDDIT_THREAD_REFUND: 'reddit_thread_refund',\n VIDEO_ANALYSIS: 'video_analysis',\n VIDEO_ANALYSIS_REFUND: 'video_analysis_refund',\n VIDEO_ANALYSIS_ADJUST: 'video_analysis_adjust',\n MEMORY_AI: 'memory_ai',\n MEMORY_AI_REFUND: 'memory_ai_refund',\n TRUSTPILOT_REVIEWS: 'trustpilot_reviews',\n TRUSTPILOT_REVIEWS_REFUND: 'trustpilot_reviews_refund',\n TRUSTPILOT_REVIEW: 'trustpilot_review',\n TRUSTPILOT_REVIEW_REFUND: 'trustpilot_review_refund',\n} as const\n\nexport type LedgerOperation = typeof LedgerOperation[keyof typeof LedgerOperation]\n\nexport const MEMORY_AI_MARGIN_MULTIPLE = 3\n\nexport const MC_PER_USD =\n SUBSCRIPTION_TIERS['price_1TmiHRS8aAcsk3TGwmSNfNIa'].credits_mc /\n SUBSCRIPTION_TIERS['price_1TmiHRS8aAcsk3TGwmSNfNIa'].monthly_usd\n"],"mappings":"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","names":[]}
@@ -0,0 +1,7 @@
1
+ // src/version.ts
2
+ var PACKAGE_VERSION = "0.4.2";
3
+
4
+ export {
5
+ PACKAGE_VERSION
6
+ };
7
+ //# sourceMappingURL=chunk-7HICT4GY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/version.ts"],"sourcesContent":["export const PACKAGE_VERSION = '0.4.2'\n"],"mappings":";AAAO,IAAM,kBAAkB;","names":[]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-K443GQY5.js";
4
4
  import {
5
5
  DEFAULT_MAPS_PROXY_MODE
6
- } from "./chunk-BP27CZ5Q.js";
6
+ } from "./chunk-XGIPATLV.js";
7
7
 
8
8
  // src/lib/slugify.ts
9
9
  function slugify(s) {
@@ -1925,4 +1925,4 @@ export {
1925
1925
  runWorkflow,
1926
1926
  runWorkflowStep
1927
1927
  };
1928
- //# sourceMappingURL=chunk-NNEIXK5L.js.map
1928
+ //# sourceMappingURL=chunk-FUWZWKGO.js.map
@@ -14,10 +14,10 @@ import {
14
14
  import {
15
15
  DEFAULT_MAPS_PROXY_MODE,
16
16
  DEFAULT_PROXY_MODE
17
- } from "./chunk-BP27CZ5Q.js";
17
+ } from "./chunk-XGIPATLV.js";
18
18
  import {
19
19
  PACKAGE_VERSION
20
- } from "./chunk-2ULBZRQQ.js";
20
+ } from "./chunk-7HICT4GY.js";
21
21
  import {
22
22
  sanitizeVendorName
23
23
  } from "./chunk-M2S27J6Z.js";
@@ -316,6 +316,17 @@ var WORKFLOW_RECIPES = [
316
316
  produces: ["content gaps", "page comparison CSV", "PAA questions CSV", "section map", "writer brief"],
317
317
  runHint: "Use workflow_run with workflowId serp-comparison for competitor gaps or paa-expansion-brief when the user mainly wants a section map from PAA data."
318
318
  },
319
+ {
320
+ id: "recurring_tracking_and_memory",
321
+ title: "Recurring Tracking & Memory",
322
+ description: "Run a check on a daily, weekly, or custom cadence with no external cron needed, and save each result somewhere searchable so you can compare against past runs later - rankings, prices, competitor changes, anything you would otherwise check by hand and forget to log.",
323
+ primaryWorkflowId: null,
324
+ recommendedTools: ["create-scheduled-action", "search_serp", "table-create", "table-insert-rows", "table-query", "memory-put", "memory-search", "list-scheduled-actions"],
325
+ requiredInputs: ["plain-language description of what to check and how often"],
326
+ optionalInputs: ["vault to save into", "timeOfDay", "timezone"],
327
+ produces: ["a live scheduled action that runs automatically on cadence", "a table row or note per run for structured history", "a searchable trend you can compare run-over-run"],
328
+ runHint: "Use create-scheduled-action with a plain description and cadence; the run itself checks list-vaults, uses table-insert-rows for repeating structured data (e.g. a keyword rank check) or memory-put for a one-off note, and reads prior runs with table-query or memory-search before writing the new one. For a one-time blueprint to build your own external cron/DB instead of a live scheduled action, use rank_tracker_workflow."
329
+ },
319
330
  {
320
331
  id: "ai_search_visibility_audit",
321
332
  title: "AI Search Visibility Audit",
@@ -2127,6 +2138,9 @@ function formatMapsPlaceIntel(raw, input) {
2127
2138
  const about = d.aboutAttributes ?? [];
2128
2139
  const reviews = d.reviews ?? [];
2129
2140
  const reviewsStatus = d.reviewsStatus ?? "not_requested";
2141
+ const services = d.services ?? [];
2142
+ const areasServed = d.areasServed ?? [];
2143
+ const servicesStatus = d.servicesStatus ?? "not_requested";
2130
2144
  const hoursTable = d.hoursTable ?? [];
2131
2145
  const ratingLine = [rating, reviewCount ? `(${reviewCount} reviews)` : null].filter(Boolean).join(" ");
2132
2146
  const basicLines = [
@@ -2181,6 +2195,20 @@ ${reviews.map((r, i) => {
2181
2195
  ${r.text ?? ""}`;
2182
2196
  }).join("\n\n")}`;
2183
2197
  })();
2198
+ const servicesSection = (() => {
2199
+ if (servicesStatus === "not_requested") return "";
2200
+ if (servicesStatus === "unavailable") return "\n## Services & Areas Served\n> Could not be retrieved this run \u2014 retry with `includeServices: true`.";
2201
+ if (servicesStatus === "none_exist") return "\n## Services & Areas Served\n*Not listed on this business's profile.*";
2202
+ const parts = [
2203
+ services.length ? `**Services**
2204
+ ${services.map((s) => `- ${s}`).join("\n")}` : null,
2205
+ areasServed.length ? `**Areas Served**
2206
+ ${areasServed.map((a) => `- ${a}`).join("\n")}` : null
2207
+ ].filter(Boolean);
2208
+ return parts.length ? `
2209
+ ## Services & Areas Served
2210
+ ${parts.join("\n\n")}` : "";
2211
+ })();
2184
2212
  const full = [
2185
2213
  `# ${name}`,
2186
2214
  category ? `*${category}*` : null,
@@ -2196,6 +2224,7 @@ ${basicLines}` : null,
2196
2224
  ## Entity IDs
2197
2225
  ${entitySection}` : null,
2198
2226
  reviewsSection,
2227
+ servicesSection,
2199
2228
  durationMs != null ? `
2200
2229
  ---
2201
2230
  *Extracted in ${(durationMs / 1e3).toFixed(1)}s*` : null
@@ -2219,7 +2248,10 @@ ${entitySection}` : null,
2219
2248
  lng: lng ?? null,
2220
2249
  reviewsStatus,
2221
2250
  reviewsCollected: reviews.length,
2222
- reviewTopics: topics.map((t) => ({ label: String(t.label ?? ""), count: String(t.count ?? "") }))
2251
+ reviewTopics: topics.map((t) => ({ label: String(t.label ?? ""), count: String(t.count ?? "") })),
2252
+ services,
2253
+ areasServed,
2254
+ servicesStatus
2223
2255
  }
2224
2256
  };
2225
2257
  }
@@ -2753,7 +2785,8 @@ var MapsPlaceIntelInputSchema = {
2753
2785
  gl: z.string().length(2).default("us").describe("Google country code inferred from location."),
2754
2786
  hl: z.string().length(2).default("en").describe("Language inferred from user request."),
2755
2787
  includeReviews: z.boolean().default(false).describe("Fetch individual review cards \u2014 for reviews, customer pain, complaints, or praise themes."),
2756
- maxReviews: z.number().int().min(1).max(500).default(50).describe("Max review cards when includeReviews is true. Default 50, maximum 500.")
2788
+ maxReviews: z.number().int().min(1).max(500).default(50).describe("Max review cards when includeReviews is true. Default 50, maximum 500."),
2789
+ includeServices: z.boolean().default(false).describe("Fetch the business's configured services list and areas-served list, when the profile has them. Adds one extra page visit; not present for every business.")
2757
2790
  };
2758
2791
  var MapsSearchInputSchema = {
2759
2792
  query: z.string().min(1).describe('Business category, niche, or search term, e.g. "roofers". Do not include location here \u2014 use location instead.'),
@@ -3066,7 +3099,10 @@ var MapsPlaceIntelOutputSchema = {
3066
3099
  reviewTopics: z.array(z.object({
3067
3100
  label: z.string(),
3068
3101
  count: z.string()
3069
- }))
3102
+ })),
3103
+ services: z.array(z.string()),
3104
+ areasServed: z.array(z.string()),
3105
+ servicesStatus: z.string()
3070
3106
  };
3071
3107
  var CreditsInfoOutputSchema = {
3072
3108
  balanceCredits: z.number().nullable(),
@@ -4854,7 +4890,7 @@ var BrowserProfileLogin = z2.object({
4854
4890
  var BrowserProfileConnectOutputSchema = {
4855
4891
  ok: z2.boolean(),
4856
4892
  tool: z2.literal("browser_profile_connect"),
4857
- session_id: NullableString2,
4893
+ session_id: NullableString2.describe("The underlying live browser session id backing this sign-in."),
4858
4894
  auth_connection_id: z2.string(),
4859
4895
  watch_url: z2.string().describe("mcpscraper.dev sign-in link to give the user so they can complete this login."),
4860
4896
  live_view_url: NullableString2.describe("Deprecated; always null. Open watch_url to view the sign-in."),
@@ -4864,10 +4900,10 @@ var BrowserProfileConnectOutputSchema = {
4864
4900
  account_email: NullableString2,
4865
4901
  note: NullableString2,
4866
4902
  status: z2.string(),
4867
- flow_status: NullableString2,
4868
- flow_step: NullableString2,
4869
- flow_expires_at: NullableString2,
4870
- post_login_url: NullableString2,
4903
+ flow_status: NullableString2.describe("Deprecated; always null."),
4904
+ flow_step: NullableString2.describe("Deprecated; always null."),
4905
+ flow_expires_at: NullableString2.describe("Deprecated; always null."),
4906
+ post_login_url: NullableString2.describe("Deprecated; always null."),
4871
4907
  connected_logins: z2.array(BrowserProfileLogin).describe("Every login currently saved in this profile, so you can see what else is connected."),
4872
4908
  next_steps: z2.array(z2.string()),
4873
4909
  raw: BrowserRawObject.optional()
@@ -5292,6 +5328,11 @@ function slugPart(value) {
5292
5328
  if (!trimmed) return null;
5293
5329
  return trimmed.replace(/^https?:\/\//, "").replace(/^www\./, "").replace(/\/.*$/, "").replace(/[^a-z0-9._-]+/g, "-").replace(/[._-]+/g, "-").replace(/^-+|-+$/g, "");
5294
5330
  }
5331
+ function normalizeDomain2(value) {
5332
+ const trimmed = value?.trim().toLowerCase();
5333
+ if (!trimmed) return null;
5334
+ return trimmed.replace(/^https?:\/\//, "").replace(/^www\./, "").replace(/\/.*$/, "").replace(/[^a-z0-9.-]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
5335
+ }
5295
5336
  function savedProfileNameFromEmail(email) {
5296
5337
  const value = slugPart(email);
5297
5338
  if (!value) return null;
@@ -5401,13 +5442,13 @@ function registerBrowserAgentMcpTools(server, opts) {
5401
5442
  "browser_profile_connect",
5402
5443
  {
5403
5444
  title: "Save a Site Login to a Profile",
5404
- description: "Save a logged-in browser session so this server can reuse a site the user is signed into (ChatGPT, Claude, Reddit, any account-gated site). Returns a watch_url; the user signs in fresh (existing browser cookies are NOT imported) and cookies save to a named profile. ONE profile holds MANY logins \u2014 call again with the same profile and a different domain to stack another account. NOT for one-off scraping (use extract_url) or driving the browser (use browser_open). After sign-in, poll browser_profile_list until AUTHENTICATED, then browser_open with the profile.",
5445
+ description: 'Open a live hosted browser session so the user can sign into a site (ChatGPT, Claude, Reddit, any account-gated site) directly in their own browser tab, then save the login to a named profile. Returns a watch_url \u2014 give it to the user; they sign in fresh on the real site (existing browser cookies are NOT imported), then click "Done" on that page to save the session and close it. ONE profile holds MANY logins \u2014 call again with the same profile and a different domain to stack another account. NOT for one-off scraping (use extract_url) or driving the browser (use browser_open). Billed at the standard live-browser rate while the sign-in session stays open. After the user clicks Done, poll browser_profile_list until AUTHENTICATED, then browser_open with the profile.',
5405
5446
  inputSchema: BrowserProfileConnectInputSchema,
5406
5447
  outputSchema: recordOutputSchema("browser_profile_connect", BrowserProfileConnectOutputSchema),
5407
5448
  annotations: annotations("Save a Site Login to a Profile")
5408
5449
  },
5409
5450
  async (input) => {
5410
- const domain = slugPart(input.domain) || "chatgpt.com";
5451
+ const domain = normalizeDomain2(input.domain) || "chatgpt.com";
5411
5452
  const setupUrl = input.login_url ?? input.url ?? (domain === "chatgpt.com" ? "https://chatgpt.com/" : `https://${domain}/`);
5412
5453
  const profile = input.profile?.trim() || savedProfileNameFromEmail(input.email) || browserServiceProfileName();
5413
5454
  if (!profile) {
@@ -5423,14 +5464,15 @@ function registerBrowserAgentMcpTools(server, opts) {
5423
5464
  domain,
5424
5465
  login_url: setupUrl,
5425
5466
  ...accountEmail ? { account_email: accountEmail } : {},
5426
- ...note ? { note } : {}
5467
+ ...note ? { note } : {},
5468
+ ...typeof input.timeout_seconds === "number" ? { timeout_seconds: input.timeout_seconds } : {}
5427
5469
  });
5428
5470
  if (!open.ok) return errorResult("browser_profile_connect", open.data);
5429
5471
  const connectedLogins = await fetchConnectedLogins(profile).catch(() => []);
5430
5472
  return structuredResult({
5431
5473
  ok: true,
5432
5474
  tool: "browser_profile_connect",
5433
- session_id: null,
5475
+ session_id: open.data.browser_session_id ?? null,
5434
5476
  auth_connection_id: open.data.connection_id,
5435
5477
  watch_url: `${consoleBase}/console/auth/${open.data.connection_id}`,
5436
5478
  live_view_url: null,
@@ -5440,13 +5482,13 @@ function registerBrowserAgentMcpTools(server, opts) {
5440
5482
  account_email: accountEmail,
5441
5483
  note,
5442
5484
  status: open.data.status ?? null,
5443
- flow_status: open.data.flow_status ?? null,
5444
- flow_step: open.data.flow_step ?? null,
5445
- flow_expires_at: open.data.flow_expires_at ?? null,
5446
- post_login_url: open.data.post_login_url ?? null,
5485
+ flow_status: null,
5486
+ flow_step: null,
5487
+ flow_expires_at: null,
5488
+ post_login_url: null,
5447
5489
  connected_logins: connectedLogins,
5448
5490
  next_steps: [
5449
- `Give the user watch_url so they can sign in to ${domain}.`,
5491
+ `Give the user watch_url so they can sign in to ${domain} directly in that page, then click "Done \u2014 I'm signed in".`,
5450
5492
  "Poll browser_profile_list (with this profile) until the login reads AUTHENTICATED.",
5451
5493
  "To add another account to this same profile, call browser_profile_connect again with the same profile and a different domain.",
5452
5494
  "When authenticated, call browser_open with this profile to drive the logged-in session."
@@ -5471,7 +5513,7 @@ function registerBrowserAgentMcpTools(server, opts) {
5471
5513
  error: "profile or email is required when BROWSER_AGENT_PROFILE_NAME is not available"
5472
5514
  });
5473
5515
  }
5474
- const domain = slugPart(input.domain) || void 0;
5516
+ const domain = normalizeDomain2(input.domain) || void 0;
5475
5517
  const res = await req("POST", "/agent/profiles/list", {
5476
5518
  profile,
5477
5519
  ...domain ? { domain } : {},
@@ -8054,4 +8096,4 @@ export {
8054
8096
  registerMemoryMcpTools,
8055
8097
  MemoryMcpToolExecutor
8056
8098
  };
8057
- //# sourceMappingURL=chunk-QUOZ3LZG.js.map
8099
+ //# sourceMappingURL=chunk-GFY6XHZS.js.map