mcp-scraper 0.95.2 → 0.96.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/CHANGELOG.md +67 -1
  2. package/README.md +21 -3
  3. package/dist/actions-R4EJDLRO.js +1 -0
  4. package/dist/artifacts-4ZDNP2JW.js +1 -0
  5. package/dist/artifacts-N62OPIT5.js +1 -0
  6. package/dist/artifacts-PSADD5OC.js +1 -0
  7. package/dist/artifacts-RUR3OHAK.js +1 -0
  8. package/dist/bin/api-server.js +1 -1
  9. package/dist/bin/mcp-scraper-cli.js +22 -22
  10. package/dist/bin/mcp-scraper-core.js +1 -1
  11. package/dist/bin/mcp-scraper-install.js +1 -1
  12. package/dist/bin/mcp-stdio-server.js +1 -1
  13. package/dist/bin/paa-harvest.js +1 -1
  14. package/dist/blob-store-GIH26EDO.js +1 -0
  15. package/dist/bundle-FCXZMIRB.js +1 -0
  16. package/dist/chunk-24YDQ3EO.js +5 -0
  17. package/dist/chunk-3F7AFM53.js +1 -0
  18. package/dist/chunk-4HZXATHB.js +27 -0
  19. package/dist/chunk-55ZANTHL.js +3 -0
  20. package/dist/chunk-5BKSKLHX.js +1 -0
  21. package/dist/chunk-5LYINW7Z.js +8 -0
  22. package/dist/chunk-63VWBMYR.js +3 -0
  23. package/dist/chunk-6BD75VKS.js +218 -0
  24. package/dist/chunk-6N5EC7ZO.js +1 -0
  25. package/dist/chunk-7POHNTVW.js +1 -0
  26. package/dist/chunk-7SR7MEU5.js +62 -0
  27. package/dist/chunk-7WPCGRD7.js +182 -0
  28. package/dist/chunk-B3JRL45T.js +1 -0
  29. package/dist/chunk-B4ZKPLSP.js +1 -0
  30. package/dist/chunk-BPKTUCV7.js +12 -0
  31. package/dist/chunk-C7MGJUTU.js +1 -0
  32. package/dist/{chunk-W2BVJ7S2.js → chunk-CNSVZTTT.js} +4 -4
  33. package/dist/chunk-CORWWDHL.js +1 -0
  34. package/dist/chunk-CVQUHVHX.js +1 -0
  35. package/dist/chunk-FB4KBB5W.js +16 -0
  36. package/dist/{chunk-Y3Q4FIKK.js → chunk-H6MODA7W.js} +199 -84
  37. package/dist/chunk-HCK6PLM3.js +3 -0
  38. package/dist/chunk-HNNYXMSI.js +1 -0
  39. package/dist/chunk-HUNSEGUN.js +57 -0
  40. package/dist/{chunk-MC4W6TZT.js → chunk-HVQZRQRJ.js} +41 -8
  41. package/dist/chunk-IFPION5D.js +121 -0
  42. package/dist/chunk-IY6ZUUY7.js +173 -0
  43. package/dist/chunk-JHT6A4U6.js +11 -0
  44. package/dist/chunk-JMZIDHYQ.js +2 -0
  45. package/dist/chunk-KXJCGV3H.js +1 -0
  46. package/dist/chunk-MVMWPKRC.js +2 -0
  47. package/dist/chunk-NALXKTUU.js +1 -0
  48. package/dist/chunk-NNOX3FYG.js +198 -0
  49. package/dist/chunk-OILOHQNL.js +2 -0
  50. package/dist/chunk-OLYPLX5C.js +1 -0
  51. package/dist/chunk-QER2ELZP.js +1 -0
  52. package/dist/chunk-RDHGQ2WZ.js +1 -0
  53. package/dist/chunk-RIHI3KH7.js +955 -0
  54. package/dist/chunk-RN4VG3VH.js +4 -0
  55. package/dist/chunk-RYX4FJVH.js +1 -0
  56. package/dist/chunk-SDQW7IJN.js +1 -0
  57. package/dist/{chunk-ENZUJEIM.js → chunk-SE4VKLEC.js} +1 -1
  58. package/dist/chunk-SEZETSB3.js +1 -0
  59. package/dist/chunk-SFUOSJ3A.js +159 -0
  60. package/dist/chunk-UIOSADPB.js +1718 -0
  61. package/dist/{chunk-ZH75KWBI.js → chunk-UNEJYZ4T.js} +1 -1
  62. package/dist/chunk-UXNR3K6I.js +1 -0
  63. package/dist/{chunk-VREXSMC6.js → chunk-VVSHZV5S.js} +5 -5
  64. package/dist/chunk-WNUXMPVX.js +1 -0
  65. package/dist/chunk-WP3QS4CJ.js +1 -0
  66. package/dist/chunk-ZTMQEDIB.js +41 -0
  67. package/dist/contracts-GUXGFCVV.js +1 -0
  68. package/dist/core-schema-423BSTE6.js +936 -0
  69. package/dist/dispatch-P7IY75LH.js +1 -0
  70. package/dist/index.cjs +103 -213
  71. package/dist/index.d.cts +184 -169
  72. package/dist/index.d.ts +184 -169
  73. package/dist/index.js +1 -1
  74. package/dist/media-artifacts-67CJWI7O.js +1 -0
  75. package/dist/metering-ZH2P62IC.js +1 -0
  76. package/dist/migrations-3AKEC5QE.js +1 -0
  77. package/dist/queue-AC4XKD6Z.js +1 -0
  78. package/dist/reconciliation-UZUZ6B74.js +1 -0
  79. package/dist/report-artifact-offload-6OOY2PTM.js +1 -0
  80. package/dist/repository-4EC5EXVN.js +1 -0
  81. package/dist/{location-data-repository-A2QZVP7O.js → repository-CYXVMYAI.js} +1 -1
  82. package/dist/server-DXZ27KQO.js +5825 -0
  83. package/dist/settlement-6CS4JZTY.js +1 -0
  84. package/dist/worker-ATRD6VKM.js +1 -0
  85. package/package.json +2 -2
  86. package/dist/analytics-repository-DZZKDZL6.js +0 -1
  87. package/dist/chunk-6DRKDSXY.js +0 -182
  88. package/dist/chunk-6ND5AFV5.js +0 -27
  89. package/dist/chunk-7XDBGQDY.js +0 -6
  90. package/dist/chunk-7YOXSMHG.js +0 -1565
  91. package/dist/chunk-BLVBUMH5.js +0 -21
  92. package/dist/chunk-EDQ57S4P.js +0 -1
  93. package/dist/chunk-GLTECY3U.js +0 -1282
  94. package/dist/chunk-GPSPSJBJ.js +0 -1
  95. package/dist/chunk-HE45FFBU.js +0 -1
  96. package/dist/chunk-HUV2WTRW.js +0 -1
  97. package/dist/chunk-IXJQHXDC.js +0 -2595
  98. package/dist/chunk-K3D2S36Q.js +0 -16
  99. package/dist/chunk-KFOFU3LA.js +0 -1
  100. package/dist/chunk-LMWU7VPZ.js +0 -63
  101. package/dist/chunk-O4LUUIYG.js +0 -4
  102. package/dist/chunk-OLSW4AN4.js +0 -19
  103. package/dist/chunk-RLFCJGHA.js +0 -100
  104. package/dist/chunk-T4VTJNDZ.js +0 -84
  105. package/dist/chunk-TMB56NCA.js +0 -1
  106. package/dist/chunk-VXOXB3IB.js +0 -1
  107. package/dist/chunk-WO3N5FH2.js +0 -5
  108. package/dist/chunk-WO46LTBW.js +0 -1
  109. package/dist/chunk-XPEJB4BZ.js +0 -1
  110. package/dist/db-CDEZHBRN.js +0 -1
  111. package/dist/extract-bundle-SXC6EWJR.js +0 -26
  112. package/dist/gmail-service-EWR76XE7.js +0 -1
  113. package/dist/lead-list-enrichment-repository-SIWGXWQV.js +0 -1
  114. package/dist/operation-metering-UJ53YX7S.js +0 -1
  115. package/dist/server-QVEKDIDQ.js +0 -5014
  116. package/dist/site-extract-repository-23ND4N77.js +0 -1
  117. package/dist/stripe-event-worker-LPXTITVC.js +0 -1
  118. package/dist/worker-EDN2TJH3.js +0 -1
  119. /package/dist/{chunk-YGBTTW5D.js → chunk-2IATUJO6.js} +0 -0
  120. /package/dist/{chunk-6DTXIZY2.js → chunk-4ZVO6GX4.js} +0 -0
  121. /package/dist/{chunk-XG6GCEUE.js → chunk-U4WIJZCX.js} +0 -0
