@cedros/pay-react 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -3
- package/dist/CedrosContext-CFEXGwQg.mjs +2163 -0
- package/dist/CedrosContext-DbndTsTA.js +11 -0
- package/dist/components/CryptoSubscribeButton.d.ts +50 -0
- package/dist/components/CryptoSubscribeButton.d.ts.map +1 -0
- package/dist/components/SubscribeButton.d.ts +55 -0
- package/dist/components/SubscribeButton.d.ts.map +1 -0
- package/dist/components/SubscriptionManagementPanel.d.ts +67 -0
- package/dist/components/SubscriptionManagementPanel.d.ts.map +1 -0
- package/dist/components/subscriptionPanelStyles.d.ts +13 -0
- package/dist/components/subscriptionPanelStyles.d.ts.map +1 -0
- package/dist/context/CedrosContext.d.ts +4 -0
- package/dist/context/CedrosContext.d.ts.map +1 -1
- package/dist/crypto-only.js +1 -1
- package/dist/crypto-only.mjs +2 -2
- package/dist/en-C739WV_-.mjs +19 -0
- package/dist/en-Cz4OpvN-.js +1 -0
- package/dist/hooks/useCryptoSubscription.d.ts +42 -0
- package/dist/hooks/useCryptoSubscription.d.ts.map +1 -0
- package/dist/hooks/useSubscription.d.ts +42 -0
- package/dist/hooks/useSubscription.d.ts.map +1 -0
- package/dist/hooks/useSubscriptionManagement.d.ts +88 -0
- package/dist/hooks/useSubscriptionManagement.d.ts.map +1 -0
- package/dist/i18n/index.d.ts +7 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1658 -361
- package/dist/managers/ManagerCache.d.ts +4 -0
- package/dist/managers/ManagerCache.d.ts.map +1 -1
- package/dist/managers/SubscriptionChangeManager.d.ts +42 -0
- package/dist/managers/SubscriptionChangeManager.d.ts.map +1 -0
- package/dist/managers/SubscriptionManager.d.ts +113 -0
- package/dist/managers/SubscriptionManager.d.ts.map +1 -0
- package/dist/pay-react.css +1 -1
- package/dist/stripe-only.js +1 -1
- package/dist/stripe-only.mjs +2 -2
- package/dist/{styles-DI2LPVdQ.mjs → styles-DFcRS8Uu.mjs} +13 -12
- package/dist/{styles-61pRysGe.js → styles-Dup9uK6S.js} +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/index.mjs +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/subscription.d.ts +300 -0
- package/dist/types/subscription.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/CedrosContext-B3iCqN6e.js +0 -11
- package/dist/CedrosContext-vX9uqZKp.mjs +0 -1796
- package/dist/en-CSsJl3nf.mjs +0 -19
- package/dist/en-D-uY3ltT.js +0 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"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(`
|
|
2
|
+
`);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(`
|
|
3
|
+
`)}:{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(`
|
|
4
|
+
`)}}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(`
|
|
5
|
+
`);throw new Error(`Invalid Cedros configuration:
|
|
6
|
+
${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:
|
|
7
|
+
|
|
8
|
+
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
|
|
9
|
+
|
|
10
|
+
Or if you only need Stripe payments, hide the crypto button with:
|
|
11
|
+
<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.getLogger=c;exports.retryWithBackoff=C;exports.useCedrosContext=Kt;exports.useCedrosTheme=_t;exports.validateConfig=Fe;exports.validateTokenMint=ne;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { BillingInterval } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Props for CryptoSubscribeButton component
|
|
4
|
+
*/
|
|
5
|
+
interface CryptoSubscribeButtonProps {
|
|
6
|
+
/** Resource/plan ID for the subscription */
|
|
7
|
+
resource: string;
|
|
8
|
+
/** Billing interval */
|
|
9
|
+
interval: BillingInterval;
|
|
10
|
+
/** Custom interval in days (only used when interval is 'custom') */
|
|
11
|
+
intervalDays?: number;
|
|
12
|
+
/** Coupon code for discount */
|
|
13
|
+
couponCode?: string;
|
|
14
|
+
/** Custom button label */
|
|
15
|
+
label?: string;
|
|
16
|
+
/** Disable button */
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
/** Track subscription attempt for analytics */
|
|
19
|
+
onAttempt?: (method: 'stripe' | 'crypto') => void;
|
|
20
|
+
/** Callback on successful subscription */
|
|
21
|
+
onSuccess?: (transactionId: string) => void;
|
|
22
|
+
/** Callback on error */
|
|
23
|
+
onError?: (error: string) => void;
|
|
24
|
+
/** Additional CSS class */
|
|
25
|
+
className?: string;
|
|
26
|
+
/** URL to open in new tab for testing (e.g., Storybook test page) */
|
|
27
|
+
testPageUrl?: string;
|
|
28
|
+
/** Hide inline success/error messages */
|
|
29
|
+
hideMessages?: boolean;
|
|
30
|
+
/** Auto-check subscription status on mount when wallet is connected */
|
|
31
|
+
autoCheckStatus?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Button component for x402 crypto subscription payments
|
|
35
|
+
*
|
|
36
|
+
* Shows subscription status when active, otherwise allows subscribing
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* <CryptoSubscribeButton
|
|
41
|
+
* resource="plan-pro"
|
|
42
|
+
* interval="monthly"
|
|
43
|
+
* autoCheckStatus
|
|
44
|
+
* onSuccess={(txId) => console.log('Subscribed!', txId)}
|
|
45
|
+
* />
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function CryptoSubscribeButton({ resource, interval, intervalDays, couponCode, label, disabled, onAttempt, onSuccess, onError, className, testPageUrl, hideMessages, autoCheckStatus, }: CryptoSubscribeButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=CryptoSubscribeButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CryptoSubscribeButton.d.ts","sourceRoot":"","sources":["../../src/components/CryptoSubscribeButton.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhD;;GAEG;AACH,UAAU,0BAA0B;IAClC,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,KAAK,IAAI,CAAC;IAClD,0CAA0C;IAC1C,SAAS,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,wBAAwB;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,KAAK,EACL,QAAgB,EAChB,SAAS,EACT,SAAS,EACT,OAAO,EACP,SAAc,EACd,WAAW,EACX,YAAoB,EACpB,eAAsB,GACvB,EAAE,0BAA0B,2CAue5B"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { BillingInterval } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Props for SubscribeButton component
|
|
4
|
+
*/
|
|
5
|
+
interface SubscribeButtonProps {
|
|
6
|
+
/** Resource/plan ID for the subscription */
|
|
7
|
+
resource: string;
|
|
8
|
+
/** Billing interval */
|
|
9
|
+
interval: BillingInterval;
|
|
10
|
+
/** Custom interval in days (only used when interval is 'custom') */
|
|
11
|
+
intervalDays?: number;
|
|
12
|
+
/** Number of trial days (0 for no trial) */
|
|
13
|
+
trialDays?: number;
|
|
14
|
+
/** URL to redirect on success */
|
|
15
|
+
successUrl?: string;
|
|
16
|
+
/** URL to redirect on cancel */
|
|
17
|
+
cancelUrl?: string;
|
|
18
|
+
/** Metadata for tracking */
|
|
19
|
+
metadata?: Record<string, string>;
|
|
20
|
+
/** Customer email (pre-fills Stripe checkout) */
|
|
21
|
+
customerEmail?: string;
|
|
22
|
+
/** Coupon code for discount */
|
|
23
|
+
couponCode?: string;
|
|
24
|
+
/** Custom button label */
|
|
25
|
+
label?: string;
|
|
26
|
+
/** Disable button */
|
|
27
|
+
disabled?: boolean;
|
|
28
|
+
/** Track subscription attempt for analytics */
|
|
29
|
+
onAttempt?: (method: 'stripe' | 'crypto') => void;
|
|
30
|
+
/** Callback on successful subscription redirect */
|
|
31
|
+
onSuccess?: (sessionId: string) => void;
|
|
32
|
+
/** Callback on error */
|
|
33
|
+
onError?: (error: string) => void;
|
|
34
|
+
/** Additional CSS class */
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Button component for Stripe subscription checkout
|
|
39
|
+
*
|
|
40
|
+
* Handles redirect to Stripe-hosted subscription checkout
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```tsx
|
|
44
|
+
* <SubscribeButton
|
|
45
|
+
* resource="plan-pro"
|
|
46
|
+
* interval="monthly"
|
|
47
|
+
* trialDays={14}
|
|
48
|
+
* onSuccess={(sessionId) => console.log('Redirecting...', sessionId)}
|
|
49
|
+
* onError={(error) => console.error(error)}
|
|
50
|
+
* />
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function SubscribeButton({ resource, interval, intervalDays, trialDays, successUrl, cancelUrl, metadata, customerEmail, couponCode, label, disabled, onAttempt, onSuccess, onError, className, }: SubscribeButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=SubscribeButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubscribeButton.d.ts","sourceRoot":"","sources":["../../src/components/SubscribeButton.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhD;;GAEG;AACH,UAAU,oBAAoB;IAC5B,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,KAAK,IAAI,CAAC;IAClD,mDAAmD;IACnD,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,wBAAwB;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,UAAU,EACV,SAAS,EACT,QAAQ,EACR,aAAa,EACb,UAAU,EACV,KAAK,EACL,QAAgB,EAChB,SAAS,EACT,SAAS,EACT,OAAO,EACP,SAAc,GACf,EAAE,oBAAoB,2CA2HtB"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { BillingInterval } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Available plan for upgrade/downgrade
|
|
4
|
+
*/
|
|
5
|
+
export interface AvailablePlan {
|
|
6
|
+
/** Plan resource ID */
|
|
7
|
+
resource: string;
|
|
8
|
+
/** Display name */
|
|
9
|
+
name: string;
|
|
10
|
+
/** Price per period (in cents) */
|
|
11
|
+
price: number;
|
|
12
|
+
/** Currency */
|
|
13
|
+
currency: string;
|
|
14
|
+
/** Billing interval */
|
|
15
|
+
interval: BillingInterval;
|
|
16
|
+
/** Optional description */
|
|
17
|
+
description?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Props for SubscriptionManagementPanel
|
|
21
|
+
*/
|
|
22
|
+
export interface SubscriptionManagementPanelProps {
|
|
23
|
+
/** Current plan resource ID */
|
|
24
|
+
resource: string;
|
|
25
|
+
/** User identifier (email, customer ID, or wallet address) */
|
|
26
|
+
userId: string;
|
|
27
|
+
/** Available plans for upgrade/downgrade */
|
|
28
|
+
availablePlans?: AvailablePlan[];
|
|
29
|
+
/** Callback when subscription is successfully changed */
|
|
30
|
+
onSubscriptionChanged?: (newResource: string, newInterval: BillingInterval) => void;
|
|
31
|
+
/** Callback when subscription is canceled */
|
|
32
|
+
onSubscriptionCanceled?: () => void;
|
|
33
|
+
/** Return URL for billing portal */
|
|
34
|
+
billingPortalReturnUrl?: string;
|
|
35
|
+
/** Show billing portal button (Stripe subscriptions only) */
|
|
36
|
+
showBillingPortal?: boolean;
|
|
37
|
+
/** Custom class name */
|
|
38
|
+
className?: string;
|
|
39
|
+
/** Custom styles */
|
|
40
|
+
style?: React.CSSProperties;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Subscription management panel component
|
|
44
|
+
*
|
|
45
|
+
* Provides a UI for viewing and managing existing subscriptions:
|
|
46
|
+
* - View current subscription details
|
|
47
|
+
* - Upgrade or downgrade to different plans
|
|
48
|
+
* - Cancel subscription
|
|
49
|
+
* - Access Stripe billing portal
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* <SubscriptionManagementPanel
|
|
54
|
+
* resource="plan-pro"
|
|
55
|
+
* userId="user@example.com"
|
|
56
|
+
* availablePlans={[
|
|
57
|
+
* { resource: 'plan-basic', name: 'Basic', price: 999, currency: 'USD', interval: 'monthly' },
|
|
58
|
+
* { resource: 'plan-pro', name: 'Pro', price: 1999, currency: 'USD', interval: 'monthly' },
|
|
59
|
+
* { resource: 'plan-enterprise', name: 'Enterprise', price: 4999, currency: 'USD', interval: 'monthly' },
|
|
60
|
+
* ]}
|
|
61
|
+
* onSubscriptionChanged={(newResource) => console.log('Changed to:', newResource)}
|
|
62
|
+
* showBillingPortal
|
|
63
|
+
* />
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function SubscriptionManagementPanel({ resource, userId, availablePlans, onSubscriptionChanged, onSubscriptionCanceled, billingPortalReturnUrl, showBillingPortal, className, style, }: SubscriptionManagementPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
67
|
+
//# sourceMappingURL=SubscriptionManagementPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubscriptionManagementPanel.d.ts","sourceRoot":"","sources":["../../src/components/SubscriptionManagementPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,UAAU,CAAC;AAQvE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,eAAe;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,2BAA2B;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,yDAAyD;IACzD,qBAAqB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,KAAK,IAAI,CAAC;IACpF,6CAA6C;IAC7C,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IACpC,oCAAoC;IACpC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,6DAA6D;IAC7D,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAmED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,2BAA2B,CAAC,EAC1C,QAAQ,EACR,MAAM,EACN,cAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,sBAAsB,EACtB,iBAAyB,EACzB,SAAS,EACT,KAAK,GACN,EAAE,gCAAgC,2CA2LlC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Inline styles for SubscriptionManagementPanel
|
|
4
|
+
* Separated to keep component file under 500 lines
|
|
5
|
+
*/
|
|
6
|
+
export declare const subscriptionPanelStyles: Record<string, CSSProperties>;
|
|
7
|
+
/** Format currency amount */
|
|
8
|
+
export declare function formatAmount(amount: number, currency: string): string;
|
|
9
|
+
/** Format date */
|
|
10
|
+
export declare function formatDate(isoDate: string): string;
|
|
11
|
+
/** Get status badge color */
|
|
12
|
+
export declare function getStatusColor(status: string): string;
|
|
13
|
+
//# sourceMappingURL=subscriptionPanelStyles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriptionPanelStyles.d.ts","sourceRoot":"","sources":["../../src/components/subscriptionPanelStyles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CA0MjE,CAAC;AAEF,6BAA6B;AAC7B,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKrE;AAED,kBAAkB;AAClB,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,6BAA6B;AAC7B,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAcrD"}
|
|
@@ -3,6 +3,8 @@ import { CedrosConfig } from '../types';
|
|
|
3
3
|
import { IStripeManager } from '../managers/StripeManager';
|
|
4
4
|
import { IX402Manager } from '../managers/X402Manager';
|
|
5
5
|
import { IWalletManager } from '../managers/WalletManager';
|
|
6
|
+
import { ISubscriptionManager } from '../managers/SubscriptionManager';
|
|
7
|
+
import { ISubscriptionChangeManager } from '../managers/SubscriptionChangeManager';
|
|
6
8
|
import { WalletPool } from '../utils/walletPool';
|
|
7
9
|
/**
|
|
8
10
|
* Context value containing configuration and manager instances.
|
|
@@ -15,6 +17,8 @@ export interface CedrosContextValue {
|
|
|
15
17
|
stripeManager: IStripeManager;
|
|
16
18
|
x402Manager: IX402Manager;
|
|
17
19
|
walletManager: IWalletManager;
|
|
20
|
+
subscriptionManager: ISubscriptionManager;
|
|
21
|
+
subscriptionChangeManager: ISubscriptionChangeManager;
|
|
18
22
|
/** Context-scoped wallet pool (for internal use by CedrosPay component) */
|
|
19
23
|
walletPool: WalletPool;
|
|
20
24
|
/** Cached Solana availability check result (null = not checked yet, string = error message, undefined = available) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CedrosContext.d.ts","sourceRoot":"","sources":["../../src/context/CedrosContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAoD,MAAM,OAAO,CAAC;AACxG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"CedrosContext.d.ts","sourceRoot":"","sources":["../../src/context/CedrosContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAoD,MAAM,OAAO,CAAC;AACxG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AAKxF,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAaxE;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,cAAc,CAAC;IAC9B,WAAW,EAAE,YAAY,CAAC;IAC1B,aAAa,EAAE,cAAc,CAAC;IAC9B,mBAAmB,EAAE,oBAAoB,CAAC;IAC1C,yBAAyB,EAAE,0BAA0B,CAAC;IACtD,2EAA2E;IAC3E,UAAU,EAAE,UAAU,CAAC;IACvB,sHAAsH;IACtH,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACxC;AAED;;GAEG;AACH,UAAU,mBAAmB;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAID;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,mBAAmB,2CAuHvE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,kBAAkB,CAQrD"}
|
package/dist/crypto-only.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./CedrosContext-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./CedrosContext-DbndTsTA.js"),e=require("./styles-Dup9uK6S.js");require("@solana/wallet-adapter-wallets");exports.CedrosProvider=t.CedrosProvider;exports.KNOWN_STABLECOINS=t.KNOWN_STABLECOINS;exports.LogLevel=t.LogLevel;exports.Logger=t.Logger;exports.RATE_LIMITER_PRESETS=t.RATE_LIMITER_PRESETS;exports.createLogger=t.createLogger;exports.createRateLimiter=t.createRateLimiter;exports.getLogger=t.getLogger;exports.useCedrosContext=t.useCedrosContext;exports.useCedrosTheme=t.useCedrosTheme;exports.validateConfig=t.validateConfig;exports.validateTokenMint=t.validateTokenMint;exports.CEDROS_EVENTS=e.CEDROS_EVENTS;exports.CryptoButton=e.CryptoButton;exports.ERROR_CATEGORIES=e.ERROR_CATEGORIES;exports.PaymentMethodBadge=e.PaymentMethodBadge;exports.PaymentModal=e.PaymentModal;exports.ProductPrice=e.ProductPrice;exports.calculateDiscountPercentage=e.calculateDiscountPercentage;exports.emitPaymentError=e.emitPaymentError;exports.emitPaymentProcessing=e.emitPaymentProcessing;exports.emitPaymentStart=e.emitPaymentStart;exports.emitPaymentSuccess=e.emitPaymentSuccess;exports.formatCouponCodes=e.formatCouponCodes;exports.getUserErrorMessage=e.getUserErrorMessage;exports.isRetryableError=e.isRetryableError;exports.parseCouponCodes=e.parseCouponCodes;exports.parseStructuredErrorResponse=e.parseErrorResponse;exports.usePaymentMode=e.usePaymentMode;exports.useX402Payment=e.useX402Payment;
|
package/dist/crypto-only.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as r, K as t, L as o, b as n, R as m, d as i, c as d, g, u as E, a as C, v as P, e as c } from "./CedrosContext-
|
|
2
|
-
import { C as R, m as p, E as y, b as S, P as L, a as l, d as T, i as M, g as f, e as v, h as O, f as _, l as I, k as N, p as b, j as h, c as x, n as A } from "./styles-
|
|
1
|
+
import { C as r, K as t, L as o, b as n, R as m, d as i, c as d, g, u as E, a as C, v as P, e as c } from "./CedrosContext-CFEXGwQg.mjs";
|
|
2
|
+
import { C as R, m as p, E as y, b as S, P as L, a as l, d as T, i as M, g as f, e as v, h as O, f as _, l as I, k as N, p as b, j as h, c as x, n as A } from "./styles-DFcRS8Uu.mjs";
|
|
3
3
|
import "@solana/wallet-adapter-wallets";
|
|
4
4
|
export {
|
|
5
5
|
R as CEDROS_EVENTS,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const e = "CEDROS PAY - Translation Source File (English)", a = "1.0.0", i = "en", n = { pay_with_card: "Pay with Card", pay_with_crypto: "Pay with USDC", pay_with_usdc: "Pay with USDC", purchase: "Purchase", card: "Card", usdc_solana: "USDC (Solana)", crypto: "Crypto", connect_wallet: "Connect Wallet", connecting: "Connecting...", processing: "Processing...", loading: "Loading...", close: "Close", cancel: "Cancel", confirm: "Confirm", retry: "Try Again", go_back: "Go Back", contact_support: "Contact Support", disconnect: "Disconnect", payment_successful: "Payment successful!", subscribe: "Subscribe", subscribe_with_crypto: "Subscribe with USDC", subscribed: "Subscribed", subscribed_until: "Subscribed until", subscription_active: "Your subscription is active!", redirecting_to_checkout: "Redirecting to checkout..." }, t = { invalid_payment_proof: { message: "Payment verification failed", action: "Please try your payment again. If this continues, contact support." }, invalid_signature: { message: "Transaction signature is invalid", action: "Please approve the transaction in your wallet and try again." }, invalid_transaction: { message: "Transaction format is invalid", action: "Please try your payment again. If this continues, try updating your wallet app." }, transaction_not_found: { message: "Transaction not found on the blockchain", action: "Your transaction may still be processing. Please wait a moment and check your wallet, or try again." }, transaction_not_confirmed: { message: "Transaction is still processing", action: "Please wait a moment for the blockchain to confirm your transaction, then try again." }, transaction_failed: { message: "Transaction failed on the blockchain", action: "Check your wallet for details. You may need to adjust your transaction settings or add more SOL for fees." }, transaction_expired: { message: "Transaction took too long to process", action: "Please try your payment again. Consider increasing transaction priority if your wallet supports it." }, invalid_recipient: { message: "Payment was sent to the wrong address", action: "Please try again and ensure you approve the correct transaction in your wallet." }, invalid_sender: { message: "Payment sender wallet is invalid", action: "Please reconnect your wallet and try again." }, unauthorized_refund_issuer: { message: "You are not authorized to issue refunds", action: "Only authorized accounts can process refunds. Please contact support if you believe this is an error." }, amount_below_minimum: { message: "Payment amount is too low", action: "Please check the required amount and try again." }, amount_mismatch: { message: "Payment amount does not match the quote", action: "The price may have changed. Please refresh and try your payment again." }, insufficient_funds_sol: { message: "Not enough SOL for transaction fees", action: "Add at least 0.001 SOL to your wallet to cover network fees, then try again." }, insufficient_funds_token: { message: "Insufficient balance in your wallet", action: "Add more funds to your wallet and try again." }, invalid_token_mint: { message: "Incorrect payment token", action: "Please pay with the correct token as shown in the payment details." }, not_spl_transfer: { message: "Transaction is not a valid token transfer", action: "Please ensure you are sending the correct token type from your wallet." }, missing_token_account: { message: "Token account not found", action: "Your wallet may need to create a token account first. Try again or use a different wallet." }, invalid_token_program: { message: "Invalid token program", action: "Please try your payment again. If this continues, try using a different wallet." }, missing_memo: { message: "Payment memo is required but was not included", action: "Please try your payment again and ensure transaction details are approved in your wallet." }, invalid_memo: { message: "Payment memo format is invalid", action: "Please try your payment again." }, payment_already_used: { message: "This payment has already been processed", action: "Check your transaction history. If you need to make another payment, please start a new transaction." }, signature_reused: { message: "Transaction signature has already been used", action: "Please create a new payment transaction." }, quote_expired: { message: "Payment quote has expired", action: "Prices are updated frequently. Please refresh and try your payment again." }, missing_field: { message: "Required information is missing", action: "Please check all required fields and try again." }, invalid_field: { message: "Some information is invalid", action: "Please check your input and try again." }, invalid_amount: { message: "Payment amount is invalid", action: "Please check the amount and try again." }, invalid_wallet: { message: "Wallet address is invalid", action: "Please reconnect your wallet and try again." }, invalid_resource: { message: "Invalid item selection", action: "Please refresh the page and try again." }, invalid_coupon: { message: "Invalid coupon code", action: "Please check the coupon code and try again." }, invalid_cart_item: { message: "One or more cart items are invalid", action: "Please review your cart and try again." }, empty_cart: { message: "Your cart is empty", action: "Please add items to your cart before checking out." }, resource_not_found: { message: "Item not found", action: "This item may no longer be available. Please refresh and try again." }, cart_not_found: { message: "Shopping cart not found", action: "Your cart may have expired. Please start a new order." }, refund_not_found: { message: "Refund not found", action: "Please check your refund reference number or contact support." }, product_not_found: { message: "Product not available", action: "This product may no longer be available. Please browse our current selection." }, coupon_not_found: { message: "Coupon code not found", action: "Please check the coupon code or remove it to continue." }, session_not_found: { message: "Payment session expired", action: "Please start a new payment." }, cart_already_paid: { message: "This order has already been paid", action: "Check your order history. If you need to make another purchase, please start a new order." }, refund_already_processed: { message: "This refund has already been processed", action: "Check your transaction history or contact support for details." }, coupon_expired: { message: "Coupon has expired", action: "Please remove the coupon code or use a different code." }, coupon_usage_limit_reached: { message: "Coupon usage limit reached", action: "This coupon has been fully redeemed. Please try a different code." }, coupon_not_applicable: { message: "Coupon cannot be applied to this purchase", action: "Please check the coupon terms or remove it to continue." }, coupon_wrong_payment_method: { message: "Coupon not valid for this payment method", action: "Try a different payment method or remove the coupon code." }, stripe_error: { message: "Card payment service temporarily unavailable", action: "Please try again in a moment, or use cryptocurrency payment instead." }, rpc_error: { message: "Blockchain network temporarily unavailable", action: "Please try again in a moment, or use card payment instead." }, network_error: { message: "Network connection issue", action: "Please check your internet connection and try again." }, internal_error: { message: "Something went wrong on our end", action: "Please try again. If this continues, contact support." }, database_error: { message: "Service temporarily unavailable", action: "Please try again in a moment." }, config_error: { message: "Service configuration error", action: "Please contact support for assistance." }, unknown_error: { message: "An unexpected error occurred", action: "Please try again or contact support if this continues." } }, o = { unknown_token_mint: "Warning: Unrecognized token mint address. Double-check this is the correct token to avoid loss of funds.", token_typo_warning: "Token address does not match known stablecoins (USDC, USDT, PYUSD, CASH). Verify carefully to prevent permanent loss of funds." }, s = { no_wallet_detected: "No Solana wallet detected", install_wallet: "Please install a Solana wallet like Phantom, Solflare, or Backpack.", wallet_not_connected: "Wallet not connected", connect_your_wallet: "Please connect your wallet to continue.", wallet_connection_failed: "Failed to connect wallet", try_again: "Please try connecting again.", transaction_rejected: "Transaction was rejected", approve_in_wallet: "Please approve the transaction in your wallet to continue.", select_wallet: "Select Wallet", change: "Change Wallet" }, r = {
|
|
2
|
+
comment: e,
|
|
3
|
+
version: a,
|
|
4
|
+
locale: "en",
|
|
5
|
+
ui: n,
|
|
6
|
+
errors: t,
|
|
7
|
+
validation: o,
|
|
8
|
+
wallet: s
|
|
9
|
+
};
|
|
10
|
+
export {
|
|
11
|
+
e as comment,
|
|
12
|
+
r as default,
|
|
13
|
+
t as errors,
|
|
14
|
+
i as locale,
|
|
15
|
+
n as ui,
|
|
16
|
+
o as validation,
|
|
17
|
+
a as version,
|
|
18
|
+
s as wallet
|
|
19
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="CEDROS PAY - Translation Source File (English)",a="1.0.0",n="en",t={pay_with_card:"Pay with Card",pay_with_crypto:"Pay with USDC",pay_with_usdc:"Pay with USDC",purchase:"Purchase",card:"Card",usdc_solana:"USDC (Solana)",crypto:"Crypto",connect_wallet:"Connect Wallet",connecting:"Connecting...",processing:"Processing...",loading:"Loading...",close:"Close",cancel:"Cancel",confirm:"Confirm",retry:"Try Again",go_back:"Go Back",contact_support:"Contact Support",disconnect:"Disconnect",payment_successful:"Payment successful!",subscribe:"Subscribe",subscribe_with_crypto:"Subscribe with USDC",subscribed:"Subscribed",subscribed_until:"Subscribed until",subscription_active:"Your subscription is active!",redirecting_to_checkout:"Redirecting to checkout..."},o={invalid_payment_proof:{message:"Payment verification failed",action:"Please try your payment again. If this continues, contact support."},invalid_signature:{message:"Transaction signature is invalid",action:"Please approve the transaction in your wallet and try again."},invalid_transaction:{message:"Transaction format is invalid",action:"Please try your payment again. If this continues, try updating your wallet app."},transaction_not_found:{message:"Transaction not found on the blockchain",action:"Your transaction may still be processing. Please wait a moment and check your wallet, or try again."},transaction_not_confirmed:{message:"Transaction is still processing",action:"Please wait a moment for the blockchain to confirm your transaction, then try again."},transaction_failed:{message:"Transaction failed on the blockchain",action:"Check your wallet for details. You may need to adjust your transaction settings or add more SOL for fees."},transaction_expired:{message:"Transaction took too long to process",action:"Please try your payment again. Consider increasing transaction priority if your wallet supports it."},invalid_recipient:{message:"Payment was sent to the wrong address",action:"Please try again and ensure you approve the correct transaction in your wallet."},invalid_sender:{message:"Payment sender wallet is invalid",action:"Please reconnect your wallet and try again."},unauthorized_refund_issuer:{message:"You are not authorized to issue refunds",action:"Only authorized accounts can process refunds. Please contact support if you believe this is an error."},amount_below_minimum:{message:"Payment amount is too low",action:"Please check the required amount and try again."},amount_mismatch:{message:"Payment amount does not match the quote",action:"The price may have changed. Please refresh and try your payment again."},insufficient_funds_sol:{message:"Not enough SOL for transaction fees",action:"Add at least 0.001 SOL to your wallet to cover network fees, then try again."},insufficient_funds_token:{message:"Insufficient balance in your wallet",action:"Add more funds to your wallet and try again."},invalid_token_mint:{message:"Incorrect payment token",action:"Please pay with the correct token as shown in the payment details."},not_spl_transfer:{message:"Transaction is not a valid token transfer",action:"Please ensure you are sending the correct token type from your wallet."},missing_token_account:{message:"Token account not found",action:"Your wallet may need to create a token account first. Try again or use a different wallet."},invalid_token_program:{message:"Invalid token program",action:"Please try your payment again. If this continues, try using a different wallet."},missing_memo:{message:"Payment memo is required but was not included",action:"Please try your payment again and ensure transaction details are approved in your wallet."},invalid_memo:{message:"Payment memo format is invalid",action:"Please try your payment again."},payment_already_used:{message:"This payment has already been processed",action:"Check your transaction history. If you need to make another payment, please start a new transaction."},signature_reused:{message:"Transaction signature has already been used",action:"Please create a new payment transaction."},quote_expired:{message:"Payment quote has expired",action:"Prices are updated frequently. Please refresh and try your payment again."},missing_field:{message:"Required information is missing",action:"Please check all required fields and try again."},invalid_field:{message:"Some information is invalid",action:"Please check your input and try again."},invalid_amount:{message:"Payment amount is invalid",action:"Please check the amount and try again."},invalid_wallet:{message:"Wallet address is invalid",action:"Please reconnect your wallet and try again."},invalid_resource:{message:"Invalid item selection",action:"Please refresh the page and try again."},invalid_coupon:{message:"Invalid coupon code",action:"Please check the coupon code and try again."},invalid_cart_item:{message:"One or more cart items are invalid",action:"Please review your cart and try again."},empty_cart:{message:"Your cart is empty",action:"Please add items to your cart before checking out."},resource_not_found:{message:"Item not found",action:"This item may no longer be available. Please refresh and try again."},cart_not_found:{message:"Shopping cart not found",action:"Your cart may have expired. Please start a new order."},refund_not_found:{message:"Refund not found",action:"Please check your refund reference number or contact support."},product_not_found:{message:"Product not available",action:"This product may no longer be available. Please browse our current selection."},coupon_not_found:{message:"Coupon code not found",action:"Please check the coupon code or remove it to continue."},session_not_found:{message:"Payment session expired",action:"Please start a new payment."},cart_already_paid:{message:"This order has already been paid",action:"Check your order history. If you need to make another purchase, please start a new order."},refund_already_processed:{message:"This refund has already been processed",action:"Check your transaction history or contact support for details."},coupon_expired:{message:"Coupon has expired",action:"Please remove the coupon code or use a different code."},coupon_usage_limit_reached:{message:"Coupon usage limit reached",action:"This coupon has been fully redeemed. Please try a different code."},coupon_not_applicable:{message:"Coupon cannot be applied to this purchase",action:"Please check the coupon terms or remove it to continue."},coupon_wrong_payment_method:{message:"Coupon not valid for this payment method",action:"Try a different payment method or remove the coupon code."},stripe_error:{message:"Card payment service temporarily unavailable",action:"Please try again in a moment, or use cryptocurrency payment instead."},rpc_error:{message:"Blockchain network temporarily unavailable",action:"Please try again in a moment, or use card payment instead."},network_error:{message:"Network connection issue",action:"Please check your internet connection and try again."},internal_error:{message:"Something went wrong on our end",action:"Please try again. If this continues, contact support."},database_error:{message:"Service temporarily unavailable",action:"Please try again in a moment."},config_error:{message:"Service configuration error",action:"Please contact support for assistance."},unknown_error:{message:"An unexpected error occurred",action:"Please try again or contact support if this continues."}},i={unknown_token_mint:"Warning: Unrecognized token mint address. Double-check this is the correct token to avoid loss of funds.",token_typo_warning:"Token address does not match known stablecoins (USDC, USDT, PYUSD, CASH). Verify carefully to prevent permanent loss of funds."},r={no_wallet_detected:"No Solana wallet detected",install_wallet:"Please install a Solana wallet like Phantom, Solflare, or Backpack.",wallet_not_connected:"Wallet not connected",connect_your_wallet:"Please connect your wallet to continue.",wallet_connection_failed:"Failed to connect wallet",try_again:"Please try connecting again.",transaction_rejected:"Transaction was rejected",approve_in_wallet:"Please approve the transaction in your wallet to continue.",select_wallet:"Select Wallet",change:"Change Wallet"},s={comment:e,version:a,locale:n,ui:t,errors:o,validation:i,wallet:r};exports.comment=e;exports.default=s;exports.errors=o;exports.locale=n;exports.ui=t;exports.validation=i;exports.version=a;exports.wallet=r;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SubscriptionStatusResponse, SubscriptionQuote, BillingInterval, PaymentResult } from '../types';
|
|
2
|
+
import { SubscriptionQuoteOptions } from '../managers/SubscriptionManager';
|
|
3
|
+
/**
|
|
4
|
+
* Hook for x402 crypto subscription payments
|
|
5
|
+
*
|
|
6
|
+
* Handles:
|
|
7
|
+
* - Checking subscription status
|
|
8
|
+
* - Requesting subscription quotes
|
|
9
|
+
* - Processing crypto subscription payments
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* function CryptoSubscribePage() {
|
|
14
|
+
* const { checkStatus, processPayment, status, subscriptionStatus, expiresAt } = useCryptoSubscription();
|
|
15
|
+
*
|
|
16
|
+
* // Check subscription on mount
|
|
17
|
+
* useEffect(() => {
|
|
18
|
+
* if (publicKey) {
|
|
19
|
+
* checkStatus({ resource: 'plan-pro', userId: publicKey.toString() });
|
|
20
|
+
* }
|
|
21
|
+
* }, [publicKey]);
|
|
22
|
+
*
|
|
23
|
+
* // Process subscription payment
|
|
24
|
+
* const handleSubscribe = async () => {
|
|
25
|
+
* await processPayment('plan-pro', 'monthly');
|
|
26
|
+
* };
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function useCryptoSubscription(): {
|
|
31
|
+
quote: SubscriptionQuote | null;
|
|
32
|
+
checkStatus: (resource: string) => Promise<SubscriptionStatusResponse | null>;
|
|
33
|
+
requestQuote: (resource: string, interval: BillingInterval, options?: SubscriptionQuoteOptions) => Promise<SubscriptionQuote | null>;
|
|
34
|
+
processPayment: (resource: string, interval: BillingInterval, options?: SubscriptionQuoteOptions) => Promise<PaymentResult>;
|
|
35
|
+
reset: () => void;
|
|
36
|
+
status: "idle" | "loading" | "checking" | "success" | "error";
|
|
37
|
+
error: string | null;
|
|
38
|
+
sessionId: string | null;
|
|
39
|
+
subscriptionStatus: import('..').SubscriptionStatus | null;
|
|
40
|
+
expiresAt: string | null;
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=useCryptoSubscription.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCryptoSubscription.d.ts","sourceRoot":"","sources":["../../src/hooks/useCryptoSubscription.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,0BAA0B,EAC1B,iBAAiB,EACjB,eAAe,EACf,aAAa,EACd,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAGhF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,qBAAqB;;4BAqChB,MAAM,KAAG,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC;6BAgDxD,MAAM,YACN,eAAe,YACf,wBAAwB,KACjC,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;+BAuCxB,MAAM,YACN,eAAe,YACf,wBAAwB,KACjC,OAAO,CAAC,aAAa,CAAC;;;;;;;EAmJ5B"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SubscriptionSessionRequest, SubscriptionStatusRequest, SubscriptionStatusResponse, SubscriptionQuote, BillingInterval, PaymentResult } from '../types';
|
|
2
|
+
import { SubscriptionQuoteOptions } from '../managers/SubscriptionManager';
|
|
3
|
+
/**
|
|
4
|
+
* Hook for subscription management
|
|
5
|
+
*
|
|
6
|
+
* Handles:
|
|
7
|
+
* - Creating Stripe subscription sessions and redirecting to checkout
|
|
8
|
+
* - Checking subscription status (for x402 gating)
|
|
9
|
+
* - Requesting subscription quotes (for x402 crypto payments)
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* function SubscribePage() {
|
|
14
|
+
* const { processSubscription, checkStatus, status, error } = useSubscription();
|
|
15
|
+
*
|
|
16
|
+
* const handleSubscribe = async () => {
|
|
17
|
+
* await processSubscription({
|
|
18
|
+
* resource: 'plan-pro',
|
|
19
|
+
* interval: 'monthly',
|
|
20
|
+
* });
|
|
21
|
+
* };
|
|
22
|
+
*
|
|
23
|
+
* return (
|
|
24
|
+
* <button onClick={handleSubscribe} disabled={status === 'loading'}>
|
|
25
|
+
* {status === 'loading' ? 'Processing...' : 'Subscribe'}
|
|
26
|
+
* </button>
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function useSubscription(): {
|
|
32
|
+
processSubscription: (request: SubscriptionSessionRequest) => Promise<PaymentResult>;
|
|
33
|
+
checkStatus: (request: SubscriptionStatusRequest) => Promise<SubscriptionStatusResponse>;
|
|
34
|
+
requestQuote: (resource: string, interval: BillingInterval, options?: SubscriptionQuoteOptions) => Promise<SubscriptionQuote>;
|
|
35
|
+
reset: () => void;
|
|
36
|
+
status: "idle" | "loading" | "checking" | "success" | "error";
|
|
37
|
+
error: string | null;
|
|
38
|
+
sessionId: string | null;
|
|
39
|
+
subscriptionStatus: import('..').SubscriptionStatus | null;
|
|
40
|
+
expiresAt: string | null;
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=useSubscription.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSubscription.d.ts","sourceRoot":"","sources":["../../src/hooks/useSubscription.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,0BAA0B,EAC1B,yBAAyB,EACzB,0BAA0B,EAC1B,iBAAiB,EACjB,eAAe,EACf,aAAa,EACd,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,eAAe;mCAcX,0BAA0B,KAAG,OAAO,CAAC,aAAa,CAAC;2BAyBnD,yBAAyB,KAAG,OAAO,CAAC,0BAA0B,CAAC;6BAuCnE,MAAM,YACN,eAAe,YACf,wBAAwB,KACjC,OAAO,CAAC,iBAAiB,CAAC;;;;;;;EAwDhC"}
|