mcp-scraper 0.96.1 → 0.96.3

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 (57) hide show
  1. package/CHANGELOG.md +26 -1
  2. package/README.md +1 -1
  3. package/dist/actions-FKAX2PYT.js +1 -0
  4. package/dist/bin/api-server.js +1 -1
  5. package/dist/bin/mcp-scraper-cli.js +1 -1
  6. package/dist/bin/mcp-scraper-core.js +1 -1
  7. package/dist/bin/mcp-scraper-install.js +1 -1
  8. package/dist/bin/mcp-stdio-server.js +1 -1
  9. package/dist/bin/paa-harvest.js +1 -1
  10. package/dist/bundle-7JMACIIR.js +1 -0
  11. package/dist/chunk-3HXMW2UJ.js +1 -0
  12. package/dist/{chunk-RN4VG3VH.js → chunk-42SLBGDI.js} +1 -1
  13. package/dist/{chunk-JHT6A4U6.js → chunk-4KHDV5E7.js} +1 -1
  14. package/dist/{chunk-FB4KBB5W.js → chunk-7ZR5IO3B.js} +2 -2
  15. package/dist/{chunk-HUNSEGUN.js → chunk-ANQ4JJVI.js} +43 -29
  16. package/dist/{chunk-SE4VKLEC.js → chunk-CFZXZKFT.js} +1 -1
  17. package/dist/{chunk-6BD75VKS.js → chunk-DJT2547J.js} +1 -1
  18. package/dist/chunk-E7I3OQHQ.js +203 -0
  19. package/dist/{chunk-HVQZRQRJ.js → chunk-GLCR4KJI.js} +16 -37
  20. package/dist/chunk-JGGQ3UX5.js +1 -0
  21. package/dist/chunk-JREMJRSS.js +1 -0
  22. package/dist/chunk-K3VDGJNK.js +1 -0
  23. package/dist/{chunk-H6MODA7W.js → chunk-MJOXIDKF.js} +5 -5
  24. package/dist/chunk-OY24ERPV.js +8 -0
  25. package/dist/{chunk-7WPCGRD7.js → chunk-P55O4IDC.js} +41 -34
  26. package/dist/{chunk-ZTMQEDIB.js → chunk-PANT6VEM.js} +1 -1
  27. package/dist/chunk-PKQHHCO4.js +20 -0
  28. package/dist/{chunk-RIHI3KH7.js → chunk-QYPSFZK3.js} +1 -1
  29. package/dist/{chunk-BPKTUCV7.js → chunk-U7BZ5KTE.js} +1 -1
  30. package/dist/{chunk-SFUOSJ3A.js → chunk-WBJ6Y7WP.js} +2 -2
  31. package/dist/dispatch-E6VTNHHS.js +1 -0
  32. package/dist/index.cjs +10 -10
  33. package/dist/index.js +1 -1
  34. package/dist/metering-YHZ46GV4.js +1 -0
  35. package/dist/queue-4XHYUV7J.js +1 -0
  36. package/dist/reconciliation-43CSC3XD.js +1 -0
  37. package/dist/repository-UKDA4IWP.js +1 -0
  38. package/dist/{server-DXZ27KQO.js → server-74VGVXA4.js} +840 -802
  39. package/dist/settlement-I5IBIK6U.js +1 -0
  40. package/dist/worker-L5NISZQV.js +1 -0
  41. package/package.json +1 -2
  42. package/dist/actions-R4EJDLRO.js +0 -1
  43. package/dist/bundle-FCXZMIRB.js +0 -1
  44. package/dist/chunk-5BKSKLHX.js +0 -1
  45. package/dist/chunk-5LYINW7Z.js +0 -8
  46. package/dist/chunk-CORWWDHL.js +0 -1
  47. package/dist/chunk-CVQUHVHX.js +0 -1
  48. package/dist/chunk-IY6ZUUY7.js +0 -173
  49. package/dist/chunk-RYX4FJVH.js +0 -1
  50. package/dist/chunk-UXNR3K6I.js +0 -1
  51. package/dist/dispatch-P7IY75LH.js +0 -1
  52. package/dist/metering-ZH2P62IC.js +0 -1
  53. package/dist/queue-AC4XKD6Z.js +0 -1
  54. package/dist/reconciliation-UZUZ6B74.js +0 -1
  55. package/dist/repository-4EC5EXVN.js +0 -1
  56. package/dist/settlement-6CS4JZTY.js +0 -1
  57. package/dist/worker-ATRD6VKM.js +0 -1
