mcp-scraper 0.90.7 → 0.90.8

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 (50) hide show
  1. package/CHANGELOG.md +32 -1
  2. package/README.md +2 -2
  3. package/dist/{analytics-repository-FXS45ZTM.js → analytics-repository-IHOFBSUV.js} +1 -1
  4. package/dist/bin/api-server.js +1 -1
  5. package/dist/bin/mcp-scraper-cli.js +1 -1
  6. package/dist/bin/mcp-scraper-core.js +1 -1
  7. package/dist/bin/mcp-scraper-install.js +1 -1
  8. package/dist/bin/mcp-stdio-server.js +1 -1
  9. package/dist/bin/paa-harvest.js +1 -1
  10. package/dist/{chunk-5NQY2N7J.js → chunk-2F35B4U5.js} +2 -2
  11. package/dist/{chunk-BDLR4CCL.js → chunk-2SP57VCG.js} +6 -6
  12. package/dist/{chunk-ZKQRA6NQ.js → chunk-53IEEOKA.js} +167 -167
  13. package/dist/chunk-6DTXIZY2.js +1 -0
  14. package/dist/{chunk-YTEAWZEN.js → chunk-6FMIMP5Z.js} +1 -1
  15. package/dist/chunk-7SHEBDEB.js +1 -0
  16. package/dist/{chunk-LPEIHMYH.js → chunk-DKXZIIA5.js} +1 -1
  17. package/dist/{chunk-TBTA7VVZ.js → chunk-IK5BG7MO.js} +1 -1
  18. package/dist/{chunk-QUFR3KG2.js → chunk-J374DIKA.js} +1 -1
  19. package/dist/{chunk-I7IS7NTC.js → chunk-KZV2FLGG.js} +1 -1
  20. package/dist/{chunk-UKFNSXP3.js → chunk-LI7WHOII.js} +1 -1
  21. package/dist/{chunk-B2C7JU4O.js → chunk-LSFDB5XE.js} +1 -1
  22. package/dist/{chunk-DSK6RKBS.js → chunk-OIMPG6M6.js} +1 -1
  23. package/dist/{chunk-OT2HUS2G.js → chunk-OMYTA34L.js} +1 -1
  24. package/dist/chunk-ORB4RHCK.js +63 -0
  25. package/dist/chunk-OVTHAIDS.js +1 -0
  26. package/dist/{chunk-IGJKAECE.js → chunk-QTDLZTQ7.js} +1 -1
  27. package/dist/chunk-RK2VCTZI.js +1 -0
  28. package/dist/{chunk-TOJBPATJ.js → chunk-WJ4XFLS4.js} +159 -115
  29. package/dist/{chunk-74HHYSAZ.js → chunk-X7GZJU5P.js} +1 -1
  30. package/dist/{chunk-R7LCD65B.js → chunk-ZMNUI5LB.js} +7 -7
  31. package/dist/db-B5XJTOGN.js +1 -0
  32. package/dist/{extract-bundle-INT6JMJP.js → extract-bundle-II3RPATK.js} +10 -10
  33. package/dist/gmail-service-E5KORS6C.js +1 -0
  34. package/dist/index.cjs +18 -18
  35. package/dist/index.js +1 -1
  36. package/dist/{lead-list-enrichment-repository-B6Q4O4DG.js → lead-list-enrichment-repository-AWZZMY2H.js} +1 -1
  37. package/dist/{location-data-repository-CBI5K7MR.js → location-data-repository-6XAVI65Z.js} +1 -1
  38. package/dist/operation-metering-DB5F7SXN.js +1 -0
  39. package/dist/server-MI6XN25Z.js +4961 -0
  40. package/dist/{site-extract-repository-VPYOC3CP.js → site-extract-repository-JHSVJJ62.js} +1 -1
  41. package/dist/stripe-event-worker-7KNF3VH5.js +1 -0
  42. package/dist/worker-3VTFFYHH.js +1 -0
  43. package/package.json +1 -1
  44. package/dist/chunk-KDDU6BW3.js +0 -48
  45. package/dist/chunk-WEPU72WA.js +0 -1
  46. package/dist/db-SVSD2AWJ.js +0 -1
  47. package/dist/gmail-service-YCPMGW3E.js +0 -1
  48. package/dist/server-LYWW6XYE.js +0 -4956
  49. package/dist/stripe-event-worker-AQVRF24K.js +0 -1
  50. package/dist/worker-U43KLOLN.js +0 -1
@@ -1,4 +1,4 @@
1
- import{f as tt}from"./chunk-M5QHXNFZ.js";import{a as Ne}from"./chunk-4FROKQJN.js";import{a as Pe,b as be,c as At,e as We,j as Ie}from"./chunk-BDLR4CCL.js";import{a as me,c as Qt,d as yt,g as ve,l as Ae}from"./chunk-2TZBO52D.js";import{a as fe,i as Te,j as J,k as It,m as j,n as Ct,o as Zt}from"./chunk-TOJBPATJ.js";import{chromium as ee}from"playwright-extra";import Fn from"puppeteer-extra-plugin-stealth";import{chromium as Rn}from"playwright";var F={container:".eJH8qe.adDDi",dataInitq:"[data-initq]",item:".related-question-pair",itemDataQ:"data-q",itemDataInitQ:"data-initq",itemQuestionEl:".JlqpRe",answerContainer:".bCOlv, .hgKElc, .wDYxhc, .LGOjhe, .fo7IQd, .fmW3u",aiAnswerBody:".pWvJNd",aiCitation:"a.PMDqCb[href]",aiSourceCard:"a.vIWmYe[href], a.Zbfntb[href]",sourceTitle:"h3",sourceSite:".VuuXrf",sourceCite:"cite",clickTarget:".JlqpRe",expandedClass:"aoRk1c",captchaMarker:'#captcha-form, #recaptcha, form[action*="/sorry/"], .g-recaptcha, [data-sitekey]'},Le={container:'div[jscontroller="HWk0Gf"]',sectionHeading:'.mgAbYb[role="heading"]',item:"a.rIRoqf"},Lt={udm:"39",item:"a.rIRoqf",durationPattern:/^\d+:\d+$/,platforms:["YouTube","TikTok","Instagram","Facebook","X"]},xe={section:".ULSxyf",item:"a.KYg7td.INpicf",title:".hyYc0c",source:".K4ETW"},Oe={sectionTag:"g-section-with-header",sectionHeadingText:"What people are saying",card:'.dRzkFf[role="listitem"]',cardLink:'a.WlydOe[jsname="YKoRaf"]',titleH1:"h1.WQWxe",titleDiv:".eAaXgc",popularCommentLabel:".qgdis",source:".sTl1Td",platformBadge:".appd0, .KrMNbf",ytChannel:".sjVJQd",ytDate:".PLq9Je",authorNote:".nDgy9d"},Be={root:"[data-lhcontainer][data-streaming-container][eid]",legacyRoot:'[data-hveid="CBMQAA"]',wrapper:".Fgyi2e",controller:'[jscontroller="AkrxPe"]',contentSubtree:'[data-subtree="mfc"]',header:".heWuVc",heading:".Fzsovc.cwYVJe.RJPOee",showMoreButton:'[aria-label="Show more AI Overview"]',sourcesPanel:".OZ9ddf.WAUd4",disclaimer:".DuQANe.MSJHRb"},He={root:'[data-hveid="CAUQAA"]',wrapper:".Fgyi2e",citations:'.Fgyi2e [data-hveid] a[jsname="pxBnId"]'},Fe={result:".wHYlTd.tF2Cxc",title:"h3.LC20lb",siteName:".VuuXrf",cite:"cite.tjvcx",snippet:".VwiC3b",redditCite:"cite.qLRx3b",ratingWrap:".Y0A0hc",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Re={headingText:"Businesses",card:".w7Dbne",name:".OSrXXb",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Ge="2026-05-07",Si={ratingAndCount:"div.F7nice",hoursTable:"table.eK4R0e",reviewScrollPane:'div.m6QErb[tabindex="-1"]',reviewScrollPaneFallback:'[role="main"] div[tabindex="-1"]',reviewCardAuthor:"div.d4r55, span.d4r55, span.RPZfBb",reviewCardDate:"span.rsqaWe",reviewCardText:"span.wiI7pd",reviewCardOwnerBlock:"div.CDe7pd",hoursTableAlt:'table[aria-label*="Hour"]',reviewCard:"[data-review-id]",reviewStars:'[role="img"][aria-label*="star"]',reviewTab:'button[role="tab"][aria-label*="Review"]',aboutTab:'button[role="tab"][aria-label*="About"]',expandReview:'[data-review-id] button[aria-label*="See more"], [data-review-id] button.w8nwRe'};async function xt(e,t,n,a){let s,i=!1,d,U=()=>{},S=()=>a?.reason instanceof DOMException&&a.reason.name==="TimeoutError"?a.reason:new j,h=()=>U(S()),l=new Promise((r,u)=>{U=u}),o=async r=>{let u;try{await Promise.race([r.close().catch(()=>{}),new Promise(c=>{u=setTimeout(c,2e3)})])}finally{u&&clearTimeout(u)}};if(a?.aborted)throw S();a?.addEventListener("abort",h,{once:!0}),d=setTimeout(()=>U(new DOMException("Optional pagination timed out","TimeoutError")),3e4);try{return await Promise.race([(async()=>{let r=await e.newPage();if(i)throw await o(r),new j;if(s=r,await t(r),i)throw new j;return n(r)})(),l])}finally{i=!0,d&&clearTimeout(d),a?.removeEventListener("abort",h),s&&await o(s)}}var Hn=/\b(?:HeadlessChrome|Chrome|Chromium|Firefox)\/\d+|\bVersion\/\d+.*\bSafari\//;async function Ot(e){try{let t=await e.evaluate(()=>navigator.userAgent);return typeof t=="string"&&Hn.test(t)?t:null}catch{return null}}async function Bt(e){let t=null;try{let n=e.contexts().flatMap(a=>a.pages())[0];return n||(t=await e.newContext(),n=t.pages()[0]??await t.newPage()),await Ot(n)}catch{return null}finally{t&&await t.close().catch(()=>{})}}function ci(e,t){return t?{...e,userAgent:t}:e}ee.use(Fn());var Gn=180,Dn=3e3,Vn=5e3,En='#search, #rso, a[href] h3, [data-snhf], [role="main"]';function Xt(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}function Yn(e,t){let n=process.env[e];if(!n)return t;let a=Number(n);return Number.isInteger(a)&&a>0?a:t}function te(e){return e?e.slice(-6):null}function De(e,t){let n=(t??process.env.SERP_REDIRECT_BASE)?.trim().replace(/\/+$/,"");return n?`${n}/g/${Buffer.from(e,"utf8").toString("base64url")}`:e}function Kn(e){return e?/united states|u\.?s\.?a?\.?|^us$/i.test(e.trim()):!1}function ht(e){return e instanceof Error?e.message:String(e)}function Jn(e){return/\b409\b|conflict|already exists/i.test(ht(e))}function _n(e){return/\b404\b|not[ _-]?found|already (?:gone|deleted|closed)|does not exist/i.test(ht(e))}async function zn(e,t){try{await e.profiles.create({name:t})}catch(n){if(!Jn(n))throw n}}function Ht(e,t){return{viewport:e.viewport,locale:e.locale,...t?{userAgent:t}:{},...e.deviceScaleFactor?{deviceScaleFactor:e.deviceScaleFactor}:{},...e.isMobile!==void 0?{isMobile:e.isMobile}:{},...e.hasTouch!==void 0?{hasTouch:e.hasTouch}:{}}}async function Ut(e,t,n){let a;try{return await Promise.race([e,new Promise((s,i)=>{a=setTimeout(()=>i(new Error(`${n} timed out after ${t}ms`)),t)})])}finally{a&&clearTimeout(a)}}function qn(e){let t=e.trim();if(!t)throw new Error("channelHandle is required");if(/^https?:\/\//i.test(t)||/^(www\.|m\.)?youtube\.com\//i.test(t)){let d=new URL(/^https?:\/\//i.test(t)?t:`https://${t}`);if(d.hostname.replace(/^www\./,"").replace(/^m\./,"").toLowerCase()!=="youtube.com")throw new Error("channel URL must be on youtube.com");let S=d.pathname.split("/").filter(Boolean),h=S[0]??"",l=S[1]??"";if(h.startsWith("@"))return`https://www.youtube.com/${h}/videos`;if(h==="channel"&&l)return`https://www.youtube.com/channel/${l}/videos`;if((h==="c"||h==="user")&&l)return`https://www.youtube.com/${h}/${l}/videos`;throw new Error("channel URL must be a YouTube handle, /channel/UC..., /c/..., or /user/... URL")}let s=t.replace(/^\/+/,"").replace(/\/+$/,"").replace(/\/videos$/i,"");if(/^UC[\w-]{20,}$/.test(s))return`https://www.youtube.com/channel/${s}/videos`;let i=s.startsWith("@")?s:`@${s}`;if(!/^@[\w.-]+$/.test(i))throw new Error("channelHandle must be an @handle, UC channel ID, or YouTube channel URL");return`https://www.youtube.com/${i}/videos`}var Ft=class{browser=null;context=null;page=null;\u006b\u0065\u0072\u006e\u0065\u006cClient=null;\u006b\u0065\u0072\u006e\u0065\u006cSessionId=null;\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=null;\u006b\u0065\u0072\u006e\u0065\u006cStealth=null;\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed=null;\u006b\u0065\u0072\u006e\u0065\u006cProxySource=null;\u006b\u0065\u0072\u006e\u0065\u006cProxyType=null;\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=null;debugEnabled=!1;debugSnapshot={\u006b\u0065\u0072\u006e\u0065\u006c:null,context:null,networkLocation:null,serpNavigation:null};async launch(t){this.debugEnabled=t.debug===!0;let n=t.proxyMode??(t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId?"configured":"none"),a=t.isMobile?"mobile":"desktop";if(this.debugSnapshot={\u006b\u0065\u0072\u006e\u0065\u006c:null,context:{viewport:t.viewport,locale:t.locale,device:a,userAgent:null,deviceScaleFactor:t.deviceScaleFactor??null,isMobile:t.isMobile===!0,hasTouch:t.hasTouch===!0},networkLocation:null,serpNavigation:null},t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey){this.\u006b\u0065\u0072\u006e\u0065\u006cClient=new tt({apiKey:t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey});let i=Number.isInteger(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds)&&Number(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds)>0?Number(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds):Yn("\u004b\u0045\u0052\u004e\u0045\u004c_BROWSER_TIMEOUT_SECONDS",Gn),d=Math.min(i,600);t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName&&t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges===!0&&await zn(this.\u006b\u0065\u0072\u006e\u0065\u006cClient,t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName);let U=At(),S;t.headlessMode==="headful"||U?.forceHeadful===!0?S=!1:t.headlessMode==="headless"?S=!0:S=U?.forceHeadless===!0||process.env.\u004b\u0045\u0052\u004e\u0045\u004c_HEADLESS_DISABLED!=="true"&&!!U?.op&&We.has(U.op),this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=S?!0:null,U?.headlessSentOut&&(U.headlessSentOut.value=this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent);let h=await this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.create({stealth:t.\u006b\u0065\u0072\u006e\u0065\u006cStealth===!0,timeout_seconds:d,...S?{headless:!0}:{},...t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId?{proxy_id:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId}:{},...t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName?{profile:{name:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName,...typeof t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges=="boolean"?{save_changes:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges}:{}}}:{}});this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId=h.session_id,this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=Date.now(),this.\u006b\u0065\u0072\u006e\u0065\u006cStealth=typeof h.stealth=="boolean"?h.stealth:null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed=typeof h.proxy_id=="string"?!!h.proxy_id:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource=t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.source??null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType=t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.proxyType??null;let l=null,o=null;if(!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId&&!t.keepDefaultProxy)try{await Ut(this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.update(this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,{disable_default_proxy:!0}),5e3,`\u004b\u0065\u0072\u006e\u0065\u006c session ${this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId} disable default proxy`),l=!0}catch(u){l=!1,o=ht(u)}let r={sessionId:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,proxyMode:n,requestedProxyIdPresent:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,requestedProxyIdSuffix:te(t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId),createdProxyIdPresent:typeof h.proxy_id=="string"?!!h.proxy_id:null,createdProxyIdSuffix:te(h.proxy_id),retrievedProxyIdPresent:null,retrievedProxyIdSuffix:null,retrievedProxyIdMatchesRequested:null,defaultProxyDisabled:l,defaultProxyDisableError:o,proxyResolution:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution??null,timeoutSeconds:d,stealth:typeof h.stealth=="boolean"?h.stealth:null,profilePresent:null,poolPresent:null,retrieveError:null};if(this.debugSnapshot.\u006b\u0065\u0072\u006e\u0065\u006c=r,console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_created",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,timeout_seconds:d,proxy_mode:n,proxy_id_present:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,profile_name_present:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName,proxy_resolution_source:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.source})),this.debugEnabled&&await this.populate\u004b\u0065\u0072\u006e\u0065\u006cRetrieveDebug(r,t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId),this.browser=await Rn.connectOverCDP(h.cdp_ws_url),t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName||t.preserve\u004b\u0065\u0072\u006e\u0065\u006cContext)this.context=this.browser.contexts()[0]??await this.browser.newContext(Ht(t)),this.page=this.context.pages()[0]??await this.context.newPage(),this.debugSnapshot.context.userAgent=await Ot(this.page);else{let u=await Bt(this.browser);this.debugSnapshot.context.userAgent=u,this.context=await this.browser.newContext(Ht(t,u)),this.page=await this.context.newPage()}if(await this.installEsbuildHelperShims(this.context),t.preserve\u004b\u0065\u0072\u006e\u0065\u006cContext||await this.page.setViewportSize(t.viewport),(this.debugEnabled||t.requireUsEgress)&&(this.debugSnapshot.networkLocation=await this.captureBrowserNetworkLocation()),t.requireUsEgress){let u=this.debugSnapshot.networkLocation?.country??null;if(!Kn(u))throw new J(`Non-US egress (${u??"unknown"}) \u2014 retrying with a fresh session`)}return}let s={headless:t.headless,proxy:t.proxy?{server:t.proxy}:void 0,...t.browserExecutablePath?{executablePath:t.browserExecutablePath}:{},...t.ignoreDefaultArgs?{ignoreDefaultArgs:t.ignoreDefaultArgs}:{}};if(t.profileDir)this.context=await ee.launchPersistentContext(t.profileDir,{...s,...Ht(t)}),await this.installEsbuildHelperShims(this.context),this.page=await this.context.newPage(),this.debugSnapshot.context.userAgent=await Ot(this.page);else{this.browser=await ee.launch(s);let i=await Bt(this.browser);this.debugSnapshot.context.userAgent=i,this.context=await this.browser.newContext(Ht(t,i)),await this.installEsbuildHelperShims(this.context),this.page=await this.context.newPage()}this.debugEnabled&&(this.debugSnapshot.networkLocation=await this.captureBrowserNetworkLocation())}async populate\u004b\u0065\u0072\u006e\u0065\u006cRetrieveDebug(t,n){if(!(!this.\u006b\u0065\u0072\u006e\u0065\u006cClient||!this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId))try{let a=await Ut(this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.retrieve(this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId),5e3,`\u004b\u0065\u0072\u006e\u0065\u006c session ${this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId} retrieve`);t.retrievedProxyIdPresent=typeof a.proxy_id=="string"?!!a.proxy_id:!1,t.retrievedProxyIdSuffix=te(a.proxy_id),t.retrievedProxyIdMatchesRequested=n?a.proxy_id===n:!a.proxy_id,t.timeoutSeconds=typeof a.timeout_seconds=="number"?a.timeout_seconds:t.timeoutSeconds,t.stealth=typeof a.stealth=="boolean"?a.stealth:t.stealth,t.profilePresent=!!a.profile,t.poolPresent=!!a.pool}catch(a){t.retrieveError=ht(a)}}async captureBrowserNetworkLocation(){let t=(a,s="ipapi.co")=>({source:s,ip:null,city:null,region:null,country:null,org:null,timezone:null,error:a});if(!this.context)return t("browser context is not available");let n=null;try{n=await this.context.newPage();let a=await this.loadJsonInDebugPage(n,"https://ipwho.is/");if(a){let U=typeof a.connection=="object"&&a.connection!==null?a.connection:{};return{source:"ipwho.is",ip:typeof a.ip=="string"?a.ip:null,city:typeof a.city=="string"?a.city:null,region:typeof a.region=="string"?a.region:null,country:typeof a.country=="string"?a.country:null,org:typeof U.org=="string"?U.org:null,timezone:typeof a.timezone=="object"&&a.timezone!==null&&typeof a.timezone.id=="string"?a.timezone.id:null,error:null}}let s=await this.loadJsonInDebugPage(n,"https://api64.ipify.org?format=json");if(s)return{source:"api64.ipify.org",ip:typeof s.ip=="string"?s.ip:null,city:null,region:null,country:null,org:null,timezone:null,error:null};await Ut(n.goto("https://ipapi.co/json/",{waitUntil:"domcontentloaded",timeout:7e3}),8e3,"browser network location navigation");let i=await n.locator("body").innerText({timeout:2e3}),d=JSON.parse(i);return{source:"ipapi.co",ip:typeof d.ip=="string"?d.ip:null,city:typeof d.city=="string"?d.city:null,region:typeof d.region=="string"?d.region:null,country:typeof d.country_name=="string"?d.country_name:typeof d.country=="string"?d.country:null,org:typeof d.org=="string"?d.org:null,timezone:typeof d.timezone=="string"?d.timezone:null,error:null}}catch(a){return t(ht(a))}finally{await n?.close().catch(()=>{})}}async loadJsonInDebugPage(t,n){try{await Ut(t.goto(n,{waitUntil:"domcontentloaded",timeout:7e3}),8e3,`browser network location navigation ${n}`);let a=await t.locator("body").innerText({timeout:2e3});return JSON.parse(a)}catch{return null}}async installEsbuildHelperShims(t){await t.addInitScript(()=>{let n=globalThis;typeof n.__name!="function"&&(n.__name=a=>a),typeof n.__publicField!="function"&&(n.__publicField=(a,s,i)=>(a[s]=i,i))})}async withTemporaryPage(t,n){if(!this.context)throw new Error("Browser context is not available");return xt(this.context,async()=>{},t,n)}async navigateToSERP(t,n,a,s,i){let d=new URLSearchParams({q:t,gl:a,hl:s,pws:"0"});i?.tbs&&d.set("tbs",i.tbs),n&&d.set("uule",n);let U="https://www.google.com/search?"+d.toString(),S=De(U),h=i?.debug?{requestedUrl:U,finalUrl:null,title:null,bodySnippet:null,hasPaa:null,captchaDetected:null,googleSorryUrl:null,redirected:null}:null;h&&(this.debugSnapshot.serpNavigation=h);try{await this.page.goto(S,{waitUntil:"domcontentloaded",timeout:Xt(i?.deadlineMs,i?.purpose==="serp"?8e3:45e3)})}catch(o){await this.updateSerpNavigationDebug(h,U,{hasPaa:null,captchaDetected:null});let r=await this.captureDiagnostics(U);throw new It(`page.goto failed: ${o.message} | ${r}`)}if(await this.isSerpChallengeVisible())throw await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!0}),new J(this.captchaMessage());if(i?.purpose==="serp"){await this.page.waitForSelector(En,{timeout:Xt(i.deadlineMs,1500)}).catch(()=>null);let o=await this.page.locator(F.item).count().catch(()=>0)>0;return await this.updateSerpNavigationDebug(h,U,{hasPaa:o,captchaDetected:!1}),{hasPaa:o}}if(await this.page.waitForSelector(F.item,{timeout:Xt(i?.deadlineMs,4e3)}).catch(()=>null))return await this.updateSerpNavigationDebug(h,U,{hasPaa:!0,captchaDetected:!1}),{hasPaa:!0};if(await this.isSerpChallengeVisible())throw await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!0}),new J(this.captchaMessage());for(let o=1;o<=6;o++)if(await this.page.evaluate(u=>{window.scrollTo(0,document.body.scrollHeight*u)},o/6),await this.page.waitForTimeout(600),await this.page.locator(F.item).count()>0)return await this.updateSerpNavigationDebug(h,U,{hasPaa:!0,captchaDetected:!1}),{hasPaa:!0};return await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!1}),{hasPaa:!1}}async isSerpChallengeVisible(){if(!this.page)return!1;if(await this.page.locator(F.captchaMarker).count().catch(()=>0)>0)return!0;let n=this.page.url();if(/google\.[^/]+\/sorry\//i.test(n))return!0;let a=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,1e3)).catch(()=>"");return/recaptcha|unusual traffic|are you a robot|about this page|detected unusual traffic/i.test(a)}async updateSerpNavigationDebug(t,n,a){if(!(!t||!this.page))try{let s=this.page.url(),i=await this.page.title().catch(()=>""),d=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,500)).catch(()=>""),U=/recaptcha|unusual traffic|are you a robot/i.test(d);t.finalUrl=s,t.title=i,t.bodySnippet=d,t.hasPaa=a.hasPaa,t.captchaDetected=a.captchaDetected??U,t.googleSorryUrl=/google\.[^/]+\/sorry\//i.test(s),t.redirected=s!==n}catch(s){t.bodySnippet=`debug capture failed: ${ht(s)}`}}async captureDiagnostics(t){try{let n=this.page.url(),a=await this.page.title().catch(()=>""),s=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,400)).catch(()=>""),i=/consent\.google\./.test(n)||/before you continue/i.test(s),d=/recaptcha|unusual traffic|are you a robot/i.test(s),U=[i?"CONSENT_WALL":"",d?"BOT_CHALLENGE":"",n!==t?"REDIRECTED":""].filter(Boolean).join(",");return`intended=${t} | final=${n} | title="${a}" | flags=[${U}] | body="${s}"`}catch(n){return`diagnostics-failed: ${n.message}`}}captchaMessage(){return this.\u006b\u0065\u0072\u006e\u0065\u006cClient?"Google returned a CAPTCHA on this session \u2014 retrying with a fresh session.":fe}async navigateTo(t){let n=process.env.ADS_ARRIVAL_REDIRECT_BASE?.trim(),a=n?De(t,n):t;try{if(await this.page.goto(a,{waitUntil:"domcontentloaded",timeout:45e3}),/google\.[^/]+\/search\?/i.test(t)&&await this.isSerpChallengeVisible())throw new J(this.captchaMessage())}catch(s){if(s instanceof J)throw s;let i=await this.captureDiagnostics(t);throw new It(`page.goto failed: ${s.message} | ${i}`)}}async navigateToChannel(t){let n=qn(t);try{await this.page.goto(n,{waitUntil:"networkidle",timeout:3e4})}catch(a){let s=await this.captureDiagnostics(n);throw new It(`navigateToChannel failed: ${a.message} | ${s}`)}}async evaluate(t,n){return this.page.evaluate(t,n)}getPage(){return this.page}get\u004b\u0065\u0072\u006e\u0065\u006cSessionId(){return this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId}getProviderSessionMetadata(){return{provider:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId?"\u006b\u0065\u0072\u006e\u0065\u006c":"local",providerSessionId:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,disconnectObservation:null}}getDebugSnapshot(){return this.debugSnapshot}async close(){if(this.browser){let t=this.browser,n=this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,a=this.\u006b\u0065\u0072\u006e\u0065\u006cClient,s=this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs,i=this.\u006b\u0065\u0072\u006e\u0065\u006cStealth,d=this.\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed,U=this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource,S=this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType,h=this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent,l=this.getProviderSessionMetadata();if(this.browser=null,this.context=null,this.page=null,this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId=null,this.\u006b\u0065\u0072\u006e\u0065\u006cClient=null,this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=null,this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource=null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType=null,a&&n&&s!=null&&Ie({\u006b\u0065\u0072\u006e\u0065\u006cSessionId:n,source:"browser_driver",stealth:i,headlessSent:h,proxyUsed:d,proxySource:U,proxyType:S,openedAtMs:s,closedAtMs:Date.now()}),a&&n){console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_started",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n}));let o=Ut(a.browsers.deleteByID(n),Vn,`\u004b\u0065\u0072\u006e\u0065\u006c session ${n} delete`),r=Ut(t.close(),Dn,`\u004b\u0065\u0072\u006e\u0065\u006c browser ${n} close`),[u,c]=await Promise.allSettled([o,r]),g=u.status==="rejected"&&_n(u.reason),v={\u006b\u0065\u0072\u006e\u0065\u006cSessionId:n,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!0,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:u.status==="fulfilled"||g,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:u.status==="rejected"&&!g?u.reason instanceof Error?u.reason.message:String(u.reason):null,browserCloseSucceeded:c.status==="fulfilled",browserCloseError:c.status==="rejected"?c.reason instanceof Error?c.reason.message:String(c.reason):null,provider:l.provider,providerSessionId:l.providerSessionId,providerDisconnectObserved:!1,providerDisconnectMessage:null};return u.status==="rejected"&&!g?(console.warn(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_failed",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n,message:v.\u006b\u0065\u0072\u006e\u0065\u006cDeleteError})),console.warn(`\u004b\u0065\u0072\u006e\u0065\u006c session cleanup failed for ${n}:`,u.reason)):console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_succeeded",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n})),c.status==="rejected"&&(console.warn(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_close_failed",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n,message:v.browserCloseError})),console.warn(`\u004b\u0065\u0072\u006e\u0065\u006c browser close failed for ${n}:`,c.reason)),v}return await t.close(),{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:!0,browserCloseError:null,provider:l.provider,providerSessionId:l.providerSessionId,providerDisconnectObserved:!1,providerDisconnectMessage:null}}else if(this.context){let t=this.context;return this.context=null,this.page=null,await t.close(),{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:!0,browserCloseError:null,provider:"local",providerSessionId:null,providerDisconnectObserved:!1,providerDisconnectMessage:null}}return{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:null,browserCloseError:null,provider:"local",providerSessionId:null,providerDisconnectObserved:!1,providerDisconnectMessage:null}}};import{chromium as Qn}from"playwright";function $n(e,t){if(typeof e!="string")return null;let n=e.replace(/[\u0000-\u001f\u007f]+/g," ").replace(/\s+/g," ").trim();return n?n.slice(0,t):null}function Ve(e){let t=$n(e,320);return t?t.replace(/\b(?:wss?|https?):\/\/\S+/gi,"[redacted endpoint]").replace(/\b(?:authorization|proxy-authorization):\s*\S+/gi,"$1: [redacted]").replace(/\bBearer\s+\S+/gi,"Bearer [redacted]").slice(0,320):null}function Ee(e){return Ve(e)}function Ye(e){if(typeof e!="string"||e.length===0||e.length>512||e.trim()!==e||/[\s\u0000-\u001f\u007f]/.test(e)||/:\/\//.test(e))throw new Error("\u0042\u0072\u0069\u0067\u0068\u0074 \u0044\u0061\u0074\u0061 did not return a valid browser session ID");return e}function ne(e,t,n=new Date().toISOString()){let a=Ve(t);return{source:e,message:a??e.replaceAll("_"," "),observedAt:n}}function jn(e){return{provider:e.provider,providerDisconnectObserved:e.disconnectObservation!==null,providerDisconnectMessage:e.disconnectObservation?.message??null}}function Ke(e){return{...jn(e),providerSessionId:e.providerSessionId}}var Zn=new Set(["image","media","font","stylesheet","ping"]),Xn=["doubleclick.net","googleadservices.com","googlesyndication.com","google-analytics.com"],ta='#search, #rso, a[href] h3, [data-snhf], [role="main"]',ea=3e4,Je=1500;function Rt(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}function _e(){return process.env.\u0042\u0052\u0049\u0047\u0048\u0054\u0044\u0041\u0054\u0041_BROWSER_WSS?.trim()||null}function ze(){return process.env.SERP_BROWSER_PROVIDER?.trim().toLowerCase()==="\u006b\u0065\u0072\u006e\u0065\u006c"?!1:!!_e()}async function ae(e,t=!1){let n=e.request();try{let a=await n.allHeaders(),s=await fetch(n.url(),{method:n.method(),headers:{accept:a.accept??"*/*","accept-language":a["accept-language"]??"en-US,en;q=0.9","user-agent":a["user-agent"]??"Mozilla/5.0",...t?{cookie:a.cookie??"",referer:a.referer??"https://www.google.com/",...a["x-client-data"]?{"x-client-data":a["x-client-data"]}:{}}:{}},body:n.method()==="GET"||n.method()==="HEAD"?void 0:n.postData()});if(!s.ok)return!1;let i=Buffer.from(await s.arrayBuffer());return await e.fulfill({status:s.status,contentType:s.headers.get("content-type")??"application/octet-stream",headers:{"cache-control":"public, max-age=3600"},body:i}),!0}catch{return!1}}var Gt=class{browser=null;context=null;page=null;cdpSession=null;providerSessionId=null;disconnectObservation=null;closing=!1;observeDisconnect(t,n){this.closing||this.disconnectObservation||(this.disconnectObservation=ne(t,n))}async launch(t){if(this.page)return;this.closing=!1,this.providerSessionId=null,this.disconnectObservation=null;let n=_e();if(!n)throw new Error("SERP browser service is not configured");this.browser=await Qn.connectOverCDP(n,{timeout:Rt(t.operationDeadlineMs,ea)}),this.context=this.browser.contexts()[0]??await this.browser.newContext(),await this.context.addInitScript(()=>{let i=globalThis;typeof i.__name!="function"&&(i.__name=d=>d),typeof i.__publicField!="function"&&(i.__publicField=(d,U,S)=>(d[U]=S,S))}),this.page=this.context.pages()[0]??await this.context.newPage(),this.browser.on("disconnected",()=>this.observeDisconnect("browser_disconnected")),this.context.on("close",()=>this.observeDisconnect("context_closed")),this.page.on("close",()=>this.observeDisconnect("page_closed")),this.page.on("crash",()=>this.observeDisconnect("page_crashed")),this.cdpSession=await this.context.newCDPSession(this.page);let s=await this.cdpSession.send("Browser.getSessionId");this.providerSessionId=Ye(s?.sessionId),await this.setupPage(this.page)}async setupPage(t){await t.route("**/*",async n=>{let a=n.request(),s=a.resourceType(),i;try{i=new URL(a.url())}catch{await n.continue();return}let d=i.hostname.toLowerCase();if(!(i.pathname==="/sgasync"&&await ae(n,!0))&&!(i.pathname.includes("/shared_dict/")&&await ae(n))&&!(s==="script"&&(d==="www.google.com"||d==="www.gstatic.com")&&await ae(n))){if(Zn.has(s)){await n.abort("blockedbyclient");return}if(Xn.some(U=>d===U||d.endsWith(`.${U}`))){await n.abort("blockedbyclient");return}await n.continue()}})}async withTemporaryPage(t,n){if(!this.context||this.closing)throw new Error("Browser context is not available");return xt(this.context,a=>this.setupPage(a),t,n)}async navigateToSERP(t,n,a,s,i){if(!this.page)throw new Error("Browser page is not available");let d=new URLSearchParams({q:t,gl:a,hl:s,pws:"0"});return i?.tbs&&d.set("tbs",i.tbs),n&&d.set("uule",n),await this.page.goto(`https://www.google.com/search?${d}`,{waitUntil:"domcontentloaded",timeout:Rt(i?.deadlineMs,i?.purpose==="serp"?8e3:45e3)}),i?.purpose==="serp"?(await this.page.waitForSelector(ta,{timeout:Rt(i.deadlineMs,1500)}).catch(()=>null),{hasPaa:await this.page.locator(F.item).count().catch(()=>0)>0}):{hasPaa:!!await this.page.waitForSelector(F.item,{timeout:Rt(i?.deadlineMs,8e3)}).catch(()=>null)}}async navigateTo(t){if(!this.page)throw new Error("Browser page is not available");await this.page.goto(t,{waitUntil:"load",timeout:45e3})}async navigateToChannel(){throw new Error("YouTube navigation is not supported by the SERP browser driver")}async evaluate(t,n){if(!this.page)throw new Error("Browser page is not available");return this.page.evaluate(t,n)}getPage(){if(!this.page)throw new Error("Browser page is not available");return this.page}get\u004b\u0065\u0072\u006e\u0065\u006cSessionId(){return null}getProviderSessionMetadata(){return{provider:"\u0062\u0072\u0069\u0067\u0068\u0074_\u0064\u0061\u0074\u0061_browser_api",providerSessionId:this.providerSessionId,disconnectObservation:this.disconnectObservation}}getDebugSnapshot(){return{\u006b\u0065\u0072\u006e\u0065\u006c:null,context:null,networkLocation:null,serpNavigation:null}}async close(){this.closing=!0;let t=null,n;try{let s=this.browser?.close();s&&await Promise.race([s,new Promise((i,d)=>{n=setTimeout(()=>d(new Error(`Browser close acknowledgement exceeded ${Je}ms`)),Je)})])}catch(s){t=Ee(s instanceof Error?s.message:String(s))??"\u0042\u0072\u0069\u0067\u0068\u0074 \u0044\u0061\u0074\u0061 browser close failed",this.disconnectObservation??=ne("browser_close_error",t)}finally{n&&clearTimeout(n)}let a=Ke(this.getProviderSessionMetadata());return this.browser=null,this.context=null,this.page=null,this.cdpSession=null,{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:t===null,browserCloseError:t,...a}}};function qe(e){return e.plannedProvider==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?new Gt:new Ft}var st={austin:"Austin,Texas,United States","new york":"New York,New York,United States","new york city":"New York,New York,United States",nyc:"New York,New York,United States","los angeles":"Los Angeles,California,United States",la:"Los Angeles,California,United States",chicago:"Chicago,Illinois,United States",houston:"Houston,Texas,United States",phoenix:"Phoenix,Arizona,United States",philadelphia:"Philadelphia,Pennsylvania,United States",philly:"Philadelphia,Pennsylvania,United States","san antonio":"San Antonio,Texas,United States",dallas:"Dallas,Texas,United States",miami:"Miami,Florida,United States",seattle:"Seattle,Washington,United States",denver:"Denver,Colorado,United States",loveland:"Loveland,Colorado,United States","loveland co":"Loveland,Colorado,United States","fort collins":"Fort Collins,Colorado,United States",boulder:"Boulder,Colorado,United States","colorado springs":"Colorado Springs,Colorado,United States",boston:"Boston,Massachusetts,United States",atlanta:"Atlanta,Georgia,United States","san francisco":"San Francisco,California,United States",sf:"San Francisco,California,United States",portland:"Portland,Oregon,United States","las vegas":"Las Vegas,Nevada,United States",minneapolis:"Minneapolis,Minnesota,United States",detroit:"Detroit,Michigan,United States",nashville:"Nashville,Tennessee,United States",charlotte:"Charlotte,North Carolina,United States",orlando:"Orlando,Florida,United States","san diego":"San Diego,California,United States",baltimore:"Baltimore,Maryland,United States",sacramento:"Sacramento,California,United States",columbus:"Columbus,Ohio,United States",indianapolis:"Indianapolis,Indiana,United States","san jose":"San Jose,California,United States","fort worth":"Fort Worth,Texas,United States",jacksonville:"Jacksonville,Florida,United States",memphis:"Memphis,Tennessee,United States",louisville:"Louisville,Kentucky,United States",raleigh:"Raleigh,North Carolina,United States",richmond:"Richmond,Virginia,United States","salt lake city":"Salt Lake City,Utah,United States",toronto:"Toronto,Ontario,Canada",vancouver:"Vancouver,British Columbia,Canada",montreal:"Montreal,Quebec,Canada",calgary:"Calgary,Alberta,Canada",ottawa:"Ottawa,Ontario,Canada",london:"London,England,United Kingdom",manchester:"Manchester,England,United Kingdom",birmingham:"Birmingham,England,United Kingdom",edinburgh:"Edinburgh,Scotland,United Kingdom",glasgow:"Glasgow,Scotland,United Kingdom",leeds:"Leeds,England,United Kingdom",sydney:"Sydney,New South Wales,Australia",melbourne:"Melbourne,Victoria,Australia",brisbane:"Brisbane,Queensland,Australia",perth:"Perth,Western Australia,Australia",adelaide:"Adelaide,South Australia,Australia",dublin:"Dublin,Leinster,Ireland"};var $e=`3, Nanjemoy,Maryland,United States
1
+ import{f as tt}from"./chunk-M5QHXNFZ.js";import{a as Ne}from"./chunk-4FROKQJN.js";import{c as We,g as Ie}from"./chunk-2SP57VCG.js";import{a as Pe,b as be,c as At}from"./chunk-6DTXIZY2.js";import{a as me,c as Qt,d as yt,g as ve,l as Ae}from"./chunk-2TZBO52D.js";import{a as fe,i as Te,j as J,k as It,m as j,n as Ct,o as Zt}from"./chunk-WJ4XFLS4.js";import{chromium as ee}from"playwright-extra";import Fn from"puppeteer-extra-plugin-stealth";import{chromium as Rn}from"playwright";var F={container:".eJH8qe.adDDi",dataInitq:"[data-initq]",item:".related-question-pair",itemDataQ:"data-q",itemDataInitQ:"data-initq",itemQuestionEl:".JlqpRe",answerContainer:".bCOlv, .hgKElc, .wDYxhc, .LGOjhe, .fo7IQd, .fmW3u",aiAnswerBody:".pWvJNd",aiCitation:"a.PMDqCb[href]",aiSourceCard:"a.vIWmYe[href], a.Zbfntb[href]",sourceTitle:"h3",sourceSite:".VuuXrf",sourceCite:"cite",clickTarget:".JlqpRe",expandedClass:"aoRk1c",captchaMarker:'#captcha-form, #recaptcha, form[action*="/sorry/"], .g-recaptcha, [data-sitekey]'},Le={container:'div[jscontroller="HWk0Gf"]',sectionHeading:'.mgAbYb[role="heading"]',item:"a.rIRoqf"},Lt={udm:"39",item:"a.rIRoqf",durationPattern:/^\d+:\d+$/,platforms:["YouTube","TikTok","Instagram","Facebook","X"]},xe={section:".ULSxyf",item:"a.KYg7td.INpicf",title:".hyYc0c",source:".K4ETW"},Oe={sectionTag:"g-section-with-header",sectionHeadingText:"What people are saying",card:'.dRzkFf[role="listitem"]',cardLink:'a.WlydOe[jsname="YKoRaf"]',titleH1:"h1.WQWxe",titleDiv:".eAaXgc",popularCommentLabel:".qgdis",source:".sTl1Td",platformBadge:".appd0, .KrMNbf",ytChannel:".sjVJQd",ytDate:".PLq9Je",authorNote:".nDgy9d"},Be={root:"[data-lhcontainer][data-streaming-container][eid]",legacyRoot:'[data-hveid="CBMQAA"]',wrapper:".Fgyi2e",controller:'[jscontroller="AkrxPe"]',contentSubtree:'[data-subtree="mfc"]',header:".heWuVc",heading:".Fzsovc.cwYVJe.RJPOee",showMoreButton:'[aria-label="Show more AI Overview"]',sourcesPanel:".OZ9ddf.WAUd4",disclaimer:".DuQANe.MSJHRb"},He={root:'[data-hveid="CAUQAA"]',wrapper:".Fgyi2e",citations:'.Fgyi2e [data-hveid] a[jsname="pxBnId"]'},Fe={result:".wHYlTd.tF2Cxc",title:"h3.LC20lb",siteName:".VuuXrf",cite:"cite.tjvcx",snippet:".VwiC3b",redditCite:"cite.qLRx3b",ratingWrap:".Y0A0hc",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Re={headingText:"Businesses",card:".w7Dbne",name:".OSrXXb",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Ge="2026-05-07",Si={ratingAndCount:"div.F7nice",hoursTable:"table.eK4R0e",reviewScrollPane:'div.m6QErb[tabindex="-1"]',reviewScrollPaneFallback:'[role="main"] div[tabindex="-1"]',reviewCardAuthor:"div.d4r55, span.d4r55, span.RPZfBb",reviewCardDate:"span.rsqaWe",reviewCardText:"span.wiI7pd",reviewCardOwnerBlock:"div.CDe7pd",hoursTableAlt:'table[aria-label*="Hour"]',reviewCard:"[data-review-id]",reviewStars:'[role="img"][aria-label*="star"]',reviewTab:'button[role="tab"][aria-label*="Review"]',aboutTab:'button[role="tab"][aria-label*="About"]',expandReview:'[data-review-id] button[aria-label*="See more"], [data-review-id] button.w8nwRe'};async function xt(e,t,n,a){let s,i=!1,d,U=()=>{},S=()=>a?.reason instanceof DOMException&&a.reason.name==="TimeoutError"?a.reason:new j,h=()=>U(S()),l=new Promise((r,u)=>{U=u}),o=async r=>{let u;try{await Promise.race([r.close().catch(()=>{}),new Promise(c=>{u=setTimeout(c,2e3)})])}finally{u&&clearTimeout(u)}};if(a?.aborted)throw S();a?.addEventListener("abort",h,{once:!0}),d=setTimeout(()=>U(new DOMException("Optional pagination timed out","TimeoutError")),3e4);try{return await Promise.race([(async()=>{let r=await e.newPage();if(i)throw await o(r),new j;if(s=r,await t(r),i)throw new j;return n(r)})(),l])}finally{i=!0,d&&clearTimeout(d),a?.removeEventListener("abort",h),s&&await o(s)}}var Hn=/\b(?:HeadlessChrome|Chrome|Chromium|Firefox)\/\d+|\bVersion\/\d+.*\bSafari\//;async function Ot(e){try{let t=await e.evaluate(()=>navigator.userAgent);return typeof t=="string"&&Hn.test(t)?t:null}catch{return null}}async function Bt(e){let t=null;try{let n=e.contexts().flatMap(a=>a.pages())[0];return n||(t=await e.newContext(),n=t.pages()[0]??await t.newPage()),await Ot(n)}catch{return null}finally{t&&await t.close().catch(()=>{})}}function ci(e,t){return t?{...e,userAgent:t}:e}ee.use(Fn());var Gn=180,Dn=3e3,Vn=5e3,En='#search, #rso, a[href] h3, [data-snhf], [role="main"]';function Xt(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}function Yn(e,t){let n=process.env[e];if(!n)return t;let a=Number(n);return Number.isInteger(a)&&a>0?a:t}function te(e){return e?e.slice(-6):null}function De(e,t){let n=(t??process.env.SERP_REDIRECT_BASE)?.trim().replace(/\/+$/,"");return n?`${n}/g/${Buffer.from(e,"utf8").toString("base64url")}`:e}function Kn(e){return e?/united states|u\.?s\.?a?\.?|^us$/i.test(e.trim()):!1}function ht(e){return e instanceof Error?e.message:String(e)}function Jn(e){return/\b409\b|conflict|already exists/i.test(ht(e))}function _n(e){return/\b404\b|not[ _-]?found|already (?:gone|deleted|closed)|does not exist/i.test(ht(e))}async function zn(e,t){try{await e.profiles.create({name:t})}catch(n){if(!Jn(n))throw n}}function Ht(e,t){return{viewport:e.viewport,locale:e.locale,...t?{userAgent:t}:{},...e.deviceScaleFactor?{deviceScaleFactor:e.deviceScaleFactor}:{},...e.isMobile!==void 0?{isMobile:e.isMobile}:{},...e.hasTouch!==void 0?{hasTouch:e.hasTouch}:{}}}async function Ut(e,t,n){let a;try{return await Promise.race([e,new Promise((s,i)=>{a=setTimeout(()=>i(new Error(`${n} timed out after ${t}ms`)),t)})])}finally{a&&clearTimeout(a)}}function qn(e){let t=e.trim();if(!t)throw new Error("channelHandle is required");if(/^https?:\/\//i.test(t)||/^(www\.|m\.)?youtube\.com\//i.test(t)){let d=new URL(/^https?:\/\//i.test(t)?t:`https://${t}`);if(d.hostname.replace(/^www\./,"").replace(/^m\./,"").toLowerCase()!=="youtube.com")throw new Error("channel URL must be on youtube.com");let S=d.pathname.split("/").filter(Boolean),h=S[0]??"",l=S[1]??"";if(h.startsWith("@"))return`https://www.youtube.com/${h}/videos`;if(h==="channel"&&l)return`https://www.youtube.com/channel/${l}/videos`;if((h==="c"||h==="user")&&l)return`https://www.youtube.com/${h}/${l}/videos`;throw new Error("channel URL must be a YouTube handle, /channel/UC..., /c/..., or /user/... URL")}let s=t.replace(/^\/+/,"").replace(/\/+$/,"").replace(/\/videos$/i,"");if(/^UC[\w-]{20,}$/.test(s))return`https://www.youtube.com/channel/${s}/videos`;let i=s.startsWith("@")?s:`@${s}`;if(!/^@[\w.-]+$/.test(i))throw new Error("channelHandle must be an @handle, UC channel ID, or YouTube channel URL");return`https://www.youtube.com/${i}/videos`}var Ft=class{browser=null;context=null;page=null;\u006b\u0065\u0072\u006e\u0065\u006cClient=null;\u006b\u0065\u0072\u006e\u0065\u006cSessionId=null;\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=null;\u006b\u0065\u0072\u006e\u0065\u006cStealth=null;\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed=null;\u006b\u0065\u0072\u006e\u0065\u006cProxySource=null;\u006b\u0065\u0072\u006e\u0065\u006cProxyType=null;\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=null;last\u004b\u0065\u0072\u006e\u0065\u006cBillingMode=null;last\u004b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=null;last\u004b\u0065\u0072\u006e\u0065\u006cClosedAtMs=null;debugEnabled=!1;debugSnapshot={\u006b\u0065\u0072\u006e\u0065\u006c:null,context:null,networkLocation:null,serpNavigation:null};async launch(t){this.debugEnabled=t.debug===!0;let n=t.proxyMode??(t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId?"configured":"none"),a=t.isMobile?"mobile":"desktop";if(this.debugSnapshot={\u006b\u0065\u0072\u006e\u0065\u006c:null,context:{viewport:t.viewport,locale:t.locale,device:a,userAgent:null,deviceScaleFactor:t.deviceScaleFactor??null,isMobile:t.isMobile===!0,hasTouch:t.hasTouch===!0},networkLocation:null,serpNavigation:null},t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey){this.\u006b\u0065\u0072\u006e\u0065\u006cClient=new tt({apiKey:t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey});let i=Number.isInteger(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds)&&Number(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds)>0?Number(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds):Yn("\u004b\u0045\u0052\u004e\u0045\u004c_BROWSER_TIMEOUT_SECONDS",Gn),d=Math.min(i,600);t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName&&t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges===!0&&await zn(this.\u006b\u0065\u0072\u006e\u0065\u006cClient,t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName);let U=At(),S;t.headlessMode==="headful"||U?.forceHeadful===!0?S=!1:t.headlessMode==="headless"?S=!0:S=U?.forceHeadless===!0||process.env.\u004b\u0045\u0052\u004e\u0045\u004c_HEADLESS_DISABLED!=="true"&&!!U?.op&&We.has(U.op),this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=S?!0:null,this.last\u004b\u0065\u0072\u006e\u0065\u006cBillingMode=S?"headless":"headful",U?.headlessSentOut&&(U.headlessSentOut.value=this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent);let h=await this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.create({stealth:t.\u006b\u0065\u0072\u006e\u0065\u006cStealth===!0,timeout_seconds:d,...S?{headless:!0}:{},...t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId?{proxy_id:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId}:{},...t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName?{profile:{name:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName,...typeof t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges=="boolean"?{save_changes:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges}:{}}}:{}});this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId=h.session_id,this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=Date.now(),this.last\u004b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs,this.last\u004b\u0065\u0072\u006e\u0065\u006cClosedAtMs=null,this.\u006b\u0065\u0072\u006e\u0065\u006cStealth=typeof h.stealth=="boolean"?h.stealth:null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed=typeof h.proxy_id=="string"?!!h.proxy_id:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource=t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.source??null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType=t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.proxyType??null;let l=null,o=null;if(!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId&&!t.keepDefaultProxy)try{await Ut(this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.update(this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,{disable_default_proxy:!0}),5e3,`\u004b\u0065\u0072\u006e\u0065\u006c session ${this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId} disable default proxy`),l=!0}catch(u){l=!1,o=ht(u)}let r={sessionId:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,proxyMode:n,requestedProxyIdPresent:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,requestedProxyIdSuffix:te(t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId),createdProxyIdPresent:typeof h.proxy_id=="string"?!!h.proxy_id:null,createdProxyIdSuffix:te(h.proxy_id),retrievedProxyIdPresent:null,retrievedProxyIdSuffix:null,retrievedProxyIdMatchesRequested:null,defaultProxyDisabled:l,defaultProxyDisableError:o,proxyResolution:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution??null,timeoutSeconds:d,stealth:typeof h.stealth=="boolean"?h.stealth:null,profilePresent:null,poolPresent:null,retrieveError:null};if(this.debugSnapshot.\u006b\u0065\u0072\u006e\u0065\u006c=r,console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_created",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,timeout_seconds:d,proxy_mode:n,proxy_id_present:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,profile_name_present:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName,proxy_resolution_source:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.source})),this.debugEnabled&&await this.populate\u004b\u0065\u0072\u006e\u0065\u006cRetrieveDebug(r,t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId),this.browser=await Rn.connectOverCDP(h.cdp_ws_url),t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName||t.preserve\u004b\u0065\u0072\u006e\u0065\u006cContext)this.context=this.browser.contexts()[0]??await this.browser.newContext(Ht(t)),this.page=this.context.pages()[0]??await this.context.newPage(),this.debugSnapshot.context.userAgent=await Ot(this.page);else{let u=await Bt(this.browser);this.debugSnapshot.context.userAgent=u,this.context=await this.browser.newContext(Ht(t,u)),this.page=await this.context.newPage()}if(await this.installEsbuildHelperShims(this.context),t.preserve\u004b\u0065\u0072\u006e\u0065\u006cContext||await this.page.setViewportSize(t.viewport),(this.debugEnabled||t.requireUsEgress)&&(this.debugSnapshot.networkLocation=await this.captureBrowserNetworkLocation()),t.requireUsEgress){let u=this.debugSnapshot.networkLocation?.country??null;if(!Kn(u))throw new J(`Non-US egress (${u??"unknown"}) \u2014 retrying with a fresh session`)}return}let s={headless:t.headless,proxy:t.proxy?{server:t.proxy}:void 0,...t.browserExecutablePath?{executablePath:t.browserExecutablePath}:{},...t.ignoreDefaultArgs?{ignoreDefaultArgs:t.ignoreDefaultArgs}:{}};if(t.profileDir)this.context=await ee.launchPersistentContext(t.profileDir,{...s,...Ht(t)}),await this.installEsbuildHelperShims(this.context),this.page=await this.context.newPage(),this.debugSnapshot.context.userAgent=await Ot(this.page);else{this.browser=await ee.launch(s);let i=await Bt(this.browser);this.debugSnapshot.context.userAgent=i,this.context=await this.browser.newContext(Ht(t,i)),await this.installEsbuildHelperShims(this.context),this.page=await this.context.newPage()}this.debugEnabled&&(this.debugSnapshot.networkLocation=await this.captureBrowserNetworkLocation())}async populate\u004b\u0065\u0072\u006e\u0065\u006cRetrieveDebug(t,n){if(!(!this.\u006b\u0065\u0072\u006e\u0065\u006cClient||!this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId))try{let a=await Ut(this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.retrieve(this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId),5e3,`\u004b\u0065\u0072\u006e\u0065\u006c session ${this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId} retrieve`);t.retrievedProxyIdPresent=typeof a.proxy_id=="string"?!!a.proxy_id:!1,t.retrievedProxyIdSuffix=te(a.proxy_id),t.retrievedProxyIdMatchesRequested=n?a.proxy_id===n:!a.proxy_id,t.timeoutSeconds=typeof a.timeout_seconds=="number"?a.timeout_seconds:t.timeoutSeconds,t.stealth=typeof a.stealth=="boolean"?a.stealth:t.stealth,t.profilePresent=!!a.profile,t.poolPresent=!!a.pool}catch(a){t.retrieveError=ht(a)}}async captureBrowserNetworkLocation(){let t=(a,s="ipapi.co")=>({source:s,ip:null,city:null,region:null,country:null,org:null,timezone:null,error:a});if(!this.context)return t("browser context is not available");let n=null;try{n=await this.context.newPage();let a=await this.loadJsonInDebugPage(n,"https://ipwho.is/");if(a){let U=typeof a.connection=="object"&&a.connection!==null?a.connection:{};return{source:"ipwho.is",ip:typeof a.ip=="string"?a.ip:null,city:typeof a.city=="string"?a.city:null,region:typeof a.region=="string"?a.region:null,country:typeof a.country=="string"?a.country:null,org:typeof U.org=="string"?U.org:null,timezone:typeof a.timezone=="object"&&a.timezone!==null&&typeof a.timezone.id=="string"?a.timezone.id:null,error:null}}let s=await this.loadJsonInDebugPage(n,"https://api64.ipify.org?format=json");if(s)return{source:"api64.ipify.org",ip:typeof s.ip=="string"?s.ip:null,city:null,region:null,country:null,org:null,timezone:null,error:null};await Ut(n.goto("https://ipapi.co/json/",{waitUntil:"domcontentloaded",timeout:7e3}),8e3,"browser network location navigation");let i=await n.locator("body").innerText({timeout:2e3}),d=JSON.parse(i);return{source:"ipapi.co",ip:typeof d.ip=="string"?d.ip:null,city:typeof d.city=="string"?d.city:null,region:typeof d.region=="string"?d.region:null,country:typeof d.country_name=="string"?d.country_name:typeof d.country=="string"?d.country:null,org:typeof d.org=="string"?d.org:null,timezone:typeof d.timezone=="string"?d.timezone:null,error:null}}catch(a){return t(ht(a))}finally{await n?.close().catch(()=>{})}}async loadJsonInDebugPage(t,n){try{await Ut(t.goto(n,{waitUntil:"domcontentloaded",timeout:7e3}),8e3,`browser network location navigation ${n}`);let a=await t.locator("body").innerText({timeout:2e3});return JSON.parse(a)}catch{return null}}async installEsbuildHelperShims(t){await t.addInitScript(()=>{let n=globalThis;typeof n.__name!="function"&&(n.__name=a=>a),typeof n.__publicField!="function"&&(n.__publicField=(a,s,i)=>(a[s]=i,i))})}async withTemporaryPage(t,n){if(!this.context)throw new Error("Browser context is not available");return xt(this.context,async()=>{},t,n)}async navigateToSERP(t,n,a,s,i){let d=new URLSearchParams({q:t,gl:a,hl:s,pws:"0"});i?.tbs&&d.set("tbs",i.tbs),n&&d.set("uule",n);let U="https://www.google.com/search?"+d.toString(),S=De(U),h=i?.debug?{requestedUrl:U,finalUrl:null,title:null,bodySnippet:null,hasPaa:null,captchaDetected:null,googleSorryUrl:null,redirected:null}:null;h&&(this.debugSnapshot.serpNavigation=h);try{await this.page.goto(S,{waitUntil:"domcontentloaded",timeout:Xt(i?.deadlineMs,i?.purpose==="serp"?8e3:45e3)})}catch(o){await this.updateSerpNavigationDebug(h,U,{hasPaa:null,captchaDetected:null});let r=await this.captureDiagnostics(U);throw new It(`page.goto failed: ${o.message} | ${r}`)}if(await this.isSerpChallengeVisible())throw await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!0}),new J(this.captchaMessage());if(i?.purpose==="serp"){await this.page.waitForSelector(En,{timeout:Xt(i.deadlineMs,1500)}).catch(()=>null);let o=await this.page.locator(F.item).count().catch(()=>0)>0;return await this.updateSerpNavigationDebug(h,U,{hasPaa:o,captchaDetected:!1}),{hasPaa:o}}if(await this.page.waitForSelector(F.item,{timeout:Xt(i?.deadlineMs,4e3)}).catch(()=>null))return await this.updateSerpNavigationDebug(h,U,{hasPaa:!0,captchaDetected:!1}),{hasPaa:!0};if(await this.isSerpChallengeVisible())throw await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!0}),new J(this.captchaMessage());for(let o=1;o<=6;o++)if(await this.page.evaluate(u=>{window.scrollTo(0,document.body.scrollHeight*u)},o/6),await this.page.waitForTimeout(600),await this.page.locator(F.item).count()>0)return await this.updateSerpNavigationDebug(h,U,{hasPaa:!0,captchaDetected:!1}),{hasPaa:!0};return await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!1}),{hasPaa:!1}}async isSerpChallengeVisible(){if(!this.page)return!1;if(await this.page.locator(F.captchaMarker).count().catch(()=>0)>0)return!0;let n=this.page.url();if(/google\.[^/]+\/sorry\//i.test(n))return!0;let a=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,1e3)).catch(()=>"");return/recaptcha|unusual traffic|are you a robot|about this page|detected unusual traffic/i.test(a)}async updateSerpNavigationDebug(t,n,a){if(!(!t||!this.page))try{let s=this.page.url(),i=await this.page.title().catch(()=>""),d=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,500)).catch(()=>""),U=/recaptcha|unusual traffic|are you a robot/i.test(d);t.finalUrl=s,t.title=i,t.bodySnippet=d,t.hasPaa=a.hasPaa,t.captchaDetected=a.captchaDetected??U,t.googleSorryUrl=/google\.[^/]+\/sorry\//i.test(s),t.redirected=s!==n}catch(s){t.bodySnippet=`debug capture failed: ${ht(s)}`}}async captureDiagnostics(t){try{let n=this.page.url(),a=await this.page.title().catch(()=>""),s=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,400)).catch(()=>""),i=/consent\.google\./.test(n)||/before you continue/i.test(s),d=/recaptcha|unusual traffic|are you a robot/i.test(s),U=[i?"CONSENT_WALL":"",d?"BOT_CHALLENGE":"",n!==t?"REDIRECTED":""].filter(Boolean).join(",");return`intended=${t} | final=${n} | title="${a}" | flags=[${U}] | body="${s}"`}catch(n){return`diagnostics-failed: ${n.message}`}}captchaMessage(){return this.\u006b\u0065\u0072\u006e\u0065\u006cClient?"Google returned a CAPTCHA on this session \u2014 retrying with a fresh session.":fe}async navigateTo(t){let n=process.env.ADS_ARRIVAL_REDIRECT_BASE?.trim(),a=n?De(t,n):t;try{if(await this.page.goto(a,{waitUntil:"domcontentloaded",timeout:45e3}),/google\.[^/]+\/search\?/i.test(t)&&await this.isSerpChallengeVisible())throw new J(this.captchaMessage())}catch(s){if(s instanceof J)throw s;let i=await this.captureDiagnostics(t);throw new It(`page.goto failed: ${s.message} | ${i}`)}}async navigateToChannel(t){let n=qn(t);try{await this.page.goto(n,{waitUntil:"networkidle",timeout:3e4})}catch(a){let s=await this.captureDiagnostics(n);throw new It(`navigateToChannel failed: ${a.message} | ${s}`)}}async evaluate(t,n){return this.page.evaluate(t,n)}getPage(){return this.page}get\u004b\u0065\u0072\u006e\u0065\u006cSessionId(){return this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId}get\u004b\u0065\u0072\u006e\u0065\u006cMeteringEvidence(){return{sessionId:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId??this.debugSnapshot.\u006b\u0065\u0072\u006e\u0065\u006c?.sessionId??null,billingMode:this.last\u004b\u0065\u0072\u006e\u0065\u006cBillingMode,openedAtMs:this.last\u004b\u0065\u0072\u006e\u0065\u006cOpenedAtMs,closedAtMs:this.last\u004b\u0065\u0072\u006e\u0065\u006cClosedAtMs}}getProviderSessionMetadata(){return{provider:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId?"\u006b\u0065\u0072\u006e\u0065\u006c":"local",providerSessionId:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,disconnectObservation:null,billingMode:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId?this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent?"headless":"headful":null}}getDebugSnapshot(){return this.debugSnapshot}async close(){if(this.browser){let t=this.browser,n=this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,a=this.\u006b\u0065\u0072\u006e\u0065\u006cClient,s=this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs,i=this.\u006b\u0065\u0072\u006e\u0065\u006cStealth,d=this.\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed,U=this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource,S=this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType,h=this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent,l=this.getProviderSessionMetadata();if(this.browser=null,this.context=null,this.page=null,this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId=null,this.\u006b\u0065\u0072\u006e\u0065\u006cClient=null,this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=null,this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource=null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType=null,a&&n){console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_started",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n}));let o=Ut(a.browsers.deleteByID(n),Vn,`\u004b\u0065\u0072\u006e\u0065\u006c session ${n} delete`),r=Ut(t.close(),Dn,`\u004b\u0065\u0072\u006e\u0065\u006c browser ${n} close`),[u,c]=await Promise.allSettled([o,r]);this.last\u004b\u0065\u0072\u006e\u0065\u006cClosedAtMs=Date.now(),s!=null&&Ie({\u006b\u0065\u0072\u006e\u0065\u006cSessionId:n,source:"browser_driver",stealth:i,headlessSent:h,proxyUsed:d,proxySource:U,proxyType:S,openedAtMs:s,closedAtMs:this.last\u004b\u0065\u0072\u006e\u0065\u006cClosedAtMs});let g=u.status==="rejected"&&_n(u.reason),v={\u006b\u0065\u0072\u006e\u0065\u006cSessionId:n,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!0,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:u.status==="fulfilled"||g,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:u.status==="rejected"&&!g?u.reason instanceof Error?u.reason.message:String(u.reason):null,browserCloseSucceeded:c.status==="fulfilled",browserCloseError:c.status==="rejected"?c.reason instanceof Error?c.reason.message:String(c.reason):null,provider:l.provider,providerSessionId:l.providerSessionId,providerDisconnectObserved:!1,providerDisconnectMessage:null};return u.status==="rejected"&&!g?(console.warn(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_failed",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n,message:v.\u006b\u0065\u0072\u006e\u0065\u006cDeleteError})),console.warn(`\u004b\u0065\u0072\u006e\u0065\u006c session cleanup failed for ${n}:`,u.reason)):console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_succeeded",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n})),c.status==="rejected"&&(console.warn(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_close_failed",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n,message:v.browserCloseError})),console.warn(`\u004b\u0065\u0072\u006e\u0065\u006c browser close failed for ${n}:`,c.reason)),v}return await t.close(),{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:!0,browserCloseError:null,provider:l.provider,providerSessionId:l.providerSessionId,providerDisconnectObserved:!1,providerDisconnectMessage:null}}else if(this.context){let t=this.context;return this.context=null,this.page=null,await t.close(),{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:!0,browserCloseError:null,provider:"local",providerSessionId:null,providerDisconnectObserved:!1,providerDisconnectMessage:null}}return{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:null,browserCloseError:null,provider:"local",providerSessionId:null,providerDisconnectObserved:!1,providerDisconnectMessage:null}}};import{chromium as Qn}from"playwright";function $n(e,t){if(typeof e!="string")return null;let n=e.replace(/[\u0000-\u001f\u007f]+/g," ").replace(/\s+/g," ").trim();return n?n.slice(0,t):null}function Ve(e){let t=$n(e,320);return t?t.replace(/\b(?:wss?|https?):\/\/\S+/gi,"[redacted endpoint]").replace(/\b(?:authorization|proxy-authorization):\s*\S+/gi,"$1: [redacted]").replace(/\bBearer\s+\S+/gi,"Bearer [redacted]").slice(0,320):null}function Ee(e){return Ve(e)}function Ye(e){if(typeof e!="string"||e.length===0||e.length>512||e.trim()!==e||/[\s\u0000-\u001f\u007f]/.test(e)||/:\/\//.test(e))throw new Error("\u0042\u0072\u0069\u0067\u0068\u0074 \u0044\u0061\u0074\u0061 did not return a valid browser session ID");return e}function ne(e,t,n=new Date().toISOString()){let a=Ve(t);return{source:e,message:a??e.replaceAll("_"," "),observedAt:n}}function jn(e){return{provider:e.provider,providerDisconnectObserved:e.disconnectObservation!==null,providerDisconnectMessage:e.disconnectObservation?.message??null}}function Ke(e){return{...jn(e),providerSessionId:e.providerSessionId}}var Zn=new Set(["image","media","font","stylesheet","ping"]),Xn=["doubleclick.net","googleadservices.com","googlesyndication.com","google-analytics.com"],ta='#search, #rso, a[href] h3, [data-snhf], [role="main"]',ea=3e4,Je=1500;function Rt(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}function _e(){return process.env.\u0042\u0052\u0049\u0047\u0048\u0054\u0044\u0041\u0054\u0041_BROWSER_WSS?.trim()||null}function ze(){return process.env.SERP_BROWSER_PROVIDER?.trim().toLowerCase()==="\u006b\u0065\u0072\u006e\u0065\u006c"?!1:!!_e()}async function ae(e,t=!1){let n=e.request();try{let a=await n.allHeaders(),s=await fetch(n.url(),{method:n.method(),headers:{accept:a.accept??"*/*","accept-language":a["accept-language"]??"en-US,en;q=0.9","user-agent":a["user-agent"]??"Mozilla/5.0",...t?{cookie:a.cookie??"",referer:a.referer??"https://www.google.com/",...a["x-client-data"]?{"x-client-data":a["x-client-data"]}:{}}:{}},body:n.method()==="GET"||n.method()==="HEAD"?void 0:n.postData()});if(!s.ok)return!1;let i=Buffer.from(await s.arrayBuffer());return await e.fulfill({status:s.status,contentType:s.headers.get("content-type")??"application/octet-stream",headers:{"cache-control":"public, max-age=3600"},body:i}),!0}catch{return!1}}var Gt=class{browser=null;context=null;page=null;cdpSession=null;providerSessionId=null;disconnectObservation=null;closing=!1;observeDisconnect(t,n){this.closing||this.disconnectObservation||(this.disconnectObservation=ne(t,n))}async launch(t){if(this.page)return;this.closing=!1,this.providerSessionId=null,this.disconnectObservation=null;let n=_e();if(!n)throw new Error("SERP browser service is not configured");this.browser=await Qn.connectOverCDP(n,{timeout:Rt(t.operationDeadlineMs,ea)}),this.context=this.browser.contexts()[0]??await this.browser.newContext(),await this.context.addInitScript(()=>{let i=globalThis;typeof i.__name!="function"&&(i.__name=d=>d),typeof i.__publicField!="function"&&(i.__publicField=(d,U,S)=>(d[U]=S,S))}),this.page=this.context.pages()[0]??await this.context.newPage(),this.browser.on("disconnected",()=>this.observeDisconnect("browser_disconnected")),this.context.on("close",()=>this.observeDisconnect("context_closed")),this.page.on("close",()=>this.observeDisconnect("page_closed")),this.page.on("crash",()=>this.observeDisconnect("page_crashed")),this.cdpSession=await this.context.newCDPSession(this.page);let s=await this.cdpSession.send("Browser.getSessionId");this.providerSessionId=Ye(s?.sessionId),await this.setupPage(this.page)}async setupPage(t){await t.route("**/*",async n=>{let a=n.request(),s=a.resourceType(),i;try{i=new URL(a.url())}catch{await n.continue();return}let d=i.hostname.toLowerCase();if(!(i.pathname==="/sgasync"&&await ae(n,!0))&&!(i.pathname.includes("/shared_dict/")&&await ae(n))&&!(s==="script"&&(d==="www.google.com"||d==="www.gstatic.com")&&await ae(n))){if(Zn.has(s)){await n.abort("blockedbyclient");return}if(Xn.some(U=>d===U||d.endsWith(`.${U}`))){await n.abort("blockedbyclient");return}await n.continue()}})}async withTemporaryPage(t,n){if(!this.context||this.closing)throw new Error("Browser context is not available");return xt(this.context,a=>this.setupPage(a),t,n)}async navigateToSERP(t,n,a,s,i){if(!this.page)throw new Error("Browser page is not available");let d=new URLSearchParams({q:t,gl:a,hl:s,pws:"0"});return i?.tbs&&d.set("tbs",i.tbs),n&&d.set("uule",n),await this.page.goto(`https://www.google.com/search?${d}`,{waitUntil:"domcontentloaded",timeout:Rt(i?.deadlineMs,i?.purpose==="serp"?8e3:45e3)}),i?.purpose==="serp"?(await this.page.waitForSelector(ta,{timeout:Rt(i.deadlineMs,1500)}).catch(()=>null),{hasPaa:await this.page.locator(F.item).count().catch(()=>0)>0}):{hasPaa:!!await this.page.waitForSelector(F.item,{timeout:Rt(i?.deadlineMs,8e3)}).catch(()=>null)}}async navigateTo(t){if(!this.page)throw new Error("Browser page is not available");await this.page.goto(t,{waitUntil:"load",timeout:45e3})}async navigateToChannel(){throw new Error("YouTube navigation is not supported by the SERP browser driver")}async evaluate(t,n){if(!this.page)throw new Error("Browser page is not available");return this.page.evaluate(t,n)}getPage(){if(!this.page)throw new Error("Browser page is not available");return this.page}get\u004b\u0065\u0072\u006e\u0065\u006cSessionId(){return null}getProviderSessionMetadata(){return{provider:"\u0062\u0072\u0069\u0067\u0068\u0074_\u0064\u0061\u0074\u0061_browser_api",providerSessionId:this.providerSessionId,disconnectObservation:this.disconnectObservation}}getDebugSnapshot(){return{\u006b\u0065\u0072\u006e\u0065\u006c:null,context:null,networkLocation:null,serpNavigation:null}}async close(){this.closing=!0;let t=null,n;try{let s=this.browser?.close();s&&await Promise.race([s,new Promise((i,d)=>{n=setTimeout(()=>d(new Error(`Browser close acknowledgement exceeded ${Je}ms`)),Je)})])}catch(s){t=Ee(s instanceof Error?s.message:String(s))??"\u0042\u0072\u0069\u0067\u0068\u0074 \u0044\u0061\u0074\u0061 browser close failed",this.disconnectObservation??=ne("browser_close_error",t)}finally{n&&clearTimeout(n)}let a=Ke(this.getProviderSessionMetadata());return this.browser=null,this.context=null,this.page=null,this.cdpSession=null,{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:t===null,browserCloseError:t,...a}}};function qe(e){return e.plannedProvider==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?new Gt:new Ft}var st={austin:"Austin,Texas,United States","new york":"New York,New York,United States","new york city":"New York,New York,United States",nyc:"New York,New York,United States","los angeles":"Los Angeles,California,United States",la:"Los Angeles,California,United States",chicago:"Chicago,Illinois,United States",houston:"Houston,Texas,United States",phoenix:"Phoenix,Arizona,United States",philadelphia:"Philadelphia,Pennsylvania,United States",philly:"Philadelphia,Pennsylvania,United States","san antonio":"San Antonio,Texas,United States",dallas:"Dallas,Texas,United States",miami:"Miami,Florida,United States",seattle:"Seattle,Washington,United States",denver:"Denver,Colorado,United States",loveland:"Loveland,Colorado,United States","loveland co":"Loveland,Colorado,United States","fort collins":"Fort Collins,Colorado,United States",boulder:"Boulder,Colorado,United States","colorado springs":"Colorado Springs,Colorado,United States",boston:"Boston,Massachusetts,United States",atlanta:"Atlanta,Georgia,United States","san francisco":"San Francisco,California,United States",sf:"San Francisco,California,United States",portland:"Portland,Oregon,United States","las vegas":"Las Vegas,Nevada,United States",minneapolis:"Minneapolis,Minnesota,United States",detroit:"Detroit,Michigan,United States",nashville:"Nashville,Tennessee,United States",charlotte:"Charlotte,North Carolina,United States",orlando:"Orlando,Florida,United States","san diego":"San Diego,California,United States",baltimore:"Baltimore,Maryland,United States",sacramento:"Sacramento,California,United States",columbus:"Columbus,Ohio,United States",indianapolis:"Indianapolis,Indiana,United States","san jose":"San Jose,California,United States","fort worth":"Fort Worth,Texas,United States",jacksonville:"Jacksonville,Florida,United States",memphis:"Memphis,Tennessee,United States",louisville:"Louisville,Kentucky,United States",raleigh:"Raleigh,North Carolina,United States",richmond:"Richmond,Virginia,United States","salt lake city":"Salt Lake City,Utah,United States",toronto:"Toronto,Ontario,Canada",vancouver:"Vancouver,British Columbia,Canada",montreal:"Montreal,Quebec,Canada",calgary:"Calgary,Alberta,Canada",ottawa:"Ottawa,Ontario,Canada",london:"London,England,United Kingdom",manchester:"Manchester,England,United Kingdom",birmingham:"Birmingham,England,United Kingdom",edinburgh:"Edinburgh,Scotland,United Kingdom",glasgow:"Glasgow,Scotland,United Kingdom",leeds:"Leeds,England,United Kingdom",sydney:"Sydney,New South Wales,Australia",melbourne:"Melbourne,Victoria,Australia",brisbane:"Brisbane,Queensland,Australia",perth:"Perth,Western Australia,Australia",adelaide:"Adelaide,South Australia,Australia",dublin:"Dublin,Leinster,Ireland"};var $e=`3, Nanjemoy,Maryland,United States
2
2
  Aaronsburg,Pennsylvania,United States
3
3
  Abbeville,Alabama,United States
4
4
  Abbeville,Georgia,United States
@@ -21691,20 +21691,20 @@ Zuehl,Texas,United States
21691
21691
  Zumbrota,Minnesota,United States
21692
21692
  Zuni,New Mexico,United States
21693
21693
  Zwolle,Louisiana,United States`,je={ad:"Andorra",ae:"United Arab Emirates",af:"Afghanistan",ag:"Antigua and Barbuda",al:"Albania",am:"Armenia",ao:"Angola",aq:"Antarctica",ar:"Argentina",as:"American Samoa",at:"Austria",au:"Australia",az:"Azerbaijan",ba:"Bosnia and Herzegovina",bb:"Barbados",bd:"Bangladesh",be:"Belgium",bf:"Burkina Faso",bg:"Bulgaria",bh:"Bahrain",bi:"Burundi",bj:"Benin",bl:"Saint Barthelemy",bn:"Brunei",bo:"Bolivia",bq:"Caribbean Netherlands",br:"Brazil",bs:"The Bahamas",bt:"Bhutan",bw:"Botswana",by:"Belarus",bz:"Belize",ca:"Canada",cc:"Cocos (Keeling) Islands",cd:"Democratic Republic of the Congo",cf:"Central African Republic",cg:"Republic of the Congo",ch:"Switzerland",ci:"Cote d'Ivoire",ck:"Cook Islands",cl:"Chile",cm:"Cameroon",cn:"China",co:"Colombia",cr:"Costa Rica",cv:"Cabo Verde",cw:"Curacao",cx:"Christmas Island",cy:"Cyprus",cz:"Czechia",de:"Germany",dj:"Djibouti",dk:"Denmark",dm:"Dominica",do:"Dominican Republic",dz:"Algeria",ec:"Ecuador",ee:"Estonia",eg:"Egypt",er:"Eritrea",es:"Spain",et:"Ethiopia",fi:"Finland",fj:"Fiji",fm:"Micronesia",fr:"France",ga:"Gabon",gb:"United Kingdom",gd:"Grenada",ge:"Georgia",gg:"Guernsey",gh:"Ghana",gm:"The Gambia",gn:"Guinea",gq:"Equatorial Guinea",gr:"Greece",gs:"South Georgia and the South Sandwich Islands",gt:"Guatemala",gu:"Guam",gw:"Guinea-Bissau",gy:"Guyana",hm:"Heard Island and McDonald Islands",hn:"Honduras",hr:"Croatia",ht:"Haiti",hu:"Hungary",id:"Indonesia",ie:"Ireland",il:"Israel",im:"Isle of Man",in:"India",iq:"Iraq",is:"Iceland",it:"Italy",je:"Jersey",jm:"Jamaica",jo:"Jordan",jp:"Japan",ke:"Kenya",kg:"Kyrgyzstan",kh:"Cambodia",ki:"Kiribati",km:"Comoros",kn:"Saint Kitts and Nevis",kr:"South Korea",kw:"Kuwait",kz:"Kazakhstan",la:"Laos",lb:"Lebanon",lc:"Saint Lucia",li:"Liechtenstein",lk:"Sri Lanka",lr:"Liberia",ls:"Lesotho",lt:"Lithuania",lu:"Luxembourg",lv:"Latvia",ly:"Libya",ma:"Morocco",mc:"Monaco",md:"Moldova",me:"Montenegro",mf:"Saint Martin",mg:"Madagascar",mh:"Marshall Islands",mk:"North Macedonia",ml:"Mali",mm:"Myanmar (Burma)",mn:"Mongolia",mp:"Northern Mariana Islands",mr:"Mauritania",mt:"Malta",mu:"Mauritius",mv:"Maldives",mw:"Malawi",mx:"Mexico",my:"Malaysia",mz:"Mozambique",na:"Namibia",nc:"New Caledonia",ne:"Niger",nf:"Norfolk Island",ng:"Nigeria",ni:"Nicaragua",nl:"Netherlands",no:"Norway",np:"Nepal",nr:"Nauru",nu:"Niue",nz:"New Zealand",om:"Oman",pa:"Panama",pe:"Peru",pf:"French Polynesia",pg:"Papua New Guinea",ph:"Philippines",pk:"Pakistan",pl:"Poland",pm:"Saint Pierre and Miquelon",pn:"Pitcairn Islands",pt:"Portugal",pw:"Palau",py:"Paraguay",qa:"Qatar",ro:"Romania",rs:"Serbia",ru:"Russia",rw:"Rwanda",sa:"Saudi Arabia",sb:"Solomon Islands",sc:"Seychelles",sd:"Sudan",se:"Sweden",sg:"Singapore",sh:"Saint Helena, Ascension and Tristan da Cunha",si:"Slovenia",sk:"Slovakia",sl:"Sierra Leone",sm:"San Marino",sn:"Senegal",so:"Somalia",sr:"Suriname",ss:"South Sudan",st:"Sao Tome and Principe",sv:"El Salvador",sx:"Sint Maarten",sy:"Syria",sz:"Eswatini",td:"Chad",tf:"French Southern and Antarctic Lands",tg:"Togo",th:"Thailand",tj:"Tajikistan",tk:"Tokelau",tl:"Timor-Leste",tm:"Turkmenistan",tn:"Tunisia",to:"Tonga",tr:"Turkiye",tt:"Trinidad and Tobago",tv:"Tuvalu",tz:"Tanzania",ua:"Ukraine",ug:"Uganda",um:"United States Minor Outlying Islands",us:"United States",uy:"Uruguay",uz:"Uzbekistan",va:"Vatican City",vc:"Saint Vincent and the Grenadines",ve:"Venezuela",vn:"Vietnam",vu:"Vanuatu",wf:"Wallis and Futuna",ws:"Samoa",ye:"Yemen",za:"South Africa",zm:"Zambia",zw:"Zimbabwe"};var ie={AL:"Alabama",AK:"Alaska",AZ:"Arizona",AR:"Arkansas",CA:"California",CO:"Colorado",CT:"Connecticut",DE:"Delaware",DC:"District of Columbia",FL:"Florida",GA:"Georgia",HI:"Hawaii",ID:"Idaho",IL:"Illinois",IN:"Indiana",IA:"Iowa",KS:"Kansas",KY:"Kentucky",LA:"Louisiana",ME:"Maine",MD:"Maryland",MA:"Massachusetts",MI:"Michigan",MN:"Minnesota",MS:"Mississippi",MO:"Missouri",MT:"Montana",NE:"Nebraska",NV:"Nevada",NH:"New Hampshire",NJ:"New Jersey",NM:"New Mexico",NY:"New York",NC:"North Carolina",ND:"North Dakota",OH:"Ohio",OK:"Oklahoma",OR:"Oregon",PA:"Pennsylvania",PR:"Puerto Rico",RI:"Rhode Island",SC:"South Carolina",SD:"South Dakota",TN:"Tennessee",TX:"Texas",UT:"Utah",VT:"Vermont",VA:"Virginia",WA:"Washington",WV:"West Virginia",WI:"Wisconsin",WY:"Wyoming"};var se=null,Ze=null;function na(){if(se)return;let e=new Map,t=new Map;for(let n of $e.split(`
21694
- `)){let a=n.trim();if(!a)continue;let s=a.toLowerCase();e.has(s)||e.set(s,a);let i=s.split(",",1)[0],d=t.get(i);d?d.push(a):t.set(i,[a])}for(let n of Object.values(je)){let a=String(n).toLowerCase();e.has(a)||e.set(a,String(n))}se=e,Ze=t}function aa(e){let t=[],n=e;do{let a=n&127;n>>>=7,n>0&&(a|=128),t.push(a)}while(n>0);return t}function Xe(e){let t=Buffer.from(e,"utf8");return`w+${Buffer.concat([Buffer.from([8,2,16,32,34]),Buffer.from(aa(t.length)),t]).toString("base64")}`}function Qe(){return{canonical:null,matched:!1,source:"unresolved",ambiguousCandidates:0}}function et(e,t){return{canonical:e,matched:!0,source:t,ambiguousCandidates:0}}function oe(e){let t=e.toLowerCase().trim();if(!t)return Qe();if(st[t])return et(st[t],"alias");na();let n=se,a=Ze,s=n.get(t);if(s)return et(s,"exact");let i=n.get(`${t},united states`);if(i)return et(i,"state-or-country");let d=t.split(",");if(d.length>=2){let o=d[0].trim(),r=d.slice(1).join(",").trim(),u=ie[r.toUpperCase()]??r,c=n.get(`${o},${u.toLowerCase()},united states`);if(c)return et(c,"city-state")}let U=t.match(/^(.*?)[\s,]+([a-z]{2})$/);if(U){let o=ie[U[2].toUpperCase()];if(o){let r=n.get(`${U[1].trim()},${o.toLowerCase()},united states`);if(r)return et(r,"city-state")}}let S=a.get(t);if(S?.length===1)return et(S[0],"city-unique");if(S&&S.length>1)return{canonical:null,matched:!1,source:"unresolved",ambiguousCandidates:S.length};let h=d[0].trim();if(h!==t&&st[h])return et(st[h],"alias-partial");let l=t.replace(/\s+[a-z]{2}$/,"").trim();return l!==t&&st[l]?et(st[l],"alias-partial"):Qe()}function tn(e){return oe(e).canonical??e}var de={alabama:"AL",alaska:"AK",arizona:"AZ",arkansas:"AR",california:"CA",colorado:"CO",connecticut:"CT",delaware:"DE",florida:"FL",georgia:"GA",hawaii:"HI",idaho:"ID",illinois:"IL",indiana:"IN",iowa:"IA",kansas:"KS",kentucky:"KY",louisiana:"LA",maine:"ME",maryland:"MD",massachusetts:"MA",michigan:"MI",minnesota:"MN",mississippi:"MS",missouri:"MO",montana:"MT",nebraska:"NE",nevada:"NV","new hampshire":"NH","new jersey":"NJ","new mexico":"NM","new york":"NY","north carolina":"NC","north dakota":"ND",ohio:"OH",oklahoma:"OK",oregon:"OR",pennsylvania:"PA","rhode island":"RI","south carolina":"SC","south dakota":"SD",tennessee:"TN",texas:"TX",utah:"UT",vermont:"VT",virginia:"VA",washington:"WA","west virginia":"WV",wisconsin:"WI",wyoming:"WY","district of columbia":"DC"},ia=[...Object.keys(de).map(e=>e.replace(/\s+/g,"\\s+")),...Object.values(de)].join("|"),sa=new RegExp(`\\b([A-Z][A-Za-z]+(?:[\\s.-][A-Z][A-Za-z]+){0,4}),?\\s+(${ia})\\b`,"gi");function nn(e){if(!e)return null;let t=e.trim();return/^[A-Z]{2}$/i.test(t)?t.toUpperCase():de[t.toLowerCase()]??null}function an(e){return e.replace(/\s+/g," ").trim().replace(/^.*\b(?:in|near|around|serving)\s+/i,"").toLowerCase().replace(/\b[a-z]/g,n=>n.toUpperCase())}function oa(e){if(!e)return null;let[t="",n=""]=e.split(",").map(a=>a.trim());return{city:an(t),regionCode:nn(n),canonicalLocation:e}}function da(e,t,n,a){let s=an(t),i=nn(n);if(!s||!i)return;let d=`${s.toLowerCase()}|${i}`,U=e.get(d);if(U){U.count++,U.examples.length<3&&!U.examples.includes(a)&&U.examples.push(a);return}e.set(d,{city:s,regionCode:i,count:1,examples:[a]})}function ra(e){try{return decodeURIComponent(e)}catch{}try{return decodeURIComponent(e.replace(/%(?![0-9a-fA-F]{2})/g,"%25"))}catch{return e}}function en(e,t){let n=ra(t).replace(/[+/|_-]+/g," ");for(let a of n.matchAll(sa))da(e,a[1]??"",a[2]??"",n.slice(0,180))}function kt(e,t,n){let a=oa(e),s=new Map;for(let U of t)en(s,[U.title,U.snippet??"",U.cite??"",U.url].join(" "));for(let U of n)en(s,[U.name,...U.metadata,U.websiteUrl??"",U.directionsUrl??""].join(" "));let i=Array.from(s.values()).sort((U,S)=>S.count-U.count||U.city.localeCompare(S.city)).slice(0,8);return a?i.length===0?{status:"unknown",expected:a,candidates:[]}:{status:i.some(U=>U.city.toLowerCase()===a.city.toLowerCase()&&(a.regionCode==null||U.regionCode===a.regionCode))?"matched":"mismatch",expected:a,candidates:i}:{status:"not_requested",expected:null,candidates:i}}var la=[/An AI Overview is not available for this search/gi,/Can't generate an AI overview right now\.?\s*Try again later\.?/gi,/\bAI Overview\b/gi,/\bView all\b/gi],Sa=[/\bRelated Links\b/i,/\bAsk anything in\s*AI Mode\b/i,/\bAI can make mistakes\b/i,/\bThis is for informational purposes only\b/i,/\bShow more\b/i,/\b\d+\s+sites\b/i,/\b\d{1,2}\s*[msh]\s*[A-Z][A-Za-z]/,/\b(?:YouTube|Reddit|Facebook|Instagram|TikTok)·/];function Dt(e){return e.replace(/\u00a0/g," ").replace(/([.!?])([A-Z])/g,"$1 $2").replace(/([:;])([A-Z])/g,"$1 $2").replace(/([a-z])([A-Z][a-z])/g,"$1 $2").replace(/(\d)([A-Z][a-z])/g,"$1 $2").replace(/([a-z])(\d)/g,"$1 $2").replace(/\s+/g," ").trim()}function Ua(e){let t=-1;for(let n of Sa){let a=n.exec(e);n.lastIndex=0,a&&(t===-1||a.index<t)&&(t=a.index)}return t===-1?e:e.slice(0,t)}function ha(e,t){let n=t?.trim();if(!n||n.length<8)return e;let a=e.toLowerCase().indexOf(n.toLowerCase());return a>40?e.slice(0,a):e}function ua(e){let t=e.match(/[•·]\s*(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\.?\s+\d{1,2},\s+\d{4}/i);if(t?.index&&t.index>40)return t.index;let n=Math.max(0,e.length-260),a=e.slice(n),s=[...a.matchAll(/[.!?]\s*(?=[A-Z][A-Za-z0-9"'$])/g)];for(let d of s){let U=a.slice(d.index+1).trim(),S=U.slice(0,160),h=/^(?:Best|Top|What|How|Why|When|Where|Which|Can|Should|Is|Are|Do|Does)\b/i.test(U);if(U.length>20&&h&&/(?:\s[-|]\s|Heating|Cooling|Company|Services|Blog|Guide|Review)/i.test(S))return n+d.index+1}let i=s.at(-1);return i?.index!==void 0?n+i.index+1:e.length}function ca(e){let t=e.match(/https?:\/\/\S+/i);if(!t?.index)return e;let n=e.slice(0,t.index);return n.slice(0,ua(n))}function wa(e){if(e.length<=1200)return e;let t=e.slice(0,1200),n=Math.max(t.lastIndexOf("."),t.lastIndexOf("!"),t.lastIndexOf("?"));return(n>240?t.slice(0,n+1):t).trim()}function sn(e,t,n){if(!e)return;let a=Dt(e),s=t?Dt(t):"";if(s&&a.toLowerCase().startsWith(s.toLowerCase())&&(a=a.slice(s.length).trim()),!/^An error has occurred\.?\s*Please try again later\.?/i.test(a)){for(let i of la)a=a.replace(i," ");if(a=a.replace(/\b[A-Z][A-Za-z&'\u2019 -]{2,60}\+\d+\b/g," ").replace(/\b(?:[a-z0-9-]+\.)+[a-z]{2,}\+\d+\b/gi," "),a=Dt(a),a=Ua(a),a=ha(a,n),a=ca(a),a=Dt(a),a=a.replace(/\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\.?\s+\d{1,2},\s+\d{4}$/i,"").trim(),a=wa(a),!!a&&!/^An error has occurred\.?\s*Please try again later\.?$/i.test(a))return a}}async function on(e){let t=e??{aio:{root:"[data-lhcontainer][data-streaming-container][eid]",legacyRoot:'[data-hveid="CBMQAA"]',wrapper:".Fgyi2e",controller:'[jscontroller="AkrxPe"]',contentSubtree:'[data-subtree="mfc"]',heading:".Fzsovc.cwYVJe.RJPOee",header:".heWuVc",showMoreButton:'[aria-label="Show more AI Overview"]',sourcesPanel:".OZ9ddf.WAUd4",disclaimer:".DuQANe.MSJHRb"},aim:{root:'[data-hveid="CAUQAA"]',wrapper:".Fgyi2e"},expandWaitMs:1500},n=window.google?.sn??"unknown",a=n==="aim"?"aim":n==="web"?"web":"unknown";function s(y){return y?(y.innerText??y.textContent??"").trim():""}function i(y){if(!y)return!1;let T=y.replace(/\s+/g," ").trim();return T.length>=16&&T.split(" ").filter(Boolean).length>=2}function d(y){let T=y.querySelector(t.aio.heading);if(s(T)==="AI Overview")return!0;let w=y.querySelector(t.aio.header);return!!s(w).split(/\n|\s{2,}/).some(C=>C.trim()==="AI Overview")}function U(){let T=Array.from(document.querySelectorAll(t.aio.root)).find(d);if(T)return T;if(t.aio.legacyRoot){let C=document.querySelector(t.aio.legacyRoot);if(C&&d(C))return C}let w=document.querySelectorAll(`${t.aio.heading}, h1, h2, h3, [role="heading"]`);for(let C of w){if(s(C)!=="AI Overview")continue;let k=C.parentElement;for(let m=0;m<8&&k;m++){if(k.matches(t.aio.root)||k.querySelector(t.aio.controller)||k.querySelector(t.aio.contentSubtree))return k;k=k.parentElement}return C.parentElement}return null}function S(y){if(!y)return null;let T=y.cloneNode(!0);T.querySelectorAll(["script","style","noscript","img","picture","video",t.aio.header,t.aio.showMoreButton,t.aio.sourcesPanel,t.aio.disclaimer,'[data-subtree="dfa"]',"[data-src-id]",'[role="dialog"]',".HWMcu",".bTFeG",".CyMdWb",".MFrAxb",".F0OfWd.hfWAgb",".x2qcTc.fZavHb",".SvjEff",".sR2MY",".lKuDef",".GSPQcc","a[href]","button",'[role="button"]'].join(",")).forEach(b=>b.remove());let w=document.createElement("div");w.style.position="fixed",w.style.left="-10000px",w.style.top="0",w.style.width=`${Math.max(320,Math.round(y.getBoundingClientRect?.().width||960))}px`,w.style.opacity="0",w.style.pointerEvents="none",w.append(T),document.body.append(w);let C=T.innerText||T.textContent||"";w.remove();let k=C.replace(/\r/g,"").replace(/[ \t]+\n/g,`
21694
+ `)){let a=n.trim();if(!a)continue;let s=a.toLowerCase();e.has(s)||e.set(s,a);let i=s.split(",",1)[0],d=t.get(i);d?d.push(a):t.set(i,[a])}for(let n of Object.values(je)){let a=String(n).toLowerCase();e.has(a)||e.set(a,String(n))}se=e,Ze=t}function aa(e){let t=[],n=e;do{let a=n&127;n>>>=7,n>0&&(a|=128),t.push(a)}while(n>0);return t}function Xe(e){let t=Buffer.from(e,"utf8");return`w+${Buffer.concat([Buffer.from([8,2,16,32,34]),Buffer.from(aa(t.length)),t]).toString("base64")}`}function Qe(){return{canonical:null,matched:!1,source:"unresolved",ambiguousCandidates:0}}function et(e,t){return{canonical:e,matched:!0,source:t,ambiguousCandidates:0}}function oe(e){let t=e.toLowerCase().trim();if(!t)return Qe();if(st[t])return et(st[t],"alias");na();let n=se,a=Ze,s=n.get(t);if(s)return et(s,"exact");let i=n.get(`${t},united states`);if(i)return et(i,"state-or-country");let d=t.split(",");if(d.length>=2){let o=d[0].trim(),r=d.slice(1).join(",").trim(),u=ie[r.toUpperCase()]??r,c=n.get(`${o},${u.toLowerCase()},united states`);if(c)return et(c,"city-state")}let U=t.match(/^(.*?)[\s,]+([a-z]{2})$/);if(U){let o=ie[U[2].toUpperCase()];if(o){let r=n.get(`${U[1].trim()},${o.toLowerCase()},united states`);if(r)return et(r,"city-state")}}let S=a.get(t);if(S?.length===1)return et(S[0],"city-unique");if(S&&S.length>1)return{canonical:null,matched:!1,source:"unresolved",ambiguousCandidates:S.length};let h=d[0].trim();if(h!==t&&st[h])return et(st[h],"alias-partial");let l=t.replace(/\s+[a-z]{2}$/,"").trim();return l!==t&&st[l]?et(st[l],"alias-partial"):Qe()}function tn(e){return oe(e).canonical??e}var de={alabama:"AL",alaska:"AK",arizona:"AZ",arkansas:"AR",california:"CA",colorado:"CO",connecticut:"CT",delaware:"DE",florida:"FL",georgia:"GA",hawaii:"HI",idaho:"ID",illinois:"IL",indiana:"IN",iowa:"IA",kansas:"KS",kentucky:"KY",louisiana:"LA",maine:"ME",maryland:"MD",massachusetts:"MA",michigan:"MI",minnesota:"MN",mississippi:"MS",missouri:"MO",montana:"MT",nebraska:"NE",nevada:"NV","new hampshire":"NH","new jersey":"NJ","new mexico":"NM","new york":"NY","north carolina":"NC","north dakota":"ND",ohio:"OH",oklahoma:"OK",oregon:"OR",pennsylvania:"PA","rhode island":"RI","south carolina":"SC","south dakota":"SD",tennessee:"TN",texas:"TX",utah:"UT",vermont:"VT",virginia:"VA",washington:"WA","west virginia":"WV",wisconsin:"WI",wyoming:"WY","district of columbia":"DC"},ia=[...Object.keys(de).map(e=>e.replace(/\s+/g,"\\s+")),...Object.values(de)].join("|"),sa=new RegExp(`\\b([A-Z][A-Za-z]+(?:[\\s.-][A-Z][A-Za-z]+){0,4}),?\\s+(${ia})\\b`,"gi");function nn(e){if(!e)return null;let t=e.trim();return/^[A-Z]{2}$/i.test(t)?t.toUpperCase():de[t.toLowerCase()]??null}function an(e){return e.replace(/\s+/g," ").trim().replace(/^.*\b(?:in|near|around|serving)\s+/i,"").toLowerCase().replace(/\b[a-z]/g,n=>n.toUpperCase())}function oa(e){if(!e)return null;let[t="",n=""]=e.split(",").map(a=>a.trim());return{city:an(t),regionCode:nn(n),canonicalLocation:e}}function da(e,t,n,a){let s=an(t),i=nn(n);if(!s||!i)return;let d=`${s.toLowerCase()}|${i}`,U=e.get(d);if(U){U.count++,U.examples.length<3&&!U.examples.includes(a)&&U.examples.push(a);return}e.set(d,{city:s,regionCode:i,count:1,examples:[a]})}function ra(e){try{return decodeURIComponent(e)}catch{}try{return decodeURIComponent(e.replace(/%(?![0-9a-fA-F]{2})/g,"%25"))}catch{return e}}function en(e,t){let n=ra(t).replace(/[+/|_-]+/g," ");for(let a of n.matchAll(sa))da(e,a[1]??"",a[2]??"",n.slice(0,180))}function Mt(e,t,n){let a=oa(e),s=new Map;for(let U of t)en(s,[U.title,U.snippet??"",U.cite??"",U.url].join(" "));for(let U of n)en(s,[U.name,...U.metadata,U.websiteUrl??"",U.directionsUrl??""].join(" "));let i=Array.from(s.values()).sort((U,S)=>S.count-U.count||U.city.localeCompare(S.city)).slice(0,8);return a?i.length===0?{status:"unknown",expected:a,candidates:[]}:{status:i.some(U=>U.city.toLowerCase()===a.city.toLowerCase()&&(a.regionCode==null||U.regionCode===a.regionCode))?"matched":"mismatch",expected:a,candidates:i}:{status:"not_requested",expected:null,candidates:i}}var la=[/An AI Overview is not available for this search/gi,/Can't generate an AI overview right now\.?\s*Try again later\.?/gi,/\bAI Overview\b/gi,/\bView all\b/gi],Sa=[/\bRelated Links\b/i,/\bAsk anything in\s*AI Mode\b/i,/\bAI can make mistakes\b/i,/\bThis is for informational purposes only\b/i,/\bShow more\b/i,/\b\d+\s+sites\b/i,/\b\d{1,2}\s*[msh]\s*[A-Z][A-Za-z]/,/\b(?:YouTube|Reddit|Facebook|Instagram|TikTok)·/];function Dt(e){return e.replace(/\u00a0/g," ").replace(/([.!?])([A-Z])/g,"$1 $2").replace(/([:;])([A-Z])/g,"$1 $2").replace(/([a-z])([A-Z][a-z])/g,"$1 $2").replace(/(\d)([A-Z][a-z])/g,"$1 $2").replace(/([a-z])(\d)/g,"$1 $2").replace(/\s+/g," ").trim()}function Ua(e){let t=-1;for(let n of Sa){let a=n.exec(e);n.lastIndex=0,a&&(t===-1||a.index<t)&&(t=a.index)}return t===-1?e:e.slice(0,t)}function ha(e,t){let n=t?.trim();if(!n||n.length<8)return e;let a=e.toLowerCase().indexOf(n.toLowerCase());return a>40?e.slice(0,a):e}function ua(e){let t=e.match(/[•·]\s*(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\.?\s+\d{1,2},\s+\d{4}/i);if(t?.index&&t.index>40)return t.index;let n=Math.max(0,e.length-260),a=e.slice(n),s=[...a.matchAll(/[.!?]\s*(?=[A-Z][A-Za-z0-9"'$])/g)];for(let d of s){let U=a.slice(d.index+1).trim(),S=U.slice(0,160),h=/^(?:Best|Top|What|How|Why|When|Where|Which|Can|Should|Is|Are|Do|Does)\b/i.test(U);if(U.length>20&&h&&/(?:\s[-|]\s|Heating|Cooling|Company|Services|Blog|Guide|Review)/i.test(S))return n+d.index+1}let i=s.at(-1);return i?.index!==void 0?n+i.index+1:e.length}function ca(e){let t=e.match(/https?:\/\/\S+/i);if(!t?.index)return e;let n=e.slice(0,t.index);return n.slice(0,ua(n))}function wa(e){if(e.length<=1200)return e;let t=e.slice(0,1200),n=Math.max(t.lastIndexOf("."),t.lastIndexOf("!"),t.lastIndexOf("?"));return(n>240?t.slice(0,n+1):t).trim()}function sn(e,t,n){if(!e)return;let a=Dt(e),s=t?Dt(t):"";if(s&&a.toLowerCase().startsWith(s.toLowerCase())&&(a=a.slice(s.length).trim()),!/^An error has occurred\.?\s*Please try again later\.?/i.test(a)){for(let i of la)a=a.replace(i," ");if(a=a.replace(/\b[A-Z][A-Za-z&'\u2019 -]{2,60}\+\d+\b/g," ").replace(/\b(?:[a-z0-9-]+\.)+[a-z]{2,}\+\d+\b/gi," "),a=Dt(a),a=Ua(a),a=ha(a,n),a=ca(a),a=Dt(a),a=a.replace(/\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\.?\s+\d{1,2},\s+\d{4}$/i,"").trim(),a=wa(a),!!a&&!/^An error has occurred\.?\s*Please try again later\.?$/i.test(a))return a}}async function on(e){let t=e??{aio:{root:"[data-lhcontainer][data-streaming-container][eid]",legacyRoot:'[data-hveid="CBMQAA"]',wrapper:".Fgyi2e",controller:'[jscontroller="AkrxPe"]',contentSubtree:'[data-subtree="mfc"]',heading:".Fzsovc.cwYVJe.RJPOee",header:".heWuVc",showMoreButton:'[aria-label="Show more AI Overview"]',sourcesPanel:".OZ9ddf.WAUd4",disclaimer:".DuQANe.MSJHRb"},aim:{root:'[data-hveid="CAUQAA"]',wrapper:".Fgyi2e"},expandWaitMs:1500},n=window.google?.sn??"unknown",a=n==="aim"?"aim":n==="web"?"web":"unknown";function s(y){return y?(y.innerText??y.textContent??"").trim():""}function i(y){if(!y)return!1;let T=y.replace(/\s+/g," ").trim();return T.length>=16&&T.split(" ").filter(Boolean).length>=2}function d(y){let T=y.querySelector(t.aio.heading);if(s(T)==="AI Overview")return!0;let w=y.querySelector(t.aio.header);return!!s(w).split(/\n|\s{2,}/).some(C=>C.trim()==="AI Overview")}function U(){let T=Array.from(document.querySelectorAll(t.aio.root)).find(d);if(T)return T;if(t.aio.legacyRoot){let C=document.querySelector(t.aio.legacyRoot);if(C&&d(C))return C}let w=document.querySelectorAll(`${t.aio.heading}, h1, h2, h3, [role="heading"]`);for(let C of w){if(s(C)!=="AI Overview")continue;let M=C.parentElement;for(let m=0;m<8&&M;m++){if(M.matches(t.aio.root)||M.querySelector(t.aio.controller)||M.querySelector(t.aio.contentSubtree))return M;M=M.parentElement}return C.parentElement}return null}function S(y){if(!y)return null;let T=y.cloneNode(!0);T.querySelectorAll(["script","style","noscript","img","picture","video",t.aio.header,t.aio.showMoreButton,t.aio.sourcesPanel,t.aio.disclaimer,'[data-subtree="dfa"]',"[data-src-id]",'[role="dialog"]',".HWMcu",".bTFeG",".CyMdWb",".MFrAxb",".F0OfWd.hfWAgb",".x2qcTc.fZavHb",".SvjEff",".sR2MY",".lKuDef",".GSPQcc","a[href]","button",'[role="button"]'].join(",")).forEach(b=>b.remove());let w=document.createElement("div");w.style.position="fixed",w.style.left="-10000px",w.style.top="0",w.style.width=`${Math.max(320,Math.round(y.getBoundingClientRect?.().width||960))}px`,w.style.opacity="0",w.style.pointerEvents="none",w.append(T),document.body.append(w);let C=T.innerText||T.textContent||"";w.remove();let M=C.replace(/\r/g,"").replace(/[ \t]+\n/g,`
21695
21695
  `).replace(/\n[ \t]+/g,`
21696
21696
  `).replace(/\n{3,}/g,`
21697
21697
 
21698
21698
  `).replace(/[ \t]{2,}/g," ").trim().split(`
21699
- `).map(b=>b.replace(/\u00a0/g," ").trim()).filter(Boolean),m=[];for(let b=0;b<k.length;b++){let W=k[b],D=k[b+1]??"";if(W!=="AI Overview"&&W!=="Show more"&&!/^AI can make mistakes/i.test(W)&&!/^Thank you\b/i.test(W)&&!/^Your feedback helps Google improve/i.test(W)&&!/^\+?\d+$/.test(W)){if(/^\+\d+$/.test(D)&&W.length<=80){b++;continue}m.push(W)}}let I=m.join(`
21699
+ `).map(b=>b.replace(/\u00a0/g," ").trim()).filter(Boolean),m=[];for(let b=0;b<M.length;b++){let W=M[b],D=M[b+1]??"";if(W!=="AI Overview"&&W!=="Show more"&&!/^AI can make mistakes/i.test(W)&&!/^Thank you\b/i.test(W)&&!/^Your feedback helps Google improve/i.test(W)&&!/^\+?\d+$/.test(W)){if(/^\+\d+$/.test(D)&&W.length<=80){b++;continue}m.push(W)}}let I=m.join(`
21700
21700
  `).replace(/\n{3,}/g,`
21701
21701
 
21702
- `).trim();return!I||/not available|try again|can't generate/i.test(I)?null:I}function h(y){if(!y||y.startsWith("javascript:"))return null;try{let T=new URL(y,window.location.href);return!["http:","https:"].includes(T.protocol)||T.username||T.password?null:{href:T.href,rawHref:T.href}}catch{return null}}function l(y){if(!y)return[];let T=new Set,w=[];for(let C of Array.from(y.querySelectorAll("a[href]"))){let k=h(C.getAttribute("href")??"");if(!k||T.has(k.rawHref))continue;T.add(k.rawHref);let m="";try{m=new URL(k.href).hostname.replace(/^www\./,"")}catch{}w.push({text:s(C)||m||k.href,href:k.href,rawHref:k.rawHref})}return w}async function o(y){let T=y.querySelector(t.aio.showMoreButton);if(!T||T.getAttribute("aria-expanded")!=="false")return!1;T.click();let w=t.expandWaitMs??1500;return w>0&&await new Promise(C=>setTimeout(C,w)),!0}let r=U(),u=null,c=[],g=!1,v=!1,P=[];if(r){g=await o(r);let y=r.querySelector(t.aio.controller),T=r.querySelector(t.aio.contentSubtree),w=r.querySelector(t.aio.showMoreButton);v=y?.getAttribute("data-trnct")==="false"||w?.getAttribute("aria-expanded")==="true"||!w,u=S(T??y??r),P=(u??"").split(`
21703
- `).map(C=>C.trim()).filter(C=>/^\d+\.\s+.+/.test(C)),c=l(r)}let M=document.querySelector(t.aim.root),A=a==="aim"&&!!M,x=M?.closest(t.aim.wrapper)??M,B=A?S(x):null,N=A&&i(B),p=N?B:null,L=N?l(x):[],f=!!r&&i(u);return{surface:a,aiOverview:{detected:f,text:f?u:null,citations:f?c:[],expanded:f?g:!1,fullyExpanded:f?v:!1,sections:f?P:[]},aiMode:{detected:N&&p!==null,text:p,citations:L}}}import{createHash as ga}from"crypto";var rn=8e3,ln=3e3,Sn=1e4,ya=8;function nt(e){return/(^|\.)google\.(?:com|[a-z]{2,3}(?:\.[a-z]{2})?)$/i.test(e)}function pt(e){if(!e||e.length>rn)return null;try{let t=new URL(e);return t.protocol!=="http:"&&t.protocol!=="https:"||t.username||t.password?null:t}catch{return null}}function Ca(e,t){if(!e||e.length>rn||/^javascript:/i.test(e))return null;try{let n=new URL(e,t);return pt(n.href)}catch{return null}}function Mt(e){let t=pt(e);return!t||t.protocol!=="https:"||!nt(t.hostname)||t.pathname!=="/goto"?null:t.searchParams.get("url")?t:null}function re(e){if(e.linkType!=="google_goto_redirect"||e.resolutionStatus!=="resolved"||!Mt(e.rawUrl)||!e.resolvedUrl)return!1;let t=pt(e.resolvedUrl);return!!(t&&!nt(t.hostname)&&t.href===e.resolvedUrl&&e.url===t.href)}function ot(e){let t=e.normalize("NFKC").toLocaleLowerCase("en-US").replace(/[^\p{L}\p{N}\s]/gu,"").replace(/\s+/g," ").trim();return`paa_${ga("sha256").update(t).digest("hex").slice(0,16)}`}function Vt(e,t){let n=Ca(e,t);if(!n)return null;let a=n.href;if(!nt(n.hostname))return{url:a,rawUrl:a,resolvedUrl:a,linkType:"plain",resolutionStatus:"not_needed"};if(n.pathname==="/url"){let s=pt(n.searchParams.get("q")??n.searchParams.get("url")??"");return!s||nt(s.hostname)?null:{url:s.href,rawUrl:a,resolvedUrl:s.href,linkType:"google_url_redirect",resolutionStatus:"resolved"}}return n.pathname==="/goto"&&n.searchParams.get("url")?{url:a,rawUrl:a,resolvedUrl:null,linkType:"google_goto_redirect",resolutionStatus:"unresolved"}:null}function le(e){return Mt(e)?.searchParams.get("url")??null}function Un(e,t){try{let n=new URL(e),a=pt(new URL(t,n).href);return!a||nt(a.hostname)?null:(!a.hash&&n.hash&&(a.hash=n.hash),a.href)}catch{return null}}async function hn(e,t={}){let n=[...new Set([...e].flatMap(o=>Mt(o)?[o]:[]))],a=new Map(n.map(o=>[o,{rawUrl:o,resolvedUrl:null,resolutionStatus:"unresolved"}])),s=typeof globalThis.fetch=="function"?globalThis.fetch.bind(globalThis):null,i=t.fetchImpl??s;if(n.length===0||!i)return{resolutions:[...a.values()],nonGoogleRequestsObserved:0};let d=Math.max(1,t.timeoutMs??ln),U=Date.now()+Math.max(1,t.totalBudgetMs??Sn),S=Math.max(1,Math.min(16,Math.floor(t.concurrency??ya))),h=0,l=async()=>{for(;h<n.length;){let o=n[h++],r=Mt(o),u=r?.searchParams.get("url");if(!r||!u){a.set(o,{rawUrl:o,resolvedUrl:null,resolutionStatus:"rejected"});continue}r.hash="";let c=r.href;for(let g=0;g<2;g++){let v=U-Date.now();if(v<=0)return;let P=new AbortController,M=setTimeout(()=>P.abort(),Math.min(d,v)),A;try{A=await i(c,{method:"GET",redirect:"manual",headers:{accept:"*/*","user-agent":"Mozilla/5.0"},signal:P.signal})}catch{break}finally{clearTimeout(M)}if(A.status<300||A.status>=400)break;let x=A.headers.get("location");if(!x)break;let B=Un(o,x);if(B){a.set(o,{rawUrl:o,resolvedUrl:B,resolutionStatus:"resolved"});break}let N;try{N=new URL(x,c)}catch{a.set(o,{rawUrl:o,resolvedUrl:null,resolutionStatus:"rejected"});break}if(!nt(N.hostname)||le(N.href)!==u){a.set(o,{rawUrl:o,resolvedUrl:null,resolutionStatus:"rejected"});break}c=N.href}}};return await Promise.all(Array.from({length:Math.min(S,n.length)},()=>l())),{resolutions:[...a.values()],nonGoogleRequestsObserved:0}}function dn(e,t){try{return new URL(e.resolvedUrl??e.url).hostname.replace(/^www\./,"")}catch{return t}}async function un(e,t={}){let n=[],a=o=>{for(let r of o)n.push(r),a(r.children??[])};a(e.tree??[]);let s=[...e.flat.flatMap(o=>o.sources??[]),...n.flatMap(o=>o.sources),...e.organicResults??[],...(e.aiOverview?.citations??[]).map(({text:o,href:r,...u})=>({...u,url:r})),...(e.aiMode?.citations??[]).map(({text:o,href:r,...u})=>({...u,url:r}))],i=new Map(s.filter(o=>!!o?.rawUrl).map(o=>[o.rawUrl,o])),d=[...i.values()].filter(o=>o.linkType==="google_goto_redirect"&&o.resolutionStatus!=="resolved").map(o=>o.rawUrl);if(d.length>0){let o=await hn(d,t);for(let r of o.resolutions){let u=i.get(r.rawUrl);u&&i.set(r.rawUrl,r.resolutionStatus==="resolved"&&r.resolvedUrl?{...u,url:r.resolvedUrl,resolvedUrl:r.resolvedUrl,resolutionStatus:"resolved"}:{...u,resolutionStatus:r.resolutionStatus})}}let U=o=>({...o,...i.get(o.rawUrl)??o}),S=o=>o.map(r=>{let u=U(r);return{...u,site:dn(u,r.site)}});for(let o of e.flat){o.sources=S(o.sources??[]);let r=o.sources[0];o.source_title=r?.title??o.source_title,o.source_site=r?.site??o.source_site,o.source_cite=r?.url??o.source_cite}for(let o of n){o.sources=S(o.sources??[]);let r=o.sources[0];o.sourceTitle=r?.title??o.sourceTitle,o.sourceSite=r?.site??o.sourceSite,o.sourceCite=r?.url??o.sourceCite}for(let o=0;o<(e.organicResults?.length??0);o++){let r=U(e.organicResults[o]);e.organicResults[o]={...r,domain:dn(r,e.organicResults[o].domain)??""}}let h=o=>{let r=U({url:o.href,rawUrl:o.rawUrl,resolvedUrl:o.resolvedUrl,linkType:o.linkType,resolutionStatus:o.resolutionStatus}),{url:u,...c}=r;return{...o,...c,href:u}};e.aiOverview&&(e.aiOverview.citations=(e.aiOverview.citations??[]).map(h)),e.aiMode&&(e.aiMode.citations=(e.aiMode.citations??[]).map(h));let l=[...i.values()];return e.diagnostics.links={linkCandidatesObserved:i.size,plainLinksObserved:l.filter(o=>o.linkType==="plain").length,googleUrlRedirectsObserved:l.filter(o=>o.linkType==="google_url_redirect").length,googleGotoRedirectsObserved:l.filter(o=>o.linkType==="google_goto_redirect").length,redirectsResolved:l.filter(o=>o.linkType!=="plain"&&o.resolutionStatus==="resolved").length,redirectsUnresolved:l.filter(o=>o.resolutionStatus==="unresolved").length,redirectsRejected:l.filter(o=>o.resolutionStatus==="rejected").length,resolverNonGoogleRequestsObserved:0,paaSourcesPreserved:e.flat.reduce((o,r)=>o+r.sources.length,0),aiOverviewLabelValidated:e.aiOverview?.detected??!1},e}async function cn(e,t,n={}){let a=new Map;for(let r of t){let u=a.get(r.rawUrl);u&&re(u)||a.set(r.rawUrl,r.linkType==="google_goto_redirect"&&!re(r)?{...r,url:r.rawUrl,resolvedUrl:null,resolutionStatus:"unresolved"}:r)}let s=[...a.values()].filter(r=>r.linkType==="google_goto_redirect"&&!re(r));if(s.length===0)return a;let i=Date.now()+(n.totalBudgetMs??Sn),d=await hn(s.map(r=>r.rawUrl),n);for(let r of d.resolutions){let u=a.get(r.rawUrl);u&&a.set(r.rawUrl,r.resolutionStatus==="resolved"&&r.resolvedUrl?{...u,url:r.resolvedUrl,resolvedUrl:r.resolvedUrl,resolutionStatus:"resolved"}:{...u,resolutionStatus:r.resolutionStatus})}let U=s.filter(r=>a.get(r.rawUrl)?.resolutionStatus==="unresolved");if(U.length===0||n.browserFallback===!1||Date.now()>=i)return n.onNetworkAudit?.({nonGoogleRequestsObserved:0}),a;let S=n.timeoutMs??ln,h=await e.context().newPage().catch(()=>null);if(!h)return n.onNetworkAudit?.({nonGoogleRequestsObserved:0}),a;let l=null,o=0;try{await h.route("**/*",async r=>{let u=r.request().url();try{nt(new URL(u).hostname)||(o+=1)}catch{}let c=le(u);if(!l||c!==l.token){await r.abort("blockedbyclient").catch(()=>{});return}let g=l;try{let v=await r.fetch({maxRedirects:0,timeout:g.timeoutMs});g.location=v.headers().location??null}finally{await r.abort("blockedbyclient").catch(()=>{}),g.finish()}});for(let r of U){let u=i-Date.now();if(u<=0)break;let c=Mt(r.rawUrl),g=c?.searchParams.get("url");if(!c||!g){a.set(r.rawUrl,{...r,resolutionStatus:"rejected"});continue}let v=Math.min(S,u);c.hash="";let P=c.href,M=!1;for(let A=0;A<2;A++){let x,B=new Promise(y=>{x=y}),N=`mcp-goto-${Math.random().toString(36).slice(2)}`;l={token:g,timeoutMs:v,location:null,finish:x},await h.evaluate(({url:y,id:T})=>{let w=document.createElement("iframe");w.id=T,w.hidden=!0,w.src=y,document.body.append(w)},{url:P,id:N}).catch(()=>null),await Promise.race([B,new Promise(y=>setTimeout(y,v))]);let p=l.location;if(l=null,await h.evaluate(y=>document.getElementById(y)?.remove(),N).catch(()=>null),!p)break;let L=Un(r.rawUrl,p);if(L){a.set(r.rawUrl,{...r,url:L,resolvedUrl:L,resolutionStatus:"resolved"});break}let f;try{f=new URL(p,P)}catch{M=!0;break}if(!nt(f.hostname)||le(f.href)!==g){M=!0;break}P=f.href}M&&a.get(r.rawUrl)?.resolutionStatus!=="resolved"&&a.set(r.rawUrl,{...r,resolutionStatus:"rejected"})}}finally{l=null,await h.close().catch(()=>{}),n.onNetworkAudit?.({nonGoogleRequestsObserved:o})}return a}var wn=String.raw`^(?:an error has occurred(?:[.!…]\s*)?(?:please try again later[.!…]?)?|loading|please wait|try again|something went wrong)[.!…\s]*$`,ka=700,Ma=1e3,pa=1400,gn=900,ma=3,yn=250,Et=class{constructor(t,n,a,s){this.driver=t;this.reporter=n;this.onPaaProgress=a;this.onProviderSession=s}driver;reporter;onPaaProgress;onProviderSession;completeness={paaWithoutAnswer:0,paaWithoutSource:0,paaAnswersRecovered:0,aioShareCaptured:null};aioShareUrlEarly=null;linkDiagnostics=this.emptyLinkDiagnostics();collectedRows=[];partialContext=null;progressSequence=0;clickedQuestions=new Set;paaLifecycle=this.emptyPaaLifecycle(0);checkpointMaterial=null;interactionObservations=[];phaseTimings={};currentPhaseTimings(t){return{...this.phaseTimings,totalServerMs:Math.max(0,Date.now()-t)}}emptyPaaLifecycle(t){return{requestedQuestions:t,questionsFound:0,targetStatus:"not_met",discoveryStatus:"in_progress",materialStatus:"partial",completionReason:"PAA expansion is still running.",automaticRetries:0,retryBreakdown:{controlRetries:0,browserRetries:0,providerFallbacks:0,runtimeRecoveries:0,idempotentReplays:0},knownQuestions:0,processedQuestions:0,failedInteractions:0,noGrowthConfirmations:0,visibleControls:0,eligibleControls:0,dispatchedInteractions:0,confirmedInteractions:0,unconfirmedInteractions:0}}emptyLinkDiagnostics(){return{linkCandidatesObserved:0,plainLinksObserved:0,googleUrlRedirectsObserved:0,googleGotoRedirectsObserved:0,redirectsResolved:0,redirectsUnresolved:0,redirectsRejected:0,resolverNonGoogleRequestsObserved:0,paaSourcesPreserved:0,aiOverviewLabelValidated:!1}}mergePaaSources(t=[],n=[]){let a=new Map;for(let s of[...t,...n]){let i=a.get(s.rawUrl);if(!i){a.set(s.rawUrl,s);continue}let d=s.resolutionStatus==="resolved"&&i.resolutionStatus!=="resolved"?s:i;a.set(s.rawUrl,{...d,title:d.title??i.title??s.title,site:d.site??i.site??s.site})}return[...a.values()]}normalizeAICitations(t,n){let a=new Set;return n.flatMap(s=>{let i=Vt(s.rawHref??s.href,t);if(!i||a.has(i.rawUrl))return[];a.add(i.rawUrl);let{url:d,...U}=i;return[{...U,text:s.text,href:d}]})}async resolveMaterialLinks(t,n,a,s,i){let d=Date.now(),U=[...n.flatMap(c=>c.sources??[]),...a,...s.citations.map(({text:c,href:g,...v})=>({...v,url:g})),...i.citations.map(({text:c,href:g,...v})=>({...v,url:g}))],S=new Map(U.map(c=>[c.rawUrl,c])),h=0,l=await cn(t,U,{onNetworkAudit:c=>{h=c.nonGoogleRequestsObserved}}),o=c=>({...c,...l.get(c.rawUrl)??c});for(let c of n){c.sources=(c.sources??[]).map(o);let g=c.sources[0];c.source_title=g?.title??c.source_title,c.source_site=g?.site??c.source_site,c.source_cite=g?.url??c.source_cite}for(let c=0;c<a.length;c++){let g=o(a[c]);if(g.resolvedUrl)try{g.domain=new URL(g.resolvedUrl).hostname.replace(/^www\./,"")}catch{}a[c]=g}let r=c=>{let g=o({url:c.href,rawUrl:c.rawUrl,resolvedUrl:c.resolvedUrl,linkType:c.linkType,resolutionStatus:c.resolutionStatus}),{url:v,...P}=g;return{...P,text:c.text,href:v}};s.citations=s.citations.map(r),i.citations=i.citations.map(r);let u=[...l.values()];this.linkDiagnostics={linkCandidatesObserved:S.size,plainLinksObserved:u.filter(c=>c.linkType==="plain").length,googleUrlRedirectsObserved:u.filter(c=>c.linkType==="google_url_redirect").length,googleGotoRedirectsObserved:u.filter(c=>c.linkType==="google_goto_redirect").length,redirectsResolved:u.filter(c=>c.linkType!=="plain"&&c.resolutionStatus==="resolved").length,redirectsUnresolved:u.filter(c=>c.resolutionStatus==="unresolved").length,redirectsRejected:u.filter(c=>c.resolutionStatus==="rejected").length,resolverNonGoogleRequestsObserved:h,paaSourcesPreserved:n.reduce((c,g)=>c+(g.sources??[]).length,0),aiOverviewLabelValidated:s.detected},this.phaseTimings.linkResolutionMs=(this.phaseTimings.linkResolutionMs??0)+(Date.now()-d)}normalizeQuestion(t){return t.toLowerCase().replace(/[^\w\s]/g,"").replace(/\s+/g," ").trim()}throwIfAborted(t){if(t?.aborted)throw t.reason instanceof DOMException&&t.reason.name==="TimeoutError"?t.reason:new j}async throwIfCaptcha(t,n){if(await t.locator(F.captchaMarker).count().catch(()=>0)>0)throw new J(`${n} returned a CAPTCHA \u2014 retrying with a fresh session.`)}async extractVisibleItems(t,n){let a=F,s=await t.evaluate(({selectors:d,onlyQuestion:U,answerPlaceholderPattern:S})=>{function h(o){if(!o)return"";let r=[];for(let u of o.childNodes)if(u.nodeType===Node.TEXT_NODE){let c=u.textContent?.trim();c&&r.push(c)}else{if(u.tagName==="STYLE"||u.tagName==="SCRIPT")continue;{let c=h(u);c&&r.push(c)}}return r.join(" ").replace(/\s+/g," ").trim()}function l(o){return(o??"").replace(/\s*\(\+\d+\)\s*-\s*View related links.*$/i,"").replace(/\s*-\s*Opens in new tab.*$/i,"").trim()}return Array.from(document.querySelectorAll(d.item)).filter(o=>!U||(o.getAttribute(d.itemDataQ)||o.getAttribute(d.itemDataInitQ)||o.querySelector(d.itemQuestionEl)?.innerText?.trim()||"")===U).map(o=>{let r=o.querySelector(d.clickTarget),u=o.classList.contains(d.expandedClass)||r?.getAttribute("aria-expanded")==="true",c=o.querySelector(d.answerContainer),v=c?.querySelector(d.aiAnswerBody)??c,P=h(v),M=new RegExp(S,"i").test(P),A=[...Array.from((v??o).querySelectorAll("a[href]")),...Array.from(o.querySelectorAll(d.aiCitation)),...Array.from(o.querySelectorAll(d.aiSourceCard))],x=!M&&(u&&P.length>=10||P.length>30&&A.some(L=>/^https?:\/\//.test(L.href))),B=x&&o.querySelector(d.sourceTitle)?.innerText?.trim()||void 0,N=x&&o.querySelector(d.sourceSite)?.innerText?.trim()||void 0,p=[];if(x){let L=new Set;for(let y of A)!/^https?:\/\//.test(y.href)||L.has(y.href)||(L.add(y.href),p.push({title:l(y.getAttribute("aria-label"))||(y.textContent||"").trim(),rawHref:y.href}));let f=p.find(y=>y.title.length>2)??p[0];f&&(B=B||f.title||void 0)}return{googleLinkId:o.getAttribute("data-lk")||o.querySelector("[data-lk]")?.getAttribute("data-lk")||null,googleEvidenceId:o.getAttribute("data-ved")||o.querySelector("[data-ved]")?.getAttribute("data-ved")||null,question:o.getAttribute(d.itemDataQ)||o.getAttribute(d.itemDataInitQ)||o.querySelector(d.itemQuestionEl)?.innerText?.trim()||"",answer:x&&P||void 0,sourceTitle:B,sourceSite:N,sources:p}})},{selectors:a,onlyQuestion:n,answerPlaceholderPattern:wn}),i=typeof t.url=="function"?t.url():"https://www.google.com/";return s.flatMap(d=>{let U=[],S=new Set;for(let r of d.sources){let u=Vt(r.rawHref,i);if(!u||S.has(u.rawUrl))continue;S.add(u.rawUrl);let c=d.sourceSite??null;try{c||=new URL(u.resolvedUrl??u.rawUrl).hostname.replace(/^www\./,"")}catch{}U.push({...u,title:r.title||d.sourceTitle||null,site:c})}let h=U[0],l={questionId:ot(d.question),googleLinkId:d.googleLinkId,googleEvidenceId:d.googleEvidenceId,question:d.question,answer:sn(d.answer,d.question,d.sourceTitle),sourceTitle:h?.title??d.sourceTitle,sourceSite:h?.site??d.sourceSite,sourceCite:h?.url,sources:U},o=ve.safeParse(l);return o.success?[o.data]:(console.warn("[PAAExtractor] item parse failed:",d.question,o.error.issues[0]?.message),[])})}jitteredDelayMs(t,n){return t+Math.floor(Math.random()*(n-t+1))}async clickItem(t,n){try{await t.locator(`${F.item}[data-q="${n}"], ${F.item}[data-initq="${n}"]`).first().click()}catch{}}toFlatRow(t,n,a,s){return{seed_query:s,question_id:t.questionId??ot(t.question),google_link_id:t.googleLinkId??"",google_evidence_id:t.googleEvidenceId??"",question:t.question,answer:t.answer??"",source_title:t.sourceTitle??"",source_site:t.sourceSite??"",source_cite:t.sourceCite??"",sources:t.sources??[],depth:n,parent_question:a??"",extracted_at:new Date().toISOString()}}upsertCollectedRow(t){let n=this.normalizeQuestion(t.question),a=this.collectedRows.findIndex(U=>this.normalizeQuestion(U.question)===n);if(a<0)return this.collectedRows.push({...t}),!0;let s=this.collectedRows[a],i={...s,...t,answer:t.answer||s.answer,source_title:t.source_title||s.source_title,source_site:t.source_site||s.source_site,source_cite:t.source_cite||s.source_cite,sources:this.mergePaaSources(s.sources,t.sources),extracted_at:t.extracted_at||s.extracted_at},d=i.answer!==s.answer||i.source_title!==s.source_title||i.source_site!==s.source_site||i.source_cite!==s.source_cite||JSON.stringify(i.sources)!==JSON.stringify(s.sources);return d&&(this.collectedRows[a]=i),d}async emitProgress(t){if(!this.onPaaProgress||this.collectedRows.length===0&&!this.checkpointMaterial)return;let n={sequence:++this.progressSequence,observedAt:new Date().toISOString(),clickedQuestions:[...this.clickedQuestions],phase:t,records:this.collectedRows.map(a=>({...a})),lifecycle:{...this.paaLifecycle},...this.checkpointMaterial?{material:structuredClone(this.checkpointMaterial)}:{},interactions:this.interactionObservations.map(a=>({...a,confirmationSignals:[...a.confirmationSignals]}))};try{await this.onPaaProgress(n)}catch(a){console.warn(JSON.stringify({event:"paa_progress_sink_failed",sequence:n.sequence,phase:n.phase,message:a instanceof Error?a.message:String(a)}))}}getPartialResult(){let t=this.partialContext;if(!t||this.collectedRows.length===0&&!this.checkpointMaterial)return null;let n=this.collectedRows.map(U=>({...U})),a=this.checkpointMaterial,s=t.questionsOnly?0:n.filter(U=>!U.answer?.trim()).length,i=t.questionsOnly?0:n.filter(U=>(U.sources??[]).length===0).length,d={seed:t.seed,totalQuestions:n.length,maxDepthReached:n.reduce((U,S)=>Math.max(U,S.depth),0),durationMs:Date.now()-t.startMs,errorCount:0};return{seed:t.seed,location:t.location,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(t.startMs),completionStatus:"paa_found",problem:null,...a?.pagination?{pagination:{...a.pagination}}:{},resultQuality:"partial",degradedResult:!1,retryRecommended:!0,paaLifecycle:{...this.paaLifecycle,questionsFound:n.length,targetStatus:n.length>=(t.maxQuestions??0)?"met":"not_met",discoveryStatus:"interrupted",materialStatus:s>0||i>0?"partial":"complete",completionReason:"The browser attempt ended before frontier exhaustion could be proven."},completeness:{...this.completeness,paaWithoutAnswer:s,paaWithoutSource:i,paaRequested:t.maxQuestions,paaReturned:n.length,paaUnique:n.length},warnings:[{code:"paa_partial",surface:"paa",message:`Harvest stopped before finishing; returning the ${n.length} question(s) collected up to that point.`,retryable:!0}]},totalQuestions:n.length,surface:a?.surface??"web",aiOverview:a?.aiOverview??{detected:!1,text:null,citations:[]},aiMode:a?.aiMode??{detected:!1,text:null,citations:[]},whatPeopleSaying:a?.whatPeopleSaying??[],tree:this.buildTree(n,t.seed),flat:n,videos:a?.videos??[],forums:a?.forums??[],organicResults:a?.organicResults??[],localPack:a?.localPack??[],entityIds:a?.entityIds??{entities:[],kgIds:[],cids:[],gcids:[]},stats:d}}async runBFS(t,n,a){await t.waitForTimeout(700);let s=new Set,i=new Set,d=[];this.clickedQuestions=new Set,this.interactionObservations=[],this.phaseTimings={};let U=new Set,S=new Map,h=new Set,l=new Set,o=new Map,r=2,u=3,c=0,g={sel:F.item,dataQ:F.itemDataQ,dataInitQ:F.itemDataInitQ,questionEl:F.itemQuestionEl,answerSel:F.answerContainer,expandedClass:F.expandedClass,clickTarget:F.clickTarget,answerPlaceholderPattern:wn,questionsOnly:n.questionsOnly,sourceSel:"a[href]"},v=()=>t.evaluate(({sel:N,dataQ:p,dataInitQ:L,questionEl:f,expandedClass:y,clickTarget:T,answerSel:w,answerPlaceholderPattern:C,questionsOnly:k})=>{let m=I=>{if(!I)return"";let b=[];for(let W of I.childNodes){if(W.nodeType===Node.TEXT_NODE){let K=W.textContent?.trim();K&&b.push(K);continue}if(W.nodeType!==Node.ELEMENT_NODE)continue;let D=W;if(D.tagName==="STYLE"||D.tagName==="SCRIPT"||D.getAttribute("aria-hidden")==="true")continue;let z=m(D);z&&b.push(z)}return b.join(" ").replace(/\s+/g," ").trim()};return Array.from(document.querySelectorAll(N)).map((I,b)=>{let W=m(I.querySelector(w)).replace(/An AI Overview is not available for this search/gi," ").replace(/Can't generate an AI overview right now\.?\s*Try again later\.?/gi," ").replace(/\bAI Overview\b/gi," ").replace(/\s+/g," ").trim(),D=I.classList.contains(y)||I.querySelector(T)?.getAttribute("aria-expanded")==="true",z=W.length>=10&&!new RegExp(C,"i").test(W);return{q:I.getAttribute(p)||I.getAttribute(L)||I.querySelector(f)?.innerText?.trim()||"",done:D&&(k||z),expanded:D,index:b}}).filter(I=>I.q)},g),P=async(N,p,L,f,y,T)=>{let w=Date.now(),C={id:`${T}:${ot(N)}:${y}`,questionId:ot(N),question:N,batchNumber:T,controlAttempt:y,observedAt:new Date(w).toISOString(),beforeQuestionCount:p,expandedBefore:f},k=L>=0?t.locator(g.sel).nth(L).locator(g.clickTarget):null,m=null,I=k?await(async()=>(f&&(await k.click({timeout:gn,force:!0}),await t.waitForTimeout(120)),await k.click({timeout:gn,force:!0}),!0))().catch(O=>(m=O instanceof Error&&(O.name==="TimeoutError"||/timeout/i.test(O.message))?"click_ack_timeout":"click_failed",!1)):!1,b=Date.now()-w;if(!I&&m!=="click_ack_timeout")return{dispatched:!1,confirmed:!1,observation:{...C,dispatched:!1,outcome:"dispatch_failed",confirmationSignals:[],confirmationCheckpointMs:null,confirmedAtMs:null,dispatchDurationMs:b,totalDurationMs:b,afterQuestionCount:p,newQuestionCount:0,expandedAfter:f,answerObserved:!1,sourceCount:0,errorCode:L<0?"control_missing":m??"click_failed"}};let W={exists:!0,expanded:f,answerReady:!1,sourceCount:0,questionCount:p},D=[],z=null,K=null,R=!1;for(let O of[ka,Ma,pa]){let Z=w+O-Date.now();if(Z>0&&await t.waitForTimeout(Z),W=await t.evaluate(({sel:H,dataQ:E,dataInitQ:G,questionEl:V,expandedClass:$,clickTarget:X,answerSel:Nt,answerPlaceholderPattern:rt,sourceSel:ft,target:gt})=>{let Tt=St=>{if(!St)return"";let jt=[];for(let bt of St.childNodes){if(bt.nodeType===Node.TEXT_NODE){let pe=bt.textContent?.trim();pe&&jt.push(pe);continue}if(bt.nodeType!==Node.ELEMENT_NODE)continue;let Wt=bt;if(Wt.tagName==="STYLE"||Wt.tagName==="SCRIPT"||Wt.getAttribute("aria-hidden")==="true")continue;let Me=Tt(Wt);Me&&jt.push(Me)}return jt.join(" ").replace(/\s+/g," ").trim()},lt=Array.from(document.querySelectorAll(H)),Pt=lt.find(St=>(St.getAttribute(E)||St.getAttribute(G)||St.querySelector(V)?.innerText?.trim())===gt);if(!Pt)return{exists:!1,expanded:!1,answerReady:!1,sourceCount:0,questionCount:lt.length};let Bn=Pt.classList.contains($)||Pt.querySelector(X)?.getAttribute("aria-expanded")==="true",ye=Pt.querySelector(Nt),Ce=Tt(ye).replace(/An AI Overview is not available for this search/gi," ").replace(/Can't generate an AI overview right now\.?\s*Try again later\.?/gi," ").replace(/\bAI Overview\b/gi," ").replace(/\s+/g," ").trim(),ke=Ce.length>=10&&!new RegExp(rt,"i").test(Ce);return{exists:!0,expanded:Bn,answerReady:ke,sourceCount:ke?ye?.querySelectorAll(ft).length??0:0,questionCount:lt.length}},{...g,target:N}).catch(()=>W),D=[...W.expanded?["expanded"]:[],...W.answerReady?["answer"]:[],...W.sourceCount>0?["source"]:[],...W.questionCount>p?["question_growth"]:[]],W.answerReady||W.sourceCount>0||W.questionCount>p){R=!0,z=O,K=Date.now()-w;break}}let q=Date.now()-w,wt={...C,dispatched:I,outcome:R?"confirmed":I?"unconfirmed":"dispatch_failed",confirmationSignals:D,confirmationCheckpointMs:z,confirmedAtMs:K,dispatchDurationMs:b,totalDurationMs:q,afterQuestionCount:W.questionCount,newQuestionCount:Math.max(0,W.questionCount-p),expandedAfter:W.expanded,answerObserved:W.answerReady,sourceCount:W.sourceCount,errorCode:I?R?null:W.exists?"confirmation_timeout":"control_missing":m};return{dispatched:I,confirmed:R,observation:wt}},M=0;t:for(;;){if(n.softDeadlineMs&&Date.now()>=n.softDeadlineMs)throw this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"interrupted",completionReason:"The execution deadline arrived before frontier exhaustion could be proven."},new Ct(this.paaLifecycle.completionReason);this.throwIfAborted(a);let N=await v(),p=!1;for(let w of N)i.has(w.q)||(i.add(w.q),d.push(w.q),d.length<=n.maxQuestions&&(p=this.upsertCollectedRow(this.toFlatRow({questionId:ot(w.q),googleLinkId:null,googleEvidenceId:null,question:w.q,sources:[]},1,null,n.query))||p)),w.done&&h.add(w.q);if(this.paaLifecycle={...this.paaLifecycle,questionsFound:Math.min(d.length,n.maxQuestions),targetStatus:d.length>=n.maxQuestions?"met":"not_met",knownQuestions:d.length,processedQuestions:h.size,failedInteractions:l.size,visibleControls:N.length},p&&await this.emitProgress("discovered"),n.questionsOnly&&i.size>=n.maxQuestions){this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"target_reached",targetStatus:"met",completionReason:"The requested unique-question count was observed."};break}if(!n.questionsOnly&&i.size>=n.maxQuestions){let w=!1,C=new Set(d.slice(0,n.maxQuestions));for(let k of await this.extractVisibleItems(t)){if(!C.has(k.question))continue;let m=o.get(k.question),I={...k,answer:k.answer??m?.answer,sourceTitle:k.sourceTitle??m?.sourceTitle,sourceSite:k.sourceSite??m?.sourceSite,sourceCite:k.sourceCite??m?.sourceCite,sources:this.mergePaaSources(m?.sources,k.sources)};o.set(k.question,I),w=this.upsertCollectedRow(this.toFlatRow(I,1,null,n.query))||w}if(w&&await this.emitProgress("answer_captured"),[...C].every(k=>{let m=o.get(k);return!!(m?.answer?.trim()&&m.sources.length>0)})){l.clear(),this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"target_reached",targetStatus:"met",failedInteractions:0,completionReason:"The requested unique-question count and its answer/source material were observed."};break}}let L=new Set(d.slice(0,n.maxQuestions)),f=N.filter(w=>L.has(w.q)&&!w.done&&(S.get(w.q)??0)<r&&!U.has(w.q)),y=f.slice(-ma);if(this.paaLifecycle={...this.paaLifecycle,eligibleControls:f.length},y.length===0){if(i.size>=n.maxQuestions){this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"target_reached",targetStatus:"met",completionReason:"The requested unique-question count was observed."};break}let w=new Set(N.map(k=>k.q)),C=d.slice(0,n.maxQuestions).filter(k=>!h.has(k)&&(l.has(k)||!w.has(k)));if(C.length>0)throw this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"interrupted",failedInteractions:new Set([...l,...C]).size,completionReason:"At least one known PAA control failed or disappeared before it could be confirmed."},await this.emitProgress("expansion_finished"),new Ct(this.paaLifecycle.completionReason);for(let k=1;k<=u;k++){this.throwIfAborted(a),await this.throwIfCaptcha(t,"Google PAA exhaustion confirmation"),await t.mouse.wheel(0,320);let m=await t.waitForFunction(({sel:b,min:W})=>document.querySelectorAll(b).length>W,{sel:F.item,min:N.length},{timeout:1500,polling:100}).catch(()=>null);if(this.paaLifecycle={...this.paaLifecycle,noGrowthConfirmations:k},m||(await v()).some(b=>!i.has(b.q)))continue t}this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"frontier_exhausted",targetStatus:"not_met",failedInteractions:0,noGrowthConfirmations:u,completionReason:"Every known eligible PAA control was processed and three healthy no-growth confirmations found no additional questions."};break}await this.throwIfCaptcha(t,"Google PAA expansion"),c+=1;for(let w of y){if(this.reporter.onDepth(++M),(S.get(w.q)??0)>0){let C=this.paaLifecycle.retryBreakdown.controlRetries+1;this.paaLifecycle={...this.paaLifecycle,automaticRetries:C+this.paaLifecycle.retryBreakdown.browserRetries+this.paaLifecycle.retryBreakdown.runtimeRecoveries,retryBreakdown:{...this.paaLifecycle.retryBreakdown,controlRetries:C}}}S.set(w.q,(S.get(w.q)??0)+1)}let T=await Promise.all(y.map(async w=>({target:w,result:await P(w.q,N.length,w.index,w.expanded,S.get(w.q)??1,c)})));for(let{target:w,result:C}of T)(C.dispatched||C.confirmed)&&this.clickedQuestions.add(w.q),this.interactionObservations.push(C.observation);if(this.interactionObservations.length>yn&&this.interactionObservations.splice(0,this.interactionObservations.length-yn),!n.questionsOnly){let w=new Set(y.map(C=>C.q));for(let C of await this.extractVisibleItems(t))w.has(C.question)&&(o.set(C.question,C),this.upsertCollectedRow(this.toFlatRow(C,1,null,n.query))&&await this.emitProgress("answer_captured"))}for(let{target:w,result:C}of T){let k=o.get(w.q);C.confirmed||k?.answer?.trim()?(h.add(w.q),l.delete(w.q)):(S.get(w.q)??0)>=r&&(l.add(w.q),U.add(w.q))}this.paaLifecycle={...this.paaLifecycle,processedQuestions:h.size,failedInteractions:l.size,noGrowthConfirmations:0,dispatchedInteractions:this.interactionObservations.filter(w=>w.dispatched).length,confirmedInteractions:this.interactionObservations.filter(w=>w.outcome==="confirmed").length,unconfirmedInteractions:this.interactionObservations.filter(w=>w.outcome!=="confirmed").length},await this.emitProgress("click_observed")}let A=n.questionsOnly?new Map:new Map(o);n.questionsOnly||await this.fillIncompleteItems(t,d,A,n,U);let x=[];for(let N of d){if(x.length>=n.maxQuestions)break;let p=this.normalizeQuestion(N);if(s.has(p))continue;s.add(p);let L=A.get(N);if(L){let f=this.toFlatRow(L,1,null,n.query);this.upsertCollectedRow(f),x.push(f),this.reporter.onQuestion({questionId:L.questionId,googleLinkId:L.googleLinkId,googleEvidenceId:L.googleEvidenceId,question:L.question,answer:L.answer??null,sourceTitle:L.sourceTitle??null,sourceSite:L.sourceSite??null,sourceCite:L.sourceCite??null,sources:L.sources,depth:1,parentQuestion:null,children:[]})}else{let f=this.toFlatRow({questionId:ot(N),googleLinkId:null,googleEvidenceId:null,question:N,answer:void 0,sourceTitle:void 0,sourceSite:void 0,sourceCite:void 0,sources:[]},1,null,n.query);this.upsertCollectedRow(f),x.push(f)}}this.completeness.paaWithoutAnswer=n.questionsOnly?0:x.filter(N=>!N.answer).length,this.completeness.paaWithoutSource=n.questionsOnly?0:x.filter(N=>(N.sources??[]).length===0).length,this.completeness.paaRequested=n.maxQuestions,this.completeness.paaReturned=x.length,this.completeness.paaUnique=s.size;let B=!n.questionsOnly&&(this.completeness.paaWithoutAnswer>0||this.completeness.paaWithoutSource>0);return this.paaLifecycle={...this.paaLifecycle,questionsFound:x.length,targetStatus:x.length>=n.maxQuestions?"met":"not_met",materialStatus:B?"partial":"complete",processedQuestions:h.size,failedInteractions:l.size},await this.emitProgress("fill_incomplete"),await this.emitProgress("expansion_finished"),x}async fillIncompleteItems(t,n,a,s,i){let d=new Set(n.slice(0,s.maxQuestions)),U=l=>!l?.answer||(l.sources??[]).length===0,S=new Set([...d].filter(l=>U(a.get(l)))),h=new Set([...S].filter(l=>!a.get(l)?.answer));if(S.size!==0){for(let l of S){if(s.softDeadlineMs&&Date.now()>=s.softDeadlineMs)break;let o=(await this.extractVisibleItems(t,l))[0];if(!o)continue;let r=a.get(l);a.set(l,{...o,answer:o.answer??r?.answer,sourceTitle:o.sourceTitle??r?.sourceTitle,sourceSite:o.sourceSite??r?.sourceSite,sourceCite:o.sourceCite??r?.sourceCite,sources:this.mergePaaSources(r?.sources,o.sources)});let u=a.get(l);u&&this.upsertCollectedRow(this.toFlatRow(u,1,null,s.query))&&await this.emitProgress("fill_incomplete")}this.completeness.paaAnswersRecovered=[...h].filter(l=>a.get(l)?.answer).length}}async reExpandCollapsedItems(t){let n=`${F.item}:not(.${F.expandedClass}) ${F.clickTarget}`,a=await t.locator(n).count().catch(()=>0);if(a===0)return!1;for(let s=0;s<a;s++)try{let i=t.locator(n).first();await i.scrollIntoViewIfNeeded(),await i.click({force:!0}),await t.waitForTimeout(this.jitteredDelayMs(300,500))}catch{}return!0}async extractVideos(t){let n=Le;return t.evaluate(a=>{let s=[],i=Array.from(document.querySelectorAll(a.container));for(let d of i){let h=(d.querySelector(a.sectionHeading)?.textContent?.trim()??"").toLowerCase().includes("short")?"short_video":"video",l=Array.from(d.querySelectorAll(a.item));for(let o of l){let r=o.href;if(!r||!r.includes("youtube")&&!r.includes("youtu.be"))continue;let u=o.textContent?.trim()??"",c=u.indexOf("YouTube");if(c===-1)continue;let g=u.slice(0,c).trim(),P=u.slice(c+7).replace(/^[·\s·]+/,"").match(/^([^·\n]+)/),M=P?P[1].trim():"";g&&s.push({type:h,title:g,channel:M,platform:"YouTube",duration:"",url:r})}}return s},n)}async extractForums(t){let n=xe;return t.evaluate(a=>{let s=[],d=Array.from(document.querySelectorAll(a.section)).find(S=>S.textContent?.includes("Discussions"));if(!d)return s;let U=Array.from(d.querySelectorAll(a.item));for(let S of U){let h=S.href;if(!h)continue;let l=S.querySelector(a.title),o=S.querySelector(a.source),r=l?.textContent?.trim()??"",u=o?.textContent?.trim()??"";r&&s.push({title:r,source:u,url:h})}return s},n)}async extractShortVideos(t,n){try{await t.goto(n,{waitUntil:"domcontentloaded"}),await t.waitForTimeout(1500)}catch{return[]}await this.throwIfCaptcha(t,"Google short video search");let a={item:Lt.item,platforms:[...Lt.platforms]};return(await t.evaluate(i=>{let d=new Set,U=[],S=Array.from(document.querySelectorAll(i.item)),h=["youtube.com","youtu.be","tiktok.com","instagram.com","facebook.com","fb.watch"],l=new Map;for(let o of S){let r=o.href;if(!r||!h.some(c=>r.includes(c)))continue;let u=o.textContent?.trim()??"";l.has(r)||l.set(r,[]),l.get(r).push(u)}for(let[o,r]of l.entries()){if(d.has(o))continue;d.add(o);let u=r.find(M=>/^\d+:\d+$/.test(M))??"",c=r.find(M=>!/^\d+:\d+$/.test(M)&&M.length>5)??"";if(!c)continue;let g=c,v="",P="";for(let M of i.platforms){let A=-1,x=0;for(;;){let f=c.indexOf(M,x);if(f===-1)break;A=f,x=f+1}if(A===-1)continue;let B=c.slice(A+M.length);if(!(/^[\s·]/.test(B)||B.trim()===""))continue;g=c.slice(0,A).trim(),v=M;let p=B.replace(/^[\s·]+/,""),L=p.indexOf("\xB7");P=(L===-1?p:p.slice(0,L)).trim();break}g&&U.push({title:g,channel:P,platform:v,duration:u,url:o})}return U},a)).map(i=>({type:"short_video",...i}))}async extractWhatPeopleSaying(t){let n=Oe;return t.evaluate(a=>{let s=Array.from(document.querySelectorAll(a.sectionTag)).find(i=>i.textContent?.includes(a.sectionHeadingText))??document.querySelector(".yG4QQe.TBC9ub.NbhJ1c");return s?Array.from(s.querySelectorAll(a.card)).map(i=>{let U=i.querySelector(a.cardLink)?.href??"",S=i.querySelector(a.titleH1)?.textContent?.trim(),h=i.querySelector(a.titleDiv)?.textContent?.trim(),l=S??h??"",o=i.querySelector(a.source)?.textContent?.trim()??"",u=i.querySelector(a.platformBadge)?.textContent?.trim()??"",c=i.querySelector(a.ytChannel)?.textContent?.trim()??"",g=i.querySelector(a.ytDate)?.textContent?.trim()??"",v=i.querySelector(a.authorNote)?.textContent?.trim()??null,P=i.querySelector(a.popularCommentLabel),M=null;if(P){let m=P.nextSibling;for(;m;){let I=m.textContent?.trim();if(I){M=I;break}m=m.nextSibling}}let A=Array.from(i.querySelectorAll("span")),x=A.find(m=>/^\d+:\d+$/.test(m.textContent?.trim()??""))?.textContent?.trim()??null,N=A.map(m=>m.textContent?.trim()??"").filter(m=>/\d/.test(m)&&(m.includes("comment")||m.includes("reaction")||m.includes("view")||m.includes("like")||m.includes("share")))[0]??"",p=A.map(m=>m.textContent?.trim()??"").filter(m=>/\d+ (day|week|month|year|hour)s? ago|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/.test(m)),L=g||(p[0]??""),f=u||(c?"YouTube":""),y=c||o,T="unknown",w=f.toLowerCase(),C=y.toLowerCase(),k=o.toLowerCase();return w.includes("reddit")||C.startsWith("r/")?T="reddit":w.includes("facebook")||k.includes("facebook")?T="facebook":w.includes("instagram")||k.includes("instagram")?T="instagram":w.includes("tiktok")||k.includes("tiktok")?T="tiktok":w.includes("youtube")||c?T="youtube":T="news",{type:T,title:l,url:U,source:y,platform:f,popularComment:M,engagement:N,date:L,duration:x,authorNote:v}}):[]},n)}async extractOrganicResults(t){let n=Fe,a=await t.evaluate(i=>{let d=[],U=0;return document.querySelectorAll(i.result).forEach(S=>{let h=S.querySelector(i.title);if(!h)return;let l=h.textContent?.trim()??"",r=h.closest("a")?.href??"";if(!l||!r)return;U++;let u=S.querySelector(i.cite)?.textContent?.trim()??null,c=S.querySelector(i.snippet)?.textContent?.trim()??null,g=!!S.querySelector(i.redditCite),v=S.querySelector(i.ratingWrap),P=v?{value:v.querySelector(i.ratingValue)?.textContent?.trim()??"",count:v.querySelector(i.reviewCount)?.textContent?.trim()??""}:null,M="";try{M=new URL(r).hostname.replace(/^www\./,"")}catch{M=S.querySelector(i.siteName)?.textContent?.trim()??""}d.push({position:U,title:l,url:r,domain:M,cite:u,snippet:c,isRedditStyle:g,inlineRating:P})}),d},n),s=typeof t.url=="function"?t.url():"https://www.google.com/";return a.flatMap(i=>{let d=Vt(i.url,s);if(!d)return[];let U=i.domain;try{U=new URL(d.resolvedUrl??d.rawUrl).hostname.replace(/^www\./,"")}catch{}return[{...i,...d,domain:U}]})}async extractLocalPack(t){let n=Re;return t.evaluate(a=>{let s=[],i=null;return document.querySelectorAll('[role="heading"]').forEach(d=>{!i&&d.textContent?.includes(a.headingText)&&(i=d.closest("[data-hveid]"))}),i&&i.querySelectorAll(a.card).forEach((d,U)=>{let S=d.querySelector(a.name)?.textContent?.trim()??"";if(!S)return;let h=d.querySelector(a.ratingValue)?.textContent?.trim()??null,l=d.querySelector(a.reviewCount)?.textContent?.trim()??null,o=l?l.replace(/[()]/g,"").trim():null,r=d.querySelector("a[data-cid]")?.getAttribute("data-cid")??null;if(!r)for(let P of Array.from(d.querySelectorAll("a[href]"))){let M=P.href.match(/[?&]cid=(\d+)/);if(M){r=M[1];break}let A=P.href.match(/!1s0x[0-9a-f]+:0x([0-9a-f]+)/i);if(A){try{r=BigInt("0x"+A[1]).toString()}catch{}if(r)break}}let u=[];d.querySelectorAll("div, span").forEach(P=>{let M=Array.from(P.childNodes).filter(A=>A.nodeType===3).map(A=>A.textContent?.trim()??"").filter(A=>A.length>1&&A.length<120).join(" ");M&&!u.includes(M)&&u.push(M)});let c=Array.from(d.querySelectorAll("a[href]")),g=c.find(P=>P.href.includes("google.com/maps"))?.href??null,v=c.find(P=>!P.href.includes("google.com")&&P.href.startsWith("http"))?.href??null;s.push({position:U+1,name:S,cid:r,rating:h,reviewCount:o,metadata:u,websiteUrl:v,directionsUrl:g})}),s},n)}async extractEntityIds(t){return t.evaluate(()=>{let n=new Set,a=new Set,s=new Set,i=new Map;function d(S){let h=[".OSrXXb",".dbg0pd",".tzt0oe",'[role="heading"]',"h3"];for(let l of h){let o=S.querySelector(l);if(o?.textContent?.trim())return o.textContent.trim()}return""}document.querySelectorAll('[id^="pv-/g/"]').forEach(S=>{let h=S.getAttribute("id");if(!h)return;let l=h.replace("pv-","");n.add(l);let o=d(S),u=S.querySelector("a[data-cid]")?.getAttribute("data-cid")??null;u&&a.add(u),o&&i.set(l,{name:o,kgId:l,cid:u,gcid:null})}),document.querySelectorAll("[data-mid]").forEach(S=>{let h=S.getAttribute("data-mid");if(h?.startsWith("/g/")&&(n.add(h),!i.has(h))){let l=d(S);l&&i.set(h,{name:l,kgId:h,cid:null,gcid:null})}}),document.querySelectorAll(".w7Dbne").forEach(S=>{let l=S.querySelector("a[data-cid]")?.getAttribute("data-cid")??null;if(!l)return;a.add(l);let o=S.querySelector(".OSrXXb")?.textContent?.trim()??"";if(!o)return;let r=S.querySelector('[id^="pv-/g/"]'),u=r?r.getAttribute("id").replace("pv-",""):null,c=u??`cid:${l}`;if(i.has(c)){let g=i.get(c);g.cid||i.set(c,{...g,cid:l})}else i.set(c,{name:o,kgId:u,cid:l,gcid:null})}),document.querySelectorAll("a[data-cid]").forEach(S=>{let h=S.getAttribute("data-cid");if(!h)return;if(a.add(h),![...i.values()].some(o=>o.cid===h)){let o=S.parentElement,r="";for(let u=0;u<8&&o;u++){let c=o.querySelector('.OSrXXb, .dbg0pd, [role="heading"], h3');if(c?.textContent?.trim()){r=c.textContent.trim();break}o=o.parentElement}r&&i.set(`cid:${h}`,{name:r,kgId:null,cid:h,gcid:null})}});let U=Array.from(document.querySelectorAll("script:not([src])")).map(S=>S.textContent??"").filter(S=>S.length>1e4).join(`
21704
- `);for(let S of U.matchAll(/\/g\/[a-zA-Z0-9_-]{5,20}/g))n.add(S[0]);for(let S of U.matchAll(/gcid:[a-zA-Z0-9_]+/g))s.add(S[0]);for(let S of U.matchAll(/0x[0-9a-f]+:0x([0-9a-f]+)/gi))try{a.add(BigInt("0x"+S[1]).toString())}catch{}return{entities:[...i.values()],kgIds:[...n],cids:[...a],gcids:[...s]}})}mergeLocalPackIntoEntities(t,n){let a=new Set(t.cids),s=t.entities.map(i=>({...i}));for(let i of n){if(!i.cid)continue;a.add(i.cid);let d=i.name.toLowerCase().trim(),U=s.find(S=>S.name.toLowerCase().trim()===d);U?U.cid||(U.cid=i.cid):s.find(S=>S.cid===i.cid)||s.push({name:i.name,kgId:null,cid:i.cid,gcid:null})}return{...t,entities:s,cids:[...a]}}async extractAISurfaces(t,n){let a=await t.evaluate(on,{aio:Be,aim:He,expandWaitMs:1500}),s=typeof t.url=="function"?t.url():"https://www.google.com/",i={surface:a.surface,aiOverview:{...a.aiOverview,citations:this.normalizeAICitations(s,a.aiOverview.citations)},aiMode:{...a.aiMode,citations:this.normalizeAICitations(s,a.aiMode.citations)}};if(!i.aiOverview.detected)return this.completeness.aioShareCaptured=null,i;let d=this.aioShareUrlEarly??await this.captureAIOverviewShareUrl(t,n).catch(()=>null);return this.completeness.aioShareCaptured=d!==null,{...i,aiOverview:{...i.aiOverview,shareUrl:d}}}async captureAIOverviewShareUrl(t,n){if(n?.softDeadlineMs&&Date.now()>=n.softDeadlineMs||!await t.evaluate(()=>{let i=Array.from(document.querySelectorAll('h1,h2,h3,[role="heading"],div')).filter(d=>(d.textContent||"").trim()==="AI Overview");for(let d of i){let U=d;for(let S=0;S<8&&U;S++){let h=U.querySelector('[aria-label="Share"]');if(h)return h.scrollIntoView({block:"center"}),h.click(),!0;U=U.parentElement}}return!1}).catch(()=>!1))return null;let s=null;try{s=await(await t.waitForFunction(()=>{let d=document.createTreeWalker(document.body,NodeFilter.SHOW_TEXT);for(;d.nextNode();){let U=(d.currentNode.textContent||"").match(/https:\/\/share\.google\/aimode\/\S+/);if(U)return U[0]}return!1},void 0,{timeout:4500,polling:250})).jsonValue()}catch{s=null}return await t.keyboard.press("Escape").catch(()=>{}),s}buildTree(t,n){let a=[],s=new Map;for(let i of t){let d={questionId:i.question_id,googleLinkId:i.google_link_id||null,googleEvidenceId:i.google_evidence_id||null,question:i.question,answer:i.answer||null,sourceTitle:i.source_title||null,sourceSite:i.source_site||null,sourceCite:i.source_cite||null,sources:i.sources??[],depth:i.depth,parentQuestion:i.parent_question||null,children:[]};s.set(i.question,d)}for(let i of s.values())i.parentQuestion&&s.has(i.parentQuestion)?s.get(i.parentQuestion).children.push(i):a.push(i);return a}getBrowserDebugSnapshot(){return this.driver.getDebugSnapshot()}buildHarvestDebugSnapshot(t,n,a,s,i){if(t.debug)return{enabled:!0,request:{query:t.query,locationInput:t.location??null,canonicalLocation:n,locationResolved:i?i.matched:null,locationMatchSource:i?i.source:null,locationAmbiguousCandidates:i?i.ambiguousCandidates:null,uule:a,gl:t.gl,hl:t.hl,device:t.device,proxyMode:t.proxyMode,proxyZip:t.proxyZip??null,serpIdentity:t.serpIdentity??null,serpOnly:t.serpOnly,pages:t.pages??1},browser:this.getBrowserDebugSnapshot(),...s?{locationEvidence:s}:{}}}async captureSecondOrganicPage(t,n,a){if(this.throwIfAborted(a),!this.driver.withTemporaryPage)return{organic:[],status:"failed",failureCode:"unsupported_driver"};let s;try{let i=new URL(t.url()),d=h=>{try{let l=new URL(h,i);return i.origin==="https://www.google.com"&&l.origin===i.origin&&!l.username&&!l.password&&l.pathname==="/search"&&l.searchParams.getAll("q").length===1&&l.searchParams.get("q")===n.query&&l.searchParams.getAll("start").length===1&&l.searchParams.get("start")==="10"&&(!l.searchParams.has("num")||l.searchParams.get("num")==="10")&&["gl","hl"].every(o=>!l.searchParams.has(o)||l.searchParams.getAll(o).length===1&&l.searchParams.get(o)===n[o])&&["uule","tbs","udm","tbm","pws"].every(o=>l.searchParams.getAll(o).length<=1&&l.searchParams.get(o)===i.searchParams.get(o))}catch{return!1}},U=await t.evaluate(()=>document.querySelector('a#pnnext, a[rel="next"]')?.getAttribute("href")??null);if(!U)return{organic:[],status:"unavailable",failureCode:"missing_next"};if(!d(U))return{organic:[],status:"unavailable",failureCode:"invalid_next"};let S=await this.driver.withTemporaryPage(async h=>{if(await h.route("**/*",async l=>{let o=l.request();o.isNavigationRequest()&&o.frame()===h.mainFrame()&&!d(o.url())?(s=/^https:\/\/www\.google\.com\/sorry(?:\/|\?)/.test(o.url())?"captcha":"invalid_next",await l.abort("blockedbyclient")):await l.fallback()}),await h.goto(new URL(U,i).href,{waitUntil:"domcontentloaded",timeout:2e4}),this.throwIfAborted(a),await this.throwIfCaptcha(h,"Google SERP page 2"),!d(h.url()))throw s="invalid_next",new Error("Invalid pagination landing");return this.extractOrganicResults(h)},a);return this.throwIfAborted(a),S.length>0?{organic:S.map(h=>({...h,position:h.position+10})),status:"captured"}:{organic:[],status:"unavailable",failureCode:"empty_page"}}catch(i){if(this.throwIfAborted(a),i instanceof j)throw i;return{organic:[],status:"failed",failureCode:s??(i instanceof J?"captcha":i instanceof Error&&(i.name==="TimeoutError"||/timed? ?out/i.test(i.message))?"timeout":"navigation_error")}}}async extract(t,n){let a=Date.now();this.completeness={paaWithoutAnswer:0,paaWithoutSource:0,paaAnswersRecovered:0,aioShareCaptured:null},this.linkDiagnostics=this.emptyLinkDiagnostics(),this.aioShareUrlEarly=null,this.collectedRows=[],this.progressSequence=0,this.checkpointMaterial=null,this.clickedQuestions=new Set,this.paaLifecycle=this.emptyPaaLifecycle(t.maxQuestions),this.partialContext={seed:t.query,location:t.location??null,startMs:a,maxQuestions:t.maxQuestions,questionsOnly:t.questionsOnly};let s=t.device==="mobile",i={headless:t.headless,profileDir:t.profileDir,proxy:t.proxy,\u006b\u0065\u0072\u006e\u0065\u006cApiKey:t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey,\u006b\u0065\u0072\u006e\u0065\u006cProxyId:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,\u006b\u0065\u0072\u006e\u0065\u006cProfileName:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName,\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges,\u006b\u0065\u0072\u006e\u0065\u006cStealth:t.\u006b\u0065\u0072\u006e\u0065\u006cStealth,\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution,proxyMode:t.proxyMode,keepDefaultProxy:t.keepDefaultProxy,requireUsEgress:t.requireUsEgress,viewport:s?{width:390,height:844}:{width:1280,height:800},locale:`${t.hl}-${t.gl.toUpperCase()}`,deviceScaleFactor:s?3:1,isMobile:s,hasTouch:s,debug:t.debug,operationDeadlineMs:t.softDeadlineMs},d=0,U=[];try{this.throwIfAborted(n);let S=Date.now();await this.driver.launch(i),this.phaseTimings.providerConnectMs=Date.now()-S;let h=this.driver.getProviderSessionMetadata();if(h?.providerSessionId&&this.onProviderSession)try{await this.onProviderSession(h)}catch(H){console.warn(JSON.stringify({event:"paa_provider_session_sink_failed",provider:h.provider,message:H instanceof Error?H.message:String(H)}))}this.throwIfAborted(n);let l=t.location?oe(t.location):null,o=t.location?l?.canonical??t.location:null,r=o?Xe(o):null,u=t,c=t.includeAllSerpFeatures,g=c||t.includeLocalPack,v=c||t.includeForums,P=c||t.includeVideos,M=c||t.includeAiOverview,A=c||t.includeWhatPeopleSaying,x={surface:"web",aiOverview:{detected:!1,text:null,citations:[]},aiMode:{detected:!1,text:null,citations:[]}},B=Date.now(),{hasPaa:N}=await this.driver.navigateToSERP(u.query,r,t.gl,t.hl,{...yt(t.recency)?{tbs:yt(t.recency)}:{},debug:t.debug,purpose:t.serpOnly?"serp":"paa",...t.softDeadlineMs?{deadlineMs:t.softDeadlineMs}:{}});this.phaseTimings.navigationMs=Date.now()-B,this.throwIfAborted(n);let p=this.driver.getPage();if(await this.throwIfCaptcha(p,"Google SERP"),N||(this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"no_paa_observed",materialStatus:"complete",completionReason:"A readable Google SERP was observed without a People Also Ask block."}),t.questionsOnly){let H=Date.now(),E=N?await this.runBFS(p,u,n):[];this.phaseTimings.paaExpansionMs=Date.now()-H,await this.resolveMaterialLinks(p,E,[],x.aiOverview,x.aiMode);let G={seed:u.query,totalQuestions:E.length,maxDepthReached:E.reduce((V,$)=>Math.max(V,$.depth),0),durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(G),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:N?"paa_found":"no_paa",...N?{}:{noPaaObserved:!0},problem:null,paaLifecycle:{...this.paaLifecycle},completeness:{...this.completeness},links:{...this.linkDiagnostics},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,void 0,l)}:{}},totalQuestions:E.length,surface:"web",aiOverview:{detected:!1,text:null,citations:[]},aiMode:{detected:!1,text:null,citations:[]},whatPeopleSaying:[],tree:this.buildTree(E,u.query),flat:E,videos:[],forums:[],organicResults:[],localPack:[],entityIds:{entities:[],kgIds:[],cids:[],gcids:[]},stats:G}}if(M&&(this.aioShareUrlEarly=await this.captureAIOverviewShareUrl(p,t).catch(()=>null)),t.serpOnly){let H=Date.now(),[E,G,V]=await Promise.all([this.extractOrganicResults(p),g?this.extractLocalPack(p):Promise.resolve([]),this.extractEntityIds(p)]),$=this.mergeLocalPackIntoEntities(V,G),X=M?await this.extractAISurfaces(p,t):x;this.phaseTimings.serpParseMs=Date.now()-H;let Nt=t.debug?kt(o,E,G):void 0,rt=E;if((t.pages??1)>=2){let gt=new URLSearchParams({q:u.query,gl:t.gl,hl:t.hl,pws:"0",start:"10"});yt(t.recency)&&gt.set("tbs",yt(t.recency)),r&&gt.set("uule",r),await this.driver.navigateTo("https://www.google.com/search?"+gt.toString()),await this.throwIfCaptcha(p,"Google SERP page 2");let Tt=await this.extractOrganicResults(p);rt=[...E,...Tt.map(lt=>({...lt,position:lt.position+10}))],t.debug&&(Nt=kt(o,rt,G))}await this.resolveMaterialLinks(p,[],rt,X.aiOverview,X.aiMode);let ft={seed:u.query,totalQuestions:0,maxDepthReached:0,durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(ft),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:"serp_only",problem:null,completeness:{...this.completeness},links:{...this.linkDiagnostics},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,Nt,l)}:{}},totalQuestions:0,surface:X.surface,aiOverview:X.aiOverview,aiMode:X.aiMode,whatPeopleSaying:[],tree:[],flat:[],videos:[],forums:[],organicResults:rt,localPack:G,entityIds:$,stats:ft}}let[L,f,y,T,w,C]=await Promise.all([P?this.extractVideos(p):Promise.resolve([]),v?this.extractForums(p):Promise.resolve([]),A?this.extractWhatPeopleSaying(p):Promise.resolve([]),this.extractEntityIds(p),this.extractOrganicResults(p),g?this.extractLocalPack(p):Promise.resolve([])]),k=this.mergeLocalPackIntoEntities(T,C),m=t.debug?kt(o,w,C):void 0;this.reporter.onVideos(L),this.reporter.onForums(f);let I=M?await this.extractAISurfaces(p,t):x,b={requestedPages:(t.pages??1)>=2?2:1,capturedPages:1,page2Status:(t.pages??1)>=2?"not_attempted":"not_requested",page1OrganicCount:w.length,page2OrganicCount:0},W=w;if(this.checkpointMaterial={surface:I.surface,aiOverview:I.aiOverview,aiMode:I.aiMode,whatPeopleSaying:y,videos:L,forums:f,organicResults:W,localPack:C,entityIds:k,pagination:b},await this.emitProgress("serp_captured"),b.requestedPages===2){let H=await this.captureSecondOrganicPage(p,u,n);W=[...w,...H.organic],b={...b,capturedPages:H.status==="captured"?2:1,page2Status:H.status,page2OrganicCount:H.organic.length,...H.failureCode?{failureCode:H.failureCode}:{}},this.checkpointMaterial={...this.checkpointMaterial,organicResults:W,pagination:b},await this.emitProgress("serp_captured"),await this.resolveMaterialLinks(p,[],W,I.aiOverview,I.aiMode),this.checkpointMaterial={...this.checkpointMaterial,organicResults:W},await this.emitProgress("serp_captured")}let D=t.debug?kt(o,W,C):m;if(!N){await this.resolveMaterialLinks(p,[],W,I.aiOverview,I.aiMode),this.checkpointMaterial={...this.checkpointMaterial,organicResults:W},await this.emitProgress("serp_captured");let H={seed:u.query,totalQuestions:0,maxDepthReached:0,durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(H),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:"no_paa",noPaaObserved:!0,problem:null,pagination:b,paaLifecycle:{...this.paaLifecycle},completeness:{...this.completeness},links:{...this.linkDiagnostics},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,D,l)}:{}},totalQuestions:0,surface:I.surface,aiOverview:I.aiOverview,aiMode:I.aiMode,whatPeopleSaying:y,tree:[],flat:[],videos:L,forums:f,organicResults:W,localPack:C,entityIds:k,stats:H}}let z=Date.now(),K=await this.runBFS(p,u,n);this.phaseTimings.paaExpansionMs=Date.now()-z,this.throwIfAborted(n);let R=new URLSearchParams({q:u.query,gl:t.gl,hl:t.hl,pws:"0",udm:Lt.udm});r&&R.set("uule",r);let q=[];if(t.includeShortVideos!==!1)try{q=await this.extractShortVideos(p,"https://www.google.com/search?"+R.toString())}catch(H){if(!(H instanceof J))throw H;d++,U.push({code:"short_videos_captcha_skipped",surface:"short_videos",message:H.message,retryable:!0})}this.reporter.onVideos(q),await this.resolveMaterialLinks(p,K,W,I.aiOverview,I.aiMode),this.checkpointMaterial={...this.checkpointMaterial,surface:I.surface,aiOverview:I.aiOverview,aiMode:I.aiMode,videos:[...L,...q],organicResults:W},await this.emitProgress("expansion_finished");let wt=[...L,...q],O=this.buildTree(K,u.query),Z={seed:u.query,totalQuestions:K.length,maxDepthReached:K.reduce((H,E)=>Math.max(H,E.depth),0),durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(Z),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:"paa_found",problem:null,pagination:b,paaLifecycle:{...this.paaLifecycle},completeness:{...this.completeness},links:{...this.linkDiagnostics},...U.length>0?{warnings:U}:{},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,D,l)}:{}},totalQuestions:K.length,surface:I.surface,aiOverview:I.aiOverview,aiMode:I.aiMode,whatPeopleSaying:y,tree:O,flat:K,videos:wt,forums:f,organicResults:W,localPack:C,entityIds:k,stats:Z}}catch(S){throw d++,this.paaLifecycle.discoveryStatus==="in_progress"&&(this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"interrupted",completionReason:"The browser attempt ended before frontier exhaustion could be proven."}),await this.emitProgress("attempt_ending").catch(()=>{}),this.reporter.onError(S instanceof Error?S:new Error(String(S))),S}}};import{promises as _}from"fs";import dt from"path";import ut from"papaparse";var Yt=class{async writeJSON(t,n){await _.mkdir(n,{recursive:!0});let s=`${t.seed.toLowerCase().replace(/\W+/g,"-").slice(0,40)}-${Date.now()}.json`,i=dt.join(n,s);return await _.writeFile(i,JSON.stringify(t,null,2),"utf8"),await Ae({title:`${t.seed} scrape`,content:JSON.stringify(t),source:`mcp-scraper:${i}`}),i}async writeCSV(t,n){await _.mkdir(n,{recursive:!0});let s=(t[0]?.seed_query??"paa").toLowerCase().replace(/\W+/g,"-").slice(0,40),i=ut.unparse(t.map(({sources:S,...h})=>({...h,sources_json:JSON.stringify(S)})),{header:!0}),d=`${s}-${Date.now()}.csv`,U=dt.join(n,d);return await _.writeFile(U,i,"utf8"),U}async writeVideoCSV(t,n,a){await _.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=ut.unparse(t,{header:!0}),d=`${s}-videos-${Date.now()}.csv`,U=dt.join(a,d);return await _.writeFile(U,i,"utf8"),U}async writeForumCSV(t,n,a){await _.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=ut.unparse(t,{header:!0}),d=`${s}-forums-${Date.now()}.csv`,U=dt.join(a,d);return await _.writeFile(U,i,"utf8"),U}async writeAIOverviewCSV(t,n,a,s){await _.mkdir(s,{recursive:!0});let i=a.toLowerCase().replace(/\W+/g,"-").slice(0,40),d=t.map((l,o)=>({seed_query:a,response_text:o===0?n??"":"",citation_text:l.text,citation_href:l.href})),U=ut.unparse(d,{header:!0}),S=`${i}-ai-overview-${Date.now()}.csv`,h=dt.join(s,S);return await _.writeFile(h,U,"utf8"),h}async writeAIModeCSV(t,n,a,s){await _.mkdir(s,{recursive:!0});let i=a.toLowerCase().replace(/\W+/g,"-").slice(0,40),d=t.map((l,o)=>({seed_query:a,response_text:o===0?n??"":"",citation_text:l.text,citation_href:l.href})),U=ut.unparse(d,{header:!0}),S=`${i}-ai-mode-${Date.now()}.csv`,h=dt.join(s,S);return await _.writeFile(h,U,"utf8"),h}async writeWhatPeopleSayingCSV(t,n,a){await _.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=t.map(h=>({seed_query:n,...h})),d=ut.unparse(i,{header:!0}),U=`${s}-what-people-saying-${Date.now()}.csv`,S=dt.join(a,U);return await _.writeFile(S,d,"utf8"),S}};var Kt=class{onQuestion(t){process.stdout.write(JSON.stringify({event:"question",depth:t.depth,question:t.question})+`
21702
+ `).trim();return!I||/not available|try again|can't generate/i.test(I)?null:I}function h(y){if(!y||y.startsWith("javascript:"))return null;try{let T=new URL(y,window.location.href);return!["http:","https:"].includes(T.protocol)||T.username||T.password?null:{href:T.href,rawHref:T.href}}catch{return null}}function l(y){if(!y)return[];let T=new Set,w=[];for(let C of Array.from(y.querySelectorAll("a[href]"))){let M=h(C.getAttribute("href")??"");if(!M||T.has(M.rawHref))continue;T.add(M.rawHref);let m="";try{m=new URL(M.href).hostname.replace(/^www\./,"")}catch{}w.push({text:s(C)||m||M.href,href:M.href,rawHref:M.rawHref})}return w}async function o(y){let T=y.querySelector(t.aio.showMoreButton);if(!T||T.getAttribute("aria-expanded")!=="false")return!1;T.click();let w=t.expandWaitMs??1500;return w>0&&await new Promise(C=>setTimeout(C,w)),!0}let r=U(),u=null,c=[],g=!1,v=!1,P=[];if(r){g=await o(r);let y=r.querySelector(t.aio.controller),T=r.querySelector(t.aio.contentSubtree),w=r.querySelector(t.aio.showMoreButton);v=y?.getAttribute("data-trnct")==="false"||w?.getAttribute("aria-expanded")==="true"||!w,u=S(T??y??r),P=(u??"").split(`
21703
+ `).map(C=>C.trim()).filter(C=>/^\d+\.\s+.+/.test(C)),c=l(r)}let k=document.querySelector(t.aim.root),A=a==="aim"&&!!k,x=k?.closest(t.aim.wrapper)??k,B=A?S(x):null,N=A&&i(B),p=N?B:null,L=N?l(x):[],f=!!r&&i(u);return{surface:a,aiOverview:{detected:f,text:f?u:null,citations:f?c:[],expanded:f?g:!1,fullyExpanded:f?v:!1,sections:f?P:[]},aiMode:{detected:N&&p!==null,text:p,citations:L}}}import{createHash as ga}from"crypto";var rn=8e3,ln=3e3,Sn=1e4,ya=8;function nt(e){return/(^|\.)google\.(?:com|[a-z]{2,3}(?:\.[a-z]{2})?)$/i.test(e)}function pt(e){if(!e||e.length>rn)return null;try{let t=new URL(e);return t.protocol!=="http:"&&t.protocol!=="https:"||t.username||t.password?null:t}catch{return null}}function Ca(e,t){if(!e||e.length>rn||/^javascript:/i.test(e))return null;try{let n=new URL(e,t);return pt(n.href)}catch{return null}}function kt(e){let t=pt(e);return!t||t.protocol!=="https:"||!nt(t.hostname)||t.pathname!=="/goto"?null:t.searchParams.get("url")?t:null}function re(e){if(e.linkType!=="google_goto_redirect"||e.resolutionStatus!=="resolved"||!kt(e.rawUrl)||!e.resolvedUrl)return!1;let t=pt(e.resolvedUrl);return!!(t&&!nt(t.hostname)&&t.href===e.resolvedUrl&&e.url===t.href)}function ot(e){let t=e.normalize("NFKC").toLocaleLowerCase("en-US").replace(/[^\p{L}\p{N}\s]/gu,"").replace(/\s+/g," ").trim();return`paa_${ga("sha256").update(t).digest("hex").slice(0,16)}`}function Vt(e,t){let n=Ca(e,t);if(!n)return null;let a=n.href;if(!nt(n.hostname))return{url:a,rawUrl:a,resolvedUrl:a,linkType:"plain",resolutionStatus:"not_needed"};if(n.pathname==="/url"){let s=pt(n.searchParams.get("q")??n.searchParams.get("url")??"");return!s||nt(s.hostname)?null:{url:s.href,rawUrl:a,resolvedUrl:s.href,linkType:"google_url_redirect",resolutionStatus:"resolved"}}return n.pathname==="/goto"&&n.searchParams.get("url")?{url:a,rawUrl:a,resolvedUrl:null,linkType:"google_goto_redirect",resolutionStatus:"unresolved"}:null}function le(e){return kt(e)?.searchParams.get("url")??null}function Un(e,t){try{let n=new URL(e),a=pt(new URL(t,n).href);return!a||nt(a.hostname)?null:(!a.hash&&n.hash&&(a.hash=n.hash),a.href)}catch{return null}}async function hn(e,t={}){let n=[...new Set([...e].flatMap(o=>kt(o)?[o]:[]))],a=new Map(n.map(o=>[o,{rawUrl:o,resolvedUrl:null,resolutionStatus:"unresolved"}])),s=typeof globalThis.fetch=="function"?globalThis.fetch.bind(globalThis):null,i=t.fetchImpl??s;if(n.length===0||!i)return{resolutions:[...a.values()],nonGoogleRequestsObserved:0};let d=Math.max(1,t.timeoutMs??ln),U=Date.now()+Math.max(1,t.totalBudgetMs??Sn),S=Math.max(1,Math.min(16,Math.floor(t.concurrency??ya))),h=0,l=async()=>{for(;h<n.length;){let o=n[h++],r=kt(o),u=r?.searchParams.get("url");if(!r||!u){a.set(o,{rawUrl:o,resolvedUrl:null,resolutionStatus:"rejected"});continue}r.hash="";let c=r.href;for(let g=0;g<2;g++){let v=U-Date.now();if(v<=0)return;let P=new AbortController,k=setTimeout(()=>P.abort(),Math.min(d,v)),A;try{A=await i(c,{method:"GET",redirect:"manual",headers:{accept:"*/*","user-agent":"Mozilla/5.0"},signal:P.signal})}catch{break}finally{clearTimeout(k)}if(A.status<300||A.status>=400)break;let x=A.headers.get("location");if(!x)break;let B=Un(o,x);if(B){a.set(o,{rawUrl:o,resolvedUrl:B,resolutionStatus:"resolved"});break}let N;try{N=new URL(x,c)}catch{a.set(o,{rawUrl:o,resolvedUrl:null,resolutionStatus:"rejected"});break}if(!nt(N.hostname)||le(N.href)!==u){a.set(o,{rawUrl:o,resolvedUrl:null,resolutionStatus:"rejected"});break}c=N.href}}};return await Promise.all(Array.from({length:Math.min(S,n.length)},()=>l())),{resolutions:[...a.values()],nonGoogleRequestsObserved:0}}function dn(e,t){try{return new URL(e.resolvedUrl??e.url).hostname.replace(/^www\./,"")}catch{return t}}async function un(e,t={}){let n=[],a=o=>{for(let r of o)n.push(r),a(r.children??[])};a(e.tree??[]);let s=[...e.flat.flatMap(o=>o.sources??[]),...n.flatMap(o=>o.sources),...e.organicResults??[],...(e.aiOverview?.citations??[]).map(({text:o,href:r,...u})=>({...u,url:r})),...(e.aiMode?.citations??[]).map(({text:o,href:r,...u})=>({...u,url:r}))],i=new Map(s.filter(o=>!!o?.rawUrl).map(o=>[o.rawUrl,o])),d=[...i.values()].filter(o=>o.linkType==="google_goto_redirect"&&o.resolutionStatus!=="resolved").map(o=>o.rawUrl);if(d.length>0){let o=await hn(d,t);for(let r of o.resolutions){let u=i.get(r.rawUrl);u&&i.set(r.rawUrl,r.resolutionStatus==="resolved"&&r.resolvedUrl?{...u,url:r.resolvedUrl,resolvedUrl:r.resolvedUrl,resolutionStatus:"resolved"}:{...u,resolutionStatus:r.resolutionStatus})}}let U=o=>({...o,...i.get(o.rawUrl)??o}),S=o=>o.map(r=>{let u=U(r);return{...u,site:dn(u,r.site)}});for(let o of e.flat){o.sources=S(o.sources??[]);let r=o.sources[0];o.source_title=r?.title??o.source_title,o.source_site=r?.site??o.source_site,o.source_cite=r?.url??o.source_cite}for(let o of n){o.sources=S(o.sources??[]);let r=o.sources[0];o.sourceTitle=r?.title??o.sourceTitle,o.sourceSite=r?.site??o.sourceSite,o.sourceCite=r?.url??o.sourceCite}for(let o=0;o<(e.organicResults?.length??0);o++){let r=U(e.organicResults[o]);e.organicResults[o]={...r,domain:dn(r,e.organicResults[o].domain)??""}}let h=o=>{let r=U({url:o.href,rawUrl:o.rawUrl,resolvedUrl:o.resolvedUrl,linkType:o.linkType,resolutionStatus:o.resolutionStatus}),{url:u,...c}=r;return{...o,...c,href:u}};e.aiOverview&&(e.aiOverview.citations=(e.aiOverview.citations??[]).map(h)),e.aiMode&&(e.aiMode.citations=(e.aiMode.citations??[]).map(h));let l=[...i.values()];return e.diagnostics.links={linkCandidatesObserved:i.size,plainLinksObserved:l.filter(o=>o.linkType==="plain").length,googleUrlRedirectsObserved:l.filter(o=>o.linkType==="google_url_redirect").length,googleGotoRedirectsObserved:l.filter(o=>o.linkType==="google_goto_redirect").length,redirectsResolved:l.filter(o=>o.linkType!=="plain"&&o.resolutionStatus==="resolved").length,redirectsUnresolved:l.filter(o=>o.resolutionStatus==="unresolved").length,redirectsRejected:l.filter(o=>o.resolutionStatus==="rejected").length,resolverNonGoogleRequestsObserved:0,paaSourcesPreserved:e.flat.reduce((o,r)=>o+r.sources.length,0),aiOverviewLabelValidated:e.aiOverview?.detected??!1},e}async function cn(e,t,n={}){let a=new Map;for(let r of t){let u=a.get(r.rawUrl);u&&re(u)||a.set(r.rawUrl,r.linkType==="google_goto_redirect"&&!re(r)?{...r,url:r.rawUrl,resolvedUrl:null,resolutionStatus:"unresolved"}:r)}let s=[...a.values()].filter(r=>r.linkType==="google_goto_redirect"&&!re(r));if(s.length===0)return a;let i=Date.now()+(n.totalBudgetMs??Sn),d=await hn(s.map(r=>r.rawUrl),n);for(let r of d.resolutions){let u=a.get(r.rawUrl);u&&a.set(r.rawUrl,r.resolutionStatus==="resolved"&&r.resolvedUrl?{...u,url:r.resolvedUrl,resolvedUrl:r.resolvedUrl,resolutionStatus:"resolved"}:{...u,resolutionStatus:r.resolutionStatus})}let U=s.filter(r=>a.get(r.rawUrl)?.resolutionStatus==="unresolved");if(U.length===0||n.browserFallback===!1||Date.now()>=i)return n.onNetworkAudit?.({nonGoogleRequestsObserved:0}),a;let S=n.timeoutMs??ln,h=await e.context().newPage().catch(()=>null);if(!h)return n.onNetworkAudit?.({nonGoogleRequestsObserved:0}),a;let l=null,o=0;try{await h.route("**/*",async r=>{let u=r.request().url();try{nt(new URL(u).hostname)||(o+=1)}catch{}let c=le(u);if(!l||c!==l.token){await r.abort("blockedbyclient").catch(()=>{});return}let g=l;try{let v=await r.fetch({maxRedirects:0,timeout:g.timeoutMs});g.location=v.headers().location??null}finally{await r.abort("blockedbyclient").catch(()=>{}),g.finish()}});for(let r of U){let u=i-Date.now();if(u<=0)break;let c=kt(r.rawUrl),g=c?.searchParams.get("url");if(!c||!g){a.set(r.rawUrl,{...r,resolutionStatus:"rejected"});continue}let v=Math.min(S,u);c.hash="";let P=c.href,k=!1;for(let A=0;A<2;A++){let x,B=new Promise(y=>{x=y}),N=`mcp-goto-${Math.random().toString(36).slice(2)}`;l={token:g,timeoutMs:v,location:null,finish:x},await h.evaluate(({url:y,id:T})=>{let w=document.createElement("iframe");w.id=T,w.hidden=!0,w.src=y,document.body.append(w)},{url:P,id:N}).catch(()=>null),await Promise.race([B,new Promise(y=>setTimeout(y,v))]);let p=l.location;if(l=null,await h.evaluate(y=>document.getElementById(y)?.remove(),N).catch(()=>null),!p)break;let L=Un(r.rawUrl,p);if(L){a.set(r.rawUrl,{...r,url:L,resolvedUrl:L,resolutionStatus:"resolved"});break}let f;try{f=new URL(p,P)}catch{k=!0;break}if(!nt(f.hostname)||le(f.href)!==g){k=!0;break}P=f.href}k&&a.get(r.rawUrl)?.resolutionStatus!=="resolved"&&a.set(r.rawUrl,{...r,resolutionStatus:"rejected"})}}finally{l=null,await h.close().catch(()=>{}),n.onNetworkAudit?.({nonGoogleRequestsObserved:o})}return a}var wn=String.raw`^(?:an error has occurred(?:[.!…]\s*)?(?:please try again later[.!…]?)?|loading|please wait|try again|something went wrong)[.!…\s]*$`,Ma=700,ka=1e3,pa=1400,gn=900,ma=3,yn=250,Et=class{constructor(t,n,a,s){this.driver=t;this.reporter=n;this.onPaaProgress=a;this.onProviderSession=s}driver;reporter;onPaaProgress;onProviderSession;completeness={paaWithoutAnswer:0,paaWithoutSource:0,paaAnswersRecovered:0,aioShareCaptured:null};aioShareUrlEarly=null;linkDiagnostics=this.emptyLinkDiagnostics();collectedRows=[];partialContext=null;progressSequence=0;clickedQuestions=new Set;paaLifecycle=this.emptyPaaLifecycle(0);checkpointMaterial=null;interactionObservations=[];phaseTimings={};currentPhaseTimings(t){return{...this.phaseTimings,totalServerMs:Math.max(0,Date.now()-t)}}emptyPaaLifecycle(t){return{requestedQuestions:t,questionsFound:0,targetStatus:"not_met",discoveryStatus:"in_progress",materialStatus:"partial",completionReason:"PAA expansion is still running.",automaticRetries:0,retryBreakdown:{controlRetries:0,browserRetries:0,providerFallbacks:0,runtimeRecoveries:0,idempotentReplays:0},knownQuestions:0,processedQuestions:0,failedInteractions:0,noGrowthConfirmations:0,visibleControls:0,eligibleControls:0,dispatchedInteractions:0,confirmedInteractions:0,unconfirmedInteractions:0}}emptyLinkDiagnostics(){return{linkCandidatesObserved:0,plainLinksObserved:0,googleUrlRedirectsObserved:0,googleGotoRedirectsObserved:0,redirectsResolved:0,redirectsUnresolved:0,redirectsRejected:0,resolverNonGoogleRequestsObserved:0,paaSourcesPreserved:0,aiOverviewLabelValidated:!1}}mergePaaSources(t=[],n=[]){let a=new Map;for(let s of[...t,...n]){let i=a.get(s.rawUrl);if(!i){a.set(s.rawUrl,s);continue}let d=s.resolutionStatus==="resolved"&&i.resolutionStatus!=="resolved"?s:i;a.set(s.rawUrl,{...d,title:d.title??i.title??s.title,site:d.site??i.site??s.site})}return[...a.values()]}normalizeAICitations(t,n){let a=new Set;return n.flatMap(s=>{let i=Vt(s.rawHref??s.href,t);if(!i||a.has(i.rawUrl))return[];a.add(i.rawUrl);let{url:d,...U}=i;return[{...U,text:s.text,href:d}]})}async resolveMaterialLinks(t,n,a,s,i){let d=Date.now(),U=[...n.flatMap(c=>c.sources??[]),...a,...s.citations.map(({text:c,href:g,...v})=>({...v,url:g})),...i.citations.map(({text:c,href:g,...v})=>({...v,url:g}))],S=new Map(U.map(c=>[c.rawUrl,c])),h=0,l=await cn(t,U,{onNetworkAudit:c=>{h=c.nonGoogleRequestsObserved}}),o=c=>({...c,...l.get(c.rawUrl)??c});for(let c of n){c.sources=(c.sources??[]).map(o);let g=c.sources[0];c.source_title=g?.title??c.source_title,c.source_site=g?.site??c.source_site,c.source_cite=g?.url??c.source_cite}for(let c=0;c<a.length;c++){let g=o(a[c]);if(g.resolvedUrl)try{g.domain=new URL(g.resolvedUrl).hostname.replace(/^www\./,"")}catch{}a[c]=g}let r=c=>{let g=o({url:c.href,rawUrl:c.rawUrl,resolvedUrl:c.resolvedUrl,linkType:c.linkType,resolutionStatus:c.resolutionStatus}),{url:v,...P}=g;return{...P,text:c.text,href:v}};s.citations=s.citations.map(r),i.citations=i.citations.map(r);let u=[...l.values()];this.linkDiagnostics={linkCandidatesObserved:S.size,plainLinksObserved:u.filter(c=>c.linkType==="plain").length,googleUrlRedirectsObserved:u.filter(c=>c.linkType==="google_url_redirect").length,googleGotoRedirectsObserved:u.filter(c=>c.linkType==="google_goto_redirect").length,redirectsResolved:u.filter(c=>c.linkType!=="plain"&&c.resolutionStatus==="resolved").length,redirectsUnresolved:u.filter(c=>c.resolutionStatus==="unresolved").length,redirectsRejected:u.filter(c=>c.resolutionStatus==="rejected").length,resolverNonGoogleRequestsObserved:h,paaSourcesPreserved:n.reduce((c,g)=>c+(g.sources??[]).length,0),aiOverviewLabelValidated:s.detected},this.phaseTimings.linkResolutionMs=(this.phaseTimings.linkResolutionMs??0)+(Date.now()-d)}normalizeQuestion(t){return t.toLowerCase().replace(/[^\w\s]/g,"").replace(/\s+/g," ").trim()}throwIfAborted(t){if(t?.aborted)throw t.reason instanceof DOMException&&t.reason.name==="TimeoutError"?t.reason:new j}async throwIfCaptcha(t,n){if(await t.locator(F.captchaMarker).count().catch(()=>0)>0)throw new J(`${n} returned a CAPTCHA \u2014 retrying with a fresh session.`)}async extractVisibleItems(t,n){let a=F,s=await t.evaluate(({selectors:d,onlyQuestion:U,answerPlaceholderPattern:S})=>{function h(o){if(!o)return"";let r=[];for(let u of o.childNodes)if(u.nodeType===Node.TEXT_NODE){let c=u.textContent?.trim();c&&r.push(c)}else{if(u.tagName==="STYLE"||u.tagName==="SCRIPT")continue;{let c=h(u);c&&r.push(c)}}return r.join(" ").replace(/\s+/g," ").trim()}function l(o){return(o??"").replace(/\s*\(\+\d+\)\s*-\s*View related links.*$/i,"").replace(/\s*-\s*Opens in new tab.*$/i,"").trim()}return Array.from(document.querySelectorAll(d.item)).filter(o=>!U||(o.getAttribute(d.itemDataQ)||o.getAttribute(d.itemDataInitQ)||o.querySelector(d.itemQuestionEl)?.innerText?.trim()||"")===U).map(o=>{let r=o.querySelector(d.clickTarget),u=o.classList.contains(d.expandedClass)||r?.getAttribute("aria-expanded")==="true",c=o.querySelector(d.answerContainer),v=c?.querySelector(d.aiAnswerBody)??c,P=h(v),k=new RegExp(S,"i").test(P),A=[...Array.from((v??o).querySelectorAll("a[href]")),...Array.from(o.querySelectorAll(d.aiCitation)),...Array.from(o.querySelectorAll(d.aiSourceCard))],x=!k&&(u&&P.length>=10||P.length>30&&A.some(L=>/^https?:\/\//.test(L.href))),B=x&&o.querySelector(d.sourceTitle)?.innerText?.trim()||void 0,N=x&&o.querySelector(d.sourceSite)?.innerText?.trim()||void 0,p=[];if(x){let L=new Set;for(let y of A)!/^https?:\/\//.test(y.href)||L.has(y.href)||(L.add(y.href),p.push({title:l(y.getAttribute("aria-label"))||(y.textContent||"").trim(),rawHref:y.href}));let f=p.find(y=>y.title.length>2)??p[0];f&&(B=B||f.title||void 0)}return{googleLinkId:o.getAttribute("data-lk")||o.querySelector("[data-lk]")?.getAttribute("data-lk")||null,googleEvidenceId:o.getAttribute("data-ved")||o.querySelector("[data-ved]")?.getAttribute("data-ved")||null,question:o.getAttribute(d.itemDataQ)||o.getAttribute(d.itemDataInitQ)||o.querySelector(d.itemQuestionEl)?.innerText?.trim()||"",answer:x&&P||void 0,sourceTitle:B,sourceSite:N,sources:p}})},{selectors:a,onlyQuestion:n,answerPlaceholderPattern:wn}),i=typeof t.url=="function"?t.url():"https://www.google.com/";return s.flatMap(d=>{let U=[],S=new Set;for(let r of d.sources){let u=Vt(r.rawHref,i);if(!u||S.has(u.rawUrl))continue;S.add(u.rawUrl);let c=d.sourceSite??null;try{c||=new URL(u.resolvedUrl??u.rawUrl).hostname.replace(/^www\./,"")}catch{}U.push({...u,title:r.title||d.sourceTitle||null,site:c})}let h=U[0],l={questionId:ot(d.question),googleLinkId:d.googleLinkId,googleEvidenceId:d.googleEvidenceId,question:d.question,answer:sn(d.answer,d.question,d.sourceTitle),sourceTitle:h?.title??d.sourceTitle,sourceSite:h?.site??d.sourceSite,sourceCite:h?.url,sources:U},o=ve.safeParse(l);return o.success?[o.data]:(console.warn("[PAAExtractor] item parse failed:",d.question,o.error.issues[0]?.message),[])})}jitteredDelayMs(t,n){return t+Math.floor(Math.random()*(n-t+1))}async clickItem(t,n){try{await t.locator(`${F.item}[data-q="${n}"], ${F.item}[data-initq="${n}"]`).first().click()}catch{}}toFlatRow(t,n,a,s){return{seed_query:s,question_id:t.questionId??ot(t.question),google_link_id:t.googleLinkId??"",google_evidence_id:t.googleEvidenceId??"",question:t.question,answer:t.answer??"",source_title:t.sourceTitle??"",source_site:t.sourceSite??"",source_cite:t.sourceCite??"",sources:t.sources??[],depth:n,parent_question:a??"",extracted_at:new Date().toISOString()}}upsertCollectedRow(t){let n=this.normalizeQuestion(t.question),a=this.collectedRows.findIndex(U=>this.normalizeQuestion(U.question)===n);if(a<0)return this.collectedRows.push({...t}),!0;let s=this.collectedRows[a],i={...s,...t,answer:t.answer||s.answer,source_title:t.source_title||s.source_title,source_site:t.source_site||s.source_site,source_cite:t.source_cite||s.source_cite,sources:this.mergePaaSources(s.sources,t.sources),extracted_at:t.extracted_at||s.extracted_at},d=i.answer!==s.answer||i.source_title!==s.source_title||i.source_site!==s.source_site||i.source_cite!==s.source_cite||JSON.stringify(i.sources)!==JSON.stringify(s.sources);return d&&(this.collectedRows[a]=i),d}async emitProgress(t){if(!this.onPaaProgress||this.collectedRows.length===0&&!this.checkpointMaterial)return;let n={sequence:++this.progressSequence,observedAt:new Date().toISOString(),clickedQuestions:[...this.clickedQuestions],phase:t,records:this.collectedRows.map(a=>({...a})),lifecycle:{...this.paaLifecycle},...this.checkpointMaterial?{material:structuredClone(this.checkpointMaterial)}:{},interactions:this.interactionObservations.map(a=>({...a,confirmationSignals:[...a.confirmationSignals]}))};try{await this.onPaaProgress(n)}catch(a){console.warn(JSON.stringify({event:"paa_progress_sink_failed",sequence:n.sequence,phase:n.phase,message:a instanceof Error?a.message:String(a)}))}}getPartialResult(){let t=this.partialContext;if(!t||this.collectedRows.length===0&&!this.checkpointMaterial)return null;let n=this.collectedRows.map(U=>({...U})),a=this.checkpointMaterial,s=t.questionsOnly?0:n.filter(U=>!U.answer?.trim()).length,i=t.questionsOnly?0:n.filter(U=>(U.sources??[]).length===0).length,d={seed:t.seed,totalQuestions:n.length,maxDepthReached:n.reduce((U,S)=>Math.max(U,S.depth),0),durationMs:Date.now()-t.startMs,errorCount:0};return{seed:t.seed,location:t.location,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(t.startMs),completionStatus:"paa_found",problem:null,...a?.pagination?{pagination:{...a.pagination}}:{},resultQuality:"partial",degradedResult:!1,retryRecommended:!0,paaLifecycle:{...this.paaLifecycle,questionsFound:n.length,targetStatus:n.length>=(t.maxQuestions??0)?"met":"not_met",discoveryStatus:"interrupted",materialStatus:s>0||i>0?"partial":"complete",completionReason:"The browser attempt ended before frontier exhaustion could be proven."},completeness:{...this.completeness,paaWithoutAnswer:s,paaWithoutSource:i,paaRequested:t.maxQuestions,paaReturned:n.length,paaUnique:n.length},warnings:[{code:"paa_partial",surface:"paa",message:`Harvest stopped before finishing; returning the ${n.length} question(s) collected up to that point.`,retryable:!0}]},totalQuestions:n.length,surface:a?.surface??"web",aiOverview:a?.aiOverview??{detected:!1,text:null,citations:[]},aiMode:a?.aiMode??{detected:!1,text:null,citations:[]},whatPeopleSaying:a?.whatPeopleSaying??[],tree:this.buildTree(n,t.seed),flat:n,videos:a?.videos??[],forums:a?.forums??[],organicResults:a?.organicResults??[],localPack:a?.localPack??[],entityIds:a?.entityIds??{entities:[],kgIds:[],cids:[],gcids:[]},stats:d}}async runBFS(t,n,a){await t.waitForTimeout(700);let s=new Set,i=new Set,d=[];this.clickedQuestions=new Set,this.interactionObservations=[],this.phaseTimings={};let U=new Set,S=new Map,h=new Set,l=new Set,o=new Map,r=2,u=3,c=0,g={sel:F.item,dataQ:F.itemDataQ,dataInitQ:F.itemDataInitQ,questionEl:F.itemQuestionEl,answerSel:F.answerContainer,expandedClass:F.expandedClass,clickTarget:F.clickTarget,answerPlaceholderPattern:wn,questionsOnly:n.questionsOnly,sourceSel:"a[href]"},v=()=>t.evaluate(({sel:N,dataQ:p,dataInitQ:L,questionEl:f,expandedClass:y,clickTarget:T,answerSel:w,answerPlaceholderPattern:C,questionsOnly:M})=>{let m=I=>{if(!I)return"";let b=[];for(let W of I.childNodes){if(W.nodeType===Node.TEXT_NODE){let K=W.textContent?.trim();K&&b.push(K);continue}if(W.nodeType!==Node.ELEMENT_NODE)continue;let D=W;if(D.tagName==="STYLE"||D.tagName==="SCRIPT"||D.getAttribute("aria-hidden")==="true")continue;let z=m(D);z&&b.push(z)}return b.join(" ").replace(/\s+/g," ").trim()};return Array.from(document.querySelectorAll(N)).map((I,b)=>{let W=m(I.querySelector(w)).replace(/An AI Overview is not available for this search/gi," ").replace(/Can't generate an AI overview right now\.?\s*Try again later\.?/gi," ").replace(/\bAI Overview\b/gi," ").replace(/\s+/g," ").trim(),D=I.classList.contains(y)||I.querySelector(T)?.getAttribute("aria-expanded")==="true",z=W.length>=10&&!new RegExp(C,"i").test(W);return{q:I.getAttribute(p)||I.getAttribute(L)||I.querySelector(f)?.innerText?.trim()||"",done:D&&(M||z),expanded:D,index:b}}).filter(I=>I.q)},g),P=async(N,p,L,f,y,T)=>{let w=Date.now(),C={id:`${T}:${ot(N)}:${y}`,questionId:ot(N),question:N,batchNumber:T,controlAttempt:y,observedAt:new Date(w).toISOString(),beforeQuestionCount:p,expandedBefore:f},M=L>=0?t.locator(g.sel).nth(L).locator(g.clickTarget):null,m=null,I=M?await(async()=>(f&&(await M.click({timeout:gn,force:!0}),await t.waitForTimeout(120)),await M.click({timeout:gn,force:!0}),!0))().catch(O=>(m=O instanceof Error&&(O.name==="TimeoutError"||/timeout/i.test(O.message))?"click_ack_timeout":"click_failed",!1)):!1,b=Date.now()-w;if(!I&&m!=="click_ack_timeout")return{dispatched:!1,confirmed:!1,observation:{...C,dispatched:!1,outcome:"dispatch_failed",confirmationSignals:[],confirmationCheckpointMs:null,confirmedAtMs:null,dispatchDurationMs:b,totalDurationMs:b,afterQuestionCount:p,newQuestionCount:0,expandedAfter:f,answerObserved:!1,sourceCount:0,errorCode:L<0?"control_missing":m??"click_failed"}};let W={exists:!0,expanded:f,answerReady:!1,sourceCount:0,questionCount:p},D=[],z=null,K=null,G=!1;for(let O of[Ma,ka,pa]){let Z=w+O-Date.now();if(Z>0&&await t.waitForTimeout(Z),W=await t.evaluate(({sel:H,dataQ:E,dataInitQ:R,questionEl:V,expandedClass:$,clickTarget:X,answerSel:Nt,answerPlaceholderPattern:rt,sourceSel:ft,target:gt})=>{let Tt=St=>{if(!St)return"";let jt=[];for(let bt of St.childNodes){if(bt.nodeType===Node.TEXT_NODE){let pe=bt.textContent?.trim();pe&&jt.push(pe);continue}if(bt.nodeType!==Node.ELEMENT_NODE)continue;let Wt=bt;if(Wt.tagName==="STYLE"||Wt.tagName==="SCRIPT"||Wt.getAttribute("aria-hidden")==="true")continue;let ke=Tt(Wt);ke&&jt.push(ke)}return jt.join(" ").replace(/\s+/g," ").trim()},lt=Array.from(document.querySelectorAll(H)),Pt=lt.find(St=>(St.getAttribute(E)||St.getAttribute(R)||St.querySelector(V)?.innerText?.trim())===gt);if(!Pt)return{exists:!1,expanded:!1,answerReady:!1,sourceCount:0,questionCount:lt.length};let Bn=Pt.classList.contains($)||Pt.querySelector(X)?.getAttribute("aria-expanded")==="true",ye=Pt.querySelector(Nt),Ce=Tt(ye).replace(/An AI Overview is not available for this search/gi," ").replace(/Can't generate an AI overview right now\.?\s*Try again later\.?/gi," ").replace(/\bAI Overview\b/gi," ").replace(/\s+/g," ").trim(),Me=Ce.length>=10&&!new RegExp(rt,"i").test(Ce);return{exists:!0,expanded:Bn,answerReady:Me,sourceCount:Me?ye?.querySelectorAll(ft).length??0:0,questionCount:lt.length}},{...g,target:N}).catch(()=>W),D=[...W.expanded?["expanded"]:[],...W.answerReady?["answer"]:[],...W.sourceCount>0?["source"]:[],...W.questionCount>p?["question_growth"]:[]],W.answerReady||W.sourceCount>0||W.questionCount>p){G=!0,z=O,K=Date.now()-w;break}}let q=Date.now()-w,wt={...C,dispatched:I,outcome:G?"confirmed":I?"unconfirmed":"dispatch_failed",confirmationSignals:D,confirmationCheckpointMs:z,confirmedAtMs:K,dispatchDurationMs:b,totalDurationMs:q,afterQuestionCount:W.questionCount,newQuestionCount:Math.max(0,W.questionCount-p),expandedAfter:W.expanded,answerObserved:W.answerReady,sourceCount:W.sourceCount,errorCode:I?G?null:W.exists?"confirmation_timeout":"control_missing":m};return{dispatched:I,confirmed:G,observation:wt}},k=0;t:for(;;){if(n.softDeadlineMs&&Date.now()>=n.softDeadlineMs)throw this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"interrupted",completionReason:"The execution deadline arrived before frontier exhaustion could be proven."},new Ct(this.paaLifecycle.completionReason);this.throwIfAborted(a);let N=await v(),p=!1;for(let w of N)i.has(w.q)||(i.add(w.q),d.push(w.q),d.length<=n.maxQuestions&&(p=this.upsertCollectedRow(this.toFlatRow({questionId:ot(w.q),googleLinkId:null,googleEvidenceId:null,question:w.q,sources:[]},1,null,n.query))||p)),w.done&&h.add(w.q);if(this.paaLifecycle={...this.paaLifecycle,questionsFound:Math.min(d.length,n.maxQuestions),targetStatus:d.length>=n.maxQuestions?"met":"not_met",knownQuestions:d.length,processedQuestions:h.size,failedInteractions:l.size,visibleControls:N.length},p&&await this.emitProgress("discovered"),n.questionsOnly&&i.size>=n.maxQuestions){this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"target_reached",targetStatus:"met",completionReason:"The requested unique-question count was observed."};break}if(!n.questionsOnly&&i.size>=n.maxQuestions){let w=!1,C=new Set(d.slice(0,n.maxQuestions));for(let M of await this.extractVisibleItems(t)){if(!C.has(M.question))continue;let m=o.get(M.question),I={...M,answer:M.answer??m?.answer,sourceTitle:M.sourceTitle??m?.sourceTitle,sourceSite:M.sourceSite??m?.sourceSite,sourceCite:M.sourceCite??m?.sourceCite,sources:this.mergePaaSources(m?.sources,M.sources)};o.set(M.question,I),w=this.upsertCollectedRow(this.toFlatRow(I,1,null,n.query))||w}if(w&&await this.emitProgress("answer_captured"),[...C].every(M=>{let m=o.get(M);return!!(m?.answer?.trim()&&m.sources.length>0)})){l.clear(),this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"target_reached",targetStatus:"met",failedInteractions:0,completionReason:"The requested unique-question count and its answer/source material were observed."};break}}let L=new Set(d.slice(0,n.maxQuestions)),f=N.filter(w=>L.has(w.q)&&!w.done&&(S.get(w.q)??0)<r&&!U.has(w.q)),y=f.slice(-ma);if(this.paaLifecycle={...this.paaLifecycle,eligibleControls:f.length},y.length===0){if(i.size>=n.maxQuestions){this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"target_reached",targetStatus:"met",completionReason:"The requested unique-question count was observed."};break}let w=new Set(N.map(M=>M.q)),C=d.slice(0,n.maxQuestions).filter(M=>!h.has(M)&&(l.has(M)||!w.has(M)));if(C.length>0)throw this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"interrupted",failedInteractions:new Set([...l,...C]).size,completionReason:"At least one known PAA control failed or disappeared before it could be confirmed."},await this.emitProgress("expansion_finished"),new Ct(this.paaLifecycle.completionReason);for(let M=1;M<=u;M++){this.throwIfAborted(a),await this.throwIfCaptcha(t,"Google PAA exhaustion confirmation"),await t.mouse.wheel(0,320);let m=await t.waitForFunction(({sel:b,min:W})=>document.querySelectorAll(b).length>W,{sel:F.item,min:N.length},{timeout:1500,polling:100}).catch(()=>null);if(this.paaLifecycle={...this.paaLifecycle,noGrowthConfirmations:M},m||(await v()).some(b=>!i.has(b.q)))continue t}this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"frontier_exhausted",targetStatus:"not_met",failedInteractions:0,noGrowthConfirmations:u,completionReason:"Every known eligible PAA control was processed and three healthy no-growth confirmations found no additional questions."};break}await this.throwIfCaptcha(t,"Google PAA expansion"),c+=1;for(let w of y){if(this.reporter.onDepth(++k),(S.get(w.q)??0)>0){let C=this.paaLifecycle.retryBreakdown.controlRetries+1;this.paaLifecycle={...this.paaLifecycle,automaticRetries:C+this.paaLifecycle.retryBreakdown.browserRetries+this.paaLifecycle.retryBreakdown.runtimeRecoveries,retryBreakdown:{...this.paaLifecycle.retryBreakdown,controlRetries:C}}}S.set(w.q,(S.get(w.q)??0)+1)}let T=await Promise.all(y.map(async w=>({target:w,result:await P(w.q,N.length,w.index,w.expanded,S.get(w.q)??1,c)})));for(let{target:w,result:C}of T)(C.dispatched||C.confirmed)&&this.clickedQuestions.add(w.q),this.interactionObservations.push(C.observation);if(this.interactionObservations.length>yn&&this.interactionObservations.splice(0,this.interactionObservations.length-yn),!n.questionsOnly){let w=new Set(y.map(C=>C.q));for(let C of await this.extractVisibleItems(t))w.has(C.question)&&(o.set(C.question,C),this.upsertCollectedRow(this.toFlatRow(C,1,null,n.query))&&await this.emitProgress("answer_captured"))}for(let{target:w,result:C}of T){let M=o.get(w.q);C.confirmed||M?.answer?.trim()?(h.add(w.q),l.delete(w.q)):(S.get(w.q)??0)>=r&&(l.add(w.q),U.add(w.q))}this.paaLifecycle={...this.paaLifecycle,processedQuestions:h.size,failedInteractions:l.size,noGrowthConfirmations:0,dispatchedInteractions:this.interactionObservations.filter(w=>w.dispatched).length,confirmedInteractions:this.interactionObservations.filter(w=>w.outcome==="confirmed").length,unconfirmedInteractions:this.interactionObservations.filter(w=>w.outcome!=="confirmed").length},await this.emitProgress("click_observed")}let A=n.questionsOnly?new Map:new Map(o);n.questionsOnly||await this.fillIncompleteItems(t,d,A,n,U);let x=[];for(let N of d){if(x.length>=n.maxQuestions)break;let p=this.normalizeQuestion(N);if(s.has(p))continue;s.add(p);let L=A.get(N);if(L){let f=this.toFlatRow(L,1,null,n.query);this.upsertCollectedRow(f),x.push(f),this.reporter.onQuestion({questionId:L.questionId,googleLinkId:L.googleLinkId,googleEvidenceId:L.googleEvidenceId,question:L.question,answer:L.answer??null,sourceTitle:L.sourceTitle??null,sourceSite:L.sourceSite??null,sourceCite:L.sourceCite??null,sources:L.sources,depth:1,parentQuestion:null,children:[]})}else{let f=this.toFlatRow({questionId:ot(N),googleLinkId:null,googleEvidenceId:null,question:N,answer:void 0,sourceTitle:void 0,sourceSite:void 0,sourceCite:void 0,sources:[]},1,null,n.query);this.upsertCollectedRow(f),x.push(f)}}this.completeness.paaWithoutAnswer=n.questionsOnly?0:x.filter(N=>!N.answer).length,this.completeness.paaWithoutSource=n.questionsOnly?0:x.filter(N=>(N.sources??[]).length===0).length,this.completeness.paaRequested=n.maxQuestions,this.completeness.paaReturned=x.length,this.completeness.paaUnique=s.size;let B=!n.questionsOnly&&(this.completeness.paaWithoutAnswer>0||this.completeness.paaWithoutSource>0);return this.paaLifecycle={...this.paaLifecycle,questionsFound:x.length,targetStatus:x.length>=n.maxQuestions?"met":"not_met",materialStatus:B?"partial":"complete",processedQuestions:h.size,failedInteractions:l.size},await this.emitProgress("fill_incomplete"),await this.emitProgress("expansion_finished"),x}async fillIncompleteItems(t,n,a,s,i){let d=new Set(n.slice(0,s.maxQuestions)),U=l=>!l?.answer||(l.sources??[]).length===0,S=new Set([...d].filter(l=>U(a.get(l)))),h=new Set([...S].filter(l=>!a.get(l)?.answer));if(S.size!==0){for(let l of S){if(s.softDeadlineMs&&Date.now()>=s.softDeadlineMs)break;let o=(await this.extractVisibleItems(t,l))[0];if(!o)continue;let r=a.get(l);a.set(l,{...o,answer:o.answer??r?.answer,sourceTitle:o.sourceTitle??r?.sourceTitle,sourceSite:o.sourceSite??r?.sourceSite,sourceCite:o.sourceCite??r?.sourceCite,sources:this.mergePaaSources(r?.sources,o.sources)});let u=a.get(l);u&&this.upsertCollectedRow(this.toFlatRow(u,1,null,s.query))&&await this.emitProgress("fill_incomplete")}this.completeness.paaAnswersRecovered=[...h].filter(l=>a.get(l)?.answer).length}}async reExpandCollapsedItems(t){let n=`${F.item}:not(.${F.expandedClass}) ${F.clickTarget}`,a=await t.locator(n).count().catch(()=>0);if(a===0)return!1;for(let s=0;s<a;s++)try{let i=t.locator(n).first();await i.scrollIntoViewIfNeeded(),await i.click({force:!0}),await t.waitForTimeout(this.jitteredDelayMs(300,500))}catch{}return!0}async extractVideos(t){let n=Le;return t.evaluate(a=>{let s=[],i=Array.from(document.querySelectorAll(a.container));for(let d of i){let h=(d.querySelector(a.sectionHeading)?.textContent?.trim()??"").toLowerCase().includes("short")?"short_video":"video",l=Array.from(d.querySelectorAll(a.item));for(let o of l){let r=o.href;if(!r||!r.includes("youtube")&&!r.includes("youtu.be"))continue;let u=o.textContent?.trim()??"",c=u.indexOf("YouTube");if(c===-1)continue;let g=u.slice(0,c).trim(),P=u.slice(c+7).replace(/^[·\s·]+/,"").match(/^([^·\n]+)/),k=P?P[1].trim():"";g&&s.push({type:h,title:g,channel:k,platform:"YouTube",duration:"",url:r})}}return s},n)}async extractForums(t){let n=xe;return t.evaluate(a=>{let s=[],d=Array.from(document.querySelectorAll(a.section)).find(S=>S.textContent?.includes("Discussions"));if(!d)return s;let U=Array.from(d.querySelectorAll(a.item));for(let S of U){let h=S.href;if(!h)continue;let l=S.querySelector(a.title),o=S.querySelector(a.source),r=l?.textContent?.trim()??"",u=o?.textContent?.trim()??"";r&&s.push({title:r,source:u,url:h})}return s},n)}async extractShortVideos(t,n){try{await t.goto(n,{waitUntil:"domcontentloaded"}),await t.waitForTimeout(1500)}catch{return[]}await this.throwIfCaptcha(t,"Google short video search");let a={item:Lt.item,platforms:[...Lt.platforms]};return(await t.evaluate(i=>{let d=new Set,U=[],S=Array.from(document.querySelectorAll(i.item)),h=["youtube.com","youtu.be","tiktok.com","instagram.com","facebook.com","fb.watch"],l=new Map;for(let o of S){let r=o.href;if(!r||!h.some(c=>r.includes(c)))continue;let u=o.textContent?.trim()??"";l.has(r)||l.set(r,[]),l.get(r).push(u)}for(let[o,r]of l.entries()){if(d.has(o))continue;d.add(o);let u=r.find(k=>/^\d+:\d+$/.test(k))??"",c=r.find(k=>!/^\d+:\d+$/.test(k)&&k.length>5)??"";if(!c)continue;let g=c,v="",P="";for(let k of i.platforms){let A=-1,x=0;for(;;){let f=c.indexOf(k,x);if(f===-1)break;A=f,x=f+1}if(A===-1)continue;let B=c.slice(A+k.length);if(!(/^[\s·]/.test(B)||B.trim()===""))continue;g=c.slice(0,A).trim(),v=k;let p=B.replace(/^[\s·]+/,""),L=p.indexOf("\xB7");P=(L===-1?p:p.slice(0,L)).trim();break}g&&U.push({title:g,channel:P,platform:v,duration:u,url:o})}return U},a)).map(i=>({type:"short_video",...i}))}async extractWhatPeopleSaying(t){let n=Oe;return t.evaluate(a=>{let s=Array.from(document.querySelectorAll(a.sectionTag)).find(i=>i.textContent?.includes(a.sectionHeadingText))??document.querySelector(".yG4QQe.TBC9ub.NbhJ1c");return s?Array.from(s.querySelectorAll(a.card)).map(i=>{let U=i.querySelector(a.cardLink)?.href??"",S=i.querySelector(a.titleH1)?.textContent?.trim(),h=i.querySelector(a.titleDiv)?.textContent?.trim(),l=S??h??"",o=i.querySelector(a.source)?.textContent?.trim()??"",u=i.querySelector(a.platformBadge)?.textContent?.trim()??"",c=i.querySelector(a.ytChannel)?.textContent?.trim()??"",g=i.querySelector(a.ytDate)?.textContent?.trim()??"",v=i.querySelector(a.authorNote)?.textContent?.trim()??null,P=i.querySelector(a.popularCommentLabel),k=null;if(P){let m=P.nextSibling;for(;m;){let I=m.textContent?.trim();if(I){k=I;break}m=m.nextSibling}}let A=Array.from(i.querySelectorAll("span")),x=A.find(m=>/^\d+:\d+$/.test(m.textContent?.trim()??""))?.textContent?.trim()??null,N=A.map(m=>m.textContent?.trim()??"").filter(m=>/\d/.test(m)&&(m.includes("comment")||m.includes("reaction")||m.includes("view")||m.includes("like")||m.includes("share")))[0]??"",p=A.map(m=>m.textContent?.trim()??"").filter(m=>/\d+ (day|week|month|year|hour)s? ago|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/.test(m)),L=g||(p[0]??""),f=u||(c?"YouTube":""),y=c||o,T="unknown",w=f.toLowerCase(),C=y.toLowerCase(),M=o.toLowerCase();return w.includes("reddit")||C.startsWith("r/")?T="reddit":w.includes("facebook")||M.includes("facebook")?T="facebook":w.includes("instagram")||M.includes("instagram")?T="instagram":w.includes("tiktok")||M.includes("tiktok")?T="tiktok":w.includes("youtube")||c?T="youtube":T="news",{type:T,title:l,url:U,source:y,platform:f,popularComment:k,engagement:N,date:L,duration:x,authorNote:v}}):[]},n)}async extractOrganicResults(t){let n=Fe,a=await t.evaluate(i=>{let d=[],U=0;return document.querySelectorAll(i.result).forEach(S=>{let h=S.querySelector(i.title);if(!h)return;let l=h.textContent?.trim()??"",r=h.closest("a")?.href??"";if(!l||!r)return;U++;let u=S.querySelector(i.cite)?.textContent?.trim()??null,c=S.querySelector(i.snippet)?.textContent?.trim()??null,g=!!S.querySelector(i.redditCite),v=S.querySelector(i.ratingWrap),P=v?{value:v.querySelector(i.ratingValue)?.textContent?.trim()??"",count:v.querySelector(i.reviewCount)?.textContent?.trim()??""}:null,k="";try{k=new URL(r).hostname.replace(/^www\./,"")}catch{k=S.querySelector(i.siteName)?.textContent?.trim()??""}d.push({position:U,title:l,url:r,domain:k,cite:u,snippet:c,isRedditStyle:g,inlineRating:P})}),d},n),s=typeof t.url=="function"?t.url():"https://www.google.com/";return a.flatMap(i=>{let d=Vt(i.url,s);if(!d)return[];let U=i.domain;try{U=new URL(d.resolvedUrl??d.rawUrl).hostname.replace(/^www\./,"")}catch{}return[{...i,...d,domain:U}]})}async extractLocalPack(t){let n=Re;return t.evaluate(a=>{let s=[],i=null;return document.querySelectorAll('[role="heading"]').forEach(d=>{!i&&d.textContent?.includes(a.headingText)&&(i=d.closest("[data-hveid]"))}),i&&i.querySelectorAll(a.card).forEach((d,U)=>{let S=d.querySelector(a.name)?.textContent?.trim()??"";if(!S)return;let h=d.querySelector(a.ratingValue)?.textContent?.trim()??null,l=d.querySelector(a.reviewCount)?.textContent?.trim()??null,o=l?l.replace(/[()]/g,"").trim():null,r=d.querySelector("a[data-cid]")?.getAttribute("data-cid")??null;if(!r)for(let P of Array.from(d.querySelectorAll("a[href]"))){let k=P.href.match(/[?&]cid=(\d+)/);if(k){r=k[1];break}let A=P.href.match(/!1s0x[0-9a-f]+:0x([0-9a-f]+)/i);if(A){try{r=BigInt("0x"+A[1]).toString()}catch{}if(r)break}}let u=[];d.querySelectorAll("div, span").forEach(P=>{let k=Array.from(P.childNodes).filter(A=>A.nodeType===3).map(A=>A.textContent?.trim()??"").filter(A=>A.length>1&&A.length<120).join(" ");k&&!u.includes(k)&&u.push(k)});let c=Array.from(d.querySelectorAll("a[href]")),g=c.find(P=>P.href.includes("google.com/maps"))?.href??null,v=c.find(P=>!P.href.includes("google.com")&&P.href.startsWith("http"))?.href??null;s.push({position:U+1,name:S,cid:r,rating:h,reviewCount:o,metadata:u,websiteUrl:v,directionsUrl:g})}),s},n)}async extractEntityIds(t){return t.evaluate(()=>{let n=new Set,a=new Set,s=new Set,i=new Map;function d(S){let h=[".OSrXXb",".dbg0pd",".tzt0oe",'[role="heading"]',"h3"];for(let l of h){let o=S.querySelector(l);if(o?.textContent?.trim())return o.textContent.trim()}return""}document.querySelectorAll('[id^="pv-/g/"]').forEach(S=>{let h=S.getAttribute("id");if(!h)return;let l=h.replace("pv-","");n.add(l);let o=d(S),u=S.querySelector("a[data-cid]")?.getAttribute("data-cid")??null;u&&a.add(u),o&&i.set(l,{name:o,kgId:l,cid:u,gcid:null})}),document.querySelectorAll("[data-mid]").forEach(S=>{let h=S.getAttribute("data-mid");if(h?.startsWith("/g/")&&(n.add(h),!i.has(h))){let l=d(S);l&&i.set(h,{name:l,kgId:h,cid:null,gcid:null})}}),document.querySelectorAll(".w7Dbne").forEach(S=>{let l=S.querySelector("a[data-cid]")?.getAttribute("data-cid")??null;if(!l)return;a.add(l);let o=S.querySelector(".OSrXXb")?.textContent?.trim()??"";if(!o)return;let r=S.querySelector('[id^="pv-/g/"]'),u=r?r.getAttribute("id").replace("pv-",""):null,c=u??`cid:${l}`;if(i.has(c)){let g=i.get(c);g.cid||i.set(c,{...g,cid:l})}else i.set(c,{name:o,kgId:u,cid:l,gcid:null})}),document.querySelectorAll("a[data-cid]").forEach(S=>{let h=S.getAttribute("data-cid");if(!h)return;if(a.add(h),![...i.values()].some(o=>o.cid===h)){let o=S.parentElement,r="";for(let u=0;u<8&&o;u++){let c=o.querySelector('.OSrXXb, .dbg0pd, [role="heading"], h3');if(c?.textContent?.trim()){r=c.textContent.trim();break}o=o.parentElement}r&&i.set(`cid:${h}`,{name:r,kgId:null,cid:h,gcid:null})}});let U=Array.from(document.querySelectorAll("script:not([src])")).map(S=>S.textContent??"").filter(S=>S.length>1e4).join(`
21704
+ `);for(let S of U.matchAll(/\/g\/[a-zA-Z0-9_-]{5,20}/g))n.add(S[0]);for(let S of U.matchAll(/gcid:[a-zA-Z0-9_]+/g))s.add(S[0]);for(let S of U.matchAll(/0x[0-9a-f]+:0x([0-9a-f]+)/gi))try{a.add(BigInt("0x"+S[1]).toString())}catch{}return{entities:[...i.values()],kgIds:[...n],cids:[...a],gcids:[...s]}})}mergeLocalPackIntoEntities(t,n){let a=new Set(t.cids),s=t.entities.map(i=>({...i}));for(let i of n){if(!i.cid)continue;a.add(i.cid);let d=i.name.toLowerCase().trim(),U=s.find(S=>S.name.toLowerCase().trim()===d);U?U.cid||(U.cid=i.cid):s.find(S=>S.cid===i.cid)||s.push({name:i.name,kgId:null,cid:i.cid,gcid:null})}return{...t,entities:s,cids:[...a]}}async extractAISurfaces(t,n){let a=await t.evaluate(on,{aio:Be,aim:He,expandWaitMs:1500}),s=typeof t.url=="function"?t.url():"https://www.google.com/",i={surface:a.surface,aiOverview:{...a.aiOverview,citations:this.normalizeAICitations(s,a.aiOverview.citations)},aiMode:{...a.aiMode,citations:this.normalizeAICitations(s,a.aiMode.citations)}};if(!i.aiOverview.detected)return this.completeness.aioShareCaptured=null,i;let d=this.aioShareUrlEarly??await this.captureAIOverviewShareUrl(t,n).catch(()=>null);return this.completeness.aioShareCaptured=d!==null,{...i,aiOverview:{...i.aiOverview,shareUrl:d}}}async captureAIOverviewShareUrl(t,n){if(n?.softDeadlineMs&&Date.now()>=n.softDeadlineMs||!await t.evaluate(()=>{let i=Array.from(document.querySelectorAll('h1,h2,h3,[role="heading"],div')).filter(d=>(d.textContent||"").trim()==="AI Overview");for(let d of i){let U=d;for(let S=0;S<8&&U;S++){let h=U.querySelector('[aria-label="Share"]');if(h)return h.scrollIntoView({block:"center"}),h.click(),!0;U=U.parentElement}}return!1}).catch(()=>!1))return null;let s=null;try{s=await(await t.waitForFunction(()=>{let d=document.createTreeWalker(document.body,NodeFilter.SHOW_TEXT);for(;d.nextNode();){let U=(d.currentNode.textContent||"").match(/https:\/\/share\.google\/aimode\/\S+/);if(U)return U[0]}return!1},void 0,{timeout:4500,polling:250})).jsonValue()}catch{s=null}return await t.keyboard.press("Escape").catch(()=>{}),s}buildTree(t,n){let a=[],s=new Map;for(let i of t){let d={questionId:i.question_id,googleLinkId:i.google_link_id||null,googleEvidenceId:i.google_evidence_id||null,question:i.question,answer:i.answer||null,sourceTitle:i.source_title||null,sourceSite:i.source_site||null,sourceCite:i.source_cite||null,sources:i.sources??[],depth:i.depth,parentQuestion:i.parent_question||null,children:[]};s.set(i.question,d)}for(let i of s.values())i.parentQuestion&&s.has(i.parentQuestion)?s.get(i.parentQuestion).children.push(i):a.push(i);return a}getBrowserDebugSnapshot(){return this.driver.getDebugSnapshot()}buildHarvestDebugSnapshot(t,n,a,s,i){if(t.debug)return{enabled:!0,request:{query:t.query,locationInput:t.location??null,canonicalLocation:n,locationResolved:i?i.matched:null,locationMatchSource:i?i.source:null,locationAmbiguousCandidates:i?i.ambiguousCandidates:null,uule:a,gl:t.gl,hl:t.hl,device:t.device,proxyMode:t.proxyMode,proxyZip:t.proxyZip??null,serpIdentity:t.serpIdentity??null,serpOnly:t.serpOnly,pages:t.pages??1},browser:this.getBrowserDebugSnapshot(),...s?{locationEvidence:s}:{}}}async captureSecondOrganicPage(t,n,a){if(this.throwIfAborted(a),!this.driver.withTemporaryPage)return{organic:[],status:"failed",failureCode:"unsupported_driver"};let s;try{let i=new URL(t.url()),d=h=>{try{let l=new URL(h,i);return i.origin==="https://www.google.com"&&l.origin===i.origin&&!l.username&&!l.password&&l.pathname==="/search"&&l.searchParams.getAll("q").length===1&&l.searchParams.get("q")===n.query&&l.searchParams.getAll("start").length===1&&l.searchParams.get("start")==="10"&&(!l.searchParams.has("num")||l.searchParams.get("num")==="10")&&["gl","hl"].every(o=>!l.searchParams.has(o)||l.searchParams.getAll(o).length===1&&l.searchParams.get(o)===n[o])&&["uule","tbs","udm","tbm","pws"].every(o=>l.searchParams.getAll(o).length<=1&&l.searchParams.get(o)===i.searchParams.get(o))}catch{return!1}},U=await t.evaluate(()=>document.querySelector('a#pnnext, a[rel="next"]')?.getAttribute("href")??null);if(!U)return{organic:[],status:"unavailable",failureCode:"missing_next"};if(!d(U))return{organic:[],status:"unavailable",failureCode:"invalid_next"};let S=await this.driver.withTemporaryPage(async h=>{if(await h.route("**/*",async l=>{let o=l.request();o.isNavigationRequest()&&o.frame()===h.mainFrame()&&!d(o.url())?(s=/^https:\/\/www\.google\.com\/sorry(?:\/|\?)/.test(o.url())?"captcha":"invalid_next",await l.abort("blockedbyclient")):await l.fallback()}),await h.goto(new URL(U,i).href,{waitUntil:"domcontentloaded",timeout:2e4}),this.throwIfAborted(a),await this.throwIfCaptcha(h,"Google SERP page 2"),!d(h.url()))throw s="invalid_next",new Error("Invalid pagination landing");return this.extractOrganicResults(h)},a);return this.throwIfAborted(a),S.length>0?{organic:S.map(h=>({...h,position:h.position+10})),status:"captured"}:{organic:[],status:"unavailable",failureCode:"empty_page"}}catch(i){if(this.throwIfAborted(a),i instanceof j)throw i;return{organic:[],status:"failed",failureCode:s??(i instanceof J?"captcha":i instanceof Error&&(i.name==="TimeoutError"||/timed? ?out/i.test(i.message))?"timeout":"navigation_error")}}}async extract(t,n){let a=Date.now();this.completeness={paaWithoutAnswer:0,paaWithoutSource:0,paaAnswersRecovered:0,aioShareCaptured:null},this.linkDiagnostics=this.emptyLinkDiagnostics(),this.aioShareUrlEarly=null,this.collectedRows=[],this.progressSequence=0,this.checkpointMaterial=null,this.clickedQuestions=new Set,this.paaLifecycle=this.emptyPaaLifecycle(t.maxQuestions),this.partialContext={seed:t.query,location:t.location??null,startMs:a,maxQuestions:t.maxQuestions,questionsOnly:t.questionsOnly};let s=t.device==="mobile",i={headless:t.headless,profileDir:t.profileDir,proxy:t.proxy,\u006b\u0065\u0072\u006e\u0065\u006cApiKey:t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey,\u006b\u0065\u0072\u006e\u0065\u006cProxyId:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,\u006b\u0065\u0072\u006e\u0065\u006cProfileName:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName,\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges,\u006b\u0065\u0072\u006e\u0065\u006cStealth:t.\u006b\u0065\u0072\u006e\u0065\u006cStealth,\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution,proxyMode:t.proxyMode,keepDefaultProxy:t.keepDefaultProxy,requireUsEgress:t.requireUsEgress,viewport:s?{width:390,height:844}:{width:1280,height:800},locale:`${t.hl}-${t.gl.toUpperCase()}`,deviceScaleFactor:s?3:1,isMobile:s,hasTouch:s,debug:t.debug,operationDeadlineMs:t.softDeadlineMs},d=0,U=[];try{this.throwIfAborted(n);let S=Date.now();await this.driver.launch(i),this.phaseTimings.providerConnectMs=Date.now()-S;let h=this.driver.getProviderSessionMetadata();if(h?.providerSessionId&&this.onProviderSession)try{await this.onProviderSession(h)}catch(H){console.warn(JSON.stringify({event:"paa_provider_session_sink_failed",provider:h.provider,message:H instanceof Error?H.message:String(H)}))}this.throwIfAborted(n);let l=t.location?oe(t.location):null,o=t.location?l?.canonical??t.location:null,r=o?Xe(o):null,u=t,c=t.includeAllSerpFeatures,g=c||t.includeLocalPack,v=c||t.includeForums,P=c||t.includeVideos,k=c||t.includeAiOverview,A=c||t.includeWhatPeopleSaying,x={surface:"web",aiOverview:{detected:!1,text:null,citations:[]},aiMode:{detected:!1,text:null,citations:[]}},B=Date.now(),{hasPaa:N}=await this.driver.navigateToSERP(u.query,r,t.gl,t.hl,{...yt(t.recency)?{tbs:yt(t.recency)}:{},debug:t.debug,purpose:t.serpOnly?"serp":"paa",...t.softDeadlineMs?{deadlineMs:t.softDeadlineMs}:{}});this.phaseTimings.navigationMs=Date.now()-B,this.throwIfAborted(n);let p=this.driver.getPage();if(await this.throwIfCaptcha(p,"Google SERP"),N||(this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"no_paa_observed",materialStatus:"complete",completionReason:"A readable Google SERP was observed without a People Also Ask block."}),t.questionsOnly){let H=Date.now(),E=N?await this.runBFS(p,u,n):[];this.phaseTimings.paaExpansionMs=Date.now()-H,await this.resolveMaterialLinks(p,E,[],x.aiOverview,x.aiMode);let R={seed:u.query,totalQuestions:E.length,maxDepthReached:E.reduce((V,$)=>Math.max(V,$.depth),0),durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(R),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:N?"paa_found":"no_paa",...N?{}:{noPaaObserved:!0},problem:null,paaLifecycle:{...this.paaLifecycle},completeness:{...this.completeness},links:{...this.linkDiagnostics},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,void 0,l)}:{}},totalQuestions:E.length,surface:"web",aiOverview:{detected:!1,text:null,citations:[]},aiMode:{detected:!1,text:null,citations:[]},whatPeopleSaying:[],tree:this.buildTree(E,u.query),flat:E,videos:[],forums:[],organicResults:[],localPack:[],entityIds:{entities:[],kgIds:[],cids:[],gcids:[]},stats:R}}if(k&&(this.aioShareUrlEarly=await this.captureAIOverviewShareUrl(p,t).catch(()=>null)),t.serpOnly){let H=Date.now(),[E,R,V]=await Promise.all([this.extractOrganicResults(p),g?this.extractLocalPack(p):Promise.resolve([]),this.extractEntityIds(p)]),$=this.mergeLocalPackIntoEntities(V,R),X=k?await this.extractAISurfaces(p,t):x;this.phaseTimings.serpParseMs=Date.now()-H;let Nt=t.debug?Mt(o,E,R):void 0,rt=E;if((t.pages??1)>=2){let gt=new URLSearchParams({q:u.query,gl:t.gl,hl:t.hl,pws:"0",start:"10"});yt(t.recency)&&gt.set("tbs",yt(t.recency)),r&&gt.set("uule",r),await this.driver.navigateTo("https://www.google.com/search?"+gt.toString()),await this.throwIfCaptcha(p,"Google SERP page 2");let Tt=await this.extractOrganicResults(p);rt=[...E,...Tt.map(lt=>({...lt,position:lt.position+10}))],t.debug&&(Nt=Mt(o,rt,R))}await this.resolveMaterialLinks(p,[],rt,X.aiOverview,X.aiMode);let ft={seed:u.query,totalQuestions:0,maxDepthReached:0,durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(ft),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:"serp_only",problem:null,completeness:{...this.completeness},links:{...this.linkDiagnostics},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,Nt,l)}:{}},totalQuestions:0,surface:X.surface,aiOverview:X.aiOverview,aiMode:X.aiMode,whatPeopleSaying:[],tree:[],flat:[],videos:[],forums:[],organicResults:rt,localPack:R,entityIds:$,stats:ft}}let[L,f,y,T,w,C]=await Promise.all([P?this.extractVideos(p):Promise.resolve([]),v?this.extractForums(p):Promise.resolve([]),A?this.extractWhatPeopleSaying(p):Promise.resolve([]),this.extractEntityIds(p),this.extractOrganicResults(p),g?this.extractLocalPack(p):Promise.resolve([])]),M=this.mergeLocalPackIntoEntities(T,C),m=t.debug?Mt(o,w,C):void 0;this.reporter.onVideos(L),this.reporter.onForums(f);let I=k?await this.extractAISurfaces(p,t):x,b={requestedPages:(t.pages??1)>=2?2:1,capturedPages:1,page2Status:(t.pages??1)>=2?"not_attempted":"not_requested",page1OrganicCount:w.length,page2OrganicCount:0},W=w;if(this.checkpointMaterial={surface:I.surface,aiOverview:I.aiOverview,aiMode:I.aiMode,whatPeopleSaying:y,videos:L,forums:f,organicResults:W,localPack:C,entityIds:M,pagination:b},await this.emitProgress("serp_captured"),b.requestedPages===2){let H=await this.captureSecondOrganicPage(p,u,n);W=[...w,...H.organic],b={...b,capturedPages:H.status==="captured"?2:1,page2Status:H.status,page2OrganicCount:H.organic.length,...H.failureCode?{failureCode:H.failureCode}:{}},this.checkpointMaterial={...this.checkpointMaterial,organicResults:W,pagination:b},await this.emitProgress("serp_captured"),await this.resolveMaterialLinks(p,[],W,I.aiOverview,I.aiMode),this.checkpointMaterial={...this.checkpointMaterial,organicResults:W},await this.emitProgress("serp_captured")}let D=t.debug?Mt(o,W,C):m;if(!N){await this.resolveMaterialLinks(p,[],W,I.aiOverview,I.aiMode),this.checkpointMaterial={...this.checkpointMaterial,organicResults:W},await this.emitProgress("serp_captured");let H={seed:u.query,totalQuestions:0,maxDepthReached:0,durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(H),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:"no_paa",noPaaObserved:!0,problem:null,pagination:b,paaLifecycle:{...this.paaLifecycle},completeness:{...this.completeness},links:{...this.linkDiagnostics},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,D,l)}:{}},totalQuestions:0,surface:I.surface,aiOverview:I.aiOverview,aiMode:I.aiMode,whatPeopleSaying:y,tree:[],flat:[],videos:L,forums:f,organicResults:W,localPack:C,entityIds:M,stats:H}}let z=Date.now(),K=await this.runBFS(p,u,n);this.phaseTimings.paaExpansionMs=Date.now()-z,this.throwIfAborted(n);let G=new URLSearchParams({q:u.query,gl:t.gl,hl:t.hl,pws:"0",udm:Lt.udm});r&&G.set("uule",r);let q=[];if(t.includeShortVideos!==!1)try{q=await this.extractShortVideos(p,"https://www.google.com/search?"+G.toString())}catch(H){if(!(H instanceof J))throw H;d++,U.push({code:"short_videos_captcha_skipped",surface:"short_videos",message:H.message,retryable:!0})}this.reporter.onVideos(q),await this.resolveMaterialLinks(p,K,W,I.aiOverview,I.aiMode),this.checkpointMaterial={...this.checkpointMaterial,surface:I.surface,aiOverview:I.aiOverview,aiMode:I.aiMode,videos:[...L,...q],organicResults:W},await this.emitProgress("expansion_finished");let wt=[...L,...q],O=this.buildTree(K,u.query),Z={seed:u.query,totalQuestions:K.length,maxDepthReached:K.reduce((H,E)=>Math.max(H,E.depth),0),durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(Z),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:"paa_found",problem:null,pagination:b,paaLifecycle:{...this.paaLifecycle},completeness:{...this.completeness},links:{...this.linkDiagnostics},...U.length>0?{warnings:U}:{},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,D,l)}:{}},totalQuestions:K.length,surface:I.surface,aiOverview:I.aiOverview,aiMode:I.aiMode,whatPeopleSaying:y,tree:O,flat:K,videos:wt,forums:f,organicResults:W,localPack:C,entityIds:M,stats:Z}}catch(S){throw d++,this.paaLifecycle.discoveryStatus==="in_progress"&&(this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"interrupted",completionReason:"The browser attempt ended before frontier exhaustion could be proven."}),await this.emitProgress("attempt_ending").catch(()=>{}),this.reporter.onError(S instanceof Error?S:new Error(String(S))),S}}};import{promises as _}from"fs";import dt from"path";import ut from"papaparse";var Yt=class{async writeJSON(t,n){await _.mkdir(n,{recursive:!0});let s=`${t.seed.toLowerCase().replace(/\W+/g,"-").slice(0,40)}-${Date.now()}.json`,i=dt.join(n,s);return await _.writeFile(i,JSON.stringify(t,null,2),"utf8"),await Ae({title:`${t.seed} scrape`,content:JSON.stringify(t),source:`mcp-scraper:${i}`}),i}async writeCSV(t,n){await _.mkdir(n,{recursive:!0});let s=(t[0]?.seed_query??"paa").toLowerCase().replace(/\W+/g,"-").slice(0,40),i=ut.unparse(t.map(({sources:S,...h})=>({...h,sources_json:JSON.stringify(S)})),{header:!0}),d=`${s}-${Date.now()}.csv`,U=dt.join(n,d);return await _.writeFile(U,i,"utf8"),U}async writeVideoCSV(t,n,a){await _.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=ut.unparse(t,{header:!0}),d=`${s}-videos-${Date.now()}.csv`,U=dt.join(a,d);return await _.writeFile(U,i,"utf8"),U}async writeForumCSV(t,n,a){await _.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=ut.unparse(t,{header:!0}),d=`${s}-forums-${Date.now()}.csv`,U=dt.join(a,d);return await _.writeFile(U,i,"utf8"),U}async writeAIOverviewCSV(t,n,a,s){await _.mkdir(s,{recursive:!0});let i=a.toLowerCase().replace(/\W+/g,"-").slice(0,40),d=t.map((l,o)=>({seed_query:a,response_text:o===0?n??"":"",citation_text:l.text,citation_href:l.href})),U=ut.unparse(d,{header:!0}),S=`${i}-ai-overview-${Date.now()}.csv`,h=dt.join(s,S);return await _.writeFile(h,U,"utf8"),h}async writeAIModeCSV(t,n,a,s){await _.mkdir(s,{recursive:!0});let i=a.toLowerCase().replace(/\W+/g,"-").slice(0,40),d=t.map((l,o)=>({seed_query:a,response_text:o===0?n??"":"",citation_text:l.text,citation_href:l.href})),U=ut.unparse(d,{header:!0}),S=`${i}-ai-mode-${Date.now()}.csv`,h=dt.join(s,S);return await _.writeFile(h,U,"utf8"),h}async writeWhatPeopleSayingCSV(t,n,a){await _.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=t.map(h=>({seed_query:n,...h})),d=ut.unparse(i,{header:!0}),U=`${s}-what-people-saying-${Date.now()}.csv`,S=dt.join(a,U);return await _.writeFile(S,d,"utf8"),S}};var Kt=class{onQuestion(t){process.stdout.write(JSON.stringify({event:"question",depth:t.depth,question:t.question})+`
21705
21705
  `)}onDepth(t){process.stdout.write(JSON.stringify({event:"depth",depth:t})+`
21706
21706
  `)}onVideos(t){for(let n of t)process.stdout.write(JSON.stringify({event:"video",type:n.type,platform:n.platform,duration:n.duration,title:n.title,channel:n.channel,url:n.url})+`
21707
21707
  `)}onForums(t){for(let n of t)process.stdout.write(JSON.stringify({event:"forum",title:n.title,source:n.source,url:n.url})+`
21708
21708
  `)}onComplete(t){process.stdout.write(JSON.stringify({event:"complete",...t})+`
21709
21709
  `)}onError(t){process.stderr.write(JSON.stringify({event:"error",type:t.constructor.name,message:t.message})+`
21710
- `)}};import{randomInt as va}from"crypto";var Na="pr.oxylabs.io",fa=7777,Ta=10,us=2;function Cn(){return process.env.OXYLABS_USERNAME?.trim()||void 0}function kn(){return process.env.OXYLABS_PASSWORD?.trim()||void 0}function Pa(){return(process.env.OXYLABS_COUNTRY?.trim()||"US").toUpperCase()}function Jt(){return!!(Cn()&&kn())}function ba(){let e="";for(let t=0;t<10;t++)e+=String(va(0,10));return e}function Wa(e={}){let t=Cn();if(!t)return;let n=t.startsWith("customer-")?t:`customer-${t}`,a=(e.country?.trim()||Pa()).toUpperCase(),s=e.sticky?`-sessid-${ba()}-sesstime-${Ta}`:"";return`${n}-cc-${a}${s}`}function Se(e){return e.replace(/pr\.oxylabs\.io(:\d+)?/gi,"backup proxy").replace(/oxylabs/gi,"backup proxy")}function Ia(e){return`mcp-backup-custom-${`${Date.now()}-${e??0}-${Math.random().toString(36).slice(2,8)}`}`}async function _t(e,t={}){let n=Wa({sticky:t.sticky}),a=kn();if(!n||!a)throw new Error("backup proxy pool is not configured");let s=new tt({apiKey:e});try{let i=await s.proxies.create({type:"custom",name:Ia(t.attemptIndex),protocol:"http",config:{host:Na,port:fa,username:n,password:a}});if(!i.id)throw new Error("backup proxy creation did not return a proxy id");return i.id}catch(i){let d=i instanceof Error?i.message:String(i);throw new Error(Se(d))}}async function cs(e,t){if(!(!e||!Jt()))try{return await _t(e,{attemptIndex:t})}catch{return}}async function ws(e,t){if(!(!e||!t))try{await new tt({apiKey:e}).proxies.delete(t)}catch{}}var Aa={alabama:"AL",alaska:"AK",arizona:"AZ",arkansas:"AR",california:"CA",colorado:"CO",connecticut:"CT",delaware:"DE",florida:"FL",georgia:"GA",hawaii:"HI",idaho:"ID",illinois:"IL",indiana:"IN",iowa:"IA",kansas:"KS",kentucky:"KY",louisiana:"LA",maine:"ME",maryland:"MD",massachusetts:"MA",michigan:"MI",minnesota:"MN",mississippi:"MS",missouri:"MO",montana:"MT",nebraska:"NE",nevada:"NV","new hampshire":"NH","new jersey":"NJ","new mexico":"NM","new york":"NY","north carolina":"NC","north dakota":"ND",ohio:"OH",oklahoma:"OK",oregon:"OR",pennsylvania:"PA","rhode island":"RI","south carolina":"SC","south dakota":"SD",tennessee:"TN",texas:"TX",utah:"UT",vermont:"VT",virginia:"VA",washington:"WA","west virginia":"WV",wisconsin:"WI",wyoming:"WY"},La={"atlanta|GA":"30303","austin|TX":"78701","baltimore|MD":"21201","boston|MA":"02108","boulder|CO":"80302","charlotte|NC":"28202","chicago|IL":"60601","colorado_springs|CO":"80903","columbus|OH":"43215","dallas|TX":"75201","denver|CO":"80202","detroit|MI":"48226","fort_collins|CO":"80524","fort_worth|TX":"76102","houston|TX":"77002","indianapolis|IN":"46204","jacksonville|FL":"32202","las_vegas|NV":"89101","los_angeles|CA":"90012","louisville|KY":"40202","loveland|CO":"80537","memphis|TN":"38103","miami|FL":"33131","minneapolis|MN":"55401","nashville|TN":"37203","new_york|NY":"10001","orlando|FL":"32801","philadelphia|PA":"19103","phoenix|AZ":"85004","portland|OR":"97205","raleigh|NC":"27601","richmond|VA":"23219","sacramento|CA":"95814","salt_lake_city|UT":"84101","san_antonio|TX":"78205","san_diego|CA":"92101","san_francisco|CA":"94103","san_jose|CA":"95113","seattle|WA":"98101"};function xa(e){return e?e.slice(-6):null}function Y(e,t,n,a,s,i=!1){return{\u006b\u0065\u0072\u006e\u0065\u006cProxyId:n,...i&&n?{disposableProxyId:n}:{},resolution:{source:e,proxyType:e==="disabled"?"none":e==="configured_fallback"?"configured":e==="isp_created"?"isp":e==="backup_custom"?"custom":e==="location_created"||e==="location_reused"?"residential":"unknown",proxyMode:t,proxyIdPresent:!!n,proxyIdSuffix:xa(n),target:a,error:s,disposable:i}}}function Oa(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function Ba(e){return e.trim().toLowerCase().replace(/\./g,"").replace(/\s+/g," ")}function Ha(e){if(!e)return!0;let t=Ba(e);return t==="united states"||t==="united states of america"||t==="usa"||t==="us"}function Mn(e){let t=e.trim();return/^[A-Za-z]{2}$/.test(t)?t.toUpperCase():Aa[Oa(t)]??null}function Fa(e){let n=e.normalize("NFKD").replace(/[^\x00-\x7F]/g,"").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean),a=n.join("_"),s=n.join("");return Array.from(new Set([a,s].filter(Boolean)))}function it(e,t,n){return n?`mcp-serp-residential-${e.toLowerCase()}-${t.toLowerCase()}-${n}`:`mcp-serp-residential-${e.toLowerCase()}-${t.toLowerCase()}`}function zt(e,t){let n=`${Date.now()}-${t??0}-${Math.random().toString(36).slice(2,8)}`;return`${e}-fresh-${n}`}function Ra(e){return`mcp-serp-residential-us-zip-${e}`}function Ga(e,t){if(!e||t.toLowerCase()!=="us")return null;let n=tn(e),a=n.split(",").map(h=>h.trim()).filter(Boolean);if(a.length>1&&Ha(a[a.length-1])&&(a=a.slice(0,-1)),a.length===1){let h=Mn(a[0]);return h?{canonicalLocation:n,level:"state",country:"US",state:h,city:"",cityCandidates:[],proxyName:it("US",h),config:{country:"US",state:h}}:null}let[s="",i=""]=a;if(!s||!i)return null;let d=Mn(i);if(!d)return null;let U=Fa(s),S=U[0];return S?{canonicalLocation:n,level:"city",country:"US",state:d,city:S,cityCandidates:U,proxyName:it("US",d,S),config:{country:"US",state:d,city:S}}:null}function Da(e){return`${e.city}|${e.state}`}function pn(e,t){return t&&/^\d{5}$/.test(t)?t:La[Da(e)]??null}function mn(e,t){return{...e,level:"zip",zip:t,proxyName:Ra(t),config:{country:e.country,state:e.state,zip:t}}}function Ue(e,t){return{...e,proxyName:t}}function ue(e,t,n){return t.level==="zip"?e?.country?.toUpperCase()===t.country&&e?.zip===t.zip:e?.country?.toUpperCase()===t.country&&e?.state?.toUpperCase()===t.state&&(n?e?.city===n:!e?.city)}function Va(e,t){return e.find(n=>n.type==="residential"&&n.status!=="unavailable"&&!!n.id&&(n.name===t.proxyName||ue(n.config,t,t.level==="city"?t.city:void 0)))??null}function Ea(e,t){for(let n of t.cityCandidates){let a=it(t.country,t.state,n),s=e.find(i=>i.type==="residential"&&i.status!=="unavailable"&&!!i.id&&(i.name===a||ue(i.config,t,n)));if(s)return s}return null}function qt(e){return{...e,level:"state",proxyName:it(e.country,e.state),config:{country:e.country,state:e.state}}}function Ya(e,t){let n=it(t.country,t.state);return e.find(a=>a.type==="residential"&&a.status!=="unavailable"&&!!a.id&&(a.name===n||ue(a.config,t)))??null}function Ka(e,t){return qt(e)}function at(e){return e instanceof Error?e.message:String(e)}function Ja(e,t,n){let a=[],s=pn(e,t);if(s){let d=mn(e,s);a.push(Ue(d,zt(d.proxyName,n)))}for(let d of e.cityCandidates){let U={...e,level:"city",city:d,proxyName:it(e.country,e.state,d),config:{country:e.country,state:e.state,city:d}};a.push(Ue(U,zt(U.proxyName,n)))}let i=qt(e);return a.push(Ue(i,zt(i.proxyName,n))),a}async function he(e,t,n){if(e.backupOnExhaustion&&n.length>0&&e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey&&Jt())try{let a=await _t(e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey,{attemptIndex:e.attemptIndex});return Y("backup_custom",e.proxyMode,a,t,null,!0)}catch(a){n.push(`backup: ${Se(at(a))}`)}return Y("configured_fallback",e.proxyMode,e.configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId,t,n.join(" | "))}async function Ms(e){if(!e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey||!Jt())return null;try{let t=await _t(e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey,{attemptIndex:e.attemptIndex});return Y("backup_custom",e.proxyMode,t,null,null,!0)}catch{return null}}async function _a(e,t,n){let a=[];for(let s of Ja(n,t.proxyZip,t.attemptIndex))try{let i=await e.proxies.create({type:"residential",name:s.proxyName,config:s.level==="zip"?{country:s.country,zip:s.zip}:s.config});if(i.id)return Y("location_created",t.proxyMode,i.id,s,null,!0);a.push(`${s.proxyName}: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id`)}catch(i){a.push(`${s.proxyName}: ${at(i)}`)}if(process.env.\u004b\u0045\u0052\u004e\u0045\u004c_PROXY_TYPE!=="residential"){let s=qt(n);try{let i=await e.proxies.create({type:"isp",name:zt(`mcp-serp-isp-${s.country.toLowerCase()}-${(s.state??"").toLowerCase()}`,t.attemptIndex),config:{country:s.country,...s.state?{state:s.state}:{}}});if(i.id)return Y("isp_created",t.proxyMode,i.id,s,null,!0);a.push("isp: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id")}catch(i){a.push(`isp: ${at(i)}`)}}return he(t,n,a)}async function vn(e,t){if(!e||!t)return;await new tt({apiKey:e}).proxies.delete(t)}async function Nn(e){if(e.proxyMode==="none")return Y("disabled",e.proxyMode,void 0,null,null);if(e.proxyMode==="configured")return Y("configured_fallback",e.proxyMode,e.configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId,null,null);let t=Ga(e.location,e.gl);if(!t||!e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey)return Y("configured_fallback",e.proxyMode,e.configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId,t,t?null:"location could not be normalized to a US city/state proxy target");let n=new tt({apiKey:e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey});try{let a=e.attemptIndex??0;if(e.fresh)return await _a(n,e,t);if(a>=1){let l=Ka(t,a),o=[];try{let r=await n.proxies.create({type:"residential",name:l.proxyName,config:l.config});if(r.id)return Y("location_created",e.proxyMode,r.id,l,null);o.push(`${l.state}: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id`)}catch(r){o.push(`${l.state}: ${at(r)}`)}return he(e,l,o)}let s=[];for await(let l of await n.proxies.list())s.push(l);let i=pn(t,e.proxyZip),d=[];if(i){let l=mn(t,i),o=Va(s,l);if(o?.id)return Y("location_reused",e.proxyMode,o.id,l,null);try{let r=await n.proxies.create({type:"residential",name:l.proxyName,config:{country:l.country,zip:i}});if(r.id)return Y("location_created",e.proxyMode,r.id,l,null);d.push(`${i}: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id`)}catch(r){d.push(`${i}: ${at(r)}`)}}let U=Ea(s,t);if(U?.id)return Y("location_reused",e.proxyMode,U.id,t,d.join(" | ")||null);for(let l of t.cityCandidates)try{let o=await n.proxies.create({type:"residential",name:it(t.country,t.state,l),config:{country:t.country,state:t.state,city:l}});if(o.id)return Y("location_created",e.proxyMode,o.id,{...t,level:"city",city:l,proxyName:it(t.country,t.state,l),config:{country:t.country,state:t.state,city:l}},null);d.push(`${l}: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id`)}catch(o){d.push(`${l}: ${at(o)}`)}let S=qt(t),h=Ya(s,S);if(h?.id)return Y("location_reused",e.proxyMode,h.id,S,d.join(" | "));try{let l=await n.proxies.create({type:"residential",name:S.proxyName,config:S.config});if(l.id)return Y("location_created",e.proxyMode,l.id,S,d.join(" | "));d.push(`${S.state}: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id`)}catch(l){d.push(`${S.state}: ${at(l)}`)}return he(e,t,d)}catch(a){return Y("configured_fallback",e.proxyMode,e.configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId,t,at(a))}}var mt=class extends Error{constructor(t,n){super(`SERP provider mismatch: planned ${t}, observed ${n}`),this.name="SerpProviderMismatchError"}};function fn(e){return e==="\u0062\u0072\u0069\u0067\u0068\u0074_\u0064\u0061\u0074\u0061_browser_api"?"\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061":"\u006b\u0065\u0072\u006e\u0065\u006c"}function Tn(e){return za({intent:e.intent,\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available:e.\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available,\u006b\u0065\u0072\u006e\u0065\u006cAvailable:!0,persistent\u004b\u0065\u0072\u006e\u0065\u006cIdentityRequested:e.persistent\u004b\u0065\u0072\u006e\u0065\u006cIdentityRequested,retryIndex:e.retryIndex,priorTerminalReason:e.priorTerminalReason,allowedFallbacks:e.\u006b\u0065\u0072\u006e\u0065\u006cFallbackAvailable&&e.intent!=="\u006b\u0065\u0072\u006e\u0065\u006c"?["\u006b\u0065\u0072\u006e\u0065\u006c"]:[],timeoutMs:e.softDeadlineMs==null?4e5:Math.max(1,e.softDeadlineMs-Date.now())})}function Pn(e){if(e.forceManagedSerp&&e.force\u004b\u0065\u0072\u006e\u0065\u006cSerp)throw new Error("forceManagedSerp and force\u004b\u0065\u0072\u006e\u0065\u006cSerp cannot both be true");return e.forceManagedSerp?"\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061":e.force\u004b\u0065\u0072\u006e\u0065\u006cSerp?"\u006b\u0065\u0072\u006e\u0065\u006c":"auto"}function $t(e,t){if(!t)throw new Error(`Requested SERP provider is unavailable: ${e}`);return e}function za(e){if(!Number.isInteger(e.retryIndex)||e.retryIndex<0)throw new Error("retryIndex must be a non-negative integer");if(!Number.isFinite(e.timeoutMs)||e.timeoutMs<=0)throw new Error("timeoutMs must be a positive number");let t,n;e.intent==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?(t=$t("\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061",e.\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available),n="explicit_\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"):e.intent==="\u006b\u0065\u0072\u006e\u0065\u006c"?(t=$t("\u006b\u0065\u0072\u006e\u0065\u006c",e.\u006b\u0065\u0072\u006e\u0065\u006cAvailable),n="explicit_\u006b\u0065\u0072\u006e\u0065\u006c"):e.persistent\u004b\u0065\u0072\u006e\u0065\u006cIdentityRequested?(t=$t("\u006b\u0065\u0072\u006e\u0065\u006c",e.\u006b\u0065\u0072\u006e\u0065\u006cAvailable),n="persistent_\u006b\u0065\u0072\u006e\u0065\u006c_identity"):e.\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available?(t="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061",n="managed_default"):(t=$t("\u006b\u0065\u0072\u006e\u0065\u006c",e.\u006b\u0065\u0072\u006e\u0065\u006cAvailable),n="\u006b\u0065\u0072\u006e\u0065\u006c_default");let a=e.allowedFallbacks.find(d=>d!==t&&(d==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?e.\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available:e.\u006b\u0065\u0072\u006e\u0065\u006cAvailable)),s=e.retryIndex>0&&a?a:t,i=e.retryIndex===0?"primary":s===t?"same_provider_retry":"provider_fallback";return Object.freeze({plannedProvider:s,attemptKind:i,reasonCode:i==="primary"?n:i==="provider_fallback"?"provider_fallback":"same_provider_retry",retryIndex:e.retryIndex,priorTerminalReason:e.priorTerminalReason??null,timeoutMs:Math.floor(e.timeoutMs),fallbackAllowed:!!a})}var we=2,qa=2,$a=3e3;function ge(e){return e.reason instanceof DOMException&&e.reason.name==="TimeoutError"?e.reason:new j}function ja(e){if(!e||typeof e!="object")return;let t=e.signal;if(t instanceof AbortSignal)return t}function Qa(e){if(!e||typeof e!="object")return;let t=e.onAttemptEvent;return typeof t=="function"?t:void 0}function Za(e){if(!e||typeof e!="object")return;let t=e.onPaaProgress;return typeof t=="function"?t:void 0}function Xa(e){if(!e||typeof e!="object")return;let t=e.onPaaDomEvidence;return typeof t=="function"?t:void 0}async function ti(e){let t=await e.evaluate(n=>{let a=n,s=Array.from(document.querySelectorAll(a.item)),i=s.map(S=>S.querySelector(a.clickTarget)).filter(S=>S!=null),d=S=>{let h=S.getBoundingClientRect();if(h.width<=0||h.height<=0)return!1;let l=h.left+h.width/2,o=h.top+h.height/2;if(l<0||o<0||l>=window.innerWidth||o>=window.innerHeight)return!1;let r=document.elementFromPoint(l,o);return r!=null&&r!==S&&!S.contains(r)&&!r.contains(S)},U=Array.from(document.querySelectorAll("body *")).filter(S=>{let h=window.getComputedStyle(S);if(h.position!=="fixed"&&h.position!=="sticky")return!1;let l=S.getBoundingClientRect();return l.width*l.height>=window.innerWidth*window.innerHeight*.15&&h.visibility!=="hidden"&&h.display!=="none"});return{itemCount:s.length,expandedItemCount:s.filter(S=>S.classList.contains(a.expandedClass)||S.querySelector(a.clickTarget)?.getAttribute("aria-expanded")==="true").length,answeredItemCount:s.filter(S=>(S.querySelector(a.answerContainer)?.textContent?.trim().length??0)>=10).length,sourcedItemCount:s.filter(S=>S.querySelector(`${a.answerContainer} a[href]`)!=null).length,clickTargetCount:i.length,clickTargetsWithButtonRole:i.filter(S=>S.getAttribute("role")==="button"||S.tagName==="BUTTON").length,clickTargetsWithExpandedState:i.filter(S=>S.hasAttribute("aria-expanded")).length,clickTargetsOffscreen:i.filter(S=>{let h=S.getBoundingClientRect(),l=h.left+h.width/2,o=h.top+h.height/2;return l<0||o<0||l>=window.innerWidth||o>=window.innerHeight}).length,clickTargetsBlockedAtCenter:i.filter(d).length,fixedOrStickyOverlayCount:U.length}},{item:F.item,answerContainer:F.answerContainer,clickTarget:F.clickTarget,expandedClass:F.expandedClass});return{capturedAt:new Date().toISOString(),...t,selectorVersion:Ge}}async function ct(e,t){if(e)try{await e(t)}catch(n){console.warn(JSON.stringify({event:"harvest_attempt_log_failed",attempt_number:t.attemptNumber,message:n instanceof Error?n.message:String(n)}))}}function vt(e){if(e instanceof mt)return"error";if(e instanceof J)return"captcha";if(e instanceof Zt)return"location_mismatch";if(e instanceof j)return"request_aborted";if(e instanceof Ct)return"browser_session_interrupted";if(e instanceof DOMException&&(e.name==="TimeoutError"||e.name==="AbortError"))return"timeout";let t=e instanceof Error?e.message:String(e);return/browser (?:has been )?closed|context (?:has been )?closed|target page, context or browser has been closed|session closed|page has been closed/i.test(t)?"browser_session_interrupted":si(t)?"proxy_tunnel_failed":oi(t)?"proxy_unavailable":/timeout|timed out|Timeout \d+ms exceeded|deadline/i.test(t)?"timeout":"error"}function ei(e){return e.diagnostics.degradedResult?"degraded_result":e.diagnostics?.completionStatus??(e.totalQuestions>0?"paa_found":"no_paa")}function ni(e){return e.flat.length>0||e.organicResults.length>0||e.localPack.length>0||e.videos.length>0||e.forums.length>0||e.whatPeopleSaying.length>0||e.aiOverview.detected||e.aiMode.detected}function bn(e,t,n){let a=ni(e),s=(e.diagnostics.warnings?.length??0)>0,i=new Set(e.flat.map(g=>g.question.toLowerCase().replace(/[^\w\s]/g,"").replace(/\s+/g," ").trim())).size,d=n?0:e.flat.filter(g=>!g.answer?.trim()).length,U=n?0:e.flat.filter(g=>!g.source_cite?.trim()).length,S=e.diagnostics.completionStatus==="no_paa"&&(e.diagnostics.noPaaObserved===!0||a),h=e.diagnostics.completionStatus==="paa_found",l=e.diagnostics.paaLifecycle?.discoveryStatus,o=l==="interrupted"||l==="recovery_exhausted",r=h&&(i<t&&l!=="frontier_exhausted"||d>0||U>0||!!e.diagnostics.interruption||o),u=S?"complete":h&&i>0?r||s?"partial":"complete":a?s?"partial":"complete":"degraded",c=u==="degraded";return e.diagnostics={...e.diagnostics,resultQuality:u,degradedResult:c,degradationReasons:c?["empty_primary_serp"]:[],retryRecommended:c||u==="partial"&&(r||e.diagnostics.warnings?.some(g=>g.retryable)===!0),completeness:{paaWithoutAnswer:d,paaWithoutSource:U,paaAnswersRecovered:e.diagnostics.completeness?.paaAnswersRecovered??0,aioShareCaptured:e.diagnostics.completeness?.aioShareCaptured??null,paaRequested:t,paaReturned:e.flat.length,paaUnique:i},...e.diagnostics.paaLifecycle?{paaLifecycle:{...e.diagnostics.paaLifecycle,questionsFound:i,targetStatus:i>=t?"met":"not_met",materialStatus:d>0||U>0?"partial":"complete"}}:{}},e}function Wn(e,t,n){let a=e.diagnostics.paaLifecycle;if(!a)return e;let s={...a.retryBreakdown,browserRetries:t,providerFallbacks:n};return{...e,diagnostics:{...e.diagnostics,paaLifecycle:{...a,retryBreakdown:s,automaticRetries:s.controlRetries+s.browserRetries+s.runtimeRecoveries}}}}function ai(e){return(e.diagnostics.degradationReasons??[]).includes("empty_primary_serp")?"No usable primary SERP surface was captured; the result may be incomplete.":"The harvest result was marked degraded."}function Q(e){return e instanceof Error?e.message:String(e)}function ii(e){return e==="location"?qa:we}function si(e){return/ERR_TUNNEL_CONNECTION_FAILED|ERR_PROXY_CONNECTION_FAILED|ERR_SOCKS_CONNECTION_FAILED|tunnel connection failed|proxy connection failed|transport error: proxy/i.test(e)}function oi(e){return/proxy unavailable|proxy_unavailable|connection_test_failed|did not return a proxy id|configured fallback/i.test(e)}function In(e){return e==="captcha"||e==="proxy_tunnel_failed"||e==="proxy_unavailable"}function An(e){return e==="browser_session_interrupted"}function di(e){let t=e.diagnostics.debug?.locationEvidence,n=t?.expected?.canonicalLocation??e.location??"requested location",a=t?.candidates.slice(0,3).map(s=>`${s.city}, ${s.regionCode}`).join("; ");return a?`Google returned results for ${a}, not ${n}`:`Google returned results for a different location than ${n}`}function ri(e,t){return t==="location"&&e.diagnostics.debug?.locationEvidence?.status==="mismatch"}function Ln(e,t){if(t||!e.diagnostics.debug)return e;let n={...e.diagnostics};return delete n.debug,{...e,diagnostics:n}}async function xn(e,t){let n=t==null?3e3:t-Date.now();if(n<=0)return e;try{return await un(e,{totalBudgetMs:Math.min(3e3,n)})}catch(a){return console.warn(JSON.stringify({event:"harvest_goto_resolution_failed",message:Q(a)})),e}}async function ce(e,t){if(!(!e||!t))try{await vn(e,t),console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_proxy_deleted",proxy_id_suffix:t.slice(-6)}))}catch(n){console.warn(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_proxy_delete_failed",proxy_id_suffix:t.slice(-6),message:Q(n)}))}}async function On(e,t,n,a,s,i){let d=qe(t),U=new Kt,S=new Et(d,U,a,s);if(n?.aborted)return{result:null,error:ge(n),cleanup:await d.close(),debug:null};let h,l=n?new Promise((g,v)=>{h=()=>v(ge(n)),n.addEventListener("abort",h,{once:!0})}):null,o=null,r=null,u,c=null;try{let g=S.extract(e,n);l&&g.catch(()=>{}),o=await(l?Promise.race([g,l]):g)}catch(g){r=g}finally{if(n&&h&&n.removeEventListener("abort",h),i){let g;try{let v=ti(d);v.catch(()=>{});let P=await Promise.race([v,new Promise((M,A)=>{g=setTimeout(()=>A(new DOMException("PAA DOM evidence timed out","TimeoutError")),2e3)})]);await i(P)}catch(v){console.warn(JSON.stringify({event:"paa_dom_evidence_failed",message:Q(v)}))}finally{g&&clearTimeout(g)}}c=o?.diagnostics.debug??(e.debug?{enabled:!0,request:{query:e.query,locationInput:e.location??null,canonicalLocation:null,locationResolved:null,locationMatchSource:null,locationAmbiguousCandidates:null,uule:null,gl:e.gl,hl:e.hl,device:e.device,proxyMode:e.proxyMode,proxyZip:e.proxyZip??null,serpIdentity:e.serpIdentity??null,serpOnly:e.serpOnly,pages:e.pages??1},browser:d.getDebugSnapshot()}:null),u=await d.close()}if(r){let g=vt(r),v=g==="timeout"||g==="request_aborted"||g==="browser_session_interrupted"?g:null,P=null;if(v)try{P=typeof S.getPartialResult=="function"?S.getPartialResult():null}catch{P=null}return P&&v?(P.diagnostics={...P.diagnostics,interruption:{code:v,reasonSource:"client_runtime",message:Q(r)}},{result:P,error:r,cleanup:u,debug:c,salvagedFrom:r}):{result:null,error:r,cleanup:u,debug:c}}return{result:o,error:null,cleanup:u,debug:c}}async function Fs(e){let t=typeof e=="object"&&e!==null?e:{},n=ja(e),a=Qa(e),s=Za(e),i=Xa(e),d=t.forceManagedSerp===!0,U=t.force\u004b\u0065\u0072\u006e\u0065\u006cSerp===!0,S=Pn({forceManagedSerp:d,force\u004b\u0065\u0072\u006e\u0065\u006cSerp:U}),h=t.proxyMode,l=h==="location"||h==="none"||h==="configured"?h:me,o=typeof t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey=="string"?t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey.trim():Ne(),r=typeof t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId=="string"?t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId.trim():void 0,u={\u006b\u0065\u0072\u006e\u0065\u006cApiKey:o,proxyMode:l,configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId:r,location:typeof t.location=="string"?t.location:void 0,proxyZip:typeof t.proxyZip=="string"?t.proxyZip:void 0,gl:typeof t.gl=="string"?t.gl:"us"},c=typeof t.debug=="boolean"?t.debug:!1,g=l==="location"&&!!u.location,v=t.maxAttempts,P=typeof v=="number"&&Number.isInteger(v)&&v>=1?Math.min(we,v):ii(l),M=Math.min(we,P),A=typeof t.softDeadlineMs=="number"?t.softDeadlineMs:null,x=new Yt,B=null,N=l,p=0,L=()=>A==null||A-Date.now()>=$a;for(let f=0;f<M;f++){let y=f+1,T=Date.now();try{if(n?.aborted)throw ge(n);let w=Tn({intent:S,\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available:ze(),\u006b\u0065\u0072\u006e\u0065\u006cFallbackAvailable:!!o,persistent\u004b\u0065\u0072\u006e\u0065\u006cIdentityRequested:!!(t.serpIdentity||t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName),retryIndex:f,priorTerminalReason:B==null?null:vt(B),softDeadlineMs:A}),C=Qt.parse({...t,\u006b\u0065\u0072\u006e\u0065\u006cApiKey:o,proxyMode:N,debug:c||g}),k=w.plannedProvider==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?"\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061_browser":C.serpIdentity?"\u006b\u0065\u0072\u006e\u0065\u006c_persistent_identity":"\u006b\u0065\u0072\u006e\u0065\u006c_browser";await ct(a,{type:"started",attemptNumber:y,maxAttempts:M,method:k,provider:k==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061_browser"?"\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061":"\u006b\u0065\u0072\u006e\u0065\u006c",planReason:w.reasonCode,planTimeoutMs:w.timeoutMs,retryKind:y===1?null:w.attemptKind==="provider_fallback"?"provider_fallback":"same_method",retryReason:y===1||B==null?null:vt(B),query:C.query,location:C.location??null,maxQuestions:C.maxQuestions,startedAt:new Date(T).toISOString()});let m=w.plannedProvider==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?null:await Nn({...u,proxyMode:N,attemptIndex:f,fresh:N==="location"});if(w.plannedProvider==="\u006b\u0065\u0072\u006e\u0065\u006c"&&!m)throw new Error("\u004b\u0065\u0072\u006e\u0065\u006c proxy resolution did not produce an execution plan");let I={...t,\u006b\u0065\u0072\u006e\u0065\u006cApiKey:o,...m?{\u006b\u0065\u0072\u006e\u0065\u006cProxyId:m.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution:m.resolution}:{},proxyMode:N,keepDefaultProxy:f>0,softDeadlineMs:A==null?void 0:T+w.timeoutMs,debug:c||g};N==="none"&&(I.\u006b\u0065\u0072\u006e\u0065\u006cProxyId=void 0);let b=Qt.parse(I);console.info(JSON.stringify({event:"harvest_attempt_started",attempt_number:y,max_attempts:M,query:b.query,location:b.location??null,max_questions:b.maxQuestions}));let W=At(),D=null,z=async G=>{fn(G.provider)!==w.plannedProvider&&(D=new mt(w.plannedProvider,G.provider)),await ct(a,{type:"provider_session_started",attemptNumber:y,maxAttempts:M,provider:G.provider,providerSessionId:G.providerSessionId,observedAt:new Date().toISOString()})},K=W?.harvestBrowserMode==="headless-test"&&process.env[Pe]==="true",R=W?await be({...W,forceHeadless:K,forceHeadful:!K},()=>On(b,w,n,s,z,i)):await On(b,w,n,s,z,i);if(R.error||D){let G=D??R.error,V=vt(G);(V==="captcha"||V==="proxy_tunnel_failed")&&N==="location"&&(p++,p>=2&&(N="none"));let $=!R.result&&f<M-1&&L()&&(V==="captcha"||An(V)||l==="location"&&In(V));if(V==="captcha"?console.warn(JSON.stringify({event:"harvest_attempt_captcha",attempt_number:y,max_attempts:M,message:Q(G),will_retry:$})):$&&console.warn(JSON.stringify({event:"harvest_attempt_proxy_retry",attempt_number:y,max_attempts:M,outcome:V,message:Q(G),will_retry:$})),await ct(a,{type:"finished",attemptNumber:y,maxAttempts:M,outcome:V,\u006b\u0065\u0072\u006e\u0065\u006cSessionId:R.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,questionCount:R.result?.totalQuestions??0,durationMs:Date.now()-T,error:Q(G),willRetry:$,cleanup:R.cleanup,debug:R.debug,completedAt:new Date().toISOString()}),await ce(o,m?.disposableProxyId),B=G,$)continue;if(R.result&&!D){let X=await xn(R.result,A);return Wn(bn(Ln(X,c),b.maxQuestions,b.questionsOnly),f,w.attemptKind==="provider_fallback"?1:0)}break}let q=R.result;if(!q)throw new Error("Harvest attempt completed without a result");if(ri(q,l)){let G=new Zt(di(q)),V=f<M-1&&L();if(console.warn(JSON.stringify({event:"harvest_attempt_location_mismatch",attempt_number:y,max_attempts:M,message:G.message,will_retry:V})),await ct(a,{type:"finished",attemptNumber:y,maxAttempts:M,outcome:"location_mismatch",\u006b\u0065\u0072\u006e\u0065\u006cSessionId:R.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,questionCount:q.totalQuestions,durationMs:Date.now()-T,error:G.message,willRetry:V,cleanup:R.cleanup,debug:R.debug,completedAt:new Date().toISOString()}),await ce(o,m?.disposableProxyId),B=G,V)continue;break}let wt=await xn(q,A),O=Wn(bn(Ln(wt,c),b.maxQuestions,b.questionsOnly),f,w.attemptKind==="provider_fallback"?1:0),Z=ei(O),H=Z==="degraded_result"&&f<M-1&&L(),E=Z==="degraded_result"?ai(O):null;if(H&&console.warn(JSON.stringify({event:"harvest_attempt_degraded_result",attempt_number:y,max_attempts:M,degradation_reasons:O.diagnostics.degradationReasons,will_retry:!0})),await ct(a,{type:"finished",attemptNumber:y,maxAttempts:M,outcome:Z,\u006b\u0065\u0072\u006e\u0065\u006cSessionId:R.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,questionCount:O.totalQuestions,durationMs:Date.now()-T,error:E,willRetry:H,cleanup:R.cleanup,debug:R.debug,completedAt:new Date().toISOString()}),await ce(o,m?.disposableProxyId),H)continue;return(b.format==="json"||b.format==="both")&&await x.writeJSON(O,b.outputDir),(b.format==="csv"||b.format==="both")&&await Promise.all([x.writeCSV(O.flat,b.outputDir),O.videos.length>0?x.writeVideoCSV(O.videos,O.seed,b.outputDir):Promise.resolve(""),O.forums.length>0?x.writeForumCSV(O.forums,O.seed,b.outputDir):Promise.resolve(""),O.aiOverview.detected?x.writeAIOverviewCSV(O.aiOverview.citations,O.aiOverview.text,O.seed,b.outputDir):Promise.resolve(""),O.aiMode.detected?x.writeAIModeCSV(O.aiMode.citations,O.aiMode.text,O.seed,b.outputDir):Promise.resolve(""),O.whatPeopleSaying.length>0?x.writeWhatPeopleSayingCSV(O.whatPeopleSaying,O.seed,b.outputDir):Promise.resolve("")]),O}catch(w){let C=vt(w);(C==="captcha"||C==="proxy_tunnel_failed")&&N==="location"&&(p++,p>=2&&(N="none"));let k=f<M-1&&L()&&(C==="captcha"||An(C)||l==="location"&&In(C));if(C==="captcha"?console.warn(JSON.stringify({event:"harvest_attempt_captcha",attempt_number:y,max_attempts:M,message:Q(w),will_retry:k})):k&&console.warn(JSON.stringify({event:"harvest_attempt_proxy_retry",attempt_number:y,max_attempts:M,outcome:C,message:Q(w),will_retry:k})),await ct(a,{type:"finished",attemptNumber:y,maxAttempts:M,outcome:C,\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,questionCount:0,durationMs:Date.now()-T,error:Q(w),willRetry:k,cleanup:{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:null,browserCloseError:null},debug:null,completedAt:new Date().toISOString()}),B=w,k)continue;if(C==="captcha")break;throw w}}throw B&&!(B instanceof J)?B:(console.warn(JSON.stringify({event:"harvest_captcha_exhausted",max_attempts:M,session_kind:o?"\u006b\u0065\u0072\u006e\u0065\u006c":"local"})),new J(Te(`CAPTCHA on all ${M} fresh sessions. Try again in a few minutes.`)))}export{Si as a,Ot as b,Bt as c,ci as d,De as e,qn as f,Ft as g,Ee as h,Ye as i,_e as j,ze as k,Xe as l,oe as m,ot as n,Vt as o,us as p,Jt as q,cs as r,ws as s,Ms as t,vn as u,Nn as v,Fs as w};
21710
+ `)}};import{randomInt as va}from"crypto";var Na="pr.oxylabs.io",fa=7777,Ta=10,us=2;function Cn(){return process.env.OXYLABS_USERNAME?.trim()||void 0}function Mn(){return process.env.OXYLABS_PASSWORD?.trim()||void 0}function Pa(){return(process.env.OXYLABS_COUNTRY?.trim()||"US").toUpperCase()}function Jt(){return!!(Cn()&&Mn())}function ba(){let e="";for(let t=0;t<10;t++)e+=String(va(0,10));return e}function Wa(e={}){let t=Cn();if(!t)return;let n=t.startsWith("customer-")?t:`customer-${t}`,a=(e.country?.trim()||Pa()).toUpperCase(),s=e.sticky?`-sessid-${ba()}-sesstime-${Ta}`:"";return`${n}-cc-${a}${s}`}function Se(e){return e.replace(/pr\.oxylabs\.io(:\d+)?/gi,"backup proxy").replace(/oxylabs/gi,"backup proxy")}function Ia(e){return`mcp-backup-custom-${`${Date.now()}-${e??0}-${Math.random().toString(36).slice(2,8)}`}`}async function _t(e,t={}){let n=Wa({sticky:t.sticky}),a=Mn();if(!n||!a)throw new Error("backup proxy pool is not configured");let s=new tt({apiKey:e});try{let i=await s.proxies.create({type:"custom",name:Ia(t.attemptIndex),protocol:"http",config:{host:Na,port:fa,username:n,password:a}});if(!i.id)throw new Error("backup proxy creation did not return a proxy id");return i.id}catch(i){let d=i instanceof Error?i.message:String(i);throw new Error(Se(d))}}async function cs(e,t){if(!(!e||!Jt()))try{return await _t(e,{attemptIndex:t})}catch{return}}async function ws(e,t){if(!(!e||!t))try{await new tt({apiKey:e}).proxies.delete(t)}catch{}}var Aa={alabama:"AL",alaska:"AK",arizona:"AZ",arkansas:"AR",california:"CA",colorado:"CO",connecticut:"CT",delaware:"DE",florida:"FL",georgia:"GA",hawaii:"HI",idaho:"ID",illinois:"IL",indiana:"IN",iowa:"IA",kansas:"KS",kentucky:"KY",louisiana:"LA",maine:"ME",maryland:"MD",massachusetts:"MA",michigan:"MI",minnesota:"MN",mississippi:"MS",missouri:"MO",montana:"MT",nebraska:"NE",nevada:"NV","new hampshire":"NH","new jersey":"NJ","new mexico":"NM","new york":"NY","north carolina":"NC","north dakota":"ND",ohio:"OH",oklahoma:"OK",oregon:"OR",pennsylvania:"PA","rhode island":"RI","south carolina":"SC","south dakota":"SD",tennessee:"TN",texas:"TX",utah:"UT",vermont:"VT",virginia:"VA",washington:"WA","west virginia":"WV",wisconsin:"WI",wyoming:"WY"},La={"atlanta|GA":"30303","austin|TX":"78701","baltimore|MD":"21201","boston|MA":"02108","boulder|CO":"80302","charlotte|NC":"28202","chicago|IL":"60601","colorado_springs|CO":"80903","columbus|OH":"43215","dallas|TX":"75201","denver|CO":"80202","detroit|MI":"48226","fort_collins|CO":"80524","fort_worth|TX":"76102","houston|TX":"77002","indianapolis|IN":"46204","jacksonville|FL":"32202","las_vegas|NV":"89101","los_angeles|CA":"90012","louisville|KY":"40202","loveland|CO":"80537","memphis|TN":"38103","miami|FL":"33131","minneapolis|MN":"55401","nashville|TN":"37203","new_york|NY":"10001","orlando|FL":"32801","philadelphia|PA":"19103","phoenix|AZ":"85004","portland|OR":"97205","raleigh|NC":"27601","richmond|VA":"23219","sacramento|CA":"95814","salt_lake_city|UT":"84101","san_antonio|TX":"78205","san_diego|CA":"92101","san_francisco|CA":"94103","san_jose|CA":"95113","seattle|WA":"98101"};function xa(e){return e?e.slice(-6):null}function Y(e,t,n,a,s,i=!1){return{\u006b\u0065\u0072\u006e\u0065\u006cProxyId:n,...i&&n?{disposableProxyId:n}:{},resolution:{source:e,proxyType:e==="disabled"?"none":e==="configured_fallback"?"configured":e==="isp_created"?"isp":e==="backup_custom"?"custom":e==="location_created"||e==="location_reused"?"residential":"unknown",proxyMode:t,proxyIdPresent:!!n,proxyIdSuffix:xa(n),target:a,error:s,disposable:i}}}function Oa(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function Ba(e){return e.trim().toLowerCase().replace(/\./g,"").replace(/\s+/g," ")}function Ha(e){if(!e)return!0;let t=Ba(e);return t==="united states"||t==="united states of america"||t==="usa"||t==="us"}function kn(e){let t=e.trim();return/^[A-Za-z]{2}$/.test(t)?t.toUpperCase():Aa[Oa(t)]??null}function Fa(e){let n=e.normalize("NFKD").replace(/[^\x00-\x7F]/g,"").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean),a=n.join("_"),s=n.join("");return Array.from(new Set([a,s].filter(Boolean)))}function it(e,t,n){return n?`mcp-serp-residential-${e.toLowerCase()}-${t.toLowerCase()}-${n}`:`mcp-serp-residential-${e.toLowerCase()}-${t.toLowerCase()}`}function zt(e,t){let n=`${Date.now()}-${t??0}-${Math.random().toString(36).slice(2,8)}`;return`${e}-fresh-${n}`}function Ra(e){return`mcp-serp-residential-us-zip-${e}`}function Ga(e,t){if(!e||t.toLowerCase()!=="us")return null;let n=tn(e),a=n.split(",").map(h=>h.trim()).filter(Boolean);if(a.length>1&&Ha(a[a.length-1])&&(a=a.slice(0,-1)),a.length===1){let h=kn(a[0]);return h?{canonicalLocation:n,level:"state",country:"US",state:h,city:"",cityCandidates:[],proxyName:it("US",h),config:{country:"US",state:h}}:null}let[s="",i=""]=a;if(!s||!i)return null;let d=kn(i);if(!d)return null;let U=Fa(s),S=U[0];return S?{canonicalLocation:n,level:"city",country:"US",state:d,city:S,cityCandidates:U,proxyName:it("US",d,S),config:{country:"US",state:d,city:S}}:null}function Da(e){return`${e.city}|${e.state}`}function pn(e,t){return t&&/^\d{5}$/.test(t)?t:La[Da(e)]??null}function mn(e,t){return{...e,level:"zip",zip:t,proxyName:Ra(t),config:{country:e.country,state:e.state,zip:t}}}function Ue(e,t){return{...e,proxyName:t}}function ue(e,t,n){return t.level==="zip"?e?.country?.toUpperCase()===t.country&&e?.zip===t.zip:e?.country?.toUpperCase()===t.country&&e?.state?.toUpperCase()===t.state&&(n?e?.city===n:!e?.city)}function Va(e,t){return e.find(n=>n.type==="residential"&&n.status!=="unavailable"&&!!n.id&&(n.name===t.proxyName||ue(n.config,t,t.level==="city"?t.city:void 0)))??null}function Ea(e,t){for(let n of t.cityCandidates){let a=it(t.country,t.state,n),s=e.find(i=>i.type==="residential"&&i.status!=="unavailable"&&!!i.id&&(i.name===a||ue(i.config,t,n)));if(s)return s}return null}function qt(e){return{...e,level:"state",proxyName:it(e.country,e.state),config:{country:e.country,state:e.state}}}function Ya(e,t){let n=it(t.country,t.state);return e.find(a=>a.type==="residential"&&a.status!=="unavailable"&&!!a.id&&(a.name===n||ue(a.config,t)))??null}function Ka(e,t){return qt(e)}function at(e){return e instanceof Error?e.message:String(e)}function Ja(e,t,n){let a=[],s=pn(e,t);if(s){let d=mn(e,s);a.push(Ue(d,zt(d.proxyName,n)))}for(let d of e.cityCandidates){let U={...e,level:"city",city:d,proxyName:it(e.country,e.state,d),config:{country:e.country,state:e.state,city:d}};a.push(Ue(U,zt(U.proxyName,n)))}let i=qt(e);return a.push(Ue(i,zt(i.proxyName,n))),a}async function he(e,t,n){if(e.backupOnExhaustion&&n.length>0&&e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey&&Jt())try{let a=await _t(e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey,{attemptIndex:e.attemptIndex});return Y("backup_custom",e.proxyMode,a,t,null,!0)}catch(a){n.push(`backup: ${Se(at(a))}`)}return Y("configured_fallback",e.proxyMode,e.configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId,t,n.join(" | "))}async function ks(e){if(!e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey||!Jt())return null;try{let t=await _t(e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey,{attemptIndex:e.attemptIndex});return Y("backup_custom",e.proxyMode,t,null,null,!0)}catch{return null}}async function _a(e,t,n){let a=[];for(let s of Ja(n,t.proxyZip,t.attemptIndex))try{let i=await e.proxies.create({type:"residential",name:s.proxyName,config:s.level==="zip"?{country:s.country,zip:s.zip}:s.config});if(i.id)return Y("location_created",t.proxyMode,i.id,s,null,!0);a.push(`${s.proxyName}: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id`)}catch(i){a.push(`${s.proxyName}: ${at(i)}`)}if(process.env.\u004b\u0045\u0052\u004e\u0045\u004c_PROXY_TYPE!=="residential"){let s=qt(n);try{let i=await e.proxies.create({type:"isp",name:zt(`mcp-serp-isp-${s.country.toLowerCase()}-${(s.state??"").toLowerCase()}`,t.attemptIndex),config:{country:s.country,...s.state?{state:s.state}:{}}});if(i.id)return Y("isp_created",t.proxyMode,i.id,s,null,!0);a.push("isp: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id")}catch(i){a.push(`isp: ${at(i)}`)}}return he(t,n,a)}async function vn(e,t){if(!e||!t)return;await new tt({apiKey:e}).proxies.delete(t)}async function Nn(e){if(e.proxyMode==="none")return Y("disabled",e.proxyMode,void 0,null,null);if(e.proxyMode==="configured")return Y("configured_fallback",e.proxyMode,e.configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId,null,null);let t=Ga(e.location,e.gl);if(!t||!e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey)return Y("configured_fallback",e.proxyMode,e.configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId,t,t?null:"location could not be normalized to a US city/state proxy target");let n=new tt({apiKey:e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey});try{let a=e.attemptIndex??0;if(e.fresh)return await _a(n,e,t);if(a>=1){let l=Ka(t,a),o=[];try{let r=await n.proxies.create({type:"residential",name:l.proxyName,config:l.config});if(r.id)return Y("location_created",e.proxyMode,r.id,l,null);o.push(`${l.state}: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id`)}catch(r){o.push(`${l.state}: ${at(r)}`)}return he(e,l,o)}let s=[];for await(let l of await n.proxies.list())s.push(l);let i=pn(t,e.proxyZip),d=[];if(i){let l=mn(t,i),o=Va(s,l);if(o?.id)return Y("location_reused",e.proxyMode,o.id,l,null);try{let r=await n.proxies.create({type:"residential",name:l.proxyName,config:{country:l.country,zip:i}});if(r.id)return Y("location_created",e.proxyMode,r.id,l,null);d.push(`${i}: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id`)}catch(r){d.push(`${i}: ${at(r)}`)}}let U=Ea(s,t);if(U?.id)return Y("location_reused",e.proxyMode,U.id,t,d.join(" | ")||null);for(let l of t.cityCandidates)try{let o=await n.proxies.create({type:"residential",name:it(t.country,t.state,l),config:{country:t.country,state:t.state,city:l}});if(o.id)return Y("location_created",e.proxyMode,o.id,{...t,level:"city",city:l,proxyName:it(t.country,t.state,l),config:{country:t.country,state:t.state,city:l}},null);d.push(`${l}: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id`)}catch(o){d.push(`${l}: ${at(o)}`)}let S=qt(t),h=Ya(s,S);if(h?.id)return Y("location_reused",e.proxyMode,h.id,S,d.join(" | "));try{let l=await n.proxies.create({type:"residential",name:S.proxyName,config:S.config});if(l.id)return Y("location_created",e.proxyMode,l.id,S,d.join(" | "));d.push(`${S.state}: \u004b\u0065\u0072\u006e\u0065\u006c did not return a proxy id`)}catch(l){d.push(`${S.state}: ${at(l)}`)}return he(e,t,d)}catch(a){return Y("configured_fallback",e.proxyMode,e.configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId,t,at(a))}}var mt=class extends Error{constructor(t,n){super(`SERP provider mismatch: planned ${t}, observed ${n}`),this.name="SerpProviderMismatchError"}};function fn(e){return e==="\u0062\u0072\u0069\u0067\u0068\u0074_\u0064\u0061\u0074\u0061_browser_api"?"\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061":"\u006b\u0065\u0072\u006e\u0065\u006c"}function Tn(e){return za({intent:e.intent,\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available:e.\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available,\u006b\u0065\u0072\u006e\u0065\u006cAvailable:!0,persistent\u004b\u0065\u0072\u006e\u0065\u006cIdentityRequested:e.persistent\u004b\u0065\u0072\u006e\u0065\u006cIdentityRequested,retryIndex:e.retryIndex,priorTerminalReason:e.priorTerminalReason,allowedFallbacks:e.\u006b\u0065\u0072\u006e\u0065\u006cFallbackAvailable&&e.intent!=="\u006b\u0065\u0072\u006e\u0065\u006c"?["\u006b\u0065\u0072\u006e\u0065\u006c"]:[],timeoutMs:e.softDeadlineMs==null?4e5:Math.max(1,e.softDeadlineMs-Date.now())})}function Pn(e){if(e.forceManagedSerp&&e.force\u004b\u0065\u0072\u006e\u0065\u006cSerp)throw new Error("forceManagedSerp and force\u004b\u0065\u0072\u006e\u0065\u006cSerp cannot both be true");return e.forceManagedSerp?"\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061":e.force\u004b\u0065\u0072\u006e\u0065\u006cSerp?"\u006b\u0065\u0072\u006e\u0065\u006c":"auto"}function $t(e,t){if(!t)throw new Error(`Requested SERP provider is unavailable: ${e}`);return e}function za(e){if(!Number.isInteger(e.retryIndex)||e.retryIndex<0)throw new Error("retryIndex must be a non-negative integer");if(!Number.isFinite(e.timeoutMs)||e.timeoutMs<=0)throw new Error("timeoutMs must be a positive number");let t,n;e.intent==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?(t=$t("\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061",e.\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available),n="explicit_\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"):e.intent==="\u006b\u0065\u0072\u006e\u0065\u006c"?(t=$t("\u006b\u0065\u0072\u006e\u0065\u006c",e.\u006b\u0065\u0072\u006e\u0065\u006cAvailable),n="explicit_\u006b\u0065\u0072\u006e\u0065\u006c"):e.persistent\u004b\u0065\u0072\u006e\u0065\u006cIdentityRequested?(t=$t("\u006b\u0065\u0072\u006e\u0065\u006c",e.\u006b\u0065\u0072\u006e\u0065\u006cAvailable),n="persistent_\u006b\u0065\u0072\u006e\u0065\u006c_identity"):e.\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available?(t="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061",n="managed_default"):(t=$t("\u006b\u0065\u0072\u006e\u0065\u006c",e.\u006b\u0065\u0072\u006e\u0065\u006cAvailable),n="\u006b\u0065\u0072\u006e\u0065\u006c_default");let a=e.allowedFallbacks.find(d=>d!==t&&(d==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?e.\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available:e.\u006b\u0065\u0072\u006e\u0065\u006cAvailable)),s=e.retryIndex>0&&a?a:t,i=e.retryIndex===0?"primary":s===t?"same_provider_retry":"provider_fallback";return Object.freeze({plannedProvider:s,attemptKind:i,reasonCode:i==="primary"?n:i==="provider_fallback"?"provider_fallback":"same_provider_retry",retryIndex:e.retryIndex,priorTerminalReason:e.priorTerminalReason??null,timeoutMs:Math.floor(e.timeoutMs),fallbackAllowed:!!a})}var we=2,qa=2,$a=3e3;function ge(e){return e.reason instanceof DOMException&&e.reason.name==="TimeoutError"?e.reason:new j}function ja(e){if(!e||typeof e!="object")return;let t=e.signal;if(t instanceof AbortSignal)return t}function Qa(e){if(!e||typeof e!="object")return;let t=e.onAttemptEvent;return typeof t=="function"?t:void 0}function Za(e){if(!e||typeof e!="object")return;let t=e.onPaaProgress;return typeof t=="function"?t:void 0}function Xa(e){if(!e||typeof e!="object")return;let t=e.onPaaDomEvidence;return typeof t=="function"?t:void 0}async function ti(e){let t=await e.evaluate(n=>{let a=n,s=Array.from(document.querySelectorAll(a.item)),i=s.map(S=>S.querySelector(a.clickTarget)).filter(S=>S!=null),d=S=>{let h=S.getBoundingClientRect();if(h.width<=0||h.height<=0)return!1;let l=h.left+h.width/2,o=h.top+h.height/2;if(l<0||o<0||l>=window.innerWidth||o>=window.innerHeight)return!1;let r=document.elementFromPoint(l,o);return r!=null&&r!==S&&!S.contains(r)&&!r.contains(S)},U=Array.from(document.querySelectorAll("body *")).filter(S=>{let h=window.getComputedStyle(S);if(h.position!=="fixed"&&h.position!=="sticky")return!1;let l=S.getBoundingClientRect();return l.width*l.height>=window.innerWidth*window.innerHeight*.15&&h.visibility!=="hidden"&&h.display!=="none"});return{itemCount:s.length,expandedItemCount:s.filter(S=>S.classList.contains(a.expandedClass)||S.querySelector(a.clickTarget)?.getAttribute("aria-expanded")==="true").length,answeredItemCount:s.filter(S=>(S.querySelector(a.answerContainer)?.textContent?.trim().length??0)>=10).length,sourcedItemCount:s.filter(S=>S.querySelector(`${a.answerContainer} a[href]`)!=null).length,clickTargetCount:i.length,clickTargetsWithButtonRole:i.filter(S=>S.getAttribute("role")==="button"||S.tagName==="BUTTON").length,clickTargetsWithExpandedState:i.filter(S=>S.hasAttribute("aria-expanded")).length,clickTargetsOffscreen:i.filter(S=>{let h=S.getBoundingClientRect(),l=h.left+h.width/2,o=h.top+h.height/2;return l<0||o<0||l>=window.innerWidth||o>=window.innerHeight}).length,clickTargetsBlockedAtCenter:i.filter(d).length,fixedOrStickyOverlayCount:U.length}},{item:F.item,answerContainer:F.answerContainer,clickTarget:F.clickTarget,expandedClass:F.expandedClass});return{capturedAt:new Date().toISOString(),...t,selectorVersion:Ge}}async function ct(e,t){if(e)try{await e(t)}catch(n){console.warn(JSON.stringify({event:"harvest_attempt_log_failed",attempt_number:t.attemptNumber,message:n instanceof Error?n.message:String(n)}))}}function vt(e){if(e instanceof mt)return"error";if(e instanceof J)return"captcha";if(e instanceof Zt)return"location_mismatch";if(e instanceof j)return"request_aborted";if(e instanceof Ct)return"browser_session_interrupted";if(e instanceof DOMException&&(e.name==="TimeoutError"||e.name==="AbortError"))return"timeout";let t=e instanceof Error?e.message:String(e);return/browser (?:has been )?closed|context (?:has been )?closed|target page, context or browser has been closed|session closed|page has been closed/i.test(t)?"browser_session_interrupted":si(t)?"proxy_tunnel_failed":oi(t)?"proxy_unavailable":/timeout|timed out|Timeout \d+ms exceeded|deadline/i.test(t)?"timeout":"error"}function ei(e){return e.diagnostics.degradedResult?"degraded_result":e.diagnostics?.completionStatus??(e.totalQuestions>0?"paa_found":"no_paa")}function ni(e){return e.flat.length>0||e.organicResults.length>0||e.localPack.length>0||e.videos.length>0||e.forums.length>0||e.whatPeopleSaying.length>0||e.aiOverview.detected||e.aiMode.detected}function bn(e,t,n){let a=ni(e),s=(e.diagnostics.warnings?.length??0)>0,i=new Set(e.flat.map(g=>g.question.toLowerCase().replace(/[^\w\s]/g,"").replace(/\s+/g," ").trim())).size,d=n?0:e.flat.filter(g=>!g.answer?.trim()).length,U=n?0:e.flat.filter(g=>!g.source_cite?.trim()).length,S=e.diagnostics.completionStatus==="no_paa"&&(e.diagnostics.noPaaObserved===!0||a),h=e.diagnostics.completionStatus==="paa_found",l=e.diagnostics.paaLifecycle?.discoveryStatus,o=l==="interrupted"||l==="recovery_exhausted",r=h&&(i<t&&l!=="frontier_exhausted"||d>0||U>0||!!e.diagnostics.interruption||o),u=S?"complete":h&&i>0?r||s?"partial":"complete":a?s?"partial":"complete":"degraded",c=u==="degraded";return e.diagnostics={...e.diagnostics,resultQuality:u,degradedResult:c,degradationReasons:c?["empty_primary_serp"]:[],retryRecommended:c||u==="partial"&&(r||e.diagnostics.warnings?.some(g=>g.retryable)===!0),completeness:{paaWithoutAnswer:d,paaWithoutSource:U,paaAnswersRecovered:e.diagnostics.completeness?.paaAnswersRecovered??0,aioShareCaptured:e.diagnostics.completeness?.aioShareCaptured??null,paaRequested:t,paaReturned:e.flat.length,paaUnique:i},...e.diagnostics.paaLifecycle?{paaLifecycle:{...e.diagnostics.paaLifecycle,questionsFound:i,targetStatus:i>=t?"met":"not_met",materialStatus:d>0||U>0?"partial":"complete"}}:{}},e}function Wn(e,t,n){let a=e.diagnostics.paaLifecycle;if(!a)return e;let s={...a.retryBreakdown,browserRetries:t,providerFallbacks:n};return{...e,diagnostics:{...e.diagnostics,paaLifecycle:{...a,retryBreakdown:s,automaticRetries:s.controlRetries+s.browserRetries+s.runtimeRecoveries}}}}function ai(e){return(e.diagnostics.degradationReasons??[]).includes("empty_primary_serp")?"No usable primary SERP surface was captured; the result may be incomplete.":"The harvest result was marked degraded."}function Q(e){return e instanceof Error?e.message:String(e)}function ii(e){return e==="location"?qa:we}function si(e){return/ERR_TUNNEL_CONNECTION_FAILED|ERR_PROXY_CONNECTION_FAILED|ERR_SOCKS_CONNECTION_FAILED|tunnel connection failed|proxy connection failed|transport error: proxy/i.test(e)}function oi(e){return/proxy unavailable|proxy_unavailable|connection_test_failed|did not return a proxy id|configured fallback/i.test(e)}function In(e){return e==="captcha"||e==="proxy_tunnel_failed"||e==="proxy_unavailable"}function An(e){return e==="browser_session_interrupted"}function di(e){let t=e.diagnostics.debug?.locationEvidence,n=t?.expected?.canonicalLocation??e.location??"requested location",a=t?.candidates.slice(0,3).map(s=>`${s.city}, ${s.regionCode}`).join("; ");return a?`Google returned results for ${a}, not ${n}`:`Google returned results for a different location than ${n}`}function ri(e,t){return t==="location"&&e.diagnostics.debug?.locationEvidence?.status==="mismatch"}function Ln(e,t){if(t||!e.diagnostics.debug)return e;let n={...e.diagnostics};return delete n.debug,{...e,diagnostics:n}}async function xn(e,t){let n=t==null?3e3:t-Date.now();if(n<=0)return e;try{return await un(e,{totalBudgetMs:Math.min(3e3,n)})}catch(a){return console.warn(JSON.stringify({event:"harvest_goto_resolution_failed",message:Q(a)})),e}}async function ce(e,t){if(!(!e||!t))try{await vn(e,t),console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_proxy_deleted",proxy_id_suffix:t.slice(-6)}))}catch(n){console.warn(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_proxy_delete_failed",proxy_id_suffix:t.slice(-6),message:Q(n)}))}}async function On(e,t,n,a,s,i){let d=qe(t),U=new Kt,S=new Et(d,U,a,s);if(n?.aborted)return{result:null,error:ge(n),cleanup:await d.close(),debug:null};let h,l=n?new Promise((g,v)=>{h=()=>v(ge(n)),n.addEventListener("abort",h,{once:!0})}):null,o=null,r=null,u,c=null;try{let g=S.extract(e,n);l&&g.catch(()=>{}),o=await(l?Promise.race([g,l]):g)}catch(g){r=g}finally{if(n&&h&&n.removeEventListener("abort",h),i){let g;try{let v=ti(d);v.catch(()=>{});let P=await Promise.race([v,new Promise((k,A)=>{g=setTimeout(()=>A(new DOMException("PAA DOM evidence timed out","TimeoutError")),2e3)})]);await i(P)}catch(v){console.warn(JSON.stringify({event:"paa_dom_evidence_failed",message:Q(v)}))}finally{g&&clearTimeout(g)}}c=o?.diagnostics.debug??(e.debug?{enabled:!0,request:{query:e.query,locationInput:e.location??null,canonicalLocation:null,locationResolved:null,locationMatchSource:null,locationAmbiguousCandidates:null,uule:null,gl:e.gl,hl:e.hl,device:e.device,proxyMode:e.proxyMode,proxyZip:e.proxyZip??null,serpIdentity:e.serpIdentity??null,serpOnly:e.serpOnly,pages:e.pages??1},browser:d.getDebugSnapshot()}:null),u=await d.close()}if(r){let g=vt(r),v=g==="timeout"||g==="request_aborted"||g==="browser_session_interrupted"?g:null,P=null;if(v)try{P=typeof S.getPartialResult=="function"?S.getPartialResult():null}catch{P=null}return P&&v?(P.diagnostics={...P.diagnostics,interruption:{code:v,reasonSource:"client_runtime",message:Q(r)}},{result:P,error:r,cleanup:u,debug:c,salvagedFrom:r}):{result:null,error:r,cleanup:u,debug:c}}return{result:o,error:null,cleanup:u,debug:c}}async function Fs(e){let t=typeof e=="object"&&e!==null?e:{},n=ja(e),a=Qa(e),s=Za(e),i=Xa(e),d=t.forceManagedSerp===!0,U=t.force\u004b\u0065\u0072\u006e\u0065\u006cSerp===!0,S=Pn({forceManagedSerp:d,force\u004b\u0065\u0072\u006e\u0065\u006cSerp:U}),h=t.proxyMode,l=h==="location"||h==="none"||h==="configured"?h:me,o=typeof t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey=="string"?t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey.trim():Ne(),r=typeof t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId=="string"?t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId.trim():void 0,u={\u006b\u0065\u0072\u006e\u0065\u006cApiKey:o,proxyMode:l,configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId:r,location:typeof t.location=="string"?t.location:void 0,proxyZip:typeof t.proxyZip=="string"?t.proxyZip:void 0,gl:typeof t.gl=="string"?t.gl:"us"},c=typeof t.debug=="boolean"?t.debug:!1,g=l==="location"&&!!u.location,v=t.maxAttempts,P=typeof v=="number"&&Number.isInteger(v)&&v>=1?Math.min(we,v):ii(l),k=Math.min(we,P),A=typeof t.softDeadlineMs=="number"?t.softDeadlineMs:null,x=new Yt,B=null,N=l,p=0,L=()=>A==null||A-Date.now()>=$a;for(let f=0;f<k;f++){let y=f+1,T=Date.now();try{if(n?.aborted)throw ge(n);let w=Tn({intent:S,\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available:ze(),\u006b\u0065\u0072\u006e\u0065\u006cFallbackAvailable:!!o,persistent\u004b\u0065\u0072\u006e\u0065\u006cIdentityRequested:!!(t.serpIdentity||t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName),retryIndex:f,priorTerminalReason:B==null?null:vt(B),softDeadlineMs:A}),C=Qt.parse({...t,\u006b\u0065\u0072\u006e\u0065\u006cApiKey:o,proxyMode:N,debug:c||g}),M=w.plannedProvider==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?"\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061_browser":C.serpIdentity?"\u006b\u0065\u0072\u006e\u0065\u006c_persistent_identity":"\u006b\u0065\u0072\u006e\u0065\u006c_browser";await ct(a,{type:"started",attemptNumber:y,maxAttempts:k,method:M,provider:M==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061_browser"?"\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061":"\u006b\u0065\u0072\u006e\u0065\u006c",planReason:w.reasonCode,planTimeoutMs:w.timeoutMs,retryKind:y===1?null:w.attemptKind==="provider_fallback"?"provider_fallback":"same_method",retryReason:y===1||B==null?null:vt(B),query:C.query,location:C.location??null,maxQuestions:C.maxQuestions,startedAt:new Date(T).toISOString()});let m=w.plannedProvider==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?null:await Nn({...u,proxyMode:N,attemptIndex:f,fresh:N==="location"});if(w.plannedProvider==="\u006b\u0065\u0072\u006e\u0065\u006c"&&!m)throw new Error("\u004b\u0065\u0072\u006e\u0065\u006c proxy resolution did not produce an execution plan");let I={...t,\u006b\u0065\u0072\u006e\u0065\u006cApiKey:o,...m?{\u006b\u0065\u0072\u006e\u0065\u006cProxyId:m.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution:m.resolution}:{},proxyMode:N,keepDefaultProxy:f>0,softDeadlineMs:A==null?void 0:T+w.timeoutMs,debug:c||g};N==="none"&&(I.\u006b\u0065\u0072\u006e\u0065\u006cProxyId=void 0);let b=Qt.parse(I);console.info(JSON.stringify({event:"harvest_attempt_started",attempt_number:y,max_attempts:k,query:b.query,location:b.location??null,max_questions:b.maxQuestions}));let W=At(),D=null,z=async R=>{fn(R.provider)!==w.plannedProvider&&(D=new mt(w.plannedProvider,R.provider)),await ct(a,{type:"provider_session_started",attemptNumber:y,maxAttempts:k,provider:R.provider,providerSessionId:R.providerSessionId,billingMode:R.billingMode,observedAt:new Date().toISOString()})},K=W?.harvestBrowserMode==="headless-test"&&process.env[Pe]==="true",G=W?await be({...W,forceHeadless:K,forceHeadful:!K},()=>On(b,w,n,s,z,i)):await On(b,w,n,s,z,i);if(G.error||D){let R=D??G.error,V=vt(R);(V==="captcha"||V==="proxy_tunnel_failed")&&N==="location"&&(p++,p>=2&&(N="none"));let $=!G.result&&f<k-1&&L()&&(V==="captcha"||An(V)||l==="location"&&In(V));if(V==="captcha"?console.warn(JSON.stringify({event:"harvest_attempt_captcha",attempt_number:y,max_attempts:k,message:Q(R),will_retry:$})):$&&console.warn(JSON.stringify({event:"harvest_attempt_proxy_retry",attempt_number:y,max_attempts:k,outcome:V,message:Q(R),will_retry:$})),await ct(a,{type:"finished",attemptNumber:y,maxAttempts:k,outcome:V,\u006b\u0065\u0072\u006e\u0065\u006cSessionId:G.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,questionCount:G.result?.totalQuestions??0,durationMs:Date.now()-T,error:Q(R),willRetry:$,cleanup:G.cleanup,debug:G.debug,completedAt:new Date().toISOString()}),await ce(o,m?.disposableProxyId),B=R,$)continue;if(G.result&&!D){let X=await xn(G.result,A);return Wn(bn(Ln(X,c),b.maxQuestions,b.questionsOnly),f,w.attemptKind==="provider_fallback"?1:0)}break}let q=G.result;if(!q)throw new Error("Harvest attempt completed without a result");if(ri(q,l)){let R=new Zt(di(q)),V=f<k-1&&L();if(console.warn(JSON.stringify({event:"harvest_attempt_location_mismatch",attempt_number:y,max_attempts:k,message:R.message,will_retry:V})),await ct(a,{type:"finished",attemptNumber:y,maxAttempts:k,outcome:"location_mismatch",\u006b\u0065\u0072\u006e\u0065\u006cSessionId:G.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,questionCount:q.totalQuestions,durationMs:Date.now()-T,error:R.message,willRetry:V,cleanup:G.cleanup,debug:G.debug,completedAt:new Date().toISOString()}),await ce(o,m?.disposableProxyId),B=R,V)continue;break}let wt=await xn(q,A),O=Wn(bn(Ln(wt,c),b.maxQuestions,b.questionsOnly),f,w.attemptKind==="provider_fallback"?1:0),Z=ei(O),H=Z==="degraded_result"&&f<k-1&&L(),E=Z==="degraded_result"?ai(O):null;if(H&&console.warn(JSON.stringify({event:"harvest_attempt_degraded_result",attempt_number:y,max_attempts:k,degradation_reasons:O.diagnostics.degradationReasons,will_retry:!0})),await ct(a,{type:"finished",attemptNumber:y,maxAttempts:k,outcome:Z,\u006b\u0065\u0072\u006e\u0065\u006cSessionId:G.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,questionCount:O.totalQuestions,durationMs:Date.now()-T,error:E,willRetry:H,cleanup:G.cleanup,debug:G.debug,completedAt:new Date().toISOString()}),await ce(o,m?.disposableProxyId),H)continue;return(b.format==="json"||b.format==="both")&&await x.writeJSON(O,b.outputDir),(b.format==="csv"||b.format==="both")&&await Promise.all([x.writeCSV(O.flat,b.outputDir),O.videos.length>0?x.writeVideoCSV(O.videos,O.seed,b.outputDir):Promise.resolve(""),O.forums.length>0?x.writeForumCSV(O.forums,O.seed,b.outputDir):Promise.resolve(""),O.aiOverview.detected?x.writeAIOverviewCSV(O.aiOverview.citations,O.aiOverview.text,O.seed,b.outputDir):Promise.resolve(""),O.aiMode.detected?x.writeAIModeCSV(O.aiMode.citations,O.aiMode.text,O.seed,b.outputDir):Promise.resolve(""),O.whatPeopleSaying.length>0?x.writeWhatPeopleSayingCSV(O.whatPeopleSaying,O.seed,b.outputDir):Promise.resolve("")]),O}catch(w){let C=vt(w);(C==="captcha"||C==="proxy_tunnel_failed")&&N==="location"&&(p++,p>=2&&(N="none"));let M=f<k-1&&L()&&(C==="captcha"||An(C)||l==="location"&&In(C));if(C==="captcha"?console.warn(JSON.stringify({event:"harvest_attempt_captcha",attempt_number:y,max_attempts:k,message:Q(w),will_retry:M})):M&&console.warn(JSON.stringify({event:"harvest_attempt_proxy_retry",attempt_number:y,max_attempts:k,outcome:C,message:Q(w),will_retry:M})),await ct(a,{type:"finished",attemptNumber:y,maxAttempts:k,outcome:C,\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,questionCount:0,durationMs:Date.now()-T,error:Q(w),willRetry:M,cleanup:{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:null,browserCloseError:null},debug:null,completedAt:new Date().toISOString()}),B=w,M)continue;if(C==="captcha")break;throw w}}throw B&&!(B instanceof J)?B:(console.warn(JSON.stringify({event:"harvest_captcha_exhausted",max_attempts:k,session_kind:o?"\u006b\u0065\u0072\u006e\u0065\u006c":"local"})),new J(Te(`CAPTCHA on all ${k} fresh sessions. Try again in a few minutes.`)))}export{Si as a,Ot as b,Bt as c,ci as d,De as e,qn as f,Ft as g,Ee as h,Ye as i,_e as j,ze as k,Xe as l,oe as m,ot as n,Vt as o,us as p,Jt as q,cs as r,ws as s,ks as t,vn as u,Nn as v,Fs as w};