@cedros/pay-react
Version:
React frontend library for Cedros Pay - unified Stripe and Solana x402 payments
11 lines (9 loc) • 50.2 kB
JavaScript
"use strict";var qe=Object.create;var ae=Object.defineProperty;var Ke=Object.getOwnPropertyDescriptor;var ze=Object.getOwnPropertyNames;var Ve=Object.getPrototypeOf,Ge=Object.prototype.hasOwnProperty;var He=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of ze(e))!Ge.call(r,a)&&a!==t&&ae(r,a,{get:()=>e[a],enumerable:!(n=Ke(e,a))||n.enumerable});return r};var ie=(r,e,t)=>(t=r!=null?qe(Ve(r)):{},He(e||!r||!r.__esModule?ae(t,"default",{value:r,enumerable:!0}):t,r));const Y=require("react/jsx-runtime"),E=require("react"),U=require("./uuid-C0iMjdcc.js"),k=require("@solana/web3.js"),oe=require("@solana/spl-token"),se=require("@solana/wallet-adapter-wallets");var we="https://js.stripe.com/v3",Je=/^https:\/\/js\.stripe\.com\/v3\/?(\?.*)?$/;var Xe=function(){for(var e=document.querySelectorAll('script[src^="'.concat(we,'"]')),t=0;t<e.length;t++){var n=e[t];if(Je.test(n.src))return n}return null},ce=function(e){var t="",n=document.createElement("script");n.src="".concat(we).concat(t);var a=document.head||document.body;if(!a)throw new Error("Expected document.body not to be null. Stripe.js requires a <body> element.");return a.appendChild(n),n},Ye=function(e,t){!e||!e._registerWrapper||e._registerWrapper({name:"stripe-js",version:"4.6.0",startTime:t})},L=null,W=null,q=null,Qe=function(e){return function(){e(new Error("Failed to load Stripe.js"))}},Ze=function(e,t){return function(){window.Stripe?e(window.Stripe):t(new Error("Stripe.js not available"))}},et=function(e){return L!==null?L:(L=new Promise(function(t,n){if(typeof window>"u"||typeof document>"u"){t(null);return}if(window.Stripe){t(window.Stripe);return}try{var a=Xe();if(!(a&&e)){if(!a)a=ce(e);else if(a&&q!==null&&W!==null){var i;a.removeEventListener("load",q),a.removeEventListener("error",W),(i=a.parentNode)===null||i===void 0||i.removeChild(a),a=ce(e)}}q=Ze(t,n),W=Qe(n),a.addEventListener("load",q),a.addEventListener("error",W)}catch(o){n(o);return}}),L.catch(function(t){return L=null,Promise.reject(t)}))},tt=function(e,t,n){if(e===null)return null;var a=e.apply(void 0,t);return Ye(a,n),a},F,ge=!1,be=function(){return F||(F=et(null).catch(function(e){return F=null,Promise.reject(e)}),F)};Promise.resolve().then(function(){return be()}).catch(function(r){ge||console.warn(r)});var ve=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];ge=!0;var a=Date.now();return be().then(function(i){return tt(i,t,a)})},Ee=(r=>(r[r.DEBUG=0]="DEBUG",r[r.INFO=1]="INFO",r[r.WARN=2]="WARN",r[r.ERROR=3]="ERROR",r[r.SILENT=4]="SILENT",r))(Ee||{});class ee{config;constructor(e){this.config=e}setLevel(e){this.config.level=e}getLevel(){return this.config.level}debug(...e){this.config.level<=0&&this.log("DEBUG",console.log,e)}info(...e){this.config.level<=1&&this.log("INFO",console.info,e)}warn(...e){this.config.level<=2&&this.log("WARN",console.warn,e)}error(...e){this.config.level<=3&&this.log("ERROR",console.error,e)}log(e,t,n){const a=this.config.prefix?`${this.config.prefix} `:"",i=new Date().toISOString();t(`[${i}] ${a}[${e}]`,...n)}}const rt=()=>typeof process<"u"&&process.env.NODE_ENV==="development"?0:2;let z=null;function c(){return z||(z=new ee({level:rt(),prefix:"[CedrosPay]"})),z}function nt(r){z=r}function Se(r){return new ee(r)}function D(r,e){return r instanceof Error?r.message:typeof r=="string"?r:e}const at={service_unavailable:"Service temporarily unavailable. Please try again later or contact support.",server_insufficient_funds:"Service temporarily unavailable. Please try again later or contact support.",insufficient_funds_token:"Insufficient token balance in your wallet. Please add more tokens and try again.",insufficient_funds_sol:"Insufficient SOL for transaction fees. Please add some SOL to your wallet and try again.",insufficient_amount:"Payment amount is insufficient. Please check the required amount.",invalid_signature:"Transaction signature is invalid. Please try again.",send_failed:"Failed to send transaction. Please try again or contact support.",timeout:"Transaction timed out. Please check the blockchain explorer or try again."};async function S(r,e,t=!1){try{const n=await r.json();if(t&&n.verificationError){c().debug(`Payment verification failed: ${n.verificationError.code}`);const a=n.verificationError.code;return at[a]||n.verificationError.message||e}return typeof n.error=="string"?n.error:n.error&&typeof n.error=="object"&&"message"in n.error?n.error.message:e}catch{return await r.text()||e}}const it=3e4;async function w(r,e={},t=it){const n=new AbortController,a=e.signal;if(a?.aborted)throw n.abort(),new DOMException("The operation was aborted","AbortError");const i=setTimeout(()=>n.abort(),t);let o=null;a&&(o=()=>n.abort(),a.addEventListener("abort",o));try{return await fetch(r,{...e,signal:n.signal})}catch(s){throw s instanceof Error&&s.name==="AbortError"?a?.aborted?s:new Error(`Request timeout after ${t}ms`):s}finally{clearTimeout(i),a&&o&&a.removeEventListener("abort",o)}}function A(r){const{maxRequests:e,windowMs:t}=r;let n=e,a=Date.now();const i=e/t;function o(){const f=Date.now(),h=f-a;if(h>0){const y=h*i;n=Math.min(e,n+y),a=f}}function s(){return o(),n>=1?(n-=1,!0):!1}function u(){return o(),Math.floor(n)}function l(){if(o(),n>=1)return 0;const h=(1-n)/i;return Math.ceil(h)}function d(){n=e,a=Date.now()}return{tryConsume:s,getAvailableTokens:u,getTimeUntilRefill:l,reset:d}}const M={PAYMENT:{maxRequests:10,windowMs:6e4},QUOTE:{maxRequests:30,windowMs:6e4},STRICT:{maxRequests:5,windowMs:6e4},PERMISSIVE:{maxRequests:100,windowMs:6e4}};var Ce=(r=>(r.CLOSED="CLOSED",r.OPEN="OPEN",r.HALF_OPEN="HALF_OPEN",r))(Ce||{});class g extends Error{constructor(e){super(e),this.name="CircuitBreakerOpenError"}}function B(r){const{failureThreshold:e,timeout:t,name:n="circuit-breaker"}=r;let a="CLOSED",i=0,o=0,s=0,u=null,l=null,d=null;function f(){a==="OPEN"&&d!==null&&Date.now()>=d&&(c().debug(`[CircuitBreaker:${n}] Transitioning OPEN → HALF_OPEN (timeout expired)`),a="HALF_OPEN",d=null)}function h(){l=Date.now(),o++,a==="HALF_OPEN"?(c().debug(`[CircuitBreaker:${n}] Success in HALF_OPEN → CLOSED`),a="CLOSED",i=0):a==="CLOSED"&&(i=0)}function y(x){u=Date.now(),i++,c().warn(`[CircuitBreaker:${n}] Failure recorded (${i}/${e}):`,x.message),a==="HALF_OPEN"?(c().warn(`[CircuitBreaker:${n}] Failed in HALF_OPEN → OPEN`),a="OPEN",d=Date.now()+t):a==="CLOSED"&&i>=e&&(c().error(`[CircuitBreaker:${n}] Failure threshold reached (${i}) → OPEN`),a="OPEN",d=Date.now()+t)}async function p(x){if(f(),a==="OPEN"){s++;const b=d?Math.ceil((d-Date.now())/1e3):0;throw new g(`Circuit breaker is OPEN. Service is unavailable. Retry in ${b}s.`)}try{const b=await x();return h(),b}catch(b){throw y(b instanceof Error?b:new Error(String(b))),b}}function m(){return f(),a}function T(){return f(),{state:a,failures:i,successes:o,rejections:s,lastFailureTime:u,lastSuccessTime:l}}function O(){c().debug(`[CircuitBreaker:${n}] Manual reset → CLOSED`),a="CLOSED",i=0,o=0,s=0,u=null,l=null,d=null}function R(){c().warn(`[CircuitBreaker:${n}] Manual trip → OPEN`),a="OPEN",d=Date.now()+t}return{execute:p,getState:m,getStats:T,reset:O,trip:R}}const ot={STRICT:{failureThreshold:3,timeout:6e4},STANDARD:{failureThreshold:5,timeout:3e4},LENIENT:{failureThreshold:10,timeout:15e3}};function st(r,e){if(e>=3)return!1;const t=r.message.toLowerCase();return t.includes("network")||t.includes("timeout")||t.includes("fetch failed")||t.includes("econnrefused")||t.includes("503")||t.includes("502")||t.includes("500")||t.includes("429")?!0:(t.includes("400")||t.includes("401")||t.includes("403")||t.includes("404"),!1)}function ct(r,e,t,n,a){const i=e*Math.pow(t,r),o=Math.min(i,n);if(a){const s=Math.random()*o;return Math.floor(s)}return Math.floor(o)}function lt(r){return new Promise(e=>setTimeout(e,r))}async function C(r,e={}){const{maxRetries:t=3,initialDelayMs:n=1e3,backoffFactor:a=2,maxDelayMs:i=3e4,jitter:o=!0,shouldRetry:s=st,name:u="retry"}=e;let l=null,d=0;for(let f=0;f<=t;f++)try{const h=await r();return f>0&&c().debug(`[Retry:${u}] Succeeded on attempt ${f+1}/${t+1} after ${d}ms`),h}catch(h){l=h instanceof Error?h:new Error(String(h));const y=f===t,p=s(l,f);if(y||!p)throw c().warn(`[Retry:${u}] Failed on attempt ${f+1}/${t+1}. ${y?"No more retries.":"Error not retryable."}`),l;const m=ct(f,n,a,i,o);d+=m,c().warn(`[Retry:${u}] Attempt ${f+1}/${t+1} failed: ${l.message}. Retrying in ${m}ms...`),await lt(m)}throw l||new Error("Retry failed with no error")}const P={QUICK:{maxRetries:3,initialDelayMs:1e3,backoffFactor:2,maxDelayMs:1e4},STANDARD:{maxRetries:3,initialDelayMs:2e3,backoffFactor:2,maxDelayMs:3e4},AGGRESSIVE:{maxRetries:5,initialDelayMs:500,backoffFactor:1.5,maxDelayMs:15e3},PATIENT:{maxRetries:5,initialDelayMs:5e3,backoffFactor:2,maxDelayMs:6e4}};class ut{stripe=null;publicKey;routeDiscovery;rateLimiter=A(M.PAYMENT);circuitBreaker=B({failureThreshold:5,timeout:1e4,name:"stripe-manager"});constructor(e,t){this.publicKey=e,this.routeDiscovery=t}async initialize(){if(!this.stripe&&(this.stripe=await ve(this.publicKey),!this.stripe))throw new Error("Failed to initialize Stripe")}async createSession(e){if(!this.rateLimiter.tryConsume())throw new Error("Rate limit exceeded for Stripe session creation. Please try again later.");try{return await this.circuitBreaker.execute(async()=>await C(async()=>{const t=await this.routeDiscovery.buildUrl("/paywall/v1/stripe-session");c().debug("[StripeManager] Creating session with request:",e),e.couponCode?c().debug("[StripeManager] Coupon code included:",e.couponCode):c().debug("[StripeManager] No coupon code in request");const n=await w(t,{method:"POST",headers:{"Content-Type":"application/json","Idempotency-Key":U.generateUUID()},body:JSON.stringify(e)});if(!n.ok){const a=await S(n,"Failed to create Stripe session");throw new Error(a)}return n.json()},{...P.STANDARD,name:"stripe-create-session"}))}catch(t){throw t instanceof g?(c().error("[StripeManager] Circuit breaker is OPEN - Stripe service unavailable"),new Error("Stripe payment service is temporarily unavailable. Please try again in a few moments.")):t}}async redirectToCheckout(e){if(this.stripe||await this.initialize(),!this.stripe)return{success:!1,error:"Stripe not initialized"};const t=await this.stripe.redirectToCheckout({sessionId:e});return t.error?{success:!1,error:t.error.message}:{success:!0}}async processPayment(e){try{const t=await this.createSession(e);return await this.redirectToCheckout(t.sessionId)}catch(t){return{success:!1,error:D(t,"Unknown error")}}}async processCartCheckout(e){const{items:t,successUrl:n,cancelUrl:a,metadata:i,customerEmail:o,couponCode:s}=e;if(!this.rateLimiter.tryConsume())return{success:!1,error:"Rate limit exceeded for cart checkout. Please try again later."};try{const u=await this.circuitBreaker.execute(async()=>await C(async()=>{const l=await this.routeDiscovery.buildUrl("/paywall/v1/cart/checkout"),d={items:t,successUrl:n,cancelUrl:a,metadata:i,customerEmail:o,couponCode:s},f=await w(l,{method:"POST",headers:{"Content-Type":"application/json","Idempotency-Key":U.generateUUID()},body:JSON.stringify(d)});if(!f.ok){const h=await S(f,"Failed to create cart checkout session");throw new Error(h)}return await f.json()},{...P.STANDARD,name:"stripe-cart-checkout"}));return await this.redirectToCheckout(u.sessionId)}catch(u){return u instanceof g?{success:!1,error:"Stripe payment service is temporarily unavailable. Please try again in a few moments."}:{success:!1,error:D(u,"Cart checkout failed")}}}}const Pe="3.7.8",dt=Pe,I=typeof Buffer=="function",le=typeof TextDecoder=="function"?new TextDecoder:void 0,ue=typeof TextEncoder=="function"?new TextEncoder:void 0,ft="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",j=Array.prototype.slice.call(ft),K=(r=>{let e={};return r.forEach((t,n)=>e[t]=n),e})(j),ht=/^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/,v=String.fromCharCode.bind(String),de=typeof Uint8Array.from=="function"?Uint8Array.from.bind(Uint8Array):r=>new Uint8Array(Array.prototype.slice.call(r,0)),xe=r=>r.replace(/=/g,"").replace(/[+\/]/g,e=>e=="+"?"-":"_"),Te=r=>r.replace(/[^A-Za-z0-9\+\/]/g,""),Re=r=>{let e,t,n,a,i="";const o=r.length%3;for(let s=0;s<r.length;){if((t=r.charCodeAt(s++))>255||(n=r.charCodeAt(s++))>255||(a=r.charCodeAt(s++))>255)throw new TypeError("invalid character found");e=t<<16|n<<8|a,i+=j[e>>18&63]+j[e>>12&63]+j[e>>6&63]+j[e&63]}return o?i.slice(0,o-3)+"===".substring(o):i},te=typeof btoa=="function"?r=>btoa(r):I?r=>Buffer.from(r,"binary").toString("base64"):Re,Q=I?r=>Buffer.from(r).toString("base64"):r=>{let t=[];for(let n=0,a=r.length;n<a;n+=4096)t.push(v.apply(null,r.subarray(n,n+4096)));return te(t.join(""))},V=(r,e=!1)=>e?xe(Q(r)):Q(r),pt=r=>{if(r.length<2){var e=r.charCodeAt(0);return e<128?r:e<2048?v(192|e>>>6)+v(128|e&63):v(224|e>>>12&15)+v(128|e>>>6&63)+v(128|e&63)}else{var e=65536+(r.charCodeAt(0)-55296)*1024+(r.charCodeAt(1)-56320);return v(240|e>>>18&7)+v(128|e>>>12&63)+v(128|e>>>6&63)+v(128|e&63)}},yt=/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g,ke=r=>r.replace(yt,pt),fe=I?r=>Buffer.from(r,"utf8").toString("base64"):ue?r=>Q(ue.encode(r)):r=>te(ke(r)),N=(r,e=!1)=>e?xe(fe(r)):fe(r),he=r=>N(r,!0),mt=/[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g,wt=r=>{switch(r.length){case 4:var e=(7&r.charCodeAt(0))<<18|(63&r.charCodeAt(1))<<12|(63&r.charCodeAt(2))<<6|63&r.charCodeAt(3),t=e-65536;return v((t>>>10)+55296)+v((t&1023)+56320);case 3:return v((15&r.charCodeAt(0))<<12|(63&r.charCodeAt(1))<<6|63&r.charCodeAt(2));default:return v((31&r.charCodeAt(0))<<6|63&r.charCodeAt(1))}},Ae=r=>r.replace(mt,wt),Me=r=>{if(r=r.replace(/\s+/g,""),!ht.test(r))throw new TypeError("malformed base64.");r+="==".slice(2-(r.length&3));let e,t,n,a=[];for(let i=0;i<r.length;)e=K[r.charAt(i++)]<<18|K[r.charAt(i++)]<<12|(t=K[r.charAt(i++)])<<6|(n=K[r.charAt(i++)]),t===64?a.push(v(e>>16&255)):n===64?a.push(v(e>>16&255,e>>8&255)):a.push(v(e>>16&255,e>>8&255,e&255));return a.join("")},re=typeof atob=="function"?r=>atob(Te(r)):I?r=>Buffer.from(r,"base64").toString("binary"):Me,Ue=I?r=>de(Buffer.from(r,"base64")):r=>de(re(r).split("").map(e=>e.charCodeAt(0))),De=r=>Ue(Oe(r)),gt=I?r=>Buffer.from(r,"base64").toString("utf8"):le?r=>le.decode(Ue(r)):r=>Ae(re(r)),Oe=r=>Te(r.replace(/[-_]/g,e=>e=="-"?"+":"/")),Z=r=>gt(Oe(r)),bt=r=>{if(typeof r!="string")return!1;const e=r.replace(/\s+/g,"").replace(/={0,2}$/,"");return!/[^\s0-9a-zA-Z\+/]/.test(e)||!/[^\s0-9a-zA-Z\-_]/.test(e)},Ne=r=>({value:r,enumerable:!1,writable:!0,configurable:!0}),Be=function(){const r=(e,t)=>Object.defineProperty(String.prototype,e,Ne(t));r("fromBase64",function(){return Z(this)}),r("toBase64",function(e){return N(this,e)}),r("toBase64URI",function(){return N(this,!0)}),r("toBase64URL",function(){return N(this,!0)}),r("toUint8Array",function(){return De(this)})},Ie=function(){const r=(e,t)=>Object.defineProperty(Uint8Array.prototype,e,Ne(t));r("toBase64",function(e){return V(this,e)}),r("toBase64URI",function(){return V(this,!0)}),r("toBase64URL",function(){return V(this,!0)})},vt=()=>{Be(),Ie()},_={version:Pe,VERSION:dt,atob:re,atobPolyfill:Me,btoa:te,btoaPolyfill:Re,fromBase64:Z,toBase64:N,encode:N,encodeURI:he,encodeURL:he,utob:ke,btou:Ae,decode:Z,isValid:bt,fromUint8Array:V,toUint8Array:De,extendString:Be,extendUint8Array:Ie,extendBuiltins:vt};class Et{routeDiscovery;quoteRateLimiter=A(M.QUOTE);verifyRateLimiter=A(M.PAYMENT);circuitBreaker=B({failureThreshold:5,timeout:1e4,name:"x402-manager"});constructor(e){this.routeDiscovery=e}async requestQuote(e){const{resource:t,couponCode:n}=e;if(!this.quoteRateLimiter.tryConsume())throw new Error("Rate limit exceeded for quote requests. Please try again later.");try{return await this.circuitBreaker.execute(async()=>await C(async()=>{const a="/paywall/v1/quote";c().debug("[X402Manager] Requesting quote",n?"with coupon":"without coupon");const i=await this.routeDiscovery.buildUrl(a),o=await w(i,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({resource:t,couponCode:n||null})});if(o.status!==402)throw new Error(`Expected 402 status, got ${o.status}`);const s=await o.json();if(!s.accepts||s.accepts.length===0)throw new Error("Invalid x402 response: missing accepts array");return s.accepts[0]},{...P.QUICK,name:"x402-quote"}))}catch(a){throw a instanceof g?(c().error("[X402Manager] Circuit breaker is OPEN - x402 service unavailable"),new Error("Payment service is temporarily unavailable. Please try again in a few moments.")):a}}async requestCartQuote(e){const{items:t,metadata:n,couponCode:a}=e;if(!this.quoteRateLimiter.tryConsume())throw new Error("Rate limit exceeded for cart quote requests. Please try again later.");try{return await this.circuitBreaker.execute(async()=>await C(async()=>{const i=await this.routeDiscovery.buildUrl("/paywall/v1/cart/quote"),o={items:t,metadata:n,couponCode:a},s=await w(i,{method:"POST",headers:{"Content-Type":"application/json","Idempotency-Key":U.generateUUID()},body:JSON.stringify(o)});if(s.status!==402&&!s.ok){const u=await S(s,"Failed to get cart quote");throw new Error(u)}return s.json()},{...P.QUICK,name:"x402-cart-quote"}))}catch(i){throw i instanceof g?(c().error("[X402Manager] Circuit breaker is OPEN - cart quote service unavailable"),new Error("Payment service is temporarily unavailable. Please try again in a few moments.")):i}}buildPaymentHeader(e){const t=JSON.stringify(e);return _.encode(t)}parseSettlementResponse(e){const t=e.headers.get("X-PAYMENT-RESPONSE");if(!t)return null;try{const n=_.decode(t),a=JSON.parse(n);return typeof a.success!="boolean"?(c().error("Invalid settlement response: missing success field"),null):a}catch(n){return c().error("Failed to parse settlement response:",n),null}}async submitPayment(e){const{resource:t,payload:n,couponCode:a,metadata:i,resourceType:o="regular"}=e;if(!this.verifyRateLimiter.tryConsume())return{success:!1,error:"Rate limit exceeded for payment verification. Please try again later."};try{return await this.circuitBreaker.execute(async()=>await C(async()=>{const u={...n,payload:{...n.payload,resource:t,resourceType:o,metadata:{...n.payload.metadata||{},...i||{},...a?{couponCode:a}:{}}}},l=this.buildPaymentHeader(u),d="/paywall/v1/verify";c().debug("[X402Manager] Submitting payment",{resourceType:o,hasCoupon:!!a,hasMetadata:!!i});const f=await this.routeDiscovery.buildUrl(d),h=await w(f,{method:"POST",headers:{"Content-Type":"application/json","X-PAYMENT":l,"Idempotency-Key":U.generateUUID()}});if(h.ok){const{settlement:p,transactionId:m}=await this.handlePaymentVerification(h,n.payload.signature);return{success:!0,transactionId:m,settlement:p||void 0}}return{success:!1,error:await S(h,"Payment verification failed",!0)}},{...P.STANDARD,name:"x402-verify"}))}catch(s){return s instanceof g?{success:!1,error:"Payment verification service is temporarily unavailable. Please try again in a few moments."}:{success:!1,error:D(s,"Unknown error")}}}async buildGaslessTransaction(e){const{resourceId:t,userWallet:n,feePayer:a,couponCode:i}=e;if(!this.quoteRateLimiter.tryConsume())throw new Error("Rate limit exceeded for gasless transaction requests. Please try again later.");try{return await this.circuitBreaker.execute(async()=>await C(async()=>{const o=await this.routeDiscovery.buildUrl("/paywall/v1/gasless-transaction"),s=await w(o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({resourceId:t,userWallet:n,feePayer:a,couponCode:i})});if(!s.ok){const u=await S(s,"Failed to build gasless transaction");throw new Error(u)}return s.json()},{...P.QUICK,name:"x402-gasless-build"}))}catch(o){throw o instanceof g?(c().error("[X402Manager] Circuit breaker is OPEN - gasless transaction service unavailable"),new Error("Gasless transaction service is temporarily unavailable. Please try again in a few moments.")):o}}async submitGaslessTransaction(e){const{resource:t,partialTx:n,couponCode:a,metadata:i,resourceType:o="regular",requirement:s}=e;if(!this.verifyRateLimiter.tryConsume())return{success:!1,error:"Rate limit exceeded for gasless transaction verification. Please try again later."};try{return await this.circuitBreaker.execute(async()=>await C(async()=>{const l={x402Version:0,scheme:s?.scheme||"solana-spl-transfer",network:s?.network||"mainnet-beta",payload:{signature:"",transaction:n,feePayer:s?.extra?.feePayer||"",resource:t,resourceType:o,metadata:{...i||{},...a?{couponCode:a}:{}}}},d=this.buildPaymentHeader(l),h=await this.routeDiscovery.buildUrl("/paywall/v1/verify"),y=await w(h,{method:"POST",headers:{"Content-Type":"application/json","X-PAYMENT":d,"Idempotency-Key":U.generateUUID()}});if(y.ok){const{settlement:m,transactionId:T}=await this.handlePaymentVerification(y,"gasless-tx");return{success:!0,transactionId:T,settlement:m||void 0}}return{success:!1,error:await S(y,"Gasless transaction failed",!0)}},{...P.STANDARD,name:"x402-gasless-verify"}))}catch(u){return u instanceof g?{success:!1,error:"Gasless transaction verification service is temporarily unavailable. Please try again in a few moments."}:{success:!1,error:D(u,"Unknown error")}}}async handlePaymentVerification(e,t){const n=this.parseSettlementResponse(e),a=e.headers.get("Content-Type")||"";let i=t;if(a.includes("application/json"))try{i=(await e.json()).signature||t}catch(o){c().warn("Failed to parse JSON response body:",o)}return{settlement:n,transactionId:i}}validateRequirement(e){return!!(e.scheme&&e.network&&e.maxAmountRequired&&e.resource&&e.payTo&&e.asset&&e.maxTimeoutSeconds>0)}}function St(r){if(r.length>=255)throw new TypeError("Alphabet too long");const e=new Uint8Array(256);for(let l=0;l<e.length;l++)e[l]=255;for(let l=0;l<r.length;l++){const d=r.charAt(l),f=d.charCodeAt(0);if(e[f]!==255)throw new TypeError(d+" is ambiguous");e[f]=l}const t=r.length,n=r.charAt(0),a=Math.log(t)/Math.log(256),i=Math.log(256)/Math.log(t);function o(l){if(l instanceof Uint8Array||(ArrayBuffer.isView(l)?l=new Uint8Array(l.buffer,l.byteOffset,l.byteLength):Array.isArray(l)&&(l=Uint8Array.from(l))),!(l instanceof Uint8Array))throw new TypeError("Expected Uint8Array");if(l.length===0)return"";let d=0,f=0,h=0;const y=l.length;for(;h!==y&&l[h]===0;)h++,d++;const p=(y-h)*i+1>>>0,m=new Uint8Array(p);for(;h!==y;){let R=l[h],x=0;for(let b=p-1;(R!==0||x<f)&&b!==-1;b--,x++)R+=256*m[b]>>>0,m[b]=R%t>>>0,R=R/t>>>0;if(R!==0)throw new Error("Non-zero carry");f=x,h++}let T=p-f;for(;T!==p&&m[T]===0;)T++;let O=n.repeat(d);for(;T<p;++T)O+=r.charAt(m[T]);return O}function s(l){if(typeof l!="string")throw new TypeError("Expected String");if(l.length===0)return new Uint8Array;let d=0,f=0,h=0;for(;l[d]===n;)f++,d++;const y=(l.length-d)*a+1>>>0,p=new Uint8Array(y);for(;d<l.length;){const R=l.charCodeAt(d);if(R>255)return;let x=e[R];if(x===255)return;let b=0;for(let $=y-1;(x!==0||b<h)&&$!==-1;$--,b++)x+=t*p[$]>>>0,p[$]=x%256>>>0,x=x/256>>>0;if(x!==0)throw new Error("Non-zero carry");h=b,d++}let m=y-h;for(;m!==y&&p[m]===0;)m++;const T=new Uint8Array(f+(y-m));let O=f;for(;m!==y;)T[O++]=p[m++];return T}function u(l){const d=s(l);if(d)return d;throw new Error("Non-base"+t+" character")}return{encode:o,decodeUnsafe:s,decode:u}}var Ct="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";const pe=St(Ct),G={CASHx9KJUStyftLFWGvEVf59SGeG9sh5FfcnZMVPCASH:"CASH",EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v:"USDC",Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB:"USDT","2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo":"PYUSD"};function Pt(r){return r in G}function ne(r,e="token mint",t=!1){if(!r||r.trim().length===0)return{isValid:!0,isKnownStablecoin:!1};const n=r.trim();if(Pt(n))return{isValid:!0,isKnownStablecoin:!0,symbol:G[n]};const a=Object.entries(G).map(([i,o])=>` ${o}: ${i}`).join(`
`);return t?{isValid:!0,isKnownStablecoin:!1,warning:[`Warning: Unrecognized token mint address in ${e}`,` Provided: ${n}`,"","This token mint does not match any known stablecoin addresses.","You have set dangerouslyAllowUnknownMint=true, so this will proceed.","If this is a typo, payments will be sent to the wrong token and funds will be PERMANENTLY LOST.","","Known stablecoin mints (mainnet-beta):",a,"","Double-check your token mint address before deploying to production."].join(`
`)}:{isValid:!1,isKnownStablecoin:!1,error:[`SAFETY ERROR: Unrecognized token mint address in ${e}`,` Provided: ${n}`,"","This token mint does not match any known stablecoin addresses.","Using an unknown token mint can result in PERMANENT LOSS OF FUNDS if it's a typo.","","Known stablecoin mints (mainnet-beta):",a,"","If you are CERTAIN this is the correct mint address (custom token, testnet, or new stablecoin),","set dangerouslyAllowUnknownMint={true} in your CedrosProvider config:",""," <CedrosProvider"," config={{"," ...",' tokenMint: "'+n+'",'," dangerouslyAllowUnknownMint: true, // ⚠️ I have verified this mint address"," }}"," />","","⚠️ WARNING: Only enable dangerouslyAllowUnknownMint if you have TRIPLE-CHECKED the mint address."].join(`
`)}}function xt(r,e="unknown",t=!1){return ne(r,`X402Requirement (resource: ${e})`,t)}class Tt{connection;cluster;endpoint;allowUnknownMint;rpcRateLimiter=A({maxRequests:50,windowMs:6e4});rpcCircuitBreaker=B({failureThreshold:5,timeout:1e4,name:"solana-rpc"});constructor(e="mainnet-beta",t,n=!1){this.cluster=e,this.endpoint=t,this.allowUnknownMint=n,this.connection=this.createConnection()}createConnection(){const e=this.endpoint??k.clusterApiUrl(this.cluster);return new k.Connection(e,"confirmed")}transformRpcError(e){const t=e instanceof Error?e.message:typeof e=="string"?e:String(e);return t.includes("403")||t.includes("Access forbidden")?new Error("Public Solana RPC access denied. Please configure a custom RPC endpoint (e.g., from Helius, QuickNode, or Alchemy) in your CedrosProvider config using the solanaEndpoint option."):t.includes("429")||t.includes("Too Many Requests")?new Error("Solana RPC rate limit exceeded. Please configure a custom RPC endpoint with higher limits in your CedrosProvider config using the solanaEndpoint option."):e instanceof Error?e:new Error(t)}async buildTransaction(e){const{requirement:t,payerPublicKey:n,blockhash:a}=e;if(!t||!t.payTo)throw new Error("Invalid requirement: missing payTo");console.log("🔨 [WalletManager] Building NEW transaction for resource:",t.resource);const i=new k.Transaction,o=this.resolveAmountInMinorUnits(t),s=t.asset;if(!s)throw new Error("asset is required in x402 requirement");const u=xt(s,t.resource,this.allowUnknownMint);if(!u.isValid&&u.error)throw new Error(u.error);u.warning&&c().warn(u.warning);const l=new k.PublicKey(s),d=await oe.getAssociatedTokenAddress(l,n);if(!this.rpcRateLimiter.tryConsume())throw new Error("RPC rate limit exceeded. Please try again in a moment.");let f;try{f=await this.rpcCircuitBreaker.execute(async()=>await C(async()=>await this.connection.getAccountInfo(d),{...P.QUICK,name:"rpc-get-account-info"}))}catch(p){throw p instanceof g?new Error("Solana RPC service is temporarily unavailable. Please try again in a few moments."):this.transformRpcError(p)}if(!f)throw new Error("Payer is missing an associated token account for this mint");let h;try{h=t.extra?.recipientTokenAccount?new k.PublicKey(t.extra.recipientTokenAccount):new k.PublicKey(t.payTo)}catch{throw new Error("We are currently unable to process payment, please try again later")}if(i.add(oe.createTransferInstruction(d,h,n,o)),t.extra?.memo){const{TransactionInstruction:p}=await import("@solana/web3.js"),m=new p({keys:[],programId:new k.PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"),data:Buffer.from(t.extra.memo,"utf8")});i.add(m)}let y;if(a)y=a;else{if(!this.rpcRateLimiter.tryConsume())throw new Error("RPC rate limit exceeded. Please try again in a moment.");try{y=(await this.rpcCircuitBreaker.execute(async()=>await C(async()=>await this.connection.getLatestBlockhash(),{...P.QUICK,name:"rpc-get-blockhash"}))).blockhash}catch(p){throw p instanceof g?new Error("Solana RPC service is temporarily unavailable. Please try again in a few moments."):this.transformRpcError(p)}}return i.recentBlockhash=y,t.extra?.feePayer?i.feePayer=new k.PublicKey(t.extra.feePayer):i.feePayer=n,i}resolveAmountInMinorUnits(e){const t=parseInt(e.maxAmountRequired,10);if(Number.isNaN(t)||t<=0)throw new Error("Invalid maxAmountRequired in requirement");return t}buildPaymentPayload(e){const{requirement:t,signedTx:n,payerPublicKey:a}=e;return{x402Version:0,scheme:t.scheme,network:t.network,payload:{signature:n.signature,transaction:n.serialized,payer:a.toString(),memo:t.extra?.memo,recipientTokenAccount:t.extra?.recipientTokenAccount}}}async signTransaction(e){const{transaction:t,signTransaction:n}=e;console.log("✍️ [WalletManager] Requesting wallet to sign transaction");const a=await n(t),i=a.serialize(),o=a.signatures[0]?.signature;if(!o)throw new Error("Signed transaction missing signature");const s=pe.encode(o);return console.log("✅ [WalletManager] Transaction signed with signature:",s.substring(0,20)+"..."),{serialized:_.fromUint8Array(i),signature:s}}deserializeTransaction(e){try{const t=_.toUint8Array(e);return k.Transaction.from(t)}catch(t){throw new Error(`Failed to deserialize transaction: ${D(t,"Unknown error")}`)}}async partiallySignTransaction(e){const{transaction:t,signTransaction:n,blockhash:a}=e;a&&t.recentBlockhash!==a&&(t.recentBlockhash=a);const i=await n(t),o=i.signatures[0]?.signature;if(o){const u=pe.encode(o);console.log("✅ [WalletManager] Partially signed with signature:",u.substring(0,20)+"...")}const s=i.serialize({requireAllSignatures:!1,verifySignatures:!1});return _.fromUint8Array(s)}async getBalance(e){if(!this.rpcRateLimiter.tryConsume())throw new Error("RPC rate limit exceeded. Please try again in a moment.");try{return await this.rpcCircuitBreaker.execute(async()=>await C(async()=>await this.connection.getBalance(e),{...P.QUICK,name:"rpc-get-balance"}))/k.LAMPORTS_PER_SOL}catch(t){throw t instanceof g?new Error("Solana RPC service is temporarily unavailable. Please try again in a few moments."):this.transformRpcError(t)}}async verifyTransaction(e){if(!this.rpcRateLimiter.tryConsume())return c().warn("[WalletManager] RPC rate limit exceeded for transaction verification"),!1;try{return!!(await this.rpcCircuitBreaker.execute(async()=>await C(async()=>await this.connection.getSignatureStatus(e),{...P.QUICK,name:"rpc-verify-tx"}))).value?.confirmationStatus}catch(t){return t instanceof g&&c().warn("[WalletManager] Circuit breaker OPEN - cannot verify transaction"),!1}}}class Rt{stripe=null;publicKey;routeDiscovery;sessionRateLimiter=A(M.PAYMENT);statusRateLimiter=A(M.QUOTE);circuitBreaker=B({failureThreshold:5,timeout:1e4,name:"subscription-manager"});constructor(e,t){this.publicKey=e,this.routeDiscovery=t}async initialize(){if(!this.stripe&&(this.stripe=await ve(this.publicKey),!this.stripe))throw new Error("Failed to initialize Stripe")}async executeWithResilience(e,t,n,a){if(!e.tryConsume())throw new Error("Rate limit exceeded. Please try again later.");try{return await this.circuitBreaker.execute(()=>C(t,{...P.STANDARD,name:n}))}catch(i){throw i instanceof g?(c().error(`[SubscriptionManager] Circuit breaker OPEN for ${a}`),new Error("Service temporarily unavailable. Please try again in a few moments.")):i}}async createSubscriptionSession(e){if(!this.sessionRateLimiter.tryConsume())throw new Error("Rate limit exceeded for subscription session creation. Please try again later.");try{return await this.circuitBreaker.execute(async()=>await C(async()=>{const t=await this.routeDiscovery.buildUrl("/paywall/v1/subscription/stripe-session");c().debug("[SubscriptionManager] Creating subscription session:",{resource:e.resource,interval:e.interval,trialDays:e.trialDays});const n=await w(t,{method:"POST",headers:{"Content-Type":"application/json","Idempotency-Key":U.generateUUID()},body:JSON.stringify(e)});if(!n.ok){const a=await S(n,"Failed to create subscription session");throw new Error(a)}return n.json()},{...P.STANDARD,name:"subscription-create-session"}))}catch(t){throw t instanceof g?(c().error("[SubscriptionManager] Circuit breaker is OPEN - service unavailable"),new Error("Subscription service is temporarily unavailable. Please try again in a few moments.")):t}}async redirectToCheckout(e){if(this.stripe||await this.initialize(),!this.stripe)return{success:!1,error:"Stripe not initialized"};const t=await this.stripe.redirectToCheckout({sessionId:e});return t.error?{success:!1,error:t.error.message}:{success:!0,transactionId:e}}async processSubscription(e){try{const t=await this.createSubscriptionSession(e);return await this.redirectToCheckout(t.sessionId)}catch(t){return{success:!1,error:D(t,"Subscription failed")}}}async checkSubscriptionStatus(e){if(!this.statusRateLimiter.tryConsume())throw new Error("Rate limit exceeded for subscription status check. Please try again later.");try{return await this.circuitBreaker.execute(async()=>await C(async()=>{const t=new URLSearchParams({resource:e.resource,userId:e.userId}),n=await this.routeDiscovery.buildUrl(`/paywall/v1/subscription/status?${t.toString()}`);c().debug("[SubscriptionManager] Checking subscription status:",e);const a=await w(n,{method:"GET",headers:{"Content-Type":"application/json"}});if(!a.ok){const i=await S(a,"Failed to check subscription status");throw new Error(i)}return a.json()},{...P.STANDARD,name:"subscription-status-check"}))}catch(t){throw t instanceof g?(c().error("[SubscriptionManager] Circuit breaker is OPEN for status check"),new Error("Subscription status service is temporarily unavailable. Please try again in a few moments.")):t}}async requestSubscriptionQuote(e,t,n){if(!this.statusRateLimiter.tryConsume())throw new Error("Rate limit exceeded for subscription quote. Please try again later.");try{return await this.circuitBreaker.execute(async()=>await C(async()=>{const a=await this.routeDiscovery.buildUrl("/paywall/v1/subscription/quote"),i={resource:e,interval:t,couponCode:n?.couponCode,intervalDays:n?.intervalDays};c().debug("[SubscriptionManager] Requesting subscription quote:",i);const o=await w(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(o.status!==402&&!o.ok){const s=await S(o,"Failed to get subscription quote");throw new Error(s)}return o.json()},{...P.STANDARD,name:"subscription-quote"}))}catch(a){throw a instanceof g?(c().error("[SubscriptionManager] Circuit breaker is OPEN for quote"),new Error("Subscription quote service is temporarily unavailable. Please try again in a few moments.")):a}}async cancelSubscription(e){return this.executeWithResilience(this.sessionRateLimiter,async()=>{const t=await this.routeDiscovery.buildUrl("/paywall/v1/subscription/cancel");c().debug("[SubscriptionManager] Canceling subscription:",e);const n=await w(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok)throw new Error(await S(n,"Failed to cancel"));return n.json()},"subscription-cancel","cancellation")}async getBillingPortalUrl(e){return this.executeWithResilience(this.statusRateLimiter,async()=>{const t=await this.routeDiscovery.buildUrl("/paywall/v1/subscription/portal");c().debug("[SubscriptionManager] Getting billing portal URL:",e);const n=await w(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok)throw new Error(await S(n,"Failed to get portal"));return n.json()},"subscription-portal","portal")}async activateX402Subscription(e){return this.executeWithResilience(this.sessionRateLimiter,async()=>{const t=await this.routeDiscovery.buildUrl("/paywall/v1/subscription/x402/activate");c().debug("[SubscriptionManager] Activating x402 subscription:",e);const n=await w(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok)throw new Error(await S(n,"Failed to activate"));return n.json()},"subscription-activate","activation")}}class kt{routeDiscovery;rateLimiter=A(M.PAYMENT);queryRateLimiter=A(M.QUOTE);circuitBreaker=B({failureThreshold:5,timeout:1e4,name:"subscription-change-manager"});constructor(e){this.routeDiscovery=e}async executeWithResilience(e,t,n,a){if(!e.tryConsume())throw new Error("Rate limit exceeded. Please try again later.");try{return await this.circuitBreaker.execute(()=>C(t,{...P.STANDARD,name:n}))}catch(i){throw i instanceof g?(c().error(`[SubscriptionChangeManager] Circuit breaker OPEN for ${a}`),new Error("Service temporarily unavailable. Please try again in a few moments.")):i}}async changeSubscription(e){return this.executeWithResilience(this.rateLimiter,async()=>{const t=await this.routeDiscovery.buildUrl("/paywall/v1/subscription/change");c().debug("[SubscriptionChangeManager] Changing subscription:",e);const n=await w(t,{method:"POST",headers:{"Content-Type":"application/json","Idempotency-Key":U.generateUUID()},body:JSON.stringify(e)});if(!n.ok)throw new Error(await S(n,"Failed to change subscription"));return n.json()},"subscription-change","plan change")}async previewChange(e){return this.executeWithResilience(this.queryRateLimiter,async()=>{const t=await this.routeDiscovery.buildUrl("/paywall/v1/subscription/change/preview");c().debug("[SubscriptionChangeManager] Previewing subscription change:",e);const n=await w(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok)throw new Error(await S(n,"Failed to preview change"));return n.json()},"subscription-preview","change preview")}async getDetails(e,t){return this.executeWithResilience(this.queryRateLimiter,async()=>{const n=new URLSearchParams({resource:e,userId:t}),a=await this.routeDiscovery.buildUrl(`/paywall/v1/subscription/details?${n}`);c().debug("[SubscriptionChangeManager] Getting subscription details:",{resource:e,userId:t});const i=await w(a,{method:"GET",headers:{"Content-Type":"application/json"}});if(!i.ok)throw new Error(await S(i,"Failed to get subscription details"));return i.json()},"subscription-details","details")}async cancel(e){return this.executeWithResilience(this.rateLimiter,async()=>{const t=await this.routeDiscovery.buildUrl("/paywall/v1/subscription/cancel");c().debug("[SubscriptionChangeManager] Canceling subscription:",e);const n=await w(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok)throw new Error(await S(n,"Failed to cancel subscription"));return n.json()},"subscription-cancel","cancellation")}async getBillingPortalUrl(e){return this.executeWithResilience(this.queryRateLimiter,async()=>{const t=await this.routeDiscovery.buildUrl("/paywall/v1/subscription/portal");c().debug("[SubscriptionChangeManager] Getting billing portal URL:",e);const n=await w(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok)throw new Error(await S(n,"Failed to get billing portal URL"));return n.json()},"subscription-portal","portal")}}class At{serverUrl;routePrefix=null;discoveryPromise=null;maxRetries=3;baseDelayMs=1e3;constructor(e){this.serverUrl=e}async discoverPrefix(){if(this.routePrefix!==null)return this.routePrefix;if(this.discoveryPromise)return this.discoveryPromise;const e=(async()=>{let t=0;for(;t<this.maxRetries;)try{const n=await w(`${this.serverUrl}/cedros-health`);if(!n.ok){if(n.status>=400&&n.status<500)return c().warn(`Route discovery received ${n.status} - not retrying client error`),this.routePrefix="","";throw new Error(`Health check returned ${n.status}`)}const i=(await n.json()).routePrefix||"";return this.routePrefix=i,c().debug("Route discovery successful, prefix:",i||"(empty)"),i}catch(n){if(t++,t>=this.maxRetries)return c().warn(`Route discovery failed after ${t} attempts, using empty prefix for this request:`,n),"";const a=this.baseDelayMs*Math.pow(2,t-1);c().warn(`Route discovery failed (attempt ${t}/${this.maxRetries}), retrying in ${a}ms:`,n),await new Promise(i=>setTimeout(i,a))}return""})();this.discoveryPromise=e;try{return await this.discoveryPromise}finally{this.discoveryPromise=null}}async buildUrl(e){const t=await this.discoverPrefix(),n=e.startsWith("/")?e:`/${e}`;return`${this.serverUrl}${t}${n}`}reset(){this.routePrefix=null,this.discoveryPromise=null}}const H=new Map;function Le(r,e,t,n,a){return JSON.stringify({stripePublicKey:r,serverUrl:e,solanaCluster:t,solanaEndpoint:n||"",dangerouslyAllowUnknownMint:a||!1})}function Mt(r,e,t,n,a){const i=Le(r,e,t,n,a);let o=H.get(i);if(o)return o.refCount++,c().debug(`[ManagerCache] Reusing cached managers (refCount: ${o.refCount}):`,{stripePublicKey:r.slice(0,10)+"...",serverUrl:e}),o;c().debug("[ManagerCache] Creating new manager instances:",{stripePublicKey:r.slice(0,10)+"...",serverUrl:e});const s=new At(e),u=new ut(r,s),l=new Et(s),d=new Tt(t,n,a??!1),f=new Rt(r,s),h=new kt(s);return o={stripeManager:u,x402Manager:l,walletManager:d,subscriptionManager:f,subscriptionChangeManager:h,routeDiscovery:s,refCount:1},H.set(i,o),o}function Ut(r,e,t,n,a){const i=Le(r,e,t,n,a),o=H.get(i);if(!o){c().warn("[ManagerCache] Attempted to release non-existent managers:",{cacheKey:i});return}o.refCount--,c().debug(`[ManagerCache] Released manager reference (refCount: ${o.refCount}):`,{stripePublicKey:r.slice(0,10)+"...",serverUrl:e}),o.refCount<=0&&(H.delete(i),c().debug("[ManagerCache] Removed managers from cache (refCount reached 0)"))}const Dt=["stripePublicKey"],ye=new Set(["mainnet-beta","devnet","testnet"]);function Ot(){if(typeof window<"u"&&window.location)return window.location.origin;throw new Error("serverUrl is required in SSR/Node environments. In browser environments, it defaults to window.location.origin")}function Fe(r){const e=[];Dt.forEach(n=>{const a=r[n];(typeof a!="string"||a.trim().length===0)&&e.push({field:n,message:"must be a non-empty string"})});let t;if(r.serverUrl!==void 0)typeof r.serverUrl!="string"||r.serverUrl.trim().length===0?(e.push({field:"serverUrl",message:"must be a non-empty string when provided"}),t=""):t=r.serverUrl;else try{t=Ot()}catch(n){e.push({field:"serverUrl",message:n instanceof Error?n.message:"failed to determine default"}),t=""}if(ye.has(r.solanaCluster)||e.push({field:"solanaCluster",message:`must be one of ${Array.from(ye).join(", ")}`}),r.solanaEndpoint!==void 0&&(typeof r.solanaEndpoint!="string"?e.push({field:"solanaEndpoint",message:"must be a string when provided"}):r.solanaEndpoint.trim().length===0?e.push({field:"solanaEndpoint",message:'must be a non-empty string when provided (e.g., "https://api.mainnet-beta.solana.com")'}):!r.solanaEndpoint.startsWith("http://")&&!r.solanaEndpoint.startsWith("https://")&&e.push({field:"solanaEndpoint",message:'must start with "http://" or "https://" (e.g., "https://api.mainnet-beta.solana.com")'})),r.tokenMint&&typeof r.tokenMint!="string"&&e.push({field:"tokenMint",message:"must be a string when provided"}),e.length>0){const n=e.map(a=>`- ${a.field} ${a.message}`).join(`
`);throw new Error(`Invalid Cedros configuration:
${n}`)}if(r.tokenMint){const n=r.dangerouslyAllowUnknownMint===!0,a=ne(r.tokenMint,"CedrosConfig.tokenMint",n);if(!a.isValid&&a.error)throw new Error(a.error);a.warning&&c().warn(a.warning)}return{...r,serverUrl:t}}class je{adapters=null;poolId;isCleanedUp=!1;constructor(e){this.poolId=e??`pool_${Date.now()}_${Math.random().toString(36).slice(2,11)}`,c().debug(`[WalletPool] Created pool: ${this.poolId}`)}getAdapters(){return typeof window>"u"?[]:this.isCleanedUp?(c().warn(`[WalletPool] Attempted to use pool after cleanup: ${this.poolId}`),[]):this.adapters!==null?this.adapters:(c().debug(`[WalletPool] Initializing adapters for pool: ${this.poolId}`),this.adapters=[new se.PhantomWalletAdapter,new se.SolflareWalletAdapter],this.adapters)}async cleanup(){if(this.isCleanedUp){c().debug(`[WalletPool] Pool already cleaned up: ${this.poolId}`);return}if(c().debug(`[WalletPool] Cleaning up pool: ${this.poolId}`),this.isCleanedUp=!0,this.adapters===null)return;const e=this.adapters.map(async t=>{try{t.connected&&(c().debug(`[WalletPool] Disconnecting wallet: ${t.name}`),await t.disconnect())}catch(n){c().warn(`[WalletPool] Failed to disconnect wallet ${t.name}:`,n)}});await Promise.allSettled(e),this.adapters=null,c().debug(`[WalletPool] Pool cleanup complete: ${this.poolId}`)}isInitialized(){return this.adapters!==null}getId(){return this.poolId}}function _e(r){return new je(r)}const Nt=Object.freeze({surfaceBackground:"rgba(255, 255, 255, 0)",surfaceText:"#111827",surfaceBorder:"rgba(15, 23, 42, 0.08)",stripeBackground:"linear-gradient(135deg, #635bff 0%, #4f46e5 100%)",stripeText:"#ffffff",stripeShadow:"rgba(79, 70, 229, 0.25)",cryptoBackground:"linear-gradient(135deg, #14f195 0%, #9945ff 100%)",cryptoText:"#ffffff",cryptoShadow:"rgba(99, 102, 241, 0.25)",errorBackground:"#fee2e2",errorBorder:"#fca5a5",errorText:"#b91c1c",successBackground:"#dcfce7",successBorder:"#86efac",successText:"#166534",modalOverlay:"rgba(0, 0, 0, 0.5)",modalBackground:"#ffffff",modalBorder:"rgba(15, 23, 42, 0.08)",buttonBorderRadius:"8px",buttonPadding:"0.75rem 1.5rem",buttonFontSize:"1rem",buttonFontWeight:"600"}),Bt=Object.freeze({surfaceBackground:"rgba(17, 24, 39, 0.6)",surfaceText:"#f9fafb",surfaceBorder:"rgba(148, 163, 184, 0.25)",stripeBackground:"linear-gradient(135deg, #4f46e5 0%, #3730a3 100%)",stripeText:"#f5f3ff",stripeShadow:"rgba(99, 102, 241, 0.35)",cryptoBackground:"linear-gradient(135deg, #1dd4a6 0%, #6d28d9 100%)",cryptoText:"#ecfeff",cryptoShadow:"rgba(75, 85, 99, 0.35)",errorBackground:"#7f1d1d",errorBorder:"#fca5a5",errorText:"#fecaca",successBackground:"#14532d",successBorder:"#4ade80",successText:"#bbf7d0",modalOverlay:"rgba(0, 0, 0, 0.75)",modalBackground:"#1f2937",modalBorder:"rgba(148, 163, 184, 0.25)",buttonBorderRadius:"8px",buttonPadding:"0.75rem 1.5rem",buttonFontSize:"1rem",buttonFontWeight:"600"}),It={surfaceBackground:"--cedros-surface-bg",surfaceText:"--cedros-surface-text",surfaceBorder:"--cedros-surface-border",stripeBackground:"--cedros-stripe-bg",stripeText:"--cedros-stripe-text",stripeShadow:"--cedros-stripe-shadow",cryptoBackground:"--cedros-crypto-bg",cryptoText:"--cedros-crypto-text",cryptoShadow:"--cedros-crypto-shadow",errorBackground:"--cedros-error-bg",errorBorder:"--cedros-error-border",errorText:"--cedros-error-text",successBackground:"--cedros-success-bg",successBorder:"--cedros-success-border",successText:"--cedros-success-text",modalOverlay:"--cedros-modal-overlay",modalBackground:"--cedros-modal-bg",modalBorder:"--cedros-modal-border",buttonBorderRadius:"--cedros-button-radius",buttonPadding:"--cedros-button-padding",buttonFontSize:"--cedros-button-font-size",buttonFontWeight:"--cedros-button-font-weight"},$e=E.createContext(null);function Lt(r,e){return{...r==="dark"?Bt:Nt,...e}}function Ft(r){const e=Object.entries(r).map(([t,n])=>[It[t],n]);return Object.fromEntries(e)}function jt({initialMode:r="light",overrides:e,unstyled:t=!1,children:n}){const[a,i]=E.useState(r),[o,s]=E.useState(e),u=E.useRef(e);E.useEffect(()=>{if(e===u.current)return;(!e||!u.current?e!==u.current:Object.keys({...e,...u.current}).some(f=>e[f]!==u.current?.[f]))&&(u.current=e,s(e))},[e]);const l=E.useMemo(()=>{const d=Lt(a,o),f=t?{}:Ft(d),h=t?"":`cedros-theme-root cedros-theme cedros-theme--${a}`;return{mode:a,setMode:i,tokens:d,className:h,style:f,unstyled:t}},[a,o,t]);return Y.jsx($e.Provider,{value:l,children:n})}function _t(){const r=E.useContext($e);if(!r)throw new Error("useCedrosTheme must be used within CedrosProvider");return r}let J=!1,X=!1;async function $t(){if(J)return X?{available:!0}:{available:!1,error:me()};try{return await import("@solana/web3.js"),J=!0,X=!0,{available:!0}}catch{return J=!0,X=!1,{available:!1,error:me()}}}function me(){return`Solana dependencies not installed. To use crypto payments, install them with:
npm install @solana/web3.js @solana/spl-token @solana/wallet-adapter-react @solana/wallet-adapter-react-ui @solana/wallet-adapter-wallets @solana/wallet-adapter-base
Or if you only need Stripe payments, hide the crypto button with:
<CedrosPay showCrypto={false} />`}function Wt(){return typeof process<"u"&&process.env.NODE_ENV==="development"?0:2}const We=E.createContext(null);function qt({config:r,children:e}){const t=E.useMemo(()=>Fe(r),[r]),n=E.useRef(null);n.current===null&&(n.current=_e());const[a,i]=E.useState(null);E.useEffect(()=>{let s=!1;return $t().then(u=>{s||(u.available?i(void 0):i(u.error||"Solana dependencies not available"))}),()=>{s=!0}},[]),E.useEffect(()=>{const s=t.logLevel??Wt(),u=Se({level:s,prefix:"[CedrosPay]"});nt(u)},[t.logLevel]),E.useEffect(()=>{const s=n.current;return()=>{s&&s.cleanup().catch(u=>{c().warn("[CedrosProvider] Wallet pool cleanup failed:",u)})}},[]),E.useEffect(()=>{const s=t.stripePublicKey,u=t.serverUrl??"",l=t.solanaCluster,d=t.solanaEndpoint,f=t.dangerouslyAllowUnknownMint;return()=>{Ut(s,u,l,d,f)}},[t.stripePublicKey,t.serverUrl,t.solanaCluster,t.solanaEndpoint,t.dangerouslyAllowUnknownMint]);const o=E.useMemo(()=>{const{stripeManager:s,x402Manager:u,walletManager:l,subscriptionManager:d,subscriptionChangeManager:f}=Mt(t.stripePublicKey,t.serverUrl??"",t.solanaCluster,t.solanaEndpoint,t.dangerouslyAllowUnknownMint);return{config:t,stripeManager:s,x402Manager:u,walletManager:l,subscriptionManager:d,subscriptionChangeManager:f,walletPool:n.current,solanaError:a}},[t,a]);return Y.jsx(We.Provider,{value:o,children:Y.jsx(jt,{initialMode:t.theme??"light",overrides:t.themeOverrides,unstyled:t.unstyled??!1,children:e})})}function Kt(){const r=E.useContext(We);if(!r)throw new Error("useCedrosContext must be used within CedrosProvider");return r}exports.CIRCUIT_BREAKER_PRESETS=ot;exports.CedrosProvider=qt;exports.CircuitBreakerOpenError=g;exports.CircuitState=Ce;exports.KNOWN_STABLECOINS=G;exports.LogLevel=Ee;exports.Logger=ee;exports.RATE_LIMITER_PRESETS=M;exports.RETRY_PRESETS=P;exports.WalletPool=je;exports.createCircuitBreaker=B;exports.createLogger=Se;exports.createRateLimiter=A;exports.createWalletPool=_e;exports.formatError=D;exports.g