mcp-scraper 0.90.6 → 0.90.7
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 +18 -2
- package/README.md +1 -1
- package/dist/{analytics-repository-WNJESD4A.js → analytics-repository-FXS45ZTM.js} +1 -1
- 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-MADTJXNI.js → chunk-5NQY2N7J.js} +105 -105
- package/dist/{chunk-COIA4RW4.js → chunk-74HHYSAZ.js} +1 -1
- package/dist/{chunk-BVSK6YHX.js → chunk-B2C7JU4O.js} +1 -1
- package/dist/{chunk-56UT5M5Y.js → chunk-BDLR4CCL.js} +3 -3
- package/dist/{chunk-5MMN27Q6.js → chunk-DSK6RKBS.js} +1 -1
- package/dist/{chunk-AAJG5OHF.js → chunk-I7IS7NTC.js} +1 -1
- package/dist/{chunk-Q5SUDDSQ.js → chunk-IGJKAECE.js} +1 -1
- package/dist/chunk-KDDU6BW3.js +48 -0
- package/dist/{chunk-NWRRVZKW.js → chunk-LPEIHMYH.js} +1 -1
- package/dist/{chunk-YDOBZMLS.js → chunk-OT2HUS2G.js} +1 -1
- package/dist/{chunk-AQSMJCTF.js → chunk-QUFR3KG2.js} +1 -1
- package/dist/{chunk-AQXYXVOP.js → chunk-R7LCD65B.js} +1 -1
- package/dist/{chunk-XXK5PLRB.js → chunk-TBTA7VVZ.js} +9 -8
- package/dist/{chunk-KKHTMYCD.js → chunk-TOJBPATJ.js} +1 -0
- package/dist/{chunk-4OTWTGKC.js → chunk-UKFNSXP3.js} +1 -1
- package/dist/chunk-WEPU72WA.js +1 -0
- package/dist/{chunk-D6BTAT5Y.js → chunk-YGBTTW5D.js} +1 -1
- package/dist/{chunk-WDB5CTRY.js → chunk-YTEAWZEN.js} +1 -1
- package/dist/{chunk-XARSC34L.js → chunk-ZKQRA6NQ.js} +5 -5
- package/dist/{db-XN7YPDGC.js → db-SVSD2AWJ.js} +1 -1
- package/dist/{extract-bundle-CP6WBOJI.js → extract-bundle-INT6JMJP.js} +1 -1
- package/dist/{gmail-service-5NH2GVQ5.js → gmail-service-YCPMGW3E.js} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/{lead-list-enrichment-repository-AIMOP7YM.js → lead-list-enrichment-repository-B6Q4O4DG.js} +1 -1
- package/dist/{location-data-repository-25D3GHXE.js → location-data-repository-CBI5K7MR.js} +1 -1
- package/dist/{server-TQJ6Z3ZF.js → server-LYWW6XYE.js} +479 -454
- package/dist/{site-extract-repository-KG6FQU55.js → site-extract-repository-VPYOC3CP.js} +1 -1
- package/dist/{stripe-event-worker-ZNNQEVK4.js → stripe-event-worker-AQVRF24K.js} +1 -1
- package/dist/worker-U43KLOLN.js +1 -0
- package/package.json +1 -1
- package/dist/chunk-NOUHD54C.js +0 -48
- package/dist/chunk-UM4WSLKQ.js +0 -1
- package/dist/worker-4LFWAEX2.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{t as r}from"./chunk-
|
|
1
|
+
import{t as r}from"./chunk-TOJBPATJ.js";import{createHash as b,randomUUID as O}from"crypto";var p="mcp-scraper/lead-list-enrichment.requested",A=new Set(["complete","partial","empty","failed","cancelled"]),U=new Set(["complete","failed","cancelled"]),T=10,g=360,S=60,h=null,m=null;function o(e,t,s){let n=e.trim();if(!n||n.length>s)throw new Error(`${t} is required and must be ${s} characters or fewer`);return n}function d(e,t){if(!Number.isSafeInteger(e)||e<0)throw new Error(`${t} must be a non-negative safe integer`);return e}function u(e){if(e==null)return null;try{return JSON.parse(String(e))}catch{return null}}function R(e){let t=new WeakSet,s=n=>{if(n===null||typeof n=="string"||typeof n=="boolean")return n;if(typeof n=="number"){if(!Number.isFinite(n))throw new Error("canonical fingerprint input must contain finite numbers");return Object.is(n,-0)?0:n}if(Array.isArray(n))return n.map(s);if(typeof n=="object"){if(t.has(n))throw new Error("canonical fingerprint input must not be cyclic");t.add(n);let i={};for(let _ of Object.keys(n).sort()){let c=n[_];c!==void 0&&(i[_]=s(c))}return t.delete(n),i}throw new Error(`canonical fingerprint input contains unsupported ${typeof n}`)};return JSON.stringify(s(e))}function y(e){return b("sha256").update(R(e)).digest("hex")}function I(e){return b("sha256").update(R(e)).digest("hex")}function j(){return{mapsAttempts:0,pageAttempts:0,pageSuccesses:0,serpSearches:0}}function E(e){let t=u(e.input_json);if(!t)throw new Error(`lead list enrichment job ${String(e.id??"")} has invalid durable input`);return{id:String(e.id),userId:Number(e.user_id),idempotencyKey:String(e.idempotency_key),requestFingerprint:String(e.request_fingerprint),input:t,status:String(e.status),totalRows:Number(e.total_rows??0),doneRows:Number(e.done_rows??0),failedRows:Number(e.failed_rows??0),cancelledRows:Number(e.cancelled_rows??0),usage:{mapsAttempts:Number(e.maps_attempts??0),pageAttempts:Number(e.page_attempts??0),pageSuccesses:Number(e.page_successes??0),serpSearches:Number(e.serp_searches??0)},concurrencyLockId:e.concurrency_lock_id==null?null:String(e.concurrency_lock_id),debitKey:String(e.debit_key),holdMc:Number(e.hold_mc??0),billedMc:e.billed_mc==null?null:Number(e.billed_mc),result:u(e.result_json),csvArtifact:u(e.csv_artifact_json),xlsxArtifact:u(e.xlsx_artifact_json),warnings:u(e.warnings_json)??[],cancelRequestedAt:e.cancel_requested_at==null?null:String(e.cancel_requested_at),errorCode:e.error_code==null?null:String(e.error_code),errorMessage:e.error_message==null?null:String(e.error_message),retryable:e.retryable==null?null:Number(e.retryable)===1,createdAt:String(e.created_at??""),startedAt:e.started_at==null?null:String(e.started_at),completedAt:e.completed_at==null?null:String(e.completed_at),updatedAt:String(e.updated_at??"")}}function w(e){return{jobId:String(e.job_id),ordinal:Number(e.ordinal),inputDigest:String(e.input_digest),status:String(e.status),result:u(e.result_json),usage:{mapsAttempts:Number(e.maps_attempts??0),pageAttempts:Number(e.page_attempts??0),pageSuccesses:Number(e.page_successes??0),serpSearches:Number(e.serp_searches??0)},errorCode:e.error_code==null?null:String(e.error_code),errorMessage:e.error_message==null?null:String(e.error_message),retryable:Number(e.retryable??0)===1,durationMs:Number(e.duration_ms??0),startedAt:e.started_at==null?null:String(e.started_at),completedAt:e.completed_at==null?null:String(e.completed_at),updatedAt:String(e.updated_at??"")}}function M(e){return{id:String(e.id),jobId:String(e.job_id),eventName:p,status:String(e.status),attempts:Number(e.attempts??0),claimToken:e.locked_by==null?null:String(e.locked_by),lockedUntil:e.locked_until==null?null:String(e.locked_until),nextAttemptAt:e.next_attempt_at==null?null:String(e.next_attempt_at),lastError:e.last_error==null?null:String(e.last_error),createdAt:String(e.created_at??""),dispatchedAt:e.dispatched_at==null?null:String(e.dispatched_at),updatedAt:String(e.updated_at??"")}}async function a(){let e=r();return h!==e&&(h=e,m=null),m||(m=(async()=>{await e.execute(`CREATE TABLE IF NOT EXISTS lead_list_enrichment_jobs (
|
|
2
2
|
id TEXT PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id), idempotency_key TEXT NOT NULL,
|
|
3
3
|
request_fingerprint TEXT NOT NULL, input_json TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'initializing',
|
|
4
4
|
total_rows INTEGER NOT NULL DEFAULT 0, done_rows INTEGER NOT NULL DEFAULT 0,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{b as O}from"./chunk-KJQXUZ4Y.js";import{t as N}from"./chunk-
|
|
1
|
+
import{b as O}from"./chunk-KJQXUZ4Y.js";import{t as N}from"./chunk-TOJBPATJ.js";import{createHash as M,randomUUID as z}from"crypto";var D="us_zip_groups",K="us_census_places",P=25e3,k=["AL","AK","AZ","AR","CA","CO","CT","DE","DC","FL","GA","HI","ID","IL","IN","IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ","NM","NY","NC","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"],$={AL:"01",AK:"02",AZ:"04",AR:"05",CA:"06",CO:"08",CT:"09",DE:"10",DC:"11",FL:"12",GA:"13",HI:"15",ID:"16",IL:"17",IN:"18",IA:"19",KS:"20",KY:"21",LA:"22",ME:"23",MD:"24",MA:"25",MI:"26",MN:"27",MS:"28",MO:"29",MT:"30",NE:"31",NV:"32",NH:"33",NJ:"34",NM:"35",NY:"36",NC:"37",ND:"38",OH:"39",OK:"40",OR:"41",PA:"42",RI:"44",SC:"45",SD:"46",TN:"47",TX:"48",UT:"49",VT:"50",VA:"51",WA:"53",WV:"54",WI:"55",WY:"56"},x=new Set(k),A=200,H=2e3,v=null,w=null;function b(t){return t.toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function Y(t){if(t==null)return[];try{let o=JSON.parse(String(t));return Array.isArray(o)?o.map(String):[]}catch{return[]}}function C(t){return{id:String(t.id),kind:String(t.dataset_kind),sourceUrl:t.source_url==null?null:String(t.source_url),sha256:String(t.sha256),rowCount:Number(t.row_count??0),groupCount:Number(t.group_count??0),stateCount:Number(t.state_count??0),sourceRowCount:Number(t.source_row_count??t.row_count??0),rejectedRowCount:Number(t.rejected_row_count??0),zipCount:Number(t.zip_count??0),coveredStates:Y(t.covered_states_json),coverageComplete:Number(t.coverage_complete??0)===1,status:String(t.status),createdAt:String(t.created_at),completedAt:t.completed_at==null?null:String(t.completed_at),error:t.error==null?null:String(t.error)}}function F(t){return`${K}:${t}`}function X(t){let o=t?.trim();if(!o)return null;if(o.length>H)throw new Error(`sourceUrl must be ${H} characters or fewer`);let a;try{a=new URL(o)}catch{throw new Error("sourceUrl must be a valid URL")}return a.username="",a.password="",a.search="",a.hash="",a.toString()}function q(t){let o=t.trim();return/^\d{1,5}$/.test(o)?o.padStart(5,"0"):null}function f(t){let o=t.trim().toUpperCase();return x.has(o)?o:null}function y(t,o){for(let a of o){let r=t[a];if(r!==void 0)return r}return""}function g(t){if(t===void 0||t.trim()==="")return null;let o=Number(t);return Number.isFinite(o)&&o>=0?Math.trunc(o):null}function V(t){return/^Nashville-Davidson metropolitan government/i.test(t)?"Nashville":t.replace(/\s+(city|town|village|municipality|borough)$/i,"").trim()}function B(t,o){let a=O(t.replace(/^\uFEFF/,""));if(a.length===0)throw new Error("Census place CSV contains no data rows.");let r=new Set(Object.keys(a[0]??{}).map(e=>e.trim())),u=["SUMLEV","STATE","NAME","POPESTIMATE2020","POPESTIMATE2021","POPESTIMATE2022","POPESTIMATE2023","POPESTIMATE2024","POPESTIMATE2025"].filter(e=>!r.has(e));if(u.length>0)throw new Error(`Census place CSV is missing required columns: ${u.join(", ")}.`);let d=a.filter(e=>e.SUMLEV?.trim()==="162");if(o){let e=o.padStart(2,"0"),s=d.filter(l=>l.STATE?.trim().padStart(2,"0")!==e);if(s.length>0){let l=[...new Set(s.map(c=>c.STATE?.trim()||"(blank)"))].slice(0,5);throw new Error(`Census place CSV STATE does not match requested FIPS ${e}; received ${l.join(", ")}.`)}}let E=d.map(e=>{let s=e.NAME?.trim()??"";if(!s)return null;let l=V(s),c=b(l);if(!c)return null;let T={2020:g(e.POPESTIMATE2020),2021:g(e.POPESTIMATE2021),2022:g(e.POPESTIMATE2022),2023:g(e.POPESTIMATE2023),2024:g(e.POPESTIMATE2024),2025:g(e.POPESTIMATE2025)};return Object.values(T).every(m=>m===null)?null:{city:l,cityKey:c,censusName:s,estimatesBase2020:g(e.ESTIMATESBASE2020),populations:T}}).filter(e=>e!==null),p=new Map,i=e=>e.populations[2025]??e.populations[2024]??e.populations[2023]??e.populations[2022]??e.populations[2021]??e.populations[2020]??e.estimatesBase2020??-1;for(let e of E){let s=p.get(e.cityKey);(!s||i(e)>i(s)||i(e)===i(s)&&e.censusName.localeCompare(s.censusName)<0)&&p.set(e.cityKey,e)}let _=[...p.values()].sort((e,s)=>e.city.localeCompare(s.city));if(_.length===0)throw new Error("Census place CSV did not contain any valid place population rows.");return{sourceRowCount:a.length,places:_}}function W(t){let o=O(t.replace(/^\uFEFF/,""));if(o.length===0)throw new Error("Location ZIP CSV contains no data rows.");let a=o[0]??{},r=new Set(Object.keys(a).map(s=>s.trim().toLowerCase())),n=["state_abbr","state","state_id"].some(s=>r.has(s)),u=["city","primary_city"].some(s=>r.has(s)),d=["zipcode","zip","zip_code"].some(s=>r.has(s));if(!n||!u||!d)throw new Error("Location ZIP CSV must include state_abbr/state, city, and zipcode/zip columns.");let E=new Map,p=0,i=0,_=new Set,e=new Set;for(let s of o){let l=Object.fromEntries(Object.entries(s).map(([G,j])=>[G.trim().toLowerCase(),j])),c=f(y(l,["state_abbr","state","state_id"])),T=y(l,["city","primary_city"]).trim(),m=q(y(l,["zipcode","zip","zip_code"])),S=y(l,["county","county_name"]).trim();if(!c||!x.has(c)||!T||!m){i+=1;continue}let I=b(T);if(!I){i+=1;continue}let U=`${c}\0${I}`,L=E.get(U);L||(L={city:T,cityKey:I,state:c,zips:new Set,counties:new Set},E.set(U,L)),L.zips.add(m),S&&L.counties.add(S),_.add(c),e.add(m),p+=1}if(E.size===0)throw new Error("Location ZIP CSV did not contain any valid US city/ZIP rows.");return{sourceRowCount:o.length,rowCount:p,rejectedRowCount:i,zipCount:e.size,stateCount:_.size,coveredStates:[..._].sort(),groups:[...E.values()].map(s=>({city:s.city,cityKey:s.cityKey,state:s.state,zips:[...s.zips].sort(),counties:[...s.counties].sort()})).sort((s,l)=>s.state.localeCompare(l.state)||s.city.localeCompare(l.city))}}function J(t){let o=new Set(t.coveredStates),a=k.filter(n=>!o.has(n)),r=[];if(a.length>0&&r.push(`missing required states: ${a.join(", ")}`),t.zipCount<P&&r.push(`only ${t.zipCount} unique ZIPs; at least ${P} are required`),r.length>0)throw new Error(`Location ZIP snapshot is not nationwide and was not activated (${r.join("; ")}; ${t.rejectedRowCount} rejected rows).`)}async function R(){let t=N();v!==t&&(v=t,w=null),w||(w=(async()=>{await t.execute(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS location_data_imports (
|
|
3
3
|
id TEXT PRIMARY KEY,
|
|
4
4
|
dataset_kind TEXT NOT NULL,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{t as _}from"./chunk-
|
|
1
|
+
import{t as _}from"./chunk-TOJBPATJ.js";import{AsyncLocalStorage as N}from"async_hooks";var D="MCP_SCRAPER_ALLOW_HEADLESS_HARVEST_TEST",d=new N;function C(e,t){return d.run(e,t)}function l(){return d.getStore()}var p=166667e-10,L=.0001333336,y=new Set(["serp","fb_search","fb_ad","instagram"]),A=.00111,R=4,g=4e-4;function o(e,t){let r=process.env[e]?.trim();if(!r)return t;let n=Number(r);return Number.isFinite(n)&&n>=0?n:t}var m=o("NANGO_USD_PER_CONNECTION_MONTH",1),U=o("NANGO_USD_PER_FUNCTION_RUN",1e-4),S=o("NANGO_USD_PER_PROXY_REQUEST",1e-4),O=o("NANGO_USD_PER_COMPUTE_SEC",2e-4),I=o("\u0042\u0052\u0049\u0047\u0048\u0054\u0044\u0041\u0054\u0041_BROWSER_USD_PER_GB",8),f=o("\u0042\u0052\u0049\u0047\u0048\u0054\u0044\u0041\u0054\u0041_SERP_USD_PER_REQUEST",.002836168);function u(e,t){return Math.max(0,e)/1e3*(t?L:p)}function i(e,t){return e==="fal_wizper"?Math.max(0,t)/R*A:e==="deepinfra_qwen"?Math.max(0,t)/1e3*g:e==="openrouter"||e==="mcp_memory_video"||e==="mcp_memory_ai"?Math.max(0,t):e==="nango_connection"?Math.max(0,t)*m:e==="nango_function_run"?Math.max(0,t)*U:e==="nango_proxy_request"?Math.max(0,t)*S:e==="nango_compute"?Math.max(0,t)*O:e==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061_browser_api"?Math.max(0,t)/1e9*I:0}import{randomUUID as T}from"crypto";var E=!1,s=null;async function c(){if(!E)return s||(s=b().finally(()=>{s=null}),s)}async function b(){let e=_(),t=await e.execute(`
|
|
2
2
|
SELECT
|
|
3
3
|
(SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name IN ('\u006b\u0065\u0072\u006e\u0065\u006c_session_log', 'vendor_usage_log', 'cost_probe_runs')) = 3
|
|
4
4
|
AND (SELECT COUNT(*) FROM pragma_table_info('\u006b\u0065\u0072\u006e\u0065\u006c_session_log') WHERE name IN ('proxy_source', 'proxy_type', 'method')) = 3
|
|
@@ -44,7 +44,7 @@ import{t as _}from"./chunk-KKHTMYCD.js";import{AsyncLocalStorage as N}from"async
|
|
|
44
44
|
provider_status TEXT,
|
|
45
45
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
46
46
|
)
|
|
47
|
-
`),await e.execute("CREATE INDEX IF NOT EXISTS vendor_usage_log_op ON vendor_usage_log(op)"),await e.execute("CREATE INDEX IF NOT EXISTS vendor_usage_log_probe ON vendor_usage_log(probe_run_id)"),await e.execute("CREATE INDEX IF NOT EXISTS vendor_usage_log_created ON vendor_usage_log(created_at)");try{await e.execute("ALTER TABLE vendor_usage_log ADD COLUMN method TEXT")}catch{}try{await e.execute("ALTER TABLE vendor_usage_log ADD COLUMN source_key TEXT")}catch{}try{await e.execute("ALTER TABLE vendor_usage_log ADD COLUMN provider_duration_ms INTEGER")}catch{}try{await e.execute("ALTER TABLE vendor_usage_log ADD COLUMN provider_captcha INTEGER")}catch{}try{await e.execute("ALTER TABLE vendor_usage_log ADD COLUMN provider_status TEXT")}catch{}await e.execute("CREATE UNIQUE INDEX IF NOT EXISTS vendor_usage_log_vendor_source_key ON vendor_usage_log(vendor, source_key) WHERE source_key IS NOT NULL"),await e.execute(`
|
|
47
|
+
`),await e.execute("CREATE INDEX IF NOT EXISTS vendor_usage_log_op ON vendor_usage_log(op)"),await e.execute("CREATE INDEX IF NOT EXISTS vendor_usage_log_probe ON vendor_usage_log(probe_run_id)"),await e.execute("CREATE INDEX IF NOT EXISTS vendor_usage_log_created ON vendor_usage_log(created_at)");try{await e.execute("ALTER TABLE vendor_usage_log ADD COLUMN method TEXT")}catch{}try{await e.execute("ALTER TABLE vendor_usage_log ADD COLUMN source_key TEXT")}catch{}try{await e.execute("ALTER TABLE vendor_usage_log ADD COLUMN provider_duration_ms INTEGER")}catch{}try{await e.execute("ALTER TABLE vendor_usage_log ADD COLUMN provider_captcha INTEGER")}catch{}try{await e.execute("ALTER TABLE vendor_usage_log ADD COLUMN provider_status TEXT")}catch{}await e.execute("CREATE UNIQUE INDEX IF NOT EXISTS vendor_usage_log_vendor_source_key ON vendor_usage_log(vendor, source_key) WHERE source_key IS NOT NULL"),await e.execute("CREATE INDEX IF NOT EXISTS vendor_usage_log_vendor_method_created ON vendor_usage_log(vendor, method, created_at)"),await e.execute(`
|
|
48
48
|
CREATE TABLE IF NOT EXISTS cost_probe_runs (
|
|
49
49
|
id TEXT PRIMARY KEY,
|
|
50
50
|
tool TEXT NOT NULL,
|
|
@@ -70,4 +70,4 @@ import{t as _}from"./chunk-KKHTMYCD.js";import{AsyncLocalStorage as N}from"async
|
|
|
70
70
|
(id, \u006b\u0065\u0072\u006e\u0065\u006c_session_id, op, source, probe_run_id, user_id, stealth, headless_sent, proxy_used, proxy_source, proxy_type, fallback, opened_at, closed_at, duration_ms, est_cost_usd_headless, est_cost_usd_headful, error, method)
|
|
71
71
|
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,args:[T(),e.\u006b\u0065\u0072\u006e\u0065\u006cSessionId??null,t?.op??null,e.source,t?.probeRunId??null,t?.userId??null,a(e.stealth),a(e.headlessSent),a(e.proxyUsed),e.proxySource??null,e.proxyType??null,e.fallback?1:0,new Date(e.openedAtMs).toISOString(),new Date(e.closedAtMs).toISOString(),r,u(r,!1),u(r,!0),e.error??null,t?.subOp??null]})}catch(t){console.warn("[cost-telemetry] record\u004b\u0065\u0072\u006e\u0065\u006cSession failed:",t instanceof Error?t.message:String(t))}}async function P(e){try{await c();let t=l();return(await _().execute({sql:`INSERT OR IGNORE INTO vendor_usage_log
|
|
72
72
|
(id, op, probe_run_id, user_id, vendor, model, units, unit_type, est_cost_usd, error, method, source_key, provider_duration_ms, provider_captcha, provider_status)
|
|
73
|
-
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,args:[T(),e.op??t?.op??null,e.probeRunId??t?.probeRunId??null,e.userId??t?.userId??null,e.vendor,e.model??null,e.units,e.unitType,
|
|
73
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,args:[T(),e.op??t?.op??null,e.probeRunId??t?.probeRunId??null,e.userId??t?.userId??null,e.vendor,e.model??null,e.units,e.unitType,i(e.vendor,e.units),e.error??null,e.method??t?.subOp??null,e.sourceKey??null,e.providerDurationMs??null,a(e.providerCaptcha),e.providerStatus??null]})).rowsAffected===1}catch(t){return console.warn("[cost-telemetry] recordVendorUsage failed:",t instanceof Error?t.message:String(t)),!1}}function a(e){return e==null?null:e?1:0}export{D as a,C as b,l as c,L as d,y as e,f,u as g,i as h,c as i,F as j,P as k};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var s={message:"
|
|
1
|
+
var s={message:"Hosted background work now runs on schedules matched to how quickly each result matters, form deliveries and billing changes apply immediately, and X-Ray privacy retention is running again."};var _={reset:"\x1B[0m",cyan:"\x1B[36m",lime:"\x1B[32m",amber:"\x1B[33m",red:"\x1B[31m",muted:"\x1B[90m",bold:"\x1B[1m"};function r(t,e,n){return n?`${_[e]}${t}${_.reset}`:t}function o(t,e,n){let a=t.padEnd(9," ");return` ${r(a,"muted",n)} ${e.join(r(" . ","muted",n))}`}function p(t){let e=t.color??!0,n=t.apiKeyConfigured?"$MCP_SCRAPER_API_KEY":"sk_live_your_key",a=String.raw`
|
|
2
2
|
__ __ ____ ____
|
|
3
3
|
| \/ |/ ___| _ \
|
|
4
4
|
| |\/| | | | |_) |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as _,i as c}from"./chunk-
|
|
1
|
+
import{g as _,i as c}from"./chunk-TOJBPATJ.js";var g={\u006b\u0065\u0072\u006e\u0065\u006c:"browserRuntime"},a=/error|message/i,w=(new RegExp("(?:spending|billing|organization|account).{0,80}(?:cap|limit|blocked|disabled)|(?:quota|capacity).{0,40}(?:reached|exceeded)|https?:\\/\\/\\S*(?:dashboard|on\u006b\u0065\u0072\u006e\u0065\u006c)", "i")),E=/\b(?:ENOENT|ENOTDIR|EACCES|EPERM|EISDIR|EMFILE|ENFILE)\b|\b(?:mkdir|open|stat|lstat|readFile|writeFile)\s+['"]?(?:\/|[A-Za-z]:\\)|(?:^|[\s'"])(?:\/Users|\/home|\/tmp|\/var|\/private|\/opt|\/srv|\/root)\//i,k=new Set(["\u006b\u0065\u0072\u006e\u0065\u006c_session_id","browser_session_id","\u006b\u0065\u0072\u006e\u0065\u006cSessionId","browserSessionId","sessionId","\u006b\u0065\u0072\u006e\u0065\u006c_delete_started","session_cleanup_started","\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted","sessionCleanupStarted","\u006b\u0065\u0072\u006e\u0065\u006c_delete_succeeded","session_cleanup_succeeded","\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded","sessionCleanupSucceeded","\u006b\u0065\u0072\u006e\u0065\u006c_delete_error","session_cleanup_error","\u006b\u0065\u0072\u006e\u0065\u006cDeleteError","sessionCleanupError","\u006b\u0065\u0072\u006e\u0065\u006cProxyId","proxyId","requestedProxyIdSuffix","retrievedProxyIdSuffix","provider","providerName","service","serviceName","vendor","vendorName","organization","organizationId","accountId","browser_provider","provider_session_id","provider_session_observed_at","provider_lookup_status","provider_status","provider_error_code","provider_error_message","provider_reason_source","provider_duration_ms","provider_bandwidth_bytes","provider_captcha","provider_checked_at","provider_detail","provider_detail_json","provider_disconnect_observed","provider_disconnect_message","browserProvider","providerSessionId","providerLookupStatus","providerStatus","providerErrorCode","providerErrorMessage","providerReasonSource","providerDurationMs","providerBandwidthBytes","providerCaptcha","providerCheckedAt","providerDetail","providerDisconnectObserved","providerDisconnectMessage"]),S=new Set(["hosted_url","hostedUrl","live_view_url","liveViewUrl","cdp_ws_url","cdpWsUrl","browser_live_view_url"]),f=(new RegExp("\\b(?:wss?|https?):\\/\\/[^\\s\"'<>]*\\bon\u006b\u0065\u0072\u006e\u0065\u006c\\.com[^\\s\"'<>]*", "gi"));function b(e){return e.replace(f,"[browser-service]")}var R=new Set(["\u0062\u0072\u0069\u0067\u0068\u0074_\u0064\u0061\u0074\u0061_browser_api","\u006b\u0065\u0072\u006e\u0065\u006c","local"]),m=new Set(["pending","complete","not_found","unavailable_credentials","temporary_error","invalid_payload","not_applicable"]),h=new Set(["active","running","complete","completed","failed","closed","stopped","terminated","timed_out"]),I=new Set(["provider_session_api","client_runtime","extractor","unknown"]),y=new Set(["browser_disconnected","worker_disconnect","job_killed","cdp_cmd_timeout","network_inactivity_timeout","session_timeout","client_timeout","navigate_domains_limit","cdp_error","browser_session_interrupted","provider_detail_pending","provider_lookup_unavailable","provider_reported_no_error","provider_session_not_found","provider_invalid_json","provider_invalid_payload","provider_lookup_timeout","provider_lookup_network_error","unknown"]),T=new Set(["browser_provider","provider_session_id","provider_lookup_status","provider_status","provider_error_code","provider_error_message","provider_reason_source","provider_duration_ms","provider_bandwidth_bytes","provider_captcha","provider_checked_at","provider_detail","provider_detail_json","provider_disconnect_observed","provider_disconnect_message"]),P=512,A=320;function t(e,r){return typeof e=="string"&&r.has(e)?e:null}function O(e){return typeof e!="string"?null:y.has(e)||/^provider_http_(?:429|5\d\d)$/.test(e)?e:null}function D(e){return typeof e!="string"||e.length<1||e.length>P||/^(?:authorization|bearer|password|secret|token|api[_-]?key|account)/i.test(e)?null:/^[A-Za-z0-9._:-]+$/.test(e)&&!e.includes("://")?e:null}function p(e){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=0?e:null}function l(e){if(typeof e!="string"||e.length>40)return null;let r=Date.parse(e);return Number.isFinite(r)&&new Date(r).toISOString()===e?e:null}function u(e){if(typeof e!="string")return null;let r=e.replace(/[\u0000-\u001f\u007f]+/g," ").replace(/\s+/g," ").trim();if(!r||r.startsWith("{")||r.startsWith("["))return null;let o=r.replace(/\b(?:wss?|https?):\/\/\S+/gi,"[redacted endpoint]").replace(/\b(?:authorization|proxy-authorization)\s*:\s*(?:Bearer\s+)?\S+/gi,"[redacted credential]").replace(/\bBearer\s+\S+/gi,"[redacted credential]").replace(/\b(?:api[_-]?key|password|secret|token|account[_-]?id)\s*[=:]\s*[^\s,;]+/gi,"[redacted credential]").replace(/\b(?:account|organization)\s+(?:id\s+)?[A-Za-z0-9_-]{4,}/gi,"[redacted account]");return b(o).slice(0,A)}function v(e){return typeof e=="boolean"?e:null}function N(e){return{browser_provider:t(e.browser_provider,R),provider_session_id:D(e.provider_session_id),provider_session_observed_at:l(e.provider_session_observed_at),provider_lookup_status:t(e.provider_lookup_status,m),provider_status:t(e.provider_status,h),provider_error_code:O(e.provider_error_code),provider_error_message:u(e.provider_error_message),provider_reason_source:t(e.provider_reason_source,I),provider_duration_ms:p(e.provider_duration_ms),provider_bandwidth_bytes:p(e.provider_bandwidth_bytes),provider_captcha:v(e.provider_captcha),provider_checked_at:l(e.provider_checked_at),provider_disconnect_observed:v(e.provider_disconnect_observed),provider_disconnect_message:u(e.provider_disconnect_message)}}function i(e,r=""){if(typeof e=="string"){let o=b(e);return a.test(r)&&(w.test(e)||E.test(e))?o=_("service_unavailable"):a.test(r)&&(o=c(o)),o}if(Array.isArray(e))return e.map(o=>i(o,r));if(e!==null&&typeof e=="object"){let o={};for(let[n,d]of Object.entries(e)){if(k.has(n))continue;let s=g[n]??n;if(S.has(n)){o[s]=null;continue}o[s]=i(d,n)}return o}return e}function L(e){return e.map(r=>{if(r===null||typeof r!="object"||Array.isArray(r))return i(r);let o=r,n=i(o);return Object.keys(o).some(s=>T.has(s))?{...n,...N(o)}:n})}function C(e){let r=e?.diagnostics;return r?.debug?{...e,diagnostics:{...r,debug:i(r.debug)}}:e}export{i as a,L as b,C as c};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Q as p,t as o}from"./chunk-
|
|
1
|
+
import{Q as p,t as o}from"./chunk-TOJBPATJ.js";import{createHmac as T,timingSafeEqual as y}from"crypto";var N=()=>process.env.NODE_ENV==="production"||process.env.VERCEL==="1";function S(){let e=process.env.SESSION_SECRET?.trim();if(e)return e;if(N())throw new Error("SESSION_SECRET is not set \u2014 add it to your Vercel env vars (see src/api/env.ts)");return"dev-secret-change-me"}var v=()=>S();function m(e,t){if(e.length!==t.length)return!1;try{return y(Buffer.from(e,"hex"),Buffer.from(t,"hex"))}catch{return!1}}function L(e){let t=String(e),n=T("sha256",v()).update(t).digest("hex");return`${t}.${n}`}function I(e){let t=e.lastIndexOf(".");if(t===-1)return null;let n=e.slice(0,t),r=e.slice(t+1),i=T("sha256",v()).update(n).digest("hex");if(!m(r,i))return null;let s=parseInt(n);return isNaN(s)?null:s}import{randomUUID as _}from"crypto";function x(e,t,n){return e.lifecycleStatus==="connected"&&e.actionsEnabled&&t.includes(e.providerConfigKey)&&e.actionTools.includes(n)}var a=null,u=null;function c(){let e=o();return a&&u===e||(u=e,a=(async()=>{let t=e;await t.execute(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS service_connections (
|
|
3
3
|
id TEXT PRIMARY KEY,
|
|
4
4
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import{a as re}from"./chunk-XG6GCEUE.js";import{w as Z}from"./chunk-R7LCD65B.js";import{b as N,c as ee}from"./chunk-I7IS7NTC.js";import{a as x,b as k}from"./chunk-CTX3NMZQ.js";import{a as F}from"./chunk-4FROKQJN.js";import{b as j,d as Y,g as X}from"./chunk-BDLR4CCL.js";import{Mb as b,Qb as A,Sb as I,Ua as R,b as S,g as p,gb as G,h as z,ha as J,ia as V,ib as O,j as $,ka as Q,m as W,na as E,o as B,t as l}from"./chunk-TOJBPATJ.js";async function P(e,r,t=3){for(let i=1;i<=t;i++){try{let a=await fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(r),signal:AbortSignal.timeout(1e4)});if(a.ok)return;console.warn(`[webhook] attempt ${i} \u2192 ${a.status} from ${e}`)}catch(a){console.warn(`[webhook] attempt ${i} failed:`,a instanceof Error?a.message:a)}i<t&&await new Promise(a=>setTimeout(a,1e3*i*2))}console.error(`[webhook] gave up after ${t} attempts for ${e}`)}function fe(e){return e instanceof Error?e.message:String(e)}function be(e,r){return e instanceof DOMException&&(e.name==="TimeoutError"||e.name==="AbortError")?!0:/timeout|timed out|Timeout \d+ms exceeded|deadline/i.test(r)}function ye(e){return/captcha|recaptcha|unusual traffic|google\.com\/sorry|blocked/i.test(e)}function he(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 we(e){return/proxy unavailable|proxy_unavailable|connection_test_failed|did not return a proxy id|configured fallback/i.test(e)}function ve(e){return/(?:spending|billing|organization|account).{0,80}(?:cap|limit|blocked|disabled)|(?:quota|capacity).{0,40}(?:reached|exceeded)|https?:\/\/\S*dashboard/i.test(e)}function Se(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(e)}function C(e){let r=fe(e);return e instanceof W?{error_code:"request_aborted",error_type:"request_aborted",message:p("request_aborted"),retryable:!0,httpStatus:408,terminalStatus:"cancelled"}:e instanceof $||ye(r)?{error_code:"captcha_exhausted",error_type:"captcha",message:p("captcha_exhausted"),retryable:!0,httpStatus:503,terminalStatus:"failed"}:re(e,r)?{error_code:"vendor_unavailable",error_type:"service_unavailable",message:p("vendor_unavailable"),retryable:!0,httpStatus:503,terminalStatus:"failed"}:e instanceof B?{error_code:"location_mismatch",error_type:"location_mismatch",message:p("location_mismatch"),retryable:!0,httpStatus:503,terminalStatus:"failed"}:he(r)?{error_code:"proxy_tunnel_failed",error_type:"connection",message:p("proxy_tunnel_failed"),retryable:!0,httpStatus:503,terminalStatus:"failed"}:we(r)?{error_code:"proxy_unavailable",error_type:"connection",message:p("proxy_unavailable"),retryable:!0,httpStatus:503,terminalStatus:"failed"}:Se(r)?{error_code:"browser_session_interrupted",error_type:"extraction",message:p("browser_session_interrupted"),retryable:!0,httpStatus:503,terminalStatus:"failed"}:be(e,r)?{error_code:"harvest_timeout",error_type:"timeout",message:p("harvest_timeout"),retryable:!0,httpStatus:504,terminalStatus:"failed"}:ve(r)?{error_code:"service_unavailable",error_type:"service_unavailable",message:S,retryable:!0,httpStatus:503,terminalStatus:"failed"}:{error_code:"extraction_failed",error_type:"extraction",message:S,retryable:!1,httpStatus:500,terminalStatus:"failed"}}function T(e){return JSON.stringify({error_code:e.error_code,error_type:e.error_type,message:e.message,retryable:e.retryable})}function y(e,r={}){let t=z({errorCode:e.error_code,errorType:e.error_type,retryable:e.retryable,retryAfterSeconds:r.retryAfterSeconds,chargeStatus:r.chargeStatus,details:r.details});return{error:t.message,...t}}function L(e,r={}){let{error:t,...i}=y(e,r);return i}function Ce(e,r={}){let t=C(e);return{body:y(t,r),status:t.httpStatus}}import{createHash as Re}from"crypto";import{createHash as Ee,randomUUID as h}from"crypto";var M=class extends Error{constructor(){super("This idempotency key was already used with different normalized inputs."),this.name="OperationIdempotencyConflictError"}};function g(e){return Ee("sha256").update(e).digest("hex")}function H(e){return Array.isArray(e)?e.map(H):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).sort(([r],[t])=>r.localeCompare(t)).map(([r,t])=>[r,H(t)])):e}function te(e){return JSON.stringify(H(e??{}))}function d(e,r){let t=e.trim();if(!t)throw new Error(`${r} is required`);return t}function m(e,r=2e3){return e==null?null:e.slice(0,r)}async function oe(e){let r=l(),t=d(e.tool,"tool"),i=d(e.ownerScope,"ownerScope"),a=e.idempotencyKey?.trim()||null,o=e.requestFingerprint?.trim()||null;if(a==null!=(o==null))throw new Error("idempotencyKey and requestFingerprint must be supplied together");let n=a?g(`${i}\0${t}\0${a}`):null,s=e.id??h(),u=[s,e.userId??null,g(i),t,n,o,e.jobId??null,e.requestId??null,e.deploymentCommit??null,te(e.normalizedFlags),e.startedAt??new Date().toISOString()];if(n){await r.execute({sql:`INSERT OR IGNORE INTO operation_runs
|
|
2
|
+
(id, user_id, owner_scope_hash, tool, idempotency_scope_hash, request_fingerprint,
|
|
3
|
+
job_id, request_id, deployment_commit, normalized_flags_json, started_at)
|
|
4
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,args:u});let f=(await r.execute({sql:"SELECT id, request_fingerprint FROM operation_runs WHERE idempotency_scope_hash = ?",args:[n]})).rows[0];if(!f)throw new Error("Operation run insert did not produce an idempotency receipt");if(String(f.request_fingerprint)!==o)throw new M;return{id:String(f.id),replayed:String(f.id)!==s}}return await r.execute({sql:`INSERT INTO operation_runs
|
|
5
|
+
(id, user_id, owner_scope_hash, tool, idempotency_scope_hash, request_fingerprint,
|
|
6
|
+
job_id, request_id, deployment_commit, normalized_flags_json, started_at)
|
|
7
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,args:u}),{id:s,replayed:!1}}async function ne(e){let r=e.endedAt??new Date().toISOString();if((await l().execute({sql:`UPDATE operation_runs
|
|
8
|
+
SET status = ?, failure_class = ?, ended_at = ?, updated_at = ?
|
|
9
|
+
WHERE id = ? AND status = 'running'`,args:[e.status,m(e.failureClass,200),r,r,e.runId]})).rowsAffected===1)return;let i=m(e.failureClass,200),a=await l().execute({sql:"SELECT status, failure_class FROM operation_runs WHERE id = ?",args:[e.runId]});if(a.rows.length===0)throw new Error(`Unknown operation run: ${e.runId}`);let o=a.rows[0]?.failure_class==null?null:String(a.rows[0]?.failure_class);if(String(a.rows[0]?.status)!==e.status||o!==i)throw new Error(`Operation run ${e.runId} is already terminal as ${String(a.rows[0]?.status)}`)}async function ie(e){if(!Number.isInteger(e.attemptNumber)||e.attemptNumber<1)throw new Error("attemptNumber must be a positive integer");if(e.attemptNumber===1&&(e.parentAttemptId||e.edgeKind||e.retryKind))throw new Error("The first attempt cannot have a parent or retry edge");if(e.attemptNumber>1&&(!e.parentAttemptId||!e.edgeKind))throw new Error("Every non-first attempt requires a parentAttemptId and edgeKind");if(e.retryKind&&!["same_method_retry","provider_fallback","durable_resume","reconciliation"].includes(e.edgeKind??""))throw new Error("retryKind requires a retry or reconciliation edgeKind");let r=e.id??h();return await l().execute({sql:`INSERT INTO operation_attempts
|
|
10
|
+
(id, run_id, parent_attempt_id, attempt_number, edge_kind, retry_kind, retry_reason, retry_owner,
|
|
11
|
+
method, provider, normalized_flags_json, started_at)
|
|
12
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,args:[r,e.runId,e.parentAttemptId??null,e.attemptNumber,e.edgeKind??null,e.retryKind??null,m(e.retryReason,500),m(e.retryOwner,100),d(e.method,"method"),e.provider??null,te(e.normalizedFlags),e.startedAt??new Date().toISOString()]}),r}async function ae(e){if(!Number.isInteger(e.durationMs)||e.durationMs<0)throw new Error("durationMs must be a non-negative integer");let r=e.endedAt??new Date().toISOString();if((await l().execute({sql:`UPDATE operation_attempts SET
|
|
13
|
+
status = ?, error_code = ?, error_message = ?, ended_at = ?, duration_ms = ?, updated_at = ?
|
|
14
|
+
WHERE id = ? AND status = 'running'`,args:[e.status,m(e.errorCode,200),m(e.errorMessage),r,e.durationMs,r,e.attemptId]})).rowsAffected===1)return;let i=await l().execute({sql:"SELECT status, duration_ms FROM operation_attempts WHERE id = ?",args:[e.attemptId]});if(i.rows.length===0)throw new Error(`Unknown operation attempt: ${e.attemptId}`);if(String(i.rows[0]?.status)!==e.status||Number(i.rows[0]?.duration_ms)!==e.durationMs)throw new Error(`Operation attempt ${e.attemptId} is already terminal as ${String(i.rows[0]?.status)}`)}async function D(e){let r=d(e.provider,"provider"),t=d(e.method,"method"),i=g(d(e.accountScope,"accountScope")),a=e.providerSourceKey?.trim()||null,o=a?g(a):null,n=e.id??h(),s=await l().execute({sql:`INSERT OR IGNORE INTO provider_usage_receipts
|
|
15
|
+
(id, attempt_id, provider, account_scope_hash, method, provider_source_key,
|
|
16
|
+
provider_source_key_hash, provider_status)
|
|
17
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,args:[n,e.attemptId,r,i,t,a,o,e.providerStatus??null]});if(!o){if(s.rowsAffected===1)return{id:n,replayed:!1};let _=(await l().execute({sql:"SELECT attempt_id, provider, method FROM provider_usage_receipts WHERE id = ?",args:[n]})).rows[0];if(!_||String(_.attempt_id)!==e.attemptId||String(_.provider)!==r||String(_.method)!==t)throw new Error("Provider receipt ID is already used by a different receipt");return{id:n,replayed:!0}}let c=(await l().execute({sql:`SELECT id, attempt_id FROM provider_usage_receipts
|
|
18
|
+
WHERE provider = ? AND account_scope_hash = ? AND method = ? AND provider_source_key_hash = ?`,args:[r,i,t,o]})).rows[0];if(!c)throw new Error("Provider receipt insert did not produce a source receipt");if(String(c.attempt_id)!==e.attemptId)throw new Error("Provider source identity is already attached to a different attempt");return{id:String(c.id),replayed:String(c.id)!==n}}async function se(e,r){let t=d(r,"providerSourceKey"),i=g(t);if((await l().execute({sql:`UPDATE provider_usage_receipts
|
|
19
|
+
SET provider_source_key = ?, provider_source_key_hash = ?, updated_at = datetime('now')
|
|
20
|
+
WHERE id = ? AND provider_source_key IS NULL`,args:[t,i,e]})).rowsAffected===1)return;let o=await l().execute({sql:"SELECT provider_source_key_hash FROM provider_usage_receipts WHERE id = ?",args:[e]});if(!o.rows[0])throw new Error(`Unknown provider receipt: ${e}`);if(String(o.rows[0].provider_source_key_hash)!==i)throw new Error(`Provider receipt ${e} already has a different source identity`)}async function w(e){if(e.units!=null&&(!Number.isFinite(e.units)||e.units<0))throw new Error("units must be non-negative");if(e.amountUsdNanos!=null&&(!Number.isSafeInteger(e.amountUsdNanos)||e.amountUsdNanos<0))throw new Error("amountUsdNanos must be a non-negative safe integer");if(e.costState==="actual"&&e.amountUsdNanos==null)throw new Error("actual receipts require amountUsdNanos");if(e.costState==="actual"&&e.amountUsdNanos===0&&!e.zeroCostReason?.trim())throw new Error("actual zero-cost receipts require zeroCostReason");let r=e.checkedAt??new Date().toISOString(),t=e.finalizedAt??r;if((await l().execute({sql:`UPDATE provider_usage_receipts SET
|
|
21
|
+
cost_state = ?, units = ?, unit_type = ?, amount_usd_nanos = ?, rate_source = ?, zero_cost_reason = ?,
|
|
22
|
+
provider_status = ?, provider_duration_ms = ?, provider_captcha = ?, error_code = ?, error_message = ?,
|
|
23
|
+
checked_at = ?, finalized_at = ?, updated_at = ?
|
|
24
|
+
WHERE id = ? AND (cost_state = 'pending' OR (cost_state = 'estimated' AND ? = 'actual'))`,args:[e.costState,e.units??null,e.unitType??null,e.amountUsdNanos??null,e.rateSource??null,e.zeroCostReason??null,e.providerStatus??null,e.providerDurationMs??null,e.providerCaptcha==null?null:e.providerCaptcha?1:0,m(e.errorCode,200),m(e.errorMessage),r,t,t,e.receiptId,e.costState]})).rowsAffected===1)return;let a=await l().execute({sql:"SELECT cost_state, units, unit_type, amount_usd_nanos FROM provider_usage_receipts WHERE id = ?",args:[e.receiptId]});if(a.rows.length===0)throw new Error(`Unknown provider receipt: ${e.receiptId}`);let o=a.rows[0],n=o?.units==null&&e.units==null||Number(o?.units)===e.units,s=o?.amount_usd_nanos==null&&e.amountUsdNanos==null||Number(o?.amount_usd_nanos)===e.amountUsdNanos,u=o?.unit_type==null&&e.unitType==null||String(o?.unit_type)===e.unitType;if(String(o?.cost_state)!==e.costState||!n||!s||!u)throw new Error(`Provider receipt ${e.receiptId} is already finalized as ${String(a.rows[0]?.cost_state)}`)}async function He(e){let t=(await l().execute({sql:`SELECT id FROM provider_usage_receipts
|
|
25
|
+
WHERE provider = ? AND account_scope_hash = ? AND method = ? AND provider_source_key_hash = ?`,args:[d(e.provider,"provider"),g(d(e.accountScope,"accountScope")),d(e.method,"method"),g(d(e.providerSourceKey,"providerSourceKey"))]})).rows[0];if(!t)return!1;let{provider:i,accountScope:a,method:o,providerSourceKey:n,...s}=e;return await w({...s,receiptId:String(t.id)}),!0}async function De(e=30){if(!Number.isInteger(e)||e<1||e>365)throw new Error("retentionDays must be an integer between 1 and 365");let r=`-${e} days`,t=l(),[i,a,o]=await Promise.all([t.execute({sql:`UPDATE operation_attempts
|
|
26
|
+
SET error_message = NULL, updated_at = datetime('now')
|
|
27
|
+
WHERE ended_at < datetime('now', ?) AND error_message IS NOT NULL`,args:[r]}),t.execute({sql:`UPDATE provider_usage_receipts
|
|
28
|
+
SET provider_source_key = NULL, error_message = NULL, updated_at = datetime('now')
|
|
29
|
+
WHERE finalized_at < datetime('now', ?)
|
|
30
|
+
AND (provider_source_key IS NOT NULL OR error_message IS NOT NULL)`,args:[r]}),t.execute({sql:`UPDATE harvest_attempts
|
|
31
|
+
SET provider_session_id = NULL, \u006b\u0065\u0072\u006e\u0065\u006c_session_id = NULL, error = NULL,
|
|
32
|
+
\u006b\u0065\u0072\u006e\u0065\u006c_delete_error = NULL, browser_close_error = NULL,
|
|
33
|
+
provider_error_message = NULL, provider_detail_json = NULL,
|
|
34
|
+
provider_disconnect_message = NULL, debug_json = NULL
|
|
35
|
+
WHERE completed_at < datetime('now', ?)
|
|
36
|
+
AND (provider_session_id IS NOT NULL OR \u006b\u0065\u0072\u006e\u0065\u006c_session_id IS NOT NULL OR error IS NOT NULL
|
|
37
|
+
OR \u006b\u0065\u0072\u006e\u0065\u006c_delete_error IS NOT NULL OR browser_close_error IS NOT NULL
|
|
38
|
+
OR provider_error_message IS NOT NULL OR provider_detail_json IS NOT NULL
|
|
39
|
+
OR provider_disconnect_message IS NOT NULL OR debug_json IS NOT NULL)`,args:[r]})]);return{operationAttempts:i.rowsAffected,providerReceipts:a.rowsAffected,legacyHarvestAttempts:o.rowsAffected}}async function le(e){let t={billing_authorizations:{column:"id"},billing_events:{column:"id"},billing_debits:{column:"idempotency_key"},billing_credits:{column:"idempotency_key"},ledger:{column:"id"}}[e.billingTable],i=d(e.billingKey,"billingKey"),a=await l().execute({sql:`SELECT b.user_id AS billing_user_id, r.user_id AS run_user_id
|
|
40
|
+
FROM operation_runs r
|
|
41
|
+
JOIN ${e.billingTable} b ON CAST(b.${t.column} AS TEXT) = ?
|
|
42
|
+
WHERE r.id = ?`,args:[i,e.runId]});if(!a.rows[0])throw new Error("Billing link target or operation run does not exist");let o=a.rows[0].billing_user_id,n=a.rows[0].run_user_id;if(n!=null&&o!=null&&String(n)!==String(o))throw new Error("Billing link owner does not match operation run owner");await l().execute({sql:`INSERT OR IGNORE INTO operation_billing_links
|
|
43
|
+
(run_id, billing_table, billing_key, relation, amount_mc) VALUES (?, ?, ?, ?, ?)`,args:[e.runId,e.billingTable,i,e.relation,e.amountMc??null]})}async function Ue(e,r=new Date().toISOString()){let t=h();return await l().execute({sql:"INSERT INTO provider_reconciliation_runs (id, provider, started_at) VALUES (?, ?, ?)",args:[t,d(e,"provider"),r]}),t}async function qe(e){if([e.checkedCount,e.completedCount,e.pendingCount,e.unavailableCount,e.failedCount].some(a=>!Number.isInteger(a)||a<0))throw new Error("Reconciliation counts must be non-negative integers");if(e.completedCount+e.pendingCount+e.unavailableCount+e.failedCount>e.checkedCount)throw new Error("Reconciliation outcome counts cannot exceed checkedCount");let t=e.completedAt??new Date().toISOString();if((await l().execute({sql:`UPDATE provider_reconciliation_runs SET
|
|
44
|
+
status = ?, checked_count = ?, completed_count = ?, pending_count = ?, unavailable_count = ?,
|
|
45
|
+
failed_count = ?, error_code = ?, completed_at = ?
|
|
46
|
+
WHERE id = ? AND status = 'running'`,args:[e.status,e.checkedCount,e.completedCount,e.pendingCount,e.unavailableCount,e.failedCount,m(e.errorCode,200),t,e.id]})).rowsAffected!==1)throw new Error(`Unknown or terminal provider reconciliation run: ${e.id}`)}async function de(e){let r=l(),[t,i,a,o]=await Promise.all([r.execute({sql:"SELECT * FROM operation_runs WHERE id = ?",args:[e]}),r.execute({sql:"SELECT * FROM operation_attempts WHERE run_id = ? ORDER BY attempt_number",args:[e]}),r.execute({sql:`SELECT r.* FROM provider_usage_receipts r
|
|
47
|
+
JOIN operation_attempts a ON a.id = r.attempt_id
|
|
48
|
+
WHERE a.run_id = ? ORDER BY a.attempt_number, r.rowid`,args:[e]}),r.execute({sql:"SELECT * FROM operation_billing_links WHERE run_id = ? ORDER BY created_at, billing_table, billing_key",args:[e]})]);return t.rows[0]?{run:t.rows[0],attempts:[...i.rows],providerReceipts:[...a.rows],billingLinks:[...o.rows]}:null}var Oe=1e9;function Ae(e){return Re("sha256").update(JSON.stringify(e)).digest("hex")}function v(e){return`harvest:${e}`}async function We(e){let r=v(e.jobId);try{return(await oe({id:r,userId:e.userId,ownerScope:`user:${e.userId}`,tool:e.tool,normalizedFlags:e.normalizedFlags,idempotencyKey:`job:${e.jobId}`,requestFingerprint:Ae(e.normalizedFlags),jobId:e.jobId,requestId:e.requestId??null,deploymentCommit:process.env.VERCEL_GIT_COMMIT_SHA?.trim()||process.env.GIT_COMMIT_SHA?.trim()||null})).id}catch(t){return console.warn(JSON.stringify({event:"operation_run_start_failed",job_id:e.jobId,tool:e.tool,message:t instanceof Error?t.message:String(t)})),null}}async function q(e,r,t){if(e)try{await ne({runId:e,status:r,failureClass:t})}catch(i){console.warn(JSON.stringify({event:"operation_run_finish_failed",operation_run_id:e,message:i instanceof Error?i.message:String(i)}))}}async function Be(e,r,t,i){if(!(!e||!r))try{await le({runId:e,billingTable:"billing_debits",billingKey:r,relation:t,amountMc:i})}catch(a){console.warn(JSON.stringify({event:"operation_billing_link_failed",operation_run_id:e,relation:t,message:a instanceof Error?a.message:String(a)}))}}function U(e){return e==="timeout"?"timed_out":e==="request_aborted"?"cancelled":e==="browser_session_interrupted"?"interrupted":e==="captcha"||e==="proxy_tunnel_failed"||e==="proxy_unavailable"||e==="location_mismatch"||e==="error"?"failed":"succeeded"}function Ie(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 ue(e,r,t=0){let i=new Map,a=null;return async o=>{if(e)try{if(o.type==="started"){let s=t+o.attemptNumber;if(s>1&&!a){let _=(await de(e))?.attempts.at(-1);a=_?.id==null?null:String(_.id)}let u=await ie({runId:e,attemptNumber:s,method:o.method,provider:o.provider,parentAttemptId:s===1?null:a,edgeKind:s===1?null:t>0&&o.attemptNumber===1?"durable_resume":o.retryKind==="provider_fallback"?"provider_fallback":"same_method_retry",retryKind:s===1?null:t>0&&o.attemptNumber===1?"durable_resume":o.retryKind,retryReason:s===1?null:t>0&&o.attemptNumber===1?"durable_worker_resume":o.retryReason,retryOwner:s===1?null:t>0&&o.attemptNumber===1?"durable_reconciler":"harvest",normalizedFlags:{maxAttempts:o.maxAttempts,maxQuestions:o.maxQuestions,hasLocation:!!o.location,plannedProvider:o.provider,planReason:o.planReason??null,planTimeoutMs:o.planTimeoutMs??null},startedAt:o.startedAt}),c=await D({attemptId:u,provider:o.provider,accountScope:r,method:o.method,providerStatus:"started"});i.set(o.attemptNumber,{attemptId:u,receiptId:c.id,plannedProvider:o.provider,observedProvider:null,providerMismatch:!1,method:o.method,startedAtMs:Date.parse(o.startedAt)}),a=u;return}let n=i.get(o.attemptNumber);if(!n)throw new Error(`Missing operation attempt state for attempt ${o.attemptNumber}`);if(o.type==="provider_session_started"){let s=Ie(o.provider);if(n.observedProvider=s,s!==n.plannedProvider){n.providerMismatch=!0,await w({receiptId:n.receiptId,costState:"unavailable",providerStatus:"provider_mismatch",errorCode:"provider_mismatch",errorMessage:`Planned ${n.plannedProvider}; observed ${s}`,finalizedAt:o.observedAt});let u=s==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?"\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061_browser":"\u006b\u0065\u0072\u006e\u0065\u006c_browser",c=await D({attemptId:n.attemptId,provider:s,accountScope:r,method:u,providerStatus:"observed_provider_mismatch"});n.receiptId=c.id,n.method=u}await se(n.receiptId,o.providerSessionId);return}if(await ae({attemptId:n.attemptId,status:n.providerMismatch?"failed":U(o.outcome),errorCode:n.providerMismatch?"provider_mismatch":U(o.outcome)==="succeeded"?null:o.outcome,errorMessage:o.error,durationMs:o.durationMs,endedAt:o.completedAt}),(n.observedProvider??n.plannedProvider)==="\u006b\u0065\u0072\u006e\u0065\u006c"){let s=X(o.durationMs,!0);await w({receiptId:n.receiptId,costState:"estimated",units:o.durationMs/1e3,unitType:"browser_second",amountUsdNanos:Math.round(s*Oe),rateSource:`\u006b\u0065\u0072\u006e\u0065\u006c_headful_usd_per_second:${Y}`,providerStatus:n.providerMismatch?"provider_mismatch":o.outcome,providerDurationMs:o.durationMs,errorCode:n.providerMismatch?"provider_mismatch":U(o.outcome)==="succeeded"?null:o.outcome,errorMessage:o.error,finalizedAt:o.completedAt})}}catch(n){console.warn(JSON.stringify({event:"operation_attempt_telemetry_failed",operation_run_id:e,attempt_number:o.attemptNumber,message:n instanceof Error?n.message:String(n)}))}}}function ce(e,r,t=null,i="production-default",a=0){let o=ue(t,i,a);return async n=>{if(await o(n),n.type==="started"){await J({jobId:e,userId:r,attemptNumber:n.attemptNumber,maxAttempts:n.maxAttempts,query:n.query,location:n.location,maxQuestions:n.maxQuestions,startedAt:n.startedAt});return}if(n.type==="provider_session_started"){await V({jobId:e,attemptNumber:n.attemptNumber,browserProvider:n.provider,providerSessionId:n.providerSessionId,observedAt:n.observedAt});return}await Q({jobId:e,attemptNumber:n.attemptNumber,outcome:n.outcome,\u006b\u0065\u0072\u006e\u0065\u006cSessionId:n.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,questionCount:n.questionCount,durationMs:n.durationMs,error:n.error,willRetry:n.willRetry,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:n.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:n.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:n.cleanup.\u006b\u0065\u0072\u006e\u0065\u006cDeleteError,browserCloseSucceeded:n.cleanup.browserCloseSucceeded,browserCloseError:n.cleanup.browserCloseError,browserProvider:n.cleanup.provider??null,providerSessionId:n.cleanup.providerSessionId??null,providerLookupStatus:n.cleanup.providerSessionId?"pending":"not_applicable",providerErrorCode:n.cleanup.providerDisconnectObserved?"browser_session_interrupted":null,providerErrorMessage:n.cleanup.providerDisconnectMessage??null,providerReasonSource:n.cleanup.providerDisconnectObserved?"client_runtime":null,providerDisconnectObserved:n.cleanup.providerDisconnectObserved??!1,providerDisconnectMessage:n.cleanup.providerDisconnectMessage??null,debug:n.debug,completedAt:n.completedAt})}}var pe=2,K=0;function me(e){if(!e||typeof e!="object")return 0;let r=e;return typeof r.totalQuestions=="number"?r.totalQuestions:Array.isArray(r.flat)?r.flat.length:0}function _e(e){return x.paa_base+Math.max(1,e)*x.paa}async function ge(e){K++;try{let r=typeof e.options=="string"?JSON.parse(e.options):e.options,t={value:null},i=v(e.id),a=await j({op:r.serpOnly?"serp":"paa",userId:Number(e.user_id),headlessSentOut:t,operationRunId:i,operationAccountScope:"production-default"},()=>Z({...r,\u006b\u0065\u0072\u006e\u0065\u006cApiKey:F(),headless:!0,format:"json",outputDir:"/tmp/paa-output-api",onAttemptEvent:ce(e.id,e.user_id,i)}));await G(e.id,a),await q(i,"succeeded");let o=await E(e.id,e.user_id);if(typeof r.billingHoldMc=="number"&&r.billingDebitKey){let n=r.serpOnly?k(t.value):_e(me(a));await I(Number(e.user_id),r.billingDebitKey,n,r.serpOnly?"serp_refund":"paa_refund",r.serpOnly?"SERP search settlement":"PAA harvest settlement",r.serpOnly?"serp_search":"paa_harvest")}else if(!r.serpOnly&&typeof r.billingHoldMc=="number"){let n=_e(me(a)),s=r.billingHoldMc-n;s>0?await b(e.user_id,s,"paa_refund","overestimate refund"):s<0&&await A(e.user_id,-s,"paa",r.query??e.query)}else if(r.serpOnly&&typeof r.billingHoldMc=="number"){let n=k(t.value),s=r.billingHoldMc-n;s>0?await b(e.user_id,s,"serp_refund","headless-mode pricing settle"):s<0&&await A(e.user_id,-s,"serp",r.query??e.query)}e.callback_url&&await P(e.callback_url,{job_id:e.id,status:"done",result:ee(a),attempts:N(o)})}catch(r){console.error("[harvest/worker] failed",{jobId:e.id,error:r instanceof Error?r.message:String(r)});let t=C(r);await q(v(e.id),t.error_code==="harvest_timeout"?"timed_out":t.terminalStatus,t.error_code);let i=typeof e.options=="string"?JSON.parse(e.options):e.options,a=typeof i.billingHoldMc=="number"&&i.billingHoldMc>0;await O(e.id,T(t),L(t,{chargeStatus:a?"refund_pending":"not_charged"}));let o=await E(e.id,e.user_id);try{a&&(i.billingDebitKey?await I(Number(e.user_id),i.billingDebitKey,0,i.serpOnly?"serp_refund":"paa_refund","failed call",i.serpOnly?"serp_search":"paa_harvest"):await b(e.user_id,i.billingHoldMc,"refund","failed call"),await O(e.id,T(t),L(t,{chargeStatus:"refunded"})))}catch{}e.callback_url&&await P(e.callback_url,{job_id:e.id,status:"failed",...y(t),attempts:N(o)})}finally{K--}}async function Ne(){let e=await R();if(!e)return{claimed:!1};let r=Date.now();return await ge(e),{claimed:!0,jobId:e.id,completed:!0,durationMs:Date.now()-r}}async function ar(e){let r=[];for(let t=0;t<e.maxJobs&&!(Date.now()>=e.deadlineMs);t++){let i=await Ne();if(r.push(i),!i.claimed)break}return r}function sr(){setInterval(async()=>{if(K>=pe)return;let e=await R();e&&ge(e)},2e3),console.log(`[worker] started \u2014 polling every 2s, max ${pe} concurrent`)}export{ie as a,ae as b,D as c,se as d,w as e,He as f,De as g,Ue as h,qe as i,C as j,T as k,y as l,L as m,Ce as n,v as o,We as p,q,Be as r,ce as s,P as t,Ne as u,ar as v,sr as w};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as j,b as T,c as P,d as C,f as S}from"./chunk-TMB56NCA.js";import{_ as w}from"./chunk-CTX3NMZQ.js";import{Jb as N,Sb as D,d as m,e as I,i as u,t as s}from"./chunk-
|
|
1
|
+
import{a as j,b as T,c as P,d as C,f as S}from"./chunk-TMB56NCA.js";import{_ as w}from"./chunk-CTX3NMZQ.js";import{Jb as N,Sb as D,d as m,e as I,i as u,t as s}from"./chunk-TOJBPATJ.js";import{createHash as W}from"crypto";import{gunzipSync as $,gzipSync as q}from"zlib";var y="site-extracts/",L=10080*60*1e3,H=900*1e3;function U(){return process.env.SITE_EXTRACT_ARTIFACT_READ_WRITE_TOKEN?.trim()||process.env.PRIVATE_ARTIFACT_READ_WRITE_TOKEN?.trim()||process.env.CONNECTED_DATA_READ_WRITE_TOKEN?.trim()||process.env.CONNECTED_DATA_BLOB_READ_WRITE_TOKEN?.trim()||null}function v(){return process.env.VERCEL==="1"||process.env.NODE_ENV==="production"}function p(){return{prefix:y,artifactTtlMs:L,downloadTtlMs:H,token:U()}}function h(t){return j(t,y)}async function V(t){let e=await P({policy:p(),ownerId:t.ownerId,artifactKey:`${t.jobId}.zip`,createdAt:t.createdAt,filename:`${t.jobId}-site-export.zip`,contentType:"application/zip",content:t.content});return{key:e.artifactId,url:e.downloadUrl??"",bytes:e.bytes,contentType:e.contentType,filename:e.filename,sha256:e.sha256,expiresAt:e.expiresAt,downloadUrlExpiresAt:e.downloadUrlExpiresAt,kind:"bundle"}}async function G(t){let e=await T({policy:p(),ownerId:t.ownerId,scopeSegments:[t.jobId,"images"],artifactKey:`${t.imageId}.bin`,createdAt:new Date,filename:t.filename,contentType:t.contentType,content:t.content});return{key:e.artifactId,url:e.downloadUrl??"",bytes:e.bytes,contentType:e.contentType,filename:e.filename,sha256:e.sha256,expiresAt:e.expiresAt,downloadUrlExpiresAt:e.downloadUrlExpiresAt,kind:"image",imageId:t.imageId,sourceUrl:t.sourceUrl,sourcePage:t.sourcePage}}async function O(t){return T({policy:p(),ownerId:t.ownerId,scopeSegments:[t.jobId,"content"],artifactKey:`${t.chunkKey}.json.gz`,createdAt:t.createdAt,filename:`${t.chunkKey}.json.gz`,contentType:"application/gzip",content:t.content})}async function Q(t){return C({policy:p(),artifactId:t.artifactId,ownerId:t.ownerId})}async function J(t){return S({policy:p(),artifactId:t,maxBytes:50*1024*1024})}async function Z(t){return h(t.artifactId)!==t.ownerId?null:J(t.artifactId)}async function k(t){return h(t.artifactId)!==t.ownerId?null:S({policy:p(),artifactId:t.artifactId,maxBytes:25*1024*1024})}async function tt(t){return h(t.artifactId)!==t.ownerId?null:S({policy:p(),artifactId:t.artifactId,maxBytes:10*1024*1024})}async function et(t={}){let e=t.now??new Date,n=U();if(!n)return{deleted:0,store:v()?"none":"local"};if(!t.force&&!(e.getUTCHours()===3&&e.getUTCMinutes()===21))return{deleted:0,store:"private-vercel-blob",skipped:!0};let r=e.getTime()-L,{list:i,del:a}=await import("@vercel/blob"),o,c=0;for(let d=0;d<20;d+=1){let l=await i({prefix:y,token:n,limit:1e3,cursor:o}),f=l.blobs.filter(A=>new Date(A.uploadedAt).getTime()<=r);if(f.length>0&&(await a(f.map(A=>A.pathname),{token:n}),c+=f.length),!l.hasMore||!l.cursor)break;o=l.cursor}return{deleted:c,store:"private-vercel-blob"}}var F=10,b=20*1024*1024;function E(t){return W("sha256").update(t).digest("hex")}function B(t){return!t.acquiredHtml||t.extractionStatus==="failed"?null:{pageId:t.pageId??E(t.archivedUrl??t.url),url:t.archivedUrl??t.url,html:t.acquiredHtml,mainHtml:t.mainHtml??"",markdown:t.bodyMarkdown,htmlSha256:t.htmlSha256??E(t.acquiredHtml),markdownSha256:t.markdownSha256??E(t.bodyMarkdown)}}function R(t){return Buffer.from(JSON.stringify({version:"site-extract-content.v1",pages:t}))}async function M(t){let e=t.pages.flatMap(o=>{let c=B(o);return c?[c]:[]}),n=new Map,r=[],i=0,a=async()=>{if(!r.length)return;let o=R(r);if(o.length>b)throw new Error(`site export content chunk exceeds ${b} bytes`);let c=E(r.map(l=>l.pageId).join("\0")).slice(0,16),d=await O({ownerId:t.ownerId,jobId:t.jobId,createdAt:t.createdAt,chunkKey:`content-${String(i).padStart(4,"0")}-${c}`,content:q(o,{level:6})});for(let l of r)n.set(l.url,{artifactId:d.artifactId,artifactSha256:d.sha256,pageId:l.pageId,uncompressedBytes:o.length});i++,r=[]};for(let o of e){let c=[...r,o];if(r.length>0&&(c.length>F||R(c).length>b)&&await a(),r.push(o),R(r).length>b)throw new Error(`page ${o.pageId} exceeds the durable content chunk limit`)}return await a(),n}function it(t){let e=new Map;return async n=>{let r=e.get(n.artifactId);if(!r){let a=await k({artifactId:n.artifactId,ownerId:t});if(!a)throw new Error("site export content chunk is missing or unauthorized");if(E(a)!==n.artifactSha256)throw new Error("site export content chunk checksum mismatch");let o=$(a);if(o.length>b)throw new Error("site export content chunk exceeds its read limit");if(r=JSON.parse(o.toString("utf8")),r.version!=="site-extract-content.v1"||!Array.isArray(r.pages))throw new Error("site export content chunk has an unsupported contract");for(e.set(n.artifactId,r);e.size>2;)e.delete(e.keys().next().value)}let i=r.pages.find(a=>a.pageId===n.pageId);if(!i)throw new Error("site export page is missing from its content chunk");if(E(i.html)!==i.htmlSha256||E(i.markdown)!==i.markdownSha256)throw new Error("site export page checksum mismatch");return i}}var g="xray_entitlement";function pt(t){let e=Math.max(1,Number(t.options.effectiveMaxPages??t.options.maxPages??1)),n=Math.max(e,Number(t.options.requestedMaxPages??e)),r=n>e;return{requestedMaxPages:n,effectiveMaxPages:e,creditLimited:r,creditTruncated:r&&t.totalUrls>=e}}function Et(t,e=!1){return t.successfulUrls===0?"failed":t.failedUrls>0||t.remainingUrls>0||e?"partial":"complete"}function _(t){let e=Number(t.total_urls??0),n=t.attempted_urls==null,r=Number(n?t.done_urls??0:t.attempted_urls),i=Number(n?t.done_urls??0:t.successful_urls??0),a=Number(t.failed_urls??Math.max(0,r-i));return{id:String(t.id),userId:t.user_id!=null?Number(t.user_id):null,idempotencyKey:t.idempotency_key!=null?String(t.idempotency_key):null,requestFingerprint:t.request_fingerprint!=null?String(t.request_fingerprint):null,status:t.status!=null?String(t.status):"pending",startUrl:String(t.start_url??""),options:t.options?JSON.parse(String(t.options)):{},totalUrls:e,doneUrls:r,attemptedUrls:r,successfulUrls:i,failedUrls:a,remainingUrls:Math.max(0,e-r),artifacts:t.artifacts?JSON.parse(String(t.artifacts)):null,error:t.error!=null?String(t.error):null,publicError:I(t.public_error_json),billedMc:t.billed_mc!=null?Number(t.billed_mc):null,createdAt:String(t.created_at??""),updatedAt:String(t.updated_at??"")}}async function mt(t,e,n,r){await s().execute({sql:`INSERT INTO site_extract_jobs (id, user_id, status, start_url, options, created_at, updated_at)
|
|
2
2
|
VALUES (?, ?, 'pending', ?, ?, datetime('now'), datetime('now'))`,args:[t,e,n,JSON.stringify(r)]})}async function K(t,e){let r=await s().execute({sql:"SELECT * FROM site_extract_jobs WHERE user_id = ? AND idempotency_key = ? LIMIT 1",args:[t,e]});return r.rows[0]?_(r.rows[0]):null}async function gt(t){let n=await s().execute({sql:`INSERT OR IGNORE INTO site_extract_jobs
|
|
3
3
|
(id, user_id, status, start_url, options, idempotency_key, request_fingerprint, created_at, updated_at)
|
|
4
4
|
VALUES (?, ?, 'pending', ?, ?, ?, ?, datetime('now'), datetime('now'))`,args:[t.jobId,t.userId,t.startUrl,JSON.stringify(t.options),t.idempotencyKey,t.requestFingerprint]}),r=await K(t.userId,t.idempotencyKey);if(!r)throw new Error("idempotent extract job was not persisted");return{job:r,created:n.rowsAffected===1,conflict:r.requestFingerprint!==t.requestFingerprint}}async function x(t){let n=await s().execute({sql:"SELECT * FROM site_extract_jobs WHERE id = ?",args:[t]});return n.rows[0]?_(n.rows[0]):null}async function _t(t){return(await s().execute({sql:"SELECT * FROM site_extract_jobs WHERE user_id = ? ORDER BY created_at DESC LIMIT 50",args:[t]})).rows.map(r=>_(r))}async function xt(t=25){return(await s().execute({sql:`SELECT * FROM site_extract_jobs
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{k as K}from"./chunk-
|
|
1
|
+
import{k as K}from"./chunk-YTEAWZEN.js";import{a as X}from"./chunk-IGJKAECE.js";import{c as J,d as H}from"./chunk-HUV2WTRW.js";import{t as f}from"./chunk-TOJBPATJ.js";import{createHash as U,createHmac as re,timingSafeEqual as he}from"crypto";import{createHash as fe,randomUUID as Y}from"crypto";var ge=1440*60*1e3,F=5e3,h=class extends Error{constructor(n,i,o=400){super(i);this.code=n;this.status=o;this.name="GmailSelectionError"}code;status},k=null,P=null;function $(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map($).join(",")}]`:`{${Object.entries(e).sort(([t],[n])=>t.localeCompare(n)).map(([t,n])=>`${JSON.stringify(t)}:${$(n)}`).join(",")}}`}function b(e){return fe("sha256").update($(e)).digest("hex")}async function x(){let e=f();return k&&P===e||(P=e,k=(async()=>{await e.execute(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS gmail_selections (
|
|
3
3
|
selection_id TEXT PRIMARY KEY,
|
|
4
4
|
owner_identity TEXT NOT NULL,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Ca as R,Da as E,Fa as v,G as u,H as f,Na as T,Pa as h,Qa as w,Ra as _,Sa as y,Ta as C,na as g,pa as S}from"./chunk-
|
|
1
|
+
import{Ca as R,Da as E,Fa as v,G as u,H as f,Na as T,Pa as h,Qa as w,Ra as _,Sa as y,Ta as C,na as g,pa as S}from"./chunk-ZKQRA6NQ.js";import{a as P}from"./chunk-DSK6RKBS.js";import{a as m}from"./chunk-WEPU72WA.js";import{readFileSync as N}from"fs";import{homedir as I}from"os";import{join as A}from"path";import{serveStdio as b}from"@modelcontextprotocol/server/stdio";import{McpServer as k}from"@modelcontextprotocol/server";var x=new Map(w.map(r=>[r.upstreamName,r.id]));function O(r){let s=r.split(`
|
|
2
2
|
`).filter(o=>o.startsWith("data:")).map(o=>o.slice(5).trim()).filter(Boolean);if(!s.length)return JSON.parse(r);for(let o of s){let e=JSON.parse(o);if(e.result||e.error)return e}throw new Error("hosted MCP returned no JSON-RPC result")}function a(r){return{content:[{type:"text",text:JSON.stringify({ok:!1,error:r})}],isError:!0}}var c=class{baseUrl;apiKey;constructor(s,o){this.baseUrl=s.replace(/\/$/,""),this.apiKey=o}async callMemoryTool(s,o){let e=x.get(s);if(!e)return a(`unknown memory tool: ${s}`);try{let n=await fetch(`${this.baseUrl}/mcp`,{method:"POST",headers:{"content-type":"application/json",accept:"application/json, text/event-stream","x-api-key":this.apiKey},body:JSON.stringify({jsonrpc:"2.0",id:`memory:${e}`,method:"tools/call",params:{name:e,arguments:o}})}),l=await n.text();if(!n.ok)return a(`hosted memory ${e} failed (HTTP ${n.status})`);let t=O(l);return t.error?a(t.error.message??`hosted memory ${e} failed`):t.result??a(`hosted memory ${e} returned no result`)}catch(n){return a(n instanceof Error?n.message:`hosted memory ${e} call failed`)}}};function M(r,s){if(s.length===0)throw new Error("Restricted MCP tool allowlist must contain at least one tool name");let o=new Set;for(let t of s){if(typeof t!="string"||t.trim()!==t||t.length===0)throw new Error("Restricted MCP tool allowlist contains a malformed tool name");if(o.has(t))throw new Error(`Restricted MCP tool allowlist contains duplicate tool name: ${t}`);o.add(t)}let e=new Set,n=r,l=n.registerTool.bind(r);return n.registerTool=(t,i,p)=>{if(o.has(t))return e.add(t),l(t,i,p)},{assertComplete(){let t=[...o].filter(i=>!e.has(i));if(t.length>0)throw new Error(`Restricted MCP tool allowlist contains unknown or unavailable tool names: ${t.join(", ")}`)},registeredToolNames(){return[...e]}}}var L=new Set(["paa","serp","browser-agent","scheduled-results","memory"]);function $(){let s=[process.env.MCP_SCRAPER_KEY_PATH?.trim(),A(I(),".mcp-scraper-key")].filter(Boolean);for(let o of s)try{let e=N(o,"utf8").trim();if(e)return e}catch{}}function Y(r,s={}){let o=s.toolsets??L,e=process.env.MCP_SCRAPER_BASE_URL?.trim()||process.env.MCP_BASE_URL?.trim()||"https://mcpscraper.dev",n=g(),l=S({deploymentProfile:n,transportProfile:"stdio",baseUrl:e,explicitlyEnabled:process.env.MCP_SCRAPER_ALLOW_PRIVATE_NETWORK==="1"}),t=process.env.BROWSER_AGENT_CONSOLE_URL?.trim()||e,i=new k({name:"mcp-scraper",version:m},{instructions:u,cacheHints:{"server/discover":{ttlMs:3e5,cacheScope:"private"},"tools/list":{ttlMs:3e5,cacheScope:"private"},"prompts/list":{ttlMs:3e5,cacheScope:"private"},"resources/list":{ttlMs:3e5,cacheScope:"private"},"resources/templates/list":{ttlMs:3e5,cacheScope:"private"},"resources/read":{ttlMs:6e4,cacheScope:"private"}}});f(i);let p=s.allowedToolNames?M(i,s.allowedToolNames):void 0,d=s.httpExecutor??new T(e,r,{localNetworkAccess:l});return o.has("paa")&&v(i,d,{ownerId:R(r),deploymentProfile:n,transportProfile:"stdio",baseUrl:e,localNetworkAccess:l,taskHandleSecret:r}),o.has("serp")&&E(i,d,{exposeDevelopmentDiagnostics:n==="development"||n==="test"}),o.has("browser-agent")&&h(i,{baseUrl:e,apiKey:r,consoleBaseUrl:t}),o.has("scheduled-results")&&C(i,new y(e,r)),o.has("memory")&&_(i,new c(e,r)),p?.assertComplete(),i}function se(r={}){let s=process.argv.includes("--stdio")||process.env.MCP_SCRAPER_FORCE_STDIO==="1",o=!!(process.stdin.isTTY&&process.stdout.isTTY),e=process.argv.includes("--help")||process.argv.includes("-h");if(!s&&(o||e)){let l=process.argv.includes("--no-color")||process.env.NO_COLOR!==void 0||process.env.FORCE_COLOR==="0"||!process.stdout.isTTY;process.stdout.write(P({version:m,color:!l,apiKeyConfigured:!!process.env.MCP_SCRAPER_API_KEY?.trim()})),process.exit(0)}let n=(process.env.MCP_SCRAPER_API_KEY??process.env.MCP_SCRAPER_KEY??process.env.MCP_API_KEY??$())?.trim();n||(process.stderr.write(`MCP_SCRAPER_API_KEY env var or ~/.mcp-scraper-key is required
|
|
3
3
|
`),process.exit(1)),b(()=>Y(n,r),{legacy:"serve",onerror(l){process.stderr.write(`${l.message}
|
|
4
4
|
`)}})}export{se as a};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{f as tt}from"./chunk-M5QHXNFZ.js";import{a as Ne}from"./chunk-4FROKQJN.js";import{a as Pe,b as be,c as At,e as We,j as Ie}from"./chunk-56UT5M5Y.js";import{a as me,c as Qt,d as yt,g as ve,l as Ae}from"./chunk-2TZBO52D.js";import{a as fe,i as Te,j as J,k as It,m as j,n as Ct,o as Zt}from"./chunk-KKHTMYCD.js";import{chromium as ee}from"playwright-extra";import Fn from"puppeteer-extra-plugin-stealth";import{chromium as Rn}from"playwright";var F={container:".eJH8qe.adDDi",dataInitq:"[data-initq]",item:".related-question-pair",itemDataQ:"data-q",itemDataInitQ:"data-initq",itemQuestionEl:".JlqpRe",answerContainer:".bCOlv, .hgKElc, .wDYxhc, .LGOjhe, .fo7IQd, .fmW3u",aiAnswerBody:".pWvJNd",aiCitation:"a.PMDqCb[href]",aiSourceCard:"a.vIWmYe[href], a.Zbfntb[href]",sourceTitle:"h3",sourceSite:".VuuXrf",sourceCite:"cite",clickTarget:".JlqpRe",expandedClass:"aoRk1c",captchaMarker:'#captcha-form, #recaptcha, form[action*="/sorry/"], .g-recaptcha, [data-sitekey]'},Le={container:'div[jscontroller="HWk0Gf"]',sectionHeading:'.mgAbYb[role="heading"]',item:"a.rIRoqf"},Lt={udm:"39",item:"a.rIRoqf",durationPattern:/^\d+:\d+$/,platforms:["YouTube","TikTok","Instagram","Facebook","X"]},xe={section:".ULSxyf",item:"a.KYg7td.INpicf",title:".hyYc0c",source:".K4ETW"},Oe={sectionTag:"g-section-with-header",sectionHeadingText:"What people are saying",card:'.dRzkFf[role="listitem"]',cardLink:'a.WlydOe[jsname="YKoRaf"]',titleH1:"h1.WQWxe",titleDiv:".eAaXgc",popularCommentLabel:".qgdis",source:".sTl1Td",platformBadge:".appd0, .KrMNbf",ytChannel:".sjVJQd",ytDate:".PLq9Je",authorNote:".nDgy9d"},Be={root:"[data-lhcontainer][data-streaming-container][eid]",legacyRoot:'[data-hveid="CBMQAA"]',wrapper:".Fgyi2e",controller:'[jscontroller="AkrxPe"]',contentSubtree:'[data-subtree="mfc"]',header:".heWuVc",heading:".Fzsovc.cwYVJe.RJPOee",showMoreButton:'[aria-label="Show more AI Overview"]',sourcesPanel:".OZ9ddf.WAUd4",disclaimer:".DuQANe.MSJHRb"},He={root:'[data-hveid="CAUQAA"]',wrapper:".Fgyi2e",citations:'.Fgyi2e [data-hveid] a[jsname="pxBnId"]'},Fe={result:".wHYlTd.tF2Cxc",title:"h3.LC20lb",siteName:".VuuXrf",cite:"cite.tjvcx",snippet:".VwiC3b",redditCite:"cite.qLRx3b",ratingWrap:".Y0A0hc",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Re={headingText:"Businesses",card:".w7Dbne",name:".OSrXXb",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Ge="2026-05-07",Si={ratingAndCount:"div.F7nice",hoursTable:"table.eK4R0e",reviewScrollPane:'div.m6QErb[tabindex="-1"]',reviewScrollPaneFallback:'[role="main"] div[tabindex="-1"]',reviewCardAuthor:"div.d4r55, span.d4r55, span.RPZfBb",reviewCardDate:"span.rsqaWe",reviewCardText:"span.wiI7pd",reviewCardOwnerBlock:"div.CDe7pd",hoursTableAlt:'table[aria-label*="Hour"]',reviewCard:"[data-review-id]",reviewStars:'[role="img"][aria-label*="star"]',reviewTab:'button[role="tab"][aria-label*="Review"]',aboutTab:'button[role="tab"][aria-label*="About"]',expandReview:'[data-review-id] button[aria-label*="See more"], [data-review-id] button.w8nwRe'};async function xt(e,t,n,a){let s,i=!1,d,U=()=>{},S=()=>a?.reason instanceof DOMException&&a.reason.name==="TimeoutError"?a.reason:new j,h=()=>U(S()),l=new Promise((r,u)=>{U=u}),o=async r=>{let u;try{await Promise.race([r.close().catch(()=>{}),new Promise(c=>{u=setTimeout(c,2e3)})])}finally{u&&clearTimeout(u)}};if(a?.aborted)throw S();a?.addEventListener("abort",h,{once:!0}),d=setTimeout(()=>U(new DOMException("Optional pagination timed out","TimeoutError")),3e4);try{return await Promise.race([(async()=>{let r=await e.newPage();if(i)throw await o(r),new j;if(s=r,await t(r),i)throw new j;return n(r)})(),l])}finally{i=!0,d&&clearTimeout(d),a?.removeEventListener("abort",h),s&&await o(s)}}var Hn=/\b(?:HeadlessChrome|Chrome|Chromium|Firefox)\/\d+|\bVersion\/\d+.*\bSafari\//;async function Ot(e){try{let t=await e.evaluate(()=>navigator.userAgent);return typeof t=="string"&&Hn.test(t)?t:null}catch{return null}}async function Bt(e){let t=null;try{let n=e.contexts().flatMap(a=>a.pages())[0];return n||(t=await e.newContext(),n=t.pages()[0]??await t.newPage()),await Ot(n)}catch{return null}finally{t&&await t.close().catch(()=>{})}}function ci(e,t){return t?{...e,userAgent:t}:e}ee.use(Fn());var Gn=180,Dn=3e3,Vn=5e3,En='#search, #rso, a[href] h3, [data-snhf], [role="main"]';function Xt(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}function Yn(e,t){let n=process.env[e];if(!n)return t;let a=Number(n);return Number.isInteger(a)&&a>0?a:t}function te(e){return e?e.slice(-6):null}function De(e,t){let n=(t??process.env.SERP_REDIRECT_BASE)?.trim().replace(/\/+$/,"");return n?`${n}/g/${Buffer.from(e,"utf8").toString("base64url")}`:e}function Kn(e){return e?/united states|u\.?s\.?a?\.?|^us$/i.test(e.trim()):!1}function ht(e){return e instanceof Error?e.message:String(e)}function Jn(e){return/\b409\b|conflict|already exists/i.test(ht(e))}function _n(e){return/\b404\b|not[ _-]?found|already (?:gone|deleted|closed)|does not exist/i.test(ht(e))}async function zn(e,t){try{await e.profiles.create({name:t})}catch(n){if(!Jn(n))throw n}}function Ht(e,t){return{viewport:e.viewport,locale:e.locale,...t?{userAgent:t}:{},...e.deviceScaleFactor?{deviceScaleFactor:e.deviceScaleFactor}:{},...e.isMobile!==void 0?{isMobile:e.isMobile}:{},...e.hasTouch!==void 0?{hasTouch:e.hasTouch}:{}}}async function Ut(e,t,n){let a;try{return await Promise.race([e,new Promise((s,i)=>{a=setTimeout(()=>i(new Error(`${n} timed out after ${t}ms`)),t)})])}finally{a&&clearTimeout(a)}}function qn(e){let t=e.trim();if(!t)throw new Error("channelHandle is required");if(/^https?:\/\//i.test(t)||/^(www\.|m\.)?youtube\.com\//i.test(t)){let d=new URL(/^https?:\/\//i.test(t)?t:`https://${t}`);if(d.hostname.replace(/^www\./,"").replace(/^m\./,"").toLowerCase()!=="youtube.com")throw new Error("channel URL must be on youtube.com");let S=d.pathname.split("/").filter(Boolean),h=S[0]??"",l=S[1]??"";if(h.startsWith("@"))return`https://www.youtube.com/${h}/videos`;if(h==="channel"&&l)return`https://www.youtube.com/channel/${l}/videos`;if((h==="c"||h==="user")&&l)return`https://www.youtube.com/${h}/${l}/videos`;throw new Error("channel URL must be a YouTube handle, /channel/UC..., /c/..., or /user/... URL")}let s=t.replace(/^\/+/,"").replace(/\/+$/,"").replace(/\/videos$/i,"");if(/^UC[\w-]{20,}$/.test(s))return`https://www.youtube.com/channel/${s}/videos`;let i=s.startsWith("@")?s:`@${s}`;if(!/^@[\w.-]+$/.test(i))throw new Error("channelHandle must be an @handle, UC channel ID, or YouTube channel URL");return`https://www.youtube.com/${i}/videos`}var Ft=class{browser=null;context=null;page=null;\u006b\u0065\u0072\u006e\u0065\u006cClient=null;\u006b\u0065\u0072\u006e\u0065\u006cSessionId=null;\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=null;\u006b\u0065\u0072\u006e\u0065\u006cStealth=null;\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed=null;\u006b\u0065\u0072\u006e\u0065\u006cProxySource=null;\u006b\u0065\u0072\u006e\u0065\u006cProxyType=null;\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=null;debugEnabled=!1;debugSnapshot={\u006b\u0065\u0072\u006e\u0065\u006c:null,context:null,networkLocation:null,serpNavigation:null};async launch(t){this.debugEnabled=t.debug===!0;let n=t.proxyMode??(t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId?"configured":"none"),a=t.isMobile?"mobile":"desktop";if(this.debugSnapshot={\u006b\u0065\u0072\u006e\u0065\u006c:null,context:{viewport:t.viewport,locale:t.locale,device:a,userAgent:null,deviceScaleFactor:t.deviceScaleFactor??null,isMobile:t.isMobile===!0,hasTouch:t.hasTouch===!0},networkLocation:null,serpNavigation:null},t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey){this.\u006b\u0065\u0072\u006e\u0065\u006cClient=new tt({apiKey:t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey});let i=Number.isInteger(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds)&&Number(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds)>0?Number(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds):Yn("\u004b\u0045\u0052\u004e\u0045\u004c_BROWSER_TIMEOUT_SECONDS",Gn),d=Math.min(i,600);t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName&&t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges===!0&&await zn(this.\u006b\u0065\u0072\u006e\u0065\u006cClient,t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName);let U=At(),S;t.headlessMode==="headful"||U?.forceHeadful===!0?S=!1:t.headlessMode==="headless"?S=!0:S=U?.forceHeadless===!0||process.env.\u004b\u0045\u0052\u004e\u0045\u004c_HEADLESS_DISABLED!=="true"&&!!U?.op&&We.has(U.op),this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=S?!0:null,U?.headlessSentOut&&(U.headlessSentOut.value=this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent);let h=await this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.create({stealth:t.\u006b\u0065\u0072\u006e\u0065\u006cStealth===!0,timeout_seconds:d,...S?{headless:!0}:{},...t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId?{proxy_id:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId}:{},...t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName?{profile:{name:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName,...typeof t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges=="boolean"?{save_changes:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges}:{}}}:{}});this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId=h.session_id,this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=Date.now(),this.\u006b\u0065\u0072\u006e\u0065\u006cStealth=typeof h.stealth=="boolean"?h.stealth:null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed=typeof h.proxy_id=="string"?!!h.proxy_id:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource=t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.source??null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType=t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.proxyType??null;let l=null,o=null;if(!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId&&!t.keepDefaultProxy)try{await Ut(this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.update(this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,{disable_default_proxy:!0}),5e3,`\u004b\u0065\u0072\u006e\u0065\u006c session ${this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId} disable default proxy`),l=!0}catch(u){l=!1,o=ht(u)}let r={sessionId:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,proxyMode:n,requestedProxyIdPresent:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,requestedProxyIdSuffix:te(t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId),createdProxyIdPresent:typeof h.proxy_id=="string"?!!h.proxy_id:null,createdProxyIdSuffix:te(h.proxy_id),retrievedProxyIdPresent:null,retrievedProxyIdSuffix:null,retrievedProxyIdMatchesRequested:null,defaultProxyDisabled:l,defaultProxyDisableError:o,proxyResolution:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution??null,timeoutSeconds:d,stealth:typeof h.stealth=="boolean"?h.stealth:null,profilePresent:null,poolPresent:null,retrieveError:null};if(this.debugSnapshot.\u006b\u0065\u0072\u006e\u0065\u006c=r,console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_created",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,timeout_seconds:d,proxy_mode:n,proxy_id_present:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,profile_name_present:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName,proxy_resolution_source:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.source})),this.debugEnabled&&await this.populate\u004b\u0065\u0072\u006e\u0065\u006cRetrieveDebug(r,t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId),this.browser=await Rn.connectOverCDP(h.cdp_ws_url),t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName||t.preserve\u004b\u0065\u0072\u006e\u0065\u006cContext)this.context=this.browser.contexts()[0]??await this.browser.newContext(Ht(t)),this.page=this.context.pages()[0]??await this.context.newPage(),this.debugSnapshot.context.userAgent=await Ot(this.page);else{let u=await Bt(this.browser);this.debugSnapshot.context.userAgent=u,this.context=await this.browser.newContext(Ht(t,u)),this.page=await this.context.newPage()}if(await this.installEsbuildHelperShims(this.context),t.preserve\u004b\u0065\u0072\u006e\u0065\u006cContext||await this.page.setViewportSize(t.viewport),(this.debugEnabled||t.requireUsEgress)&&(this.debugSnapshot.networkLocation=await this.captureBrowserNetworkLocation()),t.requireUsEgress){let u=this.debugSnapshot.networkLocation?.country??null;if(!Kn(u))throw new J(`Non-US egress (${u??"unknown"}) \u2014 retrying with a fresh session`)}return}let s={headless:t.headless,proxy:t.proxy?{server:t.proxy}:void 0,...t.browserExecutablePath?{executablePath:t.browserExecutablePath}:{},...t.ignoreDefaultArgs?{ignoreDefaultArgs:t.ignoreDefaultArgs}:{}};if(t.profileDir)this.context=await ee.launchPersistentContext(t.profileDir,{...s,...Ht(t)}),await this.installEsbuildHelperShims(this.context),this.page=await this.context.newPage(),this.debugSnapshot.context.userAgent=await Ot(this.page);else{this.browser=await ee.launch(s);let i=await Bt(this.browser);this.debugSnapshot.context.userAgent=i,this.context=await this.browser.newContext(Ht(t,i)),await this.installEsbuildHelperShims(this.context),this.page=await this.context.newPage()}this.debugEnabled&&(this.debugSnapshot.networkLocation=await this.captureBrowserNetworkLocation())}async populate\u004b\u0065\u0072\u006e\u0065\u006cRetrieveDebug(t,n){if(!(!this.\u006b\u0065\u0072\u006e\u0065\u006cClient||!this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId))try{let a=await Ut(this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.retrieve(this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId),5e3,`\u004b\u0065\u0072\u006e\u0065\u006c session ${this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId} retrieve`);t.retrievedProxyIdPresent=typeof a.proxy_id=="string"?!!a.proxy_id:!1,t.retrievedProxyIdSuffix=te(a.proxy_id),t.retrievedProxyIdMatchesRequested=n?a.proxy_id===n:!a.proxy_id,t.timeoutSeconds=typeof a.timeout_seconds=="number"?a.timeout_seconds:t.timeoutSeconds,t.stealth=typeof a.stealth=="boolean"?a.stealth:t.stealth,t.profilePresent=!!a.profile,t.poolPresent=!!a.pool}catch(a){t.retrieveError=ht(a)}}async captureBrowserNetworkLocation(){let t=(a,s="ipapi.co")=>({source:s,ip:null,city:null,region:null,country:null,org:null,timezone:null,error:a});if(!this.context)return t("browser context is not available");let n=null;try{n=await this.context.newPage();let a=await this.loadJsonInDebugPage(n,"https://ipwho.is/");if(a){let U=typeof a.connection=="object"&&a.connection!==null?a.connection:{};return{source:"ipwho.is",ip:typeof a.ip=="string"?a.ip:null,city:typeof a.city=="string"?a.city:null,region:typeof a.region=="string"?a.region:null,country:typeof a.country=="string"?a.country:null,org:typeof U.org=="string"?U.org:null,timezone:typeof a.timezone=="object"&&a.timezone!==null&&typeof a.timezone.id=="string"?a.timezone.id:null,error:null}}let s=await this.loadJsonInDebugPage(n,"https://api64.ipify.org?format=json");if(s)return{source:"api64.ipify.org",ip:typeof s.ip=="string"?s.ip:null,city:null,region:null,country:null,org:null,timezone:null,error:null};await Ut(n.goto("https://ipapi.co/json/",{waitUntil:"domcontentloaded",timeout:7e3}),8e3,"browser network location navigation");let i=await n.locator("body").innerText({timeout:2e3}),d=JSON.parse(i);return{source:"ipapi.co",ip:typeof d.ip=="string"?d.ip:null,city:typeof d.city=="string"?d.city:null,region:typeof d.region=="string"?d.region:null,country:typeof d.country_name=="string"?d.country_name:typeof d.country=="string"?d.country:null,org:typeof d.org=="string"?d.org:null,timezone:typeof d.timezone=="string"?d.timezone:null,error:null}}catch(a){return t(ht(a))}finally{await n?.close().catch(()=>{})}}async loadJsonInDebugPage(t,n){try{await Ut(t.goto(n,{waitUntil:"domcontentloaded",timeout:7e3}),8e3,`browser network location navigation ${n}`);let a=await t.locator("body").innerText({timeout:2e3});return JSON.parse(a)}catch{return null}}async installEsbuildHelperShims(t){await t.addInitScript(()=>{let n=globalThis;typeof n.__name!="function"&&(n.__name=a=>a),typeof n.__publicField!="function"&&(n.__publicField=(a,s,i)=>(a[s]=i,i))})}async withTemporaryPage(t,n){if(!this.context)throw new Error("Browser context is not available");return xt(this.context,async()=>{},t,n)}async navigateToSERP(t,n,a,s,i){let d=new URLSearchParams({q:t,gl:a,hl:s,pws:"0"});i?.tbs&&d.set("tbs",i.tbs),n&&d.set("uule",n);let U="https://www.google.com/search?"+d.toString(),S=De(U),h=i?.debug?{requestedUrl:U,finalUrl:null,title:null,bodySnippet:null,hasPaa:null,captchaDetected:null,googleSorryUrl:null,redirected:null}:null;h&&(this.debugSnapshot.serpNavigation=h);try{await this.page.goto(S,{waitUntil:"domcontentloaded",timeout:Xt(i?.deadlineMs,i?.purpose==="serp"?8e3:45e3)})}catch(o){await this.updateSerpNavigationDebug(h,U,{hasPaa:null,captchaDetected:null});let r=await this.captureDiagnostics(U);throw new It(`page.goto failed: ${o.message} | ${r}`)}if(await this.isSerpChallengeVisible())throw await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!0}),new J(this.captchaMessage());if(i?.purpose==="serp"){await this.page.waitForSelector(En,{timeout:Xt(i.deadlineMs,1500)}).catch(()=>null);let o=await this.page.locator(F.item).count().catch(()=>0)>0;return await this.updateSerpNavigationDebug(h,U,{hasPaa:o,captchaDetected:!1}),{hasPaa:o}}if(await this.page.waitForSelector(F.item,{timeout:Xt(i?.deadlineMs,4e3)}).catch(()=>null))return await this.updateSerpNavigationDebug(h,U,{hasPaa:!0,captchaDetected:!1}),{hasPaa:!0};if(await this.isSerpChallengeVisible())throw await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!0}),new J(this.captchaMessage());for(let o=1;o<=6;o++)if(await this.page.evaluate(u=>{window.scrollTo(0,document.body.scrollHeight*u)},o/6),await this.page.waitForTimeout(600),await this.page.locator(F.item).count()>0)return await this.updateSerpNavigationDebug(h,U,{hasPaa:!0,captchaDetected:!1}),{hasPaa:!0};return await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!1}),{hasPaa:!1}}async isSerpChallengeVisible(){if(!this.page)return!1;if(await this.page.locator(F.captchaMarker).count().catch(()=>0)>0)return!0;let n=this.page.url();if(/google\.[^/]+\/sorry\//i.test(n))return!0;let a=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,1e3)).catch(()=>"");return/recaptcha|unusual traffic|are you a robot|about this page|detected unusual traffic/i.test(a)}async updateSerpNavigationDebug(t,n,a){if(!(!t||!this.page))try{let s=this.page.url(),i=await this.page.title().catch(()=>""),d=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,500)).catch(()=>""),U=/recaptcha|unusual traffic|are you a robot/i.test(d);t.finalUrl=s,t.title=i,t.bodySnippet=d,t.hasPaa=a.hasPaa,t.captchaDetected=a.captchaDetected??U,t.googleSorryUrl=/google\.[^/]+\/sorry\//i.test(s),t.redirected=s!==n}catch(s){t.bodySnippet=`debug capture failed: ${ht(s)}`}}async captureDiagnostics(t){try{let n=this.page.url(),a=await this.page.title().catch(()=>""),s=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,400)).catch(()=>""),i=/consent\.google\./.test(n)||/before you continue/i.test(s),d=/recaptcha|unusual traffic|are you a robot/i.test(s),U=[i?"CONSENT_WALL":"",d?"BOT_CHALLENGE":"",n!==t?"REDIRECTED":""].filter(Boolean).join(",");return`intended=${t} | final=${n} | title="${a}" | flags=[${U}] | body="${s}"`}catch(n){return`diagnostics-failed: ${n.message}`}}captchaMessage(){return this.\u006b\u0065\u0072\u006e\u0065\u006cClient?"Google returned a CAPTCHA on this session \u2014 retrying with a fresh session.":fe}async navigateTo(t){let n=process.env.ADS_ARRIVAL_REDIRECT_BASE?.trim(),a=n?De(t,n):t;try{if(await this.page.goto(a,{waitUntil:"domcontentloaded",timeout:45e3}),/google\.[^/]+\/search\?/i.test(t)&&await this.isSerpChallengeVisible())throw new J(this.captchaMessage())}catch(s){if(s instanceof J)throw s;let i=await this.captureDiagnostics(t);throw new It(`page.goto failed: ${s.message} | ${i}`)}}async navigateToChannel(t){let n=qn(t);try{await this.page.goto(n,{waitUntil:"networkidle",timeout:3e4})}catch(a){let s=await this.captureDiagnostics(n);throw new It(`navigateToChannel failed: ${a.message} | ${s}`)}}async evaluate(t,n){return this.page.evaluate(t,n)}getPage(){return this.page}get\u004b\u0065\u0072\u006e\u0065\u006cSessionId(){return this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId}getProviderSessionMetadata(){return{provider:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId?"\u006b\u0065\u0072\u006e\u0065\u006c":"local",providerSessionId:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,disconnectObservation:null}}getDebugSnapshot(){return this.debugSnapshot}async close(){if(this.browser){let t=this.browser,n=this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,a=this.\u006b\u0065\u0072\u006e\u0065\u006cClient,s=this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs,i=this.\u006b\u0065\u0072\u006e\u0065\u006cStealth,d=this.\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed,U=this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource,S=this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType,h=this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent,l=this.getProviderSessionMetadata();if(this.browser=null,this.context=null,this.page=null,this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId=null,this.\u006b\u0065\u0072\u006e\u0065\u006cClient=null,this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=null,this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource=null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType=null,a&&n&&s!=null&&Ie({\u006b\u0065\u0072\u006e\u0065\u006cSessionId:n,source:"browser_driver",stealth:i,headlessSent:h,proxyUsed:d,proxySource:U,proxyType:S,openedAtMs:s,closedAtMs:Date.now()}),a&&n){console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_started",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n}));let o=Ut(a.browsers.deleteByID(n),Vn,`\u004b\u0065\u0072\u006e\u0065\u006c session ${n} delete`),r=Ut(t.close(),Dn,`\u004b\u0065\u0072\u006e\u0065\u006c browser ${n} close`),[u,c]=await Promise.allSettled([o,r]),g=u.status==="rejected"&&_n(u.reason),v={\u006b\u0065\u0072\u006e\u0065\u006cSessionId:n,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!0,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:u.status==="fulfilled"||g,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:u.status==="rejected"&&!g?u.reason instanceof Error?u.reason.message:String(u.reason):null,browserCloseSucceeded:c.status==="fulfilled",browserCloseError:c.status==="rejected"?c.reason instanceof Error?c.reason.message:String(c.reason):null,provider:l.provider,providerSessionId:l.providerSessionId,providerDisconnectObserved:!1,providerDisconnectMessage:null};return u.status==="rejected"&&!g?(console.warn(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_failed",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n,message:v.\u006b\u0065\u0072\u006e\u0065\u006cDeleteError})),console.warn(`\u004b\u0065\u0072\u006e\u0065\u006c session cleanup failed for ${n}:`,u.reason)):console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_succeeded",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n})),c.status==="rejected"&&(console.warn(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_close_failed",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n,message:v.browserCloseError})),console.warn(`\u004b\u0065\u0072\u006e\u0065\u006c browser close failed for ${n}:`,c.reason)),v}return await t.close(),{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:!0,browserCloseError:null,provider:l.provider,providerSessionId:l.providerSessionId,providerDisconnectObserved:!1,providerDisconnectMessage:null}}else if(this.context){let t=this.context;return this.context=null,this.page=null,await t.close(),{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:!0,browserCloseError:null,provider:"local",providerSessionId:null,providerDisconnectObserved:!1,providerDisconnectMessage:null}}return{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:null,browserCloseError:null,provider:"local",providerSessionId:null,providerDisconnectObserved:!1,providerDisconnectMessage:null}}};import{chromium as Qn}from"playwright";function $n(e,t){if(typeof e!="string")return null;let n=e.replace(/[\u0000-\u001f\u007f]+/g," ").replace(/\s+/g," ").trim();return n?n.slice(0,t):null}function Ve(e){let t=$n(e,320);return t?t.replace(/\b(?:wss?|https?):\/\/\S+/gi,"[redacted endpoint]").replace(/\b(?:authorization|proxy-authorization):\s*\S+/gi,"$1: [redacted]").replace(/\bBearer\s+\S+/gi,"Bearer [redacted]").slice(0,320):null}function Ee(e){return Ve(e)}function Ye(e){if(typeof e!="string"||e.length===0||e.length>512||e.trim()!==e||/[\s\u0000-\u001f\u007f]/.test(e)||/:\/\//.test(e))throw new Error("\u0042\u0072\u0069\u0067\u0068\u0074 \u0044\u0061\u0074\u0061 did not return a valid browser session ID");return e}function ne(e,t,n=new Date().toISOString()){let a=Ve(t);return{source:e,message:a??e.replaceAll("_"," "),observedAt:n}}function jn(e){return{provider:e.provider,providerDisconnectObserved:e.disconnectObservation!==null,providerDisconnectMessage:e.disconnectObservation?.message??null}}function Ke(e){return{...jn(e),providerSessionId:e.providerSessionId}}var Zn=new Set(["image","media","font","stylesheet","ping"]),Xn=["doubleclick.net","googleadservices.com","googlesyndication.com","google-analytics.com"],ta='#search, #rso, a[href] h3, [data-snhf], [role="main"]',ea=3e4,Je=1500;function Rt(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}function _e(){return process.env.\u0042\u0052\u0049\u0047\u0048\u0054\u0044\u0041\u0054\u0041_BROWSER_WSS?.trim()||null}function ze(){return process.env.SERP_BROWSER_PROVIDER?.trim().toLowerCase()==="\u006b\u0065\u0072\u006e\u0065\u006c"?!1:!!_e()}async function ae(e,t=!1){let n=e.request();try{let a=await n.allHeaders(),s=await fetch(n.url(),{method:n.method(),headers:{accept:a.accept??"*/*","accept-language":a["accept-language"]??"en-US,en;q=0.9","user-agent":a["user-agent"]??"Mozilla/5.0",...t?{cookie:a.cookie??"",referer:a.referer??"https://www.google.com/",...a["x-client-data"]?{"x-client-data":a["x-client-data"]}:{}}:{}},body:n.method()==="GET"||n.method()==="HEAD"?void 0:n.postData()});if(!s.ok)return!1;let i=Buffer.from(await s.arrayBuffer());return await e.fulfill({status:s.status,contentType:s.headers.get("content-type")??"application/octet-stream",headers:{"cache-control":"public, max-age=3600"},body:i}),!0}catch{return!1}}var Gt=class{browser=null;context=null;page=null;cdpSession=null;providerSessionId=null;disconnectObservation=null;closing=!1;observeDisconnect(t,n){this.closing||this.disconnectObservation||(this.disconnectObservation=ne(t,n))}async launch(t){if(this.page)return;this.closing=!1,this.providerSessionId=null,this.disconnectObservation=null;let n=_e();if(!n)throw new Error("SERP browser service is not configured");this.browser=await Qn.connectOverCDP(n,{timeout:Rt(t.operationDeadlineMs,ea)}),this.context=this.browser.contexts()[0]??await this.browser.newContext(),await this.context.addInitScript(()=>{let i=globalThis;typeof i.__name!="function"&&(i.__name=d=>d),typeof i.__publicField!="function"&&(i.__publicField=(d,U,S)=>(d[U]=S,S))}),this.page=this.context.pages()[0]??await this.context.newPage(),this.browser.on("disconnected",()=>this.observeDisconnect("browser_disconnected")),this.context.on("close",()=>this.observeDisconnect("context_closed")),this.page.on("close",()=>this.observeDisconnect("page_closed")),this.page.on("crash",()=>this.observeDisconnect("page_crashed")),this.cdpSession=await this.context.newCDPSession(this.page);let s=await this.cdpSession.send("Browser.getSessionId");this.providerSessionId=Ye(s?.sessionId),await this.setupPage(this.page)}async setupPage(t){await t.route("**/*",async n=>{let a=n.request(),s=a.resourceType(),i;try{i=new URL(a.url())}catch{await n.continue();return}let d=i.hostname.toLowerCase();if(!(i.pathname==="/sgasync"&&await ae(n,!0))&&!(i.pathname.includes("/shared_dict/")&&await ae(n))&&!(s==="script"&&(d==="www.google.com"||d==="www.gstatic.com")&&await ae(n))){if(Zn.has(s)){await n.abort("blockedbyclient");return}if(Xn.some(U=>d===U||d.endsWith(`.${U}`))){await n.abort("blockedbyclient");return}await n.continue()}})}async withTemporaryPage(t,n){if(!this.context||this.closing)throw new Error("Browser context is not available");return xt(this.context,a=>this.setupPage(a),t,n)}async navigateToSERP(t,n,a,s,i){if(!this.page)throw new Error("Browser page is not available");let d=new URLSearchParams({q:t,gl:a,hl:s,pws:"0"});return i?.tbs&&d.set("tbs",i.tbs),n&&d.set("uule",n),await this.page.goto(`https://www.google.com/search?${d}`,{waitUntil:"domcontentloaded",timeout:Rt(i?.deadlineMs,i?.purpose==="serp"?8e3:45e3)}),i?.purpose==="serp"?(await this.page.waitForSelector(ta,{timeout:Rt(i.deadlineMs,1500)}).catch(()=>null),{hasPaa:await this.page.locator(F.item).count().catch(()=>0)>0}):{hasPaa:!!await this.page.waitForSelector(F.item,{timeout:Rt(i?.deadlineMs,8e3)}).catch(()=>null)}}async navigateTo(t){if(!this.page)throw new Error("Browser page is not available");await this.page.goto(t,{waitUntil:"load",timeout:45e3})}async navigateToChannel(){throw new Error("YouTube navigation is not supported by the SERP browser driver")}async evaluate(t,n){if(!this.page)throw new Error("Browser page is not available");return this.page.evaluate(t,n)}getPage(){if(!this.page)throw new Error("Browser page is not available");return this.page}get\u004b\u0065\u0072\u006e\u0065\u006cSessionId(){return null}getProviderSessionMetadata(){return{provider:"\u0062\u0072\u0069\u0067\u0068\u0074_\u0064\u0061\u0074\u0061_browser_api",providerSessionId:this.providerSessionId,disconnectObservation:this.disconnectObservation}}getDebugSnapshot(){return{\u006b\u0065\u0072\u006e\u0065\u006c:null,context:null,networkLocation:null,serpNavigation:null}}async close(){this.closing=!0;let t=null,n;try{let s=this.browser?.close();s&&await Promise.race([s,new Promise((i,d)=>{n=setTimeout(()=>d(new Error(`Browser close acknowledgement exceeded ${Je}ms`)),Je)})])}catch(s){t=Ee(s instanceof Error?s.message:String(s))??"\u0042\u0072\u0069\u0067\u0068\u0074 \u0044\u0061\u0074\u0061 browser close failed",this.disconnectObservation??=ne("browser_close_error",t)}finally{n&&clearTimeout(n)}let a=Ke(this.getProviderSessionMetadata());return this.browser=null,this.context=null,this.page=null,this.cdpSession=null,{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:t===null,browserCloseError:t,...a}}};function qe(e){return e.plannedProvider==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?new Gt:new Ft}var st={austin:"Austin,Texas,United States","new york":"New York,New York,United States","new york city":"New York,New York,United States",nyc:"New York,New York,United States","los angeles":"Los Angeles,California,United States",la:"Los Angeles,California,United States",chicago:"Chicago,Illinois,United States",houston:"Houston,Texas,United States",phoenix:"Phoenix,Arizona,United States",philadelphia:"Philadelphia,Pennsylvania,United States",philly:"Philadelphia,Pennsylvania,United States","san antonio":"San Antonio,Texas,United States",dallas:"Dallas,Texas,United States",miami:"Miami,Florida,United States",seattle:"Seattle,Washington,United States",denver:"Denver,Colorado,United States",loveland:"Loveland,Colorado,United States","loveland co":"Loveland,Colorado,United States","fort collins":"Fort Collins,Colorado,United States",boulder:"Boulder,Colorado,United States","colorado springs":"Colorado Springs,Colorado,United States",boston:"Boston,Massachusetts,United States",atlanta:"Atlanta,Georgia,United States","san francisco":"San Francisco,California,United States",sf:"San Francisco,California,United States",portland:"Portland,Oregon,United States","las vegas":"Las Vegas,Nevada,United States",minneapolis:"Minneapolis,Minnesota,United States",detroit:"Detroit,Michigan,United States",nashville:"Nashville,Tennessee,United States",charlotte:"Charlotte,North Carolina,United States",orlando:"Orlando,Florida,United States","san diego":"San Diego,California,United States",baltimore:"Baltimore,Maryland,United States",sacramento:"Sacramento,California,United States",columbus:"Columbus,Ohio,United States",indianapolis:"Indianapolis,Indiana,United States","san jose":"San Jose,California,United States","fort worth":"Fort Worth,Texas,United States",jacksonville:"Jacksonville,Florida,United States",memphis:"Memphis,Tennessee,United States",louisville:"Louisville,Kentucky,United States",raleigh:"Raleigh,North Carolina,United States",richmond:"Richmond,Virginia,United States","salt lake city":"Salt Lake City,Utah,United States",toronto:"Toronto,Ontario,Canada",vancouver:"Vancouver,British Columbia,Canada",montreal:"Montreal,Quebec,Canada",calgary:"Calgary,Alberta,Canada",ottawa:"Ottawa,Ontario,Canada",london:"London,England,United Kingdom",manchester:"Manchester,England,United Kingdom",birmingham:"Birmingham,England,United Kingdom",edinburgh:"Edinburgh,Scotland,United Kingdom",glasgow:"Glasgow,Scotland,United Kingdom",leeds:"Leeds,England,United Kingdom",sydney:"Sydney,New South Wales,Australia",melbourne:"Melbourne,Victoria,Australia",brisbane:"Brisbane,Queensland,Australia",perth:"Perth,Western Australia,Australia",adelaide:"Adelaide,South Australia,Australia",dublin:"Dublin,Leinster,Ireland"};var $e=`3, Nanjemoy,Maryland,United States
|
|
1
|
+
import{f as tt}from"./chunk-M5QHXNFZ.js";import{a as Ne}from"./chunk-4FROKQJN.js";import{a as Pe,b as be,c as At,e as We,j as Ie}from"./chunk-BDLR4CCL.js";import{a as me,c as Qt,d as yt,g as ve,l as Ae}from"./chunk-2TZBO52D.js";import{a as fe,i as Te,j as J,k as It,m as j,n as Ct,o as Zt}from"./chunk-TOJBPATJ.js";import{chromium as ee}from"playwright-extra";import Fn from"puppeteer-extra-plugin-stealth";import{chromium as Rn}from"playwright";var F={container:".eJH8qe.adDDi",dataInitq:"[data-initq]",item:".related-question-pair",itemDataQ:"data-q",itemDataInitQ:"data-initq",itemQuestionEl:".JlqpRe",answerContainer:".bCOlv, .hgKElc, .wDYxhc, .LGOjhe, .fo7IQd, .fmW3u",aiAnswerBody:".pWvJNd",aiCitation:"a.PMDqCb[href]",aiSourceCard:"a.vIWmYe[href], a.Zbfntb[href]",sourceTitle:"h3",sourceSite:".VuuXrf",sourceCite:"cite",clickTarget:".JlqpRe",expandedClass:"aoRk1c",captchaMarker:'#captcha-form, #recaptcha, form[action*="/sorry/"], .g-recaptcha, [data-sitekey]'},Le={container:'div[jscontroller="HWk0Gf"]',sectionHeading:'.mgAbYb[role="heading"]',item:"a.rIRoqf"},Lt={udm:"39",item:"a.rIRoqf",durationPattern:/^\d+:\d+$/,platforms:["YouTube","TikTok","Instagram","Facebook","X"]},xe={section:".ULSxyf",item:"a.KYg7td.INpicf",title:".hyYc0c",source:".K4ETW"},Oe={sectionTag:"g-section-with-header",sectionHeadingText:"What people are saying",card:'.dRzkFf[role="listitem"]',cardLink:'a.WlydOe[jsname="YKoRaf"]',titleH1:"h1.WQWxe",titleDiv:".eAaXgc",popularCommentLabel:".qgdis",source:".sTl1Td",platformBadge:".appd0, .KrMNbf",ytChannel:".sjVJQd",ytDate:".PLq9Je",authorNote:".nDgy9d"},Be={root:"[data-lhcontainer][data-streaming-container][eid]",legacyRoot:'[data-hveid="CBMQAA"]',wrapper:".Fgyi2e",controller:'[jscontroller="AkrxPe"]',contentSubtree:'[data-subtree="mfc"]',header:".heWuVc",heading:".Fzsovc.cwYVJe.RJPOee",showMoreButton:'[aria-label="Show more AI Overview"]',sourcesPanel:".OZ9ddf.WAUd4",disclaimer:".DuQANe.MSJHRb"},He={root:'[data-hveid="CAUQAA"]',wrapper:".Fgyi2e",citations:'.Fgyi2e [data-hveid] a[jsname="pxBnId"]'},Fe={result:".wHYlTd.tF2Cxc",title:"h3.LC20lb",siteName:".VuuXrf",cite:"cite.tjvcx",snippet:".VwiC3b",redditCite:"cite.qLRx3b",ratingWrap:".Y0A0hc",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Re={headingText:"Businesses",card:".w7Dbne",name:".OSrXXb",ratingValue:".yi40Hd",reviewCount:".RDApEe"},Ge="2026-05-07",Si={ratingAndCount:"div.F7nice",hoursTable:"table.eK4R0e",reviewScrollPane:'div.m6QErb[tabindex="-1"]',reviewScrollPaneFallback:'[role="main"] div[tabindex="-1"]',reviewCardAuthor:"div.d4r55, span.d4r55, span.RPZfBb",reviewCardDate:"span.rsqaWe",reviewCardText:"span.wiI7pd",reviewCardOwnerBlock:"div.CDe7pd",hoursTableAlt:'table[aria-label*="Hour"]',reviewCard:"[data-review-id]",reviewStars:'[role="img"][aria-label*="star"]',reviewTab:'button[role="tab"][aria-label*="Review"]',aboutTab:'button[role="tab"][aria-label*="About"]',expandReview:'[data-review-id] button[aria-label*="See more"], [data-review-id] button.w8nwRe'};async function xt(e,t,n,a){let s,i=!1,d,U=()=>{},S=()=>a?.reason instanceof DOMException&&a.reason.name==="TimeoutError"?a.reason:new j,h=()=>U(S()),l=new Promise((r,u)=>{U=u}),o=async r=>{let u;try{await Promise.race([r.close().catch(()=>{}),new Promise(c=>{u=setTimeout(c,2e3)})])}finally{u&&clearTimeout(u)}};if(a?.aborted)throw S();a?.addEventListener("abort",h,{once:!0}),d=setTimeout(()=>U(new DOMException("Optional pagination timed out","TimeoutError")),3e4);try{return await Promise.race([(async()=>{let r=await e.newPage();if(i)throw await o(r),new j;if(s=r,await t(r),i)throw new j;return n(r)})(),l])}finally{i=!0,d&&clearTimeout(d),a?.removeEventListener("abort",h),s&&await o(s)}}var Hn=/\b(?:HeadlessChrome|Chrome|Chromium|Firefox)\/\d+|\bVersion\/\d+.*\bSafari\//;async function Ot(e){try{let t=await e.evaluate(()=>navigator.userAgent);return typeof t=="string"&&Hn.test(t)?t:null}catch{return null}}async function Bt(e){let t=null;try{let n=e.contexts().flatMap(a=>a.pages())[0];return n||(t=await e.newContext(),n=t.pages()[0]??await t.newPage()),await Ot(n)}catch{return null}finally{t&&await t.close().catch(()=>{})}}function ci(e,t){return t?{...e,userAgent:t}:e}ee.use(Fn());var Gn=180,Dn=3e3,Vn=5e3,En='#search, #rso, a[href] h3, [data-snhf], [role="main"]';function Xt(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}function Yn(e,t){let n=process.env[e];if(!n)return t;let a=Number(n);return Number.isInteger(a)&&a>0?a:t}function te(e){return e?e.slice(-6):null}function De(e,t){let n=(t??process.env.SERP_REDIRECT_BASE)?.trim().replace(/\/+$/,"");return n?`${n}/g/${Buffer.from(e,"utf8").toString("base64url")}`:e}function Kn(e){return e?/united states|u\.?s\.?a?\.?|^us$/i.test(e.trim()):!1}function ht(e){return e instanceof Error?e.message:String(e)}function Jn(e){return/\b409\b|conflict|already exists/i.test(ht(e))}function _n(e){return/\b404\b|not[ _-]?found|already (?:gone|deleted|closed)|does not exist/i.test(ht(e))}async function zn(e,t){try{await e.profiles.create({name:t})}catch(n){if(!Jn(n))throw n}}function Ht(e,t){return{viewport:e.viewport,locale:e.locale,...t?{userAgent:t}:{},...e.deviceScaleFactor?{deviceScaleFactor:e.deviceScaleFactor}:{},...e.isMobile!==void 0?{isMobile:e.isMobile}:{},...e.hasTouch!==void 0?{hasTouch:e.hasTouch}:{}}}async function Ut(e,t,n){let a;try{return await Promise.race([e,new Promise((s,i)=>{a=setTimeout(()=>i(new Error(`${n} timed out after ${t}ms`)),t)})])}finally{a&&clearTimeout(a)}}function qn(e){let t=e.trim();if(!t)throw new Error("channelHandle is required");if(/^https?:\/\//i.test(t)||/^(www\.|m\.)?youtube\.com\//i.test(t)){let d=new URL(/^https?:\/\//i.test(t)?t:`https://${t}`);if(d.hostname.replace(/^www\./,"").replace(/^m\./,"").toLowerCase()!=="youtube.com")throw new Error("channel URL must be on youtube.com");let S=d.pathname.split("/").filter(Boolean),h=S[0]??"",l=S[1]??"";if(h.startsWith("@"))return`https://www.youtube.com/${h}/videos`;if(h==="channel"&&l)return`https://www.youtube.com/channel/${l}/videos`;if((h==="c"||h==="user")&&l)return`https://www.youtube.com/${h}/${l}/videos`;throw new Error("channel URL must be a YouTube handle, /channel/UC..., /c/..., or /user/... URL")}let s=t.replace(/^\/+/,"").replace(/\/+$/,"").replace(/\/videos$/i,"");if(/^UC[\w-]{20,}$/.test(s))return`https://www.youtube.com/channel/${s}/videos`;let i=s.startsWith("@")?s:`@${s}`;if(!/^@[\w.-]+$/.test(i))throw new Error("channelHandle must be an @handle, UC channel ID, or YouTube channel URL");return`https://www.youtube.com/${i}/videos`}var Ft=class{browser=null;context=null;page=null;\u006b\u0065\u0072\u006e\u0065\u006cClient=null;\u006b\u0065\u0072\u006e\u0065\u006cSessionId=null;\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=null;\u006b\u0065\u0072\u006e\u0065\u006cStealth=null;\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed=null;\u006b\u0065\u0072\u006e\u0065\u006cProxySource=null;\u006b\u0065\u0072\u006e\u0065\u006cProxyType=null;\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=null;debugEnabled=!1;debugSnapshot={\u006b\u0065\u0072\u006e\u0065\u006c:null,context:null,networkLocation:null,serpNavigation:null};async launch(t){this.debugEnabled=t.debug===!0;let n=t.proxyMode??(t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId?"configured":"none"),a=t.isMobile?"mobile":"desktop";if(this.debugSnapshot={\u006b\u0065\u0072\u006e\u0065\u006c:null,context:{viewport:t.viewport,locale:t.locale,device:a,userAgent:null,deviceScaleFactor:t.deviceScaleFactor??null,isMobile:t.isMobile===!0,hasTouch:t.hasTouch===!0},networkLocation:null,serpNavigation:null},t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey){this.\u006b\u0065\u0072\u006e\u0065\u006cClient=new tt({apiKey:t.\u006b\u0065\u0072\u006e\u0065\u006cApiKey});let i=Number.isInteger(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds)&&Number(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds)>0?Number(t.\u006b\u0065\u0072\u006e\u0065\u006cTimeoutSeconds):Yn("\u004b\u0045\u0052\u004e\u0045\u004c_BROWSER_TIMEOUT_SECONDS",Gn),d=Math.min(i,600);t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName&&t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges===!0&&await zn(this.\u006b\u0065\u0072\u006e\u0065\u006cClient,t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName);let U=At(),S;t.headlessMode==="headful"||U?.forceHeadful===!0?S=!1:t.headlessMode==="headless"?S=!0:S=U?.forceHeadless===!0||process.env.\u004b\u0045\u0052\u004e\u0045\u004c_HEADLESS_DISABLED!=="true"&&!!U?.op&&We.has(U.op),this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=S?!0:null,U?.headlessSentOut&&(U.headlessSentOut.value=this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent);let h=await this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.create({stealth:t.\u006b\u0065\u0072\u006e\u0065\u006cStealth===!0,timeout_seconds:d,...S?{headless:!0}:{},...t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId?{proxy_id:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId}:{},...t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName?{profile:{name:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName,...typeof t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges=="boolean"?{save_changes:t.\u006b\u0065\u0072\u006e\u0065\u006cProfileSaveChanges}:{}}}:{}});this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId=h.session_id,this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=Date.now(),this.\u006b\u0065\u0072\u006e\u0065\u006cStealth=typeof h.stealth=="boolean"?h.stealth:null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed=typeof h.proxy_id=="string"?!!h.proxy_id:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource=t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.source??null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType=t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.proxyType??null;let l=null,o=null;if(!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId&&!t.keepDefaultProxy)try{await Ut(this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.update(this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,{disable_default_proxy:!0}),5e3,`\u004b\u0065\u0072\u006e\u0065\u006c session ${this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId} disable default proxy`),l=!0}catch(u){l=!1,o=ht(u)}let r={sessionId:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,proxyMode:n,requestedProxyIdPresent:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,requestedProxyIdSuffix:te(t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId),createdProxyIdPresent:typeof h.proxy_id=="string"?!!h.proxy_id:null,createdProxyIdSuffix:te(h.proxy_id),retrievedProxyIdPresent:null,retrievedProxyIdSuffix:null,retrievedProxyIdMatchesRequested:null,defaultProxyDisabled:l,defaultProxyDisableError:o,proxyResolution:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution??null,timeoutSeconds:d,stealth:typeof h.stealth=="boolean"?h.stealth:null,profilePresent:null,poolPresent:null,retrieveError:null};if(this.debugSnapshot.\u006b\u0065\u0072\u006e\u0065\u006c=r,console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_created",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,timeout_seconds:d,proxy_mode:n,proxy_id_present:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId,profile_name_present:!!t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName,proxy_resolution_source:t.\u006b\u0065\u0072\u006e\u0065\u006cProxyResolution?.source})),this.debugEnabled&&await this.populate\u004b\u0065\u0072\u006e\u0065\u006cRetrieveDebug(r,t.\u006b\u0065\u0072\u006e\u0065\u006cProxyId),this.browser=await Rn.connectOverCDP(h.cdp_ws_url),t.\u006b\u0065\u0072\u006e\u0065\u006cProfileName||t.preserve\u004b\u0065\u0072\u006e\u0065\u006cContext)this.context=this.browser.contexts()[0]??await this.browser.newContext(Ht(t)),this.page=this.context.pages()[0]??await this.context.newPage(),this.debugSnapshot.context.userAgent=await Ot(this.page);else{let u=await Bt(this.browser);this.debugSnapshot.context.userAgent=u,this.context=await this.browser.newContext(Ht(t,u)),this.page=await this.context.newPage()}if(await this.installEsbuildHelperShims(this.context),t.preserve\u004b\u0065\u0072\u006e\u0065\u006cContext||await this.page.setViewportSize(t.viewport),(this.debugEnabled||t.requireUsEgress)&&(this.debugSnapshot.networkLocation=await this.captureBrowserNetworkLocation()),t.requireUsEgress){let u=this.debugSnapshot.networkLocation?.country??null;if(!Kn(u))throw new J(`Non-US egress (${u??"unknown"}) \u2014 retrying with a fresh session`)}return}let s={headless:t.headless,proxy:t.proxy?{server:t.proxy}:void 0,...t.browserExecutablePath?{executablePath:t.browserExecutablePath}:{},...t.ignoreDefaultArgs?{ignoreDefaultArgs:t.ignoreDefaultArgs}:{}};if(t.profileDir)this.context=await ee.launchPersistentContext(t.profileDir,{...s,...Ht(t)}),await this.installEsbuildHelperShims(this.context),this.page=await this.context.newPage(),this.debugSnapshot.context.userAgent=await Ot(this.page);else{this.browser=await ee.launch(s);let i=await Bt(this.browser);this.debugSnapshot.context.userAgent=i,this.context=await this.browser.newContext(Ht(t,i)),await this.installEsbuildHelperShims(this.context),this.page=await this.context.newPage()}this.debugEnabled&&(this.debugSnapshot.networkLocation=await this.captureBrowserNetworkLocation())}async populate\u004b\u0065\u0072\u006e\u0065\u006cRetrieveDebug(t,n){if(!(!this.\u006b\u0065\u0072\u006e\u0065\u006cClient||!this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId))try{let a=await Ut(this.\u006b\u0065\u0072\u006e\u0065\u006cClient.browsers.retrieve(this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId),5e3,`\u004b\u0065\u0072\u006e\u0065\u006c session ${this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId} retrieve`);t.retrievedProxyIdPresent=typeof a.proxy_id=="string"?!!a.proxy_id:!1,t.retrievedProxyIdSuffix=te(a.proxy_id),t.retrievedProxyIdMatchesRequested=n?a.proxy_id===n:!a.proxy_id,t.timeoutSeconds=typeof a.timeout_seconds=="number"?a.timeout_seconds:t.timeoutSeconds,t.stealth=typeof a.stealth=="boolean"?a.stealth:t.stealth,t.profilePresent=!!a.profile,t.poolPresent=!!a.pool}catch(a){t.retrieveError=ht(a)}}async captureBrowserNetworkLocation(){let t=(a,s="ipapi.co")=>({source:s,ip:null,city:null,region:null,country:null,org:null,timezone:null,error:a});if(!this.context)return t("browser context is not available");let n=null;try{n=await this.context.newPage();let a=await this.loadJsonInDebugPage(n,"https://ipwho.is/");if(a){let U=typeof a.connection=="object"&&a.connection!==null?a.connection:{};return{source:"ipwho.is",ip:typeof a.ip=="string"?a.ip:null,city:typeof a.city=="string"?a.city:null,region:typeof a.region=="string"?a.region:null,country:typeof a.country=="string"?a.country:null,org:typeof U.org=="string"?U.org:null,timezone:typeof a.timezone=="object"&&a.timezone!==null&&typeof a.timezone.id=="string"?a.timezone.id:null,error:null}}let s=await this.loadJsonInDebugPage(n,"https://api64.ipify.org?format=json");if(s)return{source:"api64.ipify.org",ip:typeof s.ip=="string"?s.ip:null,city:null,region:null,country:null,org:null,timezone:null,error:null};await Ut(n.goto("https://ipapi.co/json/",{waitUntil:"domcontentloaded",timeout:7e3}),8e3,"browser network location navigation");let i=await n.locator("body").innerText({timeout:2e3}),d=JSON.parse(i);return{source:"ipapi.co",ip:typeof d.ip=="string"?d.ip:null,city:typeof d.city=="string"?d.city:null,region:typeof d.region=="string"?d.region:null,country:typeof d.country_name=="string"?d.country_name:typeof d.country=="string"?d.country:null,org:typeof d.org=="string"?d.org:null,timezone:typeof d.timezone=="string"?d.timezone:null,error:null}}catch(a){return t(ht(a))}finally{await n?.close().catch(()=>{})}}async loadJsonInDebugPage(t,n){try{await Ut(t.goto(n,{waitUntil:"domcontentloaded",timeout:7e3}),8e3,`browser network location navigation ${n}`);let a=await t.locator("body").innerText({timeout:2e3});return JSON.parse(a)}catch{return null}}async installEsbuildHelperShims(t){await t.addInitScript(()=>{let n=globalThis;typeof n.__name!="function"&&(n.__name=a=>a),typeof n.__publicField!="function"&&(n.__publicField=(a,s,i)=>(a[s]=i,i))})}async withTemporaryPage(t,n){if(!this.context)throw new Error("Browser context is not available");return xt(this.context,async()=>{},t,n)}async navigateToSERP(t,n,a,s,i){let d=new URLSearchParams({q:t,gl:a,hl:s,pws:"0"});i?.tbs&&d.set("tbs",i.tbs),n&&d.set("uule",n);let U="https://www.google.com/search?"+d.toString(),S=De(U),h=i?.debug?{requestedUrl:U,finalUrl:null,title:null,bodySnippet:null,hasPaa:null,captchaDetected:null,googleSorryUrl:null,redirected:null}:null;h&&(this.debugSnapshot.serpNavigation=h);try{await this.page.goto(S,{waitUntil:"domcontentloaded",timeout:Xt(i?.deadlineMs,i?.purpose==="serp"?8e3:45e3)})}catch(o){await this.updateSerpNavigationDebug(h,U,{hasPaa:null,captchaDetected:null});let r=await this.captureDiagnostics(U);throw new It(`page.goto failed: ${o.message} | ${r}`)}if(await this.isSerpChallengeVisible())throw await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!0}),new J(this.captchaMessage());if(i?.purpose==="serp"){await this.page.waitForSelector(En,{timeout:Xt(i.deadlineMs,1500)}).catch(()=>null);let o=await this.page.locator(F.item).count().catch(()=>0)>0;return await this.updateSerpNavigationDebug(h,U,{hasPaa:o,captchaDetected:!1}),{hasPaa:o}}if(await this.page.waitForSelector(F.item,{timeout:Xt(i?.deadlineMs,4e3)}).catch(()=>null))return await this.updateSerpNavigationDebug(h,U,{hasPaa:!0,captchaDetected:!1}),{hasPaa:!0};if(await this.isSerpChallengeVisible())throw await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!0}),new J(this.captchaMessage());for(let o=1;o<=6;o++)if(await this.page.evaluate(u=>{window.scrollTo(0,document.body.scrollHeight*u)},o/6),await this.page.waitForTimeout(600),await this.page.locator(F.item).count()>0)return await this.updateSerpNavigationDebug(h,U,{hasPaa:!0,captchaDetected:!1}),{hasPaa:!0};return await this.updateSerpNavigationDebug(h,U,{hasPaa:!1,captchaDetected:!1}),{hasPaa:!1}}async isSerpChallengeVisible(){if(!this.page)return!1;if(await this.page.locator(F.captchaMarker).count().catch(()=>0)>0)return!0;let n=this.page.url();if(/google\.[^/]+\/sorry\//i.test(n))return!0;let a=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,1e3)).catch(()=>"");return/recaptcha|unusual traffic|are you a robot|about this page|detected unusual traffic/i.test(a)}async updateSerpNavigationDebug(t,n,a){if(!(!t||!this.page))try{let s=this.page.url(),i=await this.page.title().catch(()=>""),d=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,500)).catch(()=>""),U=/recaptcha|unusual traffic|are you a robot/i.test(d);t.finalUrl=s,t.title=i,t.bodySnippet=d,t.hasPaa=a.hasPaa,t.captchaDetected=a.captchaDetected??U,t.googleSorryUrl=/google\.[^/]+\/sorry\//i.test(s),t.redirected=s!==n}catch(s){t.bodySnippet=`debug capture failed: ${ht(s)}`}}async captureDiagnostics(t){try{let n=this.page.url(),a=await this.page.title().catch(()=>""),s=await this.page.evaluate(()=>(document.body?.innerText??"").replace(/\s+/g," ").trim().slice(0,400)).catch(()=>""),i=/consent\.google\./.test(n)||/before you continue/i.test(s),d=/recaptcha|unusual traffic|are you a robot/i.test(s),U=[i?"CONSENT_WALL":"",d?"BOT_CHALLENGE":"",n!==t?"REDIRECTED":""].filter(Boolean).join(",");return`intended=${t} | final=${n} | title="${a}" | flags=[${U}] | body="${s}"`}catch(n){return`diagnostics-failed: ${n.message}`}}captchaMessage(){return this.\u006b\u0065\u0072\u006e\u0065\u006cClient?"Google returned a CAPTCHA on this session \u2014 retrying with a fresh session.":fe}async navigateTo(t){let n=process.env.ADS_ARRIVAL_REDIRECT_BASE?.trim(),a=n?De(t,n):t;try{if(await this.page.goto(a,{waitUntil:"domcontentloaded",timeout:45e3}),/google\.[^/]+\/search\?/i.test(t)&&await this.isSerpChallengeVisible())throw new J(this.captchaMessage())}catch(s){if(s instanceof J)throw s;let i=await this.captureDiagnostics(t);throw new It(`page.goto failed: ${s.message} | ${i}`)}}async navigateToChannel(t){let n=qn(t);try{await this.page.goto(n,{waitUntil:"networkidle",timeout:3e4})}catch(a){let s=await this.captureDiagnostics(n);throw new It(`navigateToChannel failed: ${a.message} | ${s}`)}}async evaluate(t,n){return this.page.evaluate(t,n)}getPage(){return this.page}get\u004b\u0065\u0072\u006e\u0065\u006cSessionId(){return this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId}getProviderSessionMetadata(){return{provider:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId?"\u006b\u0065\u0072\u006e\u0065\u006c":"local",providerSessionId:this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,disconnectObservation:null}}getDebugSnapshot(){return this.debugSnapshot}async close(){if(this.browser){let t=this.browser,n=this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,a=this.\u006b\u0065\u0072\u006e\u0065\u006cClient,s=this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs,i=this.\u006b\u0065\u0072\u006e\u0065\u006cStealth,d=this.\u006b\u0065\u0072\u006e\u0065\u006cProxyUsed,U=this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource,S=this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType,h=this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent,l=this.getProviderSessionMetadata();if(this.browser=null,this.context=null,this.page=null,this.\u006b\u0065\u0072\u006e\u0065\u006cSessionId=null,this.\u006b\u0065\u0072\u006e\u0065\u006cClient=null,this.\u006b\u0065\u0072\u006e\u0065\u006cOpenedAtMs=null,this.\u006b\u0065\u0072\u006e\u0065\u006cHeadlessSent=null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxySource=null,this.\u006b\u0065\u0072\u006e\u0065\u006cProxyType=null,a&&n&&s!=null&&Ie({\u006b\u0065\u0072\u006e\u0065\u006cSessionId:n,source:"browser_driver",stealth:i,headlessSent:h,proxyUsed:d,proxySource:U,proxyType:S,openedAtMs:s,closedAtMs:Date.now()}),a&&n){console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_started",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n}));let o=Ut(a.browsers.deleteByID(n),Vn,`\u004b\u0065\u0072\u006e\u0065\u006c session ${n} delete`),r=Ut(t.close(),Dn,`\u004b\u0065\u0072\u006e\u0065\u006c browser ${n} close`),[u,c]=await Promise.allSettled([o,r]),g=u.status==="rejected"&&_n(u.reason),v={\u006b\u0065\u0072\u006e\u0065\u006cSessionId:n,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!0,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:u.status==="fulfilled"||g,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:u.status==="rejected"&&!g?u.reason instanceof Error?u.reason.message:String(u.reason):null,browserCloseSucceeded:c.status==="fulfilled",browserCloseError:c.status==="rejected"?c.reason instanceof Error?c.reason.message:String(c.reason):null,provider:l.provider,providerSessionId:l.providerSessionId,providerDisconnectObserved:!1,providerDisconnectMessage:null};return u.status==="rejected"&&!g?(console.warn(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_failed",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n,message:v.\u006b\u0065\u0072\u006e\u0065\u006cDeleteError})),console.warn(`\u004b\u0065\u0072\u006e\u0065\u006c session cleanup failed for ${n}:`,u.reason)):console.info(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_delete_succeeded",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n})),c.status==="rejected"&&(console.warn(JSON.stringify({event:"\u006b\u0065\u0072\u006e\u0065\u006c_browser_close_failed",\u006b\u0065\u0072\u006e\u0065\u006c_session_id:n,message:v.browserCloseError})),console.warn(`\u004b\u0065\u0072\u006e\u0065\u006c browser close failed for ${n}:`,c.reason)),v}return await t.close(),{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:!0,browserCloseError:null,provider:l.provider,providerSessionId:l.providerSessionId,providerDisconnectObserved:!1,providerDisconnectMessage:null}}else if(this.context){let t=this.context;return this.context=null,this.page=null,await t.close(),{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:!0,browserCloseError:null,provider:"local",providerSessionId:null,providerDisconnectObserved:!1,providerDisconnectMessage:null}}return{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:null,browserCloseError:null,provider:"local",providerSessionId:null,providerDisconnectObserved:!1,providerDisconnectMessage:null}}};import{chromium as Qn}from"playwright";function $n(e,t){if(typeof e!="string")return null;let n=e.replace(/[\u0000-\u001f\u007f]+/g," ").replace(/\s+/g," ").trim();return n?n.slice(0,t):null}function Ve(e){let t=$n(e,320);return t?t.replace(/\b(?:wss?|https?):\/\/\S+/gi,"[redacted endpoint]").replace(/\b(?:authorization|proxy-authorization):\s*\S+/gi,"$1: [redacted]").replace(/\bBearer\s+\S+/gi,"Bearer [redacted]").slice(0,320):null}function Ee(e){return Ve(e)}function Ye(e){if(typeof e!="string"||e.length===0||e.length>512||e.trim()!==e||/[\s\u0000-\u001f\u007f]/.test(e)||/:\/\//.test(e))throw new Error("\u0042\u0072\u0069\u0067\u0068\u0074 \u0044\u0061\u0074\u0061 did not return a valid browser session ID");return e}function ne(e,t,n=new Date().toISOString()){let a=Ve(t);return{source:e,message:a??e.replaceAll("_"," "),observedAt:n}}function jn(e){return{provider:e.provider,providerDisconnectObserved:e.disconnectObservation!==null,providerDisconnectMessage:e.disconnectObservation?.message??null}}function Ke(e){return{...jn(e),providerSessionId:e.providerSessionId}}var Zn=new Set(["image","media","font","stylesheet","ping"]),Xn=["doubleclick.net","googleadservices.com","googlesyndication.com","google-analytics.com"],ta='#search, #rso, a[href] h3, [data-snhf], [role="main"]',ea=3e4,Je=1500;function Rt(e,t){return e?Math.max(1,Math.min(t,e-Date.now())):t}function _e(){return process.env.\u0042\u0052\u0049\u0047\u0048\u0054\u0044\u0041\u0054\u0041_BROWSER_WSS?.trim()||null}function ze(){return process.env.SERP_BROWSER_PROVIDER?.trim().toLowerCase()==="\u006b\u0065\u0072\u006e\u0065\u006c"?!1:!!_e()}async function ae(e,t=!1){let n=e.request();try{let a=await n.allHeaders(),s=await fetch(n.url(),{method:n.method(),headers:{accept:a.accept??"*/*","accept-language":a["accept-language"]??"en-US,en;q=0.9","user-agent":a["user-agent"]??"Mozilla/5.0",...t?{cookie:a.cookie??"",referer:a.referer??"https://www.google.com/",...a["x-client-data"]?{"x-client-data":a["x-client-data"]}:{}}:{}},body:n.method()==="GET"||n.method()==="HEAD"?void 0:n.postData()});if(!s.ok)return!1;let i=Buffer.from(await s.arrayBuffer());return await e.fulfill({status:s.status,contentType:s.headers.get("content-type")??"application/octet-stream",headers:{"cache-control":"public, max-age=3600"},body:i}),!0}catch{return!1}}var Gt=class{browser=null;context=null;page=null;cdpSession=null;providerSessionId=null;disconnectObservation=null;closing=!1;observeDisconnect(t,n){this.closing||this.disconnectObservation||(this.disconnectObservation=ne(t,n))}async launch(t){if(this.page)return;this.closing=!1,this.providerSessionId=null,this.disconnectObservation=null;let n=_e();if(!n)throw new Error("SERP browser service is not configured");this.browser=await Qn.connectOverCDP(n,{timeout:Rt(t.operationDeadlineMs,ea)}),this.context=this.browser.contexts()[0]??await this.browser.newContext(),await this.context.addInitScript(()=>{let i=globalThis;typeof i.__name!="function"&&(i.__name=d=>d),typeof i.__publicField!="function"&&(i.__publicField=(d,U,S)=>(d[U]=S,S))}),this.page=this.context.pages()[0]??await this.context.newPage(),this.browser.on("disconnected",()=>this.observeDisconnect("browser_disconnected")),this.context.on("close",()=>this.observeDisconnect("context_closed")),this.page.on("close",()=>this.observeDisconnect("page_closed")),this.page.on("crash",()=>this.observeDisconnect("page_crashed")),this.cdpSession=await this.context.newCDPSession(this.page);let s=await this.cdpSession.send("Browser.getSessionId");this.providerSessionId=Ye(s?.sessionId),await this.setupPage(this.page)}async setupPage(t){await t.route("**/*",async n=>{let a=n.request(),s=a.resourceType(),i;try{i=new URL(a.url())}catch{await n.continue();return}let d=i.hostname.toLowerCase();if(!(i.pathname==="/sgasync"&&await ae(n,!0))&&!(i.pathname.includes("/shared_dict/")&&await ae(n))&&!(s==="script"&&(d==="www.google.com"||d==="www.gstatic.com")&&await ae(n))){if(Zn.has(s)){await n.abort("blockedbyclient");return}if(Xn.some(U=>d===U||d.endsWith(`.${U}`))){await n.abort("blockedbyclient");return}await n.continue()}})}async withTemporaryPage(t,n){if(!this.context||this.closing)throw new Error("Browser context is not available");return xt(this.context,a=>this.setupPage(a),t,n)}async navigateToSERP(t,n,a,s,i){if(!this.page)throw new Error("Browser page is not available");let d=new URLSearchParams({q:t,gl:a,hl:s,pws:"0"});return i?.tbs&&d.set("tbs",i.tbs),n&&d.set("uule",n),await this.page.goto(`https://www.google.com/search?${d}`,{waitUntil:"domcontentloaded",timeout:Rt(i?.deadlineMs,i?.purpose==="serp"?8e3:45e3)}),i?.purpose==="serp"?(await this.page.waitForSelector(ta,{timeout:Rt(i.deadlineMs,1500)}).catch(()=>null),{hasPaa:await this.page.locator(F.item).count().catch(()=>0)>0}):{hasPaa:!!await this.page.waitForSelector(F.item,{timeout:Rt(i?.deadlineMs,8e3)}).catch(()=>null)}}async navigateTo(t){if(!this.page)throw new Error("Browser page is not available");await this.page.goto(t,{waitUntil:"load",timeout:45e3})}async navigateToChannel(){throw new Error("YouTube navigation is not supported by the SERP browser driver")}async evaluate(t,n){if(!this.page)throw new Error("Browser page is not available");return this.page.evaluate(t,n)}getPage(){if(!this.page)throw new Error("Browser page is not available");return this.page}get\u004b\u0065\u0072\u006e\u0065\u006cSessionId(){return null}getProviderSessionMetadata(){return{provider:"\u0062\u0072\u0069\u0067\u0068\u0074_\u0064\u0061\u0074\u0061_browser_api",providerSessionId:this.providerSessionId,disconnectObservation:this.disconnectObservation}}getDebugSnapshot(){return{\u006b\u0065\u0072\u006e\u0065\u006c:null,context:null,networkLocation:null,serpNavigation:null}}async close(){this.closing=!0;let t=null,n;try{let s=this.browser?.close();s&&await Promise.race([s,new Promise((i,d)=>{n=setTimeout(()=>d(new Error(`Browser close acknowledgement exceeded ${Je}ms`)),Je)})])}catch(s){t=Ee(s instanceof Error?s.message:String(s))??"\u0042\u0072\u0069\u0067\u0068\u0074 \u0044\u0061\u0074\u0061 browser close failed",this.disconnectObservation??=ne("browser_close_error",t)}finally{n&&clearTimeout(n)}let a=Ke(this.getProviderSessionMetadata());return this.browser=null,this.context=null,this.page=null,this.cdpSession=null,{\u006b\u0065\u0072\u006e\u0065\u006cSessionId:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted:!1,\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded:null,\u006b\u0065\u0072\u006e\u0065\u006cDeleteError:null,browserCloseSucceeded:t===null,browserCloseError:t,...a}}};function qe(e){return e.plannedProvider==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061"?new Gt:new Ft}var st={austin:"Austin,Texas,United States","new york":"New York,New York,United States","new york city":"New York,New York,United States",nyc:"New York,New York,United States","los angeles":"Los Angeles,California,United States",la:"Los Angeles,California,United States",chicago:"Chicago,Illinois,United States",houston:"Houston,Texas,United States",phoenix:"Phoenix,Arizona,United States",philadelphia:"Philadelphia,Pennsylvania,United States",philly:"Philadelphia,Pennsylvania,United States","san antonio":"San Antonio,Texas,United States",dallas:"Dallas,Texas,United States",miami:"Miami,Florida,United States",seattle:"Seattle,Washington,United States",denver:"Denver,Colorado,United States",loveland:"Loveland,Colorado,United States","loveland co":"Loveland,Colorado,United States","fort collins":"Fort Collins,Colorado,United States",boulder:"Boulder,Colorado,United States","colorado springs":"Colorado Springs,Colorado,United States",boston:"Boston,Massachusetts,United States",atlanta:"Atlanta,Georgia,United States","san francisco":"San Francisco,California,United States",sf:"San Francisco,California,United States",portland:"Portland,Oregon,United States","las vegas":"Las Vegas,Nevada,United States",minneapolis:"Minneapolis,Minnesota,United States",detroit:"Detroit,Michigan,United States",nashville:"Nashville,Tennessee,United States",charlotte:"Charlotte,North Carolina,United States",orlando:"Orlando,Florida,United States","san diego":"San Diego,California,United States",baltimore:"Baltimore,Maryland,United States",sacramento:"Sacramento,California,United States",columbus:"Columbus,Ohio,United States",indianapolis:"Indianapolis,Indiana,United States","san jose":"San Jose,California,United States","fort worth":"Fort Worth,Texas,United States",jacksonville:"Jacksonville,Florida,United States",memphis:"Memphis,Tennessee,United States",louisville:"Louisville,Kentucky,United States",raleigh:"Raleigh,North Carolina,United States",richmond:"Richmond,Virginia,United States","salt lake city":"Salt Lake City,Utah,United States",toronto:"Toronto,Ontario,Canada",vancouver:"Vancouver,British Columbia,Canada",montreal:"Montreal,Quebec,Canada",calgary:"Calgary,Alberta,Canada",ottawa:"Ottawa,Ontario,Canada",london:"London,England,United Kingdom",manchester:"Manchester,England,United Kingdom",birmingham:"Birmingham,England,United Kingdom",edinburgh:"Edinburgh,Scotland,United Kingdom",glasgow:"Glasgow,Scotland,United Kingdom",leeds:"Leeds,England,United Kingdom",sydney:"Sydney,New South Wales,Australia",melbourne:"Melbourne,Victoria,Australia",brisbane:"Brisbane,Queensland,Australia",perth:"Perth,Western Australia,Australia",adelaide:"Adelaide,South Australia,Australia",dublin:"Dublin,Leinster,Ireland"};var $e=`3, Nanjemoy,Maryland,United States
|
|
2
2
|
Aaronsburg,Pennsylvania,United States
|
|
3
3
|
Abbeville,Alabama,United States
|
|
4
4
|
Abbeville,Georgia,United States
|