@@ -0,0 +1 @@
1
+ var o="0.96.3";export{o as a};
@@ -0,0 +1 @@
1
+ import{g as u,j as f,k as d,l as h,m as b,n as x}from"./chunk-P55O4IDC.js";import{h as w}from"./chunk-ANQ4JJVI.js";import{i as p}from"./chunk-C7MGJUTU.js";import{randomUUID as R}from"crypto";import{waitUntil as y}from"@vercel/functions";var c=class extends Error{constructor(){super("runtime_workflow_yield"),this.name="RuntimeWorkflowYield"}};function D(r){let t=Promise.resolve().then(r).catch(e=>{console.error("[runtime-job] execution failed",e instanceof Error?e.name:"UnknownError")});y(t)}async function J(r){let t=`runtime:${R()}`,e=Date.now()+(r.budgetMs??75e4),n={run:(o,i)=>i(),async checkpoint(o,i=33e4){if(!(e-Date.now()>=i))throw await w(o)?new c:Error("runtime_workflow_pause_not_admitted")}};try{return await r.execute({jobId:r.jobId,runId:t,step:n}),"completed"}catch(o){return o instanceof c?"deferred":(await r.onFailure({jobId:r.jobId,runId:t,error:o}),"failed")}}async function l(r,t){let e=process.env.CRON_SECRET?.trim();if(!e)throw Error("runtime_job_dispatch_not_configured");let n=(process.env.APP_URL??process.env.APP_ORIGIN??"https://mcpscraper.dev").replace(/\/$/,""),o=await fetch(`${n}/internal/jobs/run`,{method:"POST",headers:{authorization:`Bearer ${e}`,"content-type":"application/json"},body:JSON.stringify({kind:r,jobId:t}),signal:AbortSignal.timeout(1e4)});if(o.status!==202)throw Error(`runtime_job_dispatch_failed:${o.status}`)}function E(r){return Math.min(3600,Math.max(15,15*2**Math.min(8,Math.max(0,r-1))))}async function k(r){let t={claimed:r.rows.length,dispatched:0,failed:0},e=()=>{t.unknown=(t.unknown??0)+1},n=async o=>{let i=await r.read(o).catch(()=>null);return i?.id===o.id?i:null};for(let o of r.rows){let i=o.claimToken;if(!i||!await r.isCurrent(o,i).catch(()=>!1)){e();continue}try{await r.send(o)}catch(a){let m=(a instanceof Error?a.message:String(a)).slice(0,2e3);if(await r.retainRetry(o,i,m,E(o.attempts)).catch(async()=>{let s=await n(o);return s?.status==="failed"&&s.lastError===m}))t.failed+=1;else{let s=await n(o);s?.status==="dispatched"&&s.dispatchedAt?t.dispatched+=1:e()}continue}if(await r.acknowledge(o,i).catch(()=>!1))t.dispatched+=1;else{let a=await n(o);a?.status==="dispatched"&&a.dispatchedAt?t.dispatched+=1:e()}}return t}async function g(r){return k({rows:r,isCurrent:(t,e)=>h(t.id,e),send:async t=>{try{return await l("site_extract",t.id)}catch(e){throw Error(p(e instanceof Error?e.message:String(e)).slice(0,2e3))}},acknowledge:(t,e)=>b(t.id,e),retainRetry:(t,e,n,o)=>x(t.id,e,n,o),read:async t=>{let e=await u(t.id);return e?{id:e.id,status:e.dispatchedAt?"dispatched":e.dispatchClaimToken?"dispatching":e.dispatchError?"failed":"pending",dispatchedAt:e.dispatchedAt??null,lastError:e.dispatchError??null}:null}})}async function M(r){if((await u(r))?.dispatchedAt)return{claimed:0,dispatched:1,failed:0};let e=await d({jobId:r});return e.length?g(e):{claimed:0,dispatched:0,failed:0,unknown:1}}async function F(r=25){let t=await g(await d({limit:r})),e=await f(r);for(let n of e){t.claimed+=1;try{await l("site_extract",n.id),t.dispatched+=1}catch(o){t.failed+=1,console.warn("[site-extract/resume]",n.id,o instanceof Error?o.message:String(o))}}return{checked:t.claimed,dispatched:t.dispatched,failed:t.failed,...t.unknown?{unknown:t.unknown}:{}}}export{c as a,D as b,J as c,l as d,k as e,M as f,F as g};
@@ -0,0 +1 @@
1
+ import{a as w,b as u,c as _,d as l,e as h,m as g,p}from"./chunk-7SR7MEU5.js";import{k as c,m}from"./chunk-ANQ4JJVI.js";import{b as I,c as s}from"./chunk-4ZVO6GX4.js";async function R(e){let r=s(),n=!r?.operationRunId,o=r?.operationRunId??(await c({userId:r?.userId??null,ownerScope:r?.userId!=null?`user:${r.userId}`:"system:unscoped",tool:e.tool,normalizedFlags:{subOperation:r?.subOp??null},deploymentCommit:process.env.VERCEL_GIT_COMMIT_SHA?.trim()||process.env.GIT_COMMIT_SHA?.trim()||null})).id,a=n?null:await p(o),i=a?.attempts.at(-1),t=e.parentAttemptId??(e.retryKind&&i?String(i.id):r?.operationRootAttemptId),b=e.edgeKind??(e.retryKind==="same_method"?"same_method_retry":e.retryKind==="provider_fallback"?"provider_fallback":void 0),d=t?await _({runId:o,parentAttemptId:t,edgeKind:b??"parallel_child",method:e.method,provider:e.provider,retryKind:e.retryKind,retryReason:e.retryReason}):await u({runId:o,attemptNumber:(a?.attempts.length??0)+1,method:e.method,provider:e.provider,...i?{parentAttemptId:String(i.id),edgeKind:b??"next_phase",retryKind:e.retryKind??null,retryReason:e.retryReason??null}:{}}),y;try{y=(await h({attemptId:d,provider:e.provider,providerProduct:e.providerProduct,billingTier:e.billingTier,accountScope:r?.operationAccountScope??"production-default",method:e.method,providerStatus:"started"})).id}catch(f){throw await w({tool:e.tool,method:e.method,phase:"pending_receipt_create",errorCode:f instanceof Error?f.name:"UnknownError",runId:o,attemptId:d}).catch(()=>{}),await l({attemptId:d,status:"failed",errorCode:"pending_receipt_create_failed",durationMs:0}).catch(()=>{}),f}return{runId:o,attemptId:d,receiptId:y,ownsRun:n,startedAtMs:Date.now()}}async function S(e,r,n){await l({attemptId:e.attemptId,status:r,errorCode:n??null,durationMs:Date.now()-e.startedAtMs}),e.ownsRun&&await m({runId:e.runId,status:r,failureClass:n??null})}async function T(e,r){let n=s(),o=null,a=Date.now();if(n?.operationRunId&&n.operationRootAttemptId)try{o=await _({runId:n.operationRunId,parentAttemptId:n.operationRootAttemptId,edgeKind:"parallel_child",method:e})}catch(t){console.warn(JSON.stringify({event:"local_cost_phase_start_failed",method:e,message:t instanceof Error?t.message:String(t)}))}let i="failed";try{let t=await r();return i="succeeded",t}finally{o&&await l({attemptId:o,status:i,durationMs:Date.now()-a,errorCode:i==="failed"?"local_phase_failed":null}).catch(t=>console.warn(JSON.stringify({event:"local_cost_phase_finish_failed",method:e,message:t instanceof Error?t.message:String(t)})))}}async function M(e,r){let n=s()?.operationRunId;n&&await g({runId:n,billingTable:"billing_debits",billingKey:e,relation:"debit",amountMc:r}).catch(o=>console.warn(JSON.stringify({event:"cost_billing_link_failed",message:o instanceof Error?o.message:String(o)})))}async function K(e,r){let n=s();if(n?.operationRunId)return I({...n,op:e.op,userId:e.userId},r);let o=null,a=null;try{o=(await c({userId:e.userId,ownerScope:`user:${e.userId}`,tool:e.tool,normalizedFlags:e.normalizedFlags,deploymentCommit:process.env.VERCEL_GIT_COMMIT_SHA?.trim()||process.env.GIT_COMMIT_SHA?.trim()||null})).id,e.billingDebitKey&&await g({runId:o,billingTable:"billing_debits",billingKey:e.billingDebitKey,relation:"debit"}).catch(t=>console.warn(JSON.stringify({event:"cost_billing_link_failed",tool:e.tool,message:t instanceof Error?t.message:String(t)}))),a=await u({runId:o,attemptNumber:1,method:`${e.tool}_root`,normalizedFlags:e.normalizedFlags})}catch(t){console.warn(JSON.stringify({event:"logical_cost_run_start_failed",tool:e.tool,message:t instanceof Error?t.message:String(t)}))}let i="failed";try{let t=await I({...n,op:e.op,userId:e.userId,operationRunId:o,operationRootAttemptId:a},r);return i=t instanceof Response&&t.status>=400?"failed":"succeeded",t}finally{o&&a?await v({runId:o,rootAttemptId:a,status:i,failureClass:i==="failed"?"operation_failed":null}).catch(t=>console.warn(JSON.stringify({event:"logical_cost_run_finish_failed",tool:e.tool,message:t instanceof Error?t.message:String(t)}))):o&&await m({runId:o,status:i,failureClass:i==="failed"?"operation_failed":null}).catch(()=>{})}}async function O(e){let r=await c({...e.jobId?{id:`extract-url:${e.jobId}`,idempotencyKey:`job:${e.jobId}`,requestFingerprint:e.jobId,jobId:e.jobId}:{},userId:e.userId,ownerScope:`user:${e.userId}`,tool:"extract_url",normalizedFlags:e.normalizedFlags,deploymentCommit:process.env.VERCEL_GIT_COMMIT_SHA?.trim()||process.env.GIT_COMMIT_SHA?.trim()||null}),n=r.replayed?await p(r.id):null,o=n?.attempts[0]?.id==null?await u({runId:r.id,attemptNumber:1,method:"extract_url_root",normalizedFlags:e.normalizedFlags}):String(n.attempts[0].id);return e.billingDebitKey&&await g({runId:r.id,billingTable:"billing_debits",billingKey:e.billingDebitKey,relation:"debit"}),{runId:r.id,rootAttemptId:o}}async function v(e){let r=await p(e.runId),n=r?.attempts.find(o=>String(o.id)===e.rootAttemptId);n?.status==="running"&&await l({attemptId:e.rootAttemptId,status:e.status,errorCode:e.failureClass??null,durationMs:Math.max(0,Date.now()-Date.parse(String(n.started_at)))}),r?.run.status==="running"&&await m({runId:e.runId,status:e.status,failureClass:e.failureClass??null})}export{R as a,S as b,T as c,M as d,K as e,O as f,v as g};
@@ -1,4 +1,4 @@
1
- import{H as sn,_ as an,c as Yt,j as ut,k as je,m as nn,z as rn}from"./chunk-SFUOSJ3A.js";import{B as gn,a as f,b as v,c as ue,d as Oe,e as yt,f as ln,g as un,h as U,i as $,l as _n,m as mn,n as pn,p as gt,u as B,v as Q,z as yn}from"./chunk-NNOX3FYG.js";import{a as qe}from"./chunk-NALXKTUU.js";import{a as Kt,b as Jt,f as zt}from"./chunk-6BD75VKS.js";import{d as on,g as He,i as We,k as _t,m as mt,o as cn,r as Be,t as dn,u as pt}from"./chunk-2IATUJO6.js";import{D as L,E as Qt,N as Zt,O as en,P as Re,Q as dt,R as tn,S as lt,U as te,W as le,p as Fe,q as Gt,v as Xt,z as ct}from"./chunk-CORWWDHL.js";import{f as Ue}from"./chunk-5LYINW7Z.js";import{a as I}from"./chunk-WNUXMPVX.js";import{randomUUID as Fi}from"crypto";async function fn(e,t,n){return(await I().execute({sql:`INSERT OR IGNORE INTO stripe_events
1
+ import{H as sn,_ as an,b as ut,c as je,e as tn,t as nn,z as rn}from"./chunk-WBJ6Y7WP.js";import{B as gn,a as f,b as v,c as ue,d as Oe,e as yt,f as ln,g as un,h as U,i as $,l as _n,m as mn,n as pn,p as gt,u as B,v as Q,z as yn}from"./chunk-NNOX3FYG.js";import{a as qe}from"./chunk-NALXKTUU.js";import{a as Kt,b as Jt,f as zt}from"./chunk-DJT2547J.js";import{d as on,g as He,i as We,k as _t,m as mt,o as cn,r as Be,t as dn,u as pt}from"./chunk-2IATUJO6.js";import{$ as en,A as Yt,F as Gt,J as ct,N as L,O as Xt,X as Qt,Y as Zt,Z as Re,_ as dt,aa as lt,ca as te,ea as le,f as Ue,z as Fe}from"./chunk-OY24ERPV.js";import{a as I}from"./chunk-WNUXMPVX.js";import{randomUUID as Fi}from"crypto";async function fn(e,t,n){return(await I().execute({sql:`INSERT OR IGNORE INTO stripe_events
2
2
  (event_id, event_type, stripe_created_at, status, attempt_count, received_at, next_attempt_at, processed_at, updated_at)
3
3
  VALUES (?, ?, ?, 'pending', 0, datetime('now'), datetime('now'), datetime('now'), datetime('now'))`,args:[e,t,n]})).rowsAffected===1?"queued":"duplicate"}async function ra(e=50,t=300){let n=Math.max(1,Math.min(500,Math.trunc(e))),i=await I().execute({sql:`SELECT event_id
4
4
  FROM stripe_events
@@ -53,7 +53,7 @@ import{H as sn,_ as an,c as Yt,j as ut,k as je,m as nn,z as rn}from"./chunk-SFUO
53
53
  )`,args:[e.tier,Math.max(0,Math.round(e.concurrency)),e.subscriptionId,e.includedMemoryPlan,e.includedMemoryPlan,e.includedMemoryPlan,e.userId,e.invoiceId,e.userId,e.creditsMc]}],"write"),s=(await t.execute({sql:`SELECT l.user_id, l.amount_mc, l.operation, u.balance_mc
54
54
  FROM ledger l JOIN users u ON u.id = l.user_id
55
55
  WHERE l.stripe_pi = ? LIMIT 1`,args:[e.invoiceId]})).rows[0];if(!s||Number(s.user_id)!==e.userId||Number(s.amount_mc)!==e.creditsMc||String(s.operation)!=="subscription")throw new Error("invoice idempotency key conflicts with an existing grant");return{granted:i[0]?.rowsAffected===1,balance_mc:Number(s.balance_mc??0)}}async function _e(e,t,n){await I().execute({sql:"UPDATE users SET memory_plan = ?, memory_subscription_id = ? WHERE id = ?",args:[t,n,e]})}async function ma(e){let n=(await I().execute({sql:"SELECT memory_provisioned FROM users WHERE id = ?",args:[e]})).rows[0];return Number(n?.memory_provisioned??0)===1}async function En(e,t){await I().execute({sql:"UPDATE users SET memory_provisioned = ? WHERE id = ?",args:[t?1:0,e]})}async function bt(e){let t=await I().execute({sql:"SELECT * FROM users WHERE memory_subscription_id = ? AND active = 1",args:[e]});return t.rows[0]?ut(t.rows[0]):void 0}import{createCipheriv as Ji,createDecipheriv as zi,randomBytes as Yi,scryptSync as Gi}from"crypto";import{setScheduleEntitlementTool as Xi}from"mcpscraper-memory-tools/tools/schedule/set-schedule-entitlement";import{createHash as ji,randomUUID as qi}from"crypto";import{exportJWK as Hi,importPKCS8 as Wi,SignJWT as Bi}from"jose";function Vi(e=process.env.OAUTH_ISSUER){let t=e?.trim()||"https://mcpscraper.dev",n=new URL(t);if(n.protocol!=="https:"||n.username||n.password||n.search||n.hash||n.pathname!=="/"&&n.pathname!=="")throw new Error("OAUTH_ISSUER must be an HTTPS origin without credentials, path, query, or fragment");return n.origin}var Ki=Vi(),Ke=null;async function bn(){if(Ke)return Ke;let e=process.env.OAUTH_SIGNING_KEY;if(!e?.trim())throw new Error("OAUTH_SIGNING_KEY is not set");let t=e.includes("BEGIN")?e:Buffer.from(e,"base64").toString("utf8"),n=await Wi(t,"RS256",{extractable:!0}),i=await Hi(n),r={kty:i.kty,n:i.n,e:i.e},s=ji("sha256").update(JSON.stringify({e:r.e,kty:r.kty,n:r.n})).digest("base64url").slice(0,16);return r.kid=s,r.alg="RS256",r.use="sig",Ke={privateKey:n,publicJwk:r,kid:s},Ke}async function fa(){return(await bn()).publicJwk}async function In(e){let{privateKey:t,kid:n}=await bn();return new Bi({scope:e.scope,plan:e.plan}).setProtectedHeader({alg:"RS256",kid:n}).setIssuer(Ki).setSubject(e.identity).setAudience(e.audience).setIssuedAt().setJti(qi()).setExpirationTime(`${e.ttlSeconds}s`).sign(t)}var Qi=()=>(process.env.MCP_MEMORY_BASE_URL??"https://memory.mcpscraper.dev").replace(/\/$/,""),Zi=()=>(process.env.MCP_MEMORY_RESOURCE_URL??"https://memory.mcpscraper.dev/mcp").replace(/\/$/,""),er=()=>process.env.MCP_MEMORY_ADMIN_KEY?.trim()??"",tr=300;function nr(e){let t=e.split(`
56
- `).find(i=>i.startsWith("data:")),n=t?t.slice(5).trim():e;return JSON.parse(n)}function It(e){return e?(process.env.MEMORY_OPERATOR_IDENTITIES??"").split(",").map(n=>n.trim().toLowerCase()).filter(Boolean).includes(e.trim().toLowerCase()):!1}function An(){return Gi(qe(),"mcp-memory-key-v1",32)}function Na(e){let t=Yi(12),n=Ji("aes-256-gcm",An(),t),i=Buffer.concat([n.update(e,"utf8"),n.final()]),r=n.getAuthTag();return`${t.toString("base64")}:${r.toString("base64")}:${i.toString("base64")}`}function Ca(e){try{let[t,n,i]=e.split(":"),r=zi("aes-256-gcm",An(),Buffer.from(t,"base64"));return r.setAuthTag(Buffer.from(n,"base64")),Buffer.concat([r.update(Buffer.from(i,"base64")),r.final()]).toString("utf8")}catch{return null}}async function Sn(e,t,n){try{let i=await fetch(`${Qi()}/mcp`,{method:"POST",headers:{"content-type":"application/json",accept:"application/json, text/event-stream",authorization:`Bearer ${n}`},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"tools/call",params:{name:e,arguments:t}})}),r=await i.text();if(!i.ok)return{ok:!1,error:`memory ${e} failed (${i.status})`};let s=nr(r);if(s.error)return{ok:!1,error:s.error.message??`memory ${e} failed`};if(s.result?.structuredContent)return s.result.structuredContent;let a=s.result?.content?.find(o=>o.type==="text")?.text;if(a)try{return JSON.parse(a)}catch{return{ok:!1,error:a}}return{ok:!1,error:`memory ${e} returned no result`}}catch(i){return{ok:!1,error:i?.message??"memory call failed"}}}function hn(e){return e.email}function ir(e){return hn(e)}function wa(e){return It(e.email)?"unlimited":e.memory_plan==="pro"||e.memory_plan==="team"?e.memory_plan:"free"}async function Ra(e){try{let{key:t}=await Nn(e);if(!t)return;(await Sn("listVaultsTool",{},t)).ok&&await En(e.id,!0)}catch{}}function rr(e){return e?!!Qt[e]?.includes_memory:!1}function V(e){return e.memory_plan==="team"?"team":rr(e.subscription_tier)||e.memory_plan==="pro"?"pro":"free"}async function Nn(e,t){try{let n=It(e.email),i=n?"unlimited":t??V(e),r=n?"memory.read memory.write memory.admin":"memory.read memory.write";return{key:await In({identity:hn(e),scope:r,plan:i,audience:Zi(),ttlSeconds:tr})}}catch(n){return{key:null,error:n instanceof Error?n.message:"memory service authorization unavailable"}}}async function Z(e,t){let n=It(e.email)?"unlimited":t,{key:i,error:r}=await Nn(e,n);if(!i)return{ok:!1,error:r??"memory unavailable"};let s=await Sn("listVaultsTool",{},i);return{ok:s.ok,error:s.error}}async function Je(e){let t=er();if(!t)return{ok:!1,error:"memory not configured (MCP_MEMORY_ADMIN_KEY missing)"};let n=ir(e),i=await Xi.execute({apiKey:t,granteeIdentity:n,mcpScraperApiKey:e.api_key},{});return{ok:i.ok,error:i.error}}var Cn=["active","trialing","past_due"];function De(e){return Cn.includes(e)}function wn(e,t){for(let n of Cn){let i=e.find(r=>r.status===n&&t(r));if(i)return i}}var sr="price_1TtYPAS8aAcsk3TGHOgrDZiQ";function ar(e=new Date){return`${e.getUTCFullYear()}-${String(e.getUTCMonth()+1).padStart(2,"0")}`}var or=new Set(["connected","needs_reauth"]);function cr(e){return or.has(String(e.lifecycleStatus??""))}async function dr(e,t){let n=await I().execute({sql:"SELECT connection_id FROM connected_account_charges WHERE user_id = ? AND period_start = ?",args:[Number(e),t]});return new Set(n.rows.map(i=>String(i.connection_id)))}async function lr(e,t,n){await sn();let i=Number(e),r=I();return await r.batch([{sql:`
56
+ `).find(i=>i.startsWith("data:")),n=t?t.slice(5).trim():e;return JSON.parse(n)}function It(e){return e?(process.env.MEMORY_OPERATOR_IDENTITIES??"").split(",").map(n=>n.trim().toLowerCase()).filter(Boolean).includes(e.trim().toLowerCase()):!1}function An(){return Gi(qe(),"mcp-memory-key-v1",32)}function Na(e){let t=Yi(12),n=Ji("aes-256-gcm",An(),t),i=Buffer.concat([n.update(e,"utf8"),n.final()]),r=n.getAuthTag();return`${t.toString("base64")}:${r.toString("base64")}:${i.toString("base64")}`}function Ca(e){try{let[t,n,i]=e.split(":"),r=zi("aes-256-gcm",An(),Buffer.from(t,"base64"));return r.setAuthTag(Buffer.from(n,"base64")),Buffer.concat([r.update(Buffer.from(i,"base64")),r.final()]).toString("utf8")}catch{return null}}async function Sn(e,t,n){try{let i=await fetch(`${Qi()}/mcp`,{method:"POST",headers:{"content-type":"application/json",accept:"application/json, text/event-stream",authorization:`Bearer ${n}`},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"tools/call",params:{name:e,arguments:t}})}),r=await i.text();if(!i.ok)return{ok:!1,error:`memory ${e} failed (${i.status})`};let s=nr(r);if(s.error)return{ok:!1,error:s.error.message??`memory ${e} failed`};if(s.result?.structuredContent)return s.result.structuredContent;let a=s.result?.content?.find(o=>o.type==="text")?.text;if(a)try{return JSON.parse(a)}catch{return{ok:!1,error:a}}return{ok:!1,error:`memory ${e} returned no result`}}catch(i){return{ok:!1,error:i?.message??"memory call failed"}}}function hn(e){return e.email}function ir(e){return hn(e)}function wa(e){return It(e.email)?"unlimited":e.memory_plan==="pro"||e.memory_plan==="team"?e.memory_plan:"free"}async function Ra(e){try{let{key:t}=await Nn(e);if(!t)return;(await Sn("listVaultsTool",{},t)).ok&&await En(e.id,!0)}catch{}}function rr(e){return e?!!Xt[e]?.includes_memory:!1}function V(e){return e.memory_plan==="team"?"team":rr(e.subscription_tier)||e.memory_plan==="pro"?"pro":"free"}async function Nn(e,t){try{let n=It(e.email),i=n?"unlimited":t??V(e),r=n?"memory.read memory.write memory.admin":"memory.read memory.write";return{key:await In({identity:hn(e),scope:r,plan:i,audience:Zi(),ttlSeconds:tr})}}catch(n){return{key:null,error:n instanceof Error?n.message:"memory service authorization unavailable"}}}async function Z(e,t){let n=It(e.email)?"unlimited":t,{key:i,error:r}=await Nn(e,n);if(!i)return{ok:!1,error:r??"memory unavailable"};let s=await Sn("listVaultsTool",{},i);return{ok:s.ok,error:s.error}}async function Je(e){let t=er();if(!t)return{ok:!1,error:"memory not configured (MCP_MEMORY_ADMIN_KEY missing)"};let n=ir(e),i=await Xi.execute({apiKey:t,granteeIdentity:n,mcpScraperApiKey:e.api_key},{});return{ok:i.ok,error:i.error}}var Cn=["active","trialing","past_due"];function De(e){return Cn.includes(e)}function wn(e,t){for(let n of Cn){let i=e.find(r=>r.status===n&&t(r));if(i)return i}}var sr="price_1TtYPAS8aAcsk3TGHOgrDZiQ";function ar(e=new Date){return`${e.getUTCFullYear()}-${String(e.getUTCMonth()+1).padStart(2,"0")}`}var or=new Set(["connected","needs_reauth"]);function cr(e){return or.has(String(e.lifecycleStatus??""))}async function dr(e,t){let n=await I().execute({sql:"SELECT connection_id FROM connected_account_charges WHERE user_id = ? AND period_start = ?",args:[Number(e),t]});return new Set(n.rows.map(i=>String(i.connection_id)))}async function lr(e,t,n){await sn();let i=Number(e),r=I();return await r.batch([{sql:`
57
57
  INSERT OR IGNORE INTO connected_account_charge_transfers (
58
58
  user_id, period_start, from_connection_id, to_connection_id, provider_config_key
59
59
  )
@@ -116,7 +116,7 @@ import{H as sn,_ as an,c as Yt,j as ut,k as je,m as nn,z as rn}from"./chunk-SFUO
116
116
  last_error_code = excluded.last_error_code,
117
117
  checked_at = datetime('now'),
118
118
  synced_at = CASE WHEN ? THEN datetime('now') ELSE connected_account_billing.synced_at END,
119
- updated_at = datetime('now')`,args:[Number(e.userId),e.stripeSubscriptionId,e.stripeSubscriptionItemId,e.priceId,e.quantity,e.status,e.lastErrorCode,e.synced?1:0,e.synced?1:0]});let t=await ht(e.userId);if(!t)throw new Error("connected account billing state was not persisted");return t}var K=class extends Error{constructor(n,i,r=409,s){super(n);this.code=i;this.status=r;this.details=s;this.name="ConnectedAccountBillingError"}code;status;details};function Nt(){let e=process.env.CONNECTED_ACCOUNT_PRICE_ID?.trim();return e||sr||null}function St(e,t){let n=Math.max(0,Math.round(e));return{provider:"nango",billingMode:"flat_recurring_credits",priceId:Nt(),unitAmountCredits:Fe,interval:"month",quantity:n,projectedMonthlyCredits:n*Fe,status:t?.status??"pending",lastErrorCode:t?.last_error_code??null,syncedAt:t?.synced_at??null,usage:Xt.usage}}function me(e){return e.items.data.find(t=>!!t.price?.id&&t.price.id in L)}function Ma(e){return wn(e,t=>!!me(t))}function ur(e){return e instanceof K?e.code:"stripe_connection_billing_failed"}async function ze(e,t,n){await At({userId:e.id,stripeSubscriptionId:e.subscription_id,stripeSubscriptionItemId:null,priceId:Nt(),quantity:t,status:n instanceof K&&n.code!=="stripe_connection_billing_failed"?"blocked":"error",lastErrorCode:ur(n),synced:!1})}async function Ua(e,t){let n=[...new Set(t.filter(cr).map(c=>c.connectionId))],i=n.length,r=Nt();if(!r){let c=new K("Connected-account billing is not configured.","connected_account_price_not_configured",503);throw await ze(e,i,c),c}if(!e.subscription_id||!(e.subscription_tier??"")||!Object.values(L).some(c=>c.tier===e.subscription_tier)){if(i===0){let l=await At({userId:e.id,stripeSubscriptionId:null,stripeSubscriptionItemId:null,priceId:r,quantity:0,status:"synced",lastErrorCode:null,synced:!0});return St(0,l)}let c=new K("An active paid plan is required before connected accounts can be billed.","paid_plan_required",403);throw await ze(e,i,c),c}let s=await ht(e.id),a=Math.max(0,s?.quantity??0),o=ar();try{let c=await dr(e.id,o),l=n.filter(d=>!c.has(d));for(let d of l){if(await lr(e.id,d,o))continue;let p=Gt,E=await zt(e.id,p,Ue.CONNECTED_ACCOUNT_FEE,`1 connected account at ${Fe} credits/month (${o})`,`connection-fee:${d}:${o}`);if(!E.ok){let b=new K(`Insufficient credits to connect. Balance: ${te(E.balance_mc)} credits. Connecting requires ${te(p)} credits (${te(p-E.balance_mc)} short). Upgrade your plan or wait for your credits to refresh.`,"insufficient_credits",402,{balanceCredits:te(E.balance_mc),requiredCredits:te(p),shortByCredits:te(Math.max(0,p-E.balance_mc))});throw await ze(e,a,b),b}await I().execute({sql:`INSERT INTO connected_account_charges (user_id, connection_id, period_start, amount_mc)
119
+ updated_at = datetime('now')`,args:[Number(e.userId),e.stripeSubscriptionId,e.stripeSubscriptionItemId,e.priceId,e.quantity,e.status,e.lastErrorCode,e.synced?1:0,e.synced?1:0]});let t=await ht(e.userId);if(!t)throw new Error("connected account billing state was not persisted");return t}var K=class extends Error{constructor(n,i,r=409,s){super(n);this.code=i;this.status=r;this.details=s;this.name="ConnectedAccountBillingError"}code;status;details};function Nt(){let e=process.env.CONNECTED_ACCOUNT_PRICE_ID?.trim();return e||sr||null}function St(e,t){let n=Math.max(0,Math.round(e));return{provider:"nango",billingMode:"flat_recurring_credits",priceId:Nt(),unitAmountCredits:Fe,interval:"month",quantity:n,projectedMonthlyCredits:n*Fe,status:t?.status??"pending",lastErrorCode:t?.last_error_code??null,syncedAt:t?.synced_at??null,usage:Gt.usage}}function me(e){return e.items.data.find(t=>!!t.price?.id&&t.price.id in L)}function Ma(e){return wn(e,t=>!!me(t))}function ur(e){return e instanceof K?e.code:"stripe_connection_billing_failed"}async function ze(e,t,n){await At({userId:e.id,stripeSubscriptionId:e.subscription_id,stripeSubscriptionItemId:null,priceId:Nt(),quantity:t,status:n instanceof K&&n.code!=="stripe_connection_billing_failed"?"blocked":"error",lastErrorCode:ur(n),synced:!1})}async function Ua(e,t){let n=[...new Set(t.filter(cr).map(c=>c.connectionId))],i=n.length,r=Nt();if(!r){let c=new K("Connected-account billing is not configured.","connected_account_price_not_configured",503);throw await ze(e,i,c),c}if(!e.subscription_id||!(e.subscription_tier??"")||!Object.values(L).some(c=>c.tier===e.subscription_tier)){if(i===0){let l=await At({userId:e.id,stripeSubscriptionId:null,stripeSubscriptionItemId:null,priceId:r,quantity:0,status:"synced",lastErrorCode:null,synced:!0});return St(0,l)}let c=new K("An active paid plan is required before connected accounts can be billed.","paid_plan_required",403);throw await ze(e,i,c),c}let s=await ht(e.id),a=Math.max(0,s?.quantity??0),o=ar();try{let c=await dr(e.id,o),l=n.filter(d=>!c.has(d));for(let d of l){if(await lr(e.id,d,o))continue;let p=Yt,E=await zt(e.id,p,Ue.CONNECTED_ACCOUNT_FEE,`1 connected account at ${Fe} credits/month (${o})`,`connection-fee:${d}:${o}`);if(!E.ok){let b=new K(`Insufficient credits to connect. Balance: ${te(E.balance_mc)} credits. Connecting requires ${te(p)} credits (${te(p-E.balance_mc)} short). Upgrade your plan or wait for your credits to refresh.`,"insufficient_credits",402,{balanceCredits:te(E.balance_mc),requiredCredits:te(p),shortByCredits:te(Math.max(0,p-E.balance_mc))});throw await ze(e,a,b),b}await I().execute({sql:`INSERT INTO connected_account_charges (user_id, connection_id, period_start, amount_mc)
120
120
  VALUES (?, ?, ?, ?) ON CONFLICT(user_id, connection_id, period_start) DO NOTHING`,args:[Number(e.id),d,o,p]}),E.duplicate||await rn(e.id,1)}let _=await At({userId:e.id,stripeSubscriptionId:e.subscription_id,stripeSubscriptionItemId:null,priceId:r,quantity:i,status:"synced",lastErrorCode:null,synced:!0});return St(i,_)}catch(c){throw c instanceof K?c:(await ze(e,a,c),new K("Unable to update connected-account billing.","stripe_connection_billing_failed",503))}}async function Fa(e,t){return St(t,await ht(e))}import{createHash as Bc,createHmac as jt,generateKeyPairSync as Ss,randomUUID as de,sign as hs}from"crypto";import Ns from"twilio";import{z as u}from"zod";import{z as R}from"zod";var _r=new Set(["AED","AFN","ALL","AMD","ANG","AOA","ARS","AUD","AWG","AZN","BAM","BBD","BDT","BGN","BHD","BIF","BMD","BND","BOB","BOV","BRL","BSD","BTN","BWP","BYN","BZD","CAD","CDF","CHE","CHF","CHW","CLF","CLP","CNY","COP","COU","CRC","CUP","CVE","CZK","DJF","DKK","DOP","DZD","EGP","ERN","ETB","EUR","FJD","FKP","GBP","GEL","GHS","GIP","GMD","GNF","GTQ","GYD","HKD","HNL","HTG","HUF","IDR","ILS","INR","IQD","IRR","ISK","JMD","JOD","JPY","KES","KGS","KHR","KMF","KPW","KRW","KWD","KYD","KZT","LAK","LBP","LKR","LRD","LSL","LYD","MAD","MDL","MGA","MKD","MMK","MNT","MOP","MRU","MUR","MVR","MWK","MXN","MXV","MYR","MZN","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PAB","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","RWF","SAR","SBD","SCR","SDG","SEK","SGD","SHP","SLE","SOS","SRD","SSP","STN","SVC","SYP","SZL","THB","TJS","TMT","TND","TOP","TRY","TTD","TWD","TZS","UAH","UGX","USD","USN","UYI","UYU","UYW","UZS","VED","VES","VND","VUV","WST","XAF","XAG","XAU","XBA","XBB","XBC","XBD","XCD","XDR","XOF","XPD","XPF","XPT","XSU","XTS","XUA","XXX","YER","ZAR","ZMW","ZWG"]),Te=R.string().trim().length(3).transform(e=>e.toUpperCase()).refine(e=>_r.has(e),"Provide a valid ISO-4217 currency."),Ye=R.number().int("Money must be represented as integer minor units.").min(0,"Money cannot be negative.").max(Number.MAX_SAFE_INTEGER),Ge=R.string().trim().min(1).max(80).default("1"),mr=R.enum(["semantic_markup","source_event","crm_field","transaction"]),pr=R.object({mode:R.literal("none"),ruleVersion:Ge}).strict(),yr=R.object({mode:R.literal("fixed"),valueMinor:Ye,currency:Te,ruleVersion:Ge}).strict(),gr=R.object({mode:R.literal("dynamic"),source:mr,currency:Te,fallbackValueMinor:Ye.nullable().default(null),ruleVersion:Ge}).strict(),Rn=R.discriminatedUnion("mode",[pr,yr,gr]),fr=R.object({linkedEventName:R.string().trim().regex(/^[a-z][a-z0-9_]{1,79}$/),relation:R.enum(["before","after","either"]),intervalSeconds:R.number().int().min(0).max(10*365*24*60*60).nullable(),overrideValueMinor:Ye,currency:Te}).strict(),Xe=R.object({targetEventName:R.string().trim().regex(/^[a-z][a-z0-9_]{1,79}$/),base:Rn,conditionalOverride:fr.nullable().default(null),ruleVersion:Ge}).strict().superRefine((e,t)=>{let n=e.conditionalOverride;n&&e.base.mode!=="none"&&n.currency!==e.base.currency&&t.addIssue({code:"custom",path:["conditionalOverride","currency"],message:"Conditional override currency must match the base value currency."})});function ne(e,t){let n=Date.parse(e);if(!Number.isFinite(n))throw new Error(`${t} must be an ISO timestamp.`);return n}function vr(e,t){let n=Ye.parse(e.valueMinor),i=On(t,e.currency);return ne(e.observedAt,"observedAt"),{valueMinor:n,currency:i,observedAt:new Date(e.observedAt).toISOString()}}function Er(e){return Rn.parse(e)}function On(e,t){let i=(Array.isArray(e)?e:[e,t]).filter(r=>typeof r=="string"&&r.trim().length>0).map(r=>Te.parse(r));if(i.length===0)throw new Error("A currency is required for a monetary value.");if(new Set(i).size!==1)throw new Error(`Mixed currencies are not compatible: ${[...new Set(i)].join(", ")}.`);return i[0]}function br(e,t={}){let n=Er(e);if(n.mode==="none")return{valueMinor:null,currency:null,provenance:{mode:"none",source:null,observedAt:null,fallback:!1,ruleVersion:n.ruleVersion,resolution:"absent",baseValueMinor:null,resolvedValueMinor:null,currency:null,linkedEvent:null}};if(n.mode==="fixed"){let s=t.observedAt?new Date(ne(t.observedAt,"observedAt")).toISOString():null;return{valueMinor:n.valueMinor,currency:n.currency,provenance:{mode:"fixed",source:null,observedAt:s,fallback:!1,ruleVersion:n.ruleVersion,resolution:"fixed",baseValueMinor:n.valueMinor,resolvedValueMinor:n.valueMinor,currency:n.currency,linkedEvent:null}}}let i=t.observations?.[n.source];if(i){let s=vr(i,n.currency);return{valueMinor:s.valueMinor,currency:s.currency,provenance:{mode:"dynamic",source:n.source,observedAt:s.observedAt,fallback:!1,ruleVersion:n.ruleVersion,resolution:"dynamic",baseValueMinor:s.valueMinor,resolvedValueMinor:s.valueMinor,currency:s.currency,linkedEvent:null}}}let r=n.fallbackValueMinor;return{valueMinor:r,currency:r===null?null:n.currency,provenance:{mode:"dynamic",source:n.source,observedAt:null,fallback:r!==null,ruleVersion:n.ruleVersion,resolution:r===null?"absent":"fallback",baseValueMinor:r,resolvedValueMinor:r,currency:r===null?null:n.currency,linkedEvent:null}}}function Ir(e,t,n){let i=ne(t.occurredAt,"targetEvent.occurredAt"),r=n.filter(s=>{if(s.eventName!==e.linkedEventName)return!1;let o=(ne(s.occurredAt,"linkedEvent.occurredAt")-i)/1e3;return e.relation==="before"&&o>0||e.relation==="after"&&o<0?!1:e.intervalSeconds===null||Math.abs(o)<=e.intervalSeconds});return r.sort((s,a)=>{let o=Math.abs(ne(s.occurredAt,"linkedEvent.occurredAt")-i),c=Math.abs(ne(a.occurredAt,"linkedEvent.occurredAt")-i);return o-c||s.eventId.localeCompare(a.eventId)}),r[0]??null}function Dn(e,t){let n=Xe.parse(e);if(t.targetEvent.eventName!==n.targetEventName)throw new Error(`Value rule targets ${n.targetEventName}, not ${t.targetEvent.eventName}.`);let i=br({...n.base,ruleVersion:n.ruleVersion},t);if(!n.conditionalOverride)return i;let r=Ir(n.conditionalOverride,t.targetEvent,t.linkedEvents);if(!r)return i;if(t.providerOperation==="restatement"&&r.identityTier!=="confirmed")throw new Error("Candidate-only evidence cannot be used for a provider restatement.");let s=i.currency?On(i.currency,n.conditionalOverride.currency):Te.parse(n.conditionalOverride.currency);return{valueMinor:n.conditionalOverride.overrideValueMinor,currency:s,provenance:{...i.provenance,ruleVersion:n.ruleVersion,resolution:"conditional_override",resolvedValueMinor:n.conditionalOverride.overrideValueMinor,currency:s,linkedEvent:{eventId:r.eventId,eventName:r.eventName,occurredAt:new Date(ne(r.occurredAt,"linkedEvent.occurredAt")).toISOString(),identityTier:r.identityTier??"candidate"}}}}var Tn=u.object({gclid:u.string().trim().max(500).optional(),gbraid:u.string().trim().max(500).optional(),wbraid:u.string().trim().max(500).optional(),fbclid:u.string().trim().max(500).optional(),fbp:u.string().trim().max(500).optional(),fbc:u.string().trim().max(500).optional(),ttclid:u.string().trim().max(500).optional(),rdt_cid:u.string().trim().max(500).optional(),msclkid:u.string().trim().max(500).optional(),li_fat_id:u.string().trim().max(500).optional(),snapclid:u.string().trim().max(500).optional()}).strict(),Ar=u.object({site_analytics:u.enum(["granted","denied","unknown"]),enhanced_matching:u.enum(["granted","denied","unknown"]),advertising_measurement:u.enum(["granted","denied","unknown"])}).strict(),Sr=u.object({analytics:u.enum(["granted","denied","unknown"]).default("unknown"),adUserData:u.enum(["granted","denied","unknown"]).default("unknown"),adPersonalization:u.enum(["granted","denied","unknown"]).default("unknown"),globalPrivacyControl:u.boolean().default(!1),occurredAt:u.string().datetime(),receiptId:u.string().uuid().optional(),policyVersion:u.number().int().positive().optional(),purposes:Ar.optional()}).strict().transform(e=>({...e,purposes:e.purposes??{site_analytics:e.analytics,enhanced_matching:e.adUserData,advertising_measurement:e.adPersonalization}})),xn=u.enum(["browser","form","call","crm","transaction","custom_server","conversion","delivery"]),hr=u.object({schemaVersion:u.literal(1).default(1),eventId:u.string().trim().min(8).max(200),sourceEventId:u.string().trim().min(1).max(300).optional(),source:u.string().trim().min(1).max(80).default("xray"),sourceAccountRef:u.string().trim().max(240).optional(),eventKind:xn,eventName:u.string().trim().regex(/^[a-z][a-z0-9_]{1,79}$/),occurredAt:u.string().datetime(),visitorId:u.string().trim().max(160).optional(),sessionId:u.string().trim().max(160).optional(),personRef:u.string().trim().max(240).optional(),orderId:u.string().trim().max(240).optional(),callId:u.string().trim().max(240).optional(),dealId:u.string().trim().max(240).optional(),path:u.string().trim().max(2e3).optional(),canonicalUrl:u.string().url().max(3e3).optional(),sourceName:u.string().trim().max(180).optional(),medium:u.string().trim().max(180).optional(),campaign:u.string().trim().max(240).optional(),clickIds:Tn.optional(),consent:Sr.optional(),valueMinor:u.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),currency:u.string().trim().regex(/^[A-Za-z]{3}$/).optional(),properties:u.record(u.string().max(80),u.unknown()).default({})}).strict(),Qe=hr.extend({sourceEventId:u.string().trim().min(1).max(300),source:u.string().trim().min(1).max(80),sourceAccountRef:u.string().trim().min(1).max(240)}),Va=u.object({sourceEventId:u.string().trim().min(1).max(300),source:u.string().trim().min(1).max(80),sourceAccountRef:u.string().trim().min(1).max(240),contactId:u.string().trim().max(240).optional(),dealId:u.string().trim().min(1).max(240),pipelineId:u.string().trim().max(240).optional(),stageId:u.string().trim().min(1).max(240),stageName:u.string().trim().max(240).optional(),occurredAt:u.string().datetime(),valueMinor:u.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),currency:u.string().trim().regex(/^[A-Za-z]{3}$/).optional(),visitorId:u.string().trim().max(160).optional(),sessionId:u.string().trim().max(160).optional(),clickIds:Tn.optional(),email:u.string().email().max(320).optional(),phone:u.string().trim().max(80).optional(),orderId:u.string().trim().max(240).optional(),status:u.enum(["open","won","lost","spam","unknown"]).default("unknown")}).strict(),Nr=u.object({eventName:u.string().regex(/^[a-z][a-z0-9_]{1,79}$/).optional(),eventKind:xn.optional(),source:u.string().trim().max(80).optional(),stageId:u.string().trim().max(240).optional(),status:u.enum(["open","won","lost","spam","unknown"]).optional(),answered:u.boolean().optional(),minimumCallDurationSeconds:u.number().int().min(0).max(86400).optional(),excludedTags:u.array(u.string().trim().max(80)).max(30).default([]),requiredTags:u.array(u.string().trim().max(80)).max(30).default([])}).strict(),Ln=u.object({name:u.string().trim().min(1).max(120),conversionKind:u.string().trim().regex(/^[a-z][a-z0-9_]{1,79}$/),condition:Nr,defaultValueMinor:u.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),defaultCurrency:u.string().trim().regex(/^[A-Za-z]{3}$/).default("USD"),valueRule:Xe.optional(),enabled:u.boolean().default(!0)}).strict();function Cr(e){let t=e.trim().toLowerCase().replace(/\.$/,"");if(!t||t.includes("://")||/[/?#]/.test(t))return"";try{let n=new URL(`https://${t}`).hostname.toLowerCase().replace(/\.$/,"");return!n||n.length>253||n!=="localhost"&&!n.includes(".")||n.split(".").some(i=>!i||i.length>63||!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(i))?"":n}catch{return""}}var wr=u.string().trim().max(253).transform(Cr).refine(Boolean,"Provide a valid bare hostname."),xe=u.string().trim().max(80).regex(/^[A-Za-z][A-Za-z0-9_-]{0,79}$/).refine(e=>(e.match(/\d/g)?.length??0)<7,"Semantic dimensions cannot contain phone-like values.").transform(e=>e.toLowerCase()),Rr=u.object({value:u.number().finite().min(0).max(1e12).optional(),currency:u.string().trim().regex(/^[A-Za-z]{3}$/).transform(e=>e.toUpperCase()).optional(),orderId:u.string().trim().min(1).max(200).optional(),contentId:u.string().trim().min(1).max(200).optional(),contentType:u.string().trim().min(1).max(80).optional(),placement:xe.optional(),component:xe.optional(),action:xe.optional(),destination:xe.optional(),plan:xe.optional()}).strict(),Ct=u.object({name:u.string().trim().min(1).max(120),eventName:u.string().trim().regex(/^[a-z][a-z0-9_]{1,79}$/),triggerKind:u.enum(["page","click","form","semantic"]),path:u.string().trim().startsWith("/").max(2e3).optional(),pathMatch:u.enum(["exact","prefix"]).default("exact"),selector:u.string().trim().min(1).max(500).optional(),hostnames:u.array(wr).max(25).transform(e=>[...new Set(e)]).default([]),metadata:Rr.optional(),valueRule:Xe.optional(),oncePerSession:u.boolean().default(!1),enabled:u.boolean().default(!0)}).strict().superRefine((e,t)=>{e.triggerKind==="page"&&!e.path&&t.addIssue({code:"custom",path:["path"],message:"Page triggers require a path."}),["click","form"].includes(e.triggerKind)&&!e.selector&&t.addIssue({code:"custom",path:["selector"],message:"Click and form triggers require a selector."}),e.triggerKind==="semantic"&&(e.path||e.selector)&&t.addIssue({code:"custom",path:["triggerKind"],message:"Semantic triggers use data-xray-event and cannot include a path or selector."})});import{createHmac as Or,randomUUID as wt}from"crypto";import io from"ipaddr.js";import{randomUUID as $n}from"crypto";async function Ga(e){return(await v().query(`SELECT id, site_id, name, status, version, approved_at
121
121
  FROM analytics_identity_namespaces
122
122
  WHERE site_id=$1 AND status IN ('draft','approved','disabled')
@@ -398,7 +398,7 @@ import{H as sn,_ as an,c as Yt,j as ut,k as je,m as nn,z as rn}from"./chunk-SFUO
398
398
  (SELECT count(DISTINCT s.id)::text FROM analytics_sessions s WHERE s.site_id=p.site_id AND s.person_id=p.id) session_count,
399
399
  ((SELECT count(*) FROM analytics_events e WHERE e.site_id=p.site_id AND e.person_id=p.id)+
400
400
  (SELECT count(*) FROM analytics_external_events x WHERE x.site_id=p.site_id AND x.person_id=p.id))::text event_count
401
- FROM analytics_people p WHERE p.site_id=$1 AND p.id=$2`,[e.siteId,e.personId]);if(!n.rows[0])return{queued:0,reused:0};let i=0,r=0;for(let s of t){if(s.kind==="pipeline_event"&&(!s.mapping||s.mapping.eventName!==e.event.eventName))continue;let a=Zr({personId:e.personId,crmPersonRef:n.rows[0].crm_person_ref,event:e.event,policy:s,consent:e.consent,sessionCount:Number(n.rows[0].session_count),eventCount:Number(n.rows[0].event_count)}),o=s.kind==="pipeline_event"?mt.parse({eventId:e.canonicalEventId,eventName:e.event.eventName,occurredAt:e.event.occurredAt,...s.mapping?.valueSource==="verified_revenue"&&e.event.valueMinor!==void 0?{verifiedRevenueMinor:e.event.valueMinor,currency:e.event.currency?.toUpperCase()}:{}}):null;if(s.kind==="pipeline_event"&&s.mapping?.valueSource==="verified_revenue"&&o?.verifiedRevenueMinor===void 0)continue;let c=ti.parse({person:a,event:o,mapping:s.mapping}),l=`${s.policyId}:${s.version}:${e.canonicalEventId}`,_=et({policy:s,personId:e.personId,event:o,projection:a});(await qn({jobId:Xr("crmjob",{idempotencyKey:l}),policy:s,personId:e.personId,sourceEventId:e.canonicalEventId,payloadCiphertext:ue(JSON.stringify(c),"crm-outbound-payload"),idempotencyKey:l,requestFingerprint:_,db:e.db})).reused?r+=1:i+=1}return{queued:i,reused:r}}var st={async resolveIdentity(e){return(await nn(e))?.email??null},async callAction(e){return an({identity:e.identity,connectionId:e.connectionId,tool:e.action,input:e.payload,classification:"action",operationKind:"sync",requestId:e.idempotencyKey})},authorizeSend:e=>Wn(e),cancelUnauthorized:e=>Bn(e)};function es(e){let t=e instanceof Error?e.message:String(e);return/schema_changed|mapping_version|not_mapped|verified_revenue|required|disabled/i.test(t)?{code:"crm_outbound_contract_invalid",retryable:!1,rateLimited:!1}:/429|rate.?limit|too many/i.test(t)?{code:"crm_outbound_rate_limited",retryable:!0,rateLimited:!0}:/401|403|scope|permission|unauthorized|forbidden/i.test(t)?{code:"crm_outbound_authorization_required",retryable:!1,rateLimited:!1}:{code:"crm_outbound_provider_unavailable",retryable:!0,rateLimited:!1}}async function uc(e=10,t=Date.now()+Gr,n=st){let i=Math.max(1,Math.min(Yr,e)),r=v();await r.query(`INSERT INTO analytics_crm_outbound_worker_state(worker_key,last_started_at,last_error_code,updated_at)
401
+ FROM analytics_people p WHERE p.site_id=$1 AND p.id=$2`,[e.siteId,e.personId]);if(!n.rows[0])return{queued:0,reused:0};let i=0,r=0;for(let s of t){if(s.kind==="pipeline_event"&&(!s.mapping||s.mapping.eventName!==e.event.eventName))continue;let a=Zr({personId:e.personId,crmPersonRef:n.rows[0].crm_person_ref,event:e.event,policy:s,consent:e.consent,sessionCount:Number(n.rows[0].session_count),eventCount:Number(n.rows[0].event_count)}),o=s.kind==="pipeline_event"?mt.parse({eventId:e.canonicalEventId,eventName:e.event.eventName,occurredAt:e.event.occurredAt,...s.mapping?.valueSource==="verified_revenue"&&e.event.valueMinor!==void 0?{verifiedRevenueMinor:e.event.valueMinor,currency:e.event.currency?.toUpperCase()}:{}}):null;if(s.kind==="pipeline_event"&&s.mapping?.valueSource==="verified_revenue"&&o?.verifiedRevenueMinor===void 0)continue;let c=ti.parse({person:a,event:o,mapping:s.mapping}),l=`${s.policyId}:${s.version}:${e.canonicalEventId}`,_=et({policy:s,personId:e.personId,event:o,projection:a});(await qn({jobId:Xr("crmjob",{idempotencyKey:l}),policy:s,personId:e.personId,sourceEventId:e.canonicalEventId,payloadCiphertext:ue(JSON.stringify(c),"crm-outbound-payload"),idempotencyKey:l,requestFingerprint:_,db:e.db})).reused?r+=1:i+=1}return{queued:i,reused:r}}var st={async resolveIdentity(e){return(await tn(e))?.email??null},async callAction(e){return an({identity:e.identity,connectionId:e.connectionId,tool:e.action,input:e.payload,classification:"action",operationKind:"sync",requestId:e.idempotencyKey})},authorizeSend:e=>Wn(e),cancelUnauthorized:e=>Bn(e)};function es(e){let t=e instanceof Error?e.message:String(e);return/schema_changed|mapping_version|not_mapped|verified_revenue|required|disabled/i.test(t)?{code:"crm_outbound_contract_invalid",retryable:!1,rateLimited:!1}:/429|rate.?limit|too many/i.test(t)?{code:"crm_outbound_rate_limited",retryable:!0,rateLimited:!0}:/401|403|scope|permission|unauthorized|forbidden/i.test(t)?{code:"crm_outbound_authorization_required",retryable:!1,rateLimited:!1}:{code:"crm_outbound_provider_unavailable",retryable:!0,rateLimited:!1}}async function uc(e=10,t=Date.now()+Gr,n=st){let i=Math.max(1,Math.min(Yr,e)),r=v();await r.query(`INSERT INTO analytics_crm_outbound_worker_state(worker_key,last_started_at,last_error_code,updated_at)
402
402
  VALUES('default',now(),NULL,now()) ON CONFLICT(worker_key) DO UPDATE SET last_started_at=now(),last_error_code=NULL,updated_at=now()`);try{let s=await Hn({limit:i,leaseSeconds:90}),a=0,o=0,c=0;for(let d of s){if(Date.now()>=t){await tt({jobId:d.job.jobId,status:"retrying",safeErrorCode:"crm_outbound_tick_deadline",retryAt:new Date(Date.now()+6e4).toISOString()}),o+=1;continue}try{if(!d.schemaCurrent)throw new Error("analytics_crm_schema_changed");let p=Oe(d.payloadCiphertext,"crm-outbound-payload");if(!p)throw new Error("crm_outbound_payload_unreadable");let E=ti.parse(JSON.parse(p)),b=await n.resolveIdentity(d.ownerUserId);if(!b)throw new Error("crm_outbound_owner_identity_unavailable");if(!await(n.authorizeSend??(n===st?st.authorizeSend:async()=>!0))({jobId:d.job.jobId,attempt:d.job.attempts,purpose:d.purpose,consentReceiptRef:E.person.consentReceiptRef})){await(n.cancelUnauthorized??st.cancelUnauthorized)({jobId:d.job.jobId,attempt:d.job.attempts,safeErrorCode:"crm_outbound_privacy_fence_closed"}),c+=1;continue}let h={callAction:({connectionId:m,action:X,payload:D,idempotencyKey:A})=>n.callAction({identity:b,connectionId:m,action:X,payload:D,idempotencyKey:A})},C=d.job.kind==="person_summary"?await zn({provider:d.provider,connectionId:d.connectionId,person:E.person,dependencies:h}):await Yn({provider:d.provider,connectionId:d.connectionId,person:E.person,event:E.event,mapping:E.mapping,dependencies:h});await tt({jobId:d.job.jobId,status:"accepted",externalReceiptId:C.receiptId}),a+=1}catch(p){let E=es(p),b=new Date(Date.now()+(E.rateLimited?30*6e4:Math.min(360*6e4,3e4*2**d.job.attempts))).toISOString();await tt({jobId:d.job.jobId,status:E.retryable?"retrying":"failed",safeErrorCode:E.code,...E.retryable?{retryAt:b}:{}}),E.retryable&&d.job.attempts<5?o+=1:c+=1}}let l=await r.query("SELECT count(*)::int due FROM analytics_crm_outbound_jobs WHERE state IN ('pending','retrying') AND next_attempt_at <= now()"),_={claimed:s.length,delivered:a,retried:o,deadLettered:c,remainingDue:Number(l.rows[0]?.due??0)};return await r.query(`UPDATE analytics_crm_outbound_worker_state SET last_completed_at=now(),last_success_at=now(),
403
403
  last_error_code=NULL,last_claimed=$1,last_remaining_due=$2,updated_at=now() WHERE worker_key='default'`,[_.claimed,_.remainingDue]),_}catch(s){throw await r.query(`UPDATE analytics_crm_outbound_worker_state SET last_completed_at=now(),last_error_code='crm_outbound_worker_failed',updated_at=now()
404
404
  WHERE worker_key='default'`).catch(()=>{}),s}}import{createHash as ts,randomUUID as ii}from"crypto";import{z as g}from"zod";var oe=g.string().trim().min(1).max(160).regex(/^[a-zA-Z0-9_.:-]+$/),$t=g.string().trim().min(1).max(160).regex(/^[a-zA-Z][a-zA-Z0-9_.:-]*$/),ns=g.discriminatedUnion("kind",[g.object({kind:g.literal("event_completed"),eventName:oe,withinDays:g.number().int().min(1).max(3650).optional()}).strict(),g.object({kind:g.literal("event_frequency"),eventName:oe,minimum:g.number().int().min(1).max(1e3),withinDays:g.number().int().min(1).max(3650).optional()}).strict(),g.object({kind:g.literal("event_recency"),eventName:oe,withinDays:g.number().int().min(1).max(3650)}).strict(),g.object({kind:g.literal("page_visited"),path:g.string().trim().startsWith("/").max(2e3),withinDays:g.number().int().min(1).max(3650).optional()}).strict(),g.object({kind:g.literal("referrer_equals"),value:g.string().trim().min(1).max(500)}).strict(),g.object({kind:g.literal("source_equals"),value:g.string().trim().min(1).max(180)}).strict(),g.object({kind:g.literal("call_outcome"),outcome:oe,withinDays:g.number().int().min(1).max(3650).optional()}).strict(),g.object({kind:g.literal("crm_stage"),stage:oe}).strict(),g.object({kind:g.literal("property_equals"),property:$t,value:g.union([g.string().max(500),g.number().finite(),g.boolean()])}).strict(),g.object({kind:g.literal("property_present"),property:$t}).strict()]),is=g.object({id:oe,label:g.string().trim().min(1).max(160),operation:g.enum(["add","subtract"]),points:g.number().int().min(0).max(1e5),cap:g.number().int().min(0).max(1e5).optional(),predicates:g.array(ns).min(1).max(50)}).strict(),ri=g.object({namespaceId:oe,name:g.string().trim().min(1).max(160),kind:g.enum(["fit","engagement","combined"]),targetObject:g.enum(["person","visitor"]),minimum:g.number().int().min(-1e6).max(1e6),maximum:g.number().int().min(-1e6).max(1e6),groups:g.array(is).min(1).max(100),permittedProperties:g.array($t).max(200).default([]),enabled:g.boolean().default(!0)}).strict().superRefine((e,t)=>{e.minimum>=e.maximum&&t.addIssue({code:"custom",path:["maximum"],message:"maximum must be greater than minimum"});let n=new Set(e.permittedProperties);for(let[i,r]of e.groups.entries())for(let[s,a]of r.predicates.entries())(a.kind==="property_equals"||a.kind==="property_present")&&!n.has(a.property)&&t.addIssue({code:"custom",path:["groups",i,"predicates",s,"property"],message:"property is not allowlisted"})});function si(){return{definitions:new Map,evaluations:new Map,evaluationHistory:[]}}var ee=class extends Error{constructor(n,i){super(i);this.code=n;this.name="AnalyticsLeadScoringError"}code};function kt(e){let t=e instanceof Date?e.toISOString():e??new Date().toISOString();if(!Number.isFinite(Date.parse(t)))throw new ee("analytics_score_invalid_time","A valid evaluation time is required.");return new Date(t).toISOString()}function Le(e,t){return`${e}:${t}`}function Pt(e){return{...e,groups:e.groups.map(t=>({...t,predicates:t.predicates.map(n=>({...n}))})),permittedProperties:[...e.permittedProperties]}}function rs(e,t,n){let i=Date.parse(e),r=Date.parse(t);return!Number.isFinite(i)||i>r?!1:n===void 0||r-i<=n*864e5}function ss(e,t,n){let i=(r,s,a)=>(r??[]).filter(o=>o.name===s&&rs(o.occurredAt,n,a));switch(e.kind){case"event_completed":{let r=i(t.events,e.eventName,e.withinDays);return r.length?r.map(s=>s.ref):null}case"event_frequency":{let r=i(t.events,e.eventName,e.withinDays);return r.length>=e.minimum?r.map(s=>s.ref):null}case"event_recency":{let r=i(t.events,e.eventName,e.withinDays);return r.length?r.map(s=>s.ref):null}case"page_visited":{let r=i(t.pages,e.path,e.withinDays);return r.length?r.map(s=>s.ref):null}case"referrer_equals":{let r=(t.referrers??[]).filter(s=>s.name===e.value);return r.length?r.map(s=>s.ref):null}case"source_equals":{let r=(t.sources??[]).filter(s=>s.name===e.value);return r.length?r.map(s=>s.ref):null}case"call_outcome":{let r=i(t.calls,e.outcome,e.withinDays);return r.length?r.map(s=>s.ref):null}case"crm_stage":{let r=i(t.crmStages,e.stage);return r.length?r.map(s=>s.ref):null}case"property_equals":return t.permittedProperties?.[e.property]===e.value?[`property:${e.property}`]:null;case"property_present":{let r=t.permittedProperties?.[e.property];return r!=null?[`property:${e.property}`]:null}}}function as(e){let t=n=>Array.isArray(n)?n.map(t):n&&typeof n=="object"?Object.fromEntries(Object.entries(n).sort(([i],[r])=>i.localeCompare(r)).map(([i,r])=>[i,t(r)])):n;return ts("sha256").update(JSON.stringify(t(e))).digest("hex")}function ai(e){let t=ri.parse(e.definition),n=e.id??ii();if(e.tables.definitions.has(Le(t.namespaceId,n)))throw new ee("analytics_score_exists","A lead score with this ID already exists.");let i=kt(e.now),r={id:n,...t,groups:t.groups.map(s=>({...s,predicates:s.predicates.map(a=>({...a}))})),version:1,createdAt:i,updatedAt:i};return e.tables.definitions.set(Le(t.namespaceId,n),r),Pt(r)}function yc(e){let t=e.tables.definitions.get(Le(e.namespaceId,e.scoreId));if(!t)throw new ee("analytics_score_not_found","Lead score not found.");if(t.version!==e.expectedVersion)throw new ee("analytics_score_version_conflict","The lead score changed; reload before updating.");let n=ri.parse(e.definition);if(n.namespaceId!==e.namespaceId)throw new ee("analytics_score_namespace_mismatch","Lead scores cannot move between namespaces.");let i={...t,...n,groups:n.groups.map(r=>({...r,predicates:r.predicates.map(s=>({...s}))})),version:t.version+1,updatedAt:kt(e.now)};return e.tables.definitions.set(Le(e.namespaceId,e.scoreId),i),Pt(i)}function gc(e){return[...e.tables.definitions.values()].filter(t=>t.namespaceId===e.namespaceId).sort((t,n)=>t.name.localeCompare(n.name)).map(Pt)}function oi(e){let t=e.tables.definitions.get(Le(e.namespaceId,e.scoreId));if(!t||!t.enabled)throw new ee("analytics_score_unavailable","Lead score is missing or disabled.");let n=kt(e.now),i=t.groups.map(_=>{let d=_.predicates.map(b=>ss(b,e.facts,n)),p=d.every(b=>b!==null),E=p?Math.min(_.points,_.cap??_.points):0;return{groupId:_.id,operation:_.operation,matched:p,points:_.operation==="subtract"?-E:E,evidenceRefs:p?[...new Set(d.flatMap(b=>b??[]))].sort():[]}}),r=i.reduce((_,d)=>_+d.points,0),s=Math.max(t.minimum,Math.min(t.maximum,r)),a=[...new Set(i.flatMap(_=>_.evidenceRefs))].sort(),o=as({namespaceId:e.namespaceId,scoreId:e.scoreId,version:t.version,subjectRef:e.subjectRef,identityTier:e.identityTier,components:i,value:s}),c=e.tables.evaluations.get(o);if(c)return{...c,components:c.components.map(_=>({..._,evidenceRefs:[..._.evidenceRefs]})),evidenceRefs:[...c.evidenceRefs]};let l={id:ii(),namespaceId:e.namespaceId,subjectRef:e.subjectRef,identityTier:e.identityTier,scoreId:t.id,scoreVersion:t.version,scoreKind:t.kind,value:s,components:i,evidenceRefs:a,evaluatedAt:n,idempotencyKey:o,providerEligible:e.identityTier==="confirmed"};return e.tables.evaluations.set(o,l),e.tables.evaluationHistory.push(l),{...l,components:l.components.map(_=>({..._,evidenceRefs:[..._.evidenceRefs]})),evidenceRefs:[...l.evidenceRefs]}}import{createHmac as os,timingSafeEqual as cs}from"crypto";function y(e,t=500){if(typeof e!="string"&&typeof e!="number")return;let n=String(e).trim();return n?n.slice(0,t):void 0}function Y(e){let t=Number(e);return Number.isFinite(t)?t:void 0}function ce(e){if(typeof e=="boolean")return e;if(e==="true"||e==="1"||e===1)return!0;if(e==="false"||e==="0"||e===0)return!1}function $e(e){if(Array.isArray(e))return e.map(n=>y(n,80)).filter(n=>!!n).slice(0,30);let t=y(e,1e3);return t?t.split(",").map(n=>n.trim()).filter(Boolean).slice(0,30):[]}function G(...e){for(let t of e){let n=y(t,100);if(!n)continue;let i=new Date(n);if(Number.isFinite(i.getTime()))return i.toISOString()}return new Date().toISOString()}function ve(e,t,n){return os(e,t).update(n).digest("base64")}function Ee(e,t){if(!e||e.length!==t.length)return!1;try{return cs(Buffer.from(e),Buffer.from(t))}catch{return!1}}function be(e,t=Date.now(),n=300*1e3){let i=y(e,100);if(!i)return!1;let r=Number(i),s=Number.isFinite(r)?r>1e10?r:r*1e3:Date.parse(i);return Number.isFinite(s)&&Math.abs(t-s)<=n}function Ec(e){let t=new URL(e.requestUrl);for(let s of e.internalRewriteQueryKeys??[])t.searchParams.delete(s);let n=e.publicOrigin?.trim();if(n){let s=new URL(n);if(s.protocol!=="https:"||s.username||s.password)throw new Error("analytics webhook public origin must be an HTTPS origin");return s.pathname=t.pathname,s.search=t.search,s.hash="",s.toString()}let i=e.forwardedProto?.split(",")[0]?.trim(),r=e.forwardedHost?.split(",")[0]?.trim();return i&&(t.protocol=`${i}:`),r&&(t.host=r),t.toString()}function ci(e){return be(e.payloadTimestamp,e.now)&&Ee(e.signature,ve("sha1",e.secret,e.rawBody))}function di(e){let t=e.payload,n=y(t.resource_id??t.id,240)||"unknown",i=G(t.timestamp,t.start_time,t.created_at),r=$e(t.tags??t.tag),s=y(t.lead_status,80),a=s==="not_a_lead"||r.some(c=>c.toLowerCase()==="spam")||ce(t.spam)===!0,o={...y(t.gclid)?{gclid:y(t.gclid)}:{},...y(t.gbraid)?{gbraid:y(t.gbraid)}:{},...y(t.wbraid)?{wbraid:y(t.wbraid)}:{},...y(t.fbclid)?{fbclid:y(t.fbclid)}:{},...y(t.msclkid)?{msclkid:y(t.msclkid)}:{}};return{schemaVersion:1,eventId:`callrail_${n}_${e.phase}`,sourceEventId:`${n}:${e.phase}:${i}`,source:"callrail",sourceAccountRef:e.sourceAccountRef,eventKind:"call",eventName:e.phase==="pre_call"?"call_started":e.phase==="routing_complete"?"call_routed":e.phase==="call_modified"?"call_modified":"call_completed",occurredAt:i,callId:n,personRef:y(t.person_resource_id,240),visitorId:y(t.visitor_id??t.browser_id??t.ga,160),canonicalUrl:y(t.landing_page_url,3e3),sourceName:y(t.utm_source??t.source_name,180),medium:y(t.utm_medium??t.medium,180),campaign:y(t.utm_campaign??t.campaign,240),clickIds:o,properties:{answered:ce(t.answered)??!1,durationSeconds:Y(t.duration)??0,status:a?"spam":s||"unknown",tags:r,direction:y(t.direction,40)||"unknown",trackingNumber:y(t.tracking_phone_number,80)||null,changes:$e(t.changes)}}}function li(e){return be(e.requestTime,e.now)&&Ee(e.signature.trim(),ve("sha1",e.secret,`${e.requestTime}${e.rawBody}`))}function ui(e){let t=e.payload,n=y(t.activity_id??t.call_id??t.id,240)||"unknown",i=G(t.timestamp,t.event_time,t.started_at,t.created_at),r=$e(t.tags??t.tag_list),s=y(t.status??t.disposition,80)||"unknown",a=s.toLowerCase().includes("spam")||r.some(o=>o.toLowerCase()==="spam");return{schemaVersion:1,eventId:`ctm_${n}_${e.phase}`,sourceEventId:`${n}:${e.phase}:${i}`,source:"calltrackingmetrics",sourceAccountRef:e.sourceAccountRef,eventKind:"call",eventName:e.phase.includes("start")?"call_started":e.phase.includes("answer")?"call_answered":"call_completed",occurredAt:i,callId:n,personRef:y(t.contact_id??t.visitor_id,240),visitorId:y(t.visitor_id??t.cookie_id,160),sessionId:y(t.session_id,160),canonicalUrl:y(t.landing_page_url??t.landing_url,3e3),sourceName:y(t.source??t.utm_source,180),medium:y(t.medium??t.utm_medium,180),campaign:y(t.campaign??t.utm_campaign,240),clickIds:{...y(t.gclid)?{gclid:y(t.gclid)}:{},...y(t.fbclid)?{fbclid:y(t.fbclid)}:{},...y(t.msclkid)?{msclkid:y(t.msclkid)}:{}},properties:{answered:ce(t.answered)??e.phase.includes("answer"),durationSeconds:Y(t.duration??t.talk_time)??0,status:a?"spam":s,tags:r,direction:y(t.direction,40)||"unknown",trackingNumber:y(t.tracking_number??t.dialed_number,80)||null,score:Y(t.score)??null}}}import ds from"twilio";function _i(e){return ds.validateRequest(e.authToken,e.signature,e.url,e.params)}function mi(e){let t=e.params,n=y(t.CallSid,240)||"unknown",i=(y(t.CallStatus,80)||"unknown").toLowerCase(),r=G(t.Timestamp,t.CallTimestamp,t.StartTime),s=["completed","busy","failed","no-answer","canceled"].includes(i),a=["in-progress","answered","completed"].includes(i);return{schemaVersion:1,eventId:`twilio_${n}_${i}`,sourceEventId:`${n}:${i}`,source:"twilio",sourceAccountRef:e.sourceAccountRef,eventKind:"call",eventName:s?"call_completed":a?"call_answered":"call_started",occurredAt:r,callId:n,visitorId:y(t.XRayVisitorId,160),sessionId:y(t.XRaySessionId,160),personRef:y(t.ContactId,240),properties:{answered:ce(t.Answered)??a,durationSeconds:Y(t.CallDuration??t.Duration)??0,status:i,direction:y(t.Direction,40)||"unknown",trackingNumber:y(t.To,80)||null,attributionLink:t.XRaySessionId?"explicit_session":"unattributed"}}}import{createCipheriv as ls,createDecipheriv as us,createHash as _s,createHmac as ms}from"crypto";var ke={session:"xrs_",visitor:"xrv_",person:"xrp_",cursor:"xrc_",candidate:"xri_"};function Ut(e){return _s("sha256").update(`xray-report:${e}:`).update(qe()).digest()}function T(e,t,n){let i=Ut("reference"),r=Buffer.from(`v1:${e}:${t}`),s=Buffer.from(n),a=ms("sha256",Ut("reference-iv")).update(r).update(s).digest().subarray(0,12),o=ls("aes-256-gcm",i,a);o.setAAD(r);let c=Buffer.concat([o.update(s),o.final()]);return`${ke[e]}${Buffer.concat([a,c,o.getAuthTag()]).toString("base64url")}`}function at(e,t,n){let i=ke[e];if(!n.startsWith(i))throw new Error("analytics_reference_invalid");try{let r=Buffer.from(n.slice(i.length),"base64url");if(r.length<29)throw new Error("short reference");let s=r.subarray(0,12),a=r.subarray(r.length-16),o=r.subarray(12,r.length-16),c=us("aes-256-gcm",Ut("reference"),s);return c.setAAD(Buffer.from(`v1:${e}:${t}`)),c.setAuthTag(a),Buffer.concat([c.update(o),c.final()]).toString("utf8")}catch{throw new Error("analytics_reference_invalid")}}function ps(e,t){return T("cursor",e,JSON.stringify(t))}function Ae(e,t){if(!t)return null;try{let n=JSON.parse(at("cursor",e,t));if(!n.at||!n.id||Number.isNaN(Date.parse(n.at)))throw new Error("invalid");return n}catch{throw new Error("analytics_cursor_invalid")}}function Se(e){if(e===void 0)return 50;if(!Number.isInteger(e)||e<1||e>100)throw new Error("analytics_limit_invalid");return e}function Mt(e){if(typeof e!="string"||!e)return null;try{let t=new URL(e);return`${t.origin}${t.pathname}`.slice(0,2e3)}catch{return null}}function Ie(e){if(e==null)return null;let t=Number(e);return Number.isFinite(t)?t:null}function N(e){let t=e instanceof Date?e:new Date(e);if(!Number.isFinite(t.getTime()))throw new Error("analytics_timestamp_invalid");return t.toISOString()}function pi(e){return e===null?null:N(e)}function he(e,t,n,i){let r=t.length>n,s=t.slice(0,n),a=s.at(-1);return{items:s.map(i),pageInfo:{hasNextPage:r,nextCursor:r&&a?ps(e,{at:a._cursorAt,id:a._cursorId}):null}}}async function Ne(e,t){await B(t,e.siteId,e.userId)}async function Lc(e,t=v()){await Ne(e,t);let n=Se(e.limit),i=Ae(e.siteId,e.cursor),s=(await t.query(`/* analyticsSessions:keyset */
@@ -932,4 +932,4 @@ MCowBQYDK2VwAyEAi2HR1srL4o18O8BRa7gVJY7G7bupbN3H9AwJrHCDiOg=
932
932
  )
933
933
  ORDER BY edge.confidence DESC, edge.last_seen_at DESC
934
934
  LIMIT 1
935
- FOR SHARE OF p, ns, cs, receipt`,[t.siteId,$("customer_id",t.stableUserId)])).rows[0]??null}async function Wt(e,t){let n=process.env.MCP_SCRAPER_XRAY_SITE_ID?.trim();if(!n)return{status:"skipped",eventName:Pe,reason:"site_not_configured"};if(!Ws(n))return{status:"skipped",eventName:Pe,reason:"site_id_invalid"};let i=String(e.userId).trim();if(!i||!e.invoiceId.trim()||!Number.isSafeInteger(e.amountPaidMinor)||e.amountPaidMinor<0||!/^[a-z]{3}$/i.test(e.currency)||!Number.isFinite(new Date(e.occurredAt).getTime()))throw new Error("analytics_first_party_outcome_invalid");let r=t??{db:v(),record:(a,o)=>Ai({...a,transactionClient:o})},s=await r.db.connect();try{await s.query("BEGIN");let a=await Bs(s,{siteId:n,stableUserId:i});if(!a)return await s.query("ROLLBACK"),{status:"skipped",eventName:Pe,reason:"identity_or_consent_unavailable"};let o={schemaVersion:1,eventId:`mcp_invoice_${e.invoiceId}`.slice(0,200),sourceEventId:`stripe:invoice:${e.invoiceId}`.slice(0,300),source:"mcp_scraper",sourceAccountRef:"first_party_billing",eventKind:"transaction",eventName:Pe,occurredAt:e.occurredAt,personRef:i,orderId:e.invoiceId,valueMinor:e.amountPaidMinor,currency:e.currency.toUpperCase(),consent:{analytics:"granted",adUserData:"granted",adPersonalization:a.advertising_measurement?"granted":"denied",globalPrivacyControl:!1,occurredAt:new Date(a.effective_at).toISOString(),receiptId:a.receipt_id,policyVersion:a.policy_version,purposes:{site_analytics:"granted",enhanced_matching:"granted",advertising_measurement:a.advertising_measurement?"granted":"denied"}},properties:{product:"mcp_scraper",billingKind:"base_plan_paid_invoice",revenueProvenance:"stripe_paid_invoice"}},c=await r.record({siteId:n,event:o},s);return await s.query("COMMIT"),{status:"recorded",eventName:Pe,reason:"recorded",created:c.created,conversionIds:c.conversionIds}}catch(a){throw await s.query("ROLLBACK").catch(()=>{}),a}finally{s.release()}}function Si(e,t){return e&&(t??0)>0}function hi(e){let t=e;return t?.price?.id??t?.pricing?.price_details?.price??t?.plan?.id}function Ce(e){if(typeof e=="string")return e;if(e&&typeof e=="object"&&"id"in e)return String(e.id)}function Vs(e){let t=e.subscription;if(t)return Ce(t);let n=e.parent;return Ce(n?.subscription_details?.subscription)}async function Ks(e,t){let n=await P(e);return n||!t||(n=await je(t),n&&await Ve(n.id,e)),n}async function Js(e,t,n){let i=t.memory_subscription_id;if(!(!i||i===n))try{let r=await e.subscriptions.retrieve(i);r.status!=="canceled"&&!r.cancel_at_period_end&&await e.subscriptions.update(i,{cancel_at_period_end:!0})}catch(r){console.error("[stripe] could not wind down standalone memory subscription",i,r instanceof Error?r.message:r)}}async function Bt(e,t,n){if(!t.id||t.status!=="paid")return{status:"not_applicable",invoiceId:t.id??null};let i=t.lines.data.some(p=>{let E=hi(p);return!!E&&E in L});if(!Si(i,t.total))return{status:"not_applicable",invoiceId:t.id};let r=Vs(t),a=(r?me(await e.subscriptions.retrieve(r))?.price?.id:void 0)??t.lines.data.map(hi).find(p=>!!p&&p in L),o=a?L[a]:void 0;if(!o)return{status:"not_applicable",invoiceId:t.id};let c=Ce(t.customer);if(!c)throw new Error("Paid subscription invoice has no Stripe customer");let l=await Ks(c,t.customer_email);if(!l)throw new Error("Paid subscription invoice does not map to an MCP Scraper account");let _=await vn({invoiceId:t.id,userId:l.id,subscriptionId:r??l.subscription_id,tier:o.tier,concurrency:o.concurrency,creditsMc:o.credits_mc,description:`${o.label} subscription credits`,neverExpires:!!o.credits_never_expire,includedMemoryPlan:o.includes_memory?"pro":null});o.includes_memory&&(await Js(e,l,r??l.subscription_id),await Z(l,V({...l,memory_plan:"pro",subscription_tier:o.tier})));let d=await Je(l);d.ok||console.warn("[stripe] scheduled-action credential sync failed:",d.error??"unknown error");try{await Wt({userId:l.id,invoiceId:t.id,amountPaidMinor:t.amount_paid,currency:t.currency,occurredAt:new Date(((t.status_transitions?.paid_at??n)||Math.floor(Date.now()/1e3))*1e3).toISOString()})}catch(p){console.error("[stripe] X-Ray paid outcome failed",{invoiceId:t.id,error:p instanceof Error?p.message:String(p)})}return{status:_.granted?"fulfilled":"already_fulfilled",invoiceId:t.id,userId:l.id,tier:o.tier}}async function Ni(e,t,n){let i=await e.checkout.sessions.retrieve(t,{expand:["invoice"]});if(i.mode!=="subscription")throw new Error("Checkout session is not a subscription purchase");if(i.payment_status!=="paid"&&i.payment_status!=="no_payment_required")return{status:"not_applicable",invoiceId:Ce(i.invoice)??null};let r=Ce(i.customer);if(n&&r!==n)throw new Error("Checkout session does not belong to this billing account");let s=typeof i.invoice=="object"&&i.invoice&&!("deleted"in i.invoice)?i.invoice:await e.invoices.retrieve(Ce(i.invoice)??"");if(!s?.id)throw new Error("Paid subscription checkout has no invoice");return Bt(e,s,i.created)}var Ci="scale_credit_pack";function ot(e){if(typeof e=="string")return e;if(e&&typeof e=="object"&&"id"in e)return String(e.id)}function wi(e){let t=Number(e);if(!Number.isSafeInteger(t)||t<1||t>lt)throw new Error(`quantity must be a whole number from 1 to ${lt}`);return t}function Vd(e){return e.subscription_tier==="scale"}function Kd(e,t){let n=wi(t);return{purchase_kind:Ci,account_user_id:String(e),eligible_tier:"scale",increment_quantity:String(n),increment_usd:String(Re),credits_per_increment:String(dt)}}async function Ri(e,t,n){let i=await e.checkout.sessions.retrieve(t);if(i.mode!=="payment"||i.metadata?.purchase_kind!==Ci)return{status:"not_applicable",paymentIntentId:ot(i.payment_intent)??null};if(i.payment_status!=="paid")return{status:"not_applicable",paymentIntentId:ot(i.payment_intent)??null};let r=ot(i.customer);if(!r)throw new Error("Paid Scale credit-pack checkout has no Stripe customer");if(n&&r!==n)throw new Error("Checkout session does not belong to this billing account");let s=wi(i.metadata.increment_quantity),a=s*Re*100;if(i.currency!=="usd"||i.amount_subtotal!==a)throw new Error("Scale credit-pack checkout amount does not match the product contract");let o=await e.checkout.sessions.listLineItems(i.id,{limit:2}),c=o.data[0];if(o.data.length!==1||c?.quantity!==s||c.price?.currency!=="usd"||c.price?.unit_amount!==Re*100)throw new Error("Scale credit-pack checkout line item does not match the product contract");let l=await P(r);if(!l)throw new Error("Paid Scale credit-pack checkout does not map to an MCP Scraper account");if(i.metadata.account_user_id!==String(l.id)||i.metadata.eligible_tier!=="scale")throw new Error("Scale credit-pack checkout account metadata does not match the billing account");let _=ot(i.payment_intent);if(!_)throw new Error("Paid Scale credit-pack checkout has no payment intent");let d=s*dt;return{status:(await Yt(l.id,s*tn,Ue.TOPUP,`$${s*Re} Scale credit pack (${d.toLocaleString("en-US")} credits)`,`stripe-payment-intent:${_}`,{neverExpires:!1})).duplicate?"already_fulfilled":"fulfilled",paymentIntentId:_,userId:l.id,quantity:s,credits:d}}var M=new zs(process.env.STRIPE_SECRET_KEY,{apiVersion:"2026-02-25.clover"});async function Xs(e,t){if(!(!e||e===t))try{let n=await M.subscriptions.retrieve(e),i=n.items.data[0]?.price?.id,r=n.status!=="canceled"&&!n.cancel_at_period_end;i&&i in le&&r&&await M.subscriptions.update(e,{cancel_at_period_end:!0})}catch(n){console.error("[stripe] could not wind down standalone memory subscription",e,n instanceof Error?n.message:n)}}var Qs=new Ys;Qs.post("/webhooks",async e=>{let t=e.req.header("stripe-signature"),n=await e.req.text(),i;try{i=M.webhooks.constructEvent(n,t,process.env.STRIPE_WEBHOOK_SECRET)}catch{return e.json({error:"Invalid signature"},400)}try{let r=await fn(i.id,i.type,i.created);return r==="queued"&&Zs(),e.json({received:!0,disposition:r})}catch(r){let s=r instanceof Error?r.message:String(r);return console.error("[stripe] webhook enqueue failed",i.id,s),e.json({error:"Webhook enqueue failed"},500)}});function Zs(){let e=import("./queue-AC4XKD6Z.js").then(({drainStripeEventQueue:t})=>t({limit:10,leaseSeconds:300})).catch(t=>{console.error("[stripe] immediate queue drain failed; the scheduled drain will retry",t instanceof Error?t.message:String(t))});Gs(e)}async function ol(e){if(e.type==="checkout.session.completed"||e.type==="checkout.session.async_payment_succeeded"){let t=e.data.object;t.mode==="payment"?await Ri(M,t.id):await Ni(M,t.id);return}if(e.type==="invoice.created"){let t=e.data.object;Oi(t)&&t.status==="draft"&&await M.invoices.update(t.id,{description:Zt,footer:en,custom_fields:[{name:"Pack benefit",value:"2 browsers per $5 monthly pack"},{name:"Billing cadence",value:"Monthly"}]});return}if(e.type==="invoice.paid"||e.type==="invoice.payment_succeeded"){let t=e.data.object;if(Oi(t)){let i=t.customer_email?void 0:await Ti(t.customer,void 0),r=t.customer_email??i?.email;if(!r)throw new Error("Paid concurrency invoice has no customer receipt email");await ea(t.id,r);return}if(t.lines.data.map(xi).find(i=>i&&i in le))return;await Bt(M,t,e.created)}if(e.type==="customer.subscription.created"||e.type==="customer.subscription.updated"){let t=e.data.object,n=Di(t);if(n){let s=await P(t.customer);if(!s)return;let a=De(t.status);await ft(s.id,a?ta(n):0),await vt(s.id,a?t.id:null);return}let i=me(t)?.price?.id??t.items.data[0]?.price?.id;if(i&&i in le){let s=le[i],a=await Ti(t.customer,t.customer_email);if(a){let o=De(t.status),c=o?s.plan:"free";await _e(a.id,c,o?t.id:null),await Z(a,V({...a,memory_plan:c}))}return}let r=await P(t.customer);if(!r)return;if(i&&i in L){let s=L[i],a=De(t.status),o=a?s.tier:null;if(await Et(r.id,o,a?s.concurrency:0,a?t.id:null),s.includes_memory){let c=a?"pro":"free";a&&await Xs(r.memory_subscription_id,t.id),await _e(r.id,c,null),await Z(r,V({...r,memory_plan:c}))}else r.memory_subscription_id===t.id&&(await _e(r.id,"free",null),await Z(r,V({...r,memory_plan:"free"})));if(a){let c=await Je(r);c.ok||console.warn("[stripe] scheduled-action credential sync failed:",c.error??"unknown error")}}}if(e.type==="customer.subscription.deleted"){let t=e.data.object;if(Di(t)){let i=await P(t.customer);i&&(await ft(i.id,0),await vt(i.id,null));return}let n=me(t)?.price?.id??t.items.data[0]?.price?.id;if(n&&n in L){let i=L[n],r=await P(t.customer);r&&(await Et(r.id,null,0,null),(i.includes_memory||r.memory_subscription_id===t.id)&&(await _e(r.id,"free",null),await Z(r,V({...r,memory_plan:"free"}))));return}if(n&&n in le||await bt(t.id)){let i=await bt(t.id)??await P(t.customer);i&&(await _e(i.id,"free",null),await Z(i,V({...i,memory_plan:"free"})));return}}}function Oi(e){return e.lines.data.some(t=>xi(t)===ct)}async function ea(e,t){let i=(await M.invoicePayments.list({invoice:e,status:"paid",limit:10})).data.find(a=>a.status==="paid");if(!i)throw new Error("Paid concurrency invoice has no paid Stripe payment");let r;if(i.payment.type==="charge")r=i.payment.charge;else if(i.payment.type==="payment_intent"&&i.payment.payment_intent){let a=typeof i.payment.payment_intent=="string"?i.payment.payment_intent:i.payment.payment_intent.id;r=(await M.paymentIntents.retrieve(a,{expand:["latest_charge"]})).latest_charge}if(!r)throw new Error("Paid concurrency invoice has no receipt-capable charge");let s=typeof r=="string"?await M.charges.retrieve(r):r;s.receipt_email!==t&&await M.charges.update(s.id,{receipt_email:t})}function Di(e){return e.items.data.find(t=>t.price?.id===ct)}function ta(e){let t=e.quantity??1;if(!Number.isSafeInteger(t)||t<1)throw new Error("Stripe concurrency pack quantity must be a positive safe integer");return t}function xi(e){let t=e;return t?.price?.id??t?.pricing?.price_details?.price??t?.plan?.id}async function Ti(e,t){let n=await P(e);if(n)return n;if(t)return n=await je(t),n&&await Ve(n.id,e),n}export{Ve as a,ft as b,vt as c,Et as d,_e as e,ma as f,Ki as g,fa as h,In as i,It as j,Na as k,Ca as l,Sn as m,ir as n,wa as o,Ra as p,rr as q,Nn as r,Je as s,ra as t,sa as u,aa as v,oa as w,ca as x,ht as y,K as z,me as A,Ma as B,Ua as C,Fa as D,Xe as E,Qe as F,Ln as G,Cr as H,Rr as I,Ct as J,Ga as K,Xa as L,Qa as M,Za as N,oo as O,Un as P,po as Q,yo as R,go as S,fo as T,vo as U,Eo as V,bo as W,Io as X,Ao as Y,So as Z,ho as _,No as $,Co as aa,jn as ba,wo as ca,Lr as da,Ro as ea,se as fa,nt as ga,F as ha,Oo as ia,Pr as ja,Lo as ka,$o as la,ko as ma,zn as na,Yn as oa,Po as pa,jo as qa,Zn as ra,qo as sa,Hr as ta,Xo as ua,fe as va,Qo as wa,uc as xa,si as ya,ai as za,yc as Aa,gc as Ba,oi as Ca,Ec as Da,ci as Ea,di as Fa,li as Ga,ui as Ha,_i as Ia,mi as Ja,at as Ka,Lc as La,$c as Ma,kc as Na,Pc as Oa,Mc as Pa,Uc as Qa,yi as Ra,gi as Sa,Ft as Ta,fi as Ua,vi as Va,Ds as Wa,cd as Xa,dd as Ya,ld as Za,ud as _a,_d as $a,md as ab,pd as bb,yd as cb,gd as db,fd as eb,vd as fb,Ed as gb,bd as hb,Id as ib,Ad as jb,Sd as kb,Ei as lb,hd as mb,Nd as nb,Ai as ob,Cd as pb,wd as qb,Bt as rb,Ni as sb,wi as tb,Vd as ub,Kd as vb,Ri as wb,M as xb,Qs as yb,ol as zb};
935
+ FOR SHARE OF p, ns, cs, receipt`,[t.siteId,$("customer_id",t.stableUserId)])).rows[0]??null}async function Wt(e,t){let n=process.env.MCP_SCRAPER_XRAY_SITE_ID?.trim();if(!n)return{status:"skipped",eventName:Pe,reason:"site_not_configured"};if(!Ws(n))return{status:"skipped",eventName:Pe,reason:"site_id_invalid"};let i=String(e.userId).trim();if(!i||!e.invoiceId.trim()||!Number.isSafeInteger(e.amountPaidMinor)||e.amountPaidMinor<0||!/^[a-z]{3}$/i.test(e.currency)||!Number.isFinite(new Date(e.occurredAt).getTime()))throw new Error("analytics_first_party_outcome_invalid");let r=t??{db:v(),record:(a,o)=>Ai({...a,transactionClient:o})},s=await r.db.connect();try{await s.query("BEGIN");let a=await Bs(s,{siteId:n,stableUserId:i});if(!a)return await s.query("ROLLBACK"),{status:"skipped",eventName:Pe,reason:"identity_or_consent_unavailable"};let o={schemaVersion:1,eventId:`mcp_invoice_${e.invoiceId}`.slice(0,200),sourceEventId:`stripe:invoice:${e.invoiceId}`.slice(0,300),source:"mcp_scraper",sourceAccountRef:"first_party_billing",eventKind:"transaction",eventName:Pe,occurredAt:e.occurredAt,personRef:i,orderId:e.invoiceId,valueMinor:e.amountPaidMinor,currency:e.currency.toUpperCase(),consent:{analytics:"granted",adUserData:"granted",adPersonalization:a.advertising_measurement?"granted":"denied",globalPrivacyControl:!1,occurredAt:new Date(a.effective_at).toISOString(),receiptId:a.receipt_id,policyVersion:a.policy_version,purposes:{site_analytics:"granted",enhanced_matching:"granted",advertising_measurement:a.advertising_measurement?"granted":"denied"}},properties:{product:"mcp_scraper",billingKind:"base_plan_paid_invoice",revenueProvenance:"stripe_paid_invoice"}},c=await r.record({siteId:n,event:o},s);return await s.query("COMMIT"),{status:"recorded",eventName:Pe,reason:"recorded",created:c.created,conversionIds:c.conversionIds}}catch(a){throw await s.query("ROLLBACK").catch(()=>{}),a}finally{s.release()}}function Si(e,t){return e&&(t??0)>0}function hi(e){let t=e;return t?.price?.id??t?.pricing?.price_details?.price??t?.plan?.id}function Ce(e){if(typeof e=="string")return e;if(e&&typeof e=="object"&&"id"in e)return String(e.id)}function Vs(e){let t=e.subscription;if(t)return Ce(t);let n=e.parent;return Ce(n?.subscription_details?.subscription)}async function Ks(e,t){let n=await P(e);return n||!t||(n=await je(t),n&&await Ve(n.id,e)),n}async function Js(e,t,n){let i=t.memory_subscription_id;if(!(!i||i===n))try{let r=await e.subscriptions.retrieve(i);r.status!=="canceled"&&!r.cancel_at_period_end&&await e.subscriptions.update(i,{cancel_at_period_end:!0})}catch(r){console.error("[stripe] could not wind down standalone memory subscription",i,r instanceof Error?r.message:r)}}async function Bt(e,t,n){if(!t.id||t.status!=="paid")return{status:"not_applicable",invoiceId:t.id??null};let i=t.lines.data.some(p=>{let E=hi(p);return!!E&&E in L});if(!Si(i,t.total))return{status:"not_applicable",invoiceId:t.id};let r=Vs(t),a=(r?me(await e.subscriptions.retrieve(r))?.price?.id:void 0)??t.lines.data.map(hi).find(p=>!!p&&p in L),o=a?L[a]:void 0;if(!o)return{status:"not_applicable",invoiceId:t.id};let c=Ce(t.customer);if(!c)throw new Error("Paid subscription invoice has no Stripe customer");let l=await Ks(c,t.customer_email);if(!l)throw new Error("Paid subscription invoice does not map to an MCP Scraper account");let _=await vn({invoiceId:t.id,userId:l.id,subscriptionId:r??l.subscription_id,tier:o.tier,concurrency:o.concurrency,creditsMc:o.credits_mc,description:`${o.label} subscription credits`,neverExpires:!!o.credits_never_expire,includedMemoryPlan:o.includes_memory?"pro":null});o.includes_memory&&(await Js(e,l,r??l.subscription_id),await Z(l,V({...l,memory_plan:"pro",subscription_tier:o.tier})));let d=await Je(l);d.ok||console.warn("[stripe] scheduled-action credential sync failed:",d.error??"unknown error");try{await Wt({userId:l.id,invoiceId:t.id,amountPaidMinor:t.amount_paid,currency:t.currency,occurredAt:new Date(((t.status_transitions?.paid_at??n)||Math.floor(Date.now()/1e3))*1e3).toISOString()})}catch(p){console.error("[stripe] X-Ray paid outcome failed",{invoiceId:t.id,error:p instanceof Error?p.message:String(p)})}return{status:_.granted?"fulfilled":"already_fulfilled",invoiceId:t.id,userId:l.id,tier:o.tier}}async function Ni(e,t,n){let i=await e.checkout.sessions.retrieve(t,{expand:["invoice"]});if(i.mode!=="subscription")throw new Error("Checkout session is not a subscription purchase");if(i.payment_status!=="paid"&&i.payment_status!=="no_payment_required")return{status:"not_applicable",invoiceId:Ce(i.invoice)??null};let r=Ce(i.customer);if(n&&r!==n)throw new Error("Checkout session does not belong to this billing account");let s=typeof i.invoice=="object"&&i.invoice&&!("deleted"in i.invoice)?i.invoice:await e.invoices.retrieve(Ce(i.invoice)??"");if(!s?.id)throw new Error("Paid subscription checkout has no invoice");return Bt(e,s,i.created)}var Ci="scale_credit_pack";function ot(e){if(typeof e=="string")return e;if(e&&typeof e=="object"&&"id"in e)return String(e.id)}function wi(e){let t=Number(e);if(!Number.isSafeInteger(t)||t<1||t>lt)throw new Error(`quantity must be a whole number from 1 to ${lt}`);return t}function Vd(e){return e.subscription_tier==="scale"}function Kd(e,t){let n=wi(t);return{purchase_kind:Ci,account_user_id:String(e),eligible_tier:"scale",increment_quantity:String(n),increment_usd:String(Re),credits_per_increment:String(dt)}}async function Ri(e,t,n){let i=await e.checkout.sessions.retrieve(t);if(i.mode!=="payment"||i.metadata?.purchase_kind!==Ci)return{status:"not_applicable",paymentIntentId:ot(i.payment_intent)??null};if(i.payment_status!=="paid")return{status:"not_applicable",paymentIntentId:ot(i.payment_intent)??null};let r=ot(i.customer);if(!r)throw new Error("Paid Scale credit-pack checkout has no Stripe customer");if(n&&r!==n)throw new Error("Checkout session does not belong to this billing account");let s=wi(i.metadata.increment_quantity),a=s*Re*100;if(i.currency!=="usd"||i.amount_subtotal!==a)throw new Error("Scale credit-pack checkout amount does not match the product contract");let o=await e.checkout.sessions.listLineItems(i.id,{limit:2}),c=o.data[0];if(o.data.length!==1||c?.quantity!==s||c.price?.currency!=="usd"||c.price?.unit_amount!==Re*100)throw new Error("Scale credit-pack checkout line item does not match the product contract");let l=await P(r);if(!l)throw new Error("Paid Scale credit-pack checkout does not map to an MCP Scraper account");if(i.metadata.account_user_id!==String(l.id)||i.metadata.eligible_tier!=="scale")throw new Error("Scale credit-pack checkout account metadata does not match the billing account");let _=ot(i.payment_intent);if(!_)throw new Error("Paid Scale credit-pack checkout has no payment intent");let d=s*dt;return{status:(await nn(l.id,s*en,Ue.TOPUP,`$${s*Re} Scale credit pack (${d.toLocaleString("en-US")} credits)`,`stripe-payment-intent:${_}`,{neverExpires:!1})).duplicate?"already_fulfilled":"fulfilled",paymentIntentId:_,userId:l.id,quantity:s,credits:d}}var M=new zs(process.env.STRIPE_SECRET_KEY,{apiVersion:"2026-02-25.clover"});async function Xs(e,t){if(!(!e||e===t))try{let n=await M.subscriptions.retrieve(e),i=n.items.data[0]?.price?.id,r=n.status!=="canceled"&&!n.cancel_at_period_end;i&&i in le&&r&&await M.subscriptions.update(e,{cancel_at_period_end:!0})}catch(n){console.error("[stripe] could not wind down standalone memory subscription",e,n instanceof Error?n.message:n)}}var Qs=new Ys;Qs.post("/webhooks",async e=>{let t=e.req.header("stripe-signature"),n=await e.req.text(),i;try{i=M.webhooks.constructEvent(n,t,process.env.STRIPE_WEBHOOK_SECRET)}catch{return e.json({error:"Invalid signature"},400)}try{let r=await fn(i.id,i.type,i.created);return r==="queued"&&Zs(),e.json({received:!0,disposition:r})}catch(r){let s=r instanceof Error?r.message:String(r);return console.error("[stripe] webhook enqueue failed",i.id,s),e.json({error:"Webhook enqueue failed"},500)}});function Zs(){let e=import("./queue-4XHYUV7J.js").then(({drainStripeEventQueue:t})=>t({limit:10,leaseSeconds:300})).catch(t=>{console.error("[stripe] immediate queue drain failed; the scheduled drain will retry",t instanceof Error?t.message:String(t))});Gs(e)}async function ol(e){if(e.type==="checkout.session.completed"||e.type==="checkout.session.async_payment_succeeded"){let t=e.data.object;t.mode==="payment"?await Ri(M,t.id):await Ni(M,t.id);return}if(e.type==="invoice.created"){let t=e.data.object;Oi(t)&&t.status==="draft"&&await M.invoices.update(t.id,{description:Qt,footer:Zt,custom_fields:[{name:"Pack benefit",value:"2 browsers per $5 monthly pack"},{name:"Billing cadence",value:"Monthly"}]});return}if(e.type==="invoice.paid"||e.type==="invoice.payment_succeeded"){let t=e.data.object;if(Oi(t)){let i=t.customer_email?void 0:await Ti(t.customer,void 0),r=t.customer_email??i?.email;if(!r)throw new Error("Paid concurrency invoice has no customer receipt email");await ea(t.id,r);return}if(t.lines.data.map(xi).find(i=>i&&i in le))return;await Bt(M,t,e.created)}if(e.type==="customer.subscription.created"||e.type==="customer.subscription.updated"){let t=e.data.object,n=Di(t);if(n){let s=await P(t.customer);if(!s)return;let a=De(t.status);await ft(s.id,a?ta(n):0),await vt(s.id,a?t.id:null);return}let i=me(t)?.price?.id??t.items.data[0]?.price?.id;if(i&&i in le){let s=le[i],a=await Ti(t.customer,t.customer_email);if(a){let o=De(t.status),c=o?s.plan:"free";await _e(a.id,c,o?t.id:null),await Z(a,V({...a,memory_plan:c}))}return}let r=await P(t.customer);if(!r)return;if(i&&i in L){let s=L[i],a=De(t.status),o=a?s.tier:null;if(await Et(r.id,o,a?s.concurrency:0,a?t.id:null),s.includes_memory){let c=a?"pro":"free";a&&await Xs(r.memory_subscription_id,t.id),await _e(r.id,c,null),await Z(r,V({...r,memory_plan:c}))}else r.memory_subscription_id===t.id&&(await _e(r.id,"free",null),await Z(r,V({...r,memory_plan:"free"})));if(a){let c=await Je(r);c.ok||console.warn("[stripe] scheduled-action credential sync failed:",c.error??"unknown error")}}}if(e.type==="customer.subscription.deleted"){let t=e.data.object;if(Di(t)){let i=await P(t.customer);i&&(await ft(i.id,0),await vt(i.id,null));return}let n=me(t)?.price?.id??t.items.data[0]?.price?.id;if(n&&n in L){let i=L[n],r=await P(t.customer);r&&(await Et(r.id,null,0,null),(i.includes_memory||r.memory_subscription_id===t.id)&&(await _e(r.id,"free",null),await Z(r,V({...r,memory_plan:"free"}))));return}if(n&&n in le||await bt(t.id)){let i=await bt(t.id)??await P(t.customer);i&&(await _e(i.id,"free",null),await Z(i,V({...i,memory_plan:"free"})));return}}}function Oi(e){return e.lines.data.some(t=>xi(t)===ct)}async function ea(e,t){let i=(await M.invoicePayments.list({invoice:e,status:"paid",limit:10})).data.find(a=>a.status==="paid");if(!i)throw new Error("Paid concurrency invoice has no paid Stripe payment");let r;if(i.payment.type==="charge")r=i.payment.charge;else if(i.payment.type==="payment_intent"&&i.payment.payment_intent){let a=typeof i.payment.payment_intent=="string"?i.payment.payment_intent:i.payment.payment_intent.id;r=(await M.paymentIntents.retrieve(a,{expand:["latest_charge"]})).latest_charge}if(!r)throw new Error("Paid concurrency invoice has no receipt-capable charge");let s=typeof r=="string"?await M.charges.retrieve(r):r;s.receipt_email!==t&&await M.charges.update(s.id,{receipt_email:t})}function Di(e){return e.items.data.find(t=>t.price?.id===ct)}function ta(e){let t=e.quantity??1;if(!Number.isSafeInteger(t)||t<1)throw new Error("Stripe concurrency pack quantity must be a positive safe integer");return t}function xi(e){let t=e;return t?.price?.id??t?.pricing?.price_details?.price??t?.plan?.id}async function Ti(e,t){let n=await P(e);if(n)return n;if(t)return n=await je(t),n&&await Ve(n.id,e),n}export{Ve as a,ft as b,vt as c,Et as d,_e as e,ma as f,Ki as g,fa as h,In as i,It as j,Na as k,Ca as l,Sn as m,ir as n,wa as o,Ra as p,rr as q,Nn as r,Je as s,ra as t,sa as u,aa as v,oa as w,ca as x,ht as y,K as z,me as A,Ma as B,Ua as C,Fa as D,Xe as E,Qe as F,Ln as G,Cr as H,Rr as I,Ct as J,Ga as K,Xa as L,Qa as M,Za as N,oo as O,Un as P,po as Q,yo as R,go as S,fo as T,vo as U,Eo as V,bo as W,Io as X,Ao as Y,So as Z,ho as _,No as $,Co as aa,jn as ba,wo as ca,Lr as da,Ro as ea,se as fa,nt as ga,F as ha,Oo as ia,Pr as ja,Lo as ka,$o as la,ko as ma,zn as na,Yn as oa,Po as pa,jo as qa,Zn as ra,qo as sa,Hr as ta,Xo as ua,fe as va,Qo as wa,uc as xa,si as ya,ai as za,yc as Aa,gc as Ba,oi as Ca,Ec as Da,ci as Ea,di as Fa,li as Ga,ui as Ha,_i as Ia,mi as Ja,at as Ka,Lc as La,$c as Ma,kc as Na,Pc as Oa,Mc as Pa,Uc as Qa,yi as Ra,gi as Sa,Ft as Ta,fi as Ua,vi as Va,Ds as Wa,cd as Xa,dd as Ya,ld as Za,ud as _a,_d as $a,md as ab,pd as bb,yd as cb,gd as db,fd as eb,vd as fb,Ed as gb,bd as hb,Id as ib,Ad as jb,Sd as kb,Ei as lb,hd as mb,Nd as nb,Ai as ob,Cd as pb,wd as qb,Bt as rb,Ni as sb,wi as tb,Vd as ub,Kd as vb,Ri as wb,M as xb,Qs as yb,ol as zb};
@@ -0,0 +1,8 @@
1
+ import{a as E}from"./chunk-WP3QS4CJ.js";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,tiktok_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},V={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",TIKTOK_TRANSCRIBE:"tiktok_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",TIKTOK_TRANSCRIBE_REFUND:"tiktok_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"};function $(e){return e===!0?t.serp_headless:t.serp_headful}var o=100,l=20,_=35;function K(e,r){return e*o*(r==="apify"?l:_)}var W=t.browser_minute/6e4;function me(e){return Math.round(e*W)}var Ee=1e3,ge=l,j=t.serp_headful/o,be=t.paa_base/o,Re=t.paa/o,fe=t.page_scrape/o,X={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},Q=2e6,Z=3,I=1e4,A=1e9,z=75,Ce=z*o,J=15e3,Te=J/I,Se=5e3,ee="2026-08-03.connected-usage-v3",y=15e3,Ae=y*o,h=2,v=2,O=5,M=h*o,D=v*o,x=O*o,Ne={schemaVersion:2,ratePolicyVersion:ee,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:h,mc:M,unit:"per_function_run"},proxyRequest:{credits:v,mc:D,unit:"per_proxy_request"},compute:{creditsPerSecond:O,mcPerSecond:x,sourceUnit:"millisecond",unit:"per_compute_second",formula:"ceil(computeMilliseconds * mcPerSecond / 1000)"}}};function g(e,r){if(!Number.isSafeInteger(e)||e<0)throw new Error(`${r} must be a non-negative safe integer`);return BigInt(e)}function p(e){if(e>BigInt(Number.MAX_SAFE_INTEGER))throw new Error("connected usage charge exceeds the safe integer range");return Number(e)}function Ie(e){let r=g(e.functionRuns,"functionRuns"),a=g(e.proxyRequests,"proxyRequests"),s=g(e.computeMilliseconds,"computeMilliseconds"),i=r*BigInt(M),c=a*BigInt(D),d=s*BigInt(x),m=d===0n?0n:(d+999n)/1000n,S=i+c+m;return{functionRunMc:p(i),proxyRequestMc:p(c),computeMc:p(m),amountMc:p(S),credits:p(S)/o}}function ye(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*A))*BigInt(r)*BigInt(Q),i=BigInt(A)*BigInt(I)*BigInt(Z),c=s===0n?0n:(s+i-1n)/i;if(c>BigInt(Number.MAX_SAFE_INTEGER))throw new Error("calculated mc exceeds the safe integer range");return Number(c)}var re=[{key:"serp",label:"SERP search",aliases:["search_serp","serp","google search","organic results"],credits:l,unit:"per page (ordinary search)",notes:`search_serp light mode returns one page of organic positions, URLs, titles, and descriptions by default. Unfiltered one-page full mode returns available same-page SERP features. Either mode requests two pages only when pages:2 is explicit. Unfiltered light searches cost ${l} credits per delivered page, or ${_} credits per delivered page if the backup supplies the result. One-page full searches cost ${_} credits. Setting recency to week or month applies Google's date filter through a managed browser and returns organic results only. It costs ${_} credits for one page; filtered pages:2 follows Google's page-two control and costs ${_*2} credits when both pages are delivered. Unfiltered searches use the managed browser only as the last backup. Unfiltered two-page full searches return organic results only for ${l*2} credits, with rich features marked unsupported. If only page 1 is delivered, the search is marked partial and billed for one delivered page. A temporary ${_}-credit-per-requested-page hold is settled to the delivered rate. Location, language, device, and optional module fields do not change ordinary searches. Saved browser identity and capture_serp_snapshot searches retain their ${j}-credit base price; optional page snapshots add ${n(t.page_scrape)} credit per attempted URL.`},{key:"paa",label:"PAA harvest",aliases:["harvest_paa","paa","people also ask","questions"],credits:n(t.paa),unit:`per question (+${n(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 ${n(t.paa_base)} credit base + ${n(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:n(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:n(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:n(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:n(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:n(t.yt_channel),unit:"per call"},{key:"yt_transcription",label:"YouTube transcription",aliases:["youtube_transcribe","youtube transcript","transcription","yt_transcription"],credits:n(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:n(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:n(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:n(t.maps_place),unit:"per business",notes:"Maps place runs reserve the 60-credit base plus the declared review maximum before browsing. Completed runs settle to the base plus unique saved reviews; stopped attempts are refunded."},{key:"maps_review",label:"Maps review",aliases:["maps_reviews","google reviews","review cards","reviews"],credits:n(t.maps_review),unit:"per review card",notes:"One credit per unique saved review on a completed Maps place run. The declared maximum is held before browsing; unused credits are refunded."},{key:"fb_search",label:"Facebook ad library search",aliases:["facebook_search","fb_search","fb ad search"],credits:n(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:n(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:n(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:n(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:n(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:n(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:"tiktok_transcribe",label:"TikTok video transcription",aliases:["tiktok_video_transcribe","tiktok transcript"],credits:n(2e4),unit:"base + 2/min of video",notes:"Transcribes a public TikTok video from its playback media. Flat 200-credit base plus 2 credits per minute, reconciled after transcription."},{key:"instagram_profile",label:"Instagram profile content discovery",aliases:["instagram_profile_content","instagram profile","instagram content list","ig profile"],credits:n(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:n(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:n(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:n(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:n(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:n(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:n(t.video_analysis),unit:"per 120 frames (max 480)",notes:`Full video breakdown: samples frames across a video up to 60 minutes, analyzes visuals and audio, then produces a summary, pacing, topic outline, key points, hook, style, and replication guidance. Reserves ${n(t.video_analysis)} Credits per requested 120-frame tier, up to 480 frames. Unused frame tiers and failed-run frame charges are refunded. Incurred analysis-model usage is billed separately, including usage before a failure; terminal status checks settle the original run.`},{key:"trustpilot_reviews",label:"Trustpilot review harvest",aliases:["trustpilot_reviews","trustpilot","trustpilot reviews"],credits:n(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:n(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:n(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:n(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:n(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."}],he="price_1Ta1NRS8aAcsk3TGwsRnYbix";function P(e){return e.billing_interval??"month"}function k(e){return e.billed_usd??e.monthly_usd}function w(e){return e.credits_mc/o}var u={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}},R=Object.fromEntries(Object.values(u).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 te(e){let r=Object.values(f).find(a=>a.tier_keys.includes(e));return r?`/${r.slug}/claim`:null}function ne(e){return e?Object.values(f).find(r=>r.tier_keys.includes(e))??null:null}function ve(e,r){let a=ne(e);return a?!a.tier_keys.includes(r):!1}function Oe(e){if(!e)return null;let r=R[e];return r?{tier:r.tier,label:r.label,amount_usd:k(r),interval:P(r),monthly_equivalent_usd:r.monthly_usd,credits_per_interval:w(r),concurrency:r.concurrency,credits_never_expire:!!r.credits_never_expire,includes_memory:!!r.includes_memory,private_offer:!!r.private_offer,offer_claim_path:te(r.tier)}:null}function Me(e){let r=f[e];if(!r)return null;let a=r.tier_keys.map(s=>R[s]).filter(s=>!!s).map(s=>({tier:s.tier,label:s.label,amount_usd:k(s),interval:P(s),monthly_equivalent_usd:s.monthly_usd,credits:w(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 De(){let e=R.starter,r=re.map(({aliases:i,...c})=>({...c,...c.notes?{notes:c.notes.replace(/ via fal\.ai/g,"")}:{}})),a=Object.fromEntries(r.map(i=>[i.key,{credits:i.credits,unit:i.unit,label:i.label,...i.notes?{notes:i.notes}:{}}])),s=Object.values(u).filter(i=>!i.private_offer).map(i=>({tier:i.tier,label:i.label,monthlyUsd:i.monthly_usd,credits:i.credits_mc/o,concurrency:i.concurrency}));return{...E,operationCosts:a,publicTiers:s,concurrencyPack:{ratePolicyVersion:G,monthlyUsd:L,currency:U,interval:F,billingUnit:"pack",slotsPerPack:b},scaleCreditPack:{ratePolicyVersion:se,eligibleTier:"scale",incrementUsd:B,creditsPerIncrement:C,maxQuantity:oe,currency:"usd",expiryMonths:3},creditsPerDollarStarter:Math.round(n(e.credits_mc)/e.monthly_usd),costs:r,scheduling:E.addons.scheduling,connectedAccounts:E.addons.connectedAccounts,listingWrites:X}}var L=5,U="usd",F="month",b=2,G="2026-08-14.concurrency-pack-v1",ie="$5/month for 2 extra browsers",xe="MCP Scraper browser concurrency pack \u2014 each $5 monthly pack adds 2 browsers.",Pe="Billed monthly until canceled. A receipt is emailed after each successful payment.",N="npx -y -p mcp-scraper@latest mcp-scraper-cli billing concurrency checkout",se="2026-09-21.scale-credit-pack-v1",B=10,C=8e4,ke=C*o,oe=100;function we(){let e=process.env.CONCURRENCY_BILLING_URL??"https://mcpscraper.dev/billing";return{product:"Extra browser concurrency pack",rate_policy_version:G,price_label:ie,unit_amount_usd:L,currency:U,interval:F,billing_unit:"pack",pack_quantity:1,slots_per_pack:b,extra_slots:b,billing_url:e,terminal_command:N,terminal_command_with_api_key_env:`MCP_SCRAPER_API_KEY=sk_live_your_key ${N}`}}function n(e){return e/o}var ae="npx -y -p mcp-scraper@latest mcp-scraper-cli billing subscribe";function ce(){return Object.values(u).filter(e=>!e.private_offer).sort((e,r)=>e.credits_mc-r.credits_mc)}function Le(e,r){let a=process.env.TOPUP_URL??"https://mcpscraper.dev/billing",s=n(e),i=n(r),c=ce().map(m=>m.tier).join("|"),d=`${ae} <${c}>`;return{error:"insufficient_balance",error_code:"insufficient_balance",message:`Insufficient credits. Balance: ${s} credits. This call requires ${i} credits. Credits refresh when your plan renews. Scale customers can buy ${C} Credits per $${B} increment; other customers can move to a larger plan at ${a} (terminal: ${d})`,balance_credits:s,required_credits:i,topup_url:a,upgrade_command:d}}var _e=1e7*1,Ue={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}},Fe={free:_e,pro:5e9,team:5e10},le=3;var Ge=19/le,Be=3,Ye=1.5,He=1.5,Y=2e4,H=200;function qe(e){let r=Math.max(1,Math.ceil((e||60)/60));return Y+H*r}var Ve=Y+H*30,$e=u.price_1TmiHRS8aAcsk3TGwmSNfNIa.credits_mc/u.price_1TmiHRS8aAcsk3TGwmSNfNIa.monthly_usd;var q=class extends Error{constructor(){super("Current operation wallet claim and matching durable plan are required"),this.name="WalletClaimLostError"}},T=class extends Error{constructor(){super("Named operation debit plan conflicts with durable billing history"),this.name="DebitPlanConflictError"}};function Ze(e){if(!Number.isSafeInteger(e.userId)||e.userId<=0||!Number.isSafeInteger(e.amountMc)||e.amountMc<=0||!e.key||e.key.length>500||!e.operation||!e.description||e.description.length>500)throw new T;return{sql:`EXISTS (SELECT 1 FROM billing_debits d WHERE d.idempotency_key=? AND d.user_id=?
2
+ AND d.amount_mc=? AND d.operation=? AND d.description=? AND d.status='applied'
3
+ AND NOT EXISTS (SELECT 1 FROM billing_events b WHERE b.user_id=d.user_id
4
+ AND b.billing_class='wallet_hold_settlement'
5
+ AND json_extract(b.metadata,'$.debitIdempotencyKey')=d.idempotency_key))`,args:[e.key,e.userId,e.amountMc,e.operation,e.description]}}function ze(e,r){if(!/^[a-z_]+\.[a-z_]+$/.test(e)||!/^json_extract\([a-z_]+\.[a-z_]+,'\$\.hold\.key'\)$/.test(r))throw new Error("Invalid stored hold selector");return`EXISTS (SELECT 1 FROM billing_debits d WHERE d.user_id=${e}
6
+ AND d.idempotency_key=${r} AND d.status='applied'
7
+ AND NOT EXISTS (SELECT 1 FROM billing_events b WHERE b.user_id=d.user_id
8
+ AND b.billing_class='wallet_hold_settlement' AND json_extract(b.metadata,'$.debitIdempotencyKey')=d.idempotency_key))`}export{q as a,T as b,Ze as c,ze as d,t as e,V as f,$ as g,o as h,_ as i,K as j,me as k,Ee as l,ge as m,j as n,be as o,Re as p,fe as q,X as r,A as s,z as t,Ce as u,J as v,Te as w,Se as x,ee as y,y as z,Ae as A,h as B,v as C,O as D,M as E,Ne as F,Ie as G,ye as H,re as I,he as J,P as K,k as L,w as M,u as N,R as O,te as P,ne as Q,ve as R,Oe as S,Me as T,De as U,L as V,b as W,xe as X,Pe as Y,B as Z,C as _,ke as $,oe as aa,we as ba,n as ca,Le as da,Ue as ea,Fe as fa,Be as ga,Ye as ha,He as ia,Y as ja,H as ka,qe as la,Ve as ma,$e as na};
@@ -1,13 +1,13 @@
1
- import{i as j,m as T}from"./chunk-KXJCGV3H.js";import{m as f,q as b}from"./chunk-HUNSEGUN.js";import{d as m,e as C,i as p}from"./chunk-C7MGJUTU.js";import{a as o}from"./chunk-WNUXMPVX.js";import{createHash as k}from"crypto";import{gunzipSync as M,gzipSync as $}from"zlib";var H=10,E=20*1024*1024;function _(t){return k("sha256").update(t).digest("hex")}function W(t){return!t.acquiredHtml||t.extractionStatus==="failed"?null:{pageId:t.pageId??_(t.archivedUrl??t.url),url:t.archivedUrl??t.url,html:t.acquiredHtml,mainHtml:t.mainHtml??"",markdown:t.bodyMarkdown,htmlSha256:t.htmlSha256??_(t.acquiredHtml),markdownSha256:t.markdownSha256??_(t.bodyMarkdown)}}function A(t){return Buffer.from(JSON.stringify({version:"site-extract-content.v1",pages:t}))}async function y(t){let e=t.pages.flatMap(i=>{let c=W(i);return c?[c]:[]}),n=new Map,r=[],a=0,s=async()=>{if(!r.length)return;let i=A(r);if(i.length>E)throw new Error(`site export content chunk exceeds ${E} bytes`);let c=_(r.map(u=>u.pageId).join("\0")).slice(0,16),l=await j({ownerId:t.ownerId,jobId:t.jobId,createdAt:t.createdAt,chunkKey:`content-${String(a).padStart(4,"0")}-${c}`,content:$(i,{level:6})});for(let u of r)n.set(u.url,{artifactId:l.artifactId,artifactSha256:l.sha256,pageId:u.pageId,uncompressedBytes:i.length});a++,r=[]};for(let i of e){let c=[...r,i];if(r.length>0&&(c.length>H||A(c).length>E)&&await s(),r.push(i),A(r).length>E)throw new Error(`page ${i.pageId} exceeds the durable content chunk limit`)}return await s(),n}function Y(t){let e=new Map;return async n=>{let r=e.get(n.artifactId);if(r&&r.digest!==n.artifactSha256)throw new Error("site export content chunk checksum mismatch");let a=r?.chunk;if(!a){let i=await T({artifactId:n.artifactId,ownerId:t});if(!i)throw new Error("site export content chunk is missing or unauthorized");if(_(i)!==n.artifactSha256)throw new Error("site export content chunk checksum mismatch");let c=M(i);if(c.length>E)throw new Error("site export content chunk exceeds its read limit");if(a=JSON.parse(c.toString("utf8")),a.version!=="site-extract-content.v1"||!Array.isArray(a.pages))throw new Error("site export content chunk has an unsupported contract");for(e.set(n.artifactId,{digest:n.artifactSha256,chunk:a});e.size>2;)e.delete(e.keys().next().value)}let s=a.pages.find(i=>i.pageId===n.pageId);if(!s)throw new Error("site export page is missing from its content chunk");if(_(s.html)!==s.htmlSha256||_(s.markdown)!==s.markdownSha256)throw new Error("site export page checksum mismatch");return s}}import{randomUUID as J}from"crypto";function x(t,e,n=!1){if(!e)return{sql:`NOT EXISTS (SELECT 1 FROM operation_executions x JOIN operation_runs r ON r.id=x.run_id
2
- WHERE r.id='extract-site:' || site_extract_jobs.id AND r.tool='extract_site')`,args:[]};if(e.workflow.runId!==`extract-site:${t}`||n&&(!e.phase||e.recovery))return{sql:"0",args:[]};let r=f(e.workflow,{tool:"extract_site",jobId:t,recovery:e.recovery}),a="site_extract_jobs.user_id = ?";if(!e.phase)return{sql:`(${r.sql} AND ${a})`,args:[...r.args,e.workflow.userId]};if(e.phase.userId!==e.workflow.userId)return{sql:"0",args:[]};let s=f(e.phase,{tool:"extract_site_phase",jobId:t});return{sql:`(${r.sql} AND ${a} AND ${s.sql})`,args:[...r.args,e.workflow.userId,...s.args]}}function h(t="site_extract_jobs."){return`(${b(`${t}id`,`${t}user_id`,"extract_site")}
3
- AND ${b(`${t}id`,`${t}user_id`,"extract_site_phase")})`}function I(){return b("site_extract_jobs.id","site_extract_jobs.user_id","extract_site_phase")}function D(t="site_extract_jobs."){return`(${t}status='running' OR (${t}status='pending' AND ${t}execution_generation=0 AND (
1
+ import{i as T,m as j}from"./chunk-KXJCGV3H.js";import{n as f,r as w}from"./chunk-ANQ4JJVI.js";import{d as E,e as C,i as p}from"./chunk-C7MGJUTU.js";import{a as o}from"./chunk-WNUXMPVX.js";import{createHash as U}from"crypto";import{gunzipSync as k,gzipSync as $}from"zlib";var H=10,m=20*1024*1024;function g(t){return U("sha256").update(t).digest("hex")}function W(t){return!t.acquiredHtml||t.extractionStatus==="failed"?null:{pageId:t.pageId??g(t.archivedUrl??t.url),url:t.archivedUrl??t.url,html:t.acquiredHtml,mainHtml:t.mainHtml??"",markdown:t.bodyMarkdown,htmlSha256:t.htmlSha256??g(t.acquiredHtml),markdownSha256:t.markdownSha256??g(t.bodyMarkdown)}}function A(t){return Buffer.from(JSON.stringify({version:"site-extract-content.v1",pages:t}))}async function I(t){let e=t.pages.flatMap(i=>{let c=W(i);return c?[c]:[]}),n=new Map,r=[],a=0,s=async()=>{if(!r.length)return;let i=A(r);if(i.length>m)throw new Error(`site export content chunk exceeds ${m} bytes`);let c=g(r.map(l=>l.pageId).join("\0")).slice(0,16),u=await T({ownerId:t.ownerId,jobId:t.jobId,createdAt:t.createdAt,chunkKey:`content-${String(a).padStart(4,"0")}-${c}`,content:$(i,{level:6})});for(let l of r)n.set(l.url,{artifactId:u.artifactId,artifactSha256:u.sha256,pageId:l.pageId,uncompressedBytes:i.length});a++,r=[]};for(let i of e){let c=[...r,i];if(r.length>0&&(c.length>H||A(c).length>m)&&await s(),r.push(i),A(r).length>m)throw new Error(`page ${i.pageId} exceeds the durable content chunk limit`)}return await s(),n}function Y(t){let e=new Map;return async n=>{let r=e.get(n.artifactId);if(r&&r.digest!==n.artifactSha256)throw new Error("site export content chunk checksum mismatch");let a=r?.chunk;if(!a){let i=await j({artifactId:n.artifactId,ownerId:t});if(!i)throw new Error("site export content chunk is missing or unauthorized");if(g(i)!==n.artifactSha256)throw new Error("site export content chunk checksum mismatch");let c=k(i);if(c.length>m)throw new Error("site export content chunk exceeds its read limit");if(a=JSON.parse(c.toString("utf8")),a.version!=="site-extract-content.v1"||!Array.isArray(a.pages))throw new Error("site export content chunk has an unsupported contract");for(e.set(n.artifactId,{digest:n.artifactSha256,chunk:a});e.size>2;)e.delete(e.keys().next().value)}let s=a.pages.find(i=>i.pageId===n.pageId);if(!s)throw new Error("site export page is missing from its content chunk");if(g(s.html)!==s.htmlSha256||g(s.markdown)!==s.markdownSha256)throw new Error("site export page checksum mismatch");return s}}import{randomUUID as J}from"crypto";function x(t,e,n=!1){if(!e)return{sql:`NOT EXISTS (SELECT 1 FROM operation_executions x JOIN operation_runs r ON r.id=x.run_id
2
+ WHERE r.id='extract-site:' || site_extract_jobs.id AND r.tool='extract_site')`,args:[]};if(e.workflow.runId!==`extract-site:${t}`||n&&(!e.phase||e.recovery))return{sql:"0",args:[]};let r=f(e.workflow,{tool:"extract_site",jobId:t,recovery:e.recovery}),a="site_extract_jobs.user_id = ?";if(!e.phase)return{sql:`(${r.sql} AND ${a})`,args:[...r.args,e.workflow.userId]};if(e.phase.userId!==e.workflow.userId)return{sql:"0",args:[]};let s=f(e.phase,{tool:"extract_site_phase",jobId:t});return{sql:`(${r.sql} AND ${a} AND ${s.sql})`,args:[...r.args,e.workflow.userId,...s.args]}}function h(t="site_extract_jobs."){return`(${w(`${t}id`,`${t}user_id`,"extract_site")}
3
+ AND ${w(`${t}id`,`${t}user_id`,"extract_site_phase")})`}function y(){return w("site_extract_jobs.id","site_extract_jobs.user_id","extract_site_phase")}function D(t="site_extract_jobs."){return`(${t}status='running' OR (${t}status='pending' AND ${t}execution_generation=0 AND (
4
4
  EXISTS (SELECT 1 FROM operation_runs r WHERE r.id='extract-site:' || ${t}id AND r.user_id=${t}user_id AND r.tool='extract_site')
5
- OR COALESCE(json_extract(${t}options,'$.__websiteExecutionProtocol'),0) <> 1)))`}var q="xray_entitlement";function st(t){let e=Math.max(1,Number(t.options.effectiveMaxPages??t.options.maxPages??1)),n=Math.max(e,Number(t.options.requestedMaxPages??e)),r=n>e;return{requestedMaxPages:n,effectiveMaxPages:e,creditLimited:r,creditTruncated:r&&t.totalUrls>=e}}function it(t,e=!1){return t.successfulUrls===0?"failed":t.failedUrls>0||t.remainingUrls>0||e?"partial":"complete"}function g(t){let e=Number(t.total_urls??0),n=t.attempted_urls==null,r=Number(n?t.done_urls??0:t.attempted_urls),a=Number(n?t.done_urls??0:t.successful_urls??0),s=Number(t.failed_urls??Math.max(0,r-a)),i=t.options?JSON.parse(String(t.options)):{},c=i.__websiteExecutionProtocol;delete i.__websiteExecutionProtocol;let l={id:String(t.id),userId:t.user_id!=null?Number(t.user_id):null,idempotencyKey:t.idempotency_key!=null?String(t.idempotency_key):null,requestFingerprint:t.request_fingerprint!=null?String(t.request_fingerprint):null,status:t.status!=null?String(t.status):"pending",executionGeneration:Number(t.execution_generation??0),refinalizeUntil:t.refinalize_until==null?null:String(t.refinalize_until),settlementPlan:t.settlement_plan_json?JSON.parse(String(t.settlement_plan_json)):null,settlementReceipt:t.settlement_receipt_json?JSON.parse(String(t.settlement_receipt_json)):null,dispatchClaimToken:t.dispatch_claim_token==null?null:String(t.dispatch_claim_token),dispatchClaimUntil:t.dispatch_claim_until==null?null:String(t.dispatch_claim_until),dispatchedAt:t.dispatched_at==null?null:String(t.dispatched_at),dispatchAttempts:Number(t.dispatch_attempts??0),dispatchError:t.dispatch_error==null?null:String(t.dispatch_error),startUrl:String(t.start_url??""),options:i,totalUrls:e,doneUrls:r,attemptedUrls:r,successfulUrls:a,failedUrls:s,remainingUrls:Math.max(0,e-r),artifacts:t.artifacts?JSON.parse(String(t.artifacts)):null,error:t.error!=null?String(t.error):null,publicError:C(t.public_error_json),billedMc:t.billed_mc!=null?Number(t.billed_mc):null,createdAt:String(t.created_at??""),updatedAt:String(t.updated_at??"")};return c===1&&Object.defineProperty(l,"executionProtocol",{value:1,enumerable:!1}),l}async function v(t,e){let r=await o().execute({sql:"SELECT * FROM site_extract_jobs WHERE user_id = ? AND idempotency_key = ? LIMIT 1",args:[t,e]});return r.rows[0]?g(r.rows[0]):null}async function ot(t){let n=await o().execute({sql:`INSERT OR IGNORE INTO site_extract_jobs
5
+ OR COALESCE(json_extract(${t}options,'$.__websiteExecutionProtocol'),0) <> 1)))`}var q="xray_entitlement";function st(t){let e=Math.max(1,Number(t.options.effectiveMaxPages??t.options.maxPages??1)),n=Math.max(e,Number(t.options.requestedMaxPages??e)),r=n>e;return{requestedMaxPages:n,effectiveMaxPages:e,creditLimited:r,creditTruncated:r&&t.totalUrls>=e}}function it(t,e=!1){return t.successfulUrls===0?"failed":t.failedUrls>0||t.remainingUrls>0||e?"partial":"complete"}function _(t){let e=Number(t.total_urls??0),n=t.attempted_urls==null,r=Number(n?t.done_urls??0:t.attempted_urls),a=Number(n?t.done_urls??0:t.successful_urls??0),s=Number(t.failed_urls??Math.max(0,r-a)),i=t.options?JSON.parse(String(t.options)):{},c=i.__websiteExecutionProtocol;delete i.__websiteExecutionProtocol;let u={id:String(t.id),userId:t.user_id!=null?Number(t.user_id):null,idempotencyKey:t.idempotency_key!=null?String(t.idempotency_key):null,requestFingerprint:t.request_fingerprint!=null?String(t.request_fingerprint):null,status:t.status!=null?String(t.status):"pending",executionGeneration:Number(t.execution_generation??0),refinalizeUntil:t.refinalize_until==null?null:String(t.refinalize_until),settlementPlan:t.settlement_plan_json?JSON.parse(String(t.settlement_plan_json)):null,settlementReceipt:t.settlement_receipt_json?JSON.parse(String(t.settlement_receipt_json)):null,dispatchClaimToken:t.dispatch_claim_token==null?null:String(t.dispatch_claim_token),dispatchClaimUntil:t.dispatch_claim_until==null?null:String(t.dispatch_claim_until),dispatchedAt:t.dispatched_at==null?null:String(t.dispatched_at),dispatchAttempts:Number(t.dispatch_attempts??0),dispatchError:t.dispatch_error==null?null:String(t.dispatch_error),startUrl:String(t.start_url??""),options:i,totalUrls:e,doneUrls:r,attemptedUrls:r,successfulUrls:a,failedUrls:s,remainingUrls:Math.max(0,e-r),artifacts:t.artifacts?JSON.parse(String(t.artifacts)):null,error:t.error!=null?String(t.error):null,publicError:C(t.public_error_json),billedMc:t.billed_mc!=null?Number(t.billed_mc):null,createdAt:String(t.created_at??""),updatedAt:String(t.updated_at??"")};return c===1&&Object.defineProperty(u,"executionProtocol",{value:1,enumerable:!1}),u}async function v(t,e){let r=await o().execute({sql:"SELECT * FROM site_extract_jobs WHERE user_id = ? AND idempotency_key = ? LIMIT 1",args:[t,e]});return r.rows[0]?_(r.rows[0]):null}async function ot(t){let n=await o().execute({sql:`INSERT OR IGNORE INTO site_extract_jobs
6
6
  (id, user_id, status, start_url, options, idempotency_key, request_fingerprint, created_at, updated_at)
7
- VALUES (?, ?, 'pending', ?, ?, ?, ?, datetime('now'), datetime('now'))`,args:[t.jobId,t.userId,t.startUrl,JSON.stringify({...t.options,__websiteExecutionProtocol:1}),t.idempotencyKey,t.requestFingerprint]}),r=await v(t.userId,t.idempotencyKey);if(!r)throw new Error("idempotent extract job was not persisted");return{job:r,created:n.rowsAffected===1,conflict:r.requestFingerprint!==t.requestFingerprint}}async function P(t){let n=await o().execute({sql:"SELECT * FROM site_extract_jobs WHERE id = ?",args:[t]});return n.rows[0]?g(n.rows[0]):null}async function ct(t=25){return(await o().execute({sql:`SELECT * FROM site_extract_jobs
7
+ VALUES (?, ?, 'pending', ?, ?, ?, ?, datetime('now'), datetime('now'))`,args:[t.jobId,t.userId,t.startUrl,JSON.stringify({...t.options,__websiteExecutionProtocol:1}),t.idempotencyKey,t.requestFingerprint]}),r=await v(t.userId,t.idempotencyKey);if(!r)throw new Error("idempotent extract job was not persisted");return{job:r,created:n.rowsAffected===1,conflict:r.requestFingerprint!==t.requestFingerprint}}async function P(t){let n=await o().execute({sql:"SELECT * FROM site_extract_jobs WHERE id = ?",args:[t]});return n.rows[0]?_(n.rows[0]):null}async function ct(t=25){return(await o().execute({sql:`SELECT * FROM site_extract_jobs
8
8
  WHERE billed_mc IS NULL AND status IN ('complete', 'partial', 'failed')
9
9
  AND (next_settlement_at IS NULL OR next_settlement_at <= datetime('now'))
10
- ORDER BY updated_at ASC LIMIT ?`,args:[Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(r=>g(r))}var w=`(
10
+ ORDER BY updated_at ASC LIMIT ?`,args:[Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(r=>_(r))}var N=`(
11
11
  EXISTS (SELECT 1 FROM billing_debits d
12
12
  WHERE d.idempotency_key = json_extract(site_extract_jobs.options, '$.debitKey')
13
13
  AND d.user_id = site_extract_jobs.user_id AND d.status = 'applied'
@@ -25,33 +25,40 @@ import{i as j,m as T}from"./chunk-KXJCGV3H.js";import{m as f,q as b}from"./chunk
25
25
  AND json_type(options, '$.xraySetupReceipt.heldMc') IN ('integer', 'real')
26
26
  AND json_extract(options, '$.xraySetupReceipt.heldMc') = 0
27
27
  AND json_type(options, '$.xraySetupReceipt.billedMc') IN ('integer', 'real')
28
- AND json_extract(options, '$.xraySetupReceipt.billedMc') = 0))`;async function lt(t){let e=await o().execute({sql:`SELECT * FROM site_extract_jobs WHERE id = ? AND user_id > 0
28
+ AND json_extract(options, '$.xraySetupReceipt.billedMc') = 0))`;async function ut(t){let e=await o().execute({sql:`SELECT * FROM site_extract_jobs WHERE id = ? AND user_id > 0
29
29
  AND status IN ('pending', 'running') AND billed_mc IS NULL
30
- AND execution_generation = 0 AND ${w}`,args:[t]});return e.rows[0]?g(e.rows[0]):null}async function F(t=25,e=2){let n=Math.max(1,Math.min(60,Math.round(e)));return(await o().execute({sql:`SELECT * FROM site_extract_jobs WHERE status = 'pending' AND billed_mc IS NULL
31
- AND execution_generation = 0 AND dispatched_at IS NULL AND ${w}
30
+ AND execution_generation = 0 AND ${N}`,args:[t]});return e.rows[0]?_(e.rows[0]):null}async function F(t=25,e=2){let n=Math.max(1,Math.min(60,Math.round(e)));return(await o().execute({sql:`SELECT * FROM site_extract_jobs WHERE status = 'pending' AND billed_mc IS NULL
31
+ AND execution_generation = 0 AND dispatched_at IS NULL AND ${N}
32
32
  AND (dispatch_claim_token IS NULL OR dispatch_claim_until <= datetime('now'))
33
33
  AND (next_dispatch_at IS NULL OR next_dispatch_at <= datetime('now'))
34
- AND updated_at <= datetime('now', ?) ORDER BY updated_at, id LIMIT ?`,args:[`-${n} minutes`,Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(a=>g(a))}async function ut(t={}){let e=t.jobId?[t.jobId]:(await F(t.limit)).map(r=>r.id),n=[];for(let r of e){let a=J(),i=(await o().execute({sql:`UPDATE site_extract_jobs SET dispatch_claim_token = ?, dispatch_claim_until = datetime('now', ?),
34
+ AND updated_at <= datetime('now', ?) ORDER BY updated_at, id LIMIT ?`,args:[`-${n} minutes`,Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(a=>_(a))}async function lt(t=25){return(await o().execute({sql:`SELECT * FROM site_extract_jobs WHERE status IN ('pending', 'running') AND billed_mc IS NULL
35
+ AND execution_generation = 0 AND ${N}
36
+ AND (
37
+ (dispatched_at <= datetime('now', '-30 seconds') AND NOT EXISTS (SELECT 1 FROM operation_executions e WHERE e.run_id = 'extract-site:' || site_extract_jobs.id))
38
+ OR EXISTS (SELECT 1 FROM operation_executions e JOIN operation_runs r ON r.id = e.run_id
39
+ WHERE e.run_id = 'extract-site:' || site_extract_jobs.id AND r.status = 'running'
40
+ AND e.phase = 'claimed' AND e.expires_at_ms <= CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
41
+ ) ORDER BY updated_at, id LIMIT ?`,args:[Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(n=>_(n))}async function dt(t={}){let e=t.jobId?[t.jobId]:(await F(t.limit)).map(r=>r.id),n=[];for(let r of e){let a=J(),i=(await o().execute({sql:`UPDATE site_extract_jobs SET dispatch_claim_token = ?, dispatch_claim_until = datetime('now', ?),
35
42
  dispatch_attempts = dispatch_attempts + 1, dispatch_error = NULL, next_dispatch_at = NULL,
36
43
  updated_at = datetime('now')
37
44
  WHERE id = ? AND status = 'pending' AND billed_mc IS NULL AND execution_generation = 0
38
- AND dispatched_at IS NULL AND ${w}
45
+ AND dispatched_at IS NULL AND ${N}
39
46
  AND (dispatch_claim_token IS NULL OR dispatch_claim_until <= datetime('now'))
40
47
  AND (next_dispatch_at IS NULL OR next_dispatch_at <= datetime('now'))
41
- RETURNING id, dispatch_claim_token, dispatch_attempts`,args:[a,`+${Math.max(15,Math.min(3600,Math.round(t.leaseSeconds??300)))} seconds`,r]})).rows[0];i&&n.push({id:String(i.id),claimToken:String(i.dispatch_claim_token),attempts:Number(i.dispatch_attempts)})}return n}async function dt(t,e){return(await o().execute({sql:`SELECT id FROM site_extract_jobs WHERE id = ? AND status = 'pending' AND billed_mc IS NULL
48
+ RETURNING id, dispatch_claim_token, dispatch_attempts`,args:[a,`+${Math.max(15,Math.min(3600,Math.round(t.leaseSeconds??300)))} seconds`,r]})).rows[0];i&&n.push({id:String(i.id),claimToken:String(i.dispatch_claim_token),attempts:Number(i.dispatch_attempts)})}return n}async function _t(t,e){return(await o().execute({sql:`SELECT id FROM site_extract_jobs WHERE id = ? AND status = 'pending' AND billed_mc IS NULL
42
49
  AND execution_generation = 0 AND dispatched_at IS NULL AND dispatch_claim_token = ?
43
- AND dispatch_claim_until > datetime('now') AND ${w}`,args:[t,e]})).rows.length===1}async function _t(t,e){return(await o().execute({sql:`UPDATE site_extract_jobs SET dispatched_at = datetime('now'), dispatch_claim_token = NULL,
50
+ AND dispatch_claim_until > datetime('now') AND ${N}`,args:[t,e]})).rows.length===1}async function gt(t,e){return(await o().execute({sql:`UPDATE site_extract_jobs SET dispatched_at = datetime('now'), dispatch_claim_token = NULL,
44
51
  dispatch_claim_until = NULL, next_dispatch_at = NULL, dispatch_error = NULL, updated_at = datetime('now')
45
52
  WHERE id = ? AND execution_generation = 0 AND dispatched_at IS NULL
46
- AND dispatch_claim_token = ? AND dispatch_claim_until > datetime('now')`,args:[t,e]})).rowsAffected===1}async function gt(t,e,n,r){return(await o().execute({sql:`UPDATE site_extract_jobs SET dispatch_error = ?, next_dispatch_at = datetime('now', ?),
53
+ AND dispatch_claim_token = ? AND dispatch_claim_until > datetime('now')`,args:[t,e]})).rowsAffected===1}async function pt(t,e,n,r){return(await o().execute({sql:`UPDATE site_extract_jobs SET dispatch_error = ?, next_dispatch_at = datetime('now', ?),
47
54
  dispatch_claim_token = NULL, dispatch_claim_until = NULL, updated_at = datetime('now')
48
55
  WHERE id = ? AND status = 'pending' AND billed_mc IS NULL AND execution_generation = 0
49
- AND dispatched_at IS NULL AND dispatch_claim_token = ? AND dispatch_claim_until > datetime('now')`,args:[n.slice(0,2e3),`+${Math.max(15,Math.min(3600,Math.round(r)))} seconds`,t,e]})).rowsAffected===1}async function pt(t,e,n=0){await o().execute({sql:`UPDATE site_extract_jobs SET
56
+ AND dispatched_at IS NULL AND dispatch_claim_token = ? AND dispatch_claim_until > datetime('now')`,args:[n.slice(0,2e3),`+${Math.max(15,Math.min(3600,Math.round(r)))} seconds`,t,e]})).rowsAffected===1}async function Et(t,e,n=0){await o().execute({sql:`UPDATE site_extract_jobs SET
50
57
  settlement_attempts = settlement_attempts + 1,
51
58
  settlement_error = ?,
52
59
  next_settlement_at = datetime('now', '+15 minutes'),
53
60
  updated_at = datetime('now')
54
- WHERE id = ? AND billed_mc IS NULL AND execution_generation = ? AND status IN ('complete', 'partial', 'failed')`,args:[p(e).slice(0,1e3),t,n]})}function U(t=""){return`((${t}execution_generation = 0 AND ${t}updated_at <= datetime('now', ?))
61
+ WHERE id = ? AND billed_mc IS NULL AND execution_generation = ? AND status IN ('complete', 'partial', 'failed')`,args:[p(e).slice(0,1e3),t,n]})}function O(t=""){return`((${t}execution_generation = 0 AND ${t}updated_at <= datetime('now', ?))
55
62
  OR (${t}execution_generation > 0 AND ${t}refinalize_until <= datetime('now')))`}async function mt(t=25,e=60){let n=o(),r=Math.max(15,Math.min(1440,Math.round(e)));return(await n.execute({sql:`SELECT j.* FROM site_extract_jobs j
56
63
  LEFT JOIN billing_debits d
57
64
  ON d.idempotency_key = json_extract(j.options, '$.debitKey')
@@ -63,8 +70,8 @@ import{i as j,m as T}from"./chunk-KXJCGV3H.js";import{m as f,q as b}from"./chunk
63
70
  json_extract(j.options, '$.debitKey') IS NULL
64
71
  OR d.idempotency_key IS NOT NULL
65
72
  )
66
- AND ${U("j.")} AND ${h("j.")}
67
- ORDER BY j.updated_at ASC LIMIT ?`,args:[`-${r} minutes`,Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(s=>g(s))}async function Et(t,e=60){let n=o(),r=Math.max(15,Math.min(1440,Math.round(e)));return(await n.execute({sql:`UPDATE site_extract_jobs
73
+ AND ${O("j.")} AND ${h("j.")}
74
+ ORDER BY j.updated_at ASC LIMIT ?`,args:[`-${r} minutes`,Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(s=>_(s))}async function xt(t,e=60){let n=o(),r=Math.max(15,Math.min(1440,Math.round(e)));return(await n.execute({sql:`UPDATE site_extract_jobs
68
75
  SET status = 'failed',
69
76
  error = 'Background extraction attempt expired; completed pages were preserved and settlement is pending.',
70
77
  public_error_json = ?,
@@ -72,16 +79,16 @@ import{i as j,m as T}from"./chunk-KXJCGV3H.js";import{m as f,q as b}from"./chunk
72
79
  WHERE id = ?
73
80
  AND ${D()}
74
81
  AND billed_mc IS NULL
75
- AND ${U()} AND ${h()}`,args:[m({error_code:"extraction_failed",error_type:"extraction",message:"The background extraction attempt expired. Completed pages were preserved; retry after settlement completes.",retryable:!0,charge_status:"refund_pending"}),t,`-${r} minutes`]})).rowsAffected===1}async function xt(t){let e=await o().execute({sql:`UPDATE site_extract_jobs
82
+ AND ${O()} AND ${h()}`,args:[E({error_code:"extraction_failed",error_type:"extraction",message:"The background extraction attempt expired. Completed pages were preserved; retry after settlement completes.",retryable:!0,charge_status:"refund_pending"}),t,`-${r} minutes`]})).rowsAffected===1}async function Nt(t){let e=await o().execute({sql:`UPDATE site_extract_jobs
76
83
  SET status = 'running', execution_generation = execution_generation + 1,
77
84
  refinalize_until = datetime('now', '+60 minutes'), updated_at = datetime('now')
78
85
  WHERE id = ? AND (settlement_plan_json IS NULL OR billed_mc IS NOT NULL) AND (status = 'failed' OR (
79
86
  status = 'running' AND execution_generation > 0 AND refinalize_until <= datetime('now')
80
- )) RETURNING *`,args:[t]});return e.rows[0]?g(e.rows[0]):null}async function z(t,e=0){return(await o().execute({sql:`SELECT 1 FROM site_extract_jobs WHERE id = ? AND status IN ('pending', 'running')
81
- AND execution_generation = ? AND (execution_generation = 0 OR refinalize_until > datetime('now'))`,args:[t,e]})).rows.length===1}async function Nt(t,e,n=0){await o().execute({sql:`UPDATE site_extract_jobs SET billed_mc = 0, settlement_error = ?, updated_at = datetime('now')
82
- WHERE id = ? AND billed_mc IS NULL AND execution_generation = ? AND status IN ('complete', 'partial', 'failed')`,args:[p(e).slice(0,1e3),t,n]})}async function bt(t,e,n){let r=o(),a=x(t,n);await r.execute({sql:`UPDATE site_extract_jobs
87
+ )) RETURNING *`,args:[t]});return e.rows[0]?_(e.rows[0]):null}async function z(t,e=0){return(await o().execute({sql:`SELECT 1 FROM site_extract_jobs WHERE id = ? AND status IN ('pending', 'running')
88
+ AND execution_generation = ? AND (execution_generation = 0 OR refinalize_until > datetime('now'))`,args:[t,e]})).rows.length===1}async function bt(t,e,n=0){await o().execute({sql:`UPDATE site_extract_jobs SET billed_mc = 0, settlement_error = ?, updated_at = datetime('now')
89
+ WHERE id = ? AND billed_mc IS NULL AND execution_generation = ? AND status IN ('complete', 'partial', 'failed')`,args:[p(e).slice(0,1e3),t,n]})}async function wt(t,e,n){let r=o(),a=x(t,n);await r.execute({sql:`UPDATE site_extract_jobs
83
90
  SET status = 'running', total_urls = MAX(total_urls, ?), updated_at = datetime('now')
84
- WHERE id = ? AND status IN ('pending', 'running') AND execution_generation = 0 AND ${a.sql}`,args:[e,t,...a.args]})}async function wt(t,e,n){if(e.length===0)return;let r=o(),a=await P(t);if(!a||!await z(t)){if(n)throw Error("site_crawl_page_write_not_current");return}let s=x(t,n,!0);if(!(await r.execute({sql:`SELECT 1 FROM site_extract_jobs WHERE id=? AND ${s.sql}`,args:[t,...s.args]})).rows.length){if(n)throw Error("site_crawl_page_write_not_current");return}let c=a?.userId!=null?await y({ownerId:String(a.userId),jobId:t,createdAt:a.createdAt,pages:e}):new Map,l=e.map(d=>{let{discoveryLinks:O,acquiredHtml:N,mainHtml:R,...L}=d;return L.contentRef=c.get(d.archivedUrl??d.url)??d.contentRef,{sql:`INSERT INTO site_extract_pages (job_id, url, page)
91
+ WHERE id = ? AND status IN ('pending', 'running') AND execution_generation = 0 AND ${a.sql}`,args:[e,t,...a.args]})}async function St(t,e,n){if(e.length===0)return;let r=o(),a=await P(t);if(!a||!await z(t)){if(n)throw Error("site_crawl_page_write_not_current");return}let s=x(t,n,!0);if(!(await r.execute({sql:`SELECT 1 FROM site_extract_jobs WHERE id=? AND ${s.sql}`,args:[t,...s.args]})).rows.length){if(n)throw Error("site_crawl_page_write_not_current");return}let c=a?.userId!=null?await I({ownerId:String(a.userId),jobId:t,createdAt:a.createdAt,pages:e}):new Map,u=e.map(d=>{let{discoveryLinks:M,acquiredHtml:b,mainHtml:R,...L}=d;return L.contentRef=c.get(d.archivedUrl??d.url)??d.contentRef,{sql:`INSERT INTO site_extract_pages (job_id, url, page)
85
92
  SELECT ?, ?, ?
86
93
  WHERE EXISTS (
87
94
  SELECT 1 FROM site_extract_jobs
@@ -109,7 +116,7 @@ import{i as j,m as T}from"./chunk-KXJCGV3H.js";import{m as f,q as b}from"./chunk
109
116
  AND json_extract(excluded.page, '$.wordCount') > 0,
110
117
  0
111
118
  )
112
- END`,args:[t,d.archivedUrl??d.url,JSON.stringify(L),t,...s.args]}}),u,S;try{S=await r.batch([...l,{sql:`UPDATE site_extract_jobs SET
119
+ END`,args:[t,d.archivedUrl??d.url,JSON.stringify(L),t,...s.args]}}),l,S;try{S=await r.batch([...u,{sql:`UPDATE site_extract_jobs SET
113
120
  done_urls = (SELECT COUNT(*) FROM site_extract_pages WHERE job_id = ?),
114
121
  attempted_urls = (SELECT COUNT(*) FROM site_extract_pages WHERE job_id = ?),
115
122
  successful_urls = (
@@ -136,18 +143,18 @@ import{i as j,m as T}from"./chunk-KXJCGV3H.js";import{m as f,q as b}from"./chunk
136
143
  END
137
144
  ),
138
145
  updated_at = datetime('now')
139
- WHERE id = ? AND status IN ('pending', 'running') AND execution_generation = 0 AND ${s.sql}`,args:[t,t,t,t,t,...s.args]}],"write")}catch(d){u=d}if(u){let d=await Promise.all(l.map(N=>r.execute({sql:"SELECT page FROM site_extract_pages WHERE job_id=? AND url=?",args:N.args.slice(0,2)})));if(!(await r.execute({sql:`SELECT 1 FROM site_extract_jobs WHERE id=? AND ${s.sql}
146
+ WHERE id = ? AND status IN ('pending', 'running') AND execution_generation = 0 AND ${s.sql}`,args:[t,t,t,t,t,...s.args]}],"write")}catch(d){l=d}if(l){let d=await Promise.all(u.map(b=>r.execute({sql:"SELECT page FROM site_extract_pages WHERE job_id=? AND url=?",args:b.args.slice(0,2)})));if(!(await r.execute({sql:`SELECT 1 FROM site_extract_jobs WHERE id=? AND ${s.sql}
140
147
  AND attempted_urls=(SELECT COUNT(*) FROM site_extract_pages WHERE job_id=?)
141
148
  AND successful_urls=(SELECT COUNT(*) FROM site_extract_pages WHERE job_id=site_extract_jobs.id AND CASE
142
149
  WHEN json_extract(page,'$.extractionStatus') IS NOT NULL THEN json_extract(page,'$.extractionStatus')='successful'
143
150
  ELSE COALESCE(json_extract(page,'$.status')>=200 AND json_extract(page,'$.status')<300 AND json_extract(page,'$.wordCount')>0,0) END)
144
- AND failed_urls=attempted_urls-successful_urls`,args:[t,...s.args,t]})).rows.length||d.some((N,R)=>N.rows[0]?.page!==l[R].args[2]))throw u}else if(n&&S?.at(-1)?.rowsAffected!==1)throw Error("site_crawl_page_write_not_current")}async function St(t){return(await o().execute({sql:"SELECT page FROM site_extract_pages WHERE job_id = ? ORDER BY rowid",args:[t]})).rows.map(r=>JSON.parse(String(r.page)))}async function ft(t,e=181){let n=o(),r=Math.max(1,Math.min(5001,Math.round(e)));return(await n.execute({sql:`SELECT DISTINCT CAST(images.value AS TEXT) AS url
151
+ AND failed_urls=attempted_urls-successful_urls`,args:[t,...s.args,t]})).rows.length||d.some((b,R)=>b.rows[0]?.page!==u[R].args[2]))throw l}else if(n&&S?.at(-1)?.rowsAffected!==1)throw Error("site_crawl_page_write_not_current")}async function ft(t){return(await o().execute({sql:"SELECT page FROM site_extract_pages WHERE job_id = ? ORDER BY rowid",args:[t]})).rows.map(r=>JSON.parse(String(r.page)))}async function At(t,e=181){let n=o(),r=Math.max(1,Math.min(5001,Math.round(e)));return(await n.execute({sql:`SELECT DISTINCT CAST(images.value AS TEXT) AS url
145
152
  FROM site_extract_pages p,
146
153
  json_each(CASE WHEN json_valid(p.page) THEN p.page ELSE '{}' END, '$.imageLinks') images
147
154
  WHERE p.job_id = ?
148
155
  AND images.type = 'text'
149
156
  AND length(CAST(images.value AS TEXT)) BETWEEN 1 AND 4096
150
- LIMIT ?`,args:[t,r]})).rows.map(s=>String(s.url))}async function At(t){let n=await o().execute({sql:`SELECT COUNT(*) AS n FROM site_extract_pages
157
+ LIMIT ?`,args:[t,r]})).rows.map(s=>String(s.url))}async function ht(t){let n=await o().execute({sql:`SELECT COUNT(*) AS n FROM site_extract_pages
151
158
  WHERE job_id = ? AND CASE
152
159
  WHEN json_extract(page, '$.extractionStatus') IS NOT NULL
153
160
  THEN json_extract(page, '$.extractionStatus') = 'successful'
@@ -157,26 +164,26 @@ import{i as j,m as T}from"./chunk-KXJCGV3H.js";import{m as f,q as b}from"./chunk
157
164
  AND json_extract(page, '$.wordCount') > 0,
158
165
  0
159
166
  )