@@ -0,0 +1,2 @@
1
+ import{a as D}from"./chunk-OLYPLX5C.js";import{b as R}from"./chunk-B3JRL45T.js";import{c as P}from"./chunk-OILOHQNL.js";import{createWriteStream as H,mkdirSync as W,rmSync as N}from"fs";import{join as A,extname as B,basename as z}from"path";import{pipeline as O}from"stream/promises";import{Readable as I,Transform as q}from"stream";var X=["doubleclick.net","googlesyndication.com","googletagmanager.com","google-analytics.com","googletagservices.com","adservice.google","googletag.","pagead2.googlesyndication","facebook.net/tr","connect.facebook.net","fbcdn.net/rsrc","analytics.twitter.com","static.ads-twitter.com","ads.twitter.com","t.co/i/adsct","pixel.advertising.com","hotjar.com","clarity.ms","quantserve.com","scorecardresearch.com","newrelic.com","nr-data.net","segment.io","segment.com","amplitude.com","mixpanel.com","heap.io","fullstory.com","moatads.com","criteo.com","adsrvr.org","rubiconproject.com","pubmatic.com","openx.net","appnexus.com","amazon-adsystem.com","media.net","yieldmo.com","triplelift.com","sharethrough.com","prebid.","smaato.net","indexworm.com","casalemedia.com","outbrain.com","taboola.com","revcontent.com","mgid.com","tawk.to","intercom.io","drift.com","hs-scripts.com","zopim.com","livechatinc.com","userlike.com","onetrust.com","cookielaw.org","cookieinformation.com","trustarc.com","/ads/","/ad/","/banner/","/banners/","/pixel/","/beacon/","/tracking/","/tracker/","/remarketing/","/conversion/","1x1.gif","spacer.gif","blank.gif","transparent.gif"],G=new Set([".jpg",".jpeg",".png",".webp",".gif",".avif",".svg",".tiff"]),K=new Set([".mp4",".webm",".mov",".avi",".m4v",".ogv",".mkv"]),V=new Set([".mp3",".wav",".ogg",".aac",".m4a",".flac",".opus"]);function Z(r){let e=r.toLowerCase();return X.some(t=>e.includes(t))}function J(r){return r.startsWith("data:")}function U(r){try{let e=B(new URL(r).pathname).toLowerCase();if(G.has(e))return"image";if(K.has(e))return"video";if(V.has(e))return"audio"}catch{}return null}function L(r){let e=r.toLowerCase();return e.startsWith("image/")?"image":e.startsWith("video/")?"video":e.startsWith("audio/")?"audio":null}function Q(r,e){if(!r||J(r))return null;try{return new URL(r,e).href}catch{return null}}function C(r,e){try{let t=new URL(r);return z(t.pathname).replace(/[^a-zA-Z0-9._-]/g,"_").slice(0,80)||`asset-${e}`}catch{return`asset-${e}`}}function k(r,e){let t=r?.replace(/&(?:amp|#0?38|#x26);/gi,"&").replace(/\s+/g," ").trim();return t?t.slice(0,e):null}function Y(r){let e=r.match(/[-_/](\d{2,5})x(\d{2,5})(?=[._/?#-]|$)/i);return e?{width:Number(e[1]),height:Number(e[2])}:null}function ee(r){try{let e=new URL(r);e.hash="",e.pathname=e.pathname.replace(/-(?:\d{2,5}x\d{2,5}|scaled|e\d{6,})(?=\.[a-z0-9]{2,6}$)/i,"");for(let t of["w","width","h","height","resize"])e.searchParams.delete(t);return e.searchParams.sort(),e.href}catch{return r}}function T(r){let e=(r.width??0)*(r.height??0),t=r.discoveryMethods.some(f=>f.includes("lightbox"))?1e12:0,u=/-(?:\d{2,5}x\d{2,5}|scaled|e\d{6,})(?=\.[a-z0-9]{2,6}(?:[?#]|$))/i.test(r.url)?0:1e11;return t+u+e}function S(r,e){let t=r.get(e.url);if(!t){r.set(e.url,e);return}t.discoveryMethods=[...new Set([...t.discoveryMethods,...e.discoveryMethods])],t.altTexts=[...new Set([...t.altTexts,...e.altTexts])],t.contexts=[...new Set([...t.contexts,...e.contexts])],!t.type&&e.type&&(t.type=e.type),(e.width??0)*(e.height??0)>(t.width??0)*(t.height??0)&&(t.width=e.width,t.height=e.height)}function te(r,e){let t=new Map,u=(l,s,a=null,h,i,c)=>{let n=l?Q(l.trim().replace(/&/g,"&"),e):null;if(!n||Z(n))return;let d=c??Y(n);S(t,{url:n,type:a??U(n),discoveryMethods:[s],altTexts:h?[h]:[],contexts:i?[i]:[],width:d?.width??null,height:d?.height??null})},f=(l,s,a,h)=>{for(let i of(l??"").split(",")){let[c,n]=i.trim().split(/\s+/);if(!c)continue;let d=n?.match(/^(\d+)w$/)?.[1];u(c,s,a,h,null,d?{width:Number(d),height:0}:null)}},m=(l,s="")=>{let a=l.$;for(let i of l.images){let c=i.attributes,n=k(i.alt,500),d=i.width&&i.height?{width:i.width,height:i.height}:null;for(let g of["src","data-src","data-lazy-src","data-original","data-bg","data-background","data-bg-url","data-lazy-bg","data-echo"]){let y=c[g];u(y,`static-${g}${s}`,"image",n,null,d)}f(c.srcset,`static-srcset${s}`,"image",n),f(c["data-srcset"],`static-data-srcset${s}`,"image",n)}a("source").each((i,c)=>{let n=a(c),d=n.attr("type")??"",g=d.startsWith("video/")?"video":d.startsWith("audio/")?"audio":"image";u(n.attr("src"),`static-source${s}`,g),f(n.attr("srcset"),`static-source-srcset${s}`,g)}),a("video,audio").each((i,c)=>{let n=a(c),d=c.tagName.toLowerCase();u(n.attr("src"),`static-${d}${s}`,d),d==="video"&&u(n.attr("poster"),`static-video-poster${s}`,"image")}),a("meta").each((i,c)=>{let n=a(c),d=(n.attr("property")??n.attr("name")??"").toLowerCase();(d==="og:image"||d==="og:image:url"||d==="twitter:image"||d==="twitter:image:src")&&u(n.attr("content"),`static-${d}${s}`,"image")}),a("link[href]").each((i,c)=>{let n=a(c);(n.attr("rel")??"").toLowerCase().split(/\s+/).some(g=>g==="icon"||g==="apple-touch-icon")&&u(n.attr("href"),`static-icon${s}`,"image")}),a("svg image").each((i,c)=>{let n=a(c);u(n.attr("href")??n.attr("xlink:href"),`static-svg-image${s}`,"image")}),a("a[href]").has("img").each((i,c)=>{let n=a(c),d=n.attr("href");if(d&&(/lightbox|gallery|fancybox|glightbox|swipebox|elementor-open-lightbox/i.test(`${n.attr("class")??""} ${n.attr("data-elementor-open-lightbox")??""}`)||/\.(?:avif|gif|jpe?g|png|svg|webp)(?:[?#]|$)/i.test(d))){let g=k(n.find("img").first().attr("alt"),500);u(d,`static-lightbox-target${s}`,"image",g)}});let h=a("style").toArray().map(i=>a(i).text());a("[style]").each((i,c)=>{h.push(a(c).attr("style")??"")});for(let i of h.join(`
2
+ `).matchAll(/(?:background(?:-image)?\s*:\s*)?url\(\s*(?:["']|&quot;|&#0?34;|&apos;|&#0?39;)?([^"')&]+)(?:["']|&quot;|&#0?34;|&apos;|&#0?39;)?\s*\)/gi))u(i[1],`static-css-url${s}`,"image");for(let i of l.sourceHtml.matchAll(/["'](https?:\/\/[^"'\s<>]+\.(?:avif|gif|jpe?g|png|svg|webp|mp4|webm|mp3|ogg)(?:\?[^"'\s<>]*)?)["']/gi))u(i[1],`static-bare-url${s}`)},o=typeof r=="string"?D(r):r;return m(o),o.$("script").each((l,s)=>{let a=o.$(s).text(),h=a.replace(/\\u003[cC]/g,"<").replace(/\\u003[eE]/g,">").replace(/\\u0026/gi,"&").replace(/\\["']/g,i=>i.slice(1)).replace(/\\\//g,"/");h!==a&&/<(?:img|source|video|audio)\b/i.test(h)&&m(D(h),"-json-unescaped")}),[...t.values()]}function re(r,e,t=100){let u=new Map;for(let m of r)S(u,m);for(let m of e?.assets??[])S(u,{...m,type:m.type});let f=new Map;for(let m of u.values()){let o=ee(m.url),l=f.get(o)??[];l.push(m),f.set(o,l)}return[...f.values()].map(m=>{let o=[...m].sort((s,a)=>T(a)-T(s)||s.url.localeCompare(a.url)),l={...o[0]};return l.discoveryMethods=[...new Set(m.flatMap(s=>s.discoveryMethods))],l.altTexts=[...new Set(m.flatMap(s=>s.altTexts))],l.contexts=[...new Set(m.flatMap(s=>s.contexts))],{...l,variants:o.slice(1).map(s=>s.url)}}).sort((m,o)=>T(o)-T(m)||m.url.localeCompare(o.url)).slice(0,Math.max(1,t))}async function ne(r,e,t,u={}){let f=Math.max(1,Math.min(u.maxBytes??52428800,104857600)),m=r,o=null;for(let g=0;g<=5;g++){let y=await R(m,{field:"media URL"});if(y.error||!y.parsed)throw new Error(y.error??"Media URL was rejected");if(o=await fetch(y.parsed.href,{signal:AbortSignal.timeout(15e3),redirect:"manual"}),o.status>=300&&o.status<400){let v=o.headers.get("location");if(!v)throw new Error(`HTTP ${o.status} redirect did not include Location`);m=new URL(v,y.parsed.href).href,o=null;continue}break}if(!o)throw new Error("Media download exceeded five redirects");if(!o.ok)throw new Error(`HTTP ${o.status}`);if(!o.body)throw new Error("Empty response body");let l=o.headers.get("content-type")?.split(";")[0].trim()??null;if(u.expectedType&&(!l||L(l)!==u.expectedType))throw new Error(`Expected ${u.expectedType} content but received ${l??"no content-type"}`);let s=Number(o.headers.get("content-length")??0);if(Number.isFinite(s)&&s>f)throw new Error(`Media asset exceeds ${f} byte limit`);let a=A(e,t);if(l&&!B(t)){let y={"image/jpeg":".jpg","image/png":".png","image/webp":".webp","image/gif":".gif","image/svg+xml":".svg","image/avif":".avif","video/mp4":".mp4","video/webm":".webm","audio/mpeg":".mp3","audio/ogg":".ogg","audio/wav":".wav"}[l];y&&(a=a+y)}let h=H(a);await new Promise((g,y)=>{h.once("open",()=>g()),h.once("error",y)});let i=0,c=new q({transform(g,y,v){let b=g.length;if(i+b>f){v(new Error(`Media asset exceeds ${f} byte limit`));return}if(u.consumeBytes&&!u.consumeBytes(b)){v(new Error("Media export total byte limit exceeded"));return}i+=b,v(null,g)}});try{await O(I.fromWeb(o.body),c,h)}catch(g){throw h.destroy(),N(a,{force:!0}),g}let{statSync:n}=await import("fs"),d=n(a).size;return{savedPath:a,sizeBytes:d,mimeType:l}}async function ue(r,e,t={}){let u=t.types??["image","video","audio"],f=new Set(u),m=te(r,e),o=Math.max(1,Math.min(t.maxAssets??100,250)),l=re(m,t.rendered,2e3),s=l.slice(0,o),a=new Set([...m.map(p=>p.url),...(t.rendered?.assets??[]).map(p=>p.url)]).size,h=s.flatMap(p=>{let w=p.type??U(p.url);return w&&f.has(w)?[{...p,type:w}]:[]}),i=a-h.length,c=l.length>o,n=t.rendered?.exhausted===!0&&!c,d=c?"asset_limit":t.rendered?.stopReason??"render_unavailable",g=c?[`Media discovery found ${l.length} responsive families; only the requested ${o} records were retained.`]:t.rendered?t.rendered.exhausted?[]:[`Rendered media discovery stopped with ${t.rendered.stopReason}; the inventory may be incomplete.`]:["Rendered media discovery was unavailable; this manifest contains static-source evidence only."],y={pageUrl:e,staticFound:m.length,renderedFound:t.rendered?.assets.length??0,filteredCount:i,totalFound:a,completeness:n?"complete":"partial",exhausted:n,stopReason:d,scrollRounds:t.rendered?.scrollRounds??0,warnings:g,artifact:null};if(t.outputDir===null)return{...y,outputDir:null,assets:h.map((p,w)=>({...p,mimeType:null,filename:C(p.url,w),savedPath:null,sizeBytes:null,sha256:null,downloadStatus:"not_attempted",downloadError:null,inlinePreview:null}))};let v=(()=>{try{return new URL(e).hostname.replace(/^www\./,"")}catch{return"unknown"}})(),b=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),$=t.outputDir??A(P(),"media",`${b}-${v}`);W($,{recursive:!0});let M=[];return await Promise.allSettled(h.map(async(p,w)=>{let E=C(p.url,w);try{let{savedPath:x,sizeBytes:j,mimeType:_}=await ne(p.url,$,E),F=_?L(_)??p.type:p.type;M.push({...p,type:F,mimeType:_,filename:z(x),savedPath:x,sizeBytes:j,sha256:null,downloadStatus:"downloaded",downloadError:null,inlinePreview:null})}catch(x){M.push({...p,mimeType:null,filename:E,savedPath:null,sizeBytes:null,sha256:null,downloadStatus:"failed",downloadError:x instanceof Error?x.message:"media_download_failed",inlinePreview:null})}})),M.sort((p,w)=>p.savedPath&&!w.savedPath?-1:!p.savedPath&&w.savedPath?1:p.url.localeCompare(w.url)),{...y,outputDir:$,assets:M}}export{L as a,te as b,ne as c,ue as d};
@@ -0,0 +1 @@
1
+ import{e as i,f as I,h as m,j as o}from"./chunk-SEZETSB3.js";import{i as A}from"./chunk-SDQW7IJN.js";var s="site-extracts/",y=10080*60*1e3,b=900*1e3;function x(){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 _(){return process.env.VERCEL==="1"||process.env.NODE_ENV==="production"}function r(){return{prefix:s,artifactTtlMs:y,downloadTtlMs:b,token:x()}}function l(t){return A(t,s)}async function v(t){let e=await i({policy:r(),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 R(t){let e=await I({policy:r(),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 D(t){let e=await i({policy:r(),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 S(t){return i({policy:r(),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 C(t){return m({policy:r(),artifactId:t.artifactId,ownerId:t.ownerId})}async function P(t){return o({policy:r(),artifactId:t,maxBytes:50*1024*1024})}async function B(t){return l(t.artifactId)!==t.ownerId?null:P(t.artifactId)}async function k(t){return l(t.artifactId)!==t.ownerId?null:o({policy:r(),artifactId:t.artifactId,maxBytes:25*1024*1024})}async function h(t){return l(t.artifactId)!==t.ownerId?null:o({policy:r(),artifactId:t.artifactId,maxBytes:10*1024*1024})}async function U(t={}){let e=t.now??new Date,a=x();if(!a)return{deleted:0,store:_()?"none":"local"};if(!t.force&&!(e.getUTCHours()===3&&e.getUTCMinutes()===21))return{deleted:0,store:"private-vercel-blob",skipped:!0};let E=e.getTime()-y,{list:T,del:w}=await import("@vercel/blob"),f,p=0;for(let u=0;u<20;u+=1){let n=await T({prefix:s,token:a,limit:1e3,cursor:f}),c=n.blobs.filter(d=>new Date(d.uploadedAt).getTime()<=E);if(c.length>0&&(await w(c.map(d=>d.pathname),{token:a}),p+=c.length),!n.hasMore||!n.cursor)break;f=n.cursor}return{deleted:p,store:"private-vercel-blob"}}export{s as a,y as b,b as c,r as d,l as e,v as f,R as g,D as h,S as i,C as j,P as k,B as l,k as m,h as n,U as o};
@@ -0,0 +1,2 @@
1
+ import{c as _}from"./chunk-63VWBMYR.js";import{a as p,f as w,i as x}from"./chunk-3F7AFM53.js";import{a as d,e as E,k as g}from"./chunk-RDHGQ2WZ.js";import{a as T,b as R,e as c,i as u}from"./chunk-SEZETSB3.js";import{i as l,k as m}from"./chunk-SDQW7IJN.js";import{createHash as h,randomBytes as C}from"crypto";var D=1440*60*1e3,y="mcp-reports/",F="extract-url-job-results/",O=2e3;function P(){return 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()||process.env.BLOB_READ_WRITE_TOKEN?.trim()||void 0}var A={prefix:y,artifactTtlMs:D,downloadTtlMs:900*1e3,token:P()},b={...A,hosted:!1,token:void 0},a="mcp-results/";function v(t){return{prefix:a,artifactTtlMs:T,downloadTtlMs:R,hosted:!t,token:t?void 0:P()}}var M=process.env.MCP_SCRAPER_ARTIFACT_OFFLOAD!=="false";async function j(t,e,r){let i=Date.now(),n=C(6).toString("hex"),o=await c({policy:A,ownerId:e,artifactKey:`${n}.md`,createdAt:i,filename:`${t}-${i}.md`,contentType:"text/markdown",content:r,scopeSegments:[t]});return{artifactId:o.artifactId,mimeType:o.contentType,sizeBytes:o.bytes,bytes:o.bytes,sha256:o.sha256,expiresAt:o.expiresAt,downloadUrl:o.downloadUrl,downloadUrlExpiresAt:o.downloadUrlExpiresAt,preview:r.slice(0,O)}}async function k(t,e,r){let i=JSON.stringify(r),n=await c({policy:b,ownerId:t,artifactKey:`${e}.json`,createdAt:Date.now(),filename:`${e}.json`,contentType:"application/json",content:i,scopeSegments:["extract_url"]});return{artifactId:n.artifactId,mimeType:n.contentType,sizeBytes:n.bytes,bytes:n.bytes,sha256:n.sha256,expiresAt:n.expiresAt,downloadUrl:n.downloadUrl,downloadUrlExpiresAt:n.downloadUrlExpiresAt,preview:i.slice(0,O)}}function J(t){if(t.startsWith(a))return l(t,a);let e=f(t)?.ownerId;return e||(t.startsWith(p)?w(t):t.startsWith(d)?E(t):l(t,y))}function f(t){let e=t.match(/^extract-url-job-results\/([a-f0-9]{24})\/([1-9][0-9]*)\/(exurl-[a-f0-9]{24})\.json$/);if(!e)return null;let r=Number(e[2]);return Number.isSafeInteger(r)?{ownerId:e[1],userId:r,jobId:e[3]}:null}async function I(t,e){let r=await _(t,e);if(!r||r.status!=="done"||r.options.jobKind!=="extract_url"||!r.result)return null;let i=Date.parse(`${r.created_at.replace(" ","T")}Z`);if(!Number.isFinite(i))return null;let n=new Date(i+1080*60*60*1e3);return n.getTime()<=Date.now()?null:{content:Buffer.from(JSON.stringify(r.result)),expiresAt:n.toISOString()}}async function K(t,e,r){let i=`${F}${e}/${r}/${t}.json`;if(!f(i))return null;let n=await I(t,r);return n?{artifactId:i,mimeType:"application/json",sizeBytes:n.content.length,bytes:n.content.length,sha256:h("sha256").update(n.content).digest("hex"),expiresAt:n.expiresAt,downloadUrl:null,downloadUrlExpiresAt:null,preview:n.content.toString("utf8",0,Math.min(2e3,n.content.length))}:null}async function z(t,e,r,i,n=!1){let o=f(t);if(o){if(o.userId!==i||!Number.isSafeInteger(e)||e<0||!Number.isSafeInteger(r)||r<=0)return null;let s=await I(o.jobId,o.userId);return s?{...m(s.content.subarray(e,e+r+1),e,r,s.content.length),totalBytes:s.content.length}:null}return t.startsWith(a)?u({policy:v(n),artifactId:t,offset:e,maxBytes:r}):t.startsWith(p)?x(t,e,r):t.startsWith(d)?g(t,e,r):u({policy:n?b:A,artifactId:t,offset:e,maxBytes:r})}function X(t){return t.downloadUrl?{type:"resource_link",name:"Full MCP Scraper report",title:"Download full report",uri:t.downloadUrl,mimeType:t.mimeType,size:t.sizeBytes}:null}function Y(t,e){return[t.trim(),"","--- Full report stored as artifact ---",`artifactId: ${e.artifactId} \xB7 ${e.bytes} bytes \xB7 expires ${e.expiresAt}`,"Read it with report_artifact_read (supports offset/maxBytes windowing)."].join(`
2
+ `)}export{D as a,y as b,F as c,O as d,A as e,a as f,v as g,M as h,j as i,k as j,J as k,K as l,z as m,X as n,Y as o};
@@ -0,0 +1 @@
1
+ import{createHmac as s,timingSafeEqual as u}from"crypto";var a=()=>process.env.NODE_ENV==="production"||process.env.VERCEL==="1";function f(){let e=process.env.SESSION_SECRET?.trim();if(e)return e;if(a())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 i=()=>f();function l(e,t){if(e.length!==t.length)return!1;try{return u(Buffer.from(e,"hex"),Buffer.from(t,"hex"))}catch{return!1}}function p(e){let t=String(e),n=s("sha256",i()).update(t).digest("hex");return`${t}.${n}`}function S(e){let t=e.lastIndexOf(".");if(t===-1)return null;let n=e.slice(0,t),o=e.slice(t+1),c=s("sha256",i()).update(n).digest("hex");if(!l(o,c))return null;let r=parseInt(n);return isNaN(r)?null:r}export{f as a,p as b,S as c};
@@ -0,0 +1,198 @@
1
+ import{a as g}from"./chunk-NALXKTUU.js";import{Pool as B}from"pg";var u=class extends Error{constructor(t,s,n=400){super(s);this.code=t;this.status=n;this.name="AnalyticsRepositoryError"}code;status};var D=null;function K(){let i=process.env.ANALYTICS_DATABASE_URL?.trim();if(!i)throw new u("analytics_database_unavailable","Site Analytics is not configured.",503);return i}function E(){return D||(D=new B({connectionString:K(),max:8})),D}import{randomBytes as _e,randomUUID as p}from"crypto";import{createHash as Z,randomUUID as v}from"crypto";import{createCipheriv as X,createDecipheriv as J,createHmac as x,randomBytes as Y,scryptSync as z,timingSafeEqual as V}from"crypto";var N="xray1";function G(){return process.env.ANALYTICS_RESTRICTED_DATA_SECRET?.trim()||g()}function T(i){return z(G(),`xray-restricted:${i}:v1`,32)}function k(i,e){let t=e.trim().slice(0,80);if(!t)throw new Error("analytics encryption purpose required");let s=Y(12),n=X("aes-256-gcm",T(t),s);n.setAAD(Buffer.from(`${N}:${t}`,"utf8"));let r=Buffer.concat([n.update(i,"utf8"),n.final()]),o=n.getAuthTag();return[N,Buffer.from(t,"utf8").toString("base64url"),s.toString("base64url"),o.toString("base64url"),r.toString("base64url")].join(".")}function U(i,e){try{let[t,s,n,r,o]=i.split(".");if(t!==N||!s||!n||!r||!o)return null;let a=Buffer.from(s,"base64url").toString("utf8");if(a!==e)return null;let d=J("aes-256-gcm",T(a),Buffer.from(n,"base64url"));return d.setAAD(Buffer.from(`${N}:${a}`,"utf8")),d.setAuthTag(Buffer.from(r,"base64url")),Buffer.concat([d.update(Buffer.from(o,"base64url")),d.final()]).toString("utf8")}catch{return null}}function Ne(i,e){return x("sha256",T(`identity:${i}`)).update(e.trim().toLowerCase()).digest("hex")}function ve(i,e,t,s){return x("sha256",s).update(`${i}.${e}.${t}`).digest("hex")}function Ae(i,e){if(!i||i.length!==e.length)return!1;try{return V(Buffer.from(i),Buffer.from(e))}catch{return!1}}var M="enhanced_matching",Q=90,ee=10,f=class extends Error{constructor(t,s,n){super(s);this.code=t;this.status=n;this.name="AnalyticsIdentityProfileError"}code;status};function A(i,e){return i?.trim().replace(/\s+/g," ").slice(0,e)||null}function ie(i){if(!i)return null;let[e,t]=i.split("@");return!e||!t?null:`${e.slice(0,1)}${"*".repeat(Math.min(6,Math.max(2,e.length-1)))}@${t}`}function te(i){if(!i)return null;let e=i.replace(/\D/g,"");return e.length<4?null:`***-***-${e.slice(-4)}`}function O(i){return Z("sha256").update(i).digest("hex")}async function h(i,e){if(!e.signals.length)return;let t=e.signals.map(r=>r.kind),s=e.signals.map(r=>r.valueHmac);if((await i.query(`SELECT 1 FROM analytics_identity_tombstones
2
+ WHERE site_id=$1 AND (kind,value_hmac) IN (
3
+ SELECT * FROM unnest($2::text[],$3::text[])
4
+ ) LIMIT 1`,[e.siteId,t,s])).rowCount)throw new f("analytics_identity_deleted","This identity cannot be automatically recreated.",410)}async function $(i,e){let t=A(e.displayName,160),s=A(e.email,320)?.toLowerCase()??null,n=A(e.phone,40);if(!t&&!s&&!n)return!1;let o=(await i.query(`SELECT p.public_ref FROM analytics_people p
5
+ JOIN analytics_identity_namespaces n ON n.id=p.namespace_id AND n.site_id=p.site_id AND n.status='approved'
6
+ WHERE p.id=$1 AND p.site_id=$2`,[e.personId,e.siteId])).rows[0]?.public_ref;if(!o)return!1;let a=[...new Set([o,...e.consentSubjectRefs].filter(Boolean))],l=(await i.query(`SELECT s.latest_receipt_id::text FROM analytics_consent_current_state s
7
+ JOIN analytics_consent_receipts r ON r.id=s.latest_receipt_id AND r.site_id=s.site_id
8
+ WHERE s.site_id=$1 AND s.subject_ref=ANY($2::text[])
9
+ AND s.site_analytics=true AND s.enhanced_matching=true AND s.gpc=false
10
+ AND r.action NOT IN ('withdraw','gpc')
11
+ AND (s.expires_at IS NULL OR s.expires_at > now())
12
+ ORDER BY s.effective_at DESC LIMIT 1`,[e.siteId,a])).rows[0]?.latest_receipt_id;if(!l)return!1;let m=e.verifiedAt&&Number.isFinite(Date.parse(e.verifiedAt))?new Date(e.verifiedAt).toISOString():new Date().toISOString(),_=k(JSON.stringify({schemaVersion:1,displayName:t,email:s,phone:n,evidenceType:e.evidenceType,verifiedAt:m}),"identity-profile");return await i.query(`INSERT INTO analytics_restricted_data(id,site_id,person_id,purpose,subject_ref,payload_ciphertext,expires_at,consent_receipt_id)
13
+ VALUES($1,$2,$3,$4,$5,$6,now()+($7::int * interval '1 day'),$8)
14
+ ON CONFLICT(site_id,purpose,subject_ref) DO UPDATE SET
15
+ person_id=EXCLUDED.person_id,payload_ciphertext=EXCLUDED.payload_ciphertext,
16
+ expires_at=EXCLUDED.expires_at,consent_receipt_id=EXCLUDED.consent_receipt_id,created_at=now()`,[v(),e.siteId,e.personId,M,o,_,Q,l]),!0}async function Re(i,e){let t=e.now??new Date,s=await i.query("SELECT role FROM analytics_site_grants WHERE site_id=$1 AND user_id=$2",[e.siteId,e.actorUserId]);if(!s.rowCount)throw new f("analytics_site_not_found","Site not found.",404);if(!["owner","editor"].includes(s.rows[0].role))throw new f("analytics_forbidden","Editor access is required.",403);let n=await i.query(`SELECT count(*)::text AS count FROM analytics_identity_profile_access_audits
17
+ WHERE site_id=$1 AND actor_user_id=$2 AND created_at > $3::timestamptz - interval '1 minute'`,[e.siteId,e.actorUserId,t.toISOString()]);if(Number(n.rows[0]?.count??0)>=ee)throw await i.query(`INSERT INTO analytics_identity_profile_access_audits(id,site_id,actor_user_id,subject_ref_hmac,purpose,result,created_at)
18
+ VALUES($1,$2,$3,$4,'journey_identity_display','rate_limited',$5)`,[v(),e.siteId,e.actorUserId,O(e.requestedPersonRef),t.toISOString()]),new f("analytics_identity_profile_rate_limited","Identity profile rate limit exceeded.",429);let r=async _=>{throw await i.query(`INSERT INTO analytics_identity_profile_access_audits(id,site_id,actor_user_id,subject_ref_hmac,purpose,result,created_at)
19
+ VALUES($1,$2,$3,$4,'journey_identity_display',$5,$6)`,[v(),e.siteId,e.actorUserId,O(e.requestedPersonRef),_,t.toISOString()]),new f("analytics_identity_profile_not_found","Identity profile not found.",404)};if(!e.personId)return r("not_found");let o=await i.query(`SELECT p.public_ref,r.payload_ciphertext,r.expires_at
20
+ FROM analytics_people p
21
+ JOIN analytics_restricted_data r ON r.person_id=p.id AND r.site_id=p.site_id
22
+ AND r.purpose=$3 AND r.subject_ref=p.public_ref AND r.expires_at>$4
23
+ JOIN analytics_consent_current_state s ON s.site_id=p.site_id AND s.latest_receipt_id=r.consent_receipt_id
24
+ AND s.site_analytics=true AND s.enhanced_matching=true AND s.gpc=false
25
+ AND (s.expires_at IS NULL OR s.expires_at>$4)
26
+ JOIN analytics_consent_receipts c ON c.id=s.latest_receipt_id AND c.site_id=s.site_id
27
+ AND c.action NOT IN ('withdraw','gpc')
28
+ WHERE p.id=$1 AND p.site_id=$2
29
+ AND NOT EXISTS (SELECT 1 FROM analytics_identity_tombstones t WHERE t.site_id=p.site_id AND t.person_id=p.id)
30
+ LIMIT 1`,[e.personId,e.siteId,M,t.toISOString()]);if(!o.rowCount)return r("not_found");let a=U(o.rows[0].payload_ciphertext,"identity-profile");if(!a)return r("unavailable");let d;try{d=JSON.parse(a)}catch{return r("unavailable")}let l=d.evidenceType;if(!["first_party_form","authenticated_user","crm_contact"].includes(String(l)))return r("unavailable");let m={personRef:e.requestedPersonRef,displayName:A(typeof d.displayName=="string"?d.displayName:void 0,160),maskedEmail:ie(typeof d.email=="string"?d.email:null),maskedPhone:te(typeof d.phone=="string"?d.phone:null),evidenceType:l,verifiedAt:typeof d.verifiedAt=="string"&&Number.isFinite(Date.parse(d.verifiedAt))?new Date(d.verifiedAt).toISOString():t.toISOString()};return await i.query(`INSERT INTO analytics_identity_profile_access_audits(id,site_id,person_id,actor_user_id,subject_ref_hmac,purpose,result,created_at)
31
+ VALUES($1,$2,$3,$4,$5,'journey_identity_display','returned_masked',$6)`,[v(),e.siteId,e.personId,e.actorUserId,O(e.requestedPersonRef),t.toISOString()]),m}import{randomUUID as re}from"crypto";import{createHmac as se}from"crypto";var ne=new Set(["fbclid","gclid","gbraid","wbraid","ttclid","rdt_cid","msclkid","fbp","fbc","li_fat_id","snapclid"]);function w(i){let e={};for(let[t,s]of Object.entries(i??{})){if(!ne.has(t)||typeof s!="string")continue;let n=s.trim();n&&(e[t]=n.slice(0,500))}return e}function c(i,e){return se("sha256",g()).update(`${i}:${e.trim().toLowerCase()}`).digest("hex")}function oe(i){return i.consent?.analytics==="granted"&&(i.consent.purposes?.enhanced_matching==="granted"||i.consent.adUserData==="granted")&&i.consent.globalPrivacyControl!==!0}function be(i){return!!(i.identity&&oe(i))}async function Pe(i,e){let t=e.event.visitorId?.trim().slice(0,240),s=e.event.consent;if(!t||!s)return null;let n=Date.parse(e.event.occurredAt),r=Date.now();if(!Number.isFinite(n)||n>r+5*6e4||n<r-1440*6e4)return null;let o=s.purposes,a={siteAnalytics:o?o.site_analytics==="granted":s.analytics==="granted",enhancedMatching:o?o.enhanced_matching==="granted":s.adUserData==="granted",advertisingMeasurement:o?o.advertising_measurement==="granted":s.adPersonalization==="granted"},d=s.globalPrivacyControl===!0;d&&(a.siteAnalytics=!1,a.enhancedMatching=!1,a.advertisingMeasurement=!1);let l=d?"gpc":Object.values(a).every(Boolean)?"accept_all":Object.values(a).every(R=>!R)?"reject_all":"save_choices",m=new Date(n).toISOString(),y=(await i.query(`SELECT s.latest_receipt_id::text,s.site_analytics,s.enhanced_matching,s.advertising_measurement,s.gpc,r.action
32
+ FROM analytics_consent_current_state s JOIN analytics_consent_receipts r ON r.id=s.latest_receipt_id
33
+ WHERE s.site_id=$1 AND s.subject_ref=$2 FOR UPDATE`,[e.siteId,t])).rows[0];if(y&&y.site_analytics===a.siteAnalytics&&y.enhanced_matching===a.enhancedMatching&&y.advertising_measurement===a.advertisingMeasurement&&y.gpc===d&&y.action===l)return y.latest_receipt_id;let I=re();return await i.query(`INSERT INTO analytics_consent_receipts(id,site_id,pixel_id,subject_ref,policy_version,jurisdiction_profile,
34
+ necessary,site_analytics,enhanced_matching,advertising_measurement,gpc,action,source,presented_at,occurred_at,supersedes_id)
35
+ VALUES($1,$2,$3,$4,1,'pixel',true,$5,$6,$7,$8,$9,'gateway',$10,$10,$11)`,[I,e.siteId,e.pixelId,t,a.siteAnalytics,a.enhancedMatching,a.advertisingMeasurement,d,l,m,y?.latest_receipt_id??null]),await i.query(`INSERT INTO analytics_consent_current_state(site_id,subject_ref,latest_receipt_id,policy_version,jurisdiction_profile,
36
+ necessary,site_analytics,enhanced_matching,advertising_measurement,gpc,effective_at)
37
+ VALUES($1,$2,$3,1,'pixel',true,$4,$5,$6,$7,$8)
38
+ ON CONFLICT(site_id,subject_ref) DO UPDATE SET latest_receipt_id=EXCLUDED.latest_receipt_id,
39
+ policy_version=EXCLUDED.policy_version,jurisdiction_profile=EXCLUDED.jurisdiction_profile,
40
+ site_analytics=EXCLUDED.site_analytics,enhanced_matching=EXCLUDED.enhanced_matching,
41
+ advertising_measurement=EXCLUDED.advertising_measurement,gpc=EXCLUDED.gpc,
42
+ effective_at=EXCLUDED.effective_at,updated_at=now()
43
+ WHERE EXCLUDED.effective_at>=analytics_consent_current_state.effective_at`,[e.siteId,t,I,a.siteAnalytics,a.enhancedMatching,a.advertisingMeasurement,d,m]),I}async function xe(i,e){if(!e.subjectRef)return{personId:null,activationEligible:!1};let s=(await i.query(`SELECT p.id::text AS person_id,s.advertising_measurement
44
+ FROM analytics_people p
45
+ JOIN analytics_consent_current_state s ON s.site_id=p.site_id AND s.subject_ref=$2
46
+ JOIN analytics_consent_receipts r ON r.id=s.latest_receipt_id AND r.site_id=s.site_id
47
+ WHERE p.site_id=$1
48
+ AND (($3::uuid IS NOT NULL AND p.id=$3) OR ($4::text IS NOT NULL AND EXISTS (
49
+ SELECT 1 FROM analytics_events e WHERE e.site_id=p.site_id AND e.event_id=$4
50
+ AND e.person_id=p.id AND e.visitor_id=$2
51
+ )))
52
+ AND s.site_analytics=true AND s.gpc=false AND r.action NOT IN ('withdraw','gpc')
53
+ AND (s.expires_at IS NULL OR s.expires_at>now()) LIMIT 1`,[e.siteId,e.subjectRef,e.personId??null,e.eventId??null])).rows[0];return s?{personId:s.person_id,activationEligible:s.advertising_measurement===!0}:{personId:null,activationEligible:!1}}async function C(i,e,t,s){return!t?.trim()||!s?.trim()?!1:!!(await i.query(`SELECT 1 FROM analytics_consent_current_state s
54
+ JOIN analytics_consent_receipts r ON r.id=s.latest_receipt_id AND r.site_id=s.site_id
55
+ WHERE s.site_id=$1 AND s.subject_ref=$2
56
+ AND s.site_analytics=true AND s.enhanced_matching=true AND s.gpc=false
57
+ AND r.action NOT IN ('withdraw','gpc')
58
+ AND (s.expires_at IS NULL OR s.expires_at>now())
59
+ AND EXISTS (SELECT 1 FROM analytics_sessions x
60
+ WHERE x.site_id=s.site_id AND x.visitor_hmac=$3 AND x.session_hmac=$4)
61
+ ORDER BY s.effective_at DESC LIMIT 1`,[e,t,c("visitor_id",t),c("session_id",s)])).rowCount}async function H(i,e,t){return!!(await i.query(`SELECT 1 FROM analytics_consent_current_state s
62
+ JOIN analytics_consent_receipts r ON r.id=s.latest_receipt_id AND r.site_id=s.site_id
63
+ WHERE s.site_id=$1 AND s.subject_ref=$2
64
+ AND s.site_analytics=true AND s.enhanced_matching=true AND s.gpc=false
65
+ AND r.action NOT IN ('withdraw','gpc')
66
+ AND (s.expires_at IS NULL OR s.expires_at>now()) LIMIT 1`,[e,t])).rowCount}import{createHash as ae}from"crypto";function He(i,e){let t=i?.trim().toUpperCase();return t&&/^[A-Z0-9-]+$/.test(t)?t.slice(0,e):null}function q(i,e,t){return ae("sha256").update(JSON.stringify({scope:i,siteId:e,filters:t})).digest("base64url").slice(0,18)}function de(i,e){if(!i)return 0;try{let t=JSON.parse(Buffer.from(i,"base64url").toString("utf8"));if(t.v!==1||t.f!==e||!Number.isInteger(t.o)||Number(t.o)<0)throw new Error("invalid");return Number(t.o)}catch{throw new u("invalid_cursor","The pagination cursor is invalid for these filters.")}}function F(i,e,t){if(!e)return{items:i,pageInfo:{hasNextPage:!1,nextCursor:null}};let s=Math.min(100,Math.max(1,Math.trunc(e?.limit??25))),n=de(e?.cursor,t),r=i.slice(n,n+s),o=n+r.length<i.length;return{items:r,pageInfo:{hasNextPage:o,nextCursor:o?Buffer.from(JSON.stringify({v:1,f:t,o:n+r.length})).toString("base64url"):null}}}async function S(i,e,t){let n=(await i.query("SELECT role FROM analytics_site_grants WHERE site_id = $1 AND user_id = $2",[e,t])).rows[0]?.role;if(!n)throw new u("analytics_site_not_found","Site not found.",404);return n}async function ce(i,e,t){let s=await S(i,e,t);if(s==="viewer")throw new u("analytics_forbidden","Editor access is required.",403);return s}async function We(i,e,t){return S(i,e,t)}async function je(i,e,t){return ce(i,e,t)}async function Qe(i){for(;;){let t=await i.query(`SELECT id, visitor_id, session_id
67
+ FROM analytics_events
68
+ WHERE (visitor_id IS NOT NULL AND visitor_hmac IS NULL)
69
+ OR (session_id IS NOT NULL AND session_hmac IS NULL)
70
+ ORDER BY id
71
+ LIMIT $1`,[500]);if(!t.rowCount)break;await i.query(`UPDATE analytics_events e
72
+ SET visitor_hmac = COALESCE(e.visitor_hmac, patch.visitor_hmac),
73
+ session_hmac = COALESCE(e.session_hmac, patch.session_hmac)
74
+ FROM unnest($1::uuid[], $2::text[], $3::text[]) AS patch(id, visitor_hmac, session_hmac)
75
+ WHERE e.id = patch.id`,[t.rows.map(s=>s.id),t.rows.map(s=>s.visitor_id?c("visitor_id",s.visitor_id):null),t.rows.map(s=>s.session_id?c("session_id",s.session_id):null)])}for(;;){let t=await i.query(`SELECT id, session_id
76
+ FROM analytics_conversions
77
+ WHERE session_id IS NOT NULL AND session_hmac IS NULL
78
+ ORDER BY id
79
+ LIMIT $1`,[500]);if(!t.rowCount)break;await i.query(`UPDATE analytics_conversions c
80
+ SET session_hmac = patch.session_hmac
81
+ FROM unnest($1::uuid[], $2::text[]) AS patch(id, session_hmac)
82
+ WHERE c.id = patch.id AND c.session_hmac IS NULL`,[t.rows.map(s=>s.id),t.rows.map(s=>c("session_id",s.session_id))])}}function W(){return`xrp_${_e(18).toString("base64url")}`}function ei(i,e){let t=c("crm_entity_id",`${i}:${e}`).slice(0,32).split("");return t[12]="5",t[16]=["8","9","a","b"][Number.parseInt(t[16],16)%4],`${t.slice(0,8).join("")}-${t.slice(8,12).join("")}-${t.slice(12,16).join("")}-${t.slice(16,20).join("")}-${t.slice(20).join("")}`}async function j(i,e,t){let s=await i.query("SELECT id FROM analytics_identity_namespaces WHERE site_id=$1 AND status='approved' ORDER BY version DESC LIMIT 1",[e]);s.rows[0]||(await i.query(`INSERT INTO analytics_identity_namespaces(
83
+ id,site_id,name,status,approved_hosts,approved_sources,version,approved_by_user_id,approved_at
84
+ )
85
+ SELECT $1,s.id,'X-Ray primary','approved',
86
+ COALESCE((SELECT jsonb_agg(d.hostname ORDER BY d.hostname)
87
+ FROM analytics_pixels p
88
+ JOIN analytics_pixel_domains d ON d.pixel_id=p.id AND d.state='approved'
89
+ WHERE p.site_id=s.id),'[]'::jsonb),
90
+ $3::jsonb,1,s.owner_user_id,now()
91
+ FROM analytics_sites s WHERE s.id=$2
92
+ ON CONFLICT(site_id,name,version) DO NOTHING`,[p(),e,JSON.stringify([t])]),s=await i.query("SELECT id FROM analytics_identity_namespaces WHERE site_id=$1 AND status='approved' ORDER BY version DESC LIMIT 1",[e]));let n=s.rows[0]?.id;if(!n)throw new u("identity_namespace_unavailable","The Site identity graph could not be initialized.",409);return await i.query(`UPDATE analytics_identity_namespaces
93
+ SET approved_sources=(SELECT jsonb_agg(value ORDER BY value)
94
+ FROM (SELECT DISTINCT value
95
+ FROM jsonb_array_elements_text(approved_sources || $3::jsonb)) merged_sources),
96
+ approved_hosts=(SELECT COALESCE(jsonb_agg(hostname ORDER BY hostname),'[]'::jsonb)
97
+ FROM (SELECT DISTINCT hostname
98
+ FROM (SELECT jsonb_array_elements_text(approved_hosts) AS hostname
99
+ UNION ALL
100
+ SELECT d.hostname
101
+ FROM analytics_pixels p
102
+ JOIN analytics_pixel_domains d ON d.pixel_id=p.id AND d.state='approved'
103
+ WHERE p.site_id=$2) hosts) distinct_hosts),
104
+ updated_at=now()
105
+ WHERE id=$1 AND site_id=$2`,[n,e,JSON.stringify([t])]),n}async function le(i,e){if(!e.visitorId&&!e.sessionId)return{events:0,sessions:0,touches:0,conversions:0};let t=e.visitorId?c("visitor_id",e.visitorId):null,s=e.sessionId?c("session_id",e.sessionId):null,n=await i.query(`UPDATE analytics_events SET person_id = $1 WHERE site_id = $2 AND person_id IS NULL
106
+ AND (($3::text IS NOT NULL AND visitor_id = $3) OR ($4::text IS NOT NULL AND session_id = $4))`,[e.personId,e.siteId,e.visitorId??null,e.sessionId??null]),r=await i.query(`UPDATE analytics_conversions SET person_id = $1 WHERE site_id = $2 AND person_id IS NULL
107
+ AND $3::text IS NOT NULL AND session_id = $3`,[e.personId,e.siteId,e.sessionId??null]),o=await i.query(`UPDATE analytics_sessions SET person_id = $1
108
+ WHERE site_id = $2 AND person_id IS NULL
109
+ AND (($3::text IS NOT NULL AND visitor_hmac = $3)
110
+ OR ($4::text IS NOT NULL AND session_hmac = $4))`,[e.personId,e.siteId,t,s]),a=await i.query(`UPDATE analytics_attribution_touches SET person_id = $1
111
+ WHERE site_id = $2 AND person_id IS NULL
112
+ AND (($3::text IS NOT NULL AND visitor_hmac = $3)
113
+ OR ($4::text IS NOT NULL AND session_id IN (
114
+ SELECT id FROM analytics_sessions
115
+ WHERE site_id = $2 AND session_hmac = $4
116
+ )))`,[e.personId,e.siteId,t,s]);return{events:n.rowCount??0,sessions:o.rowCount??0,touches:a.rowCount??0,conversions:r.rowCount??0}}async function L(i,e){let s=(await i.query(`SELECT id FROM analytics_people
117
+ WHERE site_id=$1 AND (namespace_id=$2 OR namespace_id IS NULL)
118
+ AND (($3::uuid IS NOT NULL AND crm_entity_id=$3::uuid)
119
+ OR ($3::uuid IS NULL AND $4::text IS NOT NULL AND crm_person_ref=$4))
120
+ ORDER BY first_seen_at,id LIMIT 1 FOR UPDATE`,[e.siteId,e.namespaceId,e.crmEntityId??null,e.crmPersonRef??null])).rows[0]?.id;if(!s&&!e.crmEntityId&&!e.crmPersonRef&&e.signals.length&&(s=(await i.query(`SELECT assignment.person_id
121
+ FROM analytics_identity_nodes node
122
+ JOIN analytics_identity_assignments assignment
123
+ ON assignment.identity_node_id=node.id AND assignment.site_id=node.site_id
124
+ WHERE node.site_id=$1 AND EXISTS (
125
+ SELECT 1 FROM jsonb_to_recordset($2::jsonb) signal(kind text,value_hmac text)
126
+ WHERE signal.kind=node.kind AND signal.value_hmac=node.value_hmac
127
+ )
128
+ ORDER BY assignment.assigned_at,assignment.person_id LIMIT 1`,[e.siteId,JSON.stringify(e.signals.map(r=>({kind:r.kind,value_hmac:r.valueHmac})))])).rows[0]?.person_id),s)await i.query(`UPDATE analytics_people SET last_seen_at=now(),
129
+ namespace_id=COALESCE(namespace_id,$2),
130
+ crm_entity_id=COALESCE(crm_entity_id,$3::uuid),
131
+ public_ref=COALESCE(public_ref,$4)
132
+ WHERE id=$1 AND site_id=$5`,[s,e.namespaceId,e.crmEntityId??null,W(),e.siteId]);else{let n=e.crmEntityId??null,r=e.crmPersonRef??(n?`XRay::entity::${n}`:`XRay::anonymous::${p()}`);s=(await i.query(`INSERT INTO analytics_people(id,site_id,namespace_id,crm_person_ref,crm_entity_id,public_ref)
133
+ VALUES($1,$2,$3,$4,$5::uuid,$6)
134
+ ON CONFLICT(site_id,crm_person_ref) DO UPDATE SET last_seen_at=now(),
135
+ namespace_id=COALESCE(analytics_people.namespace_id,EXCLUDED.namespace_id),
136
+ crm_entity_id=COALESCE(analytics_people.crm_entity_id,EXCLUDED.crm_entity_id),
137
+ public_ref=COALESCE(analytics_people.public_ref,EXCLUDED.public_ref)
138
+ RETURNING id`,[p(),e.siteId,e.namespaceId,r,n,W()])).rows[0].id}return{personId:s,mergedPersonIds:[]}}async function b(i,e){let s=(await i.query(`SELECT person_id,crm_entity_id::text FROM analytics_identity_assignments
139
+ WHERE identity_node_id=$1 AND site_id=$2 FOR UPDATE`,[e.identityNodeId,e.siteId])).rows[0];if(!s){await i.query(`INSERT INTO analytics_identity_assignments(
140
+ identity_node_id,site_id,person_id,crm_entity_id,evidence_kind
141
+ ) VALUES($1,$2,$3,$4::uuid,$5)
142
+ ON CONFLICT(identity_node_id) DO NOTHING`,[e.identityNodeId,e.siteId,e.personId,e.crmEntityId??null,e.evidenceKind]);let n=await i.query("SELECT person_id FROM analytics_identity_assignments WHERE identity_node_id=$1 AND site_id=$2",[e.identityNodeId,e.siteId]);if(n.rows[0]?.person_id===e.personId)return"assigned";if(!n.rows[0])throw new u("identity_assignment_unavailable","Identity assignment could not be recorded.",409);s={person_id:n.rows[0].person_id,crm_entity_id:null}}return s.person_id===e.personId?(await i.query(`UPDATE analytics_identity_assignments SET updated_at=now(),
143
+ crm_entity_id=COALESCE(crm_entity_id,$3::uuid),evidence_kind=$4
144
+ WHERE identity_node_id=$1 AND site_id=$2`,[e.identityNodeId,e.siteId,e.crmEntityId??null,e.evidenceKind]),"existing"):(await i.query(`INSERT INTO analytics_identity_assignment_conflicts(
145
+ id,site_id,identity_node_id,active_person_id,attempted_person_id,
146
+ active_crm_entity_id,attempted_crm_entity_id,evidence_kind
147
+ ) VALUES($1,$2,$3,$4,$5,$6::uuid,$7::uuid,$8)
148
+ ON CONFLICT(identity_node_id,active_person_id,attempted_person_id)
149
+ WHERE status='pending' DO UPDATE SET observed_at=now(),evidence_kind=EXCLUDED.evidence_kind`,[p(),e.siteId,e.identityNodeId,s.person_id,e.personId,s.crm_entity_id,e.crmEntityId??null,e.evidenceKind]),"conflict")}async function me(i,e){let s=(await i.query(`WITH person_nodes AS (
150
+ SELECT DISTINCT identity_node_id
151
+ FROM analytics_identity_edges
152
+ WHERE site_id=$1 AND namespace_id=$2 AND person_id=$3
153
+ )
154
+ UPDATE analytics_candidate_associations a
155
+ SET status='promoted',promoted_person_id=$3,promoted_at=$4::timestamptz,updated_at=now()
156
+ WHERE a.site_id=$1 AND a.namespace_id=$2
157
+ AND (a.left_identity_node_id IN (SELECT identity_node_id FROM person_nodes)
158
+ OR a.right_identity_node_id IN (SELECT identity_node_id FROM person_nodes))
159
+ AND (a.status IN ('active','expired') OR (a.status='promoted' AND a.promoted_person_id=$3))
160
+ RETURNING a.id`,[e.siteId,e.namespaceId,e.personId,e.occurredAt])).rows.map(r=>r.id);if(!s.length)return{associationIds:[],touches:0};for(let r of s)await i.query(`INSERT INTO analytics_candidate_promotions(
161
+ id,site_id,namespace_id,association_id,person_id,evidence_kind,
162
+ evidence_ref_hmac,promoted_by,promoted_at
163
+ ) VALUES($1,$2,$3,$4,$5,$6,$7,'system',$8::timestamptz)
164
+ ON CONFLICT(association_id,person_id) DO NOTHING`,[p(),e.siteId,e.namespaceId,r,e.personId,e.candidateEvidenceKind,e.evidenceRefHmac,e.occurredAt]);let n=await i.query(`UPDATE analytics_attribution_touches touch SET person_id=$3
165
+ FROM analytics_candidate_attribution_touches candidate_touch
166
+ WHERE candidate_touch.site_id=$1 AND candidate_touch.namespace_id=$2
167
+ AND candidate_touch.association_id=ANY($4::uuid[])
168
+ AND candidate_touch.touch_id=touch.id AND touch.site_id=$1 AND touch.person_id IS NULL`,[e.siteId,e.namespaceId,e.personId,s]);return{associationIds:s,touches:n.rowCount??0}}async function ye(i,e){let t=c("promotion_evidence",`${e.evidenceKind}:${e.evidenceRef}`),s=c("promotion_person",e.personId),n=c("promotion_receipt",`${e.siteId}:${e.personId}:${e.evidenceKind}:${e.evidenceRef}`);await i.query(`INSERT INTO analytics_identity_promotion_receipts(
169
+ id,site_id,namespace_id,canonical_person_id,canonical_person_ref_hmac,
170
+ evidence_kind,evidence_ref_hmac,prior_person_ids,prior_identity_node_ids,
171
+ candidate_association_ids,affected_history_counts,schema_version,idempotency_key,promoted_at
172
+ ) VALUES($1,$2,$3,$4,$5,$6,$7,$8::uuid[],$9::uuid[],$10::uuid[],$11::jsonb,
173
+ 'xray.identity-promotion.v1',$12,$13::timestamptz)
174
+ ON CONFLICT(site_id,idempotency_key) DO NOTHING`,[p(),e.siteId,e.namespaceId,e.personId,s,e.evidenceKind,t,e.priorPersonIds,e.priorIdentityNodeIds,e.candidateAssociationIds,JSON.stringify({...e.history,candidateTouches:e.candidateTouches}),n,e.occurredAt])}async function P(i,e){let t=e.occurredAt??new Date().toISOString(),s=await le(i,e),n=c("promotion_evidence",`${e.evidenceKind}:${e.evidenceRef}`),r=await me(i,{siteId:e.siteId,namespaceId:e.namespaceId,personId:e.personId,candidateEvidenceKind:e.candidateEvidenceKind,evidenceRefHmac:n,occurredAt:t});await ye(i,{...e,history:s,candidateAssociationIds:r.associationIds,candidateTouches:r.touches,occurredAt:t})}async function ii(i,e){let t=e.customerId||e.orderId||e.email||e.phone;if(!t||!await C(i,e.siteId,e.visitorId,e.sessionId))return null;let s=await j(i,e.siteId,"pixel"),n=[...e.email?[{kind:"email",valueHmac:c("email",e.email)}]:[],...e.phone?[{kind:"phone",valueHmac:c("phone",e.phone)}]:[],...e.customerId?[{kind:"customer_id",valueHmac:c("customer_id",e.customerId)}]:[],...e.orderId?[{kind:"customer_id",valueHmac:c("customer_id",`order:${e.orderId}`)}]:[]];await h(i,{siteId:e.siteId,signals:n});let r=`XRay::${c("person_ref",t).slice(0,24)}`,o=[...n,...e.visitorId?[{kind:"visitor_id",valueHmac:c("visitor_id",e.visitorId)}]:[],...e.sessionId?[{kind:"session_id",valueHmac:c("session_id",e.sessionId)}]:[]],a=await L(i,{siteId:e.siteId,namespaceId:s,crmPersonRef:r,signals:o}),d=a.personId,l=[];e.visitorId&&l.push({kind:"visitor_id",value:e.visitorId,evidence:"pixel_identify",confidence:.98}),e.sessionId&&l.push({kind:"session_id",value:e.sessionId,evidence:"pixel_identify",confidence:.98}),e.email&&l.push({kind:"email",value:e.email,evidence:"pixel_identify",confidence:1}),e.phone&&l.push({kind:"phone",value:e.phone,evidence:"pixel_identify",confidence:.99}),e.customerId&&l.push({kind:"customer_id",value:e.customerId,evidence:"customer_id",confidence:1}),e.orderId&&l.push({kind:"customer_id",value:`order:${e.orderId}`,evidence:"order_id",confidence:1});for(let[y,I]of Object.entries(w(e.clickIds)))l.push({kind:"click_id",value:`${y}:${I}`,evidence:y,confidence:.9});let m=[],_=!1;for(let y of l){let I=await i.query(`INSERT INTO analytics_identity_nodes(id, site_id, namespace_id, kind, value_hmac) VALUES ($1,$2,$3,$4,$5)
175
+ ON CONFLICT(site_id, kind, value_hmac) DO UPDATE SET last_seen_at = now(),
176
+ namespace_id=COALESCE(analytics_identity_nodes.namespace_id,EXCLUDED.namespace_id) RETURNING id`,[p(),e.siteId,s,y.kind,c(y.kind,y.value)]);m.push(I.rows[0].id),await i.query(`INSERT INTO analytics_identity_edges(id, site_id, namespace_id, person_id, identity_node_id, evidence_kind, confidence)
177
+ VALUES ($1,$2,$3,$4,$5,$6,$7)
178
+ ON CONFLICT(person_id, identity_node_id, evidence_kind) DO UPDATE
179
+ SET last_seen_at = now(), confidence = greatest(analytics_identity_edges.confidence, EXCLUDED.confidence),
180
+ namespace_id=COALESCE(analytics_identity_edges.namespace_id,EXCLUDED.namespace_id)`,[p(),e.siteId,s,d,I.rows[0].id,y.evidence,y.confidence]);let R=await b(i,{siteId:e.siteId,personId:d,identityNodeId:I.rows[0].id,evidenceKind:y.evidence});_||=R==="conflict"}return _||await P(i,{siteId:e.siteId,namespaceId:s,personId:d,evidenceKind:e.customerId?"authenticated_login":"browser_identify",candidateEvidenceKind:e.email?"verified_email":e.phone?"verified_phone":"authenticated_user",evidenceRef:t,priorPersonIds:a.mergedPersonIds,priorIdentityNodeIds:m,visitorId:e.visitorId,sessionId:e.sessionId,occurredAt:e.occurredAt}),e.customerId&&!_&&await $(i,{siteId:e.siteId,personId:d,consentSubjectRefs:[e.visitorId??"",e.sessionId??""],evidenceType:"authenticated_user",email:e.email,phone:e.phone}),d}async function ti(i){let e=await E().connect();try{if(await e.query("BEGIN"),!await C(e,i.siteId,i.visitorId,i.sessionId))return await e.query("COMMIT"),{personId:null,linkedSignals:0,conflicts:0};let t=await j(e,i.siteId,"form"),s=[...i.email?[{kind:"email",valueHmac:c("email",i.email)}]:[],...i.phone?[{kind:"phone",valueHmac:c("phone",i.phone)}]:[]];await h(e,{siteId:i.siteId,signals:s});let n=[...s,...i.visitorId?[{kind:"visitor_id",valueHmac:c("visitor_id",i.visitorId)}]:[],...i.sessionId?[{kind:"session_id",valueHmac:c("session_id",i.sessionId)}]:[]],r=await L(e,{siteId:i.siteId,namespaceId:t,crmPersonRef:i.crmPersonRef,crmEntityId:i.crmEntityId,signals:n}),o=r.personId,a=[];i.visitorId&&a.push({kind:"visitor_id",value:i.visitorId,evidence:"first_party_form",confidence:.98}),i.sessionId&&a.push({kind:"session_id",value:i.sessionId,evidence:"first_party_form",confidence:.95}),i.email&&a.push({kind:"email",value:i.email,evidence:"submitted_email",confidence:1}),i.phone&&a.push({kind:"phone",value:i.phone,evidence:"submitted_phone",confidence:.99});for(let[m,_]of Object.entries(w(i.clickIds)))a.push({kind:"click_id",value:`${m}:${_}`,evidence:m,confidence:.9});let d=[],l=0;for(let m of a){let _=await e.query(`INSERT INTO analytics_identity_nodes(id, site_id, namespace_id, kind, value_hmac) VALUES ($1,$2,$3,$4,$5)
181
+ ON CONFLICT(site_id, kind, value_hmac) DO UPDATE SET last_seen_at = now(),
182
+ namespace_id=COALESCE(analytics_identity_nodes.namespace_id,EXCLUDED.namespace_id) RETURNING id`,[p(),i.siteId,t,m.kind,c(m.kind,m.value)]);d.push(_.rows[0].id),await e.query(`INSERT INTO analytics_identity_edges(id, site_id, namespace_id, person_id, identity_node_id, evidence_kind, confidence)
183
+ VALUES ($1,$2,$3,$4,$5,$6,$7)
184
+ ON CONFLICT(person_id, identity_node_id, evidence_kind) DO UPDATE SET last_seen_at = now(),
185
+ confidence = greatest(analytics_identity_edges.confidence, EXCLUDED.confidence),
186
+ namespace_id=COALESCE(analytics_identity_edges.namespace_id,EXCLUDED.namespace_id)`,[p(),i.siteId,t,o,_.rows[0].id,m.evidence,m.confidence]),await b(e,{siteId:i.siteId,personId:o,crmEntityId:i.crmEntityId,identityNodeId:_.rows[0].id,evidenceKind:m.evidence})==="conflict"&&(l+=1)}return i.submissionId&&await e.query("UPDATE analytics_form_submissions SET person_id = $1 WHERE id = $2 AND site_id = $3",[o,i.submissionId,i.siteId]),l===0&&await P(e,{siteId:i.siteId,namespaceId:t,personId:o,evidenceKind:"form_fill",candidateEvidenceKind:i.email?"verified_email":i.phone?"verified_phone":"authenticated_user",evidenceRef:i.submissionId??i.crmEntityId??i.crmPersonRef??o,priorPersonIds:r.mergedPersonIds,priorIdentityNodeIds:d,visitorId:i.visitorId,sessionId:i.sessionId}),l===0&&await $(e,{siteId:i.siteId,personId:o,consentSubjectRefs:[i.visitorId??""],evidenceType:i.evidenceType??"first_party_form",displayName:i.displayName,email:i.email,phone:i.phone}),await e.query("COMMIT"),{personId:o,linkedSignals:a.length,conflicts:l}}catch(t){throw await e.query("ROLLBACK"),t}finally{e.release()}}async function si(i){let e=await E().connect();try{await e.query("BEGIN");let s=(await e.query(`SELECT p.id,p.public_ref,p.namespace_id FROM analytics_people p
187
+ JOIN analytics_identity_namespaces n ON n.id=p.namespace_id AND n.site_id=p.site_id AND n.status='approved'
188
+ WHERE p.site_id=$1 AND p.crm_person_ref=$2 LIMIT 1 FOR UPDATE OF p`,[i.siteId,i.crmPersonRef])).rows[0];if(!s||!await H(e,i.siteId,s.public_ref))return await e.query("COMMIT"),{personId:null,linkedSignals:0,conflicts:0};let n=[...i.email?[{kind:"email",value:i.email,confidence:1}]:[],...i.phone?[{kind:"phone",value:i.phone,confidence:.99}]:[]];await h(e,{siteId:i.siteId,signals:n.map(_=>({kind:_.kind,valueHmac:c(_.kind,_.value)}))});let r=await L(e,{siteId:i.siteId,namespaceId:s.namespace_id,crmPersonRef:i.crmPersonRef,crmEntityId:i.crmEntityId,signals:n.map(_=>({kind:_.kind,valueHmac:c(_.kind,_.value)}))}),o=r.personId,d=(await e.query("SELECT public_ref FROM analytics_people WHERE id=$1 AND site_id=$2",[o,i.siteId])).rows[0]?.public_ref??s.public_ref,l=[],m=0;for(let _ of n){let y=await e.query(`INSERT INTO analytics_identity_nodes(id,site_id,namespace_id,kind,value_hmac) VALUES($1,$2,$3,$4,$5)
189
+ ON CONFLICT(site_id,kind,value_hmac) DO UPDATE SET last_seen_at=now(),
190
+ namespace_id=COALESCE(analytics_identity_nodes.namespace_id,EXCLUDED.namespace_id) RETURNING id`,[p(),i.siteId,s.namespace_id,_.kind,c(_.kind,_.value)]);l.push(y.rows[0].id),await e.query(`INSERT INTO analytics_identity_edges(id,site_id,namespace_id,person_id,identity_node_id,evidence_kind,confidence)
191
+ VALUES($1,$2,$3,$4,$5,'crm_contact',$6)
192
+ ON CONFLICT(person_id,identity_node_id,evidence_kind) DO UPDATE SET last_seen_at=now(),
193
+ confidence=greatest(analytics_identity_edges.confidence,EXCLUDED.confidence)`,[p(),i.siteId,s.namespace_id,o,y.rows[0].id,_.confidence]),await b(e,{siteId:i.siteId,personId:o,crmEntityId:i.crmEntityId,identityNodeId:y.rows[0].id,evidenceKind:"crm_contact"})==="conflict"&&(m+=1)}return m===0&&await P(e,{siteId:i.siteId,namespaceId:s.namespace_id,personId:o,evidenceKind:"crm_identity",candidateEvidenceKind:"crm_contact",evidenceRef:i.crmPersonRef,priorPersonIds:r.mergedPersonIds,priorIdentityNodeIds:l}),m===0&&await $(e,{siteId:i.siteId,personId:o,consentSubjectRefs:[d],evidenceType:"crm_contact",displayName:i.displayName,email:i.email,phone:i.phone}),await e.query("COMMIT"),{personId:o,linkedSignals:n.length,conflicts:m}}catch(t){throw await e.query("ROLLBACK"),t}finally{e.release()}}async function ni(i,e,t){let s=E();await S(s,i,e);let n=await s.query(`SELECT p.id, p.first_seen_at, p.last_seen_at, true AS crm_linked,
194
+ (SELECT count(*)::int FROM analytics_identity_edges e WHERE e.person_id = p.id) AS signal_count,
195
+ (SELECT count(*)::int FROM analytics_form_submissions f WHERE f.person_id = p.id) AS form_submission_count,
196
+ (SELECT count(*)::int FROM analytics_conversions c WHERE c.person_id = p.id) AS conversion_count,
197
+ (SELECT COALESCE(sum(c.value_minor), 0)::bigint FROM analytics_conversions c WHERE c.person_id = p.id) AS revenue_minor
198
+ FROM analytics_people p WHERE p.site_id = $1 ORDER BY p.last_seen_at DESC, p.id DESC LIMIT 1000`,[i]),r=F(n.rows,t,q("people",i,{start:"all",end:"all"}));return{people:r.items,pageInfo:r.pageInfo}}export{u as a,E as b,k as c,U as d,Ne as e,ve as f,Ae as g,w as h,c as i,f as j,Re as k,oe as l,be as m,Pe as n,xe as o,He as p,q,F as r,S as s,ce as t,We as u,je as v,Qe as w,W as x,ei as y,le as z,b as A,ii as B,ti as C,si as D,ni as E};
@@ -0,0 +1,2 @@
1
+ import{mkdirSync as p,openSync as f,writeFileSync as m,closeSync as c,unlinkSync as g}from"fs";import{homedir as S}from"os";import{join as s}from"path";var u=!0;function w(r){u=r}function d(r){return r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,80)||"mcp-scraper-report"}function R(r){return r.split(`
2
+ `).find(t=>t.startsWith("# "))?.replace(/^#\s+/,"").trim()||"MCP Scraper Report"}function v(r){return r?.trim()||process.env.MCP_SCRAPER_OUTPUT_DIR?.trim()||s(S(),"Downloads","mcp-scraper")}function C(r){if(!y())return null;let o=v(),t=null,e=null;try{p(o,{recursive:!0});let a=`${new Date().toISOString().replace(/[:.]/g,"-")}-${d(R(r))}`;for(let n=0;n<1e3;n++){let i=s(o,`${a}${n?"-"+n:""}.md`);try{t=f(i,"wx"),e=i;break}catch(l){if(l.code!=="EEXIST")throw l}}return t===null?null:(m(t,r,"utf8"),c(t),t=null,e)}catch{if(t!==null)try{c(t)}catch{}if(e!==null)try{g(e)}catch{}return null}}function y(){return u&&process.env.MCP_SCRAPER_SAVE_REPORTS!=="false"}export{w as a,d as b,v as c,C as d,y as e};
@@ -0,0 +1 @@
1
+ import{load as w}from"cheerio";var T="script,style,noscript,svg,iframe,canvas,nav,header,footer,aside",_=4096;function l(r){return(r??"").replace(/\s+/g," ").trim()}function C(r){let e=r.replace(/[\x00-\x09\x0b\x0c\x0e-\x1f]/g," ").trim();if(!e)return null;try{return JSON.parse(e)}catch(a){let o=/at position (\d+)/.exec(a instanceof Error?a.message:"")?.[1];if(!o)return null;try{return JSON.parse(e.slice(0,Number(o)))}catch{return null}}}function f(r,e,a={value:2e3}){if(a.value--<=0||r==null)return;if(Array.isArray(r)){for(let d of r)f(d,e,a);return}if(typeof r!="object")return;let o=r,c=o["@type"];if(typeof c=="string"&&c&&e.add(c),Array.isArray(c))for(let d of c)typeof d=="string"&&d&&e.add(d);Array.isArray(o["@graph"])&&f(o["@graph"],e,a)}function N(r){let e=r("main").first();if(e.length)return e;let a=r("article").first();if(a.length)return a;let o=r("body").first();return o.length?o:r.root()}function x(r,e){let a=Number(r.attr(e)??0);return Number.isFinite(a)&&a>0?a:null}function P(r){let e=w(r),a={};e("meta").each((m,s)=>{let t=e(s),n=l(t.attr("name")??t.attr("property")).toLowerCase(),i=l(t.attr("content"));n&&i&&(a[n]=i)});let o=[];e("h1,h2,h3,h4,h5,h6").each((m,s)=>{let t=e(s),n=l(t.text());n&&o.push({level:Number(s.tagName.slice(1)),text:n})});let c=[],d=new Set;e('script[type="application/ld+json"]').each((m,s)=>{let t=C(e(s).text());t!=null&&(Array.isArray(t)?c.push(...t):c.push(t),f(t,d))});let g=new Set;e("[itemtype]").each((m,s)=>{let t=e(s).attr("itemtype")??"";for(let n of t.split(/\s+/))try{let i=new URL(n);if(i.hostname==="schema.org"||i.hostname==="www.schema.org"){let h=i.pathname.replace(/^\/+/,"");h&&g.add(h)}}catch{}});let u=N(e).clone();u.find(T).remove(),u.find("[href],[src],[srcset],[data-src],[data-srcset]").each((m,s)=>{let t=e(s);for(let n of["href","src","srcset","data-src","data-srcset"]){let i=t.attr(n);i&&i.length>_&&t.removeAttr(n)}}),u.find("img").each((m,s)=>{let t=e(s),n=t.attr("src");if(!n||n.startsWith("data:")){let i=t.attr("data-src")??t.attr("data-lazy-src")??t.attr("data-original");i&&t.attr("src",i)}});let b=u.html()??"",A=l(u.text()),p=[];e("a[href]").each((m,s)=>{let t=e(s),n=l(t.attr("href"));n&&p.push({href:n,text:l(t.text()),rel:l(t.attr("rel")).toLowerCase()||null})});let y=[];return e("img").each((m,s)=>{let t=e(s),n=Object.fromEntries(Object.entries(s.attribs??{}).map(([i,h])=>[i.toLowerCase(),h]));y.push({src:t.attr("src")??t.attr("data-src")??t.attr("data-lazy-src")??t.attr("data-original")??null,srcset:t.attr("srcset")??t.attr("data-srcset")??null,alt:t.attr("alt")??null,width:x(t,"width"),height:x(t,"height"),attributes:n})}),{$:e,sourceHtml:r,title:l(e("title").first().text())||null,meta:a,headings:o,schema:c,schemaTypes:[...d],microdataTypes:[...g],canonicalUrl:l(e('link[rel~="canonical"]').first().attr("href"))||null,mainHtml:b,mainText:A,bodyClass:e("body").first().attr("class")??"",links:p,images:y}}export{P as a};
@@ -0,0 +1 @@
1
+ function u(e){if(Date.now()>=e)throw new Error("Reddit request deadline exhausted")}var t=class extends Error{constructor(n){super(`${n} deadline exceeded`),this.name="DeadlineExceededError"}};async function w(e,n,r,s=Number.POSITIVE_INFINITY){let o=Math.min(e-Date.now(),s);if(o<=0)throw new t(r);let T=Date.now()+o,i,a=Promise.resolve().then(()=>{if(Date.now()>=e)throw new t(r);return n()});try{let E=await Promise.race([a,new Promise((_,D)=>{i=setTimeout(()=>D(new t(r)),o)})]);if(Date.now()>=Math.min(e,T))throw new t(r);return E}finally{i&&clearTimeout(i)}}export{u as a,t as b,w as c};
@@ -0,0 +1 @@
1
+ import{c as f,d,e as p,h as u,i as A,j as m}from"./chunk-SEZETSB3.js";import{c as s,i as l}from"./chunk-SDQW7IJN.js";import{randomUUID as D}from"crypto";var x="connected-data-exports/",_=10080*60*1e3,b=900*1e3;function C(){return process.env.CONNECTED_DATA_READ_WRITE_TOKEN?.trim()||process.env.CONNECTED_DATA_BLOB_READ_WRITE_TOKEN?.trim()||null}function r(){return{prefix:x,artifactTtlMs:_,downloadTtlMs:b,token:C()}}function i(t){return(t.toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"connected-data-export").slice(0,120)}function N(t){return l(t,x)}function w(t){return f(t,r())}function O(t,e=Date.now()){let n=w(t);return!n||n.getTime()<=e}async function P(t){return g({...t,contentType:"application/x-ndjson"})}async function g(t){let e=t.stableCreatedAt?Date.parse(t.stableCreatedAt):NaN,n=Number.isFinite(e)?e:Date.now(),c=i(t.filename),y=t.stableKey?i(t.stableKey):D(),a;try{a=await p({policy:r(),ownerId:t.ownerId,artifactKey:`${i(t.exportId)}-${y}--${c}`,createdAt:n,filename:c,contentType:t.contentType,content:typeof t.content=="string"?t.content:Buffer.from(t.content)})}catch(o){throw o instanceof Error&&o.message==="private_artifact_blob_not_configured"?new Error("connected_data_private_blob_not_configured"):o}return{...a,...a.capabilities.includes("text")?{readback:{tool:"report_artifact_read",arguments:{artifactId:a.artifactId,offset:0,maxBytes:2e4},continuation:"Repeat with offset set to the previous result nextOffset until nextOffset is null."}}:{}}}async function B(t){return u({...t,policy:r()})}async function R(t,e,n){return A({policy:r(),artifactId:t,offset:e,maxBytes:n})}async function U(t){try{return await m({...t,policy:r(),maxBytes:t.maxBytes??25*1024*1024})}catch(e){if(e instanceof s&&e.code==="read_limit")return null;throw e}}async function h(t={}){let e=t.now??new Date,n=r();return n.token?!t.force&&!(e.getUTCHours()===3&&e.getUTCMinutes()===17)?{deleted:0,store:"private-vercel-blob",skipped:!0}:d({policy:n,now:e,includeLegacy:!0,maxObjects:2e4}):{deleted:0,store:process.env.VERCEL==="1"||process.env.NODE_ENV==="production"?"none":"local"}}export{x as a,_ as b,b as c,r as d,N as e,w as f,O as g,P as h,g as i,B as j,R as k,U as l,h as m};