@iflow-mcp/jakeliume-webpeel 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +313 -0
- package/dist/cache.d.ts +30 -0
- package/dist/cache.js +139 -0
- package/dist/cli/commands/auth.d.ts +5 -0
- package/dist/cli/commands/auth.js +411 -0
- package/dist/cli/commands/doctor.d.ts +37 -0
- package/dist/cli/commands/doctor.js +371 -0
- package/dist/cli/commands/fetch.d.ts +6 -0
- package/dist/cli/commands/fetch.js +1345 -0
- package/dist/cli/commands/guide.d.ts +2 -0
- package/dist/cli/commands/guide.js +183 -0
- package/dist/cli/commands/interact.d.ts +5 -0
- package/dist/cli/commands/interact.js +840 -0
- package/dist/cli/commands/jobs.d.ts +5 -0
- package/dist/cli/commands/jobs.js +997 -0
- package/dist/cli/commands/monitor.d.ts +12 -0
- package/dist/cli/commands/monitor.js +197 -0
- package/dist/cli/commands/observe.d.ts +12 -0
- package/dist/cli/commands/observe.js +158 -0
- package/dist/cli/commands/screenshot.d.ts +5 -0
- package/dist/cli/commands/screenshot.js +282 -0
- package/dist/cli/commands/search.d.ts +5 -0
- package/dist/cli/commands/search.js +1021 -0
- package/dist/cli/commands/setup.d.ts +13 -0
- package/dist/cli/commands/setup.js +244 -0
- package/dist/cli/commands/skill.d.ts +15 -0
- package/dist/cli/commands/skill.js +195 -0
- package/dist/cli/utils.d.ts +84 -0
- package/dist/cli/utils.js +806 -0
- package/dist/cli-auth.d.ts +75 -0
- package/dist/cli-auth.js +369 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.js +99 -0
- package/dist/core/actions.d.ts +69 -0
- package/dist/core/actions.js +495 -0
- package/dist/core/agent.d.ts +98 -0
- package/dist/core/agent.js +558 -0
- package/dist/core/answer.d.ts +42 -0
- package/dist/core/answer.js +395 -0
- package/dist/core/application-tracker.d.ts +84 -0
- package/dist/core/application-tracker.js +184 -0
- package/dist/core/apply.d.ts +162 -0
- package/dist/core/apply.js +816 -0
- package/dist/core/auth-detection.d.ts +35 -0
- package/dist/core/auth-detection.js +358 -0
- package/dist/core/auto-extract.d.ts +82 -0
- package/dist/core/auto-extract.js +604 -0
- package/dist/core/auto-interact.d.ts +23 -0
- package/dist/core/auto-interact.js +246 -0
- package/dist/core/bm25-filter.d.ts +66 -0
- package/dist/core/bm25-filter.js +288 -0
- package/dist/core/branding.d.ts +54 -0
- package/dist/core/branding.js +234 -0
- package/dist/core/browser-fetch.d.ts +323 -0
- package/dist/core/browser-fetch.js +1600 -0
- package/dist/core/browser-pool.d.ts +91 -0
- package/dist/core/browser-pool.js +550 -0
- package/dist/core/budget.d.ts +42 -0
- package/dist/core/budget.js +324 -0
- package/dist/core/business-intel.d.ts +47 -0
- package/dist/core/business-intel.js +279 -0
- package/dist/core/cache.d.ts +13 -0
- package/dist/core/cache.js +121 -0
- package/dist/core/cf-worker-proxy.d.ts +32 -0
- package/dist/core/cf-worker-proxy.js +87 -0
- package/dist/core/challenge-detection.d.ts +26 -0
- package/dist/core/challenge-detection.js +468 -0
- package/dist/core/change-tracking.d.ts +75 -0
- package/dist/core/change-tracking.js +276 -0
- package/dist/core/chunker.d.ts +46 -0
- package/dist/core/chunker.js +249 -0
- package/dist/core/chunking.d.ts +42 -0
- package/dist/core/chunking.js +181 -0
- package/dist/core/circuit-breaker.d.ts +44 -0
- package/dist/core/circuit-breaker.js +85 -0
- package/dist/core/content-pruner.d.ts +47 -0
- package/dist/core/content-pruner.js +425 -0
- package/dist/core/cookie-cache.d.ts +60 -0
- package/dist/core/cookie-cache.js +163 -0
- package/dist/core/crawl-checkpoint.d.ts +54 -0
- package/dist/core/crawl-checkpoint.js +104 -0
- package/dist/core/crawler.d.ts +84 -0
- package/dist/core/crawler.js +349 -0
- package/dist/core/cross-verify.d.ts +27 -0
- package/dist/core/cross-verify.js +93 -0
- package/dist/core/deep-fetch.d.ts +74 -0
- package/dist/core/deep-fetch.js +405 -0
- package/dist/core/deep-research.d.ts +141 -0
- package/dist/core/deep-research.js +972 -0
- package/dist/core/design-analysis.d.ts +70 -0
- package/dist/core/design-analysis.js +490 -0
- package/dist/core/design-compare.d.ts +38 -0
- package/dist/core/design-compare.js +264 -0
- package/dist/core/diff.d.ts +61 -0
- package/dist/core/diff.js +289 -0
- package/dist/core/dns-cache.d.ts +20 -0
- package/dist/core/dns-cache.js +198 -0
- package/dist/core/documents.d.ts +23 -0
- package/dist/core/documents.js +123 -0
- package/dist/core/domain-memory.d.ts +66 -0
- package/dist/core/domain-memory.js +163 -0
- package/dist/core/domain-verify.d.ts +40 -0
- package/dist/core/domain-verify.js +379 -0
- package/dist/core/engine-ranker.d.ts +112 -0
- package/dist/core/engine-ranker.js +395 -0
- package/dist/core/extract-inline.d.ts +38 -0
- package/dist/core/extract-inline.js +215 -0
- package/dist/core/extract-listings.d.ts +38 -0
- package/dist/core/extract-listings.js +461 -0
- package/dist/core/extract.d.ts +9 -0
- package/dist/core/extract.js +139 -0
- package/dist/core/fetch-cache.d.ts +57 -0
- package/dist/core/fetch-cache.js +95 -0
- package/dist/core/fetcher.d.ts +13 -0
- package/dist/core/fetcher.js +12 -0
- package/dist/core/google-cache.d.ts +29 -0
- package/dist/core/google-cache.js +180 -0
- package/dist/core/google-serp-parser.d.ts +82 -0
- package/dist/core/google-serp-parser.js +287 -0
- package/dist/core/hotel-search.d.ts +122 -0
- package/dist/core/hotel-search.js +382 -0
- package/dist/core/http-fetch.d.ts +72 -0
- package/dist/core/http-fetch.js +820 -0
- package/dist/core/human.d.ts +175 -0
- package/dist/core/human.js +680 -0
- package/dist/core/image-caption.d.ts +44 -0
- package/dist/core/image-caption.js +271 -0
- package/dist/core/jobs.d.ts +75 -0
- package/dist/core/jobs.js +634 -0
- package/dist/core/json-ld.d.ts +15 -0
- package/dist/core/json-ld.js +617 -0
- package/dist/core/language-detect.d.ts +18 -0
- package/dist/core/language-detect.js +135 -0
- package/dist/core/links.d.ts +10 -0
- package/dist/core/links.js +44 -0
- package/dist/core/llm-extract.d.ts +71 -0
- package/dist/core/llm-extract.js +507 -0
- package/dist/core/llm-provider.d.ts +100 -0
- package/dist/core/llm-provider.js +702 -0
- package/dist/core/local-search.d.ts +60 -0
- package/dist/core/local-search.js +308 -0
- package/dist/core/logger.d.ts +28 -0
- package/dist/core/logger.js +104 -0
- package/dist/core/map.d.ts +33 -0
- package/dist/core/map.js +127 -0
- package/dist/core/markdown.d.ts +92 -0
- package/dist/core/markdown.js +809 -0
- package/dist/core/metadata.d.ts +34 -0
- package/dist/core/metadata.js +422 -0
- package/dist/core/observe.d.ts +113 -0
- package/dist/core/observe.js +395 -0
- package/dist/core/ocr.d.ts +12 -0
- package/dist/core/ocr.js +33 -0
- package/dist/core/paginate.d.ts +31 -0
- package/dist/core/paginate.js +106 -0
- package/dist/core/pdf.d.ts +8 -0
- package/dist/core/pdf.js +25 -0
- package/dist/core/peel-tls.d.ts +25 -0
- package/dist/core/peel-tls.js +220 -0
- package/dist/core/pipeline.d.ts +132 -0
- package/dist/core/pipeline.js +1666 -0
- package/dist/core/profiles.d.ts +61 -0
- package/dist/core/profiles.js +350 -0
- package/dist/core/prompt-guard.d.ts +30 -0
- package/dist/core/prompt-guard.js +119 -0
- package/dist/core/proxy-config.d.ts +90 -0
- package/dist/core/proxy-config.js +172 -0
- package/dist/core/quick-answer.d.ts +53 -0
- package/dist/core/quick-answer.js +833 -0
- package/dist/core/rate-governor.d.ts +80 -0
- package/dist/core/rate-governor.js +238 -0
- package/dist/core/readability.d.ts +57 -0
- package/dist/core/readability.js +533 -0
- package/dist/core/research.d.ts +66 -0
- package/dist/core/research.js +270 -0
- package/dist/core/retry.d.ts +60 -0
- package/dist/core/retry.js +119 -0
- package/dist/core/safe-browsing.d.ts +30 -0
- package/dist/core/safe-browsing.js +206 -0
- package/dist/core/schema-extraction.d.ts +66 -0
- package/dist/core/schema-extraction.js +352 -0
- package/dist/core/schema-postprocess.d.ts +32 -0
- package/dist/core/schema-postprocess.js +469 -0
- package/dist/core/schema-templates.d.ts +19 -0
- package/dist/core/schema-templates.js +143 -0
- package/dist/core/screenshot.d.ts +224 -0
- package/dist/core/screenshot.js +207 -0
- package/dist/core/search-engines.d.ts +25 -0
- package/dist/core/search-engines.js +182 -0
- package/dist/core/search-provider.d.ts +243 -0
- package/dist/core/search-provider.js +1629 -0
- package/dist/core/searxng-provider.d.ts +35 -0
- package/dist/core/searxng-provider.js +105 -0
- package/dist/core/selective-evidence.d.ts +151 -0
- package/dist/core/selective-evidence.js +389 -0
- package/dist/core/site-search.d.ts +44 -0
- package/dist/core/site-search.js +252 -0
- package/dist/core/sitemap.d.ts +23 -0
- package/dist/core/sitemap.js +105 -0
- package/dist/core/source-credibility.d.ts +29 -0
- package/dist/core/source-credibility.js +584 -0
- package/dist/core/source-scoring.d.ts +166 -0
- package/dist/core/source-scoring.js +396 -0
- package/dist/core/stemmer.d.ts +38 -0
- package/dist/core/stemmer.js +509 -0
- package/dist/core/strategies.d.ts +104 -0
- package/dist/core/strategies.js +1044 -0
- package/dist/core/strategy-hooks.d.ts +145 -0
- package/dist/core/strategy-hooks.js +74 -0
- package/dist/core/structured-extract.d.ts +43 -0
- package/dist/core/structured-extract.js +550 -0
- package/dist/core/summarize.d.ts +17 -0
- package/dist/core/summarize.js +78 -0
- package/dist/core/synonyms.d.ts +42 -0
- package/dist/core/synonyms.js +184 -0
- package/dist/core/system-monitor.d.ts +61 -0
- package/dist/core/system-monitor.js +133 -0
- package/dist/core/table-format.d.ts +30 -0
- package/dist/core/table-format.js +146 -0
- package/dist/core/threat-feeds.d.ts +23 -0
- package/dist/core/threat-feeds.js +104 -0
- package/dist/core/timing.d.ts +21 -0
- package/dist/core/timing.js +33 -0
- package/dist/core/transcript-export.d.ts +47 -0
- package/dist/core/transcript-export.js +107 -0
- package/dist/core/user-agents.d.ts +82 -0
- package/dist/core/user-agents.js +239 -0
- package/dist/core/vertical-search.d.ts +54 -0
- package/dist/core/vertical-search.js +158 -0
- package/dist/core/watch-manager.d.ts +175 -0
- package/dist/core/watch-manager.js +416 -0
- package/dist/core/watch.d.ts +101 -0
- package/dist/core/watch.js +389 -0
- package/dist/core/youtube.d.ts +130 -0
- package/dist/core/youtube.js +1175 -0
- package/dist/ee/challenge-re-export.d.ts +1 -0
- package/dist/ee/challenge-re-export.js +1 -0
- package/dist/ee/challenge-solver.d.ts +72 -0
- package/dist/ee/challenge-solver.js +720 -0
- package/dist/ee/domain-extractors.d.ts +8 -0
- package/dist/ee/domain-extractors.js +8 -0
- package/dist/ee/domain-intel.d.ts +16 -0
- package/dist/ee/domain-intel.js +133 -0
- package/dist/ee/extractors/allrecipes.d.ts +2 -0
- package/dist/ee/extractors/allrecipes.js +120 -0
- package/dist/ee/extractors/amazon.d.ts +2 -0
- package/dist/ee/extractors/amazon.js +78 -0
- package/dist/ee/extractors/arxiv.d.ts +2 -0
- package/dist/ee/extractors/arxiv.js +137 -0
- package/dist/ee/extractors/bestbuy.d.ts +2 -0
- package/dist/ee/extractors/bestbuy.js +78 -0
- package/dist/ee/extractors/carscom.d.ts +2 -0
- package/dist/ee/extractors/carscom.js +121 -0
- package/dist/ee/extractors/coingecko.d.ts +2 -0
- package/dist/ee/extractors/coingecko.js +134 -0
- package/dist/ee/extractors/craigslist.d.ts +2 -0
- package/dist/ee/extractors/craigslist.js +92 -0
- package/dist/ee/extractors/devto.d.ts +2 -0
- package/dist/ee/extractors/devto.js +135 -0
- package/dist/ee/extractors/ebay.d.ts +2 -0
- package/dist/ee/extractors/ebay.js +90 -0
- package/dist/ee/extractors/espn.d.ts +2 -0
- package/dist/ee/extractors/espn.js +260 -0
- package/dist/ee/extractors/etsy.d.ts +2 -0
- package/dist/ee/extractors/etsy.js +52 -0
- package/dist/ee/extractors/facebook.d.ts +2 -0
- package/dist/ee/extractors/facebook.js +46 -0
- package/dist/ee/extractors/github.d.ts +2 -0
- package/dist/ee/extractors/github.js +196 -0
- package/dist/ee/extractors/google-flights.d.ts +2 -0
- package/dist/ee/extractors/google-flights.js +176 -0
- package/dist/ee/extractors/hackernews.d.ts +2 -0
- package/dist/ee/extractors/hackernews.js +147 -0
- package/dist/ee/extractors/imdb.d.ts +2 -0
- package/dist/ee/extractors/imdb.js +172 -0
- package/dist/ee/extractors/index.d.ts +26 -0
- package/dist/ee/extractors/index.js +247 -0
- package/dist/ee/extractors/instagram.d.ts +2 -0
- package/dist/ee/extractors/instagram.js +102 -0
- package/dist/ee/extractors/kalshi.d.ts +2 -0
- package/dist/ee/extractors/kalshi.js +121 -0
- package/dist/ee/extractors/kayak-cars.d.ts +2 -0
- package/dist/ee/extractors/kayak-cars.js +270 -0
- package/dist/ee/extractors/linkedin.d.ts +2 -0
- package/dist/ee/extractors/linkedin.js +113 -0
- package/dist/ee/extractors/medium.d.ts +2 -0
- package/dist/ee/extractors/medium.js +130 -0
- package/dist/ee/extractors/news.d.ts +4 -0
- package/dist/ee/extractors/news.js +173 -0
- package/dist/ee/extractors/npm.d.ts +2 -0
- package/dist/ee/extractors/npm.js +86 -0
- package/dist/ee/extractors/pdf.d.ts +2 -0
- package/dist/ee/extractors/pdf.js +108 -0
- package/dist/ee/extractors/pinterest.d.ts +2 -0
- package/dist/ee/extractors/pinterest.js +34 -0
- package/dist/ee/extractors/polymarket.d.ts +2 -0
- package/dist/ee/extractors/polymarket.js +358 -0
- package/dist/ee/extractors/producthunt.d.ts +2 -0
- package/dist/ee/extractors/producthunt.js +88 -0
- package/dist/ee/extractors/pubmed.d.ts +2 -0
- package/dist/ee/extractors/pubmed.js +162 -0
- package/dist/ee/extractors/pypi.d.ts +2 -0
- package/dist/ee/extractors/pypi.js +80 -0
- package/dist/ee/extractors/reddit.d.ts +2 -0
- package/dist/ee/extractors/reddit.js +438 -0
- package/dist/ee/extractors/redfin.d.ts +2 -0
- package/dist/ee/extractors/redfin.js +156 -0
- package/dist/ee/extractors/semanticscholar.d.ts +2 -0
- package/dist/ee/extractors/semanticscholar.js +131 -0
- package/dist/ee/extractors/shared.d.ts +12 -0
- package/dist/ee/extractors/shared.js +76 -0
- package/dist/ee/extractors/soundcloud.d.ts +2 -0
- package/dist/ee/extractors/soundcloud.js +34 -0
- package/dist/ee/extractors/sportsbetting.d.ts +2 -0
- package/dist/ee/extractors/sportsbetting.js +37 -0
- package/dist/ee/extractors/spotify.d.ts +2 -0
- package/dist/ee/extractors/spotify.js +34 -0
- package/dist/ee/extractors/stackoverflow.d.ts +2 -0
- package/dist/ee/extractors/stackoverflow.js +61 -0
- package/dist/ee/extractors/substack.d.ts +2 -0
- package/dist/ee/extractors/substack.js +115 -0
- package/dist/ee/extractors/substackroot.d.ts +2 -0
- package/dist/ee/extractors/substackroot.js +46 -0
- package/dist/ee/extractors/tiktok.d.ts +2 -0
- package/dist/ee/extractors/tiktok.js +29 -0
- package/dist/ee/extractors/tradingview.d.ts +2 -0
- package/dist/ee/extractors/tradingview.js +182 -0
- package/dist/ee/extractors/twitch.d.ts +2 -0
- package/dist/ee/extractors/twitch.js +36 -0
- package/dist/ee/extractors/twitter.d.ts +2 -0
- package/dist/ee/extractors/twitter.js +327 -0
- package/dist/ee/extractors/types.d.ts +14 -0
- package/dist/ee/extractors/types.js +1 -0
- package/dist/ee/extractors/walmart.d.ts +2 -0
- package/dist/ee/extractors/walmart.js +50 -0
- package/dist/ee/extractors/weather.d.ts +2 -0
- package/dist/ee/extractors/weather.js +133 -0
- package/dist/ee/extractors/wikipedia.d.ts +4 -0
- package/dist/ee/extractors/wikipedia.js +235 -0
- package/dist/ee/extractors/yelp.d.ts +2 -0
- package/dist/ee/extractors/yelp.js +216 -0
- package/dist/ee/extractors/youtube.d.ts +2 -0
- package/dist/ee/extractors/youtube.js +189 -0
- package/dist/ee/extractors/zillow.d.ts +54 -0
- package/dist/ee/extractors/zillow.js +247 -0
- package/dist/ee/extractors-re-export.d.ts +1 -0
- package/dist/ee/extractors-re-export.js +1 -0
- package/dist/ee/premium-hooks.d.ts +20 -0
- package/dist/ee/premium-hooks.js +50 -0
- package/dist/ee/spa-detection.d.ts +2 -0
- package/dist/ee/spa-detection.js +2 -0
- package/dist/ee/stability.d.ts +4 -0
- package/dist/ee/stability.js +29 -0
- package/dist/ee/swr-cache.d.ts +14 -0
- package/dist/ee/swr-cache.js +34 -0
- package/dist/index.d.ts +143 -0
- package/dist/index.js +291 -0
- package/dist/integrations/index.d.ts +2 -0
- package/dist/integrations/index.js +2 -0
- package/dist/integrations/langchain.d.ts +64 -0
- package/dist/integrations/langchain.js +115 -0
- package/dist/integrations/llamaindex.d.ts +50 -0
- package/dist/integrations/llamaindex.js +91 -0
- package/dist/mcp/handlers/act.d.ts +5 -0
- package/dist/mcp/handlers/act.js +34 -0
- package/dist/mcp/handlers/definitions.d.ts +6 -0
- package/dist/mcp/handlers/definitions.js +395 -0
- package/dist/mcp/handlers/extract.d.ts +7 -0
- package/dist/mcp/handlers/extract.js +135 -0
- package/dist/mcp/handlers/fetch.d.ts +6 -0
- package/dist/mcp/handlers/fetch.js +98 -0
- package/dist/mcp/handlers/find.d.ts +5 -0
- package/dist/mcp/handlers/find.js +137 -0
- package/dist/mcp/handlers/index.d.ts +13 -0
- package/dist/mcp/handlers/index.js +63 -0
- package/dist/mcp/handlers/legacy.d.ts +25 -0
- package/dist/mcp/handlers/legacy.js +450 -0
- package/dist/mcp/handlers/meta.d.ts +6 -0
- package/dist/mcp/handlers/meta.js +40 -0
- package/dist/mcp/handlers/monitor.d.ts +5 -0
- package/dist/mcp/handlers/monitor.js +41 -0
- package/dist/mcp/handlers/observe.d.ts +8 -0
- package/dist/mcp/handlers/observe.js +37 -0
- package/dist/mcp/handlers/read.d.ts +6 -0
- package/dist/mcp/handlers/read.js +78 -0
- package/dist/mcp/handlers/see.d.ts +5 -0
- package/dist/mcp/handlers/see.js +75 -0
- package/dist/mcp/handlers/types.d.ts +29 -0
- package/dist/mcp/handlers/types.js +28 -0
- package/dist/mcp/server.d.ts +7 -0
- package/dist/mcp/server.js +108 -0
- package/dist/mcp/smart-router.d.ts +23 -0
- package/dist/mcp/smart-router.js +178 -0
- package/dist/server/app.d.ts +14 -0
- package/dist/server/app.js +632 -0
- package/dist/server/auth-store.d.ts +28 -0
- package/dist/server/auth-store.js +88 -0
- package/dist/server/bull-queues.d.ts +60 -0
- package/dist/server/bull-queues.js +90 -0
- package/dist/server/email-service.d.ts +55 -0
- package/dist/server/email-service.js +291 -0
- package/dist/server/job-queue.d.ts +100 -0
- package/dist/server/job-queue.js +145 -0
- package/dist/server/logger.d.ts +10 -0
- package/dist/server/logger.js +37 -0
- package/dist/server/middleware/audit-log.d.ts +14 -0
- package/dist/server/middleware/audit-log.js +73 -0
- package/dist/server/middleware/auth.d.ts +35 -0
- package/dist/server/middleware/auth.js +225 -0
- package/dist/server/middleware/rate-limit.d.ts +50 -0
- package/dist/server/middleware/rate-limit.js +270 -0
- package/dist/server/middleware/scope-guard.d.ts +25 -0
- package/dist/server/middleware/scope-guard.js +45 -0
- package/dist/server/middleware/url-validator.d.ts +15 -0
- package/dist/server/middleware/url-validator.js +201 -0
- package/dist/server/openapi.yaml +6418 -0
- package/dist/server/pg-auth-store.d.ts +146 -0
- package/dist/server/pg-auth-store.js +576 -0
- package/dist/server/pg-job-queue.d.ts +59 -0
- package/dist/server/pg-job-queue.js +375 -0
- package/dist/server/routes/activity.d.ts +6 -0
- package/dist/server/routes/activity.js +79 -0
- package/dist/server/routes/admin-active.d.ts +7 -0
- package/dist/server/routes/admin-active.js +120 -0
- package/dist/server/routes/admin-stats.d.ts +7 -0
- package/dist/server/routes/admin-stats.js +176 -0
- package/dist/server/routes/agent.d.ts +24 -0
- package/dist/server/routes/agent.js +480 -0
- package/dist/server/routes/answer.d.ts +5 -0
- package/dist/server/routes/answer.js +125 -0
- package/dist/server/routes/ask.d.ts +28 -0
- package/dist/server/routes/ask.js +295 -0
- package/dist/server/routes/batch.d.ts +6 -0
- package/dist/server/routes/batch.js +493 -0
- package/dist/server/routes/cache-warm.d.ts +25 -0
- package/dist/server/routes/cache-warm.js +212 -0
- package/dist/server/routes/cli-usage.d.ts +6 -0
- package/dist/server/routes/cli-usage.js +127 -0
- package/dist/server/routes/compat.d.ts +23 -0
- package/dist/server/routes/compat.js +652 -0
- package/dist/server/routes/crawl.d.ts +13 -0
- package/dist/server/routes/crawl.js +287 -0
- package/dist/server/routes/deep-fetch.d.ts +8 -0
- package/dist/server/routes/deep-fetch.js +57 -0
- package/dist/server/routes/deep-research.d.ts +11 -0
- package/dist/server/routes/deep-research.js +232 -0
- package/dist/server/routes/demo.d.ts +24 -0
- package/dist/server/routes/demo.js +517 -0
- package/dist/server/routes/do.d.ts +8 -0
- package/dist/server/routes/do.js +72 -0
- package/dist/server/routes/extract.d.ts +14 -0
- package/dist/server/routes/extract.js +325 -0
- package/dist/server/routes/feed.d.ts +15 -0
- package/dist/server/routes/feed.js +311 -0
- package/dist/server/routes/fetch-queue.d.ts +13 -0
- package/dist/server/routes/fetch-queue.js +357 -0
- package/dist/server/routes/fetch.d.ts +7 -0
- package/dist/server/routes/fetch.js +1274 -0
- package/dist/server/routes/go.d.ts +14 -0
- package/dist/server/routes/go.js +81 -0
- package/dist/server/routes/health.d.ts +11 -0
- package/dist/server/routes/health.js +141 -0
- package/dist/server/routes/jobs.d.ts +7 -0
- package/dist/server/routes/jobs.js +574 -0
- package/dist/server/routes/map.d.ts +11 -0
- package/dist/server/routes/map.js +116 -0
- package/dist/server/routes/mcp.d.ts +14 -0
- package/dist/server/routes/mcp.js +197 -0
- package/dist/server/routes/metrics.d.ts +37 -0
- package/dist/server/routes/metrics.js +149 -0
- package/dist/server/routes/oauth.d.ts +9 -0
- package/dist/server/routes/oauth.js +396 -0
- package/dist/server/routes/playground.d.ts +17 -0
- package/dist/server/routes/playground.js +283 -0
- package/dist/server/routes/reader.d.ts +18 -0
- package/dist/server/routes/reader.js +192 -0
- package/dist/server/routes/research.d.ts +14 -0
- package/dist/server/routes/research.js +482 -0
- package/dist/server/routes/screenshot.d.ts +22 -0
- package/dist/server/routes/screenshot.js +820 -0
- package/dist/server/routes/search.d.ts +6 -0
- package/dist/server/routes/search.js +874 -0
- package/dist/server/routes/session.d.ts +17 -0
- package/dist/server/routes/session.js +548 -0
- package/dist/server/routes/share.d.ts +18 -0
- package/dist/server/routes/share.js +462 -0
- package/dist/server/routes/smart-search/handlers/cars.d.ts +2 -0
- package/dist/server/routes/smart-search/handlers/cars.js +102 -0
- package/dist/server/routes/smart-search/handlers/flights.d.ts +2 -0
- package/dist/server/routes/smart-search/handlers/flights.js +72 -0
- package/dist/server/routes/smart-search/handlers/general.d.ts +13 -0
- package/dist/server/routes/smart-search/handlers/general.js +717 -0
- package/dist/server/routes/smart-search/handlers/hotels.d.ts +2 -0
- package/dist/server/routes/smart-search/handlers/hotels.js +88 -0
- package/dist/server/routes/smart-search/handlers/products.d.ts +2 -0
- package/dist/server/routes/smart-search/handlers/products.js +1309 -0
- package/dist/server/routes/smart-search/handlers/rental.d.ts +2 -0
- package/dist/server/routes/smart-search/handlers/rental.js +154 -0
- package/dist/server/routes/smart-search/handlers/restaurants.d.ts +2 -0
- package/dist/server/routes/smart-search/handlers/restaurants.js +225 -0
- package/dist/server/routes/smart-search/handlers/transit-verdict.d.ts +41 -0
- package/dist/server/routes/smart-search/handlers/transit-verdict.js +224 -0
- package/dist/server/routes/smart-search/index.d.ts +19 -0
- package/dist/server/routes/smart-search/index.js +546 -0
- package/dist/server/routes/smart-search/intent.d.ts +3 -0
- package/dist/server/routes/smart-search/intent.js +264 -0
- package/dist/server/routes/smart-search/llm.d.ts +16 -0
- package/dist/server/routes/smart-search/llm.js +70 -0
- package/dist/server/routes/smart-search/sources/reddit.d.ts +18 -0
- package/dist/server/routes/smart-search/sources/reddit.js +34 -0
- package/dist/server/routes/smart-search/sources/yelp.d.ts +25 -0
- package/dist/server/routes/smart-search/sources/yelp.js +171 -0
- package/dist/server/routes/smart-search/sources/youtube.d.ts +8 -0
- package/dist/server/routes/smart-search/sources/youtube.js +9 -0
- package/dist/server/routes/smart-search/types.d.ts +81 -0
- package/dist/server/routes/smart-search/types.js +1 -0
- package/dist/server/routes/smart-search/utils.d.ts +20 -0
- package/dist/server/routes/smart-search/utils.js +146 -0
- package/dist/server/routes/stats.d.ts +6 -0
- package/dist/server/routes/stats.js +71 -0
- package/dist/server/routes/stripe.d.ts +15 -0
- package/dist/server/routes/stripe.js +296 -0
- package/dist/server/routes/transcript-export.d.ts +10 -0
- package/dist/server/routes/transcript-export.js +178 -0
- package/dist/server/routes/usage.d.ts +9 -0
- package/dist/server/routes/usage.js +279 -0
- package/dist/server/routes/users.d.ts +8 -0
- package/dist/server/routes/users.js +1867 -0
- package/dist/server/routes/watch.d.ts +15 -0
- package/dist/server/routes/watch.js +309 -0
- package/dist/server/routes/webhooks.d.ts +26 -0
- package/dist/server/routes/webhooks.js +170 -0
- package/dist/server/routes/youtube.d.ts +6 -0
- package/dist/server/routes/youtube.js +130 -0
- package/dist/server/sentry.d.ts +14 -0
- package/dist/server/sentry.js +104 -0
- package/dist/server/types.d.ts +15 -0
- package/dist/server/types.js +7 -0
- package/dist/server/utils/response.d.ts +44 -0
- package/dist/server/utils/response.js +69 -0
- package/dist/server/utils/sse.d.ts +22 -0
- package/dist/server/utils/sse.js +38 -0
- package/dist/types.d.ts +552 -0
- package/dist/types.js +39 -0
- package/llms.txt +105 -0
- package/package.json +189 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* local-search.ts — Local business search using Google Places API (Text Search)
|
|
3
|
+
*
|
|
4
|
+
* Primary: Google Places Text Search (New) API
|
|
5
|
+
* Secondary: Yelp Fusion API
|
|
6
|
+
* Fallback: peel() scraping Google Maps
|
|
7
|
+
*/
|
|
8
|
+
export interface LocalSearchOptions {
|
|
9
|
+
query: string;
|
|
10
|
+
location?: string;
|
|
11
|
+
country?: string;
|
|
12
|
+
language?: string;
|
|
13
|
+
radius?: number;
|
|
14
|
+
type?: string;
|
|
15
|
+
limit?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface LocalSearchResult {
|
|
18
|
+
name: string;
|
|
19
|
+
address: string;
|
|
20
|
+
rating?: number;
|
|
21
|
+
reviewCount?: number;
|
|
22
|
+
priceLevel?: number;
|
|
23
|
+
categories?: string[];
|
|
24
|
+
phone?: string;
|
|
25
|
+
website?: string;
|
|
26
|
+
googleMapsUrl?: string;
|
|
27
|
+
isOpen?: boolean;
|
|
28
|
+
hours?: string[];
|
|
29
|
+
location?: {
|
|
30
|
+
lat: number;
|
|
31
|
+
lng: number;
|
|
32
|
+
};
|
|
33
|
+
photos?: string[];
|
|
34
|
+
}
|
|
35
|
+
export interface LocalSearchResponse {
|
|
36
|
+
results: LocalSearchResult[];
|
|
37
|
+
query: string;
|
|
38
|
+
location?: string;
|
|
39
|
+
source: 'google-places' | 'yelp' | 'fallback';
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Search for local businesses/places using the best available source.
|
|
43
|
+
*
|
|
44
|
+
* Priority order:
|
|
45
|
+
* 1. Google Places Text Search (New) API — requires GOOGLE_PLACES_API_KEY
|
|
46
|
+
* 2. Yelp Fusion API — requires YELP_API_KEY (merged with Google if both available)
|
|
47
|
+
* 3. Google Maps scraping via peel() — no API key required, slowest
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const results = await localSearch({
|
|
52
|
+
* query: 'best sushi',
|
|
53
|
+
* location: 'Shibuya, Tokyo',
|
|
54
|
+
* language: 'ja',
|
|
55
|
+
* country: 'JP',
|
|
56
|
+
* });
|
|
57
|
+
* console.log(results.results[0].name); // "寿司 さわ"
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare function localSearch(opts: LocalSearchOptions): Promise<LocalSearchResponse>;
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* local-search.ts — Local business search using Google Places API (Text Search)
|
|
3
|
+
*
|
|
4
|
+
* Primary: Google Places Text Search (New) API
|
|
5
|
+
* Secondary: Yelp Fusion API
|
|
6
|
+
* Fallback: peel() scraping Google Maps
|
|
7
|
+
*/
|
|
8
|
+
import { peel } from '../index.js';
|
|
9
|
+
// ─── Google Places Text Search (New) API ─────────────────────────────────
|
|
10
|
+
const GOOGLE_PLACES_FIELD_MASK = [
|
|
11
|
+
'places.displayName',
|
|
12
|
+
'places.formattedAddress',
|
|
13
|
+
'places.rating',
|
|
14
|
+
'places.userRatingCount',
|
|
15
|
+
'places.priceLevel',
|
|
16
|
+
'places.currentOpeningHours',
|
|
17
|
+
'places.googleMapsUri',
|
|
18
|
+
'places.websiteUri',
|
|
19
|
+
'places.internationalPhoneNumber',
|
|
20
|
+
'places.types',
|
|
21
|
+
'places.location',
|
|
22
|
+
'places.photos',
|
|
23
|
+
].join(',');
|
|
24
|
+
/**
|
|
25
|
+
* Convert Google Places priceLevel string to numeric 0-4 scale.
|
|
26
|
+
* Google New API returns strings like "PRICE_LEVEL_MODERATE".
|
|
27
|
+
*/
|
|
28
|
+
function parsePriceLevel(raw) {
|
|
29
|
+
if (typeof raw === 'number')
|
|
30
|
+
return raw;
|
|
31
|
+
if (!raw)
|
|
32
|
+
return undefined;
|
|
33
|
+
const MAP = {
|
|
34
|
+
PRICE_LEVEL_FREE: 0,
|
|
35
|
+
PRICE_LEVEL_INEXPENSIVE: 1,
|
|
36
|
+
PRICE_LEVEL_MODERATE: 2,
|
|
37
|
+
PRICE_LEVEL_EXPENSIVE: 3,
|
|
38
|
+
PRICE_LEVEL_VERY_EXPENSIVE: 4,
|
|
39
|
+
};
|
|
40
|
+
return MAP[String(raw)] ?? undefined;
|
|
41
|
+
}
|
|
42
|
+
async function searchGooglePlaces(opts) {
|
|
43
|
+
const key = process.env.GOOGLE_PLACES_API_KEY;
|
|
44
|
+
if (!key)
|
|
45
|
+
return null;
|
|
46
|
+
// Build the text query — append location if not already in query
|
|
47
|
+
let textQuery = opts.query;
|
|
48
|
+
if (opts.location && !opts.query.toLowerCase().includes(opts.location.toLowerCase())) {
|
|
49
|
+
textQuery = `${opts.query} in ${opts.location}`;
|
|
50
|
+
}
|
|
51
|
+
const body = {
|
|
52
|
+
textQuery,
|
|
53
|
+
maxResultCount: Math.min(opts.limit ?? 10, 20),
|
|
54
|
+
};
|
|
55
|
+
if (opts.language)
|
|
56
|
+
body.languageCode = opts.language;
|
|
57
|
+
if (opts.country)
|
|
58
|
+
body.regionCode = opts.country;
|
|
59
|
+
if (opts.type)
|
|
60
|
+
body.includedType = opts.type;
|
|
61
|
+
// If location is lat,lng coordinates, add location bias
|
|
62
|
+
if (opts.location) {
|
|
63
|
+
const latLngMatch = opts.location.match(/^(-?\d+\.?\d*),\s*(-?\d+\.?\d*)$/);
|
|
64
|
+
if (latLngMatch) {
|
|
65
|
+
body.locationBias = {
|
|
66
|
+
circle: {
|
|
67
|
+
center: { latitude: parseFloat(latLngMatch[1]), longitude: parseFloat(latLngMatch[2]) },
|
|
68
|
+
radius: opts.radius ?? 5000,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const res = await fetch('https://places.googleapis.com/v1/places:searchText', {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
headers: {
|
|
77
|
+
'Content-Type': 'application/json',
|
|
78
|
+
'X-Goog-Api-Key': key,
|
|
79
|
+
'X-Goog-FieldMask': GOOGLE_PLACES_FIELD_MASK,
|
|
80
|
+
},
|
|
81
|
+
body: JSON.stringify(body),
|
|
82
|
+
signal: AbortSignal.timeout(8000),
|
|
83
|
+
});
|
|
84
|
+
if (!res.ok) {
|
|
85
|
+
console.warn(`[local-search] Google Places API ${res.status}: ${await res.text().catch(() => '')}`);
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const data = await res.json();
|
|
89
|
+
if (!data.places?.length)
|
|
90
|
+
return [];
|
|
91
|
+
return data.places.map((p) => {
|
|
92
|
+
// Build photo URLs
|
|
93
|
+
const photos = [];
|
|
94
|
+
if (p.photos?.length) {
|
|
95
|
+
for (const photo of p.photos.slice(0, 3)) {
|
|
96
|
+
if (photo.name) {
|
|
97
|
+
photos.push(`https://places.googleapis.com/v1/${photo.name}/media?maxHeightPx=400&key=${key}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Parse hours
|
|
102
|
+
const hours = p.currentOpeningHours?.weekdayDescriptions ?? [];
|
|
103
|
+
return {
|
|
104
|
+
name: p.displayName?.text ?? '',
|
|
105
|
+
address: p.formattedAddress ?? '',
|
|
106
|
+
rating: p.rating,
|
|
107
|
+
reviewCount: p.userRatingCount,
|
|
108
|
+
priceLevel: parsePriceLevel(p.priceLevel),
|
|
109
|
+
categories: p.types?.filter((t) => !t.startsWith('point_of_interest') && !t.startsWith('establishment')),
|
|
110
|
+
phone: p.internationalPhoneNumber,
|
|
111
|
+
website: p.websiteUri,
|
|
112
|
+
googleMapsUrl: p.googleMapsUri,
|
|
113
|
+
isOpen: p.currentOpeningHours?.openNow,
|
|
114
|
+
hours,
|
|
115
|
+
location: p.location ? { lat: p.location.latitude, lng: p.location.longitude } : undefined,
|
|
116
|
+
photos,
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
console.warn('[local-search] Google Places request failed:', err.message);
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// ─── Yelp Fusion API ──────────────────────────────────────────────────────
|
|
126
|
+
async function searchYelp(opts) {
|
|
127
|
+
const key = process.env.YELP_API_KEY;
|
|
128
|
+
if (!key)
|
|
129
|
+
return null;
|
|
130
|
+
try {
|
|
131
|
+
const params = new URLSearchParams({
|
|
132
|
+
term: opts.query,
|
|
133
|
+
limit: String(Math.min(opts.limit ?? 10, 50)),
|
|
134
|
+
sort_by: 'rating',
|
|
135
|
+
});
|
|
136
|
+
// Location can be an address string or lat,lng
|
|
137
|
+
if (opts.location) {
|
|
138
|
+
const latLngMatch = opts.location.match(/^(-?\d+\.?\d*),\s*(-?\d+\.?\d*)$/);
|
|
139
|
+
if (latLngMatch) {
|
|
140
|
+
params.set('latitude', latLngMatch[1]);
|
|
141
|
+
params.set('longitude', latLngMatch[2]);
|
|
142
|
+
params.set('radius', String(Math.min(opts.radius ?? 5000, 40000)));
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
params.set('location', opts.location);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
params.set('location', 'New York, NY');
|
|
150
|
+
}
|
|
151
|
+
if (opts.language)
|
|
152
|
+
params.set('locale', opts.language + '_' + (opts.country ?? '').toUpperCase());
|
|
153
|
+
const res = await fetch(`https://api.yelp.com/v3/businesses/search?${params}`, {
|
|
154
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
155
|
+
signal: AbortSignal.timeout(6000),
|
|
156
|
+
});
|
|
157
|
+
if (!res.ok)
|
|
158
|
+
return null;
|
|
159
|
+
const data = await res.json();
|
|
160
|
+
return (data.businesses || []).map((b) => ({
|
|
161
|
+
name: b.name,
|
|
162
|
+
address: b.location
|
|
163
|
+
? [b.location.address1, b.location.city, b.location.state, b.location.country]
|
|
164
|
+
.filter(Boolean)
|
|
165
|
+
.join(', ')
|
|
166
|
+
: '',
|
|
167
|
+
rating: b.rating,
|
|
168
|
+
reviewCount: b.review_count,
|
|
169
|
+
priceLevel: b.price ? b.price.length : undefined, // "$" → 1, "$$" → 2, etc.
|
|
170
|
+
categories: (b.categories || []).map((c) => c.alias),
|
|
171
|
+
phone: b.display_phone,
|
|
172
|
+
website: b.url,
|
|
173
|
+
googleMapsUrl: undefined,
|
|
174
|
+
isOpen: b.is_closed === false,
|
|
175
|
+
hours: undefined,
|
|
176
|
+
location: b.coordinates
|
|
177
|
+
? { lat: b.coordinates.latitude, lng: b.coordinates.longitude }
|
|
178
|
+
: undefined,
|
|
179
|
+
photos: b.image_url ? [b.image_url] : [],
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
console.warn('[local-search] Yelp request failed:', err.message);
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// ─── Google Maps scraping fallback ────────────────────────────────────────
|
|
188
|
+
async function searchGoogleMapsFallback(opts) {
|
|
189
|
+
try {
|
|
190
|
+
const query = opts.location
|
|
191
|
+
? `${opts.query} in ${opts.location}`
|
|
192
|
+
: opts.query;
|
|
193
|
+
const url = `https://www.google.com/maps/search/${encodeURIComponent(query)}`;
|
|
194
|
+
const result = await peel(url, { render: true, timeout: 15000 });
|
|
195
|
+
// Extract what we can from the markdown content
|
|
196
|
+
const lines = result.content.split('\n').filter(Boolean);
|
|
197
|
+
const businesses = [];
|
|
198
|
+
// Simple heuristic: look for business name patterns followed by rating/address
|
|
199
|
+
let current = null;
|
|
200
|
+
for (const line of lines) {
|
|
201
|
+
// Rating line: "4.5 (1,234)"
|
|
202
|
+
const ratingMatch = line.match(/^(\d\.\d)\s*\((\d[\d,]*)\)/);
|
|
203
|
+
if (ratingMatch && current) {
|
|
204
|
+
current.rating = parseFloat(ratingMatch[1]);
|
|
205
|
+
current.reviewCount = parseInt(ratingMatch[2].replace(/,/g, ''));
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
// Push completed entry and start new one for non-empty lines that look like names
|
|
209
|
+
if (line.length > 3 && line.length < 100 && !line.startsWith('http') && !ratingMatch) {
|
|
210
|
+
if (current?.name) {
|
|
211
|
+
businesses.push(current);
|
|
212
|
+
}
|
|
213
|
+
current = { name: line, address: '' };
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (current?.name)
|
|
217
|
+
businesses.push(current);
|
|
218
|
+
return businesses.slice(0, opts.limit ?? 10);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return [];
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// ─── Dedup by name+address similarity ────────────────────────────────────
|
|
225
|
+
function normalize(s) {
|
|
226
|
+
return s.toLowerCase().replace(/[^a-z0-9\s]/g, '').replace(/\s+/g, ' ').trim();
|
|
227
|
+
}
|
|
228
|
+
function isSimilar(a, b) {
|
|
229
|
+
const nameA = normalize(a.name);
|
|
230
|
+
const nameB = normalize(b.name);
|
|
231
|
+
if (nameA === nameB)
|
|
232
|
+
return true;
|
|
233
|
+
// Jaccard similarity on word tokens
|
|
234
|
+
const tokA = new Set(nameA.split(' '));
|
|
235
|
+
const tokB = new Set(nameB.split(' '));
|
|
236
|
+
const intersection = [...tokA].filter(t => tokB.has(t));
|
|
237
|
+
const union = new Set([...tokA, ...tokB]);
|
|
238
|
+
const jaccard = intersection.length / union.size;
|
|
239
|
+
return jaccard >= 0.7;
|
|
240
|
+
}
|
|
241
|
+
function dedupResults(primary, secondary) {
|
|
242
|
+
const merged = [...primary];
|
|
243
|
+
for (const item of secondary) {
|
|
244
|
+
if (!merged.some(existing => isSimilar(existing, item))) {
|
|
245
|
+
merged.push(item);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return merged;
|
|
249
|
+
}
|
|
250
|
+
// ─── Main export ──────────────────────────────────────────────────────────
|
|
251
|
+
/**
|
|
252
|
+
* Search for local businesses/places using the best available source.
|
|
253
|
+
*
|
|
254
|
+
* Priority order:
|
|
255
|
+
* 1. Google Places Text Search (New) API — requires GOOGLE_PLACES_API_KEY
|
|
256
|
+
* 2. Yelp Fusion API — requires YELP_API_KEY (merged with Google if both available)
|
|
257
|
+
* 3. Google Maps scraping via peel() — no API key required, slowest
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```typescript
|
|
261
|
+
* const results = await localSearch({
|
|
262
|
+
* query: 'best sushi',
|
|
263
|
+
* location: 'Shibuya, Tokyo',
|
|
264
|
+
* language: 'ja',
|
|
265
|
+
* country: 'JP',
|
|
266
|
+
* });
|
|
267
|
+
* console.log(results.results[0].name); // "寿司 さわ"
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
export async function localSearch(opts) {
|
|
271
|
+
const limit = opts.limit ?? 10;
|
|
272
|
+
let source = 'fallback';
|
|
273
|
+
// Try Google Places first (best data quality)
|
|
274
|
+
const googleResults = await searchGooglePlaces(opts);
|
|
275
|
+
if (googleResults !== null) {
|
|
276
|
+
source = 'google-places';
|
|
277
|
+
let results = googleResults;
|
|
278
|
+
// Also fetch Yelp in parallel if key is available, merge for more coverage
|
|
279
|
+
const yelpResults = await searchYelp({ ...opts, limit: Math.ceil(limit / 2) });
|
|
280
|
+
if (yelpResults && yelpResults.length > 0) {
|
|
281
|
+
results = dedupResults(googleResults, yelpResults);
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
results: results.slice(0, limit),
|
|
285
|
+
query: opts.query,
|
|
286
|
+
location: opts.location,
|
|
287
|
+
source,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
// Try Yelp as primary if no Google key
|
|
291
|
+
const yelpResults = await searchYelp(opts);
|
|
292
|
+
if (yelpResults !== null && yelpResults.length > 0) {
|
|
293
|
+
return {
|
|
294
|
+
results: yelpResults.slice(0, limit),
|
|
295
|
+
query: opts.query,
|
|
296
|
+
location: opts.location,
|
|
297
|
+
source: 'yelp',
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
// Last resort: scrape Google Maps
|
|
301
|
+
const fallbackResults = await searchGoogleMapsFallback(opts);
|
|
302
|
+
return {
|
|
303
|
+
results: fallbackResults.slice(0, limit),
|
|
304
|
+
query: opts.query,
|
|
305
|
+
location: opts.location,
|
|
306
|
+
source: 'fallback',
|
|
307
|
+
};
|
|
308
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight structured logger — no external dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Production: JSON lines (structured, parseable by log aggregators)
|
|
5
|
+
* Development: Human-readable console output
|
|
6
|
+
*
|
|
7
|
+
* Supports child loggers for request-scoped context.
|
|
8
|
+
*
|
|
9
|
+
* Levels: debug < info < warn < error < silent
|
|
10
|
+
*
|
|
11
|
+
* Respects WEBPEEL_LOG_LEVEL env var.
|
|
12
|
+
* Defaults: production → 'info', development → 'debug'.
|
|
13
|
+
*
|
|
14
|
+
* All output goes to stderr so stdout stays clean for data/JSON (CLI piping).
|
|
15
|
+
*/
|
|
16
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
17
|
+
interface LogContext {
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}
|
|
20
|
+
export interface Logger {
|
|
21
|
+
debug: (...args: any[]) => void;
|
|
22
|
+
info: (...args: any[]) => void;
|
|
23
|
+
warn: (...args: any[]) => void;
|
|
24
|
+
error: (...args: any[]) => void;
|
|
25
|
+
child: (context: LogContext) => Logger;
|
|
26
|
+
}
|
|
27
|
+
export declare function createLogger(module: string): Logger;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight structured logger — no external dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Production: JSON lines (structured, parseable by log aggregators)
|
|
5
|
+
* Development: Human-readable console output
|
|
6
|
+
*
|
|
7
|
+
* Supports child loggers for request-scoped context.
|
|
8
|
+
*
|
|
9
|
+
* Levels: debug < info < warn < error < silent
|
|
10
|
+
*
|
|
11
|
+
* Respects WEBPEEL_LOG_LEVEL env var.
|
|
12
|
+
* Defaults: production → 'info', development → 'debug'.
|
|
13
|
+
*
|
|
14
|
+
* All output goes to stderr so stdout stays clean for data/JSON (CLI piping).
|
|
15
|
+
*/
|
|
16
|
+
const LEVELS = {
|
|
17
|
+
debug: 0,
|
|
18
|
+
info: 1,
|
|
19
|
+
warn: 2,
|
|
20
|
+
error: 3,
|
|
21
|
+
silent: 4,
|
|
22
|
+
};
|
|
23
|
+
const currentLevel = () => {
|
|
24
|
+
const env = process.env.WEBPEEL_LOG_LEVEL?.toLowerCase();
|
|
25
|
+
if (env && env in LEVELS)
|
|
26
|
+
return env;
|
|
27
|
+
return process.env.NODE_ENV === 'production' ? 'info' : 'debug';
|
|
28
|
+
};
|
|
29
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
30
|
+
function formatJson(level, module, args, context) {
|
|
31
|
+
// Extract message and data from args
|
|
32
|
+
let msg = '';
|
|
33
|
+
const data = {};
|
|
34
|
+
for (const arg of args) {
|
|
35
|
+
if (typeof arg === 'string') {
|
|
36
|
+
msg = msg ? `${msg} ${arg}` : arg;
|
|
37
|
+
}
|
|
38
|
+
else if (typeof arg === 'object' && arg !== null) {
|
|
39
|
+
// Merge objects into data
|
|
40
|
+
if (arg instanceof Error) {
|
|
41
|
+
data.error = { message: arg.message, stack: arg.stack, name: arg.name };
|
|
42
|
+
if ('code' in arg)
|
|
43
|
+
data.error.code = arg.code;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
Object.assign(data, arg);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
msg = msg ? `${msg} ${String(arg)}` : String(arg);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const entry = {
|
|
54
|
+
level,
|
|
55
|
+
module,
|
|
56
|
+
msg,
|
|
57
|
+
timestamp: new Date().toISOString(),
|
|
58
|
+
...context,
|
|
59
|
+
};
|
|
60
|
+
if (Object.keys(data).length > 0) {
|
|
61
|
+
entry.data = data;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return JSON.stringify(entry);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return JSON.stringify({ level, module, msg: String(args), timestamp: new Date().toISOString() });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function createLoggerInternal(module, context = {}) {
|
|
71
|
+
const prefix = `[webpeel:${module}]`;
|
|
72
|
+
const shouldLog = (level) => LEVELS[currentLevel()] <= LEVELS[level];
|
|
73
|
+
const logFn = (level, ...args) => {
|
|
74
|
+
if (!shouldLog(level))
|
|
75
|
+
return;
|
|
76
|
+
if (isProduction) {
|
|
77
|
+
console.error(formatJson(level, module, args, context));
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// Human-readable for development
|
|
81
|
+
console.error(prefix, ...(level === 'warn' ? ['[WARN]'] : level === 'error' ? ['[ERROR]'] : []), ...args.map((a) => {
|
|
82
|
+
if (typeof a === 'object' && a !== null && !(a instanceof Error)) {
|
|
83
|
+
try {
|
|
84
|
+
return JSON.stringify(a);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return String(a);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return a;
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
return {
|
|
95
|
+
debug: (...args) => logFn('debug', ...args),
|
|
96
|
+
info: (...args) => logFn('info', ...args),
|
|
97
|
+
warn: (...args) => logFn('warn', ...args),
|
|
98
|
+
error: (...args) => logFn('error', ...args),
|
|
99
|
+
child: (childContext) => createLoggerInternal(module, { ...context, ...childContext }),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export function createLogger(module) {
|
|
103
|
+
return createLoggerInternal(module);
|
|
104
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain URL mapping
|
|
3
|
+
* Combines sitemap discovery with link crawling to discover all URLs on a domain
|
|
4
|
+
*/
|
|
5
|
+
export interface MapOptions {
|
|
6
|
+
/** Include sitemap URLs (default: true) */
|
|
7
|
+
useSitemap?: boolean;
|
|
8
|
+
/** Crawl the homepage for additional links (default: true) */
|
|
9
|
+
crawlHomepage?: boolean;
|
|
10
|
+
/** Maximum URLs to discover (default: 5000) */
|
|
11
|
+
maxUrls?: number;
|
|
12
|
+
/** Timeout per request in ms (default: 10000) */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
/** Include URL patterns matching these regexes only */
|
|
15
|
+
includePatterns?: string[];
|
|
16
|
+
/** Exclude URL patterns matching these regexes */
|
|
17
|
+
excludePatterns?: string[];
|
|
18
|
+
/** Filter URLs by relevance to this search query */
|
|
19
|
+
search?: string;
|
|
20
|
+
/** Only return URLs matching these content types */
|
|
21
|
+
contentTypeFilter?: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface MapResult {
|
|
24
|
+
/** All discovered URLs (deduplicated) */
|
|
25
|
+
urls: string[];
|
|
26
|
+
/** Sitemap URLs used */
|
|
27
|
+
sitemapUrls: string[];
|
|
28
|
+
/** Total URLs discovered */
|
|
29
|
+
total: number;
|
|
30
|
+
/** Time elapsed in ms */
|
|
31
|
+
elapsed: number;
|
|
32
|
+
}
|
|
33
|
+
export declare function mapDomain(startUrl: string, options?: MapOptions): Promise<MapResult>;
|
package/dist/core/map.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain URL mapping
|
|
3
|
+
* Combines sitemap discovery with link crawling to discover all URLs on a domain
|
|
4
|
+
*/
|
|
5
|
+
import { discoverSitemap } from './sitemap.js';
|
|
6
|
+
import { peel } from '../index.js';
|
|
7
|
+
/** Safely compile a user-supplied regex pattern with length limit. */
|
|
8
|
+
function safeRegex(pattern) {
|
|
9
|
+
if (pattern.length > 200) {
|
|
10
|
+
throw new Error(`Regex pattern too long (${pattern.length} chars, max 200)`);
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
return new RegExp(pattern);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
throw new Error(`Invalid regex pattern: ${pattern}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export async function mapDomain(startUrl, options = {}) {
|
|
20
|
+
const startTime = Date.now();
|
|
21
|
+
const { useSitemap = true, crawlHomepage = true, maxUrls = 5000, timeout = 10000, includePatterns = [], excludePatterns = [], search, contentTypeFilter = [], } = options;
|
|
22
|
+
const urlObj = new URL(startUrl);
|
|
23
|
+
const domain = urlObj.hostname;
|
|
24
|
+
const allUrls = new Map(); // URL -> relevance score
|
|
25
|
+
let sitemapUrls = [];
|
|
26
|
+
// Compile filter patterns
|
|
27
|
+
const includeRegexes = includePatterns.map(p => safeRegex(p));
|
|
28
|
+
const excludeRegexes = excludePatterns.map(p => safeRegex(p));
|
|
29
|
+
// Parse search terms
|
|
30
|
+
const searchTerms = search ? search.toLowerCase().split(/\s+/).filter(t => t.length > 0) : [];
|
|
31
|
+
/**
|
|
32
|
+
* Calculate relevance score for a URL based on search terms
|
|
33
|
+
* Scores based on matches in URL path and title/description if available
|
|
34
|
+
*/
|
|
35
|
+
function calculateRelevance(url, title, description) {
|
|
36
|
+
if (searchTerms.length === 0)
|
|
37
|
+
return 1; // No search = all equal
|
|
38
|
+
let score = 0;
|
|
39
|
+
const urlLower = url.toLowerCase();
|
|
40
|
+
const titleLower = (title || '').toLowerCase();
|
|
41
|
+
const descLower = (description || '').toLowerCase();
|
|
42
|
+
for (const term of searchTerms) {
|
|
43
|
+
// URL path matches (highest weight)
|
|
44
|
+
if (urlLower.includes(term))
|
|
45
|
+
score += 3;
|
|
46
|
+
// Title matches
|
|
47
|
+
if (titleLower.includes(term))
|
|
48
|
+
score += 2;
|
|
49
|
+
// Description matches
|
|
50
|
+
if (descLower.includes(term))
|
|
51
|
+
score += 1;
|
|
52
|
+
}
|
|
53
|
+
return score;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Check if URL should be included based on patterns and content type
|
|
57
|
+
*/
|
|
58
|
+
function shouldInclude(url) {
|
|
59
|
+
if (excludeRegexes.some(r => r.test(url)))
|
|
60
|
+
return false;
|
|
61
|
+
if (includeRegexes.length > 0 && !includeRegexes.some(r => r.test(url)))
|
|
62
|
+
return false;
|
|
63
|
+
// Content type filter (check file extension)
|
|
64
|
+
if (contentTypeFilter.length > 0) {
|
|
65
|
+
const ext = url.split('.').pop()?.toLowerCase() || '';
|
|
66
|
+
const hasMatch = contentTypeFilter.some(type => {
|
|
67
|
+
const typeExt = type.replace(/^\./, '').toLowerCase();
|
|
68
|
+
return ext === typeExt || url.toLowerCase().includes(`.${typeExt}`);
|
|
69
|
+
});
|
|
70
|
+
if (!hasMatch)
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
// Step 1: Sitemap discovery
|
|
76
|
+
if (useSitemap) {
|
|
77
|
+
const sitemap = await discoverSitemap(domain, { timeout, maxUrls });
|
|
78
|
+
sitemapUrls = sitemap.sitemapUrls;
|
|
79
|
+
for (const entry of sitemap.urls) {
|
|
80
|
+
if (allUrls.size >= maxUrls)
|
|
81
|
+
break;
|
|
82
|
+
if (shouldInclude(entry.url)) {
|
|
83
|
+
// Sitemap entries don't have title/description, just score by URL
|
|
84
|
+
const score = calculateRelevance(entry.url);
|
|
85
|
+
allUrls.set(entry.url, score);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Step 2: Crawl homepage for additional links
|
|
90
|
+
if (crawlHomepage && allUrls.size < maxUrls) {
|
|
91
|
+
try {
|
|
92
|
+
const result = await peel(startUrl, { timeout });
|
|
93
|
+
for (const link of result.links) {
|
|
94
|
+
if (allUrls.size >= maxUrls)
|
|
95
|
+
break;
|
|
96
|
+
try {
|
|
97
|
+
const linkUrl = new URL(link);
|
|
98
|
+
if (linkUrl.hostname === domain && shouldInclude(link)) {
|
|
99
|
+
const score = calculateRelevance(link);
|
|
100
|
+
if (!allUrls.has(link)) {
|
|
101
|
+
allUrls.set(link, score);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch { /* skip invalid URLs */ }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch { /* skip homepage crawl errors */ }
|
|
109
|
+
}
|
|
110
|
+
// Sort URLs by relevance score (highest first), then alphabetically
|
|
111
|
+
const sortedUrls = Array.from(allUrls.entries())
|
|
112
|
+
.sort((a, b) => {
|
|
113
|
+
if (search) {
|
|
114
|
+
// Sort by score first if searching
|
|
115
|
+
if (b[1] !== a[1])
|
|
116
|
+
return b[1] - a[1];
|
|
117
|
+
}
|
|
118
|
+
return a[0].localeCompare(b[0]);
|
|
119
|
+
})
|
|
120
|
+
.map(([url]) => url);
|
|
121
|
+
return {
|
|
122
|
+
urls: sortedUrls,
|
|
123
|
+
sitemapUrls,
|
|
124
|
+
total: allUrls.size,
|
|
125
|
+
elapsed: Date.now() - startTime,
|
|
126
|
+
};
|
|
127
|
+
}
|