160
- END`,args:[t]});return Number(n.rows[0]?.n??0)}async function ht(t,e,n,r=null,a=!1,s=null,i=0,c){let l=o(),u=x(t,c,!0);return(await l.execute({sql:`UPDATE site_extract_jobs
167
+ END`,args:[t]});return Number(n.rows[0]?.n??0)}async function Dt(t,e,n,r=null,a=!1,s=null,i=0,c){let u=o(),l=x(t,c,!0);return(await u.execute({sql:`UPDATE site_extract_jobs
161
168
  SET status = ?, artifacts = ?, error = ?, public_error_json = ?, updated_at = datetime('now')
162
169
  WHERE id = ? AND execution_generation = ? AND (settlement_plan_json IS NULL OR billed_mc IS NOT NULL)
163
170
  AND (
164
171
  (execution_generation = 0 AND (status IN ('pending', 'running') OR (? = 1 AND status = 'failed')))
165
172
  OR (execution_generation > 0 AND status = 'running' AND refinalize_until > datetime('now'))
166
- ) AND (execution_generation > 0 OR ${u.sql})`,args:[n,JSON.stringify(e??[]),r?p(r).slice(0,2e3):null,m(s),t,i,a?1:0,...u.args]})).rowsAffected===1}async function Dt(t,e,n,r=0,a){let s=x(t,a);return(await o().execute({sql:`UPDATE site_extract_jobs
173
+ ) AND (execution_generation > 0 OR ${l.sql})`,args:[n,JSON.stringify(e??[]),r?p(r).slice(0,2e3):null,E(s),t,i,a?1:0,...l.args]})).rowsAffected===1}async function Rt(t,e,n,r=0,a){let s=x(t,a);return(await o().execute({sql:`UPDATE site_extract_jobs
167
174
  SET status = 'failed', error = ?, public_error_json = ?, updated_at = datetime('now')
