@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.
Files changed (547) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +313 -0
  3. package/dist/cache.d.ts +30 -0
  4. package/dist/cache.js +139 -0
  5. package/dist/cli/commands/auth.d.ts +5 -0
  6. package/dist/cli/commands/auth.js +411 -0
  7. package/dist/cli/commands/doctor.d.ts +37 -0
  8. package/dist/cli/commands/doctor.js +371 -0
  9. package/dist/cli/commands/fetch.d.ts +6 -0
  10. package/dist/cli/commands/fetch.js +1345 -0
  11. package/dist/cli/commands/guide.d.ts +2 -0
  12. package/dist/cli/commands/guide.js +183 -0
  13. package/dist/cli/commands/interact.d.ts +5 -0
  14. package/dist/cli/commands/interact.js +840 -0
  15. package/dist/cli/commands/jobs.d.ts +5 -0
  16. package/dist/cli/commands/jobs.js +997 -0
  17. package/dist/cli/commands/monitor.d.ts +12 -0
  18. package/dist/cli/commands/monitor.js +197 -0
  19. package/dist/cli/commands/observe.d.ts +12 -0
  20. package/dist/cli/commands/observe.js +158 -0
  21. package/dist/cli/commands/screenshot.d.ts +5 -0
  22. package/dist/cli/commands/screenshot.js +282 -0
  23. package/dist/cli/commands/search.d.ts +5 -0
  24. package/dist/cli/commands/search.js +1021 -0
  25. package/dist/cli/commands/setup.d.ts +13 -0
  26. package/dist/cli/commands/setup.js +244 -0
  27. package/dist/cli/commands/skill.d.ts +15 -0
  28. package/dist/cli/commands/skill.js +195 -0
  29. package/dist/cli/utils.d.ts +84 -0
  30. package/dist/cli/utils.js +806 -0
  31. package/dist/cli-auth.d.ts +75 -0
  32. package/dist/cli-auth.js +369 -0
  33. package/dist/cli.d.ts +17 -0
  34. package/dist/cli.js +99 -0
  35. package/dist/core/actions.d.ts +69 -0
  36. package/dist/core/actions.js +495 -0
  37. package/dist/core/agent.d.ts +98 -0
  38. package/dist/core/agent.js +558 -0
  39. package/dist/core/answer.d.ts +42 -0
  40. package/dist/core/answer.js +395 -0
  41. package/dist/core/application-tracker.d.ts +84 -0
  42. package/dist/core/application-tracker.js +184 -0
  43. package/dist/core/apply.d.ts +162 -0
  44. package/dist/core/apply.js +816 -0
  45. package/dist/core/auth-detection.d.ts +35 -0
  46. package/dist/core/auth-detection.js +358 -0
  47. package/dist/core/auto-extract.d.ts +82 -0
  48. package/dist/core/auto-extract.js +604 -0
  49. package/dist/core/auto-interact.d.ts +23 -0
  50. package/dist/core/auto-interact.js +246 -0
  51. package/dist/core/bm25-filter.d.ts +66 -0
  52. package/dist/core/bm25-filter.js +288 -0
  53. package/dist/core/branding.d.ts +54 -0
  54. package/dist/core/branding.js +234 -0
  55. package/dist/core/browser-fetch.d.ts +323 -0
  56. package/dist/core/browser-fetch.js +1600 -0
  57. package/dist/core/browser-pool.d.ts +91 -0
  58. package/dist/core/browser-pool.js +550 -0
  59. package/dist/core/budget.d.ts +42 -0
  60. package/dist/core/budget.js +324 -0
  61. package/dist/core/business-intel.d.ts +47 -0
  62. package/dist/core/business-intel.js +279 -0
  63. package/dist/core/cache.d.ts +13 -0
  64. package/dist/core/cache.js +121 -0
  65. package/dist/core/cf-worker-proxy.d.ts +32 -0
  66. package/dist/core/cf-worker-proxy.js +87 -0
  67. package/dist/core/challenge-detection.d.ts +26 -0
  68. package/dist/core/challenge-detection.js +468 -0
  69. package/dist/core/change-tracking.d.ts +75 -0
  70. package/dist/core/change-tracking.js +276 -0
  71. package/dist/core/chunker.d.ts +46 -0
  72. package/dist/core/chunker.js +249 -0
  73. package/dist/core/chunking.d.ts +42 -0
  74. package/dist/core/chunking.js +181 -0
  75. package/dist/core/circuit-breaker.d.ts +44 -0
  76. package/dist/core/circuit-breaker.js +85 -0
  77. package/dist/core/content-pruner.d.ts +47 -0
  78. package/dist/core/content-pruner.js +425 -0
  79. package/dist/core/cookie-cache.d.ts +60 -0
  80. package/dist/core/cookie-cache.js +163 -0
  81. package/dist/core/crawl-checkpoint.d.ts +54 -0
  82. package/dist/core/crawl-checkpoint.js +104 -0
  83. package/dist/core/crawler.d.ts +84 -0
  84. package/dist/core/crawler.js +349 -0
  85. package/dist/core/cross-verify.d.ts +27 -0
  86. package/dist/core/cross-verify.js +93 -0
  87. package/dist/core/deep-fetch.d.ts +74 -0
  88. package/dist/core/deep-fetch.js +405 -0
  89. package/dist/core/deep-research.d.ts +141 -0
  90. package/dist/core/deep-research.js +972 -0
  91. package/dist/core/design-analysis.d.ts +70 -0
  92. package/dist/core/design-analysis.js +490 -0
  93. package/dist/core/design-compare.d.ts +38 -0
  94. package/dist/core/design-compare.js +264 -0
  95. package/dist/core/diff.d.ts +61 -0
  96. package/dist/core/diff.js +289 -0
  97. package/dist/core/dns-cache.d.ts +20 -0
  98. package/dist/core/dns-cache.js +198 -0
  99. package/dist/core/documents.d.ts +23 -0
  100. package/dist/core/documents.js +123 -0
  101. package/dist/core/domain-memory.d.ts +66 -0
  102. package/dist/core/domain-memory.js +163 -0
  103. package/dist/core/domain-verify.d.ts +40 -0
  104. package/dist/core/domain-verify.js +379 -0
  105. package/dist/core/engine-ranker.d.ts +112 -0
  106. package/dist/core/engine-ranker.js +395 -0
  107. package/dist/core/extract-inline.d.ts +38 -0
  108. package/dist/core/extract-inline.js +215 -0
  109. package/dist/core/extract-listings.d.ts +38 -0
  110. package/dist/core/extract-listings.js +461 -0
  111. package/dist/core/extract.d.ts +9 -0
  112. package/dist/core/extract.js +139 -0
  113. package/dist/core/fetch-cache.d.ts +57 -0
  114. package/dist/core/fetch-cache.js +95 -0
  115. package/dist/core/fetcher.d.ts +13 -0
  116. package/dist/core/fetcher.js +12 -0
  117. package/dist/core/google-cache.d.ts +29 -0
  118. package/dist/core/google-cache.js +180 -0
  119. package/dist/core/google-serp-parser.d.ts +82 -0
  120. package/dist/core/google-serp-parser.js +287 -0
  121. package/dist/core/hotel-search.d.ts +122 -0
  122. package/dist/core/hotel-search.js +382 -0
  123. package/dist/core/http-fetch.d.ts +72 -0
  124. package/dist/core/http-fetch.js +820 -0
  125. package/dist/core/human.d.ts +175 -0
  126. package/dist/core/human.js +680 -0
  127. package/dist/core/image-caption.d.ts +44 -0
  128. package/dist/core/image-caption.js +271 -0
  129. package/dist/core/jobs.d.ts +75 -0
  130. package/dist/core/jobs.js +634 -0
  131. package/dist/core/json-ld.d.ts +15 -0
  132. package/dist/core/json-ld.js +617 -0
  133. package/dist/core/language-detect.d.ts +18 -0
  134. package/dist/core/language-detect.js +135 -0
  135. package/dist/core/links.d.ts +10 -0
  136. package/dist/core/links.js +44 -0
  137. package/dist/core/llm-extract.d.ts +71 -0
  138. package/dist/core/llm-extract.js +507 -0
  139. package/dist/core/llm-provider.d.ts +100 -0
  140. package/dist/core/llm-provider.js +702 -0
  141. package/dist/core/local-search.d.ts +60 -0
  142. package/dist/core/local-search.js +308 -0
  143. package/dist/core/logger.d.ts +28 -0
  144. package/dist/core/logger.js +104 -0
  145. package/dist/core/map.d.ts +33 -0
  146. package/dist/core/map.js +127 -0
  147. package/dist/core/markdown.d.ts +92 -0
  148. package/dist/core/markdown.js +809 -0
  149. package/dist/core/metadata.d.ts +34 -0
  150. package/dist/core/metadata.js +422 -0
  151. package/dist/core/observe.d.ts +113 -0
  152. package/dist/core/observe.js +395 -0
  153. package/dist/core/ocr.d.ts +12 -0
  154. package/dist/core/ocr.js +33 -0
  155. package/dist/core/paginate.d.ts +31 -0
  156. package/dist/core/paginate.js +106 -0
  157. package/dist/core/pdf.d.ts +8 -0
  158. package/dist/core/pdf.js +25 -0
  159. package/dist/core/peel-tls.d.ts +25 -0
  160. package/dist/core/peel-tls.js +220 -0
  161. package/dist/core/pipeline.d.ts +132 -0
  162. package/dist/core/pipeline.js +1666 -0
  163. package/dist/core/profiles.d.ts +61 -0
  164. package/dist/core/profiles.js +350 -0
  165. package/dist/core/prompt-guard.d.ts +30 -0
  166. package/dist/core/prompt-guard.js +119 -0
  167. package/dist/core/proxy-config.d.ts +90 -0
  168. package/dist/core/proxy-config.js +172 -0
  169. package/dist/core/quick-answer.d.ts +53 -0
  170. package/dist/core/quick-answer.js +833 -0
  171. package/dist/core/rate-governor.d.ts +80 -0
  172. package/dist/core/rate-governor.js +238 -0
  173. package/dist/core/readability.d.ts +57 -0
  174. package/dist/core/readability.js +533 -0
  175. package/dist/core/research.d.ts +66 -0
  176. package/dist/core/research.js +270 -0
  177. package/dist/core/retry.d.ts +60 -0
  178. package/dist/core/retry.js +119 -0
  179. package/dist/core/safe-browsing.d.ts +30 -0
  180. package/dist/core/safe-browsing.js +206 -0
  181. package/dist/core/schema-extraction.d.ts +66 -0
  182. package/dist/core/schema-extraction.js +352 -0
  183. package/dist/core/schema-postprocess.d.ts +32 -0
  184. package/dist/core/schema-postprocess.js +469 -0
  185. package/dist/core/schema-templates.d.ts +19 -0
  186. package/dist/core/schema-templates.js +143 -0
  187. package/dist/core/screenshot.d.ts +224 -0
  188. package/dist/core/screenshot.js +207 -0
  189. package/dist/core/search-engines.d.ts +25 -0
  190. package/dist/core/search-engines.js +182 -0
  191. package/dist/core/search-provider.d.ts +243 -0
  192. package/dist/core/search-provider.js +1629 -0
  193. package/dist/core/searxng-provider.d.ts +35 -0
  194. package/dist/core/searxng-provider.js +105 -0
  195. package/dist/core/selective-evidence.d.ts +151 -0
  196. package/dist/core/selective-evidence.js +389 -0
  197. package/dist/core/site-search.d.ts +44 -0
  198. package/dist/core/site-search.js +252 -0
  199. package/dist/core/sitemap.d.ts +23 -0
  200. package/dist/core/sitemap.js +105 -0
  201. package/dist/core/source-credibility.d.ts +29 -0
  202. package/dist/core/source-credibility.js +584 -0
  203. package/dist/core/source-scoring.d.ts +166 -0
  204. package/dist/core/source-scoring.js +396 -0
  205. package/dist/core/stemmer.d.ts +38 -0
  206. package/dist/core/stemmer.js +509 -0
  207. package/dist/core/strategies.d.ts +104 -0
  208. package/dist/core/strategies.js +1044 -0
  209. package/dist/core/strategy-hooks.d.ts +145 -0
  210. package/dist/core/strategy-hooks.js +74 -0
  211. package/dist/core/structured-extract.d.ts +43 -0
  212. package/dist/core/structured-extract.js +550 -0
  213. package/dist/core/summarize.d.ts +17 -0
  214. package/dist/core/summarize.js +78 -0
  215. package/dist/core/synonyms.d.ts +42 -0
  216. package/dist/core/synonyms.js +184 -0
  217. package/dist/core/system-monitor.d.ts +61 -0
  218. package/dist/core/system-monitor.js +133 -0
  219. package/dist/core/table-format.d.ts +30 -0
  220. package/dist/core/table-format.js +146 -0
  221. package/dist/core/threat-feeds.d.ts +23 -0
  222. package/dist/core/threat-feeds.js +104 -0
  223. package/dist/core/timing.d.ts +21 -0
  224. package/dist/core/timing.js +33 -0
  225. package/dist/core/transcript-export.d.ts +47 -0
  226. package/dist/core/transcript-export.js +107 -0
  227. package/dist/core/user-agents.d.ts +82 -0
  228. package/dist/core/user-agents.js +239 -0
  229. package/dist/core/vertical-search.d.ts +54 -0
  230. package/dist/core/vertical-search.js +158 -0
  231. package/dist/core/watch-manager.d.ts +175 -0
  232. package/dist/core/watch-manager.js +416 -0
  233. package/dist/core/watch.d.ts +101 -0
  234. package/dist/core/watch.js +389 -0
  235. package/dist/core/youtube.d.ts +130 -0
  236. package/dist/core/youtube.js +1175 -0
  237. package/dist/ee/challenge-re-export.d.ts +1 -0
  238. package/dist/ee/challenge-re-export.js +1 -0
  239. package/dist/ee/challenge-solver.d.ts +72 -0
  240. package/dist/ee/challenge-solver.js +720 -0
  241. package/dist/ee/domain-extractors.d.ts +8 -0
  242. package/dist/ee/domain-extractors.js +8 -0
  243. package/dist/ee/domain-intel.d.ts +16 -0
  244. package/dist/ee/domain-intel.js +133 -0
  245. package/dist/ee/extractors/allrecipes.d.ts +2 -0
  246. package/dist/ee/extractors/allrecipes.js +120 -0
  247. package/dist/ee/extractors/amazon.d.ts +2 -0
  248. package/dist/ee/extractors/amazon.js +78 -0
  249. package/dist/ee/extractors/arxiv.d.ts +2 -0
  250. package/dist/ee/extractors/arxiv.js +137 -0
  251. package/dist/ee/extractors/bestbuy.d.ts +2 -0
  252. package/dist/ee/extractors/bestbuy.js +78 -0
  253. package/dist/ee/extractors/carscom.d.ts +2 -0
  254. package/dist/ee/extractors/carscom.js +121 -0
  255. package/dist/ee/extractors/coingecko.d.ts +2 -0
  256. package/dist/ee/extractors/coingecko.js +134 -0
  257. package/dist/ee/extractors/craigslist.d.ts +2 -0
  258. package/dist/ee/extractors/craigslist.js +92 -0
  259. package/dist/ee/extractors/devto.d.ts +2 -0
  260. package/dist/ee/extractors/devto.js +135 -0
  261. package/dist/ee/extractors/ebay.d.ts +2 -0
  262. package/dist/ee/extractors/ebay.js +90 -0
  263. package/dist/ee/extractors/espn.d.ts +2 -0
  264. package/dist/ee/extractors/espn.js +260 -0
  265. package/dist/ee/extractors/etsy.d.ts +2 -0
  266. package/dist/ee/extractors/etsy.js +52 -0
  267. package/dist/ee/extractors/facebook.d.ts +2 -0
  268. package/dist/ee/extractors/facebook.js +46 -0
  269. package/dist/ee/extractors/github.d.ts +2 -0
  270. package/dist/ee/extractors/github.js +196 -0
  271. package/dist/ee/extractors/google-flights.d.ts +2 -0
  272. package/dist/ee/extractors/google-flights.js +176 -0
  273. package/dist/ee/extractors/hackernews.d.ts +2 -0
  274. package/dist/ee/extractors/hackernews.js +147 -0
  275. package/dist/ee/extractors/imdb.d.ts +2 -0
  276. package/dist/ee/extractors/imdb.js +172 -0
  277. package/dist/ee/extractors/index.d.ts +26 -0
  278. package/dist/ee/extractors/index.js +247 -0
  279. package/dist/ee/extractors/instagram.d.ts +2 -0
  280. package/dist/ee/extractors/instagram.js +102 -0
  281. package/dist/ee/extractors/kalshi.d.ts +2 -0
  282. package/dist/ee/extractors/kalshi.js +121 -0
  283. package/dist/ee/extractors/kayak-cars.d.ts +2 -0
  284. package/dist/ee/extractors/kayak-cars.js +270 -0
  285. package/dist/ee/extractors/linkedin.d.ts +2 -0
  286. package/dist/ee/extractors/linkedin.js +113 -0
  287. package/dist/ee/extractors/medium.d.ts +2 -0
  288. package/dist/ee/extractors/medium.js +130 -0
  289. package/dist/ee/extractors/news.d.ts +4 -0
  290. package/dist/ee/extractors/news.js +173 -0
  291. package/dist/ee/extractors/npm.d.ts +2 -0
  292. package/dist/ee/extractors/npm.js +86 -0
  293. package/dist/ee/extractors/pdf.d.ts +2 -0
  294. package/dist/ee/extractors/pdf.js +108 -0
  295. package/dist/ee/extractors/pinterest.d.ts +2 -0
  296. package/dist/ee/extractors/pinterest.js +34 -0
  297. package/dist/ee/extractors/polymarket.d.ts +2 -0
  298. package/dist/ee/extractors/polymarket.js +358 -0
  299. package/dist/ee/extractors/producthunt.d.ts +2 -0
  300. package/dist/ee/extractors/producthunt.js +88 -0
  301. package/dist/ee/extractors/pubmed.d.ts +2 -0
  302. package/dist/ee/extractors/pubmed.js +162 -0
  303. package/dist/ee/extractors/pypi.d.ts +2 -0
  304. package/dist/ee/extractors/pypi.js +80 -0
  305. package/dist/ee/extractors/reddit.d.ts +2 -0
  306. package/dist/ee/extractors/reddit.js +438 -0
  307. package/dist/ee/extractors/redfin.d.ts +2 -0
  308. package/dist/ee/extractors/redfin.js +156 -0
  309. package/dist/ee/extractors/semanticscholar.d.ts +2 -0
  310. package/dist/ee/extractors/semanticscholar.js +131 -0
  311. package/dist/ee/extractors/shared.d.ts +12 -0
  312. package/dist/ee/extractors/shared.js +76 -0
  313. package/dist/ee/extractors/soundcloud.d.ts +2 -0
  314. package/dist/ee/extractors/soundcloud.js +34 -0
  315. package/dist/ee/extractors/sportsbetting.d.ts +2 -0
  316. package/dist/ee/extractors/sportsbetting.js +37 -0
  317. package/dist/ee/extractors/spotify.d.ts +2 -0
  318. package/dist/ee/extractors/spotify.js +34 -0
  319. package/dist/ee/extractors/stackoverflow.d.ts +2 -0
  320. package/dist/ee/extractors/stackoverflow.js +61 -0
  321. package/dist/ee/extractors/substack.d.ts +2 -0
  322. package/dist/ee/extractors/substack.js +115 -0
  323. package/dist/ee/extractors/substackroot.d.ts +2 -0
  324. package/dist/ee/extractors/substackroot.js +46 -0
  325. package/dist/ee/extractors/tiktok.d.ts +2 -0
  326. package/dist/ee/extractors/tiktok.js +29 -0
  327. package/dist/ee/extractors/tradingview.d.ts +2 -0
  328. package/dist/ee/extractors/tradingview.js +182 -0
  329. package/dist/ee/extractors/twitch.d.ts +2 -0
  330. package/dist/ee/extractors/twitch.js +36 -0
  331. package/dist/ee/extractors/twitter.d.ts +2 -0
  332. package/dist/ee/extractors/twitter.js +327 -0
  333. package/dist/ee/extractors/types.d.ts +14 -0
  334. package/dist/ee/extractors/types.js +1 -0
  335. package/dist/ee/extractors/walmart.d.ts +2 -0
  336. package/dist/ee/extractors/walmart.js +50 -0
  337. package/dist/ee/extractors/weather.d.ts +2 -0
  338. package/dist/ee/extractors/weather.js +133 -0
  339. package/dist/ee/extractors/wikipedia.d.ts +4 -0
  340. package/dist/ee/extractors/wikipedia.js +235 -0
  341. package/dist/ee/extractors/yelp.d.ts +2 -0
  342. package/dist/ee/extractors/yelp.js +216 -0
  343. package/dist/ee/extractors/youtube.d.ts +2 -0
  344. package/dist/ee/extractors/youtube.js +189 -0
  345. package/dist/ee/extractors/zillow.d.ts +54 -0
  346. package/dist/ee/extractors/zillow.js +247 -0
  347. package/dist/ee/extractors-re-export.d.ts +1 -0
  348. package/dist/ee/extractors-re-export.js +1 -0
  349. package/dist/ee/premium-hooks.d.ts +20 -0
  350. package/dist/ee/premium-hooks.js +50 -0
  351. package/dist/ee/spa-detection.d.ts +2 -0
  352. package/dist/ee/spa-detection.js +2 -0
  353. package/dist/ee/stability.d.ts +4 -0
  354. package/dist/ee/stability.js +29 -0
  355. package/dist/ee/swr-cache.d.ts +14 -0
  356. package/dist/ee/swr-cache.js +34 -0
  357. package/dist/index.d.ts +143 -0
  358. package/dist/index.js +291 -0
  359. package/dist/integrations/index.d.ts +2 -0
  360. package/dist/integrations/index.js +2 -0
  361. package/dist/integrations/langchain.d.ts +64 -0
  362. package/dist/integrations/langchain.js +115 -0
  363. package/dist/integrations/llamaindex.d.ts +50 -0
  364. package/dist/integrations/llamaindex.js +91 -0
  365. package/dist/mcp/handlers/act.d.ts +5 -0
  366. package/dist/mcp/handlers/act.js +34 -0
  367. package/dist/mcp/handlers/definitions.d.ts +6 -0
  368. package/dist/mcp/handlers/definitions.js +395 -0
  369. package/dist/mcp/handlers/extract.d.ts +7 -0
  370. package/dist/mcp/handlers/extract.js +135 -0
  371. package/dist/mcp/handlers/fetch.d.ts +6 -0
  372. package/dist/mcp/handlers/fetch.js +98 -0
  373. package/dist/mcp/handlers/find.d.ts +5 -0
  374. package/dist/mcp/handlers/find.js +137 -0
  375. package/dist/mcp/handlers/index.d.ts +13 -0
  376. package/dist/mcp/handlers/index.js +63 -0
  377. package/dist/mcp/handlers/legacy.d.ts +25 -0
  378. package/dist/mcp/handlers/legacy.js +450 -0
  379. package/dist/mcp/handlers/meta.d.ts +6 -0
  380. package/dist/mcp/handlers/meta.js +40 -0
  381. package/dist/mcp/handlers/monitor.d.ts +5 -0
  382. package/dist/mcp/handlers/monitor.js +41 -0
  383. package/dist/mcp/handlers/observe.d.ts +8 -0
  384. package/dist/mcp/handlers/observe.js +37 -0
  385. package/dist/mcp/handlers/read.d.ts +6 -0
  386. package/dist/mcp/handlers/read.js +78 -0
  387. package/dist/mcp/handlers/see.d.ts +5 -0
  388. package/dist/mcp/handlers/see.js +75 -0
  389. package/dist/mcp/handlers/types.d.ts +29 -0
  390. package/dist/mcp/handlers/types.js +28 -0
  391. package/dist/mcp/server.d.ts +7 -0
  392. package/dist/mcp/server.js +108 -0
  393. package/dist/mcp/smart-router.d.ts +23 -0
  394. package/dist/mcp/smart-router.js +178 -0
  395. package/dist/server/app.d.ts +14 -0
  396. package/dist/server/app.js +632 -0
  397. package/dist/server/auth-store.d.ts +28 -0
  398. package/dist/server/auth-store.js +88 -0
  399. package/dist/server/bull-queues.d.ts +60 -0
  400. package/dist/server/bull-queues.js +90 -0
  401. package/dist/server/email-service.d.ts +55 -0
  402. package/dist/server/email-service.js +291 -0
  403. package/dist/server/job-queue.d.ts +100 -0
  404. package/dist/server/job-queue.js +145 -0
  405. package/dist/server/logger.d.ts +10 -0
  406. package/dist/server/logger.js +37 -0
  407. package/dist/server/middleware/audit-log.d.ts +14 -0
  408. package/dist/server/middleware/audit-log.js +73 -0
  409. package/dist/server/middleware/auth.d.ts +35 -0
  410. package/dist/server/middleware/auth.js +225 -0
  411. package/dist/server/middleware/rate-limit.d.ts +50 -0
  412. package/dist/server/middleware/rate-limit.js +270 -0
  413. package/dist/server/middleware/scope-guard.d.ts +25 -0
  414. package/dist/server/middleware/scope-guard.js +45 -0
  415. package/dist/server/middleware/url-validator.d.ts +15 -0
  416. package/dist/server/middleware/url-validator.js +201 -0
  417. package/dist/server/openapi.yaml +6418 -0
  418. package/dist/server/pg-auth-store.d.ts +146 -0
  419. package/dist/server/pg-auth-store.js +576 -0
  420. package/dist/server/pg-job-queue.d.ts +59 -0
  421. package/dist/server/pg-job-queue.js +375 -0
  422. package/dist/server/routes/activity.d.ts +6 -0
  423. package/dist/server/routes/activity.js +79 -0
  424. package/dist/server/routes/admin-active.d.ts +7 -0
  425. package/dist/server/routes/admin-active.js +120 -0
  426. package/dist/server/routes/admin-stats.d.ts +7 -0
  427. package/dist/server/routes/admin-stats.js +176 -0
  428. package/dist/server/routes/agent.d.ts +24 -0
  429. package/dist/server/routes/agent.js +480 -0
  430. package/dist/server/routes/answer.d.ts +5 -0
  431. package/dist/server/routes/answer.js +125 -0
  432. package/dist/server/routes/ask.d.ts +28 -0
  433. package/dist/server/routes/ask.js +295 -0
  434. package/dist/server/routes/batch.d.ts +6 -0
  435. package/dist/server/routes/batch.js +493 -0
  436. package/dist/server/routes/cache-warm.d.ts +25 -0
  437. package/dist/server/routes/cache-warm.js +212 -0
  438. package/dist/server/routes/cli-usage.d.ts +6 -0
  439. package/dist/server/routes/cli-usage.js +127 -0
  440. package/dist/server/routes/compat.d.ts +23 -0
  441. package/dist/server/routes/compat.js +652 -0
  442. package/dist/server/routes/crawl.d.ts +13 -0
  443. package/dist/server/routes/crawl.js +287 -0
  444. package/dist/server/routes/deep-fetch.d.ts +8 -0
  445. package/dist/server/routes/deep-fetch.js +57 -0
  446. package/dist/server/routes/deep-research.d.ts +11 -0
  447. package/dist/server/routes/deep-research.js +232 -0
  448. package/dist/server/routes/demo.d.ts +24 -0
  449. package/dist/server/routes/demo.js +517 -0
  450. package/dist/server/routes/do.d.ts +8 -0
  451. package/dist/server/routes/do.js +72 -0
  452. package/dist/server/routes/extract.d.ts +14 -0
  453. package/dist/server/routes/extract.js +325 -0
  454. package/dist/server/routes/feed.d.ts +15 -0
  455. package/dist/server/routes/feed.js +311 -0
  456. package/dist/server/routes/fetch-queue.d.ts +13 -0
  457. package/dist/server/routes/fetch-queue.js +357 -0
  458. package/dist/server/routes/fetch.d.ts +7 -0
  459. package/dist/server/routes/fetch.js +1274 -0
  460. package/dist/server/routes/go.d.ts +14 -0
  461. package/dist/server/routes/go.js +81 -0
  462. package/dist/server/routes/health.d.ts +11 -0
  463. package/dist/server/routes/health.js +141 -0
  464. package/dist/server/routes/jobs.d.ts +7 -0
  465. package/dist/server/routes/jobs.js +574 -0
  466. package/dist/server/routes/map.d.ts +11 -0
  467. package/dist/server/routes/map.js +116 -0
  468. package/dist/server/routes/mcp.d.ts +14 -0
  469. package/dist/server/routes/mcp.js +197 -0
  470. package/dist/server/routes/metrics.d.ts +37 -0
  471. package/dist/server/routes/metrics.js +149 -0
  472. package/dist/server/routes/oauth.d.ts +9 -0
  473. package/dist/server/routes/oauth.js +396 -0
  474. package/dist/server/routes/playground.d.ts +17 -0
  475. package/dist/server/routes/playground.js +283 -0
  476. package/dist/server/routes/reader.d.ts +18 -0
  477. package/dist/server/routes/reader.js +192 -0
  478. package/dist/server/routes/research.d.ts +14 -0
  479. package/dist/server/routes/research.js +482 -0
  480. package/dist/server/routes/screenshot.d.ts +22 -0
  481. package/dist/server/routes/screenshot.js +820 -0
  482. package/dist/server/routes/search.d.ts +6 -0
  483. package/dist/server/routes/search.js +874 -0
  484. package/dist/server/routes/session.d.ts +17 -0
  485. package/dist/server/routes/session.js +548 -0
  486. package/dist/server/routes/share.d.ts +18 -0
  487. package/dist/server/routes/share.js +462 -0
  488. package/dist/server/routes/smart-search/handlers/cars.d.ts +2 -0
  489. package/dist/server/routes/smart-search/handlers/cars.js +102 -0
  490. package/dist/server/routes/smart-search/handlers/flights.d.ts +2 -0
  491. package/dist/server/routes/smart-search/handlers/flights.js +72 -0
  492. package/dist/server/routes/smart-search/handlers/general.d.ts +13 -0
  493. package/dist/server/routes/smart-search/handlers/general.js +717 -0
  494. package/dist/server/routes/smart-search/handlers/hotels.d.ts +2 -0
  495. package/dist/server/routes/smart-search/handlers/hotels.js +88 -0
  496. package/dist/server/routes/smart-search/handlers/products.d.ts +2 -0
  497. package/dist/server/routes/smart-search/handlers/products.js +1309 -0
  498. package/dist/server/routes/smart-search/handlers/rental.d.ts +2 -0
  499. package/dist/server/routes/smart-search/handlers/rental.js +154 -0
  500. package/dist/server/routes/smart-search/handlers/restaurants.d.ts +2 -0
  501. package/dist/server/routes/smart-search/handlers/restaurants.js +225 -0
  502. package/dist/server/routes/smart-search/handlers/transit-verdict.d.ts +41 -0
  503. package/dist/server/routes/smart-search/handlers/transit-verdict.js +224 -0
  504. package/dist/server/routes/smart-search/index.d.ts +19 -0
  505. package/dist/server/routes/smart-search/index.js +546 -0
  506. package/dist/server/routes/smart-search/intent.d.ts +3 -0
  507. package/dist/server/routes/smart-search/intent.js +264 -0
  508. package/dist/server/routes/smart-search/llm.d.ts +16 -0
  509. package/dist/server/routes/smart-search/llm.js +70 -0
  510. package/dist/server/routes/smart-search/sources/reddit.d.ts +18 -0
  511. package/dist/server/routes/smart-search/sources/reddit.js +34 -0
  512. package/dist/server/routes/smart-search/sources/yelp.d.ts +25 -0
  513. package/dist/server/routes/smart-search/sources/yelp.js +171 -0
  514. package/dist/server/routes/smart-search/sources/youtube.d.ts +8 -0
  515. package/dist/server/routes/smart-search/sources/youtube.js +9 -0
  516. package/dist/server/routes/smart-search/types.d.ts +81 -0
  517. package/dist/server/routes/smart-search/types.js +1 -0
  518. package/dist/server/routes/smart-search/utils.d.ts +20 -0
  519. package/dist/server/routes/smart-search/utils.js +146 -0
  520. package/dist/server/routes/stats.d.ts +6 -0
  521. package/dist/server/routes/stats.js +71 -0
  522. package/dist/server/routes/stripe.d.ts +15 -0
  523. package/dist/server/routes/stripe.js +296 -0
  524. package/dist/server/routes/transcript-export.d.ts +10 -0
  525. package/dist/server/routes/transcript-export.js +178 -0
  526. package/dist/server/routes/usage.d.ts +9 -0
  527. package/dist/server/routes/usage.js +279 -0
  528. package/dist/server/routes/users.d.ts +8 -0
  529. package/dist/server/routes/users.js +1867 -0
  530. package/dist/server/routes/watch.d.ts +15 -0
  531. package/dist/server/routes/watch.js +309 -0
  532. package/dist/server/routes/webhooks.d.ts +26 -0
  533. package/dist/server/routes/webhooks.js +170 -0
  534. package/dist/server/routes/youtube.d.ts +6 -0
  535. package/dist/server/routes/youtube.js +130 -0
  536. package/dist/server/sentry.d.ts +14 -0
  537. package/dist/server/sentry.js +104 -0
  538. package/dist/server/types.d.ts +15 -0
  539. package/dist/server/types.js +7 -0
  540. package/dist/server/utils/response.d.ts +44 -0
  541. package/dist/server/utils/response.js +69 -0
  542. package/dist/server/utils/sse.d.ts +22 -0
  543. package/dist/server/utils/sse.js +38 -0
  544. package/dist/types.d.ts +552 -0
  545. package/dist/types.js +39 -0
  546. package/llms.txt +105 -0
  547. package/package.json +189 -0
