mcp-scraper 0.94.0 → 0.94.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -35
- package/README.md +3 -3
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-core.js +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.js +1 -1
- package/dist/bin/paa-harvest.js +1 -1
- package/dist/{chunk-2GEVQBI6.js → chunk-5HALFCAC.js} +1 -1
- package/dist/{chunk-SJRXG3LV.js → chunk-6ND5AFV5.js} +3 -3
- package/dist/chunk-JKHBLSXB.js +6 -0
- package/dist/chunk-M5QHXNFZ.js +3 -3
- package/dist/chunk-NA76FFGD.js +15 -15
- package/dist/chunk-NZSDHDX3.js +1 -1
- package/dist/{chunk-LZEBDJHY.js → chunk-R6TD6OXQ.js} +3 -3
- package/dist/chunk-RK2UKLWP.js +1 -0
- package/dist/chunk-SH5KB4P7.js +1 -1
- package/dist/{chunk-ASP7YHUY.js → chunk-VCK5BJMX.js} +5 -5
- package/dist/chunk-XPEJB4BZ.js +1 -0
- package/dist/chunk-ZPK5LYEN.js +15 -15
- package/dist/chunk-ZUGTYD2I.js +4 -4
- package/dist/index.cjs +21 -21
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +1 -1
- package/dist/{server-SH6KWIEA.js → server-4VUCH5QX.js} +314 -314
- package/dist/{worker-V53ZJGJS.js → worker-5J4KF5RM.js} +1 -1
- package/package.json +137 -17
- package/THIRD_PARTY_NOTICES.html +0 -203
- package/dist/chunk-4SNU2TWB.js +0 -1
- package/dist/chunk-I46JRG5B.js +0 -1
- package/dist/chunk-LCFZSD37.js +0 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{f as nt}from"./chunk-M5QHXNFZ.js";import{b as Pe}from"./chunk-SH5KB4P7.js";import{c as xe,g as Le}from"./chunk-NA76FFGD.js";import{a as Ie,b as Ae,c as Bt}from"./chunk-6DTXIZY2.js";import{c as Lt,e as kt,l as Oe}from"./chunk-I46JRG5B.js";import{a as be,i as We,j as _,k as Ot,m as Z,n as Ct,o as te}from"./chunk-ZPK5LYEN.js";import{z as v}from"zod";var ee=v.object({query:v.string().min(1),location:v.string().optional(),gl:v.string().length(2).default("us"),hl:v.string().length(2).default("en"),device:v.enum(["desktop","mobile"]).default("desktop"),proxyMode:v.enum(["location","configured","none"]).default(Lt),proxyZip:v.string().regex(/^\d{5}$/).optional(),keepDefaultProxy:v.boolean().optional(),requireUsEgress:v.boolean().optional(),maxAttempts:v.number().int().min(1).max(12).optional(),debug:v.boolean().default(!1),depth:v.number().int().min(1).max(30).default(3),maxQuestions:v.number().int().min(1).max(100).default(100),headless:v.boolean().default(!1),profileDir:v.string().optional(),proxy:v.string().url().optional(),\u006b\u0065\u0072\u006e\u0065\u006cApiKey:v.string().optional(),\u006b\u0065\u0072\u006e\u0065\u006cProxyId:v.string().optional(),\u006b\u0065\u0072\u006e\u0065\u006cProfileName:v.string().optional(),\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges:v.boolean().optional(),\u006b\u0065\u0072\u006e\u0065\u006cStealth:v.boolean().optional(),serpIdentity:v.string().regex(/^[a-z0-9][a-z0-9_-]{0,63}$/).optional(),\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution:v.unknown().optional(),outputDir:v.string().default("./paa-output"),format:v.enum(["json","csv","both"]).default("both"),serpOnly:v.boolean().default(!1),questionsOnly:v.boolean().default(!1),questionGrowthRecoveryRounds:v.number().int().min(0).max(4).default(2),pages:v.number().int().min(1).max(2).default(1),includeAllSerpFeatures:v.boolean().default(!1),includeLocalPack:v.boolean().default(!1),includeForums:v.boolean().default(!1),includeVideos:v.boolean().default(!1),includeAiOverview:v.boolean().default(!1),includeWhatPeopleSaying:v.boolean().default(!1),includeShortVideos:v.boolean().default(!1),recency:v.enum(["day","week","month","year"]).optional(),softDeadlineMs:v.number().optional()}),Be=v.object({questionId:v.string().min(1),googleLinkId:v.string().nullable(),googleEvidenceId:v.string().nullable(),question:v.string().min(1),answer:v.string().optional(),sourceTitle:v.string().optional(),sourceSite:v.string().optional(),sourceCite:v.string().optional(),sources:v.array(v.object({title:v.string().nullable(),site:v.string().nullable(),url:v.string().min(1),rawUrl:v.string().min(1),resolvedUrl:v.string().nullable(),linkType:v.enum(["plain","google_url_redirect","google_goto_redirect"]),resolutionStatus:v.enum(["not_needed","resolved","unresolved","rejected"])})).default([])});import{chromium as ie}from"playwright-extra";import En from"puppeteer-extra-plugin-stealth";import{chromium as Yn}from"playwright";var Q={paaItem:".related-question-pair",captchaMarker:'#captcha-form, #recaptcha, form[action*="/sorry/"], .g-recaptcha, [data-sitekey]'},He={container:'div[jscontroller="HWk0Gf"]',sectionHeading:'.mgAbYb[role="heading"]',item:"a.rIRoqf"},Ht={udm:"39",item:"a.rIRoqf",durationPattern:/^\d+:\d+$/,platforms:["YouTube","TikTok","Instagram","Facebook","X"]},Fe={section:".ULSxyf",item:"a.KYg7td.INpicf",title:".hyYc0c",source:".K4ETW"},Re={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"},Ge={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"},De={root:'[data-hveid="CAUQAA"]',wrapper:".Fgyi2e",citations:'.Fgyi2e [data-hveid] a[jsname="pxBnId"]'},Ve={result:".wHYlTd.tF2Cxc",title:"h3.LC20lb",siteName:".VuuXrf",cite:"cite.tjvcx",snippet:".VwiC3b",redditCite:"cite.qLRx3b",ratingWrap:".Y0A0hc",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Ee={headingText:"Businesses",card:".w7Dbne",name:".OSrXXb",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Ye="2026-05-07",yi={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 Ft(e,t,n,a){let s,i=!1,d,U=()=>{},S=()=>a?.reason instanceof DOMException&&a.reason.name==="TimeoutError"?a.reason:new Z,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 Z;if(s=r,await t(r),i)throw new Z;return n(r)})(),l])}finally{i=!0,d&&clearTimeout(d),a?.removeEventListener("abort",h),s&&await o(s)}}var Vn=/\b(?:HeadlessChrome|Chrome|Chromium|Firefox)\/\d+|\bVersion\/\d+.*\bSafari\//;async function Rt(e){try{let t=await e.evaluate(()=>navigator.userAgent);return typeof t=="string"&&Vn.test(t)?t:null}catch{return null}}async function Gt(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 Rt(n)}catch{return null}finally{t&&await t.close().catch(()=>{})}}function pi(e,t){return t?{...e,userAgent:t}:e}ie.use(En());var Kn=180,Jn=3e3,_n=5e3,zn='#search, #rso, a[href] h3, [data-snhf], [role="main"]';function ne(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}function qn(e,t){let n=process.env[e];if(!n)return t;let a=Number(n);return Number.isInteger(a)&&a>0?a:t}function ae(e){return e?e.slice(-6):null}function Ke(e,t){let n=(t??process.env.SERP_REDIRECT_BASE)?.trim().replace(/\/+$/,"");return n?`${n}/g/${Buffer.from(e,"utf8").toString("base64url")}`:e}function jn(e){return e?/united states|u\.?s\.?a?\.?|^us$/i.test(e.trim()):!1}function ct(e){return e instanceof Error?e.message:String(e)}function $n(e){return/\b409\b|conflict|already exists/i.test(ct(e))}function Qn(e){return/\b404\b|not[ _-]?found|already (?:gone|deleted|closed)|does not exist/i.test(ct(e))}async function Zn(e,t){try{await e.profiles.create({name:t})}catch(n){if(!$n(n))throw n}}function Dt(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 Xn(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 Vt=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 nt({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):qn("\u004b\u0045\u0052\u004e\u0045\u004c_BROWSER_TIMEOUT_SECONDS",Kn),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=Bt(),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&&xe.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=ct(u)}let r={sessionId:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,proxyMode:n,requestedProxyIdPresent:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,requestedProxyIdSuffix:ae(t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId),createdProxyIdPresent:typeof h.proxy_id=="string"?!!h.proxy_id:null,createdProxyIdSuffix:ae(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 Yn.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(Dt(t)),this.page=this.context.pages()[0]??await this.context.newPage(),this.debugSnapshot.context.userAgent=await Rt(this.page);else{let u=await Gt(this.browser);this.debugSnapshot.context.userAgent=u,this.context=await this.browser.newContext(Dt(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(!jn(u))throw new _(`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 ie.launchPersistentContext(t.profileDir,{...s,...Dt(t)}),await this.installEsbuildHelperShims(this.context),this.page=await this.context.newPage(),this.debugSnapshot.context.userAgent=await Rt(this.page);else{this.browser=await ie.launch(s);let i=await Gt(this.browser);this.debugSnapshot.context.userAgent=i,this.context=await this.browser.newContext(Dt(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=ae(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=ct(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(ct(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 Ft(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=Ke(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:ne(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 Ot(`page.goto failed: ${o.message} | ${r}`)}if(await this.isSerpChallengeVisible())throw await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!0}),new _(this.captchaMessage());if(i?.purpose==="serp"){await this.page.waitForSelector(zn,{timeout:ne(i.deadlineMs,1500)}).catch(()=>null);let o=await this.page.locator(Q.paaItem).count().catch(()=>0)>0;return await this.updateSerpNavigationDebug(h,U,{hasPaa:o,captchaDetected:!1}),{hasPaa:o}}if(await this.page.waitForSelector(Q.paaItem,{timeout:ne(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 _(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(Q.paaItem).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(Q.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: ${ct(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.":be}async navigateTo(t){let n=process.env.ADS_ARRIVAL_REDIRECT_BASE?.trim(),a=n?Ke(t,n):t;try{if(await this.page.goto(a,{waitUntil:"domcontentloaded",timeout:45e3}),/google\.[^/]+\/search\?/i.test(t)&&await this.isSerpChallengeVisible())throw new _(this.captchaMessage())}catch(s){if(s instanceof _)throw s;let i=await this.captureDiagnostics(t);throw new Ot(`page.goto failed: ${s.message} | ${i}`)}}async navigateToChannel(t){let n=Xn(t);try{await this.page.goto(n,{waitUntil:"networkidle",timeout:3e4})}catch(a){let s=await this.captureDiagnostics(n);throw new Ot(`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),_n,`\u004b\u0065\u0072\u006e\u0065\u006c session ${n} delete`),r=ut(t.close(),Jn,`\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&&Le({\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"&&Qn(u.reason),N={\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:N.\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:N.browserCloseError})),console.warn(`\u004b\u0065\u0072\u006e\u0065\u006c browser close failed for ${n}:`,c.reason)),N}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 na}from"playwright";function ta(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 Je(e){let t=ta(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 _e(e){return Je(e)}function ze(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 se(e,t,n=new Date().toISOString()){let a=Je(t);return{source:e,message:a??e.replaceAll("_"," "),observedAt:n}}function ea(e){return{provider:e.provider,providerDisconnectObserved:e.disconnectObservation!==null,providerDisconnectMessage:e.disconnectObservation?.message??null}}function qe(e){return{...ea(e),providerSessionId:e.providerSessionId}}function oe(){return process.env.\u0042\u0052\u0049\u0047\u0048\u0054\u0044\u0041\u0054\u0041_BROWSER_WSS?.trim()||null}function je(){return process.env.SERP_BROWSER_PROVIDER?.trim().toLowerCase()==="\u006b\u0065\u0072\u006e\u0065\u006c"?!1:!!oe()}var aa=new Set(["image","media","font","stylesheet","ping"]),ia=["doubleclick.net","googleadservices.com","googlesyndication.com","google-analytics.com"],sa='#search, #rso, a[href] h3, [data-snhf], [role="main"]',oa=3e4,$e=1500;function Et(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}async function de(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 Yt=class{constructor(t={}){this.resourcePolicy=t}resourcePolicy;browser=null;context=null;page=null;cdpSession=null;providerSessionId=null;disconnectObservation=null;closing=!1;observeDisconnect(t,n){this.closing||this.disconnectObservation||(this.disconnectObservation=se(t,n))}async launch(t){if(this.page)return;this.closing=!1,this.providerSessionId=null,this.disconnectObservation=null;let n=oe();if(!n)throw new Error("SERP browser service is not configured");this.browser=await na.connectOverCDP(n,{timeout:Et(t.operationDeadlineMs,oa)}),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=ze(s?.sessionId),await this.setupPage(this.page),this.resourcePolicy.startupSettleMs&&await this.page.waitForTimeout(this.resourcePolicy.startupSettleMs)}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 de(n,!0))&&!(i.pathname.includes("/shared_dict/")&&await de(n))&&!(s==="script"&&(d==="www.google.com"||d==="www.gstatic.com")&&await de(n))){if(aa.has(s)&&!(s==="image"&&this.resourcePolicy.allowImages)&&!(s==="stylesheet"&&this.resourcePolicy.allowStylesheets)){await n.abort("blockedbyclient");return}if(ia.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 Ft(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:Et(i?.deadlineMs,i?.purpose==="serp"?8e3:45e3)}),i?.purpose==="serp"?(await this.page.waitForSelector(sa,{timeout:Et(i.deadlineMs,1500)}).catch(()=>null),{hasPaa:await this.page.locator(Q.paaItem).count().catch(()=>0)>0}):{hasPaa:!!await this.page.waitForSelector(Q.paaItem,{timeout:Et(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}get\u0042\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061SessionId(){return this.providerSessionId}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 ${$e}ms`)),$e)})])}catch(s){t=_e(s instanceof Error?s.message:String(s))??"\u0042\u0072\u0069\u0067\u0068\u0074 \u0044\u0061\u0074\u0061 browser close failed",this.disconnectObservation??=se("browser_close_error",t)}finally{n&&clearTimeout(n)}let a=qe(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 Yt:new Vt}var D={container:".eJH8qe.adDDi",dataInitq:"[data-initq]",item:Q.paaItem,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:Q.captchaMarker};var dt={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 Ze=`3, Nanjemoy,Maryland,United States
|
|
1
|
+
import{f as nt}from"./chunk-M5QHXNFZ.js";import{b as Pe}from"./chunk-SH5KB4P7.js";import{c as xe,g as Le}from"./chunk-NA76FFGD.js";import{a as Ie,b as Ae,c as Bt}from"./chunk-6DTXIZY2.js";import{c as Lt,e as kt,l as Oe}from"./chunk-XPEJB4BZ.js";import{a as be,i as We,j as _,k as Ot,m as Z,n as Ct,o as te}from"./chunk-ZPK5LYEN.js";import{z as v}from"zod";var ee=v.object({query:v.string().min(1),location:v.string().optional(),gl:v.string().length(2).default("us"),hl:v.string().length(2).default("en"),device:v.enum(["desktop","mobile"]).default("desktop"),proxyMode:v.enum(["location","configured","none"]).default(Lt),proxyZip:v.string().regex(/^\d{5}$/).optional(),keepDefaultProxy:v.boolean().optional(),requireUsEgress:v.boolean().optional(),maxAttempts:v.number().int().min(1).max(12).optional(),debug:v.boolean().default(!1),depth:v.number().int().min(1).max(30).default(3),maxQuestions:v.number().int().min(1).max(100).default(100),headless:v.boolean().default(!1),profileDir:v.string().optional(),proxy:v.string().url().optional(),kernelApiKey:v.string().optional(),kernelProxyId:v.string().optional(),kernelProfileName:v.string().optional(),kernelProfileSaveChanges:v.boolean().optional(),kernelStealth:v.boolean().optional(),serpIdentity:v.string().regex(/^[a-z0-9][a-z0-9_-]{0,63}$/).optional(),kernelProxyResolution:v.unknown().optional(),outputDir:v.string().default("./paa-output"),format:v.enum(["json","csv","both"]).default("both"),serpOnly:v.boolean().default(!1),questionsOnly:v.boolean().default(!1),questionGrowthRecoveryRounds:v.number().int().min(0).max(4).default(2),pages:v.number().int().min(1).max(2).default(1),includeAllSerpFeatures:v.boolean().default(!1),includeLocalPack:v.boolean().default(!1),includeForums:v.boolean().default(!1),includeVideos:v.boolean().default(!1),includeAiOverview:v.boolean().default(!1),includeWhatPeopleSaying:v.boolean().default(!1),includeShortVideos:v.boolean().default(!1),recency:v.enum(["day","week","month","year"]).optional(),softDeadlineMs:v.number().optional()}),Be=v.object({questionId:v.string().min(1),googleLinkId:v.string().nullable(),googleEvidenceId:v.string().nullable(),question:v.string().min(1),answer:v.string().optional(),sourceTitle:v.string().optional(),sourceSite:v.string().optional(),sourceCite:v.string().optional(),sources:v.array(v.object({title:v.string().nullable(),site:v.string().nullable(),url:v.string().min(1),rawUrl:v.string().min(1),resolvedUrl:v.string().nullable(),linkType:v.enum(["plain","google_url_redirect","google_goto_redirect"]),resolutionStatus:v.enum(["not_needed","resolved","unresolved","rejected"])})).default([])});import{chromium as ie}from"playwright-extra";import En from"puppeteer-extra-plugin-stealth";import{chromium as Yn}from"playwright";var Q={paaItem:".related-question-pair",captchaMarker:'#captcha-form, #recaptcha, form[action*="/sorry/"], .g-recaptcha, [data-sitekey]'},He={container:'div[jscontroller="HWk0Gf"]',sectionHeading:'.mgAbYb[role="heading"]',item:"a.rIRoqf"},Ht={udm:"39",item:"a.rIRoqf",durationPattern:/^\d+:\d+$/,platforms:["YouTube","TikTok","Instagram","Facebook","X"]},Fe={section:".ULSxyf",item:"a.KYg7td.INpicf",title:".hyYc0c",source:".K4ETW"},Re={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"},Ge={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"},De={root:'[data-hveid="CAUQAA"]',wrapper:".Fgyi2e",citations:'.Fgyi2e [data-hveid] a[jsname="pxBnId"]'},Ve={result:".wHYlTd.tF2Cxc",title:"h3.LC20lb",siteName:".VuuXrf",cite:"cite.tjvcx",snippet:".VwiC3b",redditCite:"cite.qLRx3b",ratingWrap:".Y0A0hc",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Ee={headingText:"Businesses",card:".w7Dbne",name:".OSrXXb",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Ye="2026-05-07",yi={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 Ft(e,t,n,a){let s,i=!1,d,U=()=>{},S=()=>a?.reason instanceof DOMException&&a.reason.name==="TimeoutError"?a.reason:new Z,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 Z;if(s=r,await t(r),i)throw new Z;return n(r)})(),l])}finally{i=!0,d&&clearTimeout(d),a?.removeEventListener("abort",h),s&&await o(s)}}var Vn=/\b(?:HeadlessChrome|Chrome|Chromium|Firefox)\/\d+|\bVersion\/\d+.*\bSafari\//;async function Rt(e){try{let t=await e.evaluate(()=>navigator.userAgent);return typeof t=="string"&&Vn.test(t)?t:null}catch{return null}}async function Gt(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 Rt(n)}catch{return null}finally{t&&await t.close().catch(()=>{})}}function pi(e,t){return t?{...e,userAgent:t}:e}ie.use(En());var Kn=180,Jn=3e3,_n=5e3,zn='#search, #rso, a[href] h3, [data-snhf], [role="main"]';function ne(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}function qn(e,t){let n=process.env[e];if(!n)return t;let a=Number(n);return Number.isInteger(a)&&a>0?a:t}function ae(e){return e?e.slice(-6):null}function Ke(e,t){let n=(t??process.env.SERP_REDIRECT_BASE)?.trim().replace(/\/+$/,"");return n?`${n}/g/${Buffer.from(e,"utf8").toString("base64url")}`:e}function jn(e){return e?/united states|u\.?s\.?a?\.?|^us$/i.test(e.trim()):!1}function ct(e){return e instanceof Error?e.message:String(e)}function $n(e){return/\b409\b|conflict|already exists/i.test(ct(e))}function Qn(e){return/\b404\b|not[ _-]?found|already (?:gone|deleted|closed)|does not exist/i.test(ct(e))}async function Zn(e,t){try{await e.profiles.create({name:t})}catch(n){if(!$n(n))throw n}}function Dt(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 Xn(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 Vt=class{browser=null;context=null;page=null;kernelClient=null;kernelSessionId=null;kernelOpenedAtMs=null;kernelStealth=null;kernelProxyUsed=null;kernelProxySource=null;kernelProxyType=null;kernelHeadlessSent=null;lastKernelBillingMode=null;lastKernelOpenedAtMs=null;lastKernelClosedAtMs=null;debugEnabled=!1;debugSnapshot={kernel:null,context:null,networkLocation:null,serpNavigation:null};async launch(t){this.debugEnabled=t.debug===!0;let n=t.proxyMode??(t.kernelProxyId?"configured":"none"),a=t.isMobile?"mobile":"desktop";if(this.debugSnapshot={kernel: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.kernelApiKey){this.kernelClient=new nt({apiKey:t.kernelApiKey});let i=Number.isInteger(t.kernelTimeoutSeconds)&&Number(t.kernelTimeoutSeconds)>0?Number(t.kernelTimeoutSeconds):qn("KERNEL_BROWSER_TIMEOUT_SECONDS",Kn),d=Math.min(i,600);t.kernelProfileName&&t.kernelProfileSaveChanges===!0&&await Zn(this.kernelClient,t.kernelProfileName);let U=Bt(),S;t.headlessMode==="headful"||U?.forceHeadful===!0?S=!1:t.headlessMode==="headless"?S=!0:S=U?.forceHeadless===!0||process.env.KERNEL_HEADLESS_DISABLED!=="true"&&!!U?.op&&xe.has(U.op),this.kernelHeadlessSent=S?!0:null,this.lastKernelBillingMode=S?"headless":"headful",U?.headlessSentOut&&(U.headlessSentOut.value=this.kernelHeadlessSent);let h=await this.kernelClient.browsers.create({stealth:t.kernelStealth===!0,timeout_seconds:d,...S?{headless:!0}:{},...t.kernelProxyId?{proxy_id:t.kernelProxyId}:{},...t.kernelProfileName?{profile:{name:t.kernelProfileName,...typeof t.kernelProfileSaveChanges=="boolean"?{save_changes:t.kernelProfileSaveChanges}:{}}}:{}});this.kernelSessionId=h.session_id,this.kernelOpenedAtMs=Date.now(),this.lastKernelOpenedAtMs=this.kernelOpenedAtMs,this.lastKernelClosedAtMs=null,this.kernelStealth=typeof h.stealth=="boolean"?h.stealth:null,this.kernelProxyUsed=typeof h.proxy_id=="string"?!!h.proxy_id:!!t.kernelProxyId,this.kernelProxySource=t.kernelProxyResolution?.source??null,this.kernelProxyType=t.kernelProxyResolution?.proxyType??null;let l=null,o=null;if(!t.kernelProxyId&&!t.keepDefaultProxy)try{await ut(this.kernelClient.browsers.update(this.kernelSessionId,{disable_default_proxy:!0}),5e3,`Kernel session ${this.kernelSessionId} disable default proxy`),l=!0}catch(u){l=!1,o=ct(u)}let r={sessionId:this.kernelSessionId,proxyMode:n,requestedProxyIdPresent:!!t.kernelProxyId,requestedProxyIdSuffix:ae(t.kernelProxyId),createdProxyIdPresent:typeof h.proxy_id=="string"?!!h.proxy_id:null,createdProxyIdSuffix:ae(h.proxy_id),retrievedProxyIdPresent:null,retrievedProxyIdSuffix:null,retrievedProxyIdMatchesRequested:null,defaultProxyDisabled:l,defaultProxyDisableError:o,proxyResolution:t.kernelProxyResolution??null,timeoutSeconds:d,stealth:typeof h.stealth=="boolean"?h.stealth:null,profilePresent:null,poolPresent:null,retrieveError:null};if(this.debugSnapshot.kernel=r,console.info(JSON.stringify({event:"kernel_browser_created",kernel_session_id:this.kernelSessionId,timeout_seconds:d,proxy_mode:n,proxy_id_present:!!t.kernelProxyId,profile_name_present:!!t.kernelProfileName,proxy_resolution_source:t.kernelProxyResolution?.source})),this.debugEnabled&&await this.populateKernelRetrieveDebug(r,t.kernelProxyId),this.browser=await Yn.connectOverCDP(h.cdp_ws_url),t.kernelProfileName||t.preserveKernelContext)this.context=this.browser.contexts()[0]??await this.browser.newContext(Dt(t)),this.page=this.context.pages()[0]??await this.context.newPage(),this.debugSnapshot.context.userAgent=await Rt(this.page);else{let u=await Gt(this.browser);this.debugSnapshot.context.userAgent=u,this.context=await this.browser.newContext(Dt(t,u)),this.page=await this.context.newPage()}if(await this.installEsbuildHelperShims(this.context),t.preserveKernelContext||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(!jn(u))throw new _(`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 ie.launchPersistentContext(t.profileDir,{...s,...Dt(t)}),await this.installEsbuildHelperShims(this.context),this.page=await this.context.newPage(),this.debugSnapshot.context.userAgent=await Rt(this.page);else{this.browser=await ie.launch(s);let i=await Gt(this.browser);this.debugSnapshot.context.userAgent=i,this.context=await this.browser.newContext(Dt(t,i)),await this.installEsbuildHelperShims(this.context),this.page=await this.context.newPage()}this.debugEnabled&&(this.debugSnapshot.networkLocation=await this.captureBrowserNetworkLocation())}async populateKernelRetrieveDebug(t,n){if(!(!this.kernelClient||!this.kernelSessionId))try{let a=await ut(this.kernelClient.browsers.retrieve(this.kernelSessionId),5e3,`Kernel session ${this.kernelSessionId} retrieve`);t.retrievedProxyIdPresent=typeof a.proxy_id=="string"?!!a.proxy_id:!1,t.retrievedProxyIdSuffix=ae(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=ct(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(ct(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 Ft(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=Ke(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:ne(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 Ot(`page.goto failed: ${o.message} | ${r}`)}if(await this.isSerpChallengeVisible())throw await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!0}),new _(this.captchaMessage());if(i?.purpose==="serp"){await this.page.waitForSelector(zn,{timeout:ne(i.deadlineMs,1500)}).catch(()=>null);let o=await this.page.locator(Q.paaItem).count().catch(()=>0)>0;return await this.updateSerpNavigationDebug(h,U,{hasPaa:o,captchaDetected:!1}),{hasPaa:o}}if(await this.page.waitForSelector(Q.paaItem,{timeout:ne(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 _(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(Q.paaItem).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(Q.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: ${ct(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.kernelClient?"Google returned a CAPTCHA on this session \u2014 retrying with a fresh session.":be}async navigateTo(t){let n=process.env.ADS_ARRIVAL_REDIRECT_BASE?.trim(),a=n?Ke(t,n):t;try{if(await this.page.goto(a,{waitUntil:"domcontentloaded",timeout:45e3}),/google\.[^/]+\/search\?/i.test(t)&&await this.isSerpChallengeVisible())throw new _(this.captchaMessage())}catch(s){if(s instanceof _)throw s;let i=await this.captureDiagnostics(t);throw new Ot(`page.goto failed: ${s.message} | ${i}`)}}async navigateToChannel(t){let n=Xn(t);try{await this.page.goto(n,{waitUntil:"networkidle",timeout:3e4})}catch(a){let s=await this.captureDiagnostics(n);throw new Ot(`navigateToChannel failed: ${a.message} | ${s}`)}}async evaluate(t,n){return this.page.evaluate(t,n)}getPage(){return this.page}getKernelSessionId(){return this.kernelSessionId}getKernelMeteringEvidence(){return{sessionId:this.kernelSessionId??this.debugSnapshot.kernel?.sessionId??null,billingMode:this.lastKernelBillingMode,openedAtMs:this.lastKernelOpenedAtMs,closedAtMs:this.lastKernelClosedAtMs}}getProviderSessionMetadata(){return{provider:this.kernelSessionId?"kernel":"local",providerSessionId:this.kernelSessionId,disconnectObservation:null,billingMode:this.kernelSessionId?this.kernelHeadlessSent?"headless":"headful":null}}getDebugSnapshot(){return this.debugSnapshot}async close(){if(this.browser){let t=this.browser,n=this.kernelSessionId,a=this.kernelClient,s=this.kernelOpenedAtMs,i=this.kernelStealth,d=this.kernelProxyUsed,U=this.kernelProxySource,S=this.kernelProxyType,h=this.kernelHeadlessSent,l=this.getProviderSessionMetadata();if(this.browser=null,this.context=null,this.page=null,this.kernelSessionId=null,this.kernelClient=null,this.kernelOpenedAtMs=null,this.kernelHeadlessSent=null,this.kernelProxySource=null,this.kernelProxyType=null,a&&n){console.info(JSON.stringify({event:"kernel_browser_delete_started",kernel_session_id:n}));let o=ut(a.browsers.deleteByID(n),_n,`Kernel session ${n} delete`),r=ut(t.close(),Jn,`Kernel browser ${n} close`),[u,c]=await Promise.allSettled([o,r]);this.lastKernelClosedAtMs=Date.now(),s!=null&&Le({kernelSessionId:n,source:"browser_driver",stealth:i,headlessSent:h,proxyUsed:d,proxySource:U,proxyType:S,openedAtMs:s,closedAtMs:this.lastKernelClosedAtMs});let g=u.status==="rejected"&&Qn(u.reason),N={kernelSessionId:n,kernelDeleteStarted:!0,kernelDeleteSucceeded:u.status==="fulfilled"||g,kernelDeleteError: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:"kernel_browser_delete_failed",kernel_session_id:n,message:N.kernelDeleteError})),console.warn(`Kernel session cleanup failed for ${n}:`,u.reason)):console.info(JSON.stringify({event:"kernel_browser_delete_succeeded",kernel_session_id:n})),c.status==="rejected"&&(console.warn(JSON.stringify({event:"kernel_browser_close_failed",kernel_session_id:n,message:N.browserCloseError})),console.warn(`Kernel browser close failed for ${n}:`,c.reason)),N}return await t.close(),{kernelSessionId:null,kernelDeleteStarted:!1,kernelDeleteSucceeded:null,kernelDeleteError: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(),{kernelSessionId:null,kernelDeleteStarted:!1,kernelDeleteSucceeded:null,kernelDeleteError:null,browserCloseSucceeded:!0,browserCloseError:null,provider:"local",providerSessionId:null,providerDisconnectObserved:!1,providerDisconnectMessage:null}}return{kernelSessionId:null,kernelDeleteStarted:!1,kernelDeleteSucceeded:null,kernelDeleteError:null,browserCloseSucceeded:null,browserCloseError:null,provider:"local",providerSessionId:null,providerDisconnectObserved:!1,providerDisconnectMessage:null}}};import{chromium as na}from"playwright";function ta(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 Je(e){let t=ta(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 _e(e){return Je(e)}function ze(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("Bright Data did not return a valid browser session ID");return e}function se(e,t,n=new Date().toISOString()){let a=Je(t);return{source:e,message:a??e.replaceAll("_"," "),observedAt:n}}function ea(e){return{provider:e.provider,providerDisconnectObserved:e.disconnectObservation!==null,providerDisconnectMessage:e.disconnectObservation?.message??null}}function qe(e){return{...ea(e),providerSessionId:e.providerSessionId}}function oe(){return process.env.BRIGHTDATA_BROWSER_WSS?.trim()||null}function je(){return process.env.SERP_BROWSER_PROVIDER?.trim().toLowerCase()==="kernel"?!1:!!oe()}var aa=new Set(["image","media","font","stylesheet","ping"]),ia=["doubleclick.net","googleadservices.com","googlesyndication.com","google-analytics.com"],sa='#search, #rso, a[href] h3, [data-snhf], [role="main"]',oa=3e4,$e=1500;function Et(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}async function de(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 Yt=class{constructor(t={}){this.resourcePolicy=t}resourcePolicy;browser=null;context=null;page=null;cdpSession=null;providerSessionId=null;disconnectObservation=null;closing=!1;observeDisconnect(t,n){this.closing||this.disconnectObservation||(this.disconnectObservation=se(t,n))}async launch(t){if(this.page)return;this.closing=!1,this.providerSessionId=null,this.disconnectObservation=null;let n=oe();if(!n)throw new Error("SERP browser service is not configured");this.browser=await na.connectOverCDP(n,{timeout:Et(t.operationDeadlineMs,oa)}),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=ze(s?.sessionId),await this.setupPage(this.page),this.resourcePolicy.startupSettleMs&&await this.page.waitForTimeout(this.resourcePolicy.startupSettleMs)}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 de(n,!0))&&!(i.pathname.includes("/shared_dict/")&&await de(n))&&!(s==="script"&&(d==="www.google.com"||d==="www.gstatic.com")&&await de(n))){if(aa.has(s)&&!(s==="image"&&this.resourcePolicy.allowImages)&&!(s==="stylesheet"&&this.resourcePolicy.allowStylesheets)){await n.abort("blockedbyclient");return}if(ia.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 Ft(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:Et(i?.deadlineMs,i?.purpose==="serp"?8e3:45e3)}),i?.purpose==="serp"?(await this.page.waitForSelector(sa,{timeout:Et(i.deadlineMs,1500)}).catch(()=>null),{hasPaa:await this.page.locator(Q.paaItem).count().catch(()=>0)>0}):{hasPaa:!!await this.page.waitForSelector(Q.paaItem,{timeout:Et(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}getKernelSessionId(){return null}getBrightDataSessionId(){return this.providerSessionId}getProviderSessionMetadata(){return{provider:"bright_data_browser_api",providerSessionId:this.providerSessionId,disconnectObservation:this.disconnectObservation}}getDebugSnapshot(){return{kernel: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 ${$e}ms`)),$e)})])}catch(s){t=_e(s instanceof Error?s.message:String(s))??"Bright Data browser close failed",this.disconnectObservation??=se("browser_close_error",t)}finally{n&&clearTimeout(n)}let a=qe(this.getProviderSessionMetadata());return this.browser=null,this.context=null,this.page=null,this.cdpSession=null,{kernelSessionId:null,kernelDeleteStarted:!1,kernelDeleteSucceeded:null,kernelDeleteError:null,browserCloseSucceeded:t===null,browserCloseError:t,...a}}};function Qe(e){return e.plannedProvider==="brightdata"?new Yt:new Vt}var D={container:".eJH8qe.adDDi",dataInitq:"[data-initq]",item:Q.paaItem,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:Q.captchaMarker};var dt={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 Ze=`3, Nanjemoy,Maryland,United States
|
|
2
2
|
Aaronsburg,Pennsylvania,United States
|
|
3
3
|
Abbeville,Alabama,United States
|
|
4
4
|
Abbeville,Georgia,United States
|
|
@@ -21701,10 +21701,10 @@ Zwolle,Louisiana,United States`,Xe={ad:"Andorra",ae:"United Arab Emirates",af:"A
|
|
|
21701
21701
|
|
|
21702
21702
|
`).trim();return!A||/not available|try again|can't generate/i.test(A)?null:A}function h(y){if(!y||y.startsWith("javascript:"))return null;try{let P=new URL(y,window.location.href);return!["http:","https:"].includes(P.protocol)||P.username||P.password?null:{href:P.href,rawHref:P.href}}catch{return null}}function l(y){if(!y)return[];let P=new Set,w=[];for(let M of Array.from(y.querySelectorAll("a[href]"))){let k=h(M.getAttribute("href")??"");if(!k||P.has(k.rawHref))continue;P.add(k.rawHref);let m="";try{m=new URL(k.href).hostname.replace(/^www\./,"")}catch{}w.push({text:s(M)||m||k.href,href:k.href,rawHref:k.rawHref})}return w}async function o(y){let P=y.querySelector(t.aio.showMoreButton);if(!P||P.getAttribute("aria-expanded")!=="false")return!1;P.click();let w=t.expandWaitMs??1500;return w>0&&await new Promise(M=>setTimeout(M,w)),!0}let r=U(),u=null,c=[],g=!1,N=!1,b=[];if(r){g=await o(r);let y=r.querySelector(t.aio.controller),P=r.querySelector(t.aio.contentSubtree),w=r.querySelector(t.aio.showMoreButton);N=y?.getAttribute("data-trnct")==="false"||w?.getAttribute("aria-expanded")==="true"||!w,u=S(P??y??r),b=(u??"").split(`
|
|
21703
21703
|
`).map(M=>M.trim()).filter(M=>/^\d+\.\s+.+/.test(M)),c=l(r)}let C=document.querySelector(t.aim.root),x=a==="aim"&&!!C,O=C?.closest(t.aim.wrapper)??C,H=x?S(O):null,f=x&&i(H),p=f?H:null,L=f?l(O):[],T=!!r&&i(u);return{surface:a,aiOverview:{detected:T,text:T?u:null,citations:T?c:[],expanded:T?g:!1,fullyExpanded:T?N:!1,sections:T?b:[]},aiMode:{detected:f&&p!==null,text:p,citations:L}}}import{createHash as pa}from"crypto";var Un=8e3,hn=3e3,un=1e4,ma=8;function it(e){return/(^|\.)google\.(?:com|[a-z]{2,3}(?:\.[a-z]{2})?)$/i.test(e)}function vt(e){if(!e||e.length>Un)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 va(e,t){if(!e||e.length>Un||/^javascript:/i.test(e))return null;try{let n=new URL(e,t);return vt(n.href)}catch{return null}}function mt(e){let t=vt(e);return!t||t.protocol!=="https:"||!it(t.hostname)||t.pathname!=="/goto"?null:t.searchParams.get("url")?t:null}function he(e){if(e.linkType!=="google_goto_redirect"||e.resolutionStatus!=="resolved"||!mt(e.rawUrl)||!e.resolvedUrl)return!1;let t=vt(e.resolvedUrl);return!!(t&&!it(t.hostname)&&t.href===e.resolvedUrl&&e.url===t.href)}function rt(e){let t=e.normalize("NFKC").toLocaleLowerCase("en-US").replace(/[^\p{L}\p{N}\s]/gu,"").replace(/\s+/g," ").trim();return`paa_${pa("sha256").update(t).digest("hex").slice(0,16)}`}function Jt(e,t){let n=va(e,t);if(!n)return null;let a=n.href;if(!it(n.hostname))return{url:a,rawUrl:a,resolvedUrl:a,linkType:"plain",resolutionStatus:"not_needed"};if(n.pathname==="/url"){let s=vt(n.searchParams.get("q")??n.searchParams.get("url")??"");return!s||it(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 ue(e){return mt(e)?.searchParams.get("url")??null}function cn(e,t){try{let n=new URL(e),a=vt(new URL(t,n).href);return!a||it(a.hostname)?null:(!a.hash&&n.hash&&(a.hash=n.hash),a.href)}catch{return null}}async function wn(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??hn),U=Date.now()+Math.max(1,t.totalBudgetMs??un),S=Math.max(1,Math.min(16,Math.floor(t.concurrency??ma))),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 N=U-Date.now();if(N<=0)return;let b=new AbortController,C=setTimeout(()=>b.abort(),Math.min(d,N)),x;try{x=await i(c,{method:"GET",redirect:"manual",headers:{accept:"*/*","user-agent":"Mozilla/5.0"},signal:b.signal})}catch{break}finally{clearTimeout(C)}if(x.status<300||x.status>=400)break;let O=x.headers.get("location");if(!O)break;let H=cn(o,O);if(H){a.set(o,{rawUrl:o,resolvedUrl:H,resolutionStatus:"resolved"});break}let f;try{f=new URL(O,c)}catch{a.set(o,{rawUrl:o,resolvedUrl:null,resolutionStatus:"rejected"});break}if(!it(f.hostname)||ue(f.href)!==u){a.set(o,{rawUrl:o,resolvedUrl:null,resolutionStatus:"rejected"});break}c=f.href}}};return await Promise.all(Array.from({length:Math.min(S,n.length)},()=>l())),{resolutions:[...a.values()],nonGoogleRequestsObserved:0}}function Sn(e,t){try{return new URL(e.resolvedUrl??e.url).hostname.replace(/^www\./,"")}catch{return t}}async function gn(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 wn(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:Sn(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:Sn(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 yn(e,t,n={}){let a=new Map;for(let r of t){let u=a.get(r.rawUrl);u&&he(u)||a.set(r.rawUrl,r.linkType==="google_goto_redirect"&&!he(r)?{...r,url:r.rawUrl,resolvedUrl:null,resolutionStatus:"unresolved"}:r)}let s=[...a.values()].filter(r=>r.linkType==="google_goto_redirect"&&!he(r));if(s.length===0)return a;let i=Date.now()+(n.totalBudgetMs??un),d=await wn(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??hn,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{it(new URL(u).hostname)||(o+=1)}catch{}let c=ue(u);if(!l||c!==l.token){await r.abort("blockedbyclient").catch(()=>{});return}let g=l;try{let N=await r.fetch({maxRedirects:0,timeout:g.timeoutMs});g.location=N.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 N=Math.min(S,u);c.hash="";let b=c.href,C=!1;for(let x=0;x<2;x++){let O,H=new Promise(y=>{O=y}),f=`mcp-goto-${Math.random().toString(36).slice(2)}`;l={token:g,timeoutMs:N,location:null,finish:O},await h.evaluate(({url:y,id:P})=>{let w=document.createElement("iframe");w.id=P,w.hidden=!0,w.src=y,document.body.append(w)},{url:b,id:f}).catch(()=>null),await Promise.race([H,new Promise(y=>setTimeout(y,N))]);let p=l.location;if(l=null,await h.evaluate(y=>document.getElementById(y)?.remove(),f).catch(()=>null),!p)break;let L=cn(r.rawUrl,p);if(L){a.set(r.rawUrl,{...r,url:L,resolvedUrl:L,resolutionStatus:"resolved"});break}let T;try{T=new URL(p,b)}catch{C=!0;break}if(!it(T.hostname)||ue(T.href)!==g){C=!0;break}b=T.href}C&&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 Mn=String.raw`^(?:an error has occurred(?:[.!…]\s*)?(?:please try again later[.!…]?)?|loading|please wait|try again|something went wrong)[.!…\s]*$`,Na=700,fa=1e3,Ta=1400,kn=900,Pa=3,Cn=250,_t=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=Jt(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,...N})=>({...N,url:g})),...i.citations.map(({text:c,href:g,...N})=>({...N,url:g}))],S=new Map(U.map(c=>[c.rawUrl,c])),h=0,l=await yn(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:N,...b}=g;return{...b,text:c.text,href:N}};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 Z}async throwIfCaptcha(t,n){if(await t.locator(D.captchaMarker).count().catch(()=>0)>0)throw new _(`${n} returned a CAPTCHA \u2014 retrying with a fresh session.`)}async extractVisibleItems(t,n){let a=D,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),N=c?.querySelector(d.aiAnswerBody)??c,b=h(N),C=new RegExp(S,"i").test(b),x=[...Array.from((N??o).querySelectorAll("a[href]")),...Array.from(o.querySelectorAll(d.aiCitation)),...Array.from(o.querySelectorAll(d.aiSourceCard))],O=!C&&(u&&b.length>=10||b.length>30&&x.some(L=>/^https?:\/\//.test(L.href))),H=O&&o.querySelector(d.sourceTitle)?.innerText?.trim()||void 0,f=O&&o.querySelector(d.sourceSite)?.innerText?.trim()||void 0,p=[];if(O){let L=new Set;for(let y of x)!/^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 T=p.find(y=>y.title.length>2)??p[0];T&&(H=H||T.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:O&&b||void 0,sourceTitle:H,sourceSite:f,sources:p}})},{selectors:a,onlyQuestion:n,answerPlaceholderPattern:Mn}),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=Jt(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:rt(d.question),googleLinkId:d.googleLinkId,googleEvidenceId:d.googleEvidenceId,question:d.question,answer:rn(d.answer,d.question,d.sourceTitle),sourceTitle:h?.title??d.sourceTitle,sourceSite:h?.site??d.sourceSite,sourceCite:h?.url,sources:U},o=Be.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(`${D.item}[data-q="${n}"], ${D.item}[data-initq="${n}"]`).first().click()}catch{}}toFlatRow(t,n,a,s){return{seed_query:s,question_id:t.questionId??rt(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:D.item,dataQ:D.itemDataQ,dataInitQ:D.itemDataInitQ,questionEl:D.itemQuestionEl,answerSel:D.answerContainer,expandedClass:D.expandedClass,clickTarget:D.clickTarget,answerPlaceholderPattern:Mn,questionsOnly:n.questionsOnly,sourceSel:"a[href]"},N=()=>t.evaluate(({sel:f,dataQ:p,dataInitQ:L,questionEl:T,expandedClass:y,clickTarget:P,answerSel:w,answerPlaceholderPattern:M,questionsOnly:k})=>{let m=A=>{if(!A)return"";let W=[];for(let I of A.childNodes){if(I.nodeType===Node.TEXT_NODE){let J=I.textContent?.trim();J&&W.push(J);continue}if(I.nodeType!==Node.ELEMENT_NODE)continue;let V=I;if(V.tagName==="STYLE"||V.tagName==="SCRIPT"||V.getAttribute("aria-hidden")==="true")continue;let q=m(V);q&&W.push(q)}return W.join(" ").replace(/\s+/g," ").trim()};return Array.from(document.querySelectorAll(f)).map((A,W)=>{let I=m(A.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(),V=A.classList.contains(y)||A.querySelector(P)?.getAttribute("aria-expanded")==="true",q=I.length>=10&&!new RegExp(M,"i").test(I);return{q:A.getAttribute(p)||A.getAttribute(L)||A.querySelector(T)?.innerText?.trim()||"",done:V&&(k||q),expanded:V,index:W}}).filter(A=>A.q)},g),b=async(f,p,L,T,y,P)=>{let w=Date.now(),M={id:`${P}:${rt(f)}:${y}`,questionId:rt(f),question:f,batchNumber:P,controlAttempt:y,observedAt:new Date(w).toISOString(),beforeQuestionCount:p,expandedBefore:T},k=L>=0?t.locator(g.sel).nth(L).locator(g.clickTarget):null,m=null,A=k?await(async()=>(T&&(await k.click({timeout:kn,force:!0}),await t.waitForTimeout(120)),await k.click({timeout:kn,force:!0}),!0))().catch(B=>(m=B instanceof Error&&(B.name==="TimeoutError"||/timeout/i.test(B.message))?"click_ack_timeout":"click_failed",!1)):!1,W=Date.now()-w;if(!A&&m!=="click_ack_timeout")return{dispatched:!1,confirmed:!1,observation:{...M,dispatched:!1,outcome:"dispatch_failed",confirmationSignals:[],confirmationCheckpointMs:null,confirmedAtMs:null,dispatchDurationMs:W,totalDurationMs:W,afterQuestionCount:p,newQuestionCount:0,expandedAfter:T,answerObserved:!1,sourceCount:0,errorCode:L<0?"control_missing":m??"click_failed"}};let I={exists:!0,expanded:T,answerReady:!1,sourceCount:0,questionCount:p},V=[],q=null,J=null,G=!1;for(let B of[Na,fa,Ta]){let tt=w+B-Date.now();if(tt>0&&await t.waitForTimeout(tt),I=await t.evaluate(({sel:F,dataQ:K,dataInitQ:R,questionEl:E,expandedClass:$,clickTarget:et,answerSel:Pt,answerPlaceholderPattern:St,sourceSel:bt,target:Mt})=>{let Wt=ht=>{if(!ht)return"";let Xt=[];for(let At of ht.childNodes){if(At.nodeType===Node.TEXT_NODE){let Te=At.textContent?.trim();Te&&Xt.push(Te);continue}if(At.nodeType!==Node.ELEMENT_NODE)continue;let xt=At;if(xt.tagName==="STYLE"||xt.tagName==="SCRIPT"||xt.getAttribute("aria-hidden")==="true")continue;let fe=Wt(xt);fe&&Xt.push(fe)}return Xt.join(" ").replace(/\s+/g," ").trim()},Ut=Array.from(document.querySelectorAll(F)),It=Ut.find(ht=>(ht.getAttribute(K)||ht.getAttribute(R)||ht.querySelector(E)?.innerText?.trim())===Mt);if(!It)return{exists:!1,expanded:!1,answerReady:!1,sourceCount:0,questionCount:Ut.length};let Gn=It.classList.contains($)||It.querySelector(et)?.getAttribute("aria-expanded")==="true",me=It.querySelector(Pt),ve=Wt(me).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(),Ne=ve.length>=10&&!new RegExp(St,"i").test(ve);return{exists:!0,expanded:Gn,answerReady:Ne,sourceCount:Ne?me?.querySelectorAll(bt).length??0:0,questionCount:Ut.length}},{...g,target:f}).catch(()=>I),V=[...I.expanded?["expanded"]:[],...I.answerReady?["answer"]:[],...I.sourceCount>0?["source"]:[],...I.questionCount>p?["question_growth"]:[]],I.answerReady||I.sourceCount>0||I.questionCount>p){G=!0,q=B,J=Date.now()-w;break}}let j=Date.now()-w,yt={...M,dispatched:A,outcome:G?"confirmed":A?"unconfirmed":"dispatch_failed",confirmationSignals:V,confirmationCheckpointMs:q,confirmedAtMs:J,dispatchDurationMs:W,totalDurationMs:j,afterQuestionCount:I.questionCount,newQuestionCount:Math.max(0,I.questionCount-p),expandedAfter:I.expanded,answerObserved:I.answerReady,sourceCount:I.sourceCount,errorCode:A?G?null:I.exists?"confirmation_timeout":"control_missing":m};return{dispatched:A,confirmed:G,observation:yt}},C=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 f=await N(),p=!1;for(let w of f)i.has(w.q)||(i.add(w.q),d.push(w.q),d.length<=n.maxQuestions&&(p=this.upsertCollectedRow(this.toFlatRow({questionId:rt(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:f.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,M=new Set(d.slice(0,n.maxQuestions));for(let k of await this.extractVisibleItems(t)){if(!M.has(k.question))continue;let m=o.get(k.question),A={...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,A),w=this.upsertCollectedRow(this.toFlatRow(A,1,null,n.query))||w}if(w&&await this.emitProgress("answer_captured"),[...M].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)),T=f.filter(w=>L.has(w.q)&&!w.done&&(S.get(w.q)??0)<r&&!U.has(w.q)),y=T.slice(-Pa);if(this.paaLifecycle={...this.paaLifecycle,eligibleControls:T.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(f.map(k=>k.q)),M=d.slice(0,n.maxQuestions).filter(k=>!h.has(k)&&(l.has(k)||!w.has(k)));if(M.length>0)throw this.paaLifecycle={...this.paaLifecycle,discoveryStatus:"interrupted",failedInteractions:new Set([...l,...M]).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:W,min:I})=>document.querySelectorAll(W).length>I,{sel:D.item,min:f.length},{timeout:1500,polling:100}).catch(()=>null);if(this.paaLifecycle={...this.paaLifecycle,noGrowthConfirmations:k},m||(await N()).some(W=>!i.has(W.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(++C),(S.get(w.q)??0)>0){let M=this.paaLifecycle.retryBreakdown.controlRetries+1;this.paaLifecycle={...this.paaLifecycle,automaticRetries:M+this.paaLifecycle.retryBreakdown.browserRetries+this.paaLifecycle.retryBreakdown.runtimeRecoveries,retryBreakdown:{...this.paaLifecycle.retryBreakdown,controlRetries:M}}}S.set(w.q,(S.get(w.q)??0)+1)}let P=await Promise.all(y.map(async w=>({target:w,result:await b(w.q,f.length,w.index,w.expanded,S.get(w.q)??1,c)})));for(let{target:w,result:M}of P)(M.dispatched||M.confirmed)&&this.clickedQuestions.add(w.q),this.interactionObservations.push(M.observation);if(this.interactionObservations.length>Cn&&this.interactionObservations.splice(0,this.interactionObservations.length-Cn),!n.questionsOnly){let w=new Set(y.map(M=>M.q));for(let M of await this.extractVisibleItems(t))w.has(M.question)&&(o.set(M.question,M),this.upsertCollectedRow(this.toFlatRow(M,1,null,n.query))&&await this.emitProgress("answer_captured"))}for(let{target:w,result:M}of P){let k=o.get(w.q);M.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 x=n.questionsOnly?new Map:new Map(o);n.questionsOnly||await this.fillIncompleteItems(t,d,x,n,U);let O=[];for(let f of d){if(O.length>=n.maxQuestions)break;let p=this.normalizeQuestion(f);if(s.has(p))continue;s.add(p);let L=x.get(f);if(L){let T=this.toFlatRow(L,1,null,n.query);this.upsertCollectedRow(T),O.push(T),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 T=this.toFlatRow({questionId:rt(f),googleLinkId:null,googleEvidenceId:null,question:f,answer:void 0,sourceTitle:void 0,sourceSite:void 0,sourceCite:void 0,sources:[]},1,null,n.query);this.upsertCollectedRow(T),O.push(T)}}this.completeness.paaWithoutAnswer=n.questionsOnly?0:O.filter(f=>!f.answer).length,this.completeness.paaWithoutSource=n.questionsOnly?0:O.filter(f=>(f.sources??[]).length===0).length,this.completeness.paaRequested=n.maxQuestions,this.completeness.paaReturned=O.length,this.completeness.paaUnique=s.size;let H=!n.questionsOnly&&(this.completeness.paaWithoutAnswer>0||this.completeness.paaWithoutSource>0);return this.paaLifecycle={...this.paaLifecycle,questionsFound:O.length,targetStatus:O.length>=n.maxQuestions?"met":"not_met",materialStatus:H?"partial":"complete",processedQuestions:h.size,failedInteractions:l.size},await this.emitProgress("fill_incomplete"),await this.emitProgress("expansion_finished"),O}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=`${D.item}:not(.${D.expandedClass}) ${D.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=He;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(),b=u.slice(c+7).replace(/^[·\s·]+/,"").match(/^([^·\n]+)/),C=b?b[1].trim():"";g&&s.push({type:h,title:g,channel:C,platform:"YouTube",duration:"",url:r})}}return s},n)}async extractForums(t){let n=Fe;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:Ht.item,platforms:[...Ht.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(C=>/^\d+:\d+$/.test(C))??"",c=r.find(C=>!/^\d+:\d+$/.test(C)&&C.length>5)??"";if(!c)continue;let g=c,N="",b="";for(let C of i.platforms){let x=-1,O=0;for(;;){let T=c.indexOf(C,O);if(T===-1)break;x=T,O=T+1}if(x===-1)continue;let H=c.slice(x+C.length);if(!(/^[\s·]/.test(H)||H.trim()===""))continue;g=c.slice(0,x).trim(),N=C;let p=H.replace(/^[\s·]+/,""),L=p.indexOf("\xB7");b=(L===-1?p:p.slice(0,L)).trim();break}g&&U.push({title:g,channel:b,platform:N,duration:u,url:o})}return U},a)).map(i=>({type:"short_video",...i}))}async extractWhatPeopleSaying(t){let n=Re;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()??"",N=i.querySelector(a.authorNote)?.textContent?.trim()??null,b=i.querySelector(a.popularCommentLabel),C=null;if(b){let m=b.nextSibling;for(;m;){let A=m.textContent?.trim();if(A){C=A;break}m=m.nextSibling}}let x=Array.from(i.querySelectorAll("span")),O=x.find(m=>/^\d+:\d+$/.test(m.textContent?.trim()??""))?.textContent?.trim()??null,f=x.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=x.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]??""),T=u||(c?"YouTube":""),y=c||o,P="unknown",w=T.toLowerCase(),M=y.toLowerCase(),k=o.toLowerCase();return w.includes("reddit")||M.startsWith("r/")?P="reddit":w.includes("facebook")||k.includes("facebook")?P="facebook":w.includes("instagram")||k.includes("instagram")?P="instagram":w.includes("tiktok")||k.includes("tiktok")?P="tiktok":w.includes("youtube")||c?P="youtube":P="news",{type:P,title:l,url:U,source:y,platform:T,popularComment:C,engagement:f,date:L,duration:O,authorNote:N}}):[]},n)}async extractOrganicResults(t){let n=Ve,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),N=S.querySelector(i.ratingWrap),b=N?{value:N.querySelector(i.ratingValue)?.textContent?.trim()??"",count:N.querySelector(i.reviewCount)?.textContent?.trim()??""}:null,C="";try{C=new URL(r).hostname.replace(/^www\./,"")}catch{C=S.querySelector(i.siteName)?.textContent?.trim()??""}d.push({position:U,title:l,url:r,domain:C,cite:u,snippet:c,isRedditStyle:g,inlineRating:b})}),d},n),s=typeof t.url=="function"?t.url():"https://www.google.com/";return a.flatMap(i=>{let d=Jt(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=Ee;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 b of Array.from(d.querySelectorAll("a[href]"))){let C=b.href.match(/[?&]cid=(\d+)/);if(C){r=C[1];break}let x=b.href.match(/!1s0x[0-9a-f]+:0x([0-9a-f]+)/i);if(x){try{r=BigInt("0x"+x[1]).toString()}catch{}if(r)break}}let u=[];d.querySelectorAll("div, span").forEach(b=>{let C=Array.from(b.childNodes).filter(x=>x.nodeType===3).map(x=>x.textContent?.trim()??"").filter(x=>x.length>1&&x.length<120).join(" ");C&&!u.includes(C)&&u.push(C)});let c=Array.from(d.querySelectorAll("a[href]")),g=c.find(b=>b.href.includes("google.com/maps"))?.href??null,N=c.find(b=>!b.href.includes("google.com")&&b.href.startsWith("http"))?.href??null;s.push({position:U+1,name:S,cid:r,rating:h,reviewCount:o,metadata:u,websiteUrl:N,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(ln,{aio:Ge,aim:De,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 Z)throw i;return{organic:[],status:"failed",failureCode:s??(i instanceof _?"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(F){console.warn(JSON.stringify({event:"paa_provider_session_sink_failed",provider:h.provider,message:F instanceof Error?F.message:String(F)}))}this.throwIfAborted(n);let l=t.location?Se(t.location):null,o=t.location?l?.canonical??t.location:null,r=o?nn(o):null,u=t,c=t.includeAllSerpFeatures,g=c||t.includeLocalPack,N=c||t.includeForums,b=c||t.includeVideos,C=c||t.includeAiOverview,x=c||t.includeWhatPeopleSaying,O={surface:"web",aiOverview:{detected:!1,text:null,citations:[]},aiMode:{detected:!1,text:null,citations:[]}},H=Date.now(),{hasPaa:f}=await this.driver.navigateToSERP(u.query,r,t.gl,t.hl,{...kt(t.recency)?{tbs:kt(t.recency)}:{},debug:t.debug,purpose:t.serpOnly?"serp":"paa",...t.softDeadlineMs?{deadlineMs:t.softDeadlineMs}:{}});this.phaseTimings.navigationMs=Date.now()-H,this.throwIfAborted(n);let p=this.driver.getPage();if(await this.throwIfCaptcha(p,"Google SERP"),f||(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 F=Date.now(),K=f?await this.runBFS(p,u,n):[];this.phaseTimings.paaExpansionMs=Date.now()-F,await this.resolveMaterialLinks(p,K,[],O.aiOverview,O.aiMode);let R={seed:u.query,totalQuestions:K.length,maxDepthReached:K.reduce((E,$)=>Math.max(E,$.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:f?"paa_found":"no_paa",...f?{}:{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:K.length,surface:"web",aiOverview:{detected:!1,text:null,citations:[]},aiMode:{detected:!1,text:null,citations:[]},whatPeopleSaying:[],tree:this.buildTree(K,u.query),flat:K,videos:[],forums:[],organicResults:[],localPack:[],entityIds:{entities:[],kgIds:[],cids:[],gcids:[]},stats:R}}if(C&&(this.aioShareUrlEarly=await this.captureAIOverviewShareUrl(p,t).catch(()=>null)),t.serpOnly){let F=Date.now(),[K,R,E]=await Promise.all([this.extractOrganicResults(p),g?this.extractLocalPack(p):Promise.resolve([]),this.extractEntityIds(p)]),$=this.mergeLocalPackIntoEntities(E,R),et=C?await this.extractAISurfaces(p,t):O;this.phaseTimings.serpParseMs=Date.now()-F;let Pt=t.debug?pt(o,K,R):void 0,St=K;if((t.pages??1)>=2){let Mt=new URLSearchParams({q:u.query,gl:t.gl,hl:t.hl,pws:"0",start:"10"});kt(t.recency)&&Mt.set("tbs",kt(t.recency)),r&&Mt.set("uule",r),await this.driver.navigateTo("https://www.google.com/search?"+Mt.toString()),await this.throwIfCaptcha(p,"Google SERP page 2");let Wt=await this.extractOrganicResults(p);St=[...K,...Wt.map(Ut=>({...Ut,position:Ut.position+10}))],t.debug&&(Pt=pt(o,St,R))}await this.resolveMaterialLinks(p,[],St,et.aiOverview,et.aiMode);let bt={seed:u.query,totalQuestions:0,maxDepthReached:0,durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(bt),{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,Pt,l)}:{}},totalQuestions:0,surface:et.surface,aiOverview:et.aiOverview,aiMode:et.aiMode,whatPeopleSaying:[],tree:[],flat:[],videos:[],forums:[],organicResults:St,localPack:R,entityIds:$,stats:bt}}let[L,T,y,P,w,M]=await Promise.all([b?this.extractVideos(p):Promise.resolve([]),N?this.extractForums(p):Promise.resolve([]),x?this.extractWhatPeopleSaying(p):Promise.resolve([]),this.extractEntityIds(p),this.extractOrganicResults(p),g?this.extractLocalPack(p):Promise.resolve([])]),k=this.mergeLocalPackIntoEntities(P,M),m=t.debug?pt(o,w,M):void 0;this.reporter.onVideos(L),this.reporter.onForums(T);let A=C?await this.extractAISurfaces(p,t):O,W={requestedPages:(t.pages??1)>=2?2:1,capturedPages:1,page2Status:(t.pages??1)>=2?"not_attempted":"not_requested",page1OrganicCount:w.length,page2OrganicCount:0},I=w;if(this.checkpointMaterial={surface:A.surface,aiOverview:A.aiOverview,aiMode:A.aiMode,whatPeopleSaying:y,videos:L,forums:T,organicResults:I,localPack:M,entityIds:k,pagination:W},await this.emitProgress("serp_captured"),W.requestedPages===2){let F=await this.captureSecondOrganicPage(p,u,n);I=[...w,...F.organic],W={...W,capturedPages:F.status==="captured"?2:1,page2Status:F.status,page2OrganicCount:F.organic.length,...F.failureCode?{failureCode:F.failureCode}:{}},this.checkpointMaterial={...this.checkpointMaterial,organicResults:I,pagination:W},await this.emitProgress("serp_captured"),await this.resolveMaterialLinks(p,[],I,A.aiOverview,A.aiMode),this.checkpointMaterial={...this.checkpointMaterial,organicResults:I},await this.emitProgress("serp_captured")}let V=t.debug?pt(o,I,M):m;if(!f){await this.resolveMaterialLinks(p,[],I,A.aiOverview,A.aiMode),this.checkpointMaterial={...this.checkpointMaterial,organicResults:I},await this.emitProgress("serp_captured");let F={seed:u.query,totalQuestions:0,maxDepthReached:0,durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(F),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:"no_paa",noPaaObserved:!0,problem:null,pagination:W,paaLifecycle:{...this.paaLifecycle},completeness:{...this.completeness},links:{...this.linkDiagnostics},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,V,l)}:{}},totalQuestions:0,surface:A.surface,aiOverview:A.aiOverview,aiMode:A.aiMode,whatPeopleSaying:y,tree:[],flat:[],videos:L,forums:T,organicResults:I,localPack:M,entityIds:k,stats:F}}let q=Date.now(),J=await this.runBFS(p,u,n);this.phaseTimings.paaExpansionMs=Date.now()-q,this.throwIfAborted(n);let G=new URLSearchParams({q:u.query,gl:t.gl,hl:t.hl,pws:"0",udm:Ht.udm});r&&G.set("uule",r);let j=[];if(t.includeShortVideos!==!1)try{j=await this.extractShortVideos(p,"https://www.google.com/search?"+G.toString())}catch(F){if(!(F instanceof _))throw F;d++,U.push({code:"short_videos_captcha_skipped",surface:"short_videos",message:F.message,retryable:!0})}this.reporter.onVideos(j),await this.resolveMaterialLinks(p,J,I,A.aiOverview,A.aiMode),this.checkpointMaterial={...this.checkpointMaterial,surface:A.surface,aiOverview:A.aiOverview,aiMode:A.aiMode,videos:[...L,...j],organicResults:I},await this.emitProgress("expansion_finished");let yt=[...L,...j],B=this.buildTree(J,u.query),tt={seed:u.query,totalQuestions:J.length,maxDepthReached:J.reduce((F,K)=>Math.max(F,K.depth),0),durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(tt),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:"paa_found",problem:null,pagination:W,paaLifecycle:{...this.paaLifecycle},completeness:{...this.completeness},links:{...this.linkDiagnostics},...U.length>0?{warnings:U}:{},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,V,l)}:{}},totalQuestions:J.length,surface:A.surface,aiOverview:A.aiOverview,aiMode:A.aiMode,whatPeopleSaying:y,tree:B,flat:J,videos:yt,forums:T,organicResults:I,localPack:M,entityIds:k,stats:tt}}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 z}from"fs";import lt from"path";import wt from"papaparse";var zt=class{async writeJSON(t,n){await z.mkdir(n,{recursive:!0});let s=`${t.seed.toLowerCase().replace(/\W+/g,"-").slice(0,40)}-${Date.now()}.json`,i=lt.join(n,s);return await z.writeFile(i,JSON.stringify(t,null,2),"utf8"),await Oe({title:`${t.seed} scrape`,content:JSON.stringify(t),source:`mcp-scraper:${i}`}),i}async writeCSV(t,n){await z.mkdir(n,{recursive:!0});let s=(t[0]?.seed_query??"paa").toLowerCase().replace(/\W+/g,"-").slice(0,40),i=wt.unparse(t.map(({sources:S,...h})=>({...h,sources_json:JSON.stringify(S)})),{header:!0}),d=`${s}-${Date.now()}.csv`,U=lt.join(n,d);return await z.writeFile(U,i,"utf8"),U}async writeVideoCSV(t,n,a){await z.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=wt.unparse(t,{header:!0}),d=`${s}-videos-${Date.now()}.csv`,U=lt.join(a,d);return await z.writeFile(U,i,"utf8"),U}async writeForumCSV(t,n,a){await z.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=wt.unparse(t,{header:!0}),d=`${s}-forums-${Date.now()}.csv`,U=lt.join(a,d);return await z.writeFile(U,i,"utf8"),U}async writeAIOverviewCSV(t,n,a,s){await z.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=wt.unparse(d,{header:!0}),S=`${i}-ai-overview-${Date.now()}.csv`,h=lt.join(s,S);return await z.writeFile(h,U,"utf8"),h}async writeAIModeCSV(t,n,a,s){await z.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=wt.unparse(d,{header:!0}),S=`${i}-ai-mode-${Date.now()}.csv`,h=lt.join(s,S);return await z.writeFile(h,U,"utf8"),h}async writeWhatPeopleSayingCSV(t,n,a){await z.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=t.map(h=>({seed_query:n,...h})),d=wt.unparse(i,{header:!0}),U=`${s}-what-people-saying-${Date.now()}.csv`,S=lt.join(a,U);return await z.writeFile(S,d,"utf8"),S}};var qt=class{onQuestion(t){process.stdout.write(JSON.stringify({event:"question",depth:t.depth,question:t.question})+`
|
|
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(ln,{aio:Ge,aim:De,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 Z)throw i;return{organic:[],status:"failed",failureCode:s??(i instanceof _?"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,kernelApiKey:t.kernelApiKey,kernelProxyId:t.kernelProxyId,kernelProfileName:t.kernelProfileName,kernelProfileSaveChanges:t.kernelProfileSaveChanges,kernelStealth:t.kernelStealth,kernelProxyResolution:t.kernelProxyResolution,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(F){console.warn(JSON.stringify({event:"paa_provider_session_sink_failed",provider:h.provider,message:F instanceof Error?F.message:String(F)}))}this.throwIfAborted(n);let l=t.location?Se(t.location):null,o=t.location?l?.canonical??t.location:null,r=o?nn(o):null,u=t,c=t.includeAllSerpFeatures,g=c||t.includeLocalPack,N=c||t.includeForums,b=c||t.includeVideos,C=c||t.includeAiOverview,x=c||t.includeWhatPeopleSaying,O={surface:"web",aiOverview:{detected:!1,text:null,citations:[]},aiMode:{detected:!1,text:null,citations:[]}},H=Date.now(),{hasPaa:f}=await this.driver.navigateToSERP(u.query,r,t.gl,t.hl,{...kt(t.recency)?{tbs:kt(t.recency)}:{},debug:t.debug,purpose:t.serpOnly?"serp":"paa",...t.softDeadlineMs?{deadlineMs:t.softDeadlineMs}:{}});this.phaseTimings.navigationMs=Date.now()-H,this.throwIfAborted(n);let p=this.driver.getPage();if(await this.throwIfCaptcha(p,"Google SERP"),f||(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 F=Date.now(),K=f?await this.runBFS(p,u,n):[];this.phaseTimings.paaExpansionMs=Date.now()-F,await this.resolveMaterialLinks(p,K,[],O.aiOverview,O.aiMode);let R={seed:u.query,totalQuestions:K.length,maxDepthReached:K.reduce((E,$)=>Math.max(E,$.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:f?"paa_found":"no_paa",...f?{}:{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:K.length,surface:"web",aiOverview:{detected:!1,text:null,citations:[]},aiMode:{detected:!1,text:null,citations:[]},whatPeopleSaying:[],tree:this.buildTree(K,u.query),flat:K,videos:[],forums:[],organicResults:[],localPack:[],entityIds:{entities:[],kgIds:[],cids:[],gcids:[]},stats:R}}if(C&&(this.aioShareUrlEarly=await this.captureAIOverviewShareUrl(p,t).catch(()=>null)),t.serpOnly){let F=Date.now(),[K,R,E]=await Promise.all([this.extractOrganicResults(p),g?this.extractLocalPack(p):Promise.resolve([]),this.extractEntityIds(p)]),$=this.mergeLocalPackIntoEntities(E,R),et=C?await this.extractAISurfaces(p,t):O;this.phaseTimings.serpParseMs=Date.now()-F;let Pt=t.debug?pt(o,K,R):void 0,St=K;if((t.pages??1)>=2){let Mt=new URLSearchParams({q:u.query,gl:t.gl,hl:t.hl,pws:"0",start:"10"});kt(t.recency)&&Mt.set("tbs",kt(t.recency)),r&&Mt.set("uule",r),await this.driver.navigateTo("https://www.google.com/search?"+Mt.toString()),await this.throwIfCaptcha(p,"Google SERP page 2");let Wt=await this.extractOrganicResults(p);St=[...K,...Wt.map(Ut=>({...Ut,position:Ut.position+10}))],t.debug&&(Pt=pt(o,St,R))}await this.resolveMaterialLinks(p,[],St,et.aiOverview,et.aiMode);let bt={seed:u.query,totalQuestions:0,maxDepthReached:0,durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(bt),{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,Pt,l)}:{}},totalQuestions:0,surface:et.surface,aiOverview:et.aiOverview,aiMode:et.aiMode,whatPeopleSaying:[],tree:[],flat:[],videos:[],forums:[],organicResults:St,localPack:R,entityIds:$,stats:bt}}let[L,T,y,P,w,M]=await Promise.all([b?this.extractVideos(p):Promise.resolve([]),N?this.extractForums(p):Promise.resolve([]),x?this.extractWhatPeopleSaying(p):Promise.resolve([]),this.extractEntityIds(p),this.extractOrganicResults(p),g?this.extractLocalPack(p):Promise.resolve([])]),k=this.mergeLocalPackIntoEntities(P,M),m=t.debug?pt(o,w,M):void 0;this.reporter.onVideos(L),this.reporter.onForums(T);let A=C?await this.extractAISurfaces(p,t):O,W={requestedPages:(t.pages??1)>=2?2:1,capturedPages:1,page2Status:(t.pages??1)>=2?"not_attempted":"not_requested",page1OrganicCount:w.length,page2OrganicCount:0},I=w;if(this.checkpointMaterial={surface:A.surface,aiOverview:A.aiOverview,aiMode:A.aiMode,whatPeopleSaying:y,videos:L,forums:T,organicResults:I,localPack:M,entityIds:k,pagination:W},await this.emitProgress("serp_captured"),W.requestedPages===2){let F=await this.captureSecondOrganicPage(p,u,n);I=[...w,...F.organic],W={...W,capturedPages:F.status==="captured"?2:1,page2Status:F.status,page2OrganicCount:F.organic.length,...F.failureCode?{failureCode:F.failureCode}:{}},this.checkpointMaterial={...this.checkpointMaterial,organicResults:I,pagination:W},await this.emitProgress("serp_captured"),await this.resolveMaterialLinks(p,[],I,A.aiOverview,A.aiMode),this.checkpointMaterial={...this.checkpointMaterial,organicResults:I},await this.emitProgress("serp_captured")}let V=t.debug?pt(o,I,M):m;if(!f){await this.resolveMaterialLinks(p,[],I,A.aiOverview,A.aiMode),this.checkpointMaterial={...this.checkpointMaterial,organicResults:I},await this.emitProgress("serp_captured");let F={seed:u.query,totalQuestions:0,maxDepthReached:0,durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(F),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:"no_paa",noPaaObserved:!0,problem:null,pagination:W,paaLifecycle:{...this.paaLifecycle},completeness:{...this.completeness},links:{...this.linkDiagnostics},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,V,l)}:{}},totalQuestions:0,surface:A.surface,aiOverview:A.aiOverview,aiMode:A.aiMode,whatPeopleSaying:y,tree:[],flat:[],videos:L,forums:T,organicResults:I,localPack:M,entityIds:k,stats:F}}let q=Date.now(),J=await this.runBFS(p,u,n);this.phaseTimings.paaExpansionMs=Date.now()-q,this.throwIfAborted(n);let G=new URLSearchParams({q:u.query,gl:t.gl,hl:t.hl,pws:"0",udm:Ht.udm});r&&G.set("uule",r);let j=[];if(t.includeShortVideos!==!1)try{j=await this.extractShortVideos(p,"https://www.google.com/search?"+G.toString())}catch(F){if(!(F instanceof _))throw F;d++,U.push({code:"short_videos_captcha_skipped",surface:"short_videos",message:F.message,retryable:!0})}this.reporter.onVideos(j),await this.resolveMaterialLinks(p,J,I,A.aiOverview,A.aiMode),this.checkpointMaterial={...this.checkpointMaterial,surface:A.surface,aiOverview:A.aiOverview,aiMode:A.aiMode,videos:[...L,...j],organicResults:I},await this.emitProgress("expansion_finished");let yt=[...L,...j],B=this.buildTree(J,u.query),tt={seed:u.query,totalQuestions:J.length,maxDepthReached:J.reduce((F,K)=>Math.max(F,K.depth),0),durationMs:Date.now()-a,errorCount:d};return this.reporter.onComplete(tt),{seed:u.query,location:t.location??null,extractedAt:new Date().toISOString(),diagnostics:{phaseTimings:this.currentPhaseTimings(a),completionStatus:"paa_found",problem:null,pagination:W,paaLifecycle:{...this.paaLifecycle},completeness:{...this.completeness},links:{...this.linkDiagnostics},...U.length>0?{warnings:U}:{},...t.debug?{debug:this.buildHarvestDebugSnapshot(u,o,r,V,l)}:{}},totalQuestions:J.length,surface:A.surface,aiOverview:A.aiOverview,aiMode:A.aiMode,whatPeopleSaying:y,tree:B,flat:J,videos:yt,forums:T,organicResults:I,localPack:M,entityIds:k,stats:tt}}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 z}from"fs";import lt from"path";import wt from"papaparse";var zt=class{async writeJSON(t,n){await z.mkdir(n,{recursive:!0});let s=`${t.seed.toLowerCase().replace(/\W+/g,"-").slice(0,40)}-${Date.now()}.json`,i=lt.join(n,s);return await z.writeFile(i,JSON.stringify(t,null,2),"utf8"),await Oe({title:`${t.seed} scrape`,content:JSON.stringify(t),source:`mcp-scraper:${i}`}),i}async writeCSV(t,n){await z.mkdir(n,{recursive:!0});let s=(t[0]?.seed_query??"paa").toLowerCase().replace(/\W+/g,"-").slice(0,40),i=wt.unparse(t.map(({sources:S,...h})=>({...h,sources_json:JSON.stringify(S)})),{header:!0}),d=`${s}-${Date.now()}.csv`,U=lt.join(n,d);return await z.writeFile(U,i,"utf8"),U}async writeVideoCSV(t,n,a){await z.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=wt.unparse(t,{header:!0}),d=`${s}-videos-${Date.now()}.csv`,U=lt.join(a,d);return await z.writeFile(U,i,"utf8"),U}async writeForumCSV(t,n,a){await z.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=wt.unparse(t,{header:!0}),d=`${s}-forums-${Date.now()}.csv`,U=lt.join(a,d);return await z.writeFile(U,i,"utf8"),U}async writeAIOverviewCSV(t,n,a,s){await z.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=wt.unparse(d,{header:!0}),S=`${i}-ai-overview-${Date.now()}.csv`,h=lt.join(s,S);return await z.writeFile(h,U,"utf8"),h}async writeAIModeCSV(t,n,a,s){await z.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=wt.unparse(d,{header:!0}),S=`${i}-ai-mode-${Date.now()}.csv`,h=lt.join(s,S);return await z.writeFile(h,U,"utf8"),h}async writeWhatPeopleSayingCSV(t,n,a){await z.mkdir(a,{recursive:!0});let s=n.toLowerCase().replace(/\W+/g,"-").slice(0,40),i=t.map(h=>({seed_query:n,...h})),d=wt.unparse(i,{header:!0}),U=`${s}-what-people-saying-${Date.now()}.csv`,S=lt.join(a,U);return await z.writeFile(S,d,"utf8"),S}};var qt=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 ba}from"crypto";var Wa="pr.oxylabs.io",Ia=7777,Aa=10,Ts=2;function pn(){return process.env.OXYLABS_USERNAME?.trim()||void 0}function mn(){return process.env.OXYLABS_PASSWORD?.trim()||void 0}function xa(){return(process.env.OXYLABS_COUNTRY?.trim()||"US").toUpperCase()}function jt(){return!!(pn()&&mn())}function La(){let e="";for(let t=0;t<10;t++)e+=String(ba(0,10));return e}function Oa(e={}){let t=pn();if(!t)return;let n=t.startsWith("customer-")?t:`customer-${t}`,a=(e.country?.trim()||xa()).toUpperCase(),s=e.sticky?`-sessid-${La()}-sesstime-${Aa}`:"";return`${n}-cc-${a}${s}`}function ce(e){return e.replace(/pr\.oxylabs\.io(:\d+)?/gi,"backup proxy").replace(/oxylabs/gi,"backup proxy")}function Ba(e){return`mcp-backup-custom-${`${Date.now()}-${e??0}-${Math.random().toString(36).slice(2,8)}`}`}async function $t(e,t={}){let n=Oa({sticky:t.sticky}),a=mn();if(!n||!a)throw new Error("backup proxy pool is not configured");let s=new nt({apiKey:e});try{let i=await s.proxies.create({type:"custom",name:Ba(t.attemptIndex),protocol:"http",config:{host:Wa,port:Ia,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(ce(d))}}async function Ps(e,t){if(!(!e||!jt()))try{return await $t(e,{attemptIndex:t})}catch{return}}async function bs(e,t){if(!(!e||!t))try{await new nt({apiKey:e}).proxies.delete(t)}catch{}}var vn={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"},Ha={"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 Fa(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==="mobile_created"?"mobile":e==="isp_created"?"isp":e==="backup_custom"?"custom":e==="location_created"||e==="location_reused"?"residential":"unknown",proxyMode:t,proxyIdPresent:!!n,proxyIdSuffix:Fa(n),target:a,error:s,disposable:i}}}function Ra(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function Ga(e){return e.trim().toLowerCase().replace(/\./g,"").replace(/\s+/g," ")}function Da(e){if(!e)return!0;let t=Ga(e);return t==="united states"||t==="united states of america"||t==="usa"||t==="us"}function ge(e){let t=e.trim();if(/^[A-Za-z]{2}$/.test(t)){let n=t.toUpperCase();return Object.values(vn).includes(n)?n:null}return vn[Ra(t)]??null}function Va(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 ot(e,t,n){return n?`mcp-serp-residential-${e.toLowerCase()}-${t.toLowerCase()}-${n}`:`mcp-serp-residential-${e.toLowerCase()}-${t.toLowerCase()}`}function Nt(e,t){let n=`${Date.now()}-${t??0}-${Math.random().toString(36).slice(2,8)}`;return`${e}-fresh-${n}`}function Ea(e){return`mcp-serp-residential-us-zip-${e}`}function Nn(e,t){if(!e||t.toLowerCase()!=="us")return null;let n=an(e),a=n.split(",").map(h=>h.trim()).filter(Boolean);if(a.length>1&&Da(a[a.length-1])&&(a=a.slice(0,-1)),a.length===1){let h=ge(a[0]);return h?{canonicalLocation:n,level:"state",country:"US",state:h,city:"",cityCandidates:[],proxyName:ot("US",h),config:{country:"US",state:h}}:null}let[s="",i=""]=a;if(!s||!i)return null;let d=ge(i);if(!d)return null;let U=Va(s),S=U[0];return S?{canonicalLocation:n,level:"city",country:"US",state:d,city:S,cityCandidates:U,proxyName:ot("US",d,S),config:{country:"US",state:d,city:S}}:null}function Ya(e){return`${e.city}|${e.state}`}function fn(e,t){return t&&/^\d{5}$/.test(t)?t:Ha[Ya(e)]??null}function Tn(e,t){return{...e,level:"zip",zip:t,proxyName:Ea(t),config:{country:e.country,state:e.state,zip:t}}}function we(e,t){return{...e,proxyName:t}}function Me(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 Ka(e,t){return e.find(n=>n.type==="residential"&&n.status!=="unavailable"&&!!n.id&&(n.name===t.proxyName||Me(n.config,t,t.level==="city"?t.city:void 0)))??null}function Ja(e,t){for(let n of t.cityCandidates){let a=ot(t.country,t.state,n),s=e.find(i=>i.type==="residential"&&i.status!=="unavailable"&&!!i.id&&(i.name===a||Me(i.config,t,n)));if(s)return s}return null}function Qt(e){return{...e,level:"state",proxyName:ot(e.country,e.state),config:{country:e.country,state:e.state}}}function _a(e,t){let n=ot(t.country,t.state);return e.find(a=>a.type==="residential"&&a.status!=="unavailable"&&!!a.id&&(a.name===n||Me(a.config,t)))??null}function za(e,t){return Qt(e)}function st(e){return e instanceof Error?e.message:String(e)}function qa(e,t,n){let a=[],s=fn(e,t);if(s){let d=Tn(e,s);a.push(we(d,Nt(d.proxyName,n)))}for(let d of e.cityCandidates){let U={...e,level:"city",city:d,proxyName:ot(e.country,e.state,d),config:{country:e.country,state:e.state,city:d}};a.push(we(U,Nt(U.proxyName,n)))}let i=Qt(e);return a.push(we(i,Nt(i.proxyName,n))),a}async function ye(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: ${ce(st(a))}`)}return Y("configured_fallback",e.proxyMode,e.configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId,t,n.join(" | "))}async function Ls(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 ja(e,t,n){let a=[];for(let s of qa(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}: ${st(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:Nt(`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: ${st(i)}`)}}return ye(t,n,a)}async function Pn(e,t){if(!e||!t)return;await new nt({apiKey:e}).proxies.delete(t)}async function Os(e){let t=ge(e.state);if(!t)throw new Error("A valid US state is required for a mobile Maps proxy");let n=new nt({apiKey:e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey}),a=Nn(t,"us");if(!a)throw new Error("Could not resolve the mobile Maps proxy state");let s=await n.proxies.create({type:"mobile",name:Nt(`mcp-maps-mobile-us-${t.toLowerCase()}`,e.attemptIndex),config:{country:"US",state:t}});if(!s.id)throw new Error("\u004b\u0065\u0072\u006e\u0065\u006c did not return a mobile proxy id");if(s.type!=="mobile"||s.status==="unavailable"||s.config?.state?.toUpperCase()!==t)throw await n.proxies.delete(s.id),new Error(`\u004b\u0065\u0072\u006e\u0065\u006c did not confirm a mobile proxy for ${t}`);return Y("mobile_created","configured",s.id,a,null,!0)}async function bn(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=Nn(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 nt({apiKey:e.\u006b\u0065\u0072\u006e\u0065\u006cApiKey});try{let a=e.attemptIndex??0;if(e.fresh)return await ja(n,e,t);if(a>=1){let l=za(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}: ${st(r)}`)}return ye(e,l,o)}let s=[];for await(let l of await n.proxies.list())s.push(l);let i=fn(t,e.proxyZip),d=[];if(i){let l=Tn(t,i),o=Ka(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}: ${st(r)}`)}}let U=Ja(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:ot(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:ot(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}: ${st(o)}`)}let S=Qt(t),h=_a(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}: ${st(l)}`)}return ye(e,t,d)}catch(a){return Y("configured_fallback",e.proxyMode,e.configured\u004b\u0065\u0072\u006e\u0065\u006cProxyId,t,st(a))}}var ft=class extends Error{constructor(t,n){super(`SERP provider mismatch: planned ${t}, observed ${n}`),this.name="SerpProviderMismatchError"}};function Wn(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 In(e){return $a({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 An(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 Zt(e,t){if(!t)throw new Error(`Requested SERP provider is unavailable: ${e}`);return e}function $a(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=Zt("\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=Zt("\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=Zt("\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=Zt("\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 Ce=2,Qa=2,Za=3e3;function pe(e){return e.reason instanceof DOMException&&e.reason.name==="TimeoutError"?e.reason:new Z}function Xa(e){if(!e||typeof e!="object")return;let t=e.signal;if(t instanceof AbortSignal)return t}function ti(e){if(!e||typeof e!="object")return;let t=e.onAttemptEvent;return typeof t=="function"?t:void 0}function ei(e){if(!e||typeof e!="object")return;let t=e.onPaaProgress;return typeof t=="function"?t:void 0}function ni(e){if(!e||typeof e!="object")return;let t=e.onPaaDomEvidence;return typeof t=="function"?t:void 0}async function ai(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:D.item,answerContainer:D.answerContainer,clickTarget:D.clickTarget,expandedClass:D.expandedClass});return{capturedAt:new Date().toISOString(),...t,selectorVersion:Ye}}async function gt(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 Tt(e){if(e instanceof ft)return"error";if(e instanceof _)return"captcha";if(e instanceof te)return"location_mismatch";if(e instanceof Z)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":ri(t)?"proxy_tunnel_failed":li(t)?"proxy_unavailable":/timeout|timed out|Timeout \d+ms exceeded|deadline/i.test(t)?"timeout":"error"}function ii(e){return e.diagnostics.degradedResult?"degraded_result":e.diagnostics?.completionStatus??(e.totalQuestions>0?"paa_found":"no_paa")}function si(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 xn(e,t,n){let a=si(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 Ln(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 oi(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 X(e){return e instanceof Error?e.message:String(e)}function di(e){return e==="location"?Qa:Ce}function ri(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 li(e){return/proxy unavailable|proxy_unavailable|connection_test_failed|did not return a proxy id|configured fallback/i.test(e)}function On(e){return e==="captcha"||e==="proxy_tunnel_failed"||e==="proxy_unavailable"}function Bn(e){return e==="browser_session_interrupted"}function Si(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 Ui(e,t){return t==="location"&&e.diagnostics.debug?.locationEvidence?.status==="mismatch"}function Hn(e,t){if(t||!e.diagnostics.debug)return e;let n={...e.diagnostics};return delete n.debug,{...e,diagnostics:n}}async function Fn(e,t){let n=t==null?3e3:t-Date.now();if(n<=0)return e;try{return await gn(e,{totalBudgetMs:Math.min(3e3,n)})}catch(a){return console.warn(JSON.stringify({event:"harvest_goto_resolution_failed",message:X(a)})),e}}async function ke(e,t){if(!(!e||!t))try{await Pn(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:X(n)}))}}async function Rn(e,t,n,a,s,i){let d=Qe(t),U=new qt,S=new _t(d,U,a,s);if(n?.aborted)return{result:null,error:pe(n),cleanup:await d.close(),debug:null};let h,l=n?new Promise((g,N)=>{h=()=>N(pe(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 N=ai(d);N.catch(()=>{});let b=await Promise.race([N,new Promise((C,x)=>{g=setTimeout(()=>x(new DOMException("PAA DOM evidence timed out","TimeoutError")),2e3)})]);await i(b)}catch(N){console.warn(JSON.stringify({event:"paa_dom_evidence_failed",message:X(N)}))}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=Tt(r),N=g==="timeout"||g==="request_aborted"||g==="browser_session_interrupted"?g:null,b=null;if(N)try{b=typeof S.getPartialResult=="function"?S.getPartialResult():null}catch{b=null}return b&&N?(b.diagnostics={...b.diagnostics,interruption:{code:N,reasonSource:"client_runtime",message:X(r)}},{result:b,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 Xs(e){let t=typeof e=="object"&&e!==null?e:{},n=Xa(e),a=ti(e),s=ei(e),i=ni(e),d=t.forceManagedSerp===!0,U=t.force\u004b\u0065\u0072\u006e\u0065\u006cSerp===!0,S=An({forceManagedSerp:d,force\u004b\u0065\u0072\u006e\u0065\u006cSerp:U}),h=t.proxyMode,l=h==="location"||h==="none"||h==="configured"?h:Lt,o=typeof t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey=="string"?t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey.trim():Pe(),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,N=t.maxAttempts,b=typeof N=="number"&&Number.isInteger(N)&&N>=1?Math.min(Ce,N):di(l),C=Math.min(Ce,b),x=typeof t.softDeadlineMs=="number"?t.softDeadlineMs:null,O=new zt,H=null,f=l,p=0,L=()=>x==null||x-Date.now()>=Za;for(let T=0;T<C;T++){let y=T+1,P=Date.now();try{if(n?.aborted)throw pe(n);let w=In({intent:S,\u0062\u0072\u0069\u0067\u0068\u0074\u0044\u0061\u0074\u0061Available:je(),\u006b\u0065\u0072\u006e\u0065\u006cFallbackAvailable:!!o,persistent\u004b\u0065\u0072\u006e\u0065\u006cIdentityRequested:!!(t.serpIdentity||t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName),retryIndex:T,priorTerminalReason:H==null?null:Tt(H),softDeadlineMs:x}),M=ee.parse({...t,\u006b\u0065\u0072\u006e\u0065\u006cApiKey:o,proxyMode:f,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":M.serpIdentity?"\u006b\u0065\u0072\u006e\u0065\u006c_persistent_identity":"\u006b\u0065\u0072\u006e\u0065\u006c_browser";await gt(a,{type:"started",attemptNumber:y,maxAttempts:C,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||H==null?null:Tt(H),query:M.query,location:M.location??null,maxQuestions:M.maxQuestions,startedAt:new Date(P).toISOString()});let m=w.plannedProvider==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?null:await bn({...u,proxyMode:f,attemptIndex:T,fresh:f==="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 A={...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:f,keepDefaultProxy:T>0,softDeadlineMs:x==null?void 0:P+w.timeoutMs,debug:c||g};f==="none"&&(A.\u006b\u0065\u0072\u006e\u0065\u006cProxyId=void 0);let W=ee.parse(A);console.info(JSON.stringify({event:"harvest_attempt_started",attempt_number:y,max_attempts:C,query:W.query,location:W.location??null,max_questions:W.maxQuestions}));let I=Bt(),V=null,q=async R=>{Wn(R.provider)!==w.plannedProvider&&(V=new ft(w.plannedProvider,R.provider)),await gt(a,{type:"provider_session_started",attemptNumber:y,maxAttempts:C,provider:R.provider,providerSessionId:R.providerSessionId,billingMode:R.billingMode,observedAt:new Date().toISOString()})},J=I?.harvestBrowserMode==="headless-test"&&process.env[Ie]==="true",G=I?await Ae({...I,forceHeadless:J,forceHeadful:!J},()=>Rn(W,w,n,s,q,i)):await Rn(W,w,n,s,q,i);if(G.error||V){let R=V??G.error,E=Tt(R);(E==="captcha"||E==="proxy_tunnel_failed")&&f==="location"&&(p++,p>=2&&(f="none"));let $=!G.result&&T<C-1&&L()&&(E==="captcha"||Bn(E)||l==="location"&&On(E));if(E==="captcha"?console.warn(JSON.stringify({event:"harvest_attempt_captcha",attempt_number:y,max_attempts:C,message:X(R),will_retry:$})):$&&console.warn(JSON.stringify({event:"harvest_attempt_proxy_retry",attempt_number:y,max_attempts:C,outcome:E,message:X(R),will_retry:$})),await gt(a,{type:"finished",attemptNumber:y,maxAttempts:C,outcome:E,\u006b\u0065\u0072\u006e\u0065\u006cSessionId:G.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,questionCount:G.result?.totalQuestions??0,durationMs:Date.now()-P,error:X(R),willRetry:$,cleanup:G.cleanup,debug:G.debug,completedAt:new Date().toISOString()}),await ke(o,m?.disposableProxyId),H=R,$)continue;if(G.result&&!V){let et=await Fn(G.result,x);return Ln(xn(Hn(et,c),W.maxQuestions,W.questionsOnly),T,w.attemptKind==="provider_fallback"?1:0)}break}let j=G.result;if(!j)throw new Error("Harvest attempt completed without a result");if(Ui(j,l)){let R=new te(Si(j)),E=T<C-1&&L();if(console.warn(JSON.stringify({event:"harvest_attempt_location_mismatch",attempt_number:y,max_attempts:C,message:R.message,will_retry:E})),await gt(a,{type:"finished",attemptNumber:y,maxAttempts:C,outcome:"location_mismatch",\u006b\u0065\u0072\u006e\u0065\u006cSessionId:G.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,questionCount:j.totalQuestions,durationMs:Date.now()-P,error:R.message,willRetry:E,cleanup:G.cleanup,debug:G.debug,completedAt:new Date().toISOString()}),await ke(o,m?.disposableProxyId),H=R,E)continue;break}let yt=await Fn(j,x),B=Ln(xn(Hn(yt,c),W.maxQuestions,W.questionsOnly),T,w.attemptKind==="provider_fallback"?1:0),tt=ii(B),F=tt==="degraded_result"&&T<C-1&&L(),K=tt==="degraded_result"?oi(B):null;if(F&&console.warn(JSON.stringify({event:"harvest_attempt_degraded_result",attempt_number:y,max_attempts:C,degradation_reasons:B.diagnostics.degradationReasons,will_retry:!0})),await gt(a,{type:"finished",attemptNumber:y,maxAttempts:C,outcome:tt,\u006b\u0065\u0072\u006e\u0065\u006cSessionId:G.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,questionCount:B.totalQuestions,durationMs:Date.now()-P,error:K,willRetry:F,cleanup:G.cleanup,debug:G.debug,completedAt:new Date().toISOString()}),await ke(o,m?.disposableProxyId),F)continue;return(W.format==="json"||W.format==="both")&&await O.writeJSON(B,W.outputDir),(W.format==="csv"||W.format==="both")&&await Promise.all([O.writeCSV(B.flat,W.outputDir),B.videos.length>0?O.writeVideoCSV(B.videos,B.seed,W.outputDir):Promise.resolve(""),B.forums.length>0?O.writeForumCSV(B.forums,B.seed,W.outputDir):Promise.resolve(""),B.aiOverview.detected?O.writeAIOverviewCSV(B.aiOverview.citations,B.aiOverview.text,B.seed,W.outputDir):Promise.resolve(""),B.aiMode.detected?O.writeAIModeCSV(B.aiMode.citations,B.aiMode.text,B.seed,W.outputDir):Promise.resolve(""),B.whatPeopleSaying.length>0?O.writeWhatPeopleSayingCSV(B.whatPeopleSaying,B.seed,W.outputDir):Promise.resolve("")]),B}catch(w){let M=Tt(w);(M==="captcha"||M==="proxy_tunnel_failed")&&f==="location"&&(p++,p>=2&&(f="none"));let k=T<C-1&&L()&&(M==="captcha"||Bn(M)||l==="location"&&On(M));if(M==="captcha"?console.warn(JSON.stringify({event:"harvest_attempt_captcha",attempt_number:y,max_attempts:C,message:X(w),will_retry:k})):k&&console.warn(JSON.stringify({event:"harvest_attempt_proxy_retry",attempt_number:y,max_attempts:C,outcome:M,message:X(w),will_retry:k})),await gt(a,{type:"finished",attemptNumber:y,maxAttempts:C,outcome:M,\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,questionCount:0,durationMs:Date.now()-P,error:X(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()}),H=w,k)continue;if(M==="captcha")break;throw w}}throw H&&!(H instanceof _)?H:(console.warn(JSON.stringify({event:"harvest_captcha_exhausted",max_attempts:C,session_kind:o?"\u006b\u0065\u0072\u006e\u0065\u006c":"local"})),new _(We(`CAPTCHA on all ${C} fresh sessions. Try again in a few minutes.`)))}export{yi as a,Rt as b,Gt as c,pi as d,Ke as e,Xn as f,Vt as g,_e as h,ze as i,oe as j,je as k,Yt as l,nn as m,Se as n,rt as o,Jt as p,Ts as q,jt as r,Ps as s,bs as t,ge as u,Ls as v,Pn as w,Os as x,bn as y,Xs as z};
|
|
21710
|
+
`)}};import{randomInt as ba}from"crypto";var Wa="pr.oxylabs.io",Ia=7777,Aa=10,Ts=2;function pn(){return process.env.OXYLABS_USERNAME?.trim()||void 0}function mn(){return process.env.OXYLABS_PASSWORD?.trim()||void 0}function xa(){return(process.env.OXYLABS_COUNTRY?.trim()||"US").toUpperCase()}function jt(){return!!(pn()&&mn())}function La(){let e="";for(let t=0;t<10;t++)e+=String(ba(0,10));return e}function Oa(e={}){let t=pn();if(!t)return;let n=t.startsWith("customer-")?t:`customer-${t}`,a=(e.country?.trim()||xa()).toUpperCase(),s=e.sticky?`-sessid-${La()}-sesstime-${Aa}`:"";return`${n}-cc-${a}${s}`}function ce(e){return e.replace(/pr\.oxylabs\.io(:\d+)?/gi,"backup proxy").replace(/oxylabs/gi,"backup proxy")}function Ba(e){return`mcp-backup-custom-${`${Date.now()}-${e??0}-${Math.random().toString(36).slice(2,8)}`}`}async function $t(e,t={}){let n=Oa({sticky:t.sticky}),a=mn();if(!n||!a)throw new Error("backup proxy pool is not configured");let s=new nt({apiKey:e});try{let i=await s.proxies.create({type:"custom",name:Ba(t.attemptIndex),protocol:"http",config:{host:Wa,port:Ia,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(ce(d))}}async function Ps(e,t){if(!(!e||!jt()))try{return await $t(e,{attemptIndex:t})}catch{return}}async function bs(e,t){if(!(!e||!t))try{await new nt({apiKey:e}).proxies.delete(t)}catch{}}var vn={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"},Ha={"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 Fa(e){return e?e.slice(-6):null}function Y(e,t,n,a,s,i=!1){return{kernelProxyId:n,...i&&n?{disposableProxyId:n}:{},resolution:{source:e,proxyType:e==="disabled"?"none":e==="configured_fallback"?"configured":e==="mobile_created"?"mobile":e==="isp_created"?"isp":e==="backup_custom"?"custom":e==="location_created"||e==="location_reused"?"residential":"unknown",proxyMode:t,proxyIdPresent:!!n,proxyIdSuffix:Fa(n),target:a,error:s,disposable:i}}}function Ra(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function Ga(e){return e.trim().toLowerCase().replace(/\./g,"").replace(/\s+/g," ")}function Da(e){if(!e)return!0;let t=Ga(e);return t==="united states"||t==="united states of america"||t==="usa"||t==="us"}function ge(e){let t=e.trim();if(/^[A-Za-z]{2}$/.test(t)){let n=t.toUpperCase();return Object.values(vn).includes(n)?n:null}return vn[Ra(t)]??null}function Va(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 ot(e,t,n){return n?`mcp-serp-residential-${e.toLowerCase()}-${t.toLowerCase()}-${n}`:`mcp-serp-residential-${e.toLowerCase()}-${t.toLowerCase()}`}function Nt(e,t){let n=`${Date.now()}-${t??0}-${Math.random().toString(36).slice(2,8)}`;return`${e}-fresh-${n}`}function Ea(e){return`mcp-serp-residential-us-zip-${e}`}function Nn(e,t){if(!e||t.toLowerCase()!=="us")return null;let n=an(e),a=n.split(",").map(h=>h.trim()).filter(Boolean);if(a.length>1&&Da(a[a.length-1])&&(a=a.slice(0,-1)),a.length===1){let h=ge(a[0]);return h?{canonicalLocation:n,level:"state",country:"US",state:h,city:"",cityCandidates:[],proxyName:ot("US",h),config:{country:"US",state:h}}:null}let[s="",i=""]=a;if(!s||!i)return null;let d=ge(i);if(!d)return null;let U=Va(s),S=U[0];return S?{canonicalLocation:n,level:"city",country:"US",state:d,city:S,cityCandidates:U,proxyName:ot("US",d,S),config:{country:"US",state:d,city:S}}:null}function Ya(e){return`${e.city}|${e.state}`}function fn(e,t){return t&&/^\d{5}$/.test(t)?t:Ha[Ya(e)]??null}function Tn(e,t){return{...e,level:"zip",zip:t,proxyName:Ea(t),config:{country:e.country,state:e.state,zip:t}}}function we(e,t){return{...e,proxyName:t}}function Me(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 Ka(e,t){return e.find(n=>n.type==="residential"&&n.status!=="unavailable"&&!!n.id&&(n.name===t.proxyName||Me(n.config,t,t.level==="city"?t.city:void 0)))??null}function Ja(e,t){for(let n of t.cityCandidates){let a=ot(t.country,t.state,n),s=e.find(i=>i.type==="residential"&&i.status!=="unavailable"&&!!i.id&&(i.name===a||Me(i.config,t,n)));if(s)return s}return null}function Qt(e){return{...e,level:"state",proxyName:ot(e.country,e.state),config:{country:e.country,state:e.state}}}function _a(e,t){let n=ot(t.country,t.state);return e.find(a=>a.type==="residential"&&a.status!=="unavailable"&&!!a.id&&(a.name===n||Me(a.config,t)))??null}function za(e,t){return Qt(e)}function st(e){return e instanceof Error?e.message:String(e)}function qa(e,t,n){let a=[],s=fn(e,t);if(s){let d=Tn(e,s);a.push(we(d,Nt(d.proxyName,n)))}for(let d of e.cityCandidates){let U={...e,level:"city",city:d,proxyName:ot(e.country,e.state,d),config:{country:e.country,state:e.state,city:d}};a.push(we(U,Nt(U.proxyName,n)))}let i=Qt(e);return a.push(we(i,Nt(i.proxyName,n))),a}async function ye(e,t,n){if(e.backupOnExhaustion&&n.length>0&&e.kernelApiKey&&jt())try{let a=await $t(e.kernelApiKey,{attemptIndex:e.attemptIndex});return Y("backup_custom",e.proxyMode,a,t,null,!0)}catch(a){n.push(`backup: ${ce(st(a))}`)}return Y("configured_fallback",e.proxyMode,e.configuredKernelProxyId,t,n.join(" | "))}async function Ls(e){if(!e.kernelApiKey||!jt())return null;try{let t=await $t(e.kernelApiKey,{attemptIndex:e.attemptIndex});return Y("backup_custom",e.proxyMode,t,null,null,!0)}catch{return null}}async function ja(e,t,n){let a=[];for(let s of qa(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}: Kernel did not return a proxy id`)}catch(i){a.push(`${s.proxyName}: ${st(i)}`)}if(process.env.KERNEL_PROXY_TYPE!=="residential"){let s=Qt(n);try{let i=await e.proxies.create({type:"isp",name:Nt(`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: Kernel did not return a proxy id")}catch(i){a.push(`isp: ${st(i)}`)}}return ye(t,n,a)}async function Pn(e,t){if(!e||!t)return;await new nt({apiKey:e}).proxies.delete(t)}async function Os(e){let t=ge(e.state);if(!t)throw new Error("A valid US state is required for a mobile Maps proxy");let n=new nt({apiKey:e.kernelApiKey}),a=Nn(t,"us");if(!a)throw new Error("Could not resolve the mobile Maps proxy state");let s=await n.proxies.create({type:"mobile",name:Nt(`mcp-maps-mobile-us-${t.toLowerCase()}`,e.attemptIndex),config:{country:"US",state:t}});if(!s.id)throw new Error("Kernel did not return a mobile proxy id");if(s.type!=="mobile"||s.status==="unavailable"||s.config?.state?.toUpperCase()!==t)throw await n.proxies.delete(s.id),new Error(`Kernel did not confirm a mobile proxy for ${t}`);return Y("mobile_created","configured",s.id,a,null,!0)}async function bn(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.configuredKernelProxyId,null,null);let t=Nn(e.location,e.gl);if(!t||!e.kernelApiKey)return Y("configured_fallback",e.proxyMode,e.configuredKernelProxyId,t,t?null:"location could not be normalized to a US city/state proxy target");let n=new nt({apiKey:e.kernelApiKey});try{let a=e.attemptIndex??0;if(e.fresh)return await ja(n,e,t);if(a>=1){let l=za(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}: Kernel did not return a proxy id`)}catch(r){o.push(`${l.state}: ${st(r)}`)}return ye(e,l,o)}let s=[];for await(let l of await n.proxies.list())s.push(l);let i=fn(t,e.proxyZip),d=[];if(i){let l=Tn(t,i),o=Ka(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}: Kernel did not return a proxy id`)}catch(r){d.push(`${i}: ${st(r)}`)}}let U=Ja(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:ot(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:ot(t.country,t.state,l),config:{country:t.country,state:t.state,city:l}},null);d.push(`${l}: Kernel did not return a proxy id`)}catch(o){d.push(`${l}: ${st(o)}`)}let S=Qt(t),h=_a(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}: Kernel did not return a proxy id`)}catch(l){d.push(`${S.state}: ${st(l)}`)}return ye(e,t,d)}catch(a){return Y("configured_fallback",e.proxyMode,e.configuredKernelProxyId,t,st(a))}}var ft=class extends Error{constructor(t,n){super(`SERP provider mismatch: planned ${t}, observed ${n}`),this.name="SerpProviderMismatchError"}};function Wn(e){return e==="bright_data_browser_api"?"brightdata":"kernel"}function In(e){return $a({intent:e.intent,brightDataAvailable:e.brightDataAvailable,kernelAvailable:!0,persistentKernelIdentityRequested:e.persistentKernelIdentityRequested,retryIndex:e.retryIndex,priorTerminalReason:e.priorTerminalReason,allowedFallbacks:e.kernelFallbackAvailable&&e.intent!=="kernel"?["kernel"]:[],timeoutMs:e.softDeadlineMs==null?4e5:Math.max(1,e.softDeadlineMs-Date.now())})}function An(e){if(e.forceManagedSerp&&e.forceKernelSerp)throw new Error("forceManagedSerp and forceKernelSerp cannot both be true");return e.forceManagedSerp?"brightdata":e.forceKernelSerp?"kernel":"auto"}function Zt(e,t){if(!t)throw new Error(`Requested SERP provider is unavailable: ${e}`);return e}function $a(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==="brightdata"?(t=Zt("brightdata",e.brightDataAvailable),n="explicit_brightdata"):e.intent==="kernel"?(t=Zt("kernel",e.kernelAvailable),n="explicit_kernel"):e.persistentKernelIdentityRequested?(t=Zt("kernel",e.kernelAvailable),n="persistent_kernel_identity"):e.brightDataAvailable?(t="brightdata",n="managed_default"):(t=Zt("kernel",e.kernelAvailable),n="kernel_default");let a=e.allowedFallbacks.find(d=>d!==t&&(d==="brightdata"?e.brightDataAvailable:e.kernelAvailable)),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 Ce=2,Qa=2,Za=3e3;function pe(e){return e.reason instanceof DOMException&&e.reason.name==="TimeoutError"?e.reason:new Z}function Xa(e){if(!e||typeof e!="object")return;let t=e.signal;if(t instanceof AbortSignal)return t}function ti(e){if(!e||typeof e!="object")return;let t=e.onAttemptEvent;return typeof t=="function"?t:void 0}function ei(e){if(!e||typeof e!="object")return;let t=e.onPaaProgress;return typeof t=="function"?t:void 0}function ni(e){if(!e||typeof e!="object")return;let t=e.onPaaDomEvidence;return typeof t=="function"?t:void 0}async function ai(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:D.item,answerContainer:D.answerContainer,clickTarget:D.clickTarget,expandedClass:D.expandedClass});return{capturedAt:new Date().toISOString(),...t,selectorVersion:Ye}}async function gt(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 Tt(e){if(e instanceof ft)return"error";if(e instanceof _)return"captcha";if(e instanceof te)return"location_mismatch";if(e instanceof Z)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":ri(t)?"proxy_tunnel_failed":li(t)?"proxy_unavailable":/timeout|timed out|Timeout \d+ms exceeded|deadline/i.test(t)?"timeout":"error"}function ii(e){return e.diagnostics.degradedResult?"degraded_result":e.diagnostics?.completionStatus??(e.totalQuestions>0?"paa_found":"no_paa")}function si(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 xn(e,t,n){let a=si(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 Ln(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 oi(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 X(e){return e instanceof Error?e.message:String(e)}function di(e){return e==="location"?Qa:Ce}function ri(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 li(e){return/proxy unavailable|proxy_unavailable|connection_test_failed|did not return a proxy id|configured fallback/i.test(e)}function On(e){return e==="captcha"||e==="proxy_tunnel_failed"||e==="proxy_unavailable"}function Bn(e){return e==="browser_session_interrupted"}function Si(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 Ui(e,t){return t==="location"&&e.diagnostics.debug?.locationEvidence?.status==="mismatch"}function Hn(e,t){if(t||!e.diagnostics.debug)return e;let n={...e.diagnostics};return delete n.debug,{...e,diagnostics:n}}async function Fn(e,t){let n=t==null?3e3:t-Date.now();if(n<=0)return e;try{return await gn(e,{totalBudgetMs:Math.min(3e3,n)})}catch(a){return console.warn(JSON.stringify({event:"harvest_goto_resolution_failed",message:X(a)})),e}}async function ke(e,t){if(!(!e||!t))try{await Pn(e,t),console.info(JSON.stringify({event:"kernel_proxy_deleted",proxy_id_suffix:t.slice(-6)}))}catch(n){console.warn(JSON.stringify({event:"kernel_proxy_delete_failed",proxy_id_suffix:t.slice(-6),message:X(n)}))}}async function Rn(e,t,n,a,s,i){let d=Qe(t),U=new qt,S=new _t(d,U,a,s);if(n?.aborted)return{result:null,error:pe(n),cleanup:await d.close(),debug:null};let h,l=n?new Promise((g,N)=>{h=()=>N(pe(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 N=ai(d);N.catch(()=>{});let b=await Promise.race([N,new Promise((C,x)=>{g=setTimeout(()=>x(new DOMException("PAA DOM evidence timed out","TimeoutError")),2e3)})]);await i(b)}catch(N){console.warn(JSON.stringify({event:"paa_dom_evidence_failed",message:X(N)}))}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=Tt(r),N=g==="timeout"||g==="request_aborted"||g==="browser_session_interrupted"?g:null,b=null;if(N)try{b=typeof S.getPartialResult=="function"?S.getPartialResult():null}catch{b=null}return b&&N?(b.diagnostics={...b.diagnostics,interruption:{code:N,reasonSource:"client_runtime",message:X(r)}},{result:b,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 Xs(e){let t=typeof e=="object"&&e!==null?e:{},n=Xa(e),a=ti(e),s=ei(e),i=ni(e),d=t.forceManagedSerp===!0,U=t.forceKernelSerp===!0,S=An({forceManagedSerp:d,forceKernelSerp:U}),h=t.proxyMode,l=h==="location"||h==="none"||h==="configured"?h:Lt,o=typeof t.kernelApiKey=="string"?t.kernelApiKey.trim():Pe(),r=typeof t.kernelProxyId=="string"?t.kernelProxyId.trim():void 0,u={kernelApiKey:o,proxyMode:l,configuredKernelProxyId: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,N=t.maxAttempts,b=typeof N=="number"&&Number.isInteger(N)&&N>=1?Math.min(Ce,N):di(l),C=Math.min(Ce,b),x=typeof t.softDeadlineMs=="number"?t.softDeadlineMs:null,O=new zt,H=null,f=l,p=0,L=()=>x==null||x-Date.now()>=Za;for(let T=0;T<C;T++){let y=T+1,P=Date.now();try{if(n?.aborted)throw pe(n);let w=In({intent:S,brightDataAvailable:je(),kernelFallbackAvailable:!!o,persistentKernelIdentityRequested:!!(t.serpIdentity||t.kernelProfileName),retryIndex:T,priorTerminalReason:H==null?null:Tt(H),softDeadlineMs:x}),M=ee.parse({...t,kernelApiKey:o,proxyMode:f,debug:c||g}),k=w.plannedProvider==="brightdata"?"brightdata_browser":M.serpIdentity?"kernel_persistent_identity":"kernel_browser";await gt(a,{type:"started",attemptNumber:y,maxAttempts:C,method:k,provider:k==="brightdata_browser"?"brightdata":"kernel",planReason:w.reasonCode,planTimeoutMs:w.timeoutMs,retryKind:y===1?null:w.attemptKind==="provider_fallback"?"provider_fallback":"same_method",retryReason:y===1||H==null?null:Tt(H),query:M.query,location:M.location??null,maxQuestions:M.maxQuestions,startedAt:new Date(P).toISOString()});let m=w.plannedProvider==="brightdata"?null:await bn({...u,proxyMode:f,attemptIndex:T,fresh:f==="location"});if(w.plannedProvider==="kernel"&&!m)throw new Error("Kernel proxy resolution did not produce an execution plan");let A={...t,kernelApiKey:o,...m?{kernelProxyId:m.kernelProxyId,kernelProxyResolution:m.resolution}:{},proxyMode:f,keepDefaultProxy:T>0,softDeadlineMs:x==null?void 0:P+w.timeoutMs,debug:c||g};f==="none"&&(A.kernelProxyId=void 0);let W=ee.parse(A);console.info(JSON.stringify({event:"harvest_attempt_started",attempt_number:y,max_attempts:C,query:W.query,location:W.location??null,max_questions:W.maxQuestions}));let I=Bt(),V=null,q=async R=>{Wn(R.provider)!==w.plannedProvider&&(V=new ft(w.plannedProvider,R.provider)),await gt(a,{type:"provider_session_started",attemptNumber:y,maxAttempts:C,provider:R.provider,providerSessionId:R.providerSessionId,billingMode:R.billingMode,observedAt:new Date().toISOString()})},J=I?.harvestBrowserMode==="headless-test"&&process.env[Ie]==="true",G=I?await Ae({...I,forceHeadless:J,forceHeadful:!J},()=>Rn(W,w,n,s,q,i)):await Rn(W,w,n,s,q,i);if(G.error||V){let R=V??G.error,E=Tt(R);(E==="captcha"||E==="proxy_tunnel_failed")&&f==="location"&&(p++,p>=2&&(f="none"));let $=!G.result&&T<C-1&&L()&&(E==="captcha"||Bn(E)||l==="location"&&On(E));if(E==="captcha"?console.warn(JSON.stringify({event:"harvest_attempt_captcha",attempt_number:y,max_attempts:C,message:X(R),will_retry:$})):$&&console.warn(JSON.stringify({event:"harvest_attempt_proxy_retry",attempt_number:y,max_attempts:C,outcome:E,message:X(R),will_retry:$})),await gt(a,{type:"finished",attemptNumber:y,maxAttempts:C,outcome:E,kernelSessionId:G.cleanup.kernelSessionId,questionCount:G.result?.totalQuestions??0,durationMs:Date.now()-P,error:X(R),willRetry:$,cleanup:G.cleanup,debug:G.debug,completedAt:new Date().toISOString()}),await ke(o,m?.disposableProxyId),H=R,$)continue;if(G.result&&!V){let et=await Fn(G.result,x);return Ln(xn(Hn(et,c),W.maxQuestions,W.questionsOnly),T,w.attemptKind==="provider_fallback"?1:0)}break}let j=G.result;if(!j)throw new Error("Harvest attempt completed without a result");if(Ui(j,l)){let R=new te(Si(j)),E=T<C-1&&L();if(console.warn(JSON.stringify({event:"harvest_attempt_location_mismatch",attempt_number:y,max_attempts:C,message:R.message,will_retry:E})),await gt(a,{type:"finished",attemptNumber:y,maxAttempts:C,outcome:"location_mismatch",kernelSessionId:G.cleanup.kernelSessionId,questionCount:j.totalQuestions,durationMs:Date.now()-P,error:R.message,willRetry:E,cleanup:G.cleanup,debug:G.debug,completedAt:new Date().toISOString()}),await ke(o,m?.disposableProxyId),H=R,E)continue;break}let yt=await Fn(j,x),B=Ln(xn(Hn(yt,c),W.maxQuestions,W.questionsOnly),T,w.attemptKind==="provider_fallback"?1:0),tt=ii(B),F=tt==="degraded_result"&&T<C-1&&L(),K=tt==="degraded_result"?oi(B):null;if(F&&console.warn(JSON.stringify({event:"harvest_attempt_degraded_result",attempt_number:y,max_attempts:C,degradation_reasons:B.diagnostics.degradationReasons,will_retry:!0})),await gt(a,{type:"finished",attemptNumber:y,maxAttempts:C,outcome:tt,kernelSessionId:G.cleanup.kernelSessionId,questionCount:B.totalQuestions,durationMs:Date.now()-P,error:K,willRetry:F,cleanup:G.cleanup,debug:G.debug,completedAt:new Date().toISOString()}),await ke(o,m?.disposableProxyId),F)continue;return(W.format==="json"||W.format==="both")&&await O.writeJSON(B,W.outputDir),(W.format==="csv"||W.format==="both")&&await Promise.all([O.writeCSV(B.flat,W.outputDir),B.videos.length>0?O.writeVideoCSV(B.videos,B.seed,W.outputDir):Promise.resolve(""),B.forums.length>0?O.writeForumCSV(B.forums,B.seed,W.outputDir):Promise.resolve(""),B.aiOverview.detected?O.writeAIOverviewCSV(B.aiOverview.citations,B.aiOverview.text,B.seed,W.outputDir):Promise.resolve(""),B.aiMode.detected?O.writeAIModeCSV(B.aiMode.citations,B.aiMode.text,B.seed,W.outputDir):Promise.resolve(""),B.whatPeopleSaying.length>0?O.writeWhatPeopleSayingCSV(B.whatPeopleSaying,B.seed,W.outputDir):Promise.resolve("")]),B}catch(w){let M=Tt(w);(M==="captcha"||M==="proxy_tunnel_failed")&&f==="location"&&(p++,p>=2&&(f="none"));let k=T<C-1&&L()&&(M==="captcha"||Bn(M)||l==="location"&&On(M));if(M==="captcha"?console.warn(JSON.stringify({event:"harvest_attempt_captcha",attempt_number:y,max_attempts:C,message:X(w),will_retry:k})):k&&console.warn(JSON.stringify({event:"harvest_attempt_proxy_retry",attempt_number:y,max_attempts:C,outcome:M,message:X(w),will_retry:k})),await gt(a,{type:"finished",attemptNumber:y,maxAttempts:C,outcome:M,kernelSessionId:null,questionCount:0,durationMs:Date.now()-P,error:X(w),willRetry:k,cleanup:{kernelSessionId:null,kernelDeleteStarted:!1,kernelDeleteSucceeded:null,kernelDeleteError:null,browserCloseSucceeded:null,browserCloseError:null},debug:null,completedAt:new Date().toISOString()}),H=w,k)continue;if(M==="captcha")break;throw w}}throw H&&!(H instanceof _)?H:(console.warn(JSON.stringify({event:"harvest_captcha_exhausted",max_attempts:C,session_kind:o?"kernel":"local"})),new _(We(`CAPTCHA on all ${C} fresh sessions. Try again in a few minutes.`)))}export{yi as a,Rt as b,Gt as c,pi as d,Ke as e,Xn as f,Vt as g,_e as h,ze as i,oe as j,je as k,Yt as l,nn as m,Se as n,rt as o,Jt as p,Ts as q,jt as r,Ps as s,bs as t,ge as u,Ls as v,Pn as w,Os as x,bn as y,Xs as z};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var o="0.94.1";export{o as a};
|
package/dist/chunk-SH5KB4P7.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function R(e,_=!1,n="light",r=1){let E=_&&n==="full"?r>=2?75e3:45e3:_?4e4:4e5,t=Math.min(E+5e3,795e3);return{serverMs:E,clientMs:t}}function s(){return(process.env.BROWSER_SERVICE_API_KEY??process.env
|
|
1
|
+
function R(e,_=!1,n="light",r=1){let E=_&&n==="full"?r>=2?75e3:45e3:_?4e4:4e5,t=Math.min(E+5e3,795e3);return{serverMs:E,clientMs:t}}function s(){return(process.env.BROWSER_SERVICE_API_KEY??process.env.KERNEL_API_KEY)?.trim()||void 0}function S(){return(process.env.BROWSER_AGENT_PROFILE_NAME??process.env.BROWSER_SERVICE_PROFILE_NAME??process.env.KERNEL_BROWSER_PROFILE_NAME??process.env.KERNEL_PROFILE_NAME)?.trim()||void 0}function u(){let e=(process.env.BROWSER_AGENT_PROFILE_SAVE_CHANGES??process.env.BROWSER_SERVICE_PROFILE_SAVE_CHANGES??process.env.KERNEL_BROWSER_PROFILE_SAVE_CHANGES??process.env.KERNEL_PROFILE_SAVE_CHANGES)?.trim().toLowerCase();if(e){if(["1","true","yes","on"].includes(e))return!0;if(["0","false","no","off"].includes(e))return!1}}export{R as a,s as b,S as c,u as d};
|