168
175
  WHERE id = ? AND status IN ('pending', 'running') AND execution_generation = ?
169
176
  AND (execution_generation = 0 OR refinalize_until > datetime('now'))
170
- AND (execution_generation > 0 OR (${s.sql} AND ${I()}))`,args:[p(e).slice(0,2e3),m(n),t,r,...s.args]})).rowsAffected===1}async function Rt(t,e,n){await o().execute({sql:`UPDATE site_extract_jobs
177
+ AND (execution_generation > 0 OR (${s.sql} AND ${y()}))`,args:[p(e).slice(0,2e3),E(n),t,r,...s.args]})).rowsAffected===1}async function Lt(t,e,n){await o().execute({sql:`UPDATE site_extract_jobs
171
178
  SET status = 'failed', billed_mc = 0, error = ?, public_error_json = ?, updated_at = datetime('now')
172
- WHERE id = ? AND status = 'pending' AND billed_mc IS NULL`,args:[p(e).slice(0,2e3),m(n),t]})}async function Lt(t){return await o().execute({sql:`UPDATE site_extract_jobs SET settlement_plan_json = ?, updated_at = datetime('now')
179
+ WHERE id = ? AND status = 'pending' AND billed_mc IS NULL`,args:[p(e).slice(0,2e3),E(n),t]})}async function Ct(t){return await o().execute({sql:`UPDATE site_extract_jobs SET settlement_plan_json = ?, updated_at = datetime('now')
173
180
  WHERE id = ? AND user_id = ? AND execution_generation = ? AND status = ?