@@ -0,0 +1,5 @@
1
+ /**
2
+ * /v1/answer — search + fetch + LLM-generated answer with citations (BYOK)
3
+ */
4
+ import { Router } from 'express';
5
+ export declare function createAnswerRouter(): Router;
@@ -0,0 +1,125 @@
1
+ /**
2
+ * /v1/answer — search + fetch + LLM-generated answer with citations (BYOK)
3
+ */
4
+ import { Router } from 'express';
5
+ import { answerQuestion, } from '../../core/answer.js';
6
+ const VALID_LLM_PROVIDERS = ['openai', 'anthropic', 'google'];
7
+ const VALID_SEARCH_PROVIDERS = ['duckduckgo', 'brave'];
8
+ export function createAnswerRouter() {
9
+ const router = Router();
10
+ router.post('/v1/answer', async (req, res) => {
11
+ // Deprecation notice — prefer /v1/fetch?question=... which is LLM-free
12
+ res.setHeader('X-Deprecated', 'true');
13
+ res.setHeader('X-Deprecated-Use', '/v1/fetch?question=...');
14
+ // AUTH: require authentication (global middleware sets req.auth)
15
+ const ansAuthId = req.auth?.keyInfo?.accountId || req.user?.userId;
16
+ if (!ansAuthId) {
17
+ res.status(401).json({ success: false, error: { type: 'authentication_required', message: 'API key required. Get one at https://app.webpeel.dev/keys', hint: 'Get a free API key at https://app.webpeel.dev/keys', docs: 'https://webpeel.dev/docs/errors#authentication_required' }, requestId: req.requestId });
18
+ return;
19
+ }
20
+ try {
21
+ const { question, searchProvider, searchApiKey, llmProvider, llmApiKey, llmModel, maxSources, stream, } = req.body;
22
+ // --- Validation -----------------------------------------------------------
23
+ if (!question || typeof question !== 'string' || question.trim().length === 0) {
24
+ res.status(400).json({ success: false, error: { type: 'invalid_request', message: 'Missing or invalid "question" parameter', hint: 'Include a "question" string in the request body', docs: 'https://webpeel.dev/docs/errors#invalid_request' }, requestId: req.requestId });
25
+ return;
26
+ }
27
+ if (question.length > 2000) {
28
+ res.status(400).json({ success: false, error: { type: 'invalid_request', message: '"question" too long (max 2000 characters)', hint: 'Keep the question under 2000 characters', docs: 'https://webpeel.dev/docs/errors#invalid_request' }, requestId: req.requestId });
29
+ return;
30
+ }
31
+ if (!llmProvider || !VALID_LLM_PROVIDERS.includes(llmProvider)) {
32
+ res.status(400).json({ success: false, error: { type: 'invalid_request', message: `"llmProvider" is required and must be one of: ${VALID_LLM_PROVIDERS.join(', ')}`, hint: `Supported providers: ${VALID_LLM_PROVIDERS.join(', ')}`, docs: 'https://webpeel.dev/docs/errors#invalid_request' }, requestId: req.requestId });
33
+ return;
34
+ }
35
+ if (!llmApiKey || typeof llmApiKey !== 'string' || llmApiKey.trim().length === 0) {
36
+ res.status(400).json({ success: false, error: { type: 'invalid_request', message: 'Missing or invalid "llmApiKey" (BYOK required)', hint: 'Provide your own LLM API key in the "llmApiKey" field', docs: 'https://webpeel.dev/docs/errors#invalid_request' }, requestId: req.requestId });
37
+ return;
38
+ }
39
+ const resolvedSearchProvider = searchProvider && VALID_SEARCH_PROVIDERS.includes(searchProvider)
40
+ ? searchProvider
41
+ : 'duckduckgo';
42
+ // Accept search API key from body or header
43
+ const resolvedSearchApiKey = searchApiKey || req.headers['x-search-api-key'] || undefined;
44
+ const resolvedMaxSources = typeof maxSources === 'number'
45
+ ? Math.min(Math.max(maxSources, 1), 10)
46
+ : 5;
47
+ const shouldStream = stream === true;
48
+ // --- Streaming response (SSE) -------------------------------------------
49
+ if (shouldStream) {
50
+ res.setHeader('Content-Type', 'text/event-stream');
51
+ res.setHeader('Cache-Control', 'no-cache');
52
+ res.setHeader('Connection', 'keep-alive');
53
+ res.setHeader('X-Accel-Buffering', 'no'); // nginx
54
+ res.flushHeaders();
55
+ const answerReq = {
56
+ question: question.trim(),
57
+ searchProvider: resolvedSearchProvider,
58
+ searchApiKey: resolvedSearchApiKey,
59
+ llmProvider: llmProvider,
60
+ llmApiKey: llmApiKey.trim(),
61
+ llmModel,
62
+ maxSources: resolvedMaxSources,
63
+ stream: true,
64
+ onChunk: (text) => {
65
+ const payload = JSON.stringify({ type: 'chunk', text });
66
+ res.write(`data: ${payload}\n\n`);
67
+ },
68
+ };
69
+ try {
70
+ const result = await answerQuestion(answerReq);
71
+ const donePayload = JSON.stringify({
72
+ type: 'done',
73
+ citations: result.citations,
74
+ searchProvider: result.searchProvider,
75
+ llmProvider: result.llmProvider,
76
+ llmModel: result.llmModel,
77
+ tokensUsed: result.tokensUsed,
78
+ });
79
+ res.write(`data: ${donePayload}\n\n`);
80
+ }
81
+ catch (err) {
82
+ const errMsg = err instanceof Error ? err.message : 'Unknown error';
83
+ const errPayload = JSON.stringify({ type: 'error', message: errMsg });
84
+ res.write(`data: ${errPayload}\n\n`);
85
+ }
86
+ res.end();
87
+ return;
88
+ }
89
+ // --- Non-streaming response ---------------------------------------------
90
+ const answerReq = {
91
+ question: question.trim(),
92
+ searchProvider: resolvedSearchProvider,
93
+ searchApiKey: resolvedSearchApiKey,
94
+ llmProvider: llmProvider,
95
+ llmApiKey: llmApiKey.trim(),
96
+ llmModel,
97
+ maxSources: resolvedMaxSources,
98
+ stream: false,
99
+ };
100
+ const result = await answerQuestion(answerReq);
101
+ res.json({
102
+ answer: result.answer,
103
+ citations: result.citations,
104
+ searchProvider: result.searchProvider,
105
+ llmProvider: result.llmProvider,
106
+ llmModel: result.llmModel,
107
+ tokensUsed: result.tokensUsed,
108
+ });
109
+ }
110
+ catch (error) {
111
+ const err = error;
112
+ console.error('Answer error:', err);
113
+ res.status(500).json({
114
+ success: false,
115
+ error: {
116
+ type: 'answer_failed',
117
+ message: 'Failed to generate answer. Please try again.',
118
+ docs: 'https://webpeel.dev/docs/errors#answer_failed',
119
+ },
120
+ requestId: req.requestId,
121
+ });
122
+ }
123
+ });
124
+ return router;
125
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * GET /v1/ask?q=<question>&sources=3
3
+ * POST /v1/ask { "question": "...", "sources": 3 }
4
+ *
5
+ * LLM-free web Q&A: search → fetch top pages → BM25 → best answer
6
+ *
7
+ * Returns:
8
+ * {
9
+ * question: string,
10
+ * answer: string, // best passage from top sources
11
+ * confidence: number, // 0-1
12
+ * sources: [{url, title, snippet, confidence}],
13
+ * method: "bm25",
14
+ * elapsed: number // ms
15
+ * }
16
+ *
17
+ * No LLM key required — 100% deterministic BM25 ranking.
18
+ * Competitors: Tavily charges $50/mo and requires an API key.
19
+ * We do this with zero LLM cost, included in every plan.
20
+ *
21
+ * Performance targets:
22
+ * - Source pages fetched in parallel with 5s timeout (no browser escalation)
23
+ * - Early termination when high-confidence answer found (>=0.85)
24
+ * - 10s hard timeout on the entire flow
25
+ * - 5-minute in-memory cache for repeated questions
26
+ */
27
+ import { Router } from 'express';
28
+ export declare function createAskRouter(): Router;
@@ -0,0 +1,295 @@
1
+ /**
2
+ * GET /v1/ask?q=<question>&sources=3
3
+ * POST /v1/ask { "question": "...", "sources": 3 }
4
+ *
5
+ * LLM-free web Q&A: search → fetch top pages → BM25 → best answer
6
+ *
7
+ * Returns:
8
+ * {
9
+ * question: string,
10
+ * answer: string, // best passage from top sources
11
+ * confidence: number, // 0-1
12
+ * sources: [{url, title, snippet, confidence}],
13
+ * method: "bm25",
14
+ * elapsed: number // ms
15
+ * }
16
+ *
17
+ * No LLM key required — 100% deterministic BM25 ranking.
18
+ * Competitors: Tavily charges $50/mo and requires an API key.
19
+ * We do this with zero LLM cost, included in every plan.
20
+ *
21
+ * Performance targets:
22
+ * - Source pages fetched in parallel with 5s timeout (no browser escalation)
23
+ * - Early termination when high-confidence answer found (>=0.85)
24
+ * - 10s hard timeout on the entire flow
25
+ * - 5-minute in-memory cache for repeated questions
26
+ */
27
+ import { Router } from 'express';
28
+ import { peel } from '../../index.js';
29
+ import { quickAnswer } from '../../core/quick-answer.js';
30
+ import { getBestSearchProvider } from '../../core/search-provider.js';
31
+ import { rankSearchResults, scoreFetchedSources, } from '../../core/source-scoring.js';
32
+ import { selectEvidence, isUnusableEvidenceContent, } from '../../core/selective-evidence.js';
33
+ const resultCache = new Map();
34
+ const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
35
+ function getCacheKey(question, numSources) {
36
+ return `${question.trim().toLowerCase()}|${numSources}`;
37
+ }
38
+ function getFromCache(key) {
39
+ const entry = resultCache.get(key);
40
+ if (!entry)
41
+ return null;
42
+ if (Date.now() > entry.expiresAt) {
43
+ resultCache.delete(key);
44
+ return null;
45
+ }
46
+ return entry.result;
47
+ }
48
+ function setInCache(key, result) {
49
+ // Evict stale entries periodically (simple GC — keep max 500 entries)
50
+ if (resultCache.size >= 500) {
51
+ const now = Date.now();
52
+ for (const [k, v] of resultCache) {
53
+ if (v.expiresAt < now)
54
+ resultCache.delete(k);
55
+ }
56
+ }
57
+ resultCache.set(key, { result, expiresAt: Date.now() + CACHE_TTL_MS });
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // Route factory
61
+ // ---------------------------------------------------------------------------
62
+ export function createAskRouter() {
63
+ const router = Router();
64
+ async function handleAsk(question, numSources, req, res) {
65
+ const startMs = Date.now();
66
+ const elapsed = () => Date.now() - startMs;
67
+ if (!question?.trim()) {
68
+ res.status(400).json({ success: false, error: { type: 'missing_question', message: 'Provide q= or question= parameter', hint: 'GET /v1/ask?q=your+question or POST {"question": "your question"}', docs: 'https://webpeel.dev/docs/errors#missing_question' }, requestId: req.requestId });
69
+ return;
70
+ }
71
+ // Auth check — global middleware sets req.auth
72
+ const authId = req.auth?.keyInfo?.accountId || req.user?.userId;
73
+ if (!authId) {
74
+ res.status(401).json({ success: false, error: { type: 'authentication_required', message: 'API key required. Get one at https://app.webpeel.dev/keys', hint: 'Get a free API key at https://app.webpeel.dev/keys', docs: 'https://webpeel.dev/docs/errors#authentication_required' }, requestId: req.requestId });
75
+ return;
76
+ }
77
+ const clampedSources = Math.min(Math.max(numSources, 1), 5);
78
+ // Cache check — return cached result immediately for repeated questions
79
+ const cacheKey = getCacheKey(question, clampedSources);
80
+ const cached = getFromCache(cacheKey);
81
+ if (cached) {
82
+ if (process.env.DEBUG)
83
+ console.debug('[ask] cache hit in', elapsed(), 'ms');
84
+ res.json({ ...cached, elapsed: elapsed() });
85
+ return;
86
+ }
87
+ // -----------------------------------------------------------------------
88
+ // Total flow timeout — 10s hard cap.
89
+ // -----------------------------------------------------------------------
90
+ const TOTAL_TIMEOUT_MS = 10000;
91
+ let timedOut = false;
92
+ const totalTimer = setTimeout(() => { timedOut = true; }, TOTAL_TIMEOUT_MS);
93
+ try {
94
+ // Step 1: Search — fetch more results so we can intelligently rank/dedup
95
+ const searchStart = Date.now();
96
+ const { provider, apiKey } = getBestSearchProvider();
97
+ let rawSearchResults;
98
+ try {
99
+ // Fetch up to 2x more results than needed so ranking has candidates to work with
100
+ rawSearchResults = await provider.searchWeb(question.trim(), {
101
+ count: Math.min(clampedSources * 2, 10),
102
+ apiKey,
103
+ });
104
+ }
105
+ catch {
106
+ rawSearchResults = [];
107
+ }
108
+ if (process.env.DEBUG)
109
+ console.debug(`[ask] search ${Date.now() - searchStart}ms, ${rawSearchResults.length} results`);
110
+ if (!rawSearchResults.length) {
111
+ clearTimeout(totalTimer);
112
+ res.json({
113
+ question,
114
+ answer: null,
115
+ confidence: 0,
116
+ sources: [],
117
+ method: 'bm25',
118
+ elapsed: elapsed(),
119
+ });
120
+ return;
121
+ }
122
+ // -----------------------------------------------------------------------
123
+ // Step 2: Rank search results by authority + primary source (pre-fetch)
124
+ // This prioritizes official/high-authority sources and deduplicates domains
125
+ // before we spend time fetching pages.
126
+ // -----------------------------------------------------------------------
127
+ const rankedResults = rankSearchResults(rawSearchResults, question.trim(), {
128
+ maxPerDomain: 2,
129
+ });
130
+ // Take top N candidates after ranking
131
+ const sourceUrls = rankedResults.slice(0, clampedSources);
132
+ // -----------------------------------------------------------------------
133
+ // Step 3: Fetch top sources in parallel
134
+ // - noEscalate: true → skip browser escalation (simple HTTP only)
135
+ // - render: false → don't start headless browser
136
+ // - timeout: 5000 → 5s per source max
137
+ // - budget: 3000 → keep content manageable
138
+ // -----------------------------------------------------------------------
139
+ const PER_SOURCE_TIMEOUT_MS = 5000;
140
+ const fetchStart = Date.now();
141
+ const fetchPromises = sourceUrls.map((r) => Promise.race([
142
+ peel(r.url, {
143
+ render: false,
144
+ noEscalate: true,
145
+ format: 'markdown',
146
+ timeout: PER_SOURCE_TIMEOUT_MS,
147
+ budget: 3000,
148
+ }).then((result) => ({ result, searchResult: r })),
149
+ new Promise((_, reject) => setTimeout(() => reject(new Error('per-source timeout')), PER_SOURCE_TIMEOUT_MS)),
150
+ ]));
151
+ const fetched = await Promise.allSettled(fetchPromises);
152
+ if (process.env.DEBUG) {
153
+ const ok = fetched.filter(f => f.status === 'fulfilled').length;
154
+ console.debug(`[ask] fetch ${Date.now() - fetchStart}ms, ${ok}/${sourceUrls.length} ok`);
155
+ }
156
+ // -----------------------------------------------------------------------
157
+ // Step 4: BM25 score each fetched page with quickAnswer
158
+ // Early termination: if any source yields >=0.85 confidence, use it now
159
+ // -----------------------------------------------------------------------
160
+ const HIGH_CONFIDENCE_THRESHOLD = 0.85;
161
+ const answers = [];
162
+ for (const f of fetched) {
163
+ if (timedOut)
164
+ break;
165
+ if (f.status !== 'fulfilled')
166
+ continue;
167
+ const { result, searchResult } = f.value;
168
+ const qa = quickAnswer({
169
+ question,
170
+ content: result.content,
171
+ url: result.url,
172
+ maxPassages: 2,
173
+ });
174
+ const unusableFetchedContent = isUnusableEvidenceContent(result.content);
175
+ const effectiveAnswer = unusableFetchedContent
176
+ ? (searchResult.snippet || '')
177
+ : qa.answer;
178
+ const effectiveConfidence = unusableFetchedContent
179
+ ? Math.min(qa.confidence, 0.15)
180
+ : qa.confidence;
181
+ answers.push({
182
+ answer: effectiveAnswer,
183
+ bm25Score: effectiveConfidence,
184
+ searchResult,
185
+ fetchedUrl: result.url,
186
+ fetchedTitle: result.title || searchResult.title,
187
+ metadata: result.metadata,
188
+ freshnessData: result.freshness,
189
+ });
190
+ // Early termination on high confidence
191
+ if (effectiveConfidence >= HIGH_CONFIDENCE_THRESHOLD) {
192
+ if (process.env.DEBUG)
193
+ console.debug(`[ask] early exit confidence=${effectiveConfidence.toFixed(2)} at ${elapsed()}ms`);
194
+ break;
195
+ }
196
+ }
197
+ // -----------------------------------------------------------------------
198
+ // Step 5: Final combined scoring — BM25 + authority + freshness + primary
199
+ // -----------------------------------------------------------------------
200
+ const scoredSources = scoreFetchedSources(answers.map(a => ({
201
+ searchResult: {
202
+ url: a.fetchedUrl,
203
+ title: a.fetchedTitle,
204
+ snippet: a.searchResult.snippet,
205
+ },
206
+ bm25Score: a.bm25Score,
207
+ metadata: a.metadata,
208
+ freshnessData: a.freshnessData,
209
+ })), question.trim(), { maxPerDomain: 2 });
210
+ // Sort by final score — best answer is the highest-scored source
211
+ scoredSources.sort((a, b) => b.finalScore - a.finalScore);
212
+ // -----------------------------------------------------------------------
213
+ // Step 5b: Selective evidence aggregation (AttnRes-inspired)
214
+ // Re-rank evidence blocks across all fetched sources using query-aware
215
+ // scoring, credibility weighting, and domain diversity caps.
216
+ // -----------------------------------------------------------------------
217
+ const evidenceSources = answers.map(a => ({
218
+ url: a.fetchedUrl,
219
+ title: a.fetchedTitle,
220
+ content: a.answer || '',
221
+ snippet: a.searchResult.snippet,
222
+ metadata: a.metadata,
223
+ }));
224
+ const evidenceSelection = selectEvidence({
225
+ query: question.trim(),
226
+ sources: evidenceSources,
227
+ maxBlocks: 5,
228
+ maxChars: 3000,
229
+ });
230
+ // Map back to answer text — prefer the top evidence block when available,
231
+ // fall back to BM25 answer from the highest-scored source
232
+ const answerMap = new Map(answers.map(a => [a.fetchedUrl, a.answer]));
233
+ const bestSource = scoredSources[0];
234
+ const topEvidenceBlock = evidenceSelection.blocks[0];
235
+ const bestAnswer = topEvidenceBlock?.text
236
+ || (bestSource ? answerMap.get(bestSource.url) : undefined);
237
+ clearTimeout(totalTimer);
238
+ // Build enriched sources array for the response
239
+ const enrichedSources = scoredSources.map(s => ({
240
+ url: s.url,
241
+ title: s.title,
242
+ snippet: s.snippet,
243
+ confidence: s.confidence,
244
+ authority: s.authority,
245
+ freshness: s.freshness,
246
+ isPrimarySource: s.isPrimarySource,
247
+ }));
248
+ const response = {
249
+ question,
250
+ answer: bestAnswer || null,
251
+ confidence: bestSource?.confidence || 0,
252
+ sources: enrichedSources,
253
+ method: 'bm25',
254
+ elapsed: elapsed(),
255
+ evidencePolicy: evidenceSelection.policy.type,
256
+ evidenceSourcesUsed: evidenceSelection.sourcesUsed,
257
+ };
258
+ if (timedOut) {
259
+ response.warning = 'Partial result — 10s timeout reached';
260
+ }
261
+ // Cache successful results (only when we have an answer)
262
+ if (bestAnswer && !timedOut) {
263
+ setInCache(cacheKey, response);
264
+ }
265
+ if (process.env.DEBUG)
266
+ console.debug(`[ask] done ${elapsed()}ms confidence=${bestSource?.confidence?.toFixed(2) ?? 0}`);
267
+ res.json(response);
268
+ }
269
+ catch (err) {
270
+ clearTimeout(totalTimer);
271
+ if (process.env.DEBUG)
272
+ console.debug('[ask] error:', err);
273
+ res.json({
274
+ question,
275
+ answer: null,
276
+ confidence: 0,
277
+ sources: [],
278
+ method: 'bm25',
279
+ elapsed: elapsed(),
280
+ ...(timedOut ? { warning: 'Request timed out after 10s' } : {}),
281
+ });
282
+ }
283
+ }
284
+ router.get('/v1/ask', async (req, res) => {
285
+ const question = req.query.q || req.query.question || '';
286
+ const sources = Math.min(parseInt(req.query.sources || '3', 10) || 3, 5);
287
+ await handleAsk(question, sources, req, res);
288
+ });
289
+ router.post('/v1/ask', async (req, res) => {
290
+ const question = req.body?.question || req.body?.q || '';
291
+ const sources = Math.min(parseInt(req.body?.sources ?? 3, 10) || 3, 5);
292
+ await handleAsk(question, sources, req, res);
293
+ });
294
+ return router;
295
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Batch scrape API - process multiple URLs concurrently
3
+ */
4
+ import { Router } from 'express';
5
+ import type { IJobQueue } from '../job-queue.js';
6
+ export declare function createBatchRouter(jobQueue: IJobQueue): Router;