mcp-scraper 0.88.2 → 0.89.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -15
- package/README.md +6 -5
- package/THIRD_PARTY_NOTICES.html +203 -0
- package/dist/analytics-repository-2BMT5JNE.js +1 -0
- package/dist/bin/api-server.js +2 -41
- package/dist/bin/mcp-scraper-cli.js +39 -756
- package/dist/bin/mcp-scraper-core.js +1 -60
- package/dist/bin/mcp-scraper-install.js +2 -25
- package/dist/bin/mcp-stdio-server.js +1 -19
- package/dist/bin/paa-harvest.js +1 -41
- package/dist/chunk-3GP5CYZX.js +1 -0
- package/dist/chunk-4AI7DOS7.js +59 -0
- package/dist/chunk-4FROKQJN.js +1 -0
- package/dist/chunk-7YGVI5J4.js +21710 -0
- package/dist/chunk-CCYWSJNG.js +16 -0
- package/dist/chunk-CFI6CXIV.js +182 -0
- package/dist/chunk-E2WRWV3A.js +1 -0
- package/dist/chunk-GMWKPIYX.js +1172 -0
- package/dist/chunk-HDPYG3XV.js +102 -0
- package/dist/chunk-HE45FFBU.js +1 -0
- package/dist/chunk-HUV2WTRW.js +1 -0
- package/dist/chunk-KJQXUZ4Y.js +4 -0
- package/dist/chunk-L4CGLFPU.js +4 -0
- package/dist/chunk-M22MM4N4.js +84 -0
- package/dist/chunk-MASR22K4.js +73 -0
- package/dist/chunk-MZN4U5BL.js +1 -0
- package/dist/chunk-PUHFVA7P.js +1280 -0
- package/dist/chunk-QPWPR5XG.js +10 -0
- package/dist/chunk-TMB56NCA.js +1 -0
- package/dist/chunk-TXENITMS.js +20 -0
- package/dist/chunk-W2BVJ7S2.js +13 -0
- package/dist/chunk-WO3N5FH2.js +5 -0
- package/dist/chunk-WSCGYRWA.js +2595 -0
- package/dist/chunk-X54CQLK2.js +1 -0
- package/dist/chunk-XLWNEVUZ.js +27 -0
- package/dist/chunk-XPZVJIZ2.js +100 -0
- package/dist/chunk-YQZGZBB4.js +1 -0
- package/dist/chunk-Z2QGQJS2.js +1 -0
- package/dist/db-F2MX63GI.js +1 -0
- package/dist/extract-bundle-SNUIHM3J.js +26 -0
- package/dist/gmail-service-BZ3H75XC.js +1 -0
- package/dist/index.cjs +21750 -6045
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +18 -315
- package/dist/lead-list-enrichment-repository-S2H3U7T7.js +1 -0
- package/dist/location-data-repository-OTWHWMV6.js +1 -0
- package/dist/server-RFR2A5UJ.js +7303 -0
- package/dist/site-extract-repository-SE776XDC.js +1 -0
- package/dist/worker-XUDSM3AL.js +1 -0
- package/package.json +17 -124
- package/dist/analytics-repository-GGJJCVVP.js +0 -194
- package/dist/chunk-4QMUF6XM.js +0 -1013
- package/dist/chunk-6HAV7LCE.js +0 -265
- package/dist/chunk-ABF2CGOZ.js +0 -113
- package/dist/chunk-C5Z4OFKW.js +0 -404
- package/dist/chunk-DNM65UCK.js +0 -299
- package/dist/chunk-EQGTEHLZ.js +0 -592
- package/dist/chunk-F5GQJWZU.js +0 -732
- package/dist/chunk-GGZEC22A.js +0 -215
- package/dist/chunk-GXBZXWXB.js +0 -184
- package/dist/chunk-IHXAXYIS.js +0 -843
- package/dist/chunk-K3Z5AQYE.js +0 -683
- package/dist/chunk-K45K75OF.js +0 -6
- package/dist/chunk-LFW2FRPJ.js +0 -224
- package/dist/chunk-MZDNZQWT.js +0 -2078
- package/dist/chunk-NVUKO5NN.js +0 -256
- package/dist/chunk-OM7HVEJ3.js +0 -26
- package/dist/chunk-OPQIGAFB.js +0 -286
- package/dist/chunk-OZJMVCDK.js +0 -16
- package/dist/chunk-P7FWOMU7.js +0 -505
- package/dist/chunk-PGJQDMC2.js +0 -383
- package/dist/chunk-PKZS6SHW.js +0 -33139
- package/dist/chunk-RJ7JVYKU.js +0 -68
- package/dist/chunk-S24LFPL7.js +0 -5262
- package/dist/chunk-T3MZISOF.js +0 -240
- package/dist/chunk-UZPTGUDV.js +0 -1915
- package/dist/chunk-X623GTBV.js +0 -8290
- package/dist/chunk-YXNDOQXN.js +0 -4018
- package/dist/db-Z34LPZNR.js +0 -284
- package/dist/extract-bundle-565SBZCR.js +0 -1003
- package/dist/gmail-service-E6ALS7JG.js +0 -25
- package/dist/lead-list-enrichment-repository-36RPVV6N.js +0 -67
- package/dist/location-data-repository-WPRG62GE.js +0 -34
- package/dist/server-SQZ3A7SY.js +0 -86606
- package/dist/site-extract-repository-VYFZASPU.js +0 -69
- package/dist/worker-LDCAULWL.js +0 -146
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import{b as O}from"./chunk-KJQXUZ4Y.js";import{s as N}from"./chunk-GMWKPIYX.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
|
+
CREATE TABLE IF NOT EXISTS location_data_imports (
|
|
3
|
+
id TEXT PRIMARY KEY,
|
|
4
|
+
dataset_kind TEXT NOT NULL,
|
|
5
|
+
source_url TEXT,
|
|
6
|
+
sha256 TEXT NOT NULL,
|
|
7
|
+
row_count INTEGER NOT NULL DEFAULT 0,
|
|
8
|
+
group_count INTEGER NOT NULL DEFAULT 0,
|
|
9
|
+
state_count INTEGER NOT NULL DEFAULT 0,
|
|
10
|
+
source_row_count INTEGER NOT NULL DEFAULT 0,
|
|
11
|
+
rejected_row_count INTEGER NOT NULL DEFAULT 0,
|
|
12
|
+
zip_count INTEGER NOT NULL DEFAULT 0,
|
|
13
|
+
covered_states_json TEXT NOT NULL DEFAULT '[]',
|
|
14
|
+
coverage_complete INTEGER NOT NULL DEFAULT 0,
|
|
15
|
+
status TEXT NOT NULL,
|
|
16
|
+
error TEXT,
|
|
17
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
18
|
+
completed_at TEXT
|
|
19
|
+
)
|
|
20
|
+
`);let o=new Set((await t.execute("PRAGMA table_info(location_data_imports)")).rows.map(r=>String(r.name))),a=[["source_row_count","INTEGER NOT NULL DEFAULT 0"],["rejected_row_count","INTEGER NOT NULL DEFAULT 0"],["zip_count","INTEGER NOT NULL DEFAULT 0"],["covered_states_json","TEXT NOT NULL DEFAULT '[]'"],["coverage_complete","INTEGER NOT NULL DEFAULT 0"]];for(let[r,n]of a)o.has(r)||await t.execute(`ALTER TABLE location_data_imports ADD COLUMN ${r} ${n}`);await t.execute("CREATE INDEX IF NOT EXISTS location_data_imports_kind_created ON location_data_imports(dataset_kind, created_at DESC)"),await t.execute(`
|
|
21
|
+
CREATE TABLE IF NOT EXISTS location_zip_groups (
|
|
22
|
+
import_id TEXT NOT NULL REFERENCES location_data_imports(id) ON DELETE CASCADE,
|
|
23
|
+
state_abbr TEXT NOT NULL,
|
|
24
|
+
city_key TEXT NOT NULL,
|
|
25
|
+
city TEXT NOT NULL,
|
|
26
|
+
zips_json TEXT NOT NULL,
|
|
27
|
+
counties_json TEXT NOT NULL,
|
|
28
|
+
PRIMARY KEY(import_id, state_abbr, city_key)
|
|
29
|
+
)
|
|
30
|
+
`),await t.execute("CREATE INDEX IF NOT EXISTS location_zip_groups_state ON location_zip_groups(import_id, state_abbr, city_key)"),await t.execute(`
|
|
31
|
+
CREATE TABLE IF NOT EXISTS location_census_places (
|
|
32
|
+
import_id TEXT NOT NULL REFERENCES location_data_imports(id) ON DELETE CASCADE,
|
|
33
|
+
state_abbr TEXT NOT NULL,
|
|
34
|
+
city_key TEXT NOT NULL,
|
|
35
|
+
city TEXT NOT NULL,
|
|
36
|
+
census_name TEXT NOT NULL,
|
|
37
|
+
estimates_base_2020 INTEGER,
|
|
38
|
+
population_2020 INTEGER,
|
|
39
|
+
population_2021 INTEGER,
|
|
40
|
+
population_2022 INTEGER,
|
|
41
|
+
population_2023 INTEGER,
|
|
42
|
+
population_2024 INTEGER,
|
|
43
|
+
population_2025 INTEGER,
|
|
44
|
+
PRIMARY KEY(import_id, state_abbr, city_key)
|
|
45
|
+
)
|
|
46
|
+
`),await t.execute("CREATE INDEX IF NOT EXISTS location_census_places_state ON location_census_places(import_id, state_abbr, city_key)"),await t.execute(`
|
|
47
|
+
CREATE TABLE IF NOT EXISTS location_data_active (
|
|
48
|
+
dataset_kind TEXT PRIMARY KEY,
|
|
49
|
+
import_id TEXT NOT NULL REFERENCES location_data_imports(id),
|
|
50
|
+
activated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
51
|
+
)
|
|
52
|
+
`)})().catch(o=>{throw w=null,o})),await w}async function h(t){await R();let a=(await N().execute({sql:`
|
|
53
|
+
SELECT i.*
|
|
54
|
+
FROM location_data_active a
|
|
55
|
+
JOIN location_data_imports i ON i.id = a.import_id
|
|
56
|
+
WHERE a.dataset_kind = ? AND i.status = 'ready'
|
|
57
|
+
LIMIT 1
|
|
58
|
+
`,args:[t]})).rows[0];return a?C(a):null}async function Z(){return h(D)}async function st(){return await R(),(await N().execute(`
|
|
59
|
+
SELECT i.*
|
|
60
|
+
FROM location_data_active a
|
|
61
|
+
JOIN location_data_imports i ON i.id = a.import_id
|
|
62
|
+
WHERE i.status = 'ready'
|
|
63
|
+
ORDER BY i.dataset_kind ASC
|
|
64
|
+
`)).rows.map(o=>C(o))}async function Q(t){let o=f(t);if(!o)throw new Error("state must be a two-letter US state abbreviation");let a=await Z();if(!a)return{dataset:null,groups:new Map};let r=await N().execute({sql:`
|
|
65
|
+
SELECT city, city_key, state_abbr, zips_json, counties_json
|
|
66
|
+
FROM location_zip_groups
|
|
67
|
+
WHERE import_id = ? AND state_abbr = ?
|
|
68
|
+
ORDER BY city COLLATE NOCASE ASC
|
|
69
|
+
`,args:[a.id,o]}),n=new Map;for(let u of r.rows){let d=String(u.city_key);n.set(d,{city:String(u.city),cityKey:d,state:String(u.state_abbr),zips:JSON.parse(String(u.zips_json)),counties:JSON.parse(String(u.counties_json))})}return{dataset:a,groups:n}}async function at(t){await R();let o=X(t.sourceUrl),a=M("sha256").update(t.csv).digest("hex"),r=await Z();if(r?.sha256===a)return{dataset:r,duplicate:!0};let n=W(t.csv);J(n);let u=`loc_${z().replaceAll("-","")}`,d=N();await d.execute({sql:`
|
|
70
|
+
INSERT INTO location_data_imports (
|
|
71
|
+
id, dataset_kind, source_url, sha256, row_count, group_count, state_count,
|
|
72
|
+
source_row_count, rejected_row_count, zip_count, covered_states_json, coverage_complete, status
|
|
73
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 'loading')
|
|
74
|
+
`,args:[u,D,o,a,n.rowCount,n.groups.length,n.stateCount,n.sourceRowCount,n.rejectedRowCount,n.zipCount,JSON.stringify(n.coveredStates)]});try{for(let i=0;i<n.groups.length;i+=A){let _=n.groups.slice(i,i+A).map(e=>({sql:`
|
|
75
|
+
INSERT INTO location_zip_groups (
|
|
76
|
+
import_id, state_abbr, city_key, city, zips_json, counties_json
|
|
77
|
+
) VALUES (?, ?, ?, ?, ?, ?)
|
|
78
|
+
`,args:[u,e.state,e.cityKey,e.city,JSON.stringify(e.zips),JSON.stringify(e.counties)]}));await d.batch(_,"write")}await d.batch([{sql:"UPDATE location_data_imports SET status = 'ready', completed_at = datetime('now'), error = NULL WHERE id = ? AND status = 'loading'",args:[u]},{sql:`
|
|
79
|
+
INSERT INTO location_data_active (dataset_kind, import_id, activated_at)
|
|
80
|
+
VALUES (?, ?, datetime('now'))
|
|
81
|
+
ON CONFLICT(dataset_kind) DO UPDATE SET import_id = excluded.import_id, activated_at = excluded.activated_at
|
|
82
|
+
`,args:[D,u]}],"write")}catch(i){let _=i instanceof Error?i.message:String(i);throw await d.execute({sql:"UPDATE location_data_imports SET status = 'failed', error = ?, completed_at = datetime('now') WHERE id = ?",args:[_.slice(0,1e3),u]}).catch(()=>{}),i}let p=(await d.execute({sql:"SELECT * FROM location_data_imports WHERE id = ? LIMIT 1",args:[u]})).rows[0];if(!p)throw new Error("Hosted location import completed without a durable metadata row.");return{dataset:C(p),duplicate:!1}}async function nt(t){await R();let o=f(t.state);if(!o)throw new Error("state must be a two-letter US state abbreviation");let a=F(o),r=X(t.sourceUrl),n=M("sha256").update(t.csv).digest("hex"),u=await h(a);if(u?.sha256===n)return{dataset:u,duplicate:!0};let d=$[o],E=B(t.csv,d),p=`loc_${z().replaceAll("-","")}`,i=N();await i.execute({sql:`
|
|
83
|
+
INSERT INTO location_data_imports (
|
|
84
|
+
id, dataset_kind, source_url, sha256, row_count, group_count, state_count,
|
|
85
|
+
source_row_count, rejected_row_count, zip_count, covered_states_json, coverage_complete, status
|
|
86
|
+
) VALUES (?, ?, ?, ?, ?, ?, 1, ?, 0, 0, ?, 1, 'loading')
|
|
87
|
+
`,args:[p,a,r,n,E.places.length,E.places.length,E.sourceRowCount,JSON.stringify([o])]});try{for(let s=0;s<E.places.length;s+=A){let l=E.places.slice(s,s+A).map(c=>({sql:`
|
|
88
|
+
INSERT INTO location_census_places (
|
|
89
|
+
import_id, state_abbr, city_key, city, census_name, estimates_base_2020,
|
|
90
|
+
population_2020, population_2021, population_2022, population_2023,
|
|
91
|
+
population_2024, population_2025
|
|
92
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
93
|
+
`,args:[p,o,c.cityKey,c.city,c.censusName,c.estimatesBase2020,c.populations[2020],c.populations[2021],c.populations[2022],c.populations[2023],c.populations[2024],c.populations[2025]]}));await i.batch(l,"write")}await i.batch([{sql:"UPDATE location_data_imports SET status = 'ready', completed_at = datetime('now'), error = NULL WHERE id = ? AND status = 'loading'",args:[p]},{sql:`
|
|
94
|
+
INSERT INTO location_data_active (dataset_kind, import_id, activated_at)
|
|
95
|
+
VALUES (?, ?, datetime('now'))
|
|
96
|
+
ON CONFLICT(dataset_kind) DO UPDATE SET import_id = excluded.import_id, activated_at = excluded.activated_at
|
|
97
|
+
`,args:[a,p]}],"write")}catch(s){let l=s instanceof Error?s.message:String(s);throw await i.execute({sql:"UPDATE location_data_imports SET status = 'failed', error = ?, completed_at = datetime('now') WHERE id = ?",args:[l.slice(0,1e3),p]}).catch(()=>{}),s}let e=(await i.execute({sql:"SELECT * FROM location_data_imports WHERE id = ? LIMIT 1",args:[p]})).rows[0];if(!e)throw new Error("Hosted Census import completed without a durable metadata row.");return{dataset:C(e),duplicate:!1}}async function it(t){let o=f(t.state);if(!o)throw new Error("state must be a two-letter US state abbreviation");if(!Number.isSafeInteger(t.minPopulation)||t.minPopulation<0)throw new Error("minPopulation must be a non-negative integer");if(!Number.isSafeInteger(t.maxResults)||t.maxResults<1||t.maxResults>100)throw new Error("maxResults must be between 1 and 100");let a=await h(F(o)),n=t.includeZipGroups||!!t.zip?await Q(o):{dataset:null,groups:new Map};if(!a)return{markets:[],populationDataset:null,zipDataset:n.dataset,warnings:[]};let u=await N().execute({sql:`
|
|
98
|
+
SELECT *
|
|
99
|
+
FROM location_census_places
|
|
100
|
+
WHERE import_id = ? AND state_abbr = ?
|
|
101
|
+
ORDER BY city COLLATE NOCASE ASC
|
|
102
|
+
`,args:[a.id,o]}),d=b(t.cityQuery??""),E=t.zip?.trim(),p=`population_${t.populationYear}`,i=u.rows.map(e=>{let s=e[p];if(s==null)return null;let l=Number(s);if(!Number.isSafeInteger(l)||l<t.minPopulation)return null;let c=String(e.city),T=String(e.city_key);if(d&&!T.includes(d))return null;let m=n.groups.get(T),S=m?.zips??[];return E&&!S.includes(E)?null:{city:c,state:o,location:`${c}, ${o}`,cityKey:`${c}|${o}`,censusName:String(e.census_name),population:l,populationYear:t.populationYear,estimatesBase2020:e.estimates_base_2020==null?null:Number(e.estimates_base_2020),zips:t.includeZipGroups?S:[],counties:t.includeZipGroups?m?.counties??[]:[]}}).filter(e=>e!==null).sort((e,s)=>s.population-e.population||e.city.localeCompare(s.city)).slice(0,t.maxResults),_=[];return t.includeZipGroups&&n.dataset&&i.some(e=>e.zips.length===0)&&_.push("Some hosted Census places did not match the hosted ZIP city groups."),{markets:i,populationDataset:a,zipDataset:n.dataset,warnings:_}}export{D as a,K as b,P as c,k as d,B as e,W as f,R as g,h,Z as i,st as j,Q as k,at as l,nt as m,it as n};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isIP as I}from"net";import{lookup as T}from"dns/promises";import p from"ipaddr.js";function P(n){return n.startsWith("[")&&n.endsWith("]")?n.slice(1,-1):n}function b(n){let t=P(n);if(!I(t))return!1;try{let e=p.parse(t),s=o=>[["192.0.0.0",24],["192.0.2.0",24],["198.18.0.0",15],["198.51.100.0",24],["203.0.113.0",24]].some(([m,u])=>o.match(p.parse(m),u));if(e instanceof p.IPv6&&e.isIPv4MappedAddress()){let o=e.toIPv4Address();return o.range()!=="unicast"||s(o)}return e instanceof p.IPv4&&s(e)?!0:e.range()!=="unicast"}catch{return!0}}async function N(n){let t=P(n.toLowerCase());if(t==="localhost"||t.endsWith(".localhost")||t.endsWith(".local")||b(t))return!0;try{let e=await T(t,{all:!0,verbatim:!0});return e.length===0||e.some(s=>b(s.address))}catch{return!0}}async function S(n,t){let e;try{e=new URL(n.trim())}catch{return{error:`Invalid ${t.field}`}}return(t.requireHttps?["https:"]:["http:","https:"]).includes(e.protocol)?await N(e.hostname)?{error:`${t.field} must resolve to a public internet host`}:{parsed:e}:{error:t.requireHttps?`${t.field} must use https`:`${t.field} must use http or https`}}import{load as C}from"cheerio";var _="script,style,noscript,svg,iframe,canvas,nav,header,footer,aside",k=4096;function d(n){return(n??"").replace(/\s+/g," ").trim()}function L(n){let t=n.replace(/[\x00-\x09\x0b\x0c\x0e-\x1f]/g," ").trim();if(!t)return null;try{return JSON.parse(t)}catch(e){let s=/at position (\d+)/.exec(e instanceof Error?e.message:"")?.[1];if(!s)return null;try{return JSON.parse(t.slice(0,Number(s)))}catch{return null}}}function g(n,t,e={value:2e3}){if(e.value--<=0||n==null)return;if(Array.isArray(n)){for(let l of n)g(l,t,e);return}if(typeof n!="object")return;let s=n,o=s["@type"];if(typeof o=="string"&&o&&t.add(o),Array.isArray(o))for(let l of o)typeof l=="string"&&l&&t.add(l);Array.isArray(s["@graph"])&&g(s["@graph"],t,e)}function H(n){let t=n("main").first();if(t.length)return t;let e=n("article").first();if(e.length)return e;let s=n("body").first();return s.length?s:n.root()}function w(n,t){let e=Number(n.attr(t)??0);return Number.isFinite(e)&&e>0?e:null}function W(n){let t=C(n),e={};t("meta").each((f,i)=>{let r=t(i),a=d(r.attr("name")??r.attr("property")).toLowerCase(),c=d(r.attr("content"));a&&c&&(e[a]=c)});let s=[];t("h1,h2,h3,h4,h5,h6").each((f,i)=>{let r=t(i),a=d(r.text());a&&s.push({level:Number(i.tagName.slice(1)),text:a})});let o=[],l=new Set;t('script[type="application/ld+json"]').each((f,i)=>{let r=L(t(i).text());r!=null&&(Array.isArray(r)?o.push(...r):o.push(r),g(r,l))});let m=new Set;t("[itemtype]").each((f,i)=>{let r=t(i).attr("itemtype")??"";for(let a of r.split(/\s+/))try{let c=new URL(a);if(c.hostname==="schema.org"||c.hostname==="www.schema.org"){let h=c.pathname.replace(/^\/+/,"");h&&m.add(h)}}catch{}});let u=H(t).clone();u.find(_).remove(),u.find("[href],[src],[srcset],[data-src],[data-srcset]").each((f,i)=>{let r=t(i);for(let a of["href","src","srcset","data-src","data-srcset"]){let c=r.attr(a);c&&c.length>k&&r.removeAttr(a)}}),u.find("img").each((f,i)=>{let r=t(i),a=r.attr("src");if(!a||a.startsWith("data:")){let c=r.attr("data-src")??r.attr("data-lazy-src")??r.attr("data-original");c&&r.attr("src",c)}});let A=u.html()??"",v=d(u.text()),y=[];t("a[href]").each((f,i)=>{let r=t(i),a=d(r.attr("href"));a&&y.push({href:a,text:d(r.text()),rel:d(r.attr("rel")).toLowerCase()||null})});let x=[];return t("img").each((f,i)=>{let r=t(i),a=Object.fromEntries(Object.entries(i.attribs??{}).map(([c,h])=>[c.toLowerCase(),h]));x.push({src:r.attr("src")??r.attr("data-src")??r.attr("data-lazy-src")??r.attr("data-original")??null,srcset:r.attr("srcset")??r.attr("data-srcset")??null,alt:r.attr("alt")??null,width:w(r,"width"),height:w(r,"height"),attributes:a})}),{$:t,sourceHtml:n,title:d(t("title").first().text())||null,meta:e,headings:s,schema:o,schemaTypes:[...l],microdataTypes:[...m],canonicalUrl:d(t('link[rel~="canonical"]').first().attr("href"))||null,mainHtml:A,mainText:v,bodyClass:t("body").first().attr("class")??"",links:y,images:x}}export{b as a,S as b,W as c};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash as B,randomUUID as N}from"crypto";import{mkdir as O,readFile as T,stat as v,writeFile as U}from"fs/promises";import{homedir as k}from"os";import{dirname as S,join as A}from"path";var d="connected-data-exports/",b=10080*60*1e3,R=900*1e3;function p(){return process.env.CONNECTED_DATA_READ_WRITE_TOKEN?.trim()||process.env.CONNECTED_DATA_BLOB_READ_WRITE_TOKEN?.trim()||null}function D(){return process.env.MCP_SCRAPER_OUTPUT_DIR?.trim()||A(k(),"Downloads","mcp-scraper")}function g(){return process.env.VERCEL==="1"||process.env.NODE_ENV==="production"}function x(t){return(t.toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"connected-data-export").slice(0,120)}function C(t){if(!t.startsWith(d))return null;let e=(t.split("/").at(-1)??"").match(/^(\d{13})-/);if(!e)return null;let r=Number(e[1]);return Number.isFinite(r)?r:null}function _(t){return t.startsWith(d)&&t.slice(d.length).split("/")[0]||null}function P(t){let n=C(t);return n===null?null:new Date(n+b)}function I(t,n=Date.now()){let e=C(t);return e===null||e+b<=n}async function h(t,n){let e=p();if(!e)return null;let r=Math.min(Date.now()+R,n.getTime());if(r<=Date.now())return null;let{issueSignedToken:a,presignUrl:i}=await import("@vercel/blob"),s=await a({token:e,pathname:t,operations:["get"],validUntil:r}),{presignedUrl:o}=await i(s,{access:"private",operation:"get",pathname:t,validUntil:r});return{url:o,expiresAt:new Date(r).toISOString()}}async function H(t){return L({...t,contentType:"application/x-ndjson"})}async function L(t){let n=t.stableCreatedAt?Date.parse(t.stableCreatedAt):Number.NaN,e=Number.isFinite(n)?n:Date.now(),r=x(t.filename),a=r.includes(".")?`.${r.split(".").at(-1)}`:".bin",i=t.stableKey?x(t.stableKey):N(),s=`${d}${t.ownerId}/${e}-${x(t.exportId)}-${i}--${r}`,o=(typeof t.content=="string",Buffer.from(t.content)),u=o.byteLength,c=B("sha256").update(o).digest("hex"),l=new Date(e+b),f=p(),m=s;if(f){let{put:w}=await import("@vercel/blob");m=(await w(s,o,{access:"private",token:f,contentType:t.contentType,addRandomSuffix:!t.stableKey,...t.stableKey?{allowOverwrite:!0}:{},cacheControlMaxAge:60,multipart:u>100*1024*1024})).pathname}else{if(g())throw new Error("connected_data_private_blob_not_configured");let w=A(D(),"blobs",s);await O(S(w),{recursive:!0}),await U(w,o)}let y=await h(m,l);return{artifactId:m,filename:r,contentType:t.contentType,bytes:u,sha256:c,createdAt:new Date(e).toISOString(),expiresAt:l.toISOString(),downloadUrl:y?.url??null,downloadUrlExpiresAt:y?.expiresAt??null,readback:{tool:"report_artifact_read",arguments:{artifactId:m,offset:0,maxBytes:2e4},continuation:"Repeat with offset set to the previous result nextOffset until nextOffset is null."}}}async function V(t){if(_(t.artifactId)!==t.ownerId)return null;let n=P(t.artifactId);if(!n||n.getTime()<=Date.now())return null;let e=await h(t.artifactId,n);return e?{downloadUrl:e.url,downloadUrlExpiresAt:e.expiresAt,expiresAt:n.toISOString()}:null}async function E(t,n=Number.POSITIVE_INFINITY){let e=t.getReader(),r=[],a=0;try{for(;;){let{done:i,value:s}=await e.read();if(i)break;if(s){let o=Buffer.from(s);if(a+=o.byteLength,a>n)return await e.cancel("artifact_too_large").catch(()=>{}),null;r.push(o)}}}finally{e.releaseLock()}return Buffer.concat(r)}async function j(t,n,e){if(I(t))return null;let r=p(),a;if(r){let{get:u}=await import("@vercel/blob"),c=await u(t,{access:"private",token:r,useCache:!1});if(!c||c.statusCode!==200)return null;let l=await E(c.stream);if(!l)return null;a=l}else{if(g())return null;try{a=await T(A(D(),"blobs",t))}catch{return null}}let i=a.length,s=Math.max(0,n),o=Math.min(i,s+e);return{text:a.subarray(s,o).toString("utf8"),totalBytes:i,nextOffset:o<i?o:null}}async function q(t){if(_(t.artifactId)!==t.ownerId||I(t.artifactId))return null;let n=p(),e;if(n){let{get:r}=await import("@vercel/blob"),a=await r(t.artifactId,{access:"private",token:n,useCache:!1});if(!a||a.statusCode!==200)return null;let i=await E(a.stream,t.maxBytes??25*1024*1024);if(!i)return null;e=i}else{if(g())return null;try{let r=A(D(),"blobs",t.artifactId);if((await v(r)).size>(t.maxBytes??25*1024*1024))return null;e=await T(r)}catch{return null}}return e.byteLength>(t.maxBytes??25*1024*1024)?null:e}async function z(t={}){let n=t.now??new Date,e=p();if(!e)return{deleted:0,store:g()?"none":"local"};if(!t.force&&!(n.getUTCHours()===3&&n.getUTCMinutes()===17))return{deleted:0,store:"private-vercel-blob",skipped:!0};let r=n.getTime()-b,{list:a,del:i}=await import("@vercel/blob"),s,o=0;for(let u=0;u<20;u++){let c=await a({prefix:d,token:e,limit:1e3,cursor:s}),l=c.blobs.filter(f=>new Date(f.uploadedAt).getTime()<=r);if(l.length>0&&(await i(l.map(f=>f.pathname),{token:e}),o+=l.length),!c.hasMore||!c.cursor)break;s=c.cursor}return{deleted:o,store:"private-vercel-blob"}}export{d as a,_ as b,H as c,L as d,V as e,j as f,q as g,z as h};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
function l(r){let t=[],e=[],n="",i=!1;for(let s=0;s<r.length;s+=1){let o=r[s],c=r[s+1];if(i){o==='"'&&c==='"'?(n+='"',s+=1):o==='"'?i=!1:n+=o;continue}o==='"'?i=!0:o===","?(e.push(n),n=""):o===`
|
|
2
|
+
`?(e.push(n),t.push(e),e=[],n=""):o!=="\r"&&(n+=o)}return(n.length>0||e.length>0)&&(e.push(n),t.push(e)),t}function u(r){let t=l(r).filter(n=>n.some(i=>i.trim()!=="")),e=t[0]?.map(n=>n.trim())??[];return t.slice(1).map(n=>{let i={};for(let s=0;s<e.length;s+=1)i[e[s]]=n[s]??"";return i})}function f(r){if(r==null)return"";let t=String(r);return/[",\n\r]/.test(t)?`"${t.replace(/"/g,'""')}"`:t}function g(r,t){return[r.join(","),...t.map(e=>r.map(n=>f(e[n])).join(","))].join(`
|
|
3
|
+
`)+`
|
|
4
|
+
`}export{l as a,u as b,g as c};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{Ab as R,Bb as E,Db as v,Lb as T,Nb as h,Ob as w,Pb as _,Qb as y,Rb as C,Va as g,Xa as S,w as u,x as f}from"./chunk-PUHFVA7P.js";import{a as P}from"./chunk-CCYWSJNG.js";import{a as m}from"./chunk-Z2QGQJS2.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
|
+
`).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
|
+
`),process.exit(1)),b(()=>Y(n,r),{legacy:"serve",onerror(l){process.stderr.write(`${l.message}
|
|
4
|
+
`)}})}export{se as a};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import{K as p,s as o}from"./chunk-GMWKPIYX.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
|
+
CREATE TABLE IF NOT EXISTS service_connections (
|
|
3
|
+
id TEXT PRIMARY KEY,
|
|
4
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
5
|
+
provider_config_key TEXT NOT NULL,
|
|
6
|
+
provider TEXT,
|
|
7
|
+
transport TEXT NOT NULL,
|
|
8
|
+
upstream_connection_id TEXT,
|
|
9
|
+
label TEXT,
|
|
10
|
+
user_label TEXT,
|
|
11
|
+
provider_account_id TEXT,
|
|
12
|
+
provider_account_email TEXT,
|
|
13
|
+
provider_account_name TEXT,
|
|
14
|
+
provider_identity_checked_at TEXT,
|
|
15
|
+
provider_identity_source_updated_at TEXT,
|
|
16
|
+
lifecycle_status TEXT NOT NULL DEFAULT 'pending',
|
|
17
|
+
operational_status TEXT NOT NULL DEFAULT 'unknown',
|
|
18
|
+
reconnect_required INTEGER NOT NULL DEFAULT 0,
|
|
19
|
+
actions_enabled INTEGER NOT NULL DEFAULT 0,
|
|
20
|
+
read_tools_json TEXT NOT NULL DEFAULT '[]',
|
|
21
|
+
action_tools_json TEXT NOT NULL DEFAULT '[]',
|
|
22
|
+
tool_revision TEXT,
|
|
23
|
+
last_checked_at TEXT,
|
|
24
|
+
last_successful_call_at TEXT,
|
|
25
|
+
last_failure_at TEXT,
|
|
26
|
+
last_failure_code TEXT,
|
|
27
|
+
last_failure_retryable INTEGER,
|
|
28
|
+
consecutive_failures INTEGER NOT NULL DEFAULT 0,
|
|
29
|
+
vault_name TEXT,
|
|
30
|
+
table_name TEXT,
|
|
31
|
+
legacy_owner_identity TEXT,
|
|
32
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
33
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
34
|
+
UNIQUE(user_id, provider_config_key, upstream_connection_id)
|
|
35
|
+
)
|
|
36
|
+
`);try{await t.execute("ALTER TABLE service_connections ADD COLUMN user_label TEXT")}catch{}try{await t.execute("ALTER TABLE service_connections ADD COLUMN provider_account_id TEXT")}catch{}try{await t.execute("ALTER TABLE service_connections ADD COLUMN provider_account_email TEXT")}catch{}try{await t.execute("ALTER TABLE service_connections ADD COLUMN provider_account_name TEXT")}catch{}try{await t.execute("ALTER TABLE service_connections ADD COLUMN provider_identity_checked_at TEXT")}catch{}try{await t.execute("ALTER TABLE service_connections ADD COLUMN provider_identity_source_updated_at TEXT")}catch{}await t.execute("CREATE INDEX IF NOT EXISTS service_connections_user_updated ON service_connections(user_id, updated_at DESC)"),await t.execute("CREATE INDEX IF NOT EXISTS service_connections_upstream ON service_connections(provider_config_key, upstream_connection_id)"),await t.execute(`
|
|
37
|
+
CREATE TABLE IF NOT EXISTS service_connection_health_events (
|
|
38
|
+
id TEXT PRIMARY KEY,
|
|
39
|
+
connection_id TEXT NOT NULL REFERENCES service_connections(id) ON DELETE CASCADE,
|
|
40
|
+
operational_status TEXT NOT NULL,
|
|
41
|
+
failure_code TEXT,
|
|
42
|
+
retryable INTEGER,
|
|
43
|
+
evidence_source TEXT NOT NULL,
|
|
44
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
45
|
+
)
|
|
46
|
+
`),await t.execute("CREATE INDEX IF NOT EXISTS service_connection_health_events_connection ON service_connection_health_events(connection_id, created_at DESC)"),await t.execute(`
|
|
47
|
+
CREATE TABLE IF NOT EXISTS service_connection_action_audit (
|
|
48
|
+
id TEXT PRIMARY KEY,
|
|
49
|
+
connection_id TEXT NOT NULL REFERENCES service_connections(id) ON DELETE CASCADE,
|
|
50
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
51
|
+
tool TEXT NOT NULL,
|
|
52
|
+
request_id TEXT NOT NULL,
|
|
53
|
+
status TEXT NOT NULL,
|
|
54
|
+
error_code TEXT,
|
|
55
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
56
|
+
UNIQUE(user_id, request_id)
|
|
57
|
+
)
|
|
58
|
+
`);try{await t.execute("ALTER TABLE service_connection_action_audit ADD COLUMN request_digest TEXT")}catch{}try{await t.execute("ALTER TABLE service_connection_action_audit ADD COLUMN result_json TEXT")}catch{}})().catch(t=>{throw a=null,u=null,t})),a}function f(e){if(typeof e!="string")return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(n=>typeof n=="string"):[]}catch{return[]}}function g(e){return{id:String(e.id),userId:Number(e.user_id),providerConfigKey:String(e.provider_config_key),provider:typeof e.provider=="string"?e.provider:null,transport:e.transport==="remote_mcp"?"remote_mcp":e.transport==="credential_reference"?"credential_reference":"nango",upstreamConnectionId:typeof e.upstream_connection_id=="string"?e.upstream_connection_id:null,label:typeof e.label=="string"?e.label:null,userLabel:typeof e.user_label=="string"?e.user_label:null,providerAccountId:typeof e.provider_account_id=="string"?e.provider_account_id:null,providerAccountEmail:typeof e.provider_account_email=="string"?e.provider_account_email:null,providerAccountName:typeof e.provider_account_name=="string"?e.provider_account_name:null,providerIdentityCheckedAt:typeof e.provider_identity_checked_at=="string"?e.provider_identity_checked_at:null,providerIdentitySourceUpdatedAt:typeof e.provider_identity_source_updated_at=="string"?e.provider_identity_source_updated_at:null,lifecycleStatus:String(e.lifecycle_status),operationalStatus:String(e.operational_status),reconnectRequired:Number(e.reconnect_required)===1,actionsEnabled:Number(e.actions_enabled)===1,readTools:f(e.read_tools_json),actionTools:f(e.action_tools_json),toolRevision:typeof e.tool_revision=="string"?e.tool_revision:null,lastCheckedAt:typeof e.last_checked_at=="string"?e.last_checked_at:null,lastSuccessfulCallAt:typeof e.last_successful_call_at=="string"?e.last_successful_call_at:null,lastFailureAt:typeof e.last_failure_at=="string"?e.last_failure_at:null,lastFailureCode:typeof e.last_failure_code=="string"?e.last_failure_code:null,lastFailureRetryable:e.last_failure_retryable===null||e.last_failure_retryable===void 0?null:Number(e.last_failure_retryable)===1,consecutiveFailures:Number(e.consecutive_failures??0),vaultName:typeof e.vault_name=="string"?e.vault_name:null,tableName:typeof e.table_name=="string"?e.table_name:null,createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}async function E(e){let t=await p(e.normalize("NFKC").trim().toLowerCase());if(!t)throw new Error("service_connection_user_not_found");return Number(t.id)}async function D(e,t){await c();let n=o(),r=await E(e);for(let i of t)await n.execute({sql:`
|
|
59
|
+
INSERT INTO service_connections (
|
|
60
|
+
id, user_id, provider_config_key, provider, transport, upstream_connection_id,
|
|
61
|
+
label, lifecycle_status, reconnect_required, actions_enabled, legacy_owner_identity, created_at, updated_at
|
|
62
|
+
) VALUES (?, ?, ?, ?, 'nango', ?, ?, ?, ?, 1, ?, COALESCE(?, datetime('now')), COALESCE(?, datetime('now')))
|
|
63
|
+
ON CONFLICT(user_id, provider_config_key, upstream_connection_id) DO UPDATE SET
|
|
64
|
+
provider = excluded.provider,
|
|
65
|
+
label = COALESCE(excluded.label, service_connections.label),
|
|
66
|
+
lifecycle_status = excluded.lifecycle_status,
|
|
67
|
+
reconnect_required = excluded.reconnect_required,
|
|
68
|
+
updated_at = excluded.updated_at
|
|
69
|
+
`,args:[_(),r,i.providerConfigKey,i.provider,i.upstreamConnectionId,i.label,i.lifecycleStatus,i.reconnectRequired?1:0,e,i.createdAt,i.updatedAt]});return A(e,"nango")}async function A(e,t){await c();let n=await E(e);return(await o().execute({sql:`SELECT * FROM service_connections WHERE user_id = ?${t?" AND transport = ?":""} AND lifecycle_status <> 'disconnected' ORDER BY updated_at DESC`,args:t?[n,t]:[n]})).rows.map(i=>g(i))}async function d(e,t){await c();let n=await E(e),i=(await o().execute({sql:"SELECT * FROM service_connections WHERE id = ? AND user_id = ? LIMIT 1",args:[t,n]})).rows[0];return i?g(i):null}async function w(e,t,n,r){await c(),await o().execute({sql:"UPDATE service_connections SET read_tools_json = ?, action_tools_json = ?, tool_revision = ?, updated_at = datetime('now') WHERE id = ?",args:[JSON.stringify(t),JSON.stringify(n),r,e]})}async function U(e){await c(),await o().execute({sql:`
|
|
70
|
+
UPDATE service_connections SET
|
|
71
|
+
provider_account_id = ?, provider_account_email = ?, provider_account_name = ?,
|
|
72
|
+
provider_identity_checked_at = datetime('now'), provider_identity_source_updated_at = ?,
|
|
73
|
+
updated_at = datetime('now')
|
|
74
|
+
WHERE id = ?
|
|
75
|
+
`,args:[e.providerAccountId??null,e.providerAccountEmail?.toLowerCase()??null,e.providerAccountName??null,e.sourceUpdatedAt,e.connectionId]})}async function h(e,t,n){let r=await d(e,t);if(!r||r.lifecycleStatus==="disconnected")throw new Error("service_connection_not_found");return await o().execute({sql:"UPDATE service_connections SET user_label = ?, updated_at = datetime('now') WHERE id = ? AND user_id = ?",args:[n,t,r.userId]}),n}async function X(e){await c();let t=new Date().toISOString();await o().execute({sql:`
|
|
76
|
+
UPDATE service_connections SET
|
|
77
|
+
operational_status = ?, last_checked_at = ?,
|
|
78
|
+
last_successful_call_at = CASE WHEN ? = 'available' THEN ? ELSE last_successful_call_at END,
|
|
79
|
+
last_failure_at = CASE WHEN ? IN ('degraded', 'unavailable') THEN ? ELSE NULL END,
|
|
80
|
+
last_failure_code = ?, last_failure_retryable = ?,
|
|
81
|
+
consecutive_failures = CASE WHEN ? = 'available' THEN 0 ELSE consecutive_failures + 1 END,
|
|
82
|
+
updated_at = datetime('now')
|
|
83
|
+
WHERE id = ?
|
|
84
|
+
`,args:[e.operationalStatus,t,e.operationalStatus,t,e.operationalStatus,t,e.failureCode??null,e.retryable==null?null:e.retryable?1:0,e.operationalStatus,e.connectionId]}),await o().execute({sql:"INSERT INTO service_connection_health_events (id, connection_id, operational_status, failure_code, retryable, evidence_source) VALUES (?, ?, ?, ?, ?, ?)",args:[_(),e.connectionId,e.operationalStatus,e.failureCode??null,e.retryable==null?null:e.retryable?1:0,e.evidenceSource]})}async function q(e,t,n){let r=await d(e,t);if(!r||r.lifecycleStatus==="disconnected")throw new Error("service_connection_not_found");return await o().execute({sql:"UPDATE service_connections SET actions_enabled = ?, updated_at = datetime('now') WHERE id = ? AND user_id = ?",args:[n?1:0,t,r.userId]}),n}async function k(e,t){let n=await d(e,t);if(!n)throw new Error("service_connection_not_found");await o().execute({sql:"UPDATE service_connections SET lifecycle_status = 'disconnected', operational_status = 'unknown', reconnect_required = 0, updated_at = datetime('now') WHERE id = ? AND user_id = ?",args:[t,n.userId]});let r=await o().execute({sql:"SELECT COUNT(*) AS count FROM service_connections WHERE user_id = ? AND transport = 'nango' AND lifecycle_status = 'connected'",args:[n.userId]});return Number(r.rows[0]?.count??0)}async function F(e){await c();let t=await d(e.identity,e.connectionId);if(!t)throw new Error("service_connection_not_found");await o().execute({sql:"UPDATE service_connection_action_audit SET status = ?, error_code = ?, result_json = ? WHERE user_id = ? AND request_id = ? AND connection_id = ?",args:[e.status,e.errorCode??null,e.result===void 0?null:JSON.stringify(e.result),t.userId,e.requestId,t.id]})}async function P(e){await c();let t=await d(e.identity,e.connectionId);if(!t)throw new Error("service_connection_not_found");let n=await o().execute({sql:"INSERT OR IGNORE INTO service_connection_action_audit (id, connection_id, user_id, tool, request_id, status, request_digest) VALUES (?, ?, ?, ?, ?, 'started', ?)",args:[_(),t.id,t.userId,e.tool,e.requestId,e.requestDigest]});if(Number(n.rowsAffected??0)===1)return{claimed:!0};let i=(await o().execute({sql:"SELECT connection_id, tool, status, error_code, request_digest, result_json FROM service_connection_action_audit WHERE user_id = ? AND request_id = ? LIMIT 1",args:[t.userId,e.requestId]})).rows[0],s=String(i?.connection_id??"")!==t.id||String(i?.tool??"")!==e.tool||String(i?.request_digest??"")!==e.requestDigest,l;if(!s&&typeof i?.result_json=="string")try{l=JSON.parse(i.result_json)}catch{l=void 0}return{claimed:!1,status:String(i?.status??"unknown"),errorCode:typeof i?.error_code=="string"?i.error_code:null,conflict:s,...l!==void 0?{result:l}:{}}}export{S as a,L as b,I as c,x as d,c as e,D as f,A as g,d as h,w as i,U as j,h as k,X as l,q as m,k as n,F as o,P as p};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import{s as _}from"./chunk-GMWKPIYX.js";import{AsyncLocalStorage as N}from"async_hooks";var C="MCP_SCRAPER_ALLOW_HEADLESS_HARVEST_TEST",d=new N;function D(e,t){return d.run(e,t)}function l(){return d.getStore()}import{randomUUID as T}from"crypto";var p=166667e-10,L=.0001333336,h=new Set(["serp","fb_search","fb_ad","instagram"]),A=.00111,R=4,g=4e-4;function n(e,t){let r=process.env[e]?.trim();if(!r)return t;let o=Number(r);return Number.isFinite(o)&&o>=0?o:t}var m=n("NANGO_USD_PER_CONNECTION_MONTH",1),U=n("NANGO_USD_PER_FUNCTION_RUN",1e-4),O=n("NANGO_USD_PER_PROXY_REQUEST",1e-4),S=n("NANGO_USD_PER_COMPUTE_SEC",2e-4),b=n("\u0042\u0052\u0049\u0047\u0048\u0054\u0044\u0041\u0054\u0041_BROWSER_USD_PER_GB",8);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)*O:e==="nango_compute"?Math.max(0,t)*S:e==="\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061_browser_api"?Math.max(0,t)/1e9*b:0}var E=!1,s=null;async function c(){if(!E)return s||(s=x().finally(()=>{s=null}),s)}async function x(){let e=_(),t=await e.execute(`
|
|
2
|
+
SELECT
|
|
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
|
+
AND (SELECT COUNT(*) FROM pragma_table_info('\u006b\u0065\u0072\u006e\u0065\u006c_session_log') WHERE name IN ('proxy_source', 'proxy_type', 'method')) = 3
|
|
5
|
+
AND (SELECT COUNT(*) FROM pragma_table_info('vendor_usage_log') WHERE name IN ('method', 'source_key', 'provider_duration_ms', 'provider_captcha', 'provider_status')) = 5
|
|
6
|
+
AND (SELECT COUNT(*) FROM sqlite_master WHERE type = 'index' AND name = 'vendor_usage_log_vendor_source_key') = 1
|
|
7
|
+
AND (SELECT COUNT(*) FROM pragma_table_info('cost_probe_runs') WHERE name IN ('units', 'unit_type', 'mode')) = 3
|
|
8
|
+
AS ready
|
|
9
|
+
`);if(Number(t.rows[0]?.ready??0)===1){E=!0;return}await e.execute(`
|
|
10
|
+
CREATE TABLE IF NOT EXISTS \u006b\u0065\u0072\u006e\u0065\u006c_session_log (
|
|
11
|
+
id TEXT PRIMARY KEY,
|
|
12
|
+
\u006b\u0065\u0072\u006e\u0065\u006c_session_id TEXT,
|
|
13
|
+
op TEXT,
|
|
14
|
+
source TEXT NOT NULL,
|
|
15
|
+
probe_run_id TEXT,
|
|
16
|
+
user_id INTEGER,
|
|
17
|
+
stealth INTEGER,
|
|
18
|
+
headless_sent INTEGER,
|
|
19
|
+
proxy_used INTEGER,
|
|
20
|
+
fallback INTEGER NOT NULL DEFAULT 0,
|
|
21
|
+
opened_at TEXT,
|
|
22
|
+
closed_at TEXT,
|
|
23
|
+
duration_ms INTEGER NOT NULL DEFAULT 0,
|
|
24
|
+
est_cost_usd_headless REAL NOT NULL DEFAULT 0,
|
|
25
|
+
est_cost_usd_headful REAL NOT NULL DEFAULT 0,
|
|
26
|
+
error TEXT,
|
|
27
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
28
|
+
)
|
|
29
|
+
`),await e.execute("CREATE INDEX IF NOT EXISTS \u006b\u0065\u0072\u006e\u0065\u006c_session_log_op ON \u006b\u0065\u0072\u006e\u0065\u006c_session_log(op)"),await e.execute("CREATE INDEX IF NOT EXISTS \u006b\u0065\u0072\u006e\u0065\u006c_session_log_probe ON \u006b\u0065\u0072\u006e\u0065\u006c_session_log(probe_run_id)"),await e.execute("CREATE INDEX IF NOT EXISTS \u006b\u0065\u0072\u006e\u0065\u006c_session_log_created ON \u006b\u0065\u0072\u006e\u0065\u006c_session_log(created_at)");try{await e.execute("ALTER TABLE \u006b\u0065\u0072\u006e\u0065\u006c_session_log ADD COLUMN proxy_source TEXT")}catch{}try{await e.execute("ALTER TABLE \u006b\u0065\u0072\u006e\u0065\u006c_session_log ADD COLUMN proxy_type TEXT")}catch{}try{await e.execute("ALTER TABLE \u006b\u0065\u0072\u006e\u0065\u006c_session_log ADD COLUMN method TEXT")}catch{}await e.execute(`
|
|
30
|
+
CREATE TABLE IF NOT EXISTS vendor_usage_log (
|
|
31
|
+
id TEXT PRIMARY KEY,
|
|
32
|
+
op TEXT,
|
|
33
|
+
probe_run_id TEXT,
|
|
34
|
+
user_id INTEGER,
|
|
35
|
+
vendor TEXT NOT NULL,
|
|
36
|
+
model TEXT,
|
|
37
|
+
units REAL NOT NULL DEFAULT 0,
|
|
38
|
+
unit_type TEXT,
|
|
39
|
+
est_cost_usd REAL NOT NULL DEFAULT 0,
|
|
40
|
+
error TEXT,
|
|
41
|
+
source_key TEXT,
|
|
42
|
+
provider_duration_ms INTEGER,
|
|
43
|
+
provider_captcha INTEGER,
|
|
44
|
+
provider_status TEXT,
|
|
45
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
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(`
|
|
48
|
+
CREATE TABLE IF NOT EXISTS cost_probe_runs (
|
|
49
|
+
id TEXT PRIMARY KEY,
|
|
50
|
+
tool TEXT NOT NULL,
|
|
51
|
+
target TEXT,
|
|
52
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
53
|
+
wall_ms INTEGER NOT NULL DEFAULT 0,
|
|
54
|
+
success INTEGER NOT NULL DEFAULT 0,
|
|
55
|
+
error TEXT,
|
|
56
|
+
http_only INTEGER NOT NULL DEFAULT 0,
|
|
57
|
+
\u006b\u0065\u0072\u006e\u0065\u006c_used INTEGER NOT NULL DEFAULT 0,
|
|
58
|
+
\u006b\u0065\u0072\u006e\u0065\u006c_sessions INTEGER NOT NULL DEFAULT 0,
|
|
59
|
+
\u006b\u0065\u0072\u006e\u0065\u006c_seconds_total REAL NOT NULL DEFAULT 0,
|
|
60
|
+
\u006b\u0065\u0072\u006e\u0065\u006c_tier_observed TEXT,
|
|
61
|
+
est_\u006b\u0065\u0072\u006e\u0065\u006c_cost_usd_headless REAL NOT NULL DEFAULT 0,
|
|
62
|
+
est_\u006b\u0065\u0072\u006e\u0065\u006c_cost_usd_headful REAL NOT NULL DEFAULT 0,
|
|
63
|
+
vendor_cost_usd REAL NOT NULL DEFAULT 0,
|
|
64
|
+
charged_credits REAL NOT NULL DEFAULT 0,
|
|
65
|
+
margin_usd_headless_starter REAL NOT NULL DEFAULT 0,
|
|
66
|
+
margin_usd_headful_starter REAL NOT NULL DEFAULT 0,
|
|
67
|
+
notes TEXT
|
|
68
|
+
)
|
|
69
|
+
`),await e.execute("CREATE INDEX IF NOT EXISTS cost_probe_runs_tool ON cost_probe_runs(tool)");try{await e.execute("ALTER TABLE cost_probe_runs ADD COLUMN units REAL")}catch{}try{await e.execute("ALTER TABLE cost_probe_runs ADD COLUMN unit_type TEXT")}catch{}try{await e.execute("ALTER TABLE cost_probe_runs ADD COLUMN mode TEXT")}catch{}E=!0}async function w(e){try{await c();let t=l(),r=Math.max(0,e.closedAtMs-e.openedAtMs);await _().execute({sql:`INSERT INTO \u006b\u0065\u0072\u006e\u0065\u006c_session_log
|
|
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
|
+
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 F(e){try{await c();let t=l();return(await _().execute({sql:`INSERT OR IGNORE INTO vendor_usage_log
|
|
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,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{C as a,D as b,l as c,h as d,i as e,c as f,w as g,F as h};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var p={schemaVersion:1,ratePolicy:{version:"serp-paa-2026-08-11",effectiveDate:"2026-08-11T00:00:00.000Z"},costEvidence:{id:"serp-paa-rate-basis-2026-08",status:"provisional",minimumRevenueCostRatio:2.5,observedRevenueCostRatio:2.5160607750756583},operationCosts:{serp:{credits:60,unit:"per search",label:"SERP search",notes:"Returns organic results and Google entity IDs by default; optional same-page local pack, forums, videos, AI surfaces, and What People Are Saying are enabled with flags at the same product price. search_serp and the base capture_serp_snapshot search are billed 60 credits per search. Optional SERP Intelligence page snapshots add 1 credit per attempted URL."},paa:{credits:10,unit:"per question (+400 credit base)",label:"PAA harvest",notes:"Returns original-query PAA questions with answers and sources plus organic results and Google entity IDs. Optional same-page SERP modules are flag-controlled. Billed 400 credit base + 10 per question actually returned (unused estimate refunded)."},page_scrape:{credits:1,unit:"per page",label:"Page crawl / extract",notes:"Applies to both single-URL extraction and per-page site crawls."},listing_create:{credits:10,unit:"per new listing",label:"Directory or wiki listing creation",notes:"Fixed total price for a new Local Sourcebook directory listing or Transparent Commons wiki entity. Sourcebook acquisition is included."},listing_edit:{credits:2,unit:"per existing listing revision",label:"Directory or wiki listing edit",notes:"Fixed total price for refreshing an existing Local Sourcebook listing or revising an existing Transparent Commons entity."},url_map:{credits:5,unit:"per mapping operation",label:"Site URL mapping",notes:"Flat rate for the full /map-urls call regardless of URL count discovered."},yt_channel:{credits:2,unit:"per call",label:"YouTube search / channel harvest"},yt_transcription:{credits:200,unit:"base + 2/min of video",label:"YouTube transcription",notes:"Flat 200-credit base plus 2 credits per minute of video, reconciled to the real video length after transcription (e.g. a 10-minute video is about 220 credits)."},fb_ad:{credits:7,unit:"per call",label:"Facebook search / ad lookup"},maps_search:{credits:5,unit:"per search",label:"Maps business search",notes:"Returns up to 50 Google Maps business/profile candidates. Use maps_place_intel to hydrate selected businesses."},maps_place:{credits:60,unit:"per business",label:"Maps business lookup",notes:"Base lookup. Reviews billed separately per card at maps_review rate."},maps_review:{credits:1,unit:"per review card",label:"Maps review",notes:"Charged after extraction when includeReviews is true."},fb_search:{credits:8,unit:"per search",label:"Facebook ad library search",notes:"Browser automation to search Facebook Ads Library by keyword."},google_ads_search:{credits:6,unit:"per search",label:"Google Ads Transparency search",notes:"Browser automation to find advertisers in Google Ads Transparency Center by domain or name."},google_ads_intel:{credits:2,unit:"per call",label:"Google Ads Transparency advertiser intel",notes:"Lists and hydrates an advertiser's creatives with image URLs and video references."},google_ads_transcribe:{credits:200,unit:"base + 2/min of video",label:"Google ad video transcription",notes:"Flat 200-credit base plus 2 credits per minute of video, reconciled to the real video length after transcription (e.g. a 10-minute video is about 220 credits)."},fb_transcribe:{credits:200,unit:"base + 2/min of video",label:"Facebook video / ad transcription",notes:"Flat 200-credit base plus 2 credits per minute of video, reconciled to the real video length after transcription (e.g. a 10-minute video is about 220 credits)."},fb_reels_inventory:{credits:4,unit:"per profile scan",label:"Facebook Reel URL inventory",notes:"Collects canonical Reel URLs from a Facebook profile. Logged-out scans are capped at 60 URLs; saved browser profiles can request larger inventories."},instagram_profile:{credits:4,unit:"per profile scan",label:"Instagram profile content discovery",notes:"Browser extraction of public Instagram profile grid links. Complete history may require a logged-in profile."},instagram_media:{credits:4,unit:"per post or reel",label:"Instagram media download",notes:"Extracts post text, image URLs, and reel audio/video tracks, with local downloads when the server can write files."},instagram_transcribe:{credits:200,unit:"base + 2/min of video",label:"Instagram media transcription",notes:"Whisper transcription of selected Instagram audio/video media. Flat 200-credit base plus 2 credits per minute of video, reconciled to the real video length after transcription (e.g. a 10-minute video is about 220 credits)."},browser_minute:{credits:120,unit:"per minute of use",label:"Interactive browser session",notes:"Metered per minute of use for the whole time the browser session is open. Close the session to stop the meter; abandoned sessions are auto-closed after a short idle window."},reddit_thread:{credits:30,unit:"per thread",label:"Reddit thread base lookup",notes:"Base lookup for the post itself. Comments billed separately per comment at reddit_comment rate. Refunded if the thread cannot be retrieved."},reddit_comment:{credits:2,unit:"per comment",label:"Reddit comment",notes:"Charged per comment actually extracted, billed down automatically if the balance runs out mid-thread."},video_analysis:{credits:6667,unit:"per 120 frames (max 480)",label:"Video breakdown (frame-by-frame + transcript)",notes:"Full multi-lens video breakdown: samples frames across a video (up to 30 minutes), analyzes each with vision AI, transcribes the audio, then produces summary, pacing/energy, words-per-minute, topic outline, key points, hook analysis, visual style, and a how-to-replicate recipe with a quality-control pass. $1 per 120 frames requested (max 480 = $4); billed down automatically if the video cannot use the requested frames, and refunded fully if the run fails."},trustpilot_reviews:{credits:5,unit:"per call",label:"Trustpilot review harvest",notes:"Base lookup. Reviews billed separately per card at trustpilot_review rate. Refunded if no reviews are found."},trustpilot_review:{credits:1,unit:"per review card",label:"Trustpilot review card",notes:"Charged per review actually extracted, billed down automatically if the balance runs out mid-page."},g2_reviews:{credits:5,unit:"per call",label:"G2 review harvest",notes:"Base lookup. Reviews billed separately per card at g2_review rate. Refunded if no reviews are found."},g2_review:{credits:2,unit:"per review card",label:"G2 review card",notes:"Charged per review actually extracted (each card carries up to 3 Q&A sections), billed down automatically if the balance runs out mid-page."},diff_page:{credits:1,unit:"per check",label:"Page change check",notes:"Same cost as a single page extract \u2014 one scrape is performed per check, then compared against your last stored snapshot for that URL."}},publicTiers:[{tier:"starter",label:"Starter",monthlyUsd:12,credits:8e4,concurrency:3},{tier:"growth",label:"Growth",monthlyUsd:40,credits:266667,concurrency:10},{tier:"scale",label:"Scale",monthlyUsd:100,credits:8e5,concurrency:20}],credits:{mcPerCredit:100,freeSignupCredits:0},inventory:{totalTools:376,scraperTools:250,memoryTools:126},concurrencyPack:{ratePolicyVersion:"2026-08-14.concurrency-pack-v1",monthlyUsd:5,currency:"usd",interval:"month",billingUnit:"pack",slotsPerPack:2},addons:{memory:{monthlyUsd:19,quotaGb:5,freeQuotaGb:.01},scheduling:{billingMode:"credits",entitlement:"paid_plan_included",separateSubscriptionRequired:!1,chargeEvent:"started_occurrence",runBaseCredits:75,runBaseMc:7500,llmCostMultiplier:1.5,llmCostMultiplierBps:15e3,modes:{connection_sync:{runBaseCredits:75,modelCostBilling:"none",modelCostMultiplier:0},agent:{runBaseCredits:75,modelCostBilling:"actual_reported_cost",modelCostMultiplier:1.5,modelCostMultiplierBps:15e3}}},connectedAccounts:{schemaVersion:2,ratePolicyVersion:"2026-08-03.connected-usage-v3",effectiveAt:"2026-08-03T00:00:00.000Z",entitlement:"paid_plan_add_on",connection:{billingMode:"flat_recurring_credits",amountCredits:15e3,interval:"month",unit:"active_connection",proration:"none"},usage:{billingMode:"credits",settlementMode:"authoritative_receipt",rounding:"aggregate_then_ceil_to_mc",functionRun:{credits:2,mc:200,unit:"per_function_run"},proxyRequest:{credits:2,mc:200,unit:"per_proxy_request"},compute:{creditsPerSecond:5,mcPerSecond:500,sourceUnit:"millisecond",unit:"per_compute_second",formula:"ceil(computeMilliseconds * mcPerSecond / 1000)"}}}}};var t={serp:6e3,serp_headless:6e3,serp_headful:6e3,paa:1e3,paa_base:4e4,page_scrape:100,url_map:500,yt_channel:200,yt_transcription:200,fb_ad:700,maps_search:500,maps_place:6e3,maps_review:100,fb_search:800,fb_search_result:100,fb_page_intel:700,fb_page_intel_ad:50,fb_reels_inventory:400,fb_transcribe:33300,google_ads_search:600,google_ads_intel:200,google_ads_transcribe:33300,instagram_profile:400,instagram_media:400,instagram_transcribe:33300,browser_minute:12e3,reddit_thread:3e3,reddit_comment:200,video_analysis:666700,trustpilot_reviews:500,trustpilot_review:100,g2_reviews:500,g2_review:200,diff_page:100,listing_create:1e3,listing_edit:200};function re(e){return e===!0?t.serp_headless:t.serp_headful}var B=t.browser_minute/6e4;function te(e){return Math.round(e*B)}var ie=1e3,o=100,ne=t.serp_headful/o,se=t.paa_base/o,ae=t.paa/o,oe=t.page_scrape/o,F={billingMode:"credits",chargeEvent:"accepted_write",validationCredits:0,create:{credits:t.listing_create/o,mc:t.listing_create},edit:{credits:t.listing_edit/o,mc:t.listing_edit},surfaces:["local_sourcebook","transparent_commons"],sourcebookAcquisitionIncluded:!0},G=2e6,Y=3,C=1e4,E=1e9,q=75,ce=q*o,V=15e3,le=V/C,_e=5e3,H="2026-08-03.connected-usage-v3",y=15e3,de=y*o,T=2,v=2,S=5,A=T*o,N=v*o,I=S*o,ue={schemaVersion:2,ratePolicyVersion:H,effectiveAt:"2026-08-03T00:00:00.000Z",provider:"nango",entitlement:"paid_plan_add_on",connection:{billingMode:"flat_recurring_credits",amountCredits:y,interval:"month",unit:"active_connection",proration:"none"},usage:{billingMode:"credits",settlementMode:"authoritative_receipt",rounding:"aggregate_then_ceil_to_mc",functionRun:{credits:T,mc:A,unit:"per_function_run"},proxyRequest:{credits:v,mc:N,unit:"per_proxy_request"},compute:{creditsPerSecond:S,mcPerSecond:I,sourceUnit:"millisecond",unit:"per_compute_second",formula:"ceil(computeMilliseconds * mcPerSecond / 1000)"}}};function m(e,r){if(!Number.isSafeInteger(e)||e<0)throw new Error(`${r} must be a non-negative safe integer`);return BigInt(e)}function _(e){if(e>BigInt(Number.MAX_SAFE_INTEGER))throw new Error("connected usage charge exceeds the safe integer range");return Number(e)}function pe(e){let r=m(e.functionRuns,"functionRuns"),a=m(e.proxyRequests,"proxyRequests"),s=m(e.computeMilliseconds,"computeMilliseconds"),n=r*BigInt(A),c=a*BigInt(N),l=s*BigInt(I),u=l===0n?0n:(l+999n)/1000n,R=n+c+u;return{functionRunMc:_(n),proxyRequestMc:_(c),computeMc:_(u),amountMc:_(R),credits:_(R)/o}}function me(e,r){if(!Number.isFinite(e)||e<0)throw new Error("costUsd must be a finite non-negative number");if(!Number.isInteger(r)||r<0)throw new Error("markupBps must be a non-negative integer");let s=BigInt(Math.round(e*E))*BigInt(r)*BigInt(G),n=BigInt(E)*BigInt(C)*BigInt(Y),c=s===0n?0n:(s+n-1n)/n;if(c>BigInt(Number.MAX_SAFE_INTEGER))throw new Error("calculated mc exceeds the safe integer range");return Number(c)}var W=[{key:"serp",label:"SERP search",aliases:["search_serp","serp","google search","organic results"],credits:i(t.serp_headful),unit:"per search",notes:`Returns organic results and Google entity IDs by default; optional same-page local pack, forums, videos, AI surfaces, and What People Are Saying are enabled with flags at the same product price. search_serp and the base capture_serp_snapshot search are billed ${i(t.serp_headful)} credits per search. Optional SERP Intelligence page snapshots add ${i(t.page_scrape)} credit per attempted URL.`},{key:"paa",label:"PAA harvest",aliases:["harvest_paa","paa","people also ask","questions"],credits:i(t.paa),unit:`per question (+${i(t.paa_base)} credit base)`,notes:`Returns original-query PAA questions with answers and sources plus organic results and Google entity IDs. Optional same-page SERP modules are flag-controlled. Billed ${i(t.paa_base)} credit base + ${i(t.paa)} per question actually returned (unused estimate refunded).`},{key:"page_scrape",label:"Page crawl / extract",aliases:["extract_url","extract_site","page scrape","url scrape","single page","site crawl"],credits:i(t.page_scrape),unit:"per page",notes:"Applies to both single-URL extraction and per-page site crawls."},{key:"listing_create",label:"Directory or wiki listing creation",aliases:["local-sourcebook-capture","commons_submit_entity","directory listing","wiki listing"],credits:i(t.listing_create),unit:"per new listing",notes:"Fixed total price for a new Local Sourcebook directory listing or Transparent Commons wiki entity. Sourcebook acquisition is included."},{key:"listing_edit",label:"Directory or wiki listing edit",aliases:["local_sourcebook_refresh","commons_submit_entity","listing refresh","wiki edit"],credits:i(t.listing_edit),unit:"per existing listing revision",notes:"Fixed total price for refreshing an existing Local Sourcebook listing or revising an existing Transparent Commons entity."},{key:"url_map",label:"Site URL mapping",aliases:["map_site_urls","url map","site map","crawl urls"],credits:i(t.url_map),unit:"per mapping operation",notes:"Flat rate for the full /map-urls call regardless of URL count discovered."},{key:"yt_channel",label:"YouTube search / channel harvest",aliases:["youtube_harvest","youtube search","youtube channel","yt_channel"],credits:i(t.yt_channel),unit:"per call"},{key:"yt_transcription",label:"YouTube transcription",aliases:["youtube_transcribe","youtube transcript","transcription","yt_transcription"],credits:i(2e4),unit:"base + 2/min of video",notes:"Flat 200-credit base plus 2 credits per minute of video, reconciled to the real video length after transcription (e.g. a 10-minute video is about 220 credits)."},{key:"fb_ad",label:"Facebook search / ad lookup",aliases:["facebook_page_intel","facebook_ad_search","facebook_ad","facebook ads","fb ads"],credits:i(t.fb_ad),unit:"per call"},{key:"maps_search",label:"Maps business search",aliases:["maps_search","google maps search","gmb search","gbp search","business profiles"],credits:i(t.maps_search),unit:"per search",notes:"Returns up to 50 Google Maps business/profile candidates. Use maps_place_intel to hydrate selected businesses."},{key:"maps_place",label:"Maps business lookup",aliases:["maps_place_intel","google maps","maps place","place intel"],credits:i(t.maps_place),unit:"per business",notes:"Base lookup. Reviews billed separately per card at maps_review rate."},{key:"maps_review",label:"Maps review",aliases:["maps_reviews","google reviews","review cards","reviews"],credits:i(t.maps_review),unit:"per review card",notes:"Charged after extraction when includeReviews is true."},{key:"fb_search",label:"Facebook ad library search",aliases:["facebook_search","fb_search","fb ad search"],credits:i(t.fb_search),unit:"per search",notes:"Browser automation to search Facebook Ads Library by keyword."},{key:"google_ads_search",label:"Google Ads Transparency search",aliases:["google_ads_search","google ads search","ads transparency search"],credits:i(t.google_ads_search),unit:"per search",notes:"Browser automation to find advertisers in Google Ads Transparency Center by domain or name."},{key:"google_ads_intel",label:"Google Ads Transparency advertiser intel",aliases:["google_ads_page_intel","google ads intel","ads transparency intel"],credits:i(t.google_ads_intel),unit:"per call",notes:"Lists and hydrates an advertiser's creatives with image URLs and video references."},{key:"google_ads_transcribe",label:"Google ad video transcription",aliases:["google_ads_transcribe","google ad transcript"],credits:i(2e4),unit:"base + 2/min of video",notes:"Flat 200-credit base plus 2 credits per minute of video, reconciled to the real video length after transcription (e.g. a 10-minute video is about 220 credits)."},{key:"fb_transcribe",label:"Facebook video / ad transcription",aliases:["facebook_transcribe","facebook_video_transcribe","fb_transcribe","fb ad transcript"],credits:i(2e4),unit:"base + 2/min of video",notes:"Flat 200-credit base plus 2 credits per minute of video, reconciled to the real video length after transcription (e.g. a 10-minute video is about 220 credits)."},{key:"fb_reels_inventory",label:"Facebook Reel URL inventory",aliases:["facebook_reels_inventory","facebook reels","facebook reel urls","facebook profile reels"],credits:i(t.fb_reels_inventory),unit:"per profile scan",notes:"Collects canonical Reel URLs from a Facebook profile. Logged-out scans are capped at 60 URLs; saved browser profiles can request larger inventories."},{key:"instagram_profile",label:"Instagram profile content discovery",aliases:["instagram_profile_content","instagram profile","instagram content list","ig profile"],credits:i(t.instagram_profile),unit:"per profile scan",notes:"Browser extraction of public Instagram profile grid links. Complete history may require a logged-in profile."},{key:"instagram_media",label:"Instagram media download",aliases:["instagram_media_download","instagram reel download","instagram post download","ig media"],credits:i(t.instagram_media),unit:"per post or reel",notes:"Extracts post text, image URLs, and reel audio/video tracks, with local downloads when the server can write files."},{key:"instagram_transcribe",label:"Instagram media transcription",aliases:["instagram transcript","instagram reel transcript","ig transcribe"],credits:i(2e4),unit:"base + 2/min of video",notes:"Whisper transcription of selected Instagram audio/video media. Flat 200-credit base plus 2 credits per minute of video, reconciled to the real video length after transcription (e.g. a 10-minute video is about 220 credits)."},{key:"browser_minute",label:"Interactive browser session",aliases:["browser_open","browser agent","browser_agent","live browser","browse","browser control","interactive browser"],credits:i(t.browser_minute),unit:"per minute of use",notes:"Metered per minute of use for the whole time the browser session is open. Close the session to stop the meter; abandoned sessions are auto-closed after a short idle window."},{key:"reddit_thread",label:"Reddit thread base lookup",aliases:["reddit","reddit_thread","reddit comments","subreddit","reddit post"],credits:i(t.reddit_thread),unit:"per thread",notes:"Base lookup for the post itself. Comments billed separately per comment at reddit_comment rate. Refunded if the thread cannot be retrieved."},{key:"reddit_comment",label:"Reddit comment",aliases:["reddit_comment","reddit comments"],credits:i(t.reddit_comment),unit:"per comment",notes:"Charged per comment actually extracted, billed down automatically if the balance runs out mid-thread."},{key:"video_analysis",label:"Video breakdown (frame-by-frame + transcript)",aliases:["video_frame_analysis","video breakdown","video analysis","analyze video"],credits:i(t.video_analysis),unit:"per 120 frames (max 480)",notes:"Full multi-lens video breakdown: samples frames across a video (up to 30 minutes), analyzes each with vision AI, transcribes the audio, then produces summary, pacing/energy, words-per-minute, topic outline, key points, hook analysis, visual style, and a how-to-replicate recipe with a quality-control pass. $1 per 120 frames requested (max 480 = $4); billed down automatically if the video cannot use the requested frames, and refunded fully if the run fails."},{key:"trustpilot_reviews",label:"Trustpilot review harvest",aliases:["trustpilot_reviews","trustpilot","trustpilot reviews"],credits:i(t.trustpilot_reviews),unit:"per call",notes:"Base lookup. Reviews billed separately per card at trustpilot_review rate. Refunded if no reviews are found."},{key:"trustpilot_review",label:"Trustpilot review card",aliases:["trustpilot_review","trustpilot card"],credits:i(t.trustpilot_review),unit:"per review card",notes:"Charged per review actually extracted, billed down automatically if the balance runs out mid-page."},{key:"g2_reviews",label:"G2 review harvest",aliases:["g2_reviews","g2","g2 reviews"],credits:i(t.g2_reviews),unit:"per call",notes:"Base lookup. Reviews billed separately per card at g2_review rate. Refunded if no reviews are found."},{key:"g2_review",label:"G2 review card",aliases:["g2_review","g2 card"],credits:i(t.g2_review),unit:"per review card",notes:"Charged per review actually extracted (each card carries up to 3 Q&A sections), billed down automatically if the balance runs out mid-page."},{key:"diff_page",label:"Page change check",aliases:["diff_page","page diff","change detection"],credits:i(t.diff_page),unit:"per check",notes:"Same cost as a single page extract \u2014 one scrape is performed per check, then compared against your last stored snapshot for that URL."}],ge="price_1Ta1NRS8aAcsk3TGwsRnYbix";function w(e){return e.billing_interval??"month"}function O(e){return e.billed_usd??e.monthly_usd}function M(e){return e.credits_mc/o}var d={price_1TmiHRS8aAcsk3TGwmSNfNIa:{tier:"starter",label:"Starter",price_id:"price_1TmiHRS8aAcsk3TGwmSNfNIa",monthly_usd:12,credits_mc:8e6,concurrency:3,intro_coupon:"mcp-starter-1dollar-intro-12"},price_1TrgihS8aAcsk3TG5cglrq4D:{tier:"growth",label:"Growth",price_id:"price_1TrgihS8aAcsk3TG5cglrq4D",monthly_usd:40,credits_mc:26666700,concurrency:10,intro_coupon:null},price_1TrgihS8aAcsk3TG4HnG4gbY:{tier:"scale",label:"Scale",price_id:"price_1TrgihS8aAcsk3TG4HnG4gbY",monthly_usd:100,credits_mc:8e7,concurrency:20,intro_coupon:null},price_1TwqIVS8aAcsk3TG0FE3ddDM:{tier:"sonic",label:"Sonic Annual",price_id:"price_1TwqIVS8aAcsk3TG0FE3ddDM",monthly_usd:25,billed_usd:300,credits_mc:25e7,concurrency:3,intro_coupon:null,billing_interval:"year",credits_never_expire:!0,private_offer:!0},price_1TwqIWS8aAcsk3TGbGbtlLak:{tier:"sonic-memory",label:"Sonic Annual + Memory Pro",price_id:"price_1TwqIWS8aAcsk3TGbGbtlLak",monthly_usd:34.5,billed_usd:414,credits_mc:25e7,concurrency:3,intro_coupon:null,billing_interval:"year",credits_never_expire:!0,includes_memory:!0,private_offer:!0}},b=Object.fromEntries(Object.values(d).map(e=>[e.tier,e])),f={sonic:{slug:"sonic",label:"Sonic annual partner offer",headline:"A full year of MCP Scraper, with Credits that never expire.",tier_keys:["sonic","sonic-memory"]}};function $(e){let r=Object.values(f).find(a=>a.tier_keys.includes(e));return r?`/${r.slug}/claim`:null}function K(e){return e?Object.values(f).find(r=>r.tier_keys.includes(e))??null:null}function be(e,r){let a=K(e);return a?!a.tier_keys.includes(r):!1}function fe(e){if(!e)return null;let r=b[e];return r?{tier:r.tier,label:r.label,amount_usd:O(r),interval:w(r),monthly_equivalent_usd:r.monthly_usd,credits_per_interval:M(r),concurrency:r.concurrency,credits_never_expire:!!r.credits_never_expire,includes_memory:!!r.includes_memory,private_offer:!!r.private_offer,offer_claim_path:$(r.tier)}:null}function Re(e){let r=f[e];if(!r)return null;let a=r.tier_keys.map(s=>b[s]).filter(s=>!!s).map(s=>({tier:s.tier,label:s.label,amount_usd:O(s),interval:w(s),monthly_equivalent_usd:s.monthly_usd,credits:M(s),credits_never_expire:!!s.credits_never_expire,includes_memory:!!s.includes_memory,concurrency:s.concurrency}));return a.length?{slug:r.slug,label:r.label,headline:r.headline,options:a}:null}function Ee(){let e=b.starter,r=W.map(({aliases:n,...c})=>({...c,...c.notes?{notes:c.notes.replace(/ via fal\.ai/g,"")}:{}})),a=Object.fromEntries(r.map(n=>[n.key,{credits:n.credits,unit:n.unit,label:n.label,...n.notes?{notes:n.notes}:{}}])),s=Object.values(d).filter(n=>!n.private_offer).map(n=>({tier:n.tier,label:n.label,monthlyUsd:n.monthly_usd,credits:n.credits_mc/o,concurrency:n.concurrency}));return{...p,operationCosts:a,publicTiers:s,concurrencyPack:{ratePolicyVersion:L,monthlyUsd:x,currency:k,interval:U,billingUnit:"pack",slotsPerPack:g},creditsPerDollarStarter:Math.round(i(e.credits_mc)/e.monthly_usd),costs:r,scheduling:p.addons.scheduling,connectedAccounts:p.addons.connectedAccounts,listingWrites:F}}var x=5,k="usd",U="month",g=2,L="2026-08-14.concurrency-pack-v1",Z="$5/month for 2 extra browsers",he="MCP Scraper browser concurrency pack \u2014 each $5 monthly pack adds 2 browsers.",Ce="Billed monthly until canceled. A receipt is emailed after each successful payment.",h="npx -y -p mcp-scraper@latest mcp-scraper-cli billing concurrency checkout";function ye(){let e=process.env.CONCURRENCY_BILLING_URL??"https://mcpscraper.dev/billing";return{product:"Extra browser concurrency pack",rate_policy_version:L,price_label:Z,unit_amount_usd:x,currency:k,interval:U,billing_unit:"pack",pack_quantity:1,slots_per_pack:g,extra_slots:g,billing_url:e,terminal_command:h,terminal_command_with_api_key_env:`MCP_SCRAPER_API_KEY=sk_live_your_key ${h}`}}function i(e){return e/o}var Q="npx -y -p mcp-scraper@latest mcp-scraper-cli billing subscribe";function j(){return Object.values(d).filter(e=>!e.private_offer).sort((e,r)=>e.credits_mc-r.credits_mc)}function Te(e,r){let a=process.env.TOPUP_URL??"https://mcpscraper.dev/billing",s=i(e),n=i(r),c=j().map(u=>u.tier).join("|"),l=`${Q} <${c}>`;return{error:"insufficient_balance",error_code:"insufficient_balance",message:`Insufficient credits. Balance: ${s} credits. This call requires ${n} credits. Credits refresh when your plan renews; for more now, move to a larger plan at ${a} (terminal: ${l})`,balance_credits:s,required_credits:n,topup_url:a,upgrade_command:l}}var X=1e7*1,ve={price_1TnMSTS8aAcsk3TGBgiwuvqL:{plan:"pro",label:"Pro",price_id:"price_1TnMSTS8aAcsk3TGBgiwuvqL",interval:"month",monthly_usd:19,quota_bytes:5e9},price_1TnMSTS8aAcsk3TGWBVU2agY:{plan:"pro",label:"Pro",price_id:"price_1TnMSTS8aAcsk3TGWBVU2agY",interval:"year",monthly_usd:19,quota_bytes:5e9}},Se={free:X,pro:5e9,team:5e10},z=3;var Ae=19/z,Ne={TOPUP:"topup",SUBSCRIPTION:"subscription",SIGNUP_GRANT:"signup_grant",MONTHLY_REFRESH:"monthly_free_refresh",PAA:"paa",PAA_REFUND:"paa_refund",SERP:"serp",SERP_REFUND:"serp_refund",REFUND:"refund",TRANSCRIPTION:"transcription",TRANSCRIPTION_HOLD:"transcription_hold",TRANSCRIPTION_REFUND:"transcription_refund",YT_CHANNEL:"yt_channel",FB_AD:"fb_ad",MAPS_SEARCH:"maps_search",DIRECTORY_WORKFLOW_HOLD:"directory_workflow_hold",DIRECTORY_WORKFLOW_REFUND:"directory_workflow_refund",LEAD_LIST_ENRICHMENT_HOLD:"lead_list_enrichment_hold",LEAD_LIST_ENRICHMENT_REFUND:"lead_list_enrichment_refund",MAPS_PLACE:"maps_place",MAPS_REVIEW:"maps_review",MAPS_REVIEW_REFUND:"maps_review_refund",EXTRACT_SITE:"extract_site",EXTRACT_SITE_REFUND:"extract_site_refund",EXTRACT_URL:"page_scrape",URL_MAP:"url_map",EXTRACT_SITE_HOLD:"extract_site_hold",YT_CHANNEL_REFUND:"yt_channel_refund",FB_AD_REFUND:"fb_ad_refund",URL_MAP_REFUND:"url_map_refund",FB_SEARCH:"fb_search",FB_REELS_INVENTORY:"fb_reels_inventory",FB_REELS_INVENTORY_REFUND:"fb_reels_inventory_refund",FB_TRANSCRIBE:"fb_transcribe",FB_SEARCH_REFUND:"fb_search_refund",FB_SEARCH_RESULT:"fb_search_result",FB_SEARCH_RESULT_REFUND:"fb_search_result_refund",FB_PAGE_INTEL:"fb_page_intel",FB_PAGE_INTEL_REFUND:"fb_page_intel_refund",FB_PAGE_INTEL_AD:"fb_page_intel_ad",FB_PAGE_INTEL_AD_REFUND:"fb_page_intel_ad_refund",FB_TRANSCRIBE_REFUND:"fb_transcribe_refund",GOOGLE_ADS_SEARCH:"google_ads_search",GOOGLE_ADS_SEARCH_REFUND:"google_ads_search_refund",GOOGLE_ADS_INTEL:"google_ads_intel",GOOGLE_ADS_INTEL_REFUND:"google_ads_intel_refund",GOOGLE_ADS_TRANSCRIBE:"google_ads_transcribe",GOOGLE_ADS_TRANSCRIBE_REFUND:"google_ads_transcribe_refund",INSTAGRAM_PROFILE:"instagram_profile",INSTAGRAM_PROFILE_REFUND:"instagram_profile_refund",INSTAGRAM_MEDIA:"instagram_media",INSTAGRAM_MEDIA_REFUND:"instagram_media_refund",INSTAGRAM_TRANSCRIBE:"instagram_transcribe",INSTAGRAM_TRANSCRIBE_REFUND:"instagram_transcribe_refund",BROWSER_SESSION:"browser_session",REDDIT_THREAD:"reddit_thread",REDDIT_THREAD_REFUND:"reddit_thread_refund",REDDIT_COMMENT:"reddit_comment",REDDIT_COMMENT_REFUND:"reddit_comment_refund",VIDEO_ANALYSIS:"video_analysis",VIDEO_ANALYSIS_REFUND:"video_analysis_refund",VIDEO_ANALYSIS_ADJUST:"video_analysis_adjust",VIDEO_ANALYSIS_LLM:"video_analysis_llm",MEMORY_AI:"memory_ai",MEMORY_AI_REFUND:"memory_ai_refund",TRUSTPILOT_REVIEWS:"trustpilot_reviews",TRUSTPILOT_REVIEWS_REFUND:"trustpilot_reviews_refund",TRUSTPILOT_REVIEW:"trustpilot_review",TRUSTPILOT_REVIEW_REFUND:"trustpilot_review_refund",G2_REVIEWS:"g2_reviews",G2_REVIEWS_REFUND:"g2_reviews_refund",G2_REVIEW:"g2_review",G2_REVIEW_REFUND:"g2_review_refund",DIFF_PAGE:"diff_page",DIFF_PAGE_REFUND:"diff_page_refund",LOCAL_SOURCEBOOK_CREATE:"local_sourcebook_create",LOCAL_SOURCEBOOK_CREATE_REFUND:"local_sourcebook_create_refund",LOCAL_SOURCEBOOK_EDIT:"local_sourcebook_edit",LOCAL_SOURCEBOOK_EDIT_REFUND:"local_sourcebook_edit_refund",COMMONS_CREATE:"commons_create",COMMONS_CREATE_REFUND:"commons_create_refund",COMMONS_EDIT:"commons_edit",COMMONS_EDIT_REFUND:"commons_edit_refund",SITE_AUDIT_LLM:"site_audit_llm",SCHEDULED_RUN:"scheduled_run",CONNECTED_USAGE:"connected_usage",CONNECTED_ACCOUNT_FEE:"connected_account_fee",ADMIN_GRANT:"admin_grant",ADMIN_REVOKE:"admin_revoke"},Ie=3,we=1.5,Oe=1.5,P=2e4,D=200;function Me(e){let r=Math.max(1,Math.ceil((e||60)/60));return P+D*r}var xe=P+D*30,ke=d.price_1TmiHRS8aAcsk3TGwmSNfNIa.credits_mc/d.price_1TmiHRS8aAcsk3TGwmSNfNIa.monthly_usd;export{t as a,re as b,te as c,ie as d,o as e,ne as f,se as g,ae as h,oe as i,F as j,E as k,q as l,ce as m,V as n,le as o,_e as p,H as q,y as r,de as s,T as t,v as u,S as v,A as w,ue as x,pe as y,me as z,W as A,ge as B,w as C,O as D,M as E,d as F,b as G,$ as H,K as I,be as J,fe as K,Re as L,Ee as M,x as N,g as O,he as P,Ce as Q,ye as R,i as S,Te as T,ve as U,Se as V,Ne as W,Ie as X,we as Y,Oe as Z,Me as _,xe as $,ke as aa};
|