174
- AND billed_mc IS NULL AND settlement_plan_json IS NULL`,args:[JSON.stringify(t),t.jobId,t.userId,t.generation,t.status]}),P(t.jobId)}async function Ct(t,e){let n=t.billingClass===q?"not_charged":e.netChargeMc>0?"charged":e.refundMc>0?"refunded":"not_charged";await o().execute({sql:`UPDATE site_extract_jobs SET billed_mc = ?, settlement_receipt_json = ?,
181
+ AND billed_mc IS NULL AND settlement_plan_json IS NULL`,args:[JSON.stringify(t),t.jobId,t.userId,t.generation,t.status]}),P(t.jobId)}async function Tt(t,e){let n=t.billingClass===q?"not_charged":e.netChargeMc>0?"charged":e.refundMc>0?"refunded":"not_charged";await o().execute({sql:`UPDATE site_extract_jobs SET billed_mc = ?, settlement_receipt_json = ?,
175
182
  public_error_json = CASE WHEN json_valid(public_error_json) THEN json_set(public_error_json, '$.charge_status', ?) ELSE public_error_json END,
176
183
  updated_at = datetime('now')
177
184
  WHERE id = ? AND user_id = ? AND execution_generation = ? AND status = ?
178
- AND billed_mc IS NULL AND settlement_plan_json = ?`,args:[e.netChargeMc,JSON.stringify(e),n,t.jobId,t.userId,t.generation,t.status,JSON.stringify(t)]})}async function jt(t,e,n,r,a,s=0){let{settleExtractJobCharge:i}=await import("./settlement-6CS4JZTY.js");return i(t,e,n,r,a,s)}var B=25;async function*Tt(t){let e=o(),n=0;for(;;){let r=await e.execute({sql:`SELECT rowid AS cursor_id, page
185
+ AND billed_mc IS NULL AND settlement_plan_json = ?`,args:[e.netChargeMc,JSON.stringify(e),n,t.jobId,t.userId,t.generation,t.status,JSON.stringify(t)]})}async function jt(t,e,n,r,a,s=0){let{settleExtractJobCharge:i}=await import("./settlement-I5IBIK6U.js");return i(t,e,n,r,a,s)}var B=25;async function*It(t){let e=o(),n=0;for(;;){let r=await e.execute({sql:`SELECT rowid AS cursor_id, page
179
186
  FROM site_extract_pages
180
187
  WHERE job_id = ? AND rowid > ?
181
188
  ORDER BY rowid
182
- LIMIT ${B}`,args:[t,n]});if(!r.rows.length)return;if(n=Number(r.rows.at(-1)?.cursor_id??n),!Number.isSafeInteger(n)||n<=0)throw new Error("site extract page cursor is invalid");yield r.rows.map(a=>JSON.parse(String(a.page)))}}export{Y as a,q as b,st as c,it as d,v as e,ot as f,P as g,ct as h,lt as i,ut as j,dt as k,_t as l,gt as m,pt as n,mt as o,Et as p,xt as q,z as r,Nt as s,bt as t,wt as u,St as v,ft as w,At as x,ht as y,Dt as z,Rt as A,Lt as B,Ct as C,jt as D,B as E,Tt as F};
189
+ LIMIT ${B}`,args:[t,n]});if(!r.rows.length)return;if(n=Number(r.rows.at(-1)?.cursor_id??n),!Number.isSafeInteger(n)||n<=0)throw new Error("site extract page cursor is invalid");yield r.rows.map(a=>JSON.parse(String(a.page)))}}export{Y as a,q as b,st as c,it as d,v as e,ot as f,P as g,ct as h,ut as i,lt as j,dt as k,_t as l,gt as m,pt as n,Et as o,mt as p,xt as q,Nt as r,z as s,bt as t,wt as u,St as v,ft as w,At as x,ht as y,Dt as z,Rt as A,Lt as B,Ct as C,Tt as D,jt as E,B as F,It as G};