@three-ws/x402-payment-modal 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/x402.min.js CHANGED
@@ -1,117 +1,210 @@
1
- /*! @three-ws/x402-payment-modal v1.1.0 — Apache-2.0 — https://three.ws */
2
- const te="1.1.0",h={checkoutOrigin:null,checkoutPath:"/api/x402-checkout",brand:{name:"three.ws",url:"https://three.ws"},footerNote:"x402 \xB7 onchain settled",builderCode:{wallet:"3d_agent",service:"3d_agent_modal"},esm:{solanaWeb3:"https://esm.sh/@solana/web3.js@1.95.3?bundle",nobleHashesSha3:"https://esm.sh/@noble/hashes@1.4.0/sha3?bundle"}};function j(n={}){if(!n||typeof n!="object")return h;for(const e of["checkoutOrigin","checkoutPath","footerNote"])n[e]!==void 0&&(h[e]=n[e]);return n.brand&&typeof n.brand=="object"&&Object.assign(h.brand,n.brand),n.builderCode&&typeof n.builderCode=="object"&&Object.assign(h.builderCode,n.builderCode),n.esm&&typeof n.esm=="object"&&Object.assign(h.esm,n.esm),h}function L(){return`${h.checkoutOrigin||oe}${h.checkoutPath}`}const ne="SIGN-IN-WITH-X",re="sign-in-with-x",oe=(()=>{try{const n=document.currentScript;if(n?.src)return new URL(n.src).origin;const e=document.querySelector('script[src*="/x402.js"]');if(e?.src)return new URL(e.src).origin}catch{}return location.origin})(),C={"eip155:8453":{chainId:8453,name:"Base",explorer:"https://basescan.org/tx/"},"eip155:84532":{chainId:84532,name:"Base Sepolia",explorer:"https://sepolia.basescan.org/tx/"},"eip155:42161":{chainId:42161,name:"Arbitrum",explorer:"https://arbiscan.io/tx/"},"eip155:10":{chainId:10,name:"Optimism",explorer:"https://optimistic.etherscan.io/tx/"}};function Be(n){if(!n||typeof n!="object")return n;const e=n.amount??n.maxAmountRequired;return e!=null&&n.amount==null?{...n,amount:String(e)}:n}const T="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",P="FeMbDoX7R1Psc4GEcvJdsbNbZA3bfztcyDCatJVJpump",B=Object.freeze({[T]:{symbol:"USDC",name:"USD Coin",decimals:6,stable:!0},[P]:{symbol:"THREE",name:"THREE",decimals:6,accent:"#7aa2ff",glyph:"\u25C6"}});function y(n){const e=n&&n.asset&&B[n.asset]||null,t=n?.extra?.name,r=(t?String(t).replace(/^USD Coin$/,"USDC"):e?.symbol)||"USDC",o=Number(n?.extra?.decimals??e?.decimals??6),s=e?.stable||U.has(String(t||"").toLowerCase());return{symbol:r,decimals:o,stable:s,accent:e?.accent||null,glyph:e?.glyph||null}}function Ne(n){return n?.asset===P}function q(n){return(n?.accepts||[]).filter(e=>N(e.network))}function R(n){return n.find(e=>e.asset===T)||n.find(e=>y(e).stable)||n[0]||null}function N(n){return typeof n=="string"&&(n==="solana"||n.startsWith("solana:"))}function se(n){return typeof n=="string"&&n.startsWith("eip155:")}function D(n){if(!se(n?.network))return!1;const e=n?.extra?.assetTransferMethod;return!e||e==="eip3009"}function b(n,e){return N(n)?"Solana":C[n]?.name||e?.extra?.name||n}function ae(n,e){if(!e)return null;if(N(n))return`https://solscan.io/tx/${e}`;const t=C[n];return t?`${t.explorer}${e}`:null}function v(n,e=6){const t=Number(n)/10**e;return t<.01?t.toFixed(6).replace(/0+$/,"").replace(/\.$/,""):t<1?t.toFixed(4).replace(/0+$/,"").replace(/\.$/,""):t.toFixed(2)}function ie(n){const e=JSON.stringify(n);return typeof Buffer<"u"?Buffer.from(e,"utf8").toString("base64"):btoa(unescape(encodeURIComponent(e)))}function I(n){if(!n)return null;try{const e=typeof Buffer<"u"?Buffer.from(n,"base64").toString("utf8"):decodeURIComponent(escape(atob(n)));return JSON.parse(e)}catch{return null}}const ce="x402.spend.",U=new Set(["usdc","usd coin","usdt","tether","binance-peg usd coin","dai"]);function de(n=Date.now()){const e=Math.floor(n/36e5),t=Math.floor(n/864e5);return{hour:e,day:t}}function H(n,e,t){return`${ce}${e}.${n.toLowerCase()}.${t}`}function k(n,e,t){try{const r=localStorage.getItem(H(n,e,t));return r?BigInt(r):0n}catch{return 0n}}function S(n,e,t,r){try{localStorage.setItem(H(n,e,t),r.toString())}catch{}}function le(n,e){const t=BigInt(n),r=e&&e.asset&&B[e.asset]||null,o=Number(e?.extra?.decimals??r?.decimals??6),s=String(e?.extra?.name||"").toLowerCase();return U.has(s)||r?.stable?o===6?t:o>6?t/10n**BigInt(o-6):t*10n**BigInt(6-o):t}function F({accept:n,caps:e,address:t}){if(!e||!t)return{abort:!1};const r=le(n.amount,n),o=e.maxPerCall!=null?BigInt(e.maxPerCall):null,s=e.maxPerHour!=null?BigInt(e.maxPerHour):null,i=e.maxPerDay!=null?BigInt(e.maxPerDay):null;if(o!=null&&r>o)return{abort:!0,reason:`Per-call cap exceeded (${r} > ${o} \xB5USD)`};const a=de(),l=k(t,"hr",a.hour)+r,d=k(t,"day",a.day)+r;return s!=null&&l>s?{abort:!0,reason:`Hourly cap exceeded (${l} > ${s} \xB5USD)`}:i!=null&&d>i?{abort:!0,reason:`Daily cap exceeded (${d} > ${i} \xB5USD)`}:(S(t,"hr",a.hour,l),S(t,"day",a.day,d),{abort:!1,reservation:{address:t,microUsd:r,buckets:a}})}function z(n){if(!n)return;const{address:e,microUsd:t,buckets:r}=n,o=k(e,"hr",r.hour),s=k(e,"day",r.day),i=o-t,a=s-t;S(e,"hr",r.hour,i<0n?0n:i),S(e,"day",r.day,a<0n?0n:a)}const ue="builder-code",_=/^[a-z0-9_]{1,32}$/;function W(n){const t=n?.extensions?.[ue]?.info?.a;if(!t||!_.test(t))return null;const r={a:t},o=h.builderCode.service,s=h.builderCode.wallet;return o&&_.test(o)&&(r.s=[o]),s&&_.test(s)&&(r.w=s),r}function fe(n){const e=n?.extensions?.[re];return!e||!e.info||!Array.isArray(e.supportedChains)||!e.supportedChains.length?null:e}function J(n,e){for(const t of n.supportedChains){if(e==="evm"&&t.type==="eip191")return{chain:t,kind:"evm"};if(e==="solana"&&t.type==="ed25519")return{chain:t,kind:"solana"}}return null}function V(n,e,t){const r=e.type==="eip191",o=r?`${n.domain} wants you to sign in with your Ethereum account:`:`${n.domain} wants you to sign in with your Solana account:`,[,s=""]=String(e.chainId).split(":"),i=r?String(parseInt(s,10)):s,a=[o,t,""];if(n.statement?a.push(n.statement,""):r&&a.push(""),a.push(`URI: ${n.uri}`),a.push(`Version: ${n.version||"1"}`),a.push(`Chain ID: ${i}`),a.push(`Nonce: ${n.nonce}`),a.push(`Issued At: ${n.issuedAt}`),n.expirationTime&&a.push(`Expiration Time: ${n.expirationTime}`),n.notBefore&&a.push(`Not Before: ${n.notBefore}`),n.requestId!==void 0&&n.requestId!==null&&a.push(`Request ID: ${n.requestId}`),Array.isArray(n.resources)&&n.resources.length){a.push("Resources:");for(const l of n.resources)a.push(`- ${l}`)}return a.join(`
3
- `)}function pe(n){const e=JSON.stringify(n);return typeof Buffer<"u"?Buffer.from(e,"utf8").toString("base64"):btoa(unescape(encodeURIComponent(e)))}const K="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";function he(n){if(!n||n.length===0)return"";let e=0;for(;e<n.length&&n[e]===0;)e++;let t=0n;for(let o=0;o<n.length;o++)t=t<<8n|BigInt(n[o]);let r="";for(;t>0n;)r=K[Number(t%58n)]+r,t/=58n;for(let o=0;o<e;o++)r=K[0]+r;return r}let E=null;async function xe(){if(E)return E;const e=(await import(h.esm.nobleHashesSha3)).keccak_256;return E=t=>{const r=String(t).toLowerCase().replace(/^0x/,"");if(!/^[0-9a-f]{40}$/.test(r))throw new Error(`invalid EVM address: ${t}`);const o=e(new TextEncoder().encode(r));let s="";for(let a=0;a<o.length;a++)s+=o[a].toString(16).padStart(2,"0");let i="0x";for(let a=0;a<40;a++)i+=parseInt(s[a],16)>=8?r[a].toUpperCase():r[a];return i},E}const G="x402-styles",me=`
4
- :root {
1
+ /*! @three-ws/x402-payment-modal v1.2.0 — UNLICENSED — https://github.com/nirholas/x402-payment-modal#readme */
2
+ const de="1.2.0",p={checkoutOrigin:null,checkoutPath:"/api/x402-checkout",brand:{name:null,url:null},footerNote:"x402 \xB7 onchain settled",builderCode:{wallet:"",service:""},theme:"auto",cssVars:null,esm:{solanaWeb3:"https://esm.sh/@solana/web3.js@1.95.3?bundle",nobleHashesSha3:"https://esm.sh/@noble/hashes@1.4.0/sha3?bundle"}},H={solanaWeb3:["https://cdn.jsdelivr.net/npm/@solana/web3.js@1.95.3/+esm","https://cdn.skypack.dev/@solana/web3.js@1.95.3"],nobleHashesSha3:["https://cdn.jsdelivr.net/npm/@noble/hashes@1.4.0/sha3/+esm","https://cdn.skypack.dev/@noble/hashes@1.4.0/sha3"]},ue=12e3;function W(n={}){if(!n||typeof n!="object")return p;for(const e of["checkoutOrigin","checkoutPath","footerNote","theme"])n[e]!==void 0&&(p[e]=n[e]);return n.brand&&typeof n.brand=="object"&&Object.assign(p.brand,n.brand),n.builderCode&&typeof n.builderCode=="object"&&Object.assign(p.builderCode,n.builderCode),n.esm&&typeof n.esm=="object"&&Object.assign(p.esm,n.esm),n.cssVars&&typeof n.cssVars=="object"&&(p.cssVars={...p.cssVars||{},...n.cssVars}),p}function U(){return`${p.checkoutOrigin||he}${p.checkoutPath}`}const xe="SIGN-IN-WITH-X",pe="sign-in-with-x",he=(()=>{try{const n=document.currentScript;if(n?.src)return new URL(n.src).origin;const e=document.querySelector('script[src*="/x402.js"]');if(e?.src)return new URL(e.src).origin}catch{}return location.origin})(),z={"eip155:8453":{chainId:8453,name:"Base",explorer:"https://basescan.org/tx/"},"eip155:84532":{chainId:84532,name:"Base Sepolia",explorer:"https://sepolia.basescan.org/tx/"},"eip155:42161":{chainId:42161,name:"Arbitrum",explorer:"https://arbiscan.io/tx/"},"eip155:10":{chainId:10,name:"Optimism",explorer:"https://optimistic.etherscan.io/tx/"}};function Re(n){if(!n||typeof n!="object")return n;const e=n.amount??n.maxAmountRequired;return e!=null&&n.amount==null?{...n,amount:String(e)}:n}const M="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",j="FeMbDoX7R1Psc4GEcvJdsbNbZA3bfztcyDCatJVJpump",L=Object.freeze({[M]:{symbol:"USDC",name:"USD Coin",decimals:6,stable:!0},[j]:{symbol:"THREE",name:"THREE",decimals:6,accent:"#7aa2ff",glyph:"\u25C6"}});function k(n){const e=n&&n.asset&&L[n.asset]||null,t=n?.extra?.name,r=(t?String(t).replace(/^USD Coin$/,"USDC"):e?.symbol)||"USDC",o=Number(n?.extra?.decimals??e?.decimals??6),s=e?.stable||J.has(String(t||"").toLowerCase());return{symbol:r,decimals:o,stable:s,accent:e?.accent||null,glyph:e?.glyph||null}}function He(n){return n?.asset===j}function F(n){return(n?.accepts||[]).filter(e=>O(e.network))}function V(n){return n.find(e=>e.asset===M)||n.find(e=>k(e).stable)||n[0]||null}function O(n){return typeof n=="string"&&(n==="solana"||n.startsWith("solana:"))}function fe(n){return typeof n=="string"&&n.startsWith("eip155:")}function K(n){if(!fe(n?.network))return!1;const e=n?.extra?.assetTransferMethod;return!e||e==="eip3009"}function v(n,e){return O(n)?"Solana":z[n]?.name||e?.extra?.name||n}function me(n,e){if(!e)return null;if(O(n))return`https://solscan.io/tx/${e}`;const t=z[n];return t?`${t.explorer}${e}`:null}function C(n,e=6){const t=Number(n)/10**e;return t<.01?t.toFixed(6).replace(/0+$/,"").replace(/\.$/,""):t<1?t.toFixed(4).replace(/0+$/,"").replace(/\.$/,""):t.toFixed(2)}function be(n){const e=JSON.stringify(n);return typeof Buffer<"u"?Buffer.from(e,"utf8").toString("base64"):btoa(unescape(encodeURIComponent(e)))}function q(n){if(!n)return null;try{const e=typeof Buffer<"u"?Buffer.from(n,"base64").toString("utf8"):decodeURIComponent(escape(atob(n)));return JSON.parse(e)}catch{return null}}const we="x402.spend.",J=new Set(["usdc","usd coin","usdt","tether","binance-peg usd coin","dai"]);function ye(n=Date.now()){const e=Math.floor(n/36e5),t=Math.floor(n/864e5);return{hour:e,day:t}}function Y(n,e,t){return`${we}${e}.${n.toLowerCase()}.${t}`}function P(n,e,t){try{const r=localStorage.getItem(Y(n,e,t));return r?BigInt(r):0n}catch{return 0n}}function B(n,e,t,r){try{localStorage.setItem(Y(n,e,t),r.toString())}catch{}}function ge(n,e){const t=BigInt(n),r=e&&e.asset&&L[e.asset]||null,o=Number(e?.extra?.decimals??r?.decimals??6),s=String(e?.extra?.name||"").toLowerCase();return J.has(s)||r?.stable?o===6?t:o>6?t/10n**BigInt(o-6):t*10n**BigInt(6-o):t}function G({accept:n,caps:e,address:t}){if(!e||!t)return{abort:!1};const r=ge(n.amount,n),o=e.maxPerCall!=null?BigInt(e.maxPerCall):null,s=e.maxPerHour!=null?BigInt(e.maxPerHour):null,a=e.maxPerDay!=null?BigInt(e.maxPerDay):null;if(o!=null&&r>o)return{abort:!0,reason:`Per-call cap exceeded (${r} > ${o} \xB5USD)`};const i=ye(),l=P(t,"hr",i.hour)+r,c=P(t,"day",i.day)+r;return s!=null&&l>s?{abort:!0,reason:`Hourly cap exceeded (${l} > ${s} \xB5USD)`}:a!=null&&c>a?{abort:!0,reason:`Daily cap exceeded (${c} > ${a} \xB5USD)`}:(B(t,"hr",i.hour,l),B(t,"day",i.day,c),{abort:!1,reservation:{address:t,microUsd:r,buckets:i}})}function D(n){if(!n)return;const{address:e,microUsd:t,buckets:r}=n,o=P(e,"hr",r.hour),s=P(e,"day",r.day),a=o-t,i=s-t;B(e,"hr",r.hour,a<0n?0n:a),B(e,"day",r.day,i<0n?0n:i)}const ve="builder-code",R=/^[a-z0-9_]{1,32}$/;function X(n){const t=n?.extensions?.[ve]?.info?.a;if(!t||!R.test(t))return null;const r={a:t},o=p.builderCode.service,s=p.builderCode.wallet;return o&&R.test(o)&&(r.s=[o]),s&&R.test(s)&&(r.w=s),r}function ke(n){const e=n?.extensions?.[pe];return!e||!e.info||!Array.isArray(e.supportedChains)||!e.supportedChains.length?null:e}function Z(n,e){for(const t of n.supportedChains){if(e==="evm"&&t.type==="eip191")return{chain:t,kind:"evm"};if(e==="solana"&&t.type==="ed25519")return{chain:t,kind:"solana"}}return null}function Q(n,e,t){const r=e.type==="eip191",o=r?`${n.domain} wants you to sign in with your Ethereum account:`:`${n.domain} wants you to sign in with your Solana account:`,[,s=""]=String(e.chainId).split(":"),a=r?String(parseInt(s,10)):s,i=[o,t,""];if(n.statement?i.push(n.statement,""):r&&i.push(""),i.push(`URI: ${n.uri}`),i.push(`Version: ${n.version||"1"}`),i.push(`Chain ID: ${a}`),i.push(`Nonce: ${n.nonce}`),i.push(`Issued At: ${n.issuedAt}`),n.expirationTime&&i.push(`Expiration Time: ${n.expirationTime}`),n.notBefore&&i.push(`Not Before: ${n.notBefore}`),n.requestId!==void 0&&n.requestId!==null&&i.push(`Request ID: ${n.requestId}`),Array.isArray(n.resources)&&n.resources.length){i.push("Resources:");for(const l of n.resources)i.push(`- ${l}`)}return i.join(`
3
+ `)}function Se(n){const e=JSON.stringify(n);return typeof Buffer<"u"?Buffer.from(e,"utf8").toString("base64"):btoa(unescape(encodeURIComponent(e)))}const ee="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";function Ee(n){if(!n||n.length===0)return"";let e=0;for(;e<n.length&&n[e]===0;)e++;let t=0n;for(let o=0;o<n.length;o++)t=t<<8n|BigInt(n[o]);let r="";for(;t>0n;)r=ee[Number(t%58n)]+r,t/=58n;for(let o=0;o<e;o++)r=ee[0]+r;return r}let N=null;async function $e(){if(N)return N;const e=(await ae(p.esm.nobleHashesSha3,H.nobleHashesSha3,"@noble/hashes/sha3")).keccak_256;return N=t=>{const r=String(t).toLowerCase().replace(/^0x/,"");if(!/^[0-9a-f]{40}$/.test(r))throw new Error(`invalid EVM address: ${t}`);const o=e(new TextEncoder().encode(r));let s="";for(let i=0;i<o.length;i++)s+=o[i].toString(16).padStart(2,"0");let a="0x";for(let i=0;i<40;i++)a+=parseInt(s[i],16)>=8?r[i].toUpperCase():r[i];return a},N}const te="x402-styles",Ae=`
5
4
  --x402-z: 2147483600;
5
+ --x402-font: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
6
+ --x402-mono: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, monospace;
7
+ --x402-scrim: rgba(8, 10, 18, 0.55);
8
+ --x402-surface: #ffffff;
9
+ --x402-surface-2: #f7f8fa;
10
+ --x402-fg: #0f1116;
11
+ --x402-muted: #646b7a;
12
+ --x402-faint: #9aa1ad;
13
+ --x402-border: #ecedf1;
14
+ --x402-border-strong: #d8dce4;
15
+ --x402-accent: #635bff;
16
+ --x402-accent-hover: #524bdb;
17
+ --x402-accent-weak: #f2f1ff;
18
+ --x402-accent-fg: #ffffff;
19
+ --x402-success: #16a34a;
20
+ --x402-success-fg: #15803d;
21
+ --x402-success-bg: #f0fdf4;
22
+ --x402-success-border: #bbf7d0;
23
+ --x402-error: #dc2626;
24
+ --x402-error-fg: #b91c1c;
25
+ --x402-error-bg: #fef2f2;
26
+ --x402-error-border: #fecaca;
27
+ --x402-warn-fg: #b45309;
28
+ --x402-warn-bg: #fffbeb;
29
+ --x402-warn-border: #fde68a;
30
+ --x402-link: #524bdb;
31
+ --x402-radius: 18px;
32
+ --x402-radius-md: 12px;
33
+ --x402-radius-sm: 9px;
34
+ --x402-shadow: 0 24px 80px rgba(8, 10, 18, 0.28), 0 4px 16px rgba(8, 10, 18, 0.12);
35
+ --x402-btn-bg: #0f1116;
36
+ --x402-btn-fg: #ffffff;
37
+ --x402-btn-hover: #242833;
38
+ --x402-btn-shadow: 0 1px 2px rgba(8, 10, 18, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.12);
39
+ `,ne=`
40
+ --x402-scrim: rgba(0, 0, 0, 0.62);
41
+ --x402-surface: #161616;
42
+ --x402-surface-2: #1d1d1d;
43
+ --x402-fg: #e6e8f0;
44
+ --x402-muted: #9aa1b4;
45
+ --x402-faint: #6b7088;
46
+ --x402-border: #2a2a2a;
47
+ --x402-border-strong: #3a3a40;
48
+ --x402-accent: #8b85ff;
49
+ --x402-accent-hover: #a29cff;
50
+ --x402-accent-weak: #1e1b3a;
51
+ --x402-accent-fg: #ffffff;
52
+ --x402-success: #22c55e;
53
+ --x402-success-fg: #4ade80;
54
+ --x402-success-bg: #0b1f17;
55
+ --x402-success-border: #14532d;
56
+ --x402-error: #ef4444;
57
+ --x402-error-fg: #fca5a5;
58
+ --x402-error-bg: #1f1416;
59
+ --x402-error-border: #7f1d1d;
60
+ --x402-warn-fg: #fcd34d;
61
+ --x402-warn-bg: #2a1d10;
62
+ --x402-warn-border: #78350f;
63
+ --x402-link: #a29cff;
64
+ --x402-shadow: 0 24px 80px rgba(0, 0, 0, 0.6);
65
+ --x402-btn-bg: #ffffff;
66
+ --x402-btn-fg: #0f1116;
67
+ --x402-btn-hover: #e7e9ee;
68
+ --x402-btn-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.5);
69
+ `,Ce=`
70
+ .x402-overlay { ${Ae} }
71
+ .x402-overlay.x402-theme-dark { ${ne} }
72
+ @media (prefers-color-scheme: dark) {
73
+ .x402-overlay:not(.x402-theme-light) { ${ne} }
6
74
  }
7
75
  .x402-overlay {
8
76
  position: fixed; inset: 0;
9
- background: rgba(8, 10, 18, 0.55);
77
+ background: var(--x402-scrim);
10
78
  backdrop-filter: blur(10px);
11
79
  -webkit-backdrop-filter: blur(10px);
12
80
  display: flex; align-items: center; justify-content: center;
13
81
  z-index: var(--x402-z);
14
82
  opacity: 0; transition: opacity 0.16s ease-out;
15
- font-family: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
83
+ font-family: var(--x402-font);
16
84
  -webkit-font-smoothing: antialiased;
17
- color: #0f0f0f;
85
+ color: var(--x402-fg);
18
86
  }
19
87
  .x402-overlay.x402-open { opacity: 1; }
20
88
  .x402-overlay * { box-sizing: border-box; }
89
+ .x402-overlay :focus-visible {
90
+ outline: 2px solid var(--x402-accent);
91
+ outline-offset: 2px;
92
+ }
21
93
  .x402-modal {
22
94
  width: calc(100% - 32px); max-width: 420px;
23
- background: #ffffff;
24
- border-radius: 18px;
25
- box-shadow: 0 24px 80px rgba(8, 10, 18, 0.28), 0 4px 16px rgba(8, 10, 18, 0.12);
95
+ background: var(--x402-surface);
96
+ border-radius: var(--x402-radius);
97
+ box-shadow: var(--x402-shadow);
26
98
  overflow: hidden;
27
99
  transform: translateY(8px) scale(0.985);
28
- transition: transform 0.18s ease-out;
100
+ transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
29
101
  display: flex; flex-direction: column;
30
102
  max-height: calc(100dvh - 32px);
31
103
  }
32
104
  .x402-overlay.x402-open .x402-modal { transform: translateY(0) scale(1); }
33
105
  .x402-head {
34
106
  padding: 18px 20px 14px;
35
- border-bottom: 1px solid #eef0f4;
107
+ border-bottom: 1px solid var(--x402-border);
36
108
  display: flex; align-items: center; gap: 12px;
37
109
  }
38
- .x402-head .x402-merchant {
39
- flex: 1; min-width: 0;
40
- }
110
+ .x402-head .x402-merchant { flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; }
111
+ .x402-head .x402-merchant-text { min-width: 0; }
112
+ .x402-brand-logo { width: 30px; height: 30px; flex: 0 0 auto; border-radius: 8px; object-fit: cover; }
41
113
  .x402-merchant .x402-name {
42
- font-size: 12px; color: #5a6378; font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase;
114
+ font-size: 12px; color: var(--x402-muted); font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase;
43
115
  margin-bottom: 2px;
44
116
  }
45
117
  .x402-merchant .x402-action {
46
- font-size: 17px; font-weight: 700; color: #0f0f0f;
118
+ font-size: 17px; font-weight: 700; color: var(--x402-fg);
47
119
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
48
120
  letter-spacing: -0.01em;
49
121
  }
50
122
  .x402-close {
51
- width: 32px; height: 32px;
52
- border-radius: 8px; border: none; background: #f3f4f7;
53
- font-size: 16px; color: #5a6378; cursor: pointer;
123
+ width: 32px; height: 32px; flex: 0 0 auto;
124
+ border-radius: 8px; border: none; background: var(--x402-surface-2);
125
+ color: var(--x402-muted); cursor: pointer;
54
126
  display: flex; align-items: center; justify-content: center;
55
- transition: background 0.12s;
127
+ transition: background 0.12s, color 0.12s;
56
128
  }
57
- .x402-close:hover { background: #e7e9ee; color: #0f0f0f; }
129
+ .x402-close:hover { background: var(--x402-border-strong); color: var(--x402-fg); }
130
+ .x402-close svg { width: 14px; height: 14px; }
58
131
 
59
132
  .x402-price-row {
60
133
  padding: 18px 20px;
61
- display: flex; align-items: baseline; justify-content: space-between;
62
- background: linear-gradient(180deg, #fafbfc 0%, #ffffff 100%);
63
- border-bottom: 1px solid #eef0f4;
134
+ display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
135
+ background: var(--x402-surface-2);
136
+ border-bottom: 1px solid var(--x402-border);
64
137
  }
138
+ .x402-price-main { min-width: 0; }
65
139
  .x402-price {
66
- font-size: 32px; font-weight: 700; letter-spacing: -0.02em; color: #0f0f0f;
140
+ font-size: 32px; font-weight: 700; letter-spacing: -0.02em; color: var(--x402-fg);
67
141
  font-variant-numeric: tabular-nums;
68
142
  }
69
- .x402-price .x402-currency { font-size: 14px; color: #5a6378; font-weight: 600; margin-left: 6px; letter-spacing: 0; }
143
+ .x402-price .x402-currency { font-size: 14px; color: var(--x402-muted); font-weight: 600; margin-left: 6px; letter-spacing: 0; }
144
+ .x402-price-sub { font-size: 11px; color: var(--x402-muted); margin-top: 3px; font-weight: 500; }
70
145
  .x402-network {
71
- font-size: 12px; color: #5a6378; font-weight: 500;
72
- background: #f3f4f7; padding: 5px 10px; border-radius: 99px;
146
+ font-size: 12px; color: var(--x402-muted); font-weight: 500; flex: 0 0 auto;
147
+ background: var(--x402-surface); border: 1px solid var(--x402-border);
148
+ padding: 5px 10px; border-radius: 99px;
73
149
  display: inline-flex; align-items: center; gap: 6px;
74
150
  }
75
151
  .x402-network::before {
76
152
  content: ''; width: 6px; height: 6px; border-radius: 50%;
77
- background: #22c55e;
153
+ background: var(--x402-success);
154
+ box-shadow: 0 0 0 0 var(--x402-success);
155
+ animation: x402-pulse 2s ease-out infinite;
156
+ }
157
+ @keyframes x402-pulse {
158
+ 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--x402-success) 55%, transparent); }
159
+ 70% { box-shadow: 0 0 0 5px transparent; }
160
+ 100% { box-shadow: 0 0 0 0 transparent; }
78
161
  }
79
162
 
80
163
  .x402-body {
81
- padding: 16px 20px 18px;
164
+ padding: 16px 20px max(18px, env(safe-area-inset-bottom));
82
165
  flex: 1 1 auto; overflow-y: auto;
83
166
  display: flex; flex-direction: column; gap: 10px;
84
167
  }
168
+ .x402-body > * { animation: x402-fade 0.16s ease-out both; }
169
+ @keyframes x402-fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
85
170
  .x402-step {
86
171
  display: flex; gap: 12px; align-items: flex-start;
87
172
  padding: 10px 0;
88
173
  }
89
- .x402-step + .x402-step { border-top: 1px solid #f3f4f7; }
174
+ .x402-step + .x402-step { border-top: 1px solid var(--x402-border); }
90
175
  .x402-step-num {
91
176
  width: 22px; height: 22px; flex: 0 0 auto;
92
- border-radius: 50%; border: 1.5px solid #d0d4dd; background: #fff;
93
- color: #5a6378;
177
+ border-radius: 50%; border: 1.5px solid var(--x402-border-strong); background: var(--x402-surface);
178
+ color: var(--x402-muted);
94
179
  font-size: 11px; font-weight: 700;
95
180
  display: flex; align-items: center; justify-content: center;
96
181
  }
97
182
  .x402-step.x402-active .x402-step-num {
98
- border-color: #0a84ff; background: #0a84ff; color: #fff;
183
+ border-color: var(--x402-accent); background: var(--x402-accent); color: var(--x402-accent-fg);
99
184
  animation: x402-spin 1.2s linear infinite;
100
185
  }
101
186
  .x402-step.x402-done .x402-step-num {
102
- border-color: #22c55e; background: #22c55e; color: #fff;
187
+ border-color: var(--x402-success); background: var(--x402-success); color: #fff;
103
188
  }
104
189
  .x402-step.x402-error .x402-step-num {
105
- border-color: #ef4444; background: #ef4444; color: #fff;
190
+ border-color: var(--x402-error); background: var(--x402-error); color: #fff;
106
191
  }
107
192
  @keyframes x402-spin {
108
- from { box-shadow: 0 0 0 0 rgba(10, 132, 255, 0.4); }
109
- to { box-shadow: 0 0 0 8px rgba(10, 132, 255, 0); }
193
+ from { box-shadow: 0 0 0 0 color-mix(in srgb, var(--x402-accent) 40%, transparent); }
194
+ to { box-shadow: 0 0 0 8px transparent; }
110
195
  }
111
196
  .x402-step-body { flex: 1; min-width: 0; }
112
- .x402-step-label { font-size: 14px; font-weight: 600; color: #0f0f0f; line-height: 1.35; }
113
- .x402-step-meta { font-size: 12px; color: #5a6378; margin-top: 2px; font-feature-settings: 'tnum' 1; }
114
- .x402-step.x402-error .x402-step-meta { color: #ef4444; }
197
+ .x402-step-label { font-size: 14px; font-weight: 600; color: var(--x402-fg); line-height: 1.35; }
198
+ .x402-step-meta { font-size: 12px; color: var(--x402-muted); margin-top: 2px; font-feature-settings: 'tnum' 1; }
199
+ .x402-step.x402-error .x402-step-meta { color: var(--x402-error-fg); }
200
+
201
+ .x402-skeleton {
202
+ border-radius: 6px;
203
+ background: linear-gradient(100deg, var(--x402-surface-2) 30%, var(--x402-border) 50%, var(--x402-surface-2) 70%);
204
+ background-size: 200% 100%;
205
+ animation: x402-shimmer 1.3s ease-in-out infinite;
206
+ }
207
+ @keyframes x402-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
115
208
 
116
209
  .x402-wallet-buttons {
117
210
  display: flex; flex-direction: column; gap: 8px;
@@ -119,26 +212,30 @@ const te="1.1.0",h={checkoutOrigin:null,checkoutPath:"/api/x402-checkout",brand:
119
212
  }
120
213
  .x402-wallet-btn {
121
214
  width: 100%; padding: 13px 14px;
122
- background: #ffffff; border: 1.5px solid #e2e5ec; border-radius: 11px;
123
- font-size: 14px; font-weight: 600; color: #0f0f0f;
215
+ background: var(--x402-surface); border: 1.5px solid var(--x402-border-strong); border-radius: 11px;
216
+ font-size: 14px; font-weight: 600; color: var(--x402-fg);
124
217
  cursor: pointer; font-family: inherit;
125
218
  display: flex; align-items: center; gap: 12px;
126
219
  transition: border-color 0.12s, background 0.12s, transform 0.05s;
127
220
  }
128
- .x402-wallet-btn:hover:not(:disabled) { border-color: #0a84ff; background: #f7faff; }
221
+ .x402-wallet-btn:hover:not(:disabled) { border-color: var(--x402-accent); background: var(--x402-accent-weak); }
129
222
  .x402-wallet-btn:active:not(:disabled) { transform: translateY(1px); }
130
223
  .x402-wallet-btn:disabled { opacity: 0.45; cursor: not-allowed; }
131
224
  .x402-wallet-icon {
132
225
  width: 28px; height: 28px; flex: 0 0 auto;
133
226
  border-radius: 7px;
134
227
  display: flex; align-items: center; justify-content: center;
135
- font-size: 16px;
136
- background: #f3f4f7;
228
+ background: var(--x402-surface-2); overflow: hidden;
137
229
  }
138
- .x402-wallet-icon.x402-phantom { background: linear-gradient(135deg, #ab9ff2, #534bb1); color: #fff; }
139
- .x402-wallet-icon.x402-metamask { background: linear-gradient(135deg, #f6851b, #e2761b); color: #fff; }
230
+ .x402-wallet-icon svg, .x402-wallet-icon img { width: 18px; height: 18px; }
140
231
  .x402-wallet-name { flex: 1; text-align: left; }
141
- .x402-wallet-meta { font-size: 11px; color: #8a90a8; font-weight: 500; }
232
+ .x402-wallet-meta { font-size: 11px; color: var(--x402-muted); font-weight: 500; }
233
+ .x402-wallet-install {
234
+ font-size: 12px; color: var(--x402-muted); line-height: 1.5; text-align: center;
235
+ padding: 4px 0 2px;
236
+ }
237
+ .x402-wallet-install a { color: var(--x402-link); text-decoration: none; font-weight: 600; }
238
+ .x402-wallet-install a:hover { text-decoration: underline; }
142
239
 
143
240
  .x402-token-row {
144
241
  display: flex; gap: 8px; margin-bottom: 10px;
@@ -146,230 +243,263 @@ const te="1.1.0",h={checkoutOrigin:null,checkoutPath:"/api/x402-checkout",brand:
146
243
  .x402-token-pill {
147
244
  flex: 1; min-width: 0; cursor: pointer; font-family: inherit;
148
245
  padding: 9px 12px; border-radius: 10px;
149
- background: #ffffff; border: 1.5px solid #e2e5ec;
246
+ background: var(--x402-surface); border: 1.5px solid var(--x402-border-strong);
150
247
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
151
- transition: border-color 0.12s, background 0.12s, transform 0.05s;
248
+ transition: border-color 0.12s, background 0.12s, transform 0.05s, box-shadow 0.12s;
152
249
  }
153
- .x402-token-pill:hover { border-color: #c3c9d6; background: #f9fafc; }
250
+ .x402-token-pill:hover { border-color: var(--x402-accent); background: var(--x402-accent-weak); }
154
251
  .x402-token-pill:active { transform: translateY(1px); }
155
- .x402-token-pill.x402-on { border-color: #0f0f0f; background: #f7faff; }
156
- .x402-token-sym { font-size: 13px; font-weight: 700; color: #0f0f0f; letter-spacing: -0.005em; }
157
- .x402-token-amt { font-size: 11px; color: #8a90a8; font-weight: 600; font-variant-numeric: tabular-nums; }
252
+ .x402-token-pill.x402-on {
253
+ border-color: var(--x402-accent); background: var(--x402-accent-weak);
254
+ box-shadow: inset 0 0 0 1px var(--x402-accent);
255
+ }
256
+ .x402-token-sym { font-size: 13px; font-weight: 700; color: var(--x402-fg); letter-spacing: -0.005em; }
257
+ .x402-token-amt { font-size: 11px; color: var(--x402-muted); font-weight: 600; font-variant-numeric: tabular-nums; }
158
258
 
159
259
  .x402-pay-btn {
160
260
  width: 100%; padding: 14px 16px;
161
- background: #0f0f0f; color: #fff; border: none;
162
- border-radius: 12px;
261
+ background: var(--x402-btn-bg); color: var(--x402-btn-fg); border: none;
262
+ border-radius: var(--x402-radius-md);
163
263
  font-size: 15px; font-weight: 700; font-family: inherit;
164
264
  cursor: pointer; letter-spacing: -0.005em;
165
- transition: background 0.12s, transform 0.05s;
265
+ box-shadow: var(--x402-btn-shadow);
266
+ transition: background 0.12s, transform 0.1s, box-shadow 0.12s;
166
267
  margin-top: 4px;
167
268
  display: flex; align-items: center; justify-content: center; gap: 8px;
168
269
  }
169
- .x402-pay-btn:hover:not(:disabled) { background: #1d1d1d; }
170
- .x402-pay-btn:active:not(:disabled) { transform: translateY(1px); }
171
- .x402-pay-btn:disabled { background: #c8ccd4; cursor: not-allowed; }
270
+ .x402-pay-btn:hover:not(:disabled) { background: var(--x402-btn-hover); transform: translateY(-1px); }
271
+ .x402-pay-btn:active:not(:disabled) { transform: translateY(0); }
272
+ .x402-pay-btn:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; }
172
273
 
173
274
  .x402-pay-secondary {
174
275
  width: 100%; padding: 12px 14px;
175
- background: #ffffff; color: #0f0f0f;
176
- border: 1.5px solid #e2e5ec; border-radius: 11px;
276
+ background: var(--x402-surface); color: var(--x402-fg);
277
+ border: 1.5px solid var(--x402-border-strong); border-radius: 11px;
177
278
  font-size: 14px; font-weight: 600; font-family: inherit;
178
279
  cursor: pointer; letter-spacing: -0.005em;
179
280
  margin-top: 6px;
180
281
  transition: border-color 0.12s, background 0.12s, transform 0.05s;
181
282
  }
182
- .x402-pay-secondary:hover:not(:disabled) { border-color: #0a84ff; background: #f7faff; }
283
+ .x402-pay-secondary:hover:not(:disabled) { border-color: var(--x402-accent); background: var(--x402-accent-weak); }
183
284
  .x402-pay-secondary:active:not(:disabled) { transform: translateY(1px); }
184
285
 
286
+ .x402-trust {
287
+ font-size: 11.5px; color: var(--x402-muted); text-align: center;
288
+ margin-top: 10px; line-height: 1.45;
289
+ display: flex; align-items: center; justify-content: center; gap: 6px;
290
+ }
291
+ .x402-trust svg { width: 12px; height: 12px; flex: 0 0 auto; color: var(--x402-success); }
292
+
185
293
  .x402-siwx-hint {
186
- font-size: 11px; color: #5a6378; text-align: center;
294
+ font-size: 11px; color: var(--x402-muted); text-align: center;
187
295
  margin-top: 8px; line-height: 1.4;
188
296
  }
189
297
  .x402-siwx-fallback {
190
- font-size: 12px; color: #b45309; line-height: 1.45;
298
+ font-size: 12px; color: var(--x402-warn-fg); line-height: 1.45;
191
299
  padding: 8px 10px; border-radius: 8px;
192
- background: #fffbeb; border: 1px solid #fde68a;
300
+ background: var(--x402-warn-bg); border: 1px solid var(--x402-warn-border);
193
301
  margin-bottom: 6px;
194
302
  }
195
303
 
196
304
  .x402-error-box {
197
305
  padding: 12px 14px; border-radius: 10px;
198
- background: #fef2f2; border: 1px solid #fecaca; color: #b91c1c;
199
- font-size: 13px; line-height: 1.45;
200
- font-family: ui-monospace, "JetBrains Mono", Menlo, monospace;
306
+ background: var(--x402-error-bg); border: 1px solid var(--x402-error-border); color: var(--x402-error-fg);
307
+ font-size: 13.5px; line-height: 1.5;
201
308
  word-break: break-word;
202
309
  }
203
- .x402-error-box strong { font-weight: 700; }
310
+ .x402-error-box .x402-error-title { font-weight: 700; margin-bottom: 2px; }
311
+ .x402-error-box .x402-error-detail { opacity: 0.85; font-size: 12.5px; }
204
312
 
205
313
  .x402-receipt {
206
- padding: 14px 16px; border-radius: 12px;
207
- background: linear-gradient(180deg, #f0fdf4 0%, #ffffff 100%);
208
- border: 1px solid #bbf7d0;
314
+ padding: 16px; border-radius: var(--x402-radius-md);
315
+ background: var(--x402-success-bg);
316
+ border: 1px solid var(--x402-success-border);
317
+ animation: x402-pop 0.34s cubic-bezier(0.16, 1, 0.3, 1) both;
318
+ }
319
+ @keyframes x402-pop { from { opacity: 0; transform: scale(0.94); } to { opacity: 1; transform: scale(1); } }
320
+ .x402-receipt-check {
321
+ width: 40px; height: 40px; margin: 2px auto 10px;
322
+ border-radius: 50%; background: var(--x402-success);
323
+ display: flex; align-items: center; justify-content: center;
324
+ animation: x402-check-pop 0.4s cubic-bezier(0.16, 1, 0.3, 1) 0.08s both;
209
325
  }
326
+ .x402-receipt-check svg { width: 22px; height: 22px; color: #fff; }
327
+ .x402-receipt-check svg path { stroke-dasharray: 24; stroke-dashoffset: 24; animation: x402-draw 0.4s ease-out 0.22s forwards; }
328
+ @keyframes x402-check-pop { 0% { transform: scale(0); } 60% { transform: scale(1.12); } 100% { transform: scale(1); } }
329
+ @keyframes x402-draw { to { stroke-dashoffset: 0; } }
210
330
  .x402-receipt-title {
211
- font-size: 11px; font-weight: 700; color: #15803d;
212
- text-transform: uppercase; letter-spacing: 0.06em;
213
- margin-bottom: 8px;
214
- display: flex; align-items: center; gap: 6px;
331
+ font-size: 15px; font-weight: 700; color: var(--x402-fg);
332
+ text-align: center; margin-bottom: 10px; letter-spacing: -0.01em;
215
333
  }
216
- .x402-receipt-title::before { content: '\u2713'; font-size: 14px; }
217
334
  .x402-receipt-row {
218
335
  display: flex; justify-content: space-between; gap: 12px;
219
- font-size: 12px; padding: 2px 0;
220
- font-family: ui-monospace, "JetBrains Mono", Menlo, monospace;
336
+ font-size: 12px; padding: 3px 0;
337
+ font-family: var(--x402-mono);
221
338
  }
222
- .x402-receipt-row .x402-k { color: #5a6378; }
223
- .x402-receipt-row .x402-v { color: #0f0f0f; text-align: right; word-break: break-all; }
224
- .x402-receipt-row a { color: #0a84ff; text-decoration: none; }
339
+ .x402-receipt-row .x402-k { color: var(--x402-muted); }
340
+ .x402-receipt-row .x402-v { color: var(--x402-fg); text-align: right; word-break: break-all; }
341
+ .x402-receipt-row a { color: var(--x402-link); text-decoration: none; }
225
342
  .x402-receipt-row a:hover { text-decoration: underline; }
226
343
 
227
344
  .x402-result {
228
345
  padding: 12px 14px; border-radius: 10px;
229
- background: #fafbfc; border: 1px solid #e2e5ec;
346
+ background: var(--x402-surface-2); border: 1px solid var(--x402-border);
230
347
  max-height: 240px; overflow: auto;
231
- font-family: ui-monospace, "JetBrains Mono", Menlo, monospace;
232
- font-size: 12px; line-height: 1.5; color: #0f0f0f;
348
+ font-family: var(--x402-mono);
349
+ font-size: 12px; line-height: 1.5; color: var(--x402-fg);
233
350
  white-space: pre-wrap; word-break: break-word;
234
351
  }
352
+ .x402-result.x402-prose { font-family: var(--x402-font); font-size: 13.5px; line-height: 1.55; }
235
353
 
236
354
  .x402-foot {
237
- padding: 10px 20px 14px;
238
- border-top: 1px solid #eef0f4;
355
+ padding: 10px 20px max(14px, env(safe-area-inset-bottom));
356
+ border-top: 1px solid var(--x402-border);
239
357
  display: flex; align-items: center; justify-content: space-between;
240
- font-size: 11px; color: #8a90a8;
358
+ font-size: 11px; color: var(--x402-muted);
241
359
  }
242
- .x402-foot a { color: #5a6378; text-decoration: none; font-weight: 600; }
243
- .x402-foot a:hover { color: #0f0f0f; }
360
+ .x402-foot a { color: var(--x402-muted); text-decoration: none; font-weight: 600; }
361
+ .x402-foot a:hover { color: var(--x402-fg); }
244
362
  .x402-foot .x402-secure { display: flex; align-items: center; gap: 5px; }
245
- .x402-foot .x402-secure::before { content: '\u{1F512}'; font-size: 10px; }
363
+ .x402-foot .x402-secure svg { width: 11px; height: 11px; }
246
364
 
247
- @media (max-width: 480px) {
248
- .x402-modal { max-width: none; width: calc(100% - 16px); border-radius: 16px; }
249
- .x402-price { font-size: 26px; }
365
+ .x402-sr-only {
366
+ position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
367
+ overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
250
368
  }
251
369
 
252
- @media (prefers-color-scheme: dark) {
253
- .x402-overlay { color: #e6e8f0; }
254
- .x402-modal { background: #161616; box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6); }
255
- .x402-head, .x402-price-row, .x402-foot { border-color: #272727; }
256
- .x402-step + .x402-step { border-top-color: #272727; }
257
- .x402-merchant .x402-name { color: #8a90a8; }
258
- .x402-merchant .x402-action, .x402-price, .x402-step-label { color: #e6e8f0; }
259
- .x402-step-meta { color: #8a90a8; }
260
- .x402-close { background: #222222; color: #8a90a8; }
261
- .x402-close:hover { background: #2e2e2e; color: #e6e8f0; }
262
- .x402-price-row { background: linear-gradient(180deg, #1d1d1d 0%, #161616 100%); }
263
- .x402-network { background: #222222; color: #b0b6cc; }
264
- .x402-wallet-btn { background: #1d1d1d; border-color: #2e2e2e; color: #e6e8f0; }
265
- .x402-wallet-btn:hover:not(:disabled) { background: #252525; border-color: #0a84ff; }
266
- .x402-wallet-icon { background: #2e2e2e; }
267
- .x402-wallet-meta { color: #6b7088; }
268
- .x402-pay-btn { background: #ffffff; color: #0f0f0f; }
269
- .x402-pay-btn:hover:not(:disabled) { background: #e7e9ee; }
270
- .x402-pay-btn:disabled { background: #2e2e2e; color: #5a6378; }
271
- .x402-pay-secondary { background: #1d1d1d; border-color: #2e2e2e; color: #e6e8f0; }
272
- .x402-pay-secondary:hover:not(:disabled) { background: #252525; border-color: #0a84ff; }
273
- .x402-siwx-hint { color: #8a90a8; }
274
- .x402-siwx-fallback { background: #2a1d10; border-color: #78350f; color: #fcd34d; }
275
- .x402-step-num { background: #161616; border-color: #2e2e2e; color: #8a90a8; }
276
- .x402-result { background: #1d1d1d; border-color: #2e2e2e; color: #e6e8f0; }
277
- .x402-receipt { background: linear-gradient(180deg, #0b1f17 0%, #161616 100%); border-color: #14532d; }
278
- .x402-receipt-title { color: #4ade80; }
279
- .x402-receipt-row .x402-k { color: #8a90a8; }
280
- .x402-receipt-row .x402-v { color: #e6e8f0; }
281
- .x402-receipt-row a { color: #60a5fa; }
282
- .x402-error-box { background: #1f1416; border-color: #7f1d1d; color: #fca5a5; }
283
- .x402-foot a { color: #b0b6cc; }
284
- .x402-foot a:hover { color: #ffffff; }
285
- }
286
- `;function be(){if(document.getElementById(G))return;const n=document.createElement("style");n.id=G,n.textContent=me,document.head.appendChild(n)}class ye{constructor(e){this.opts=e,this.steps=[{id:"discover",label:"Confirming price"},{id:"connect",label:"Connect wallet"},{id:"authorize",label:"Authorize payment"},{id:"verify",label:"Verify & complete"}],this.activeNetwork=null,this.payerAddress=null,this.accept=null,this.challenge=null,this.disposed=!1,this.autoConnectTried=!1}mount(){be();const e=document.createElement("div");return e.className="x402-overlay",e.innerHTML=`
287
- <div class="x402-modal" role="dialog" aria-modal="true" aria-label="x402 payment">
370
+ @media (max-width: 520px) {
371
+ .x402-overlay { align-items: flex-end; }
372
+ .x402-modal {
373
+ max-width: none; width: 100%;
374
+ border-radius: var(--x402-radius) var(--x402-radius) 0 0;
375
+ max-height: 92dvh;
376
+ transform: translateY(100%);
377
+ }
378
+ .x402-overlay.x402-open .x402-modal { transform: translateY(0); }
379
+ .x402-price { font-size: 28px; }
380
+ }
381
+
382
+ @media (prefers-reduced-motion: reduce) {
383
+ .x402-overlay, .x402-modal, .x402-body > *,
384
+ .x402-receipt, .x402-receipt-check, .x402-receipt-check svg path { animation: none !important; transition: none !important; }
385
+ .x402-step.x402-active .x402-step-num { animation: none; }
386
+ .x402-network::before { animation: none; }
387
+ .x402-receipt-check svg path { stroke-dashoffset: 0; }
388
+ }
389
+ `,m={close:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg>',lock:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>',check:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg>',shield:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l7 3v6c0 4.5-3 7.4-7 9-4-1.6-7-4.5-7-9V6z"/><path d="M9 12l2 2 4-4"/></svg>',phantom:'<svg viewBox="0 0 24 24" aria-hidden="true"><rect width="24" height="24" rx="6" fill="#ab9ff2"/><path fill="#fff" d="M19 12.4c0 3.8-3.1 6.8-7 6.8-.6 0-1-.6-.7-1.1.2-.4 0-.9-.4-1.1-.4-.2-1 0-1.3.4-.5.7-1.3 1.1-2.2 1.1H6.7c-1.2 0-2.2-1-2.2-2.2v-1.7c0-4.1 3.4-7.4 7.5-7.4h-.1c3.9 0 7.1 2.6 7.1 5.9z"/><circle cx="9.4" cy="12.4" r="1" fill="#534bb1"/><circle cx="12.6" cy="12.4" r="1" fill="#534bb1"/></svg>',wallet:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="6" width="18" height="13" rx="2.5"/><path d="M3 10h18"/><circle cx="16.5" cy="14" r="1.3" fill="currentColor" stroke="none"/></svg>'},Te={discover:"Couldn't confirm the price",connect:"Couldn't connect your wallet",authorize:"Payment couldn't be authorized",verify:"Payment couldn't be completed"};function Pe(){if(typeof window>"u")return[];const n=[],e=new Set,t=(r,o,s)=>{!o||typeof o.signTransaction!="function"||e.has(o)||(e.add(o),n.push({kind:"solana",name:r,provider:o,icon:s||m.wallet}))};return t("Phantom",window.phantom?.solana||(window.solana?.isPhantom?window.solana:null),m.phantom),t("Solflare",window.solflare?.isSolflare?window.solflare:null,m.wallet),t("Backpack",window.backpack?.isBackpack?window.backpack:null,m.wallet),t("Glow",window.glowSolana||window.glow||null,m.wallet),t("Coinbase Wallet",window.coinbaseSolana||null,m.wallet),window.solana&&!window.solana.isPhantom&&t(window.solana.isSolflare?"Solflare":"Solana wallet",window.solana,m.wallet),n}function Be(){if(typeof window>"u"||typeof window.dispatchEvent!="function")return[];const n=[],e=new Set,t=(s,a,i)=>{!a||e.has(a)||(e.add(a),n.push({kind:"evm",name:s||"Browser wallet",provider:a,icon:i||m.wallet}))},r=[],o=s=>{s?.detail&&r.push(s.detail)};window.addEventListener("eip6963:announceProvider",o);try{window.dispatchEvent(new Event("eip6963:requestProvider"))}catch{}window.removeEventListener("eip6963:announceProvider",o);for(const s of r)t(s.info?.name,s.provider,s.info?.icon);if(!n.length){const s=window.ethereum,a=i=>i?.isMetaMask?"MetaMask":i?.isCoinbaseWallet?"Coinbase Wallet":"Browser wallet";if(Array.isArray(s?.providers))for(const i of s.providers)t(a(i),i);else s&&t(a(s),s)}return n}function re(n){return n&&/^(data:|https?:)/.test(n)?`<img src="${u(n)}" alt="" />`:n||m.wallet}function Ne(){if(document.getElementById(te))return;const n=document.createElement("style");n.id=te,n.textContent=Ce,document.head.appendChild(n)}class Ie{constructor(e){this.opts=e,this.steps=[{id:"discover",label:"Confirming price"},{id:"connect",label:"Connect wallet"},{id:"authorize",label:"Authorize payment"},{id:"verify",label:"Verify & complete"}],this.activeNetwork=null,this.payerAddress=null,this.accept=null,this.challenge=null,this.disposed=!1,this.autoConnectTried=!1}mount(){Ne();const e=document.createElement("div");if(e.className="x402-overlay",p.theme==="dark"?e.classList.add("x402-theme-dark"):p.theme==="light"&&e.classList.add("x402-theme-light"),p.cssVars&&typeof p.cssVars=="object")for(const[r,o]of Object.entries(p.cssVars))/^--x402-[a-z0-9-]+$/i.test(r)&&e.style.setProperty(r,String(o));const t=p.brand?.logo?`<img class="x402-brand-logo" src="${u(p.brand.logo)}" alt="" />`:"";return e.innerHTML=`
390
+ <div class="x402-modal" role="dialog" aria-modal="true" aria-labelledby="x402-act" aria-describedby="x402-price">
288
391
  <div class="x402-head">
289
392
  <div class="x402-merchant">
290
- <div class="x402-name" data-merchant>${f(this.opts.merchant||"Payment")}</div>
291
- <div class="x402-action" data-action>${f(this.opts.action||"Pay-per-call")}</div>
393
+ ${t}
394
+ <div class="x402-merchant-text">
395
+ <div class="x402-name" data-merchant>${u(this.opts.merchant||"Payment")}</div>
396
+ <div class="x402-action" id="x402-act" data-action>${u(this.opts.action||"Pay-per-call")}</div>
397
+ </div>
292
398
  </div>
293
- <button class="x402-close" data-close aria-label="Close">\u2715</button>
399
+ <button class="x402-close" data-close aria-label="Close payment">${m.close}</button>
294
400
  </div>
295
401
  <div class="x402-price-row">
296
- <div class="x402-price" data-price>\u2014<span class="x402-currency"> USDC</span></div>
402
+ <div class="x402-price-main">
403
+ <div class="x402-price" id="x402-price" data-price>\u2014<span class="x402-currency"> USDC</span></div>
404
+ <div class="x402-price-sub" data-price-sub></div>
405
+ </div>
297
406
  <div class="x402-network" data-network>resolving\u2026</div>
298
407
  </div>
299
- <div class="x402-body" data-body></div>
408
+ <div class="x402-body" data-body aria-live="polite"></div>
300
409
  <div class="x402-foot">
301
- <span class="x402-secure">${f(h.footerNote)}</span>
302
- ${h.brand?.name?`<a href="${f(h.brand.url||"#")}" target="_blank" rel="noopener">Powered by ${f(h.brand.name)}</a>`:""}
410
+ <span class="x402-secure">${m.lock}${u(p.footerNote)}</span>
411
+ ${p.brand?.name?`<a href="${u(p.brand.url||"#")}" target="_blank" rel="noopener">Powered by ${u(p.brand.name)}</a>`:""}
303
412
  </div>
304
413
  </div>
305
- `,document.body.appendChild(e),this.overlay=e,this.bodyEl=e.querySelector("[data-body]"),this.priceEl=e.querySelector("[data-price]"),this.networkEl=e.querySelector("[data-network]"),e.querySelector("[data-close]").addEventListener("click",()=>this.close("cancelled")),e.addEventListener("click",t=>{t.target===e&&this.close("cancelled")}),this.onKey=t=>{t.key==="Escape"&&this.close("cancelled")},document.addEventListener("keydown",this.onKey),requestAnimationFrame(()=>e.classList.add("x402-open")),new Promise((t,r)=>{this.resolve=t,this.reject=r})}close(e){if(!this.disposed&&(this.disposed=!0,document.removeEventListener("keydown",this.onKey),this.overlay.classList.remove("x402-open"),setTimeout(()=>this.overlay.remove(),180),e==="cancelled"&&this.reject)){const t=new Error("cancelled");t.code="cancelled",this.reject(t)}}renderSteps(e,t={}){return this.steps.map(o=>{const s=t[o.id]||(o.id===e?"active":"idle"),i=s==="active"?"x402-active":s==="done"?"x402-done":s==="error"?"x402-error":"",a=t[`${o.id}_meta`]||"",l=s==="done"?"\u2713":s==="error"?"!":o.id===e&&s==="active"?" ":this.steps.findIndex(d=>d.id===o.id)+1;return`<div class="x402-step ${i}">
414
+ `,document.body.appendChild(e),this.overlay=e,this.bodyEl=e.querySelector("[data-body]"),this.priceEl=e.querySelector("[data-price]"),this.priceSubEl=e.querySelector("[data-price-sub]"),this.networkEl=e.querySelector("[data-network]"),e.querySelector("[data-close]").addEventListener("click",()=>this.close("cancelled")),e.addEventListener("click",r=>{r.target===e&&this.close("cancelled")}),this.previouslyFocused=typeof document<"u"?document.activeElement:null,this.onKey=r=>{if(r.key==="Escape"){this.close("cancelled");return}r.key==="Tab"&&this.trapTab(r)},document.addEventListener("keydown",this.onKey),requestAnimationFrame(()=>{e.classList.add("x402-open"),this.focusFirst()}),new Promise((r,o)=>{this.resolve=r,this.reject=o})}focusables(){return this.overlay?Array.from(this.overlay.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), select, textarea, [tabindex]:not([tabindex="-1"])')).filter(t=>t.offsetParent!==null):[]}focusFirst(){const e=this.focusables();(e.find(t=>!t.hasAttribute("data-close"))||e[0])?.focus?.()}trapTab(e){const t=this.focusables();if(!t.length)return;const r=t[0],o=t[t.length-1];e.shiftKey&&document.activeElement===r?(e.preventDefault(),o.focus()):!e.shiftKey&&document.activeElement===o&&(e.preventDefault(),r.focus())}close(e){if(!this.disposed&&(this.disposed=!0,document.removeEventListener("keydown",this.onKey),this.overlay.classList.remove("x402-open"),setTimeout(()=>this.overlay.remove(),180),this.previouslyFocused?.focus?.(),e==="cancelled"&&this.reject)){const t=new Error("cancelled");t.code="cancelled",this.reject(t)}}renderSteps(e,t={}){return this.steps.map(o=>{const s=t[o.id]||(o.id===e?"active":"idle"),a=s==="active"?"x402-active":s==="done"?"x402-done":s==="error"?"x402-error":"",i=t[`${o.id}_meta`]||"",l=s==="done"?"\u2713":s==="error"?"!":o.id===e&&s==="active"?" ":this.steps.findIndex(c=>c.id===o.id)+1;return`<div class="x402-step ${a}">
306
415
  <div class="x402-step-num">${l}</div>
307
416
  <div class="x402-step-body">
308
417
  <div class="x402-step-label">${o.label}</div>
309
- ${a?`<div class="x402-step-meta">${f(a)}</div>`:""}
418
+ ${i?`<div class="x402-step-meta">${u(i)}</div>`:""}
310
419
  </div>
311
- </div>`}).join("")}setPrice(e){const t=y(e),r=v(e.amount,t.decimals),o=t.glyph?`${t.glyph} `:"";this.priceEl.innerHTML=`${r}<span class="x402-currency"> ${o}${f(t.symbol)}</span>`,this.networkEl.textContent=b(e.network,e)}renderConnect(){const e=typeof window<"u"&&(window.solana?.isPhantom||window.phantom?.solana),t=typeof window<"u"&&window.ethereum,r=q(this.challenge);let o=r.find(u=>u===this.solanaAccept)||R(r);this.solanaAccept=o;const s=this.challenge?.accepts.find(D);if(this.siwx&&!this.payFlowOverride){const u=e?J(this.siwx,"solana"):null,c=t?J(this.siwx,"evm"):null;if(u||c){this.renderSiwxChoice({siwxSolana:u,siwxEvm:c});return}}if(this.opts.autoConnect&&!this.autoConnectTried&&!this.siwxFallbackNotice){this.autoConnectTried=!0;const u=!!(o&&e),c=!!(s&&t);if(u&&!c){this.runSolana(o);return}if(c&&!u){this.runEvm(s);return}}const i=r.length>1?`<div class="x402-token-row" role="group" aria-label="Choose payment token">
312
- ${r.map(u=>{const c=y(u),p=u===o,x=v(u.amount,c.decimals);return`<button type="button" class="x402-token-pill${p?" x402-on":""}" data-token-asset="${f(u.asset)}" aria-pressed="${p}"${c.accent&&p?` style="border-color:${f(c.accent)}"`:""}>
313
- <span class="x402-token-sym">${c.glyph?f(c.glyph)+" ":""}${f(c.symbol)}</span>
314
- <span class="x402-token-amt">${x}</span>
420
+ </div>`}).join("")}setPrice(e){const t=k(e),r=C(e.amount,t.decimals),o=t.glyph?`${t.glyph} `:"";this.priceEl.innerHTML=`${r}<span class="x402-currency"> ${o}${u(t.symbol)}</span>`,this.networkEl.textContent=v(e.network,e)}renderConnect(){const e=Pe(),t=Be();this._solWallets=e,this._evmWallets=t;const r=e.length>0,o=t.length>0,s=F(this.challenge);let a=s.find(x=>x===this.solanaAccept)||V(s);this.solanaAccept=a;const i=this.challenge?.accepts.find(K);if(this.siwx&&!this.payFlowOverride){const x=r?Z(this.siwx,"solana"):null,d=o?Z(this.siwx,"evm"):null;if(x||d){this.renderSiwxChoice({siwxSolana:x,siwxEvm:d});return}}if(this.opts.autoConnect&&!this.autoConnectTried&&!this.siwxFallbackNotice){this.autoConnectTried=!0;const x=a&&e.length===1,d=i&&t.length===1;if(x&&!d){this.runSolana(a,e[0].provider);return}if(d&&!x){this.runEvm(i,t[0].provider);return}}const l=s.length>1?`<div class="x402-token-row" role="group" aria-label="Choose payment token">
421
+ ${s.map(x=>{const d=k(x),f=x===a,b=C(x.amount,d.decimals);return`<button type="button" class="x402-token-pill${f?" x402-on":""}" data-token-asset="${u(x.asset)}" aria-pressed="${f}"${d.accent&&f?` style="border-color:${u(d.accent)}"`:""}>
422
+ <span class="x402-token-sym">${d.glyph?u(d.glyph)+" ":""}${u(d.symbol)}</span>
423
+ <span class="x402-token-amt">${b}</span>
315
424
  </button>`}).join("")}
316
- </div>`:"",a=[];if(o){const u=y(o),c=r.length>1?`${b(o.network,o)} \xB7 ${u.symbol}`:b(o.network,o);a.push(`
317
- <button class="x402-wallet-btn" data-wallet="phantom" ${e?"":"disabled"}>
318
- <div class="x402-wallet-icon x402-phantom">P</div>
319
- <span class="x402-wallet-name">${e?"Phantom":"Phantom (not detected)"}</span>
320
- <span class="x402-wallet-meta" data-sol-meta>${f(c)}</span>
321
- </button>
322
- `)}s&&a.push(`
323
- <button class="x402-wallet-btn" data-wallet="evm" ${t?"":"disabled"}>
324
- <div class="x402-wallet-icon x402-metamask">M</div>
325
- <span class="x402-wallet-name">${t?"Browser wallet":"No EVM wallet detected"}</span>
326
- <span class="x402-wallet-meta">${b(s.network,s)}</span>
327
- </button>
328
- `);const l=this.siwxFallbackNotice?`<div class="x402-siwx-fallback">${f(this.siwxFallbackNotice)}</div>`:"";this.bodyEl.innerHTML=`
425
+ </div>`:"",c=[];if(a){const x=k(a),d=s.length>1?`${v(a.network,a)} \xB7 ${x.symbol}`:v(a.network,a);e.length?e.forEach((f,b)=>c.push(`
426
+ <button class="x402-wallet-btn" data-wallet-kind="solana" data-wallet-idx="${b}">
427
+ <div class="x402-wallet-icon">${re(f.icon)}</div>
428
+ <span class="x402-wallet-name">${u(f.name)}</span>
429
+ <span class="x402-wallet-meta"${b===0?" data-sol-meta":""}>${u(d)}</span>
430
+ </button>
431
+ `)):c.push(`
432
+ <button class="x402-wallet-btn" disabled>
433
+ <div class="x402-wallet-icon">${m.phantom}</div>
434
+ <span class="x402-wallet-name">No Solana wallet detected</span>
435
+ <span class="x402-wallet-meta">${u(d)}</span>
436
+ </button>
437
+ `)}i&&(t.length?t.forEach((x,d)=>c.push(`
438
+ <button class="x402-wallet-btn" data-wallet-kind="evm" data-wallet-idx="${d}">
439
+ <div class="x402-wallet-icon">${re(x.icon)}</div>
440
+ <span class="x402-wallet-name">${u(x.name)}</span>
441
+ <span class="x402-wallet-meta">${u(v(i.network,i))}</span>
442
+ </button>
443
+ `)):c.push(`
444
+ <button class="x402-wallet-btn" disabled>
445
+ <div class="x402-wallet-icon">${m.wallet}</div>
446
+ <span class="x402-wallet-name">No EVM wallet detected</span>
447
+ <span class="x402-wallet-meta">${u(v(i.network,i))}</span>
448
+ </button>
449
+ `));const w=!r&&!o?`<div class="x402-wallet-install">No wallet detected \u2014 install
450
+ ${a?'<a href="https://phantom.app/download" target="_blank" rel="noopener">Phantom</a>':""}${a&&i?" or ":""}${i?'<a href="https://metamask.io/download" target="_blank" rel="noopener">MetaMask</a>':""}
451
+ to continue.</div>`:"",h=this.siwxFallbackNotice?`<div class="x402-siwx-fallback">${u(this.siwxFallbackNotice)}</div>`:"",y=k(this.accept),$=C(this.accept.amount,y.decimals),S=`<div class="x402-trust">${m.shield}<span>You authorize exactly ${u($)} ${u(y.symbol)} \u2014 nothing more can be charged.</span></div>`;this.bodyEl.innerHTML=`
329
452
  ${this.renderSteps("connect",{discover:"done"})}
453
+ ${h}
330
454
  ${l}
331
- ${i}
332
- <div class="x402-wallet-buttons">${a.join("")}</div>
333
- `;const d=u=>{const c=u.target.closest("[data-wallet]");if(!c||c.disabled)return;const p=c.dataset.wallet;p==="phantom"?this.runSolana(this.solanaAccept):p==="evm"&&this.runEvm(s)};this.bodyEl.querySelectorAll("[data-wallet]").forEach(u=>u.addEventListener("click",d)),this.bodyEl.querySelectorAll("[data-token-asset]").forEach(u=>{u.addEventListener("click",()=>{const c=r.find(m=>m.asset===u.dataset.tokenAsset);if(!c||c===this.solanaAccept)return;this.solanaAccept=c,this.accept=c,this.setPrice(c);const p=y(c),x=this.bodyEl.querySelector("[data-sol-meta]");x&&(x.textContent=`${b(c.network,c)} \xB7 ${p.symbol}`),this.bodyEl.querySelectorAll("[data-token-asset]").forEach(m=>{const w=m===u;m.classList.toggle("x402-on",w),m.setAttribute("aria-pressed",String(w)),m.style.borderColor=w&&p.accent?p.accent:""})})})}renderSiwxChoice({siwxSolana:e,siwxEvm:t}){const r=y(this.accept),o=v(this.accept.amount,r.decimals),s=e?{kind:"solana",chain:e.chain}:{kind:"evm",chain:t.chain},i=s.kind==="solana"?"Sign in with Phantom":"Sign in with wallet";this.bodyEl.innerHTML=`
455
+ <div class="x402-wallet-buttons">${c.join("")}</div>
456
+ ${w}
457
+ ${r||o?S:""}
458
+ `,requestAnimationFrame(()=>this.focusFirst());const A=x=>{const d=x.target.closest("[data-wallet-kind]");if(!d||d.disabled)return;const f=d.dataset.walletKind,b=Number(d.dataset.walletIdx);f==="solana"?this.runSolana(this.solanaAccept,this._solWallets[b]?.provider):f==="evm"&&this.runEvm(i,this._evmWallets[b]?.provider)};this.bodyEl.querySelectorAll("[data-wallet-kind]").forEach(x=>x.addEventListener("click",A)),this.bodyEl.querySelectorAll("[data-token-asset]").forEach(x=>{x.addEventListener("click",()=>{const d=s.find(g=>g.asset===x.dataset.tokenAsset);if(!d||d===this.solanaAccept)return;this.solanaAccept=d,this.accept=d,this.setPrice(d);const f=k(d),b=this.bodyEl.querySelector("[data-sol-meta]");b&&(b.textContent=`${v(d.network,d)} \xB7 ${f.symbol}`),this.bodyEl.querySelectorAll("[data-token-asset]").forEach(g=>{const T=g===x;g.classList.toggle("x402-on",T),g.setAttribute("aria-pressed",String(T)),g.style.borderColor=T&&f.accent?f.accent:""})})})}renderSiwxChoice({siwxSolana:e,siwxEvm:t}){const r=k(this.accept),o=C(this.accept.amount,r.decimals),s=e?{kind:"solana",chain:e.chain}:{kind:"evm",chain:t.chain},a=s.kind==="solana"?"Sign in with Phantom":"Sign in with wallet";this.bodyEl.innerHTML=`
334
459
  ${this.renderSteps("connect",{discover:"done"})}
335
- <button class="x402-pay-btn" data-action="siwx">${i}</button>
336
- <button class="x402-pay-secondary" data-action="pay">Pay ${o} ${f(r.symbol)} instead</button>
460
+ <button class="x402-pay-btn" data-action="siwx">${a}</button>
461
+ <button class="x402-pay-secondary" data-action="pay">Pay ${o} ${u(r.symbol)} instead</button>
337
462
  <div class="x402-siwx-hint">Already paid for this once? Sign in to re-enter without paying again.</div>
338
- `;const a=this.bodyEl.querySelector('[data-action="siwx"]'),l=this.bodyEl.querySelector('[data-action="pay"]');a.addEventListener("click",()=>{s.kind==="solana"?this.runSiwxSolana(s.chain):this.runSiwxEvm(s.chain)}),l.addEventListener("click",()=>{this.payFlowOverride=!0,this.renderConnect()}),requestAnimationFrame(()=>a.focus())}renderProgress(e,t={}){this.bodyEl.innerHTML=this.renderSteps(e,{discover:"done",connect:"done",...e==="verify"?{authorize:"done"}:{},[`${e}_meta`]:t.text||"",...t.statuses})}renderError(e,t){this.bodyEl.innerHTML=`
463
+ `;const i=this.bodyEl.querySelector('[data-action="siwx"]'),l=this.bodyEl.querySelector('[data-action="pay"]');i.addEventListener("click",()=>{s.kind==="solana"?this.runSiwxSolana(s.chain):this.runSiwxEvm(s.chain)}),l.addEventListener("click",()=>{this.payFlowOverride=!0,this.renderConnect()}),requestAnimationFrame(()=>i.focus())}renderProgress(e,t={}){this.bodyEl.innerHTML=this.renderSteps(e,{discover:"done",connect:"done",...e==="verify"?{authorize:"done"}:{},[`${e}_meta`]:t.text||"",...t.statuses})}renderError(e,t){this.bodyEl.innerHTML=`
339
464
  ${this.renderSteps(e,{...e!=="discover"?{discover:"done"}:{},...e==="authorize"||e==="verify"?{connect:"done"}:{},...e==="verify"?{authorize:"done"}:{},[e]:"error",[`${e}_meta`]:"failed"})}
340
- <div class="x402-error-box"><strong>${f(e)}:</strong> ${f(t)}</div>
465
+ <div class="x402-error-box">
466
+ <div class="x402-error-title">${u(Te[e]||"Something went wrong")}</div>
467
+ <div class="x402-error-detail">${u(t)}</div>
468
+ </div>
341
469
  <button class="x402-pay-btn" data-retry>Try again</button>
342
- `,this.bodyEl.querySelector("[data-retry]").addEventListener("click",()=>this.start())}renderDone({result:e,payment:t,siwx:r}){const o=typeof e=="string"?e:JSON.stringify(e,null,2);let s;if(r){const i=r.address?`${r.address.slice(0,8)}\u2026${r.address.slice(-6)}`:"\u2014";s=`
470
+ `;const r=this.bodyEl.querySelector("[data-retry]");r.addEventListener("click",()=>this.start()),requestAnimationFrame(()=>r.focus())}renderDone({result:e,payment:t,siwx:r}){const o=typeof e=="string"?e:JSON.stringify(e,null,2);let s;if(r){const l=r.address?`${r.address.slice(0,8)}\u2026${r.address.slice(-6)}`:"\u2014";s=`
343
471
  <div class="x402-receipt">
344
- <div class="x402-receipt-title">Welcome back!</div>
472
+ <div class="x402-receipt-check">${m.check}</div>
473
+ <div class="x402-receipt-title">Welcome back</div>
345
474
  <div class="x402-receipt-row">
346
475
  <span class="x402-k">network</span>
347
- <span class="x402-v">${f(b(r.network)||r.network||"\u2014")}</span>
476
+ <span class="x402-v">${u(v(r.network)||r.network||"\u2014")}</span>
348
477
  </div>
349
478
  <div class="x402-receipt-row">
350
479
  <span class="x402-k">wallet</span>
351
- <span class="x402-v">${f(i)}</span>
480
+ <span class="x402-v">${u(l)}</span>
352
481
  </div>
353
482
  <div class="x402-receipt-row">
354
483
  <span class="x402-k">paid</span>
355
484
  <span class="x402-v">previously \xB7 re-entered free</span>
356
485
  </div>
357
486
  </div>
358
- `}else{const i=ae(t?.network,t?.transaction),a=t?.transaction?`${t.transaction.slice(0,8)}\u2026${t.transaction.slice(-6)}`:"\u2014";s=`
487
+ `}else{const l=me(t?.network,t?.transaction),c=t?.transaction?`${t.transaction.slice(0,8)}\u2026${t.transaction.slice(-6)}`:"\u2014";s=`
359
488
  <div class="x402-receipt">
360
- <div class="x402-receipt-title">Payment confirmed!</div>
489
+ <div class="x402-receipt-check">${m.check}</div>
490
+ <div class="x402-receipt-title">Payment confirmed</div>
361
491
  <div class="x402-receipt-row">
362
492
  <span class="x402-k">network</span>
363
- <span class="x402-v">${f(b(t?.network)||"\u2014")}</span>
493
+ <span class="x402-v">${u(v(t?.network)||"\u2014")}</span>
364
494
  </div>
365
495
  <div class="x402-receipt-row">
366
496
  <span class="x402-k">payer</span>
367
- <span class="x402-v">${f(t?.payer?`${t.payer.slice(0,8)}\u2026${t.payer.slice(-6)}`:"\u2014")}</span>
497
+ <span class="x402-v">${u(t?.payer?`${t.payer.slice(0,8)}\u2026${t.payer.slice(-6)}`:"\u2014")}</span>
368
498
  </div>
369
- ${t?.transaction?`<div class="x402-receipt-row"><span class="x402-k">tx</span><span class="x402-v">${i?`<a href="${i}" target="_blank" rel="noopener">${a} \u2197</a>`:a}</span></div>`:""}
499
+ ${t?.transaction?`<div class="x402-receipt-row"><span class="x402-k">tx</span><span class="x402-v">${l?`<a href="${l}" target="_blank" rel="noopener">${c} \u2197</a>`:c}</span></div>`:""}
370
500
  </div>
371
- `}this.bodyEl.innerHTML=`
501
+ `}const a=typeof e=="string";this.bodyEl.innerHTML=`
372
502
  ${s}
373
- <div class="x402-result">${f(o).slice(0,4e3)}</div>
503
+ <div class="x402-result${a?" x402-prose":""}">${u(o).slice(0,4e3)}</div>
374
504
  <button class="x402-pay-btn" data-done>Done</button>
375
- `,this.bodyEl.querySelector("[data-done]").addEventListener("click",()=>{this.disposed=!0,document.removeEventListener("keydown",this.onKey),this.overlay.classList.remove("x402-open"),setTimeout(()=>this.overlay.remove(),180)})}async start(){this.bodyEl.innerHTML=this.renderSteps("discover");try{const e=await $e(this.opts);this.challenge=e,this.siwx=fe(e),this.payFlowOverride=!1,this.siwxFallbackNotice=null;const t=q(e),r=R(t);this.solanaAccept=r;const o=e.accepts.find(D),s=typeof window<"u"&&(window.solana?.isPhantom||window.phantom?.solana);this.accept=s&&r||o||e.accepts[0],this.setPrice(this.accept),this.renderConnect()}catch(e){this.renderError("discover",e.message||String(e))}}async runSolana(e){this.accept=e,this.setPrice(e),this.renderProgress("connect",{text:"Opening Phantom\u2026"});try{const t=window.phantom?.solana||window.solana;if(!t)throw new Error("Phantom wallet not detected");const o=((await t.connect())?.publicKey||t.publicKey)?.toString();if(!o)throw new Error("Phantom did not return a public key");this.payerAddress=o;const s=F({accept:e,caps:this.opts.caps,address:o});if(s.abort){this.renderError("authorize",s.reason);return}this.spendReservation=s.reservation||null,this.renderProgress("authorize",{text:`Building Solana payment for ${o.slice(0,6)}\u2026${o.slice(-4)}`});const i=await X(`${L()}?action=prepare`,{accept:e,buyer:o});this.renderProgress("authorize",{text:"Confirm in Phantom\u2026"});const a=ve(i.tx_base64),d=(await Ee()).VersionedTransaction.deserialize(a),u=await t.signTransaction(d),c=ke(u.serialize()),p=W(this.challenge),x=await X(`${L()}?action=encode`,{accept:e,signed_tx_base64:c,resource_url:new URL(this.opts.endpoint,location.href).href,...p?{builder_code:p}:{}});await this.executePaid(x.x_payment)}catch(t){this.spendReservation&&(z(this.spendReservation),this.spendReservation=null),this.renderError(this.payerAddress?"authorize":"connect",g(t))}}async runEvm(e){this.accept=e,this.setPrice(e),this.renderProgress("connect",{text:"Opening browser wallet\u2026"});try{const t=window.ethereum;if(!t)throw new Error("No EVM wallet detected");const o=(await t.request({method:"eth_requestAccounts"}))?.[0];if(!o)throw new Error("Wallet did not return an account");this.payerAddress=o;const s=F({accept:e,caps:this.opts.caps,address:o});if(s.abort){this.renderError("authorize",s.reason);return}this.spendReservation=s.reservation||null;const i=C[e.network];if(!i)throw new Error(`Unknown EVM network ${e.network}`);const a=await t.request({method:"eth_chainId"}),l="0x"+i.chainId.toString(16);if(a!==l){this.renderProgress("connect",{text:`Switch wallet to ${i.name}\u2026`});try{await t.request({method:"wallet_switchEthereumChain",params:[{chainId:l}]})}catch{throw new Error(`Wallet is on ${a}; please switch to ${i.name} (${l}) and retry`)}}this.renderProgress("authorize",{text:`Authorize ${v(e.amount)} USDC\u2026`});const d=0,u=Math.floor(Date.now()/1e3)+(e.maxTimeoutSeconds||600),c="0x"+Se(32),p={name:e.extra?.name||"USD Coin",version:e.extra?.version||"2",chainId:i.chainId,verifyingContract:e.asset},x={EIP712Domain:[{name:"name",type:"string"},{name:"version",type:"string"},{name:"chainId",type:"uint256"},{name:"verifyingContract",type:"address"}],TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},m={from:o,to:e.payTo,value:e.amount,validAfter:d,validBefore:u,nonce:c},w={primaryType:"TransferWithAuthorization",types:x,domain:p,message:m},Q=await t.request({method:"eth_signTypedData_v4",params:[o,JSON.stringify(w)]}),O={x402Version:2,scheme:"exact",network:e.network,resource:{url:this.opts.endpoint,mimeType:"application/json"},accepted:e,payload:{signature:Q,authorization:{from:o,to:e.payTo,value:e.amount,validAfter:String(d),validBefore:String(u),nonce:c}}},M=W(this.challenge);M&&(O.extensions={"builder-code":M});const ee=ie(O);await this.executePaid(ee)}catch(t){this.spendReservation&&(z(this.spendReservation),this.spendReservation=null),this.renderError(this.payerAddress?"authorize":"connect",g(t))}}async executePaid(e,t=0){this.renderProgress("verify",{text:t?"Retrying after upstream throttle\u2026":"Calling merchant endpoint\u2026"});try{const r=await fetch(this.opts.endpoint,{method:this.opts.method||"GET",headers:{...this.opts.headers||{},...this.opts.body&&!this.opts.headers?.["content-type"]?{"content-type":"application/json"}:{},"X-PAYMENT":e},body:this.opts.body?typeof this.opts.body=="string"?this.opts.body:JSON.stringify(this.opts.body):void 0}),o=r.headers.get("content-type")||"",s=await r.text();let i;if(o.includes("json"))try{i=JSON.parse(s)}catch{i=s}else i=s;if(!r.ok){if(r.status===429&&t<ge)return await this.waitForThrottle(we(r,i)),this.executePaid(e,t+1);const d=i&&typeof i=="object"&&(i.error_description||i.error)||`HTTP ${r.status}`;throw new Error(d)}const a=r.headers.get("x-payment-response"),l=I(a)||{};this.spendReservation=null,this.renderDone({result:i,payment:l}),this.resolve?.({ok:!0,result:i,payment:l,response:{status:r.status,headers:Y(r.headers)}})}catch(r){this.spendReservation&&(z(this.spendReservation),this.spendReservation=null),this.renderError("verify",g(r))}}async waitForThrottle(e){const t=Math.max(1,Math.min(30,Math.round(e)||6));for(let r=t;r>0;r--)this.renderProgress("verify",{text:`Generator is busy \u2014 retrying in ${r}s\u2026`}),await new Promise(o=>setTimeout(o,1e3));this.renderProgress("verify",{text:"Retrying\u2026"})}async runSiwxEvm(e){this.renderProgress("connect",{text:"Opening browser wallet\u2026"});try{const t=window.ethereum;if(!t)throw new Error("No EVM wallet detected");const o=(await t.request({method:"eth_requestAccounts"}))?.[0];if(!o)throw new Error("Wallet did not return an account");const i=(await xe())(o);this.payerAddress=i,this.renderProgress("authorize",{text:`Sign sign-in message as ${i.slice(0,6)}\u2026${i.slice(-4)}`});const a=V(this.siwx.info,e,i),l=await t.request({method:"personal_sign",params:[a,i]}),d=this.siwx.info,u={domain:d.domain,address:i,...d.statement?{statement:d.statement}:{},uri:d.uri,version:d.version||"1",chainId:e.chainId,type:"eip191",nonce:d.nonce,issuedAt:d.issuedAt,...d.expirationTime?{expirationTime:d.expirationTime}:{},...d.notBefore?{notBefore:d.notBefore}:{},...d.requestId!==void 0&&d.requestId!==null?{requestId:d.requestId}:{},...Array.isArray(d.resources)?{resources:d.resources}:{},signatureScheme:"eip191",signature:l};await this.executeSiwx(u,e.chainId)}catch(t){this.renderError(this.payerAddress?"authorize":"connect",g(t))}}async runSiwxSolana(e){this.renderProgress("connect",{text:"Opening Phantom\u2026"});try{const t=window.phantom?.solana||window.solana;if(!t)throw new Error("Phantom wallet not detected");const s=((await t.connect())?.publicKey||t.publicKey)?.toString();if(!s)throw new Error("Phantom did not return a public key");this.payerAddress=s,this.renderProgress("authorize",{text:`Sign sign-in message as ${s.slice(0,6)}\u2026${s.slice(-4)}`});const i=V(this.siwx.info,e,s),a=new TextEncoder().encode(i),l=await t.signMessage(a,"utf8"),d=l?.signature instanceof Uint8Array?l.signature:new Uint8Array(l?.signature||l);if(!d||!d.length)throw new Error("Phantom did not return a signature");const u=he(d),c=this.siwx.info,p={domain:c.domain,address:s,...c.statement?{statement:c.statement}:{},uri:c.uri,version:c.version||"1",chainId:e.chainId,type:"ed25519",nonce:c.nonce,issuedAt:c.issuedAt,...c.expirationTime?{expirationTime:c.expirationTime}:{},...c.notBefore?{notBefore:c.notBefore}:{},...c.requestId!==void 0&&c.requestId!==null?{requestId:c.requestId}:{},...Array.isArray(c.resources)?{resources:c.resources}:{},signatureScheme:"siws",signature:u};await this.executeSiwx(p,e.chainId)}catch(t){this.renderError(this.payerAddress?"authorize":"connect",g(t))}}async executeSiwx(e,t){this.renderProgress("verify",{text:"Verifying sign-in\u2026"});const r=pe(e);let o;try{o=await fetch(this.opts.endpoint,{method:this.opts.method||"GET",headers:{...this.opts.headers||{},...this.opts.body&&!this.opts.headers?.["content-type"]?{"content-type":"application/json"}:{},[ne]:r},body:this.opts.body?typeof this.opts.body=="string"?this.opts.body:JSON.stringify(this.opts.body):void 0})}catch(i){this.renderError("verify",g(i));return}if(o.status===200){const i=o.headers.get("content-type")||"",a=await o.text();let l;if(i.includes("json"))try{l=JSON.parse(a)}catch{l=a}else l=a;const d={address:e.address,network:t};this.renderDone({result:l,siwx:d}),this.resolve?.({ok:!0,result:l,siwx:d,response:{status:o.status,headers:Y(o.headers)}});return}if(o.status===401||o.status===402){let i=null;try{i=await o.clone().json()}catch{}const a=i?.code||i?.error;this.siwx=null,this.payerAddress=null,this.payFlowOverride=!1,this.siwxFallbackNotice=a==="siwx_not_paid"||o.status===402?"You haven't paid for this yet \u2014 pay now to unlock re-entry.":"Sign-in not accepted \u2014 please pay to continue.",!this.challenge||!Array.isArray(this.challenge.accepts)||!this.challenge.accepts.length?this.start():this.renderConnect();return}const s=await o.text().catch(()=>"");this.renderError("verify",`SIWX retry failed: HTTP ${o.status}${s?` \xB7 ${s.slice(0,120)}`:""}`)}}function f(n){return String(n??"").replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}function Y(n){const e={};return n.forEach((t,r)=>e[r]=t),e}const ge=2;function we(n,e,t=6){const r=Number.parseInt(n.headers.get("retry-after")||"",10);if(Number.isFinite(r)&&r>0)return r;const o=e&&typeof e=="object"?Number(e.retry_after):NaN;return Number.isFinite(o)&&o>0?o:t}function g(n){const e=n?.shortMessage||n?.message||String(n);return/user rejected|user denied|reject/i.test(e)?"cancelled in wallet":/throttl|rate.?limit|too many requests|less than \$|in credit|\b429\b/i.test(e)?"The service is briefly busy and your payment was not taken \u2014 retry in a few seconds.":/dynamically imported module|esm\.sh|module script failed/i.test(e)?"A component this wallet path needs (loaded from esm.sh) was blocked \u2014 often by a strict host security policy. Pay with MetaMask on Base instead; it needs no third-party code.":e.slice(0,240)}function ve(n){if(typeof Buffer<"u")return new Uint8Array(Buffer.from(n,"base64"));const e=atob(n),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t}function ke(n){if(typeof Buffer<"u")return Buffer.from(n).toString("base64");let e="";for(let t=0;t<n.length;t++)e+=String.fromCharCode(n[t]);return btoa(e)}function Se(n){const e=new Uint8Array(n);return crypto.getRandomValues(e),Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}let $=null;async function Ee(){return $||($=await import(h.esm.solanaWeb3),$)}async function X(n,e){const t=await fetch(n,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)}),r=await t.text();let o;try{o=JSON.parse(r)}catch{o={error:"parse_error",error_description:r.slice(0,200)}}if(!t.ok){const s=new Error(o.error_description||o.error||`HTTP ${t.status}`);throw s.status=t.status,s.data=o,s}return o}async function $e(n){const e={...n.headers||{}},t={method:n.method||"GET",headers:e,body:n.body?typeof n.body=="string"?n.body:JSON.stringify(n.body):void 0};t.body&&!e["content-type"]&&(e["content-type"]="application/json");const r=await fetch(n.endpoint,t),o=r.headers.get("payment-required"),s=r.status===401&&!!o;if(r.status!==402&&!s){const a=await r.text();throw new Error(`Endpoint did not return 402 (got ${r.status}). Body: ${a.slice(0,120)}`)}let i=s?I(o):await r.json().catch(()=>null);if(!i||!Array.isArray(i.accepts)||!i.accepts.length){const a=I(o);a&&Array.isArray(a.accepts)&&a.accepts.length&&(i=a)}if(!i||!Array.isArray(i.accepts)||!i.accepts.length)throw new Error("Endpoint returned 402 but no `accepts` array could be found in body or header");return i}async function Z(n){if(!n?.endpoint)throw new Error("X402.pay: endpoint is required");const e=new ye(n),t=e.mount();return queueMicrotask(()=>e.start()),t}function Ae(n){n.dataset.x402Bound!=="1"&&(n.dataset.x402Bound="1",n.addEventListener("click",async e=>{e.preventDefault();const t=Ce(n);try{const r=await Z(t);r?.siwx&&n.dispatchEvent(new CustomEvent("x402:siwx-signed",{detail:r.siwx,bubbles:!0})),n.dispatchEvent(new CustomEvent("x402:result",{detail:r,bubbles:!0}))}catch(r){if(r?.code==="cancelled")return;n.dispatchEvent(new CustomEvent("x402:error",{detail:{error:r?.message||String(r)},bubbles:!0}))}}))}function Ce(n){const e=n.dataset;let t=e.x402Body;if(t)try{t=JSON.parse(t)}catch{}let r=e.x402Headers;if(r)try{r=JSON.parse(r)}catch{r=void 0}return{endpoint:e.x402Endpoint,method:e.x402Method||(t?"POST":"GET"),body:t,headers:r,merchant:e.x402Merchant,action:e.x402Action||n.textContent?.trim().slice(0,60)}}function A(){document.querySelectorAll("[data-x402-endpoint]").forEach(Ae)}function Te(){try{const e=(document.currentScript||document.querySelector('script[src*="x402"][type="module"]')||document.querySelector("script[data-x402-checkout-origin]"))?.dataset;if(!e)return;const t={};e.x402CheckoutOrigin&&(t.checkoutOrigin=e.x402CheckoutOrigin),e.x402CheckoutPath&&(t.checkoutPath=e.x402CheckoutPath),e.x402FooterNote&&(t.footerNote=e.x402FooterNote),(e.x402BrandName||e.x402BrandUrl)&&(t.brand={},e.x402BrandName&&(t.brand.name=e.x402BrandName),e.x402BrandUrl&&(t.brand.url=e.x402BrandUrl)),(e.x402BuilderWallet||e.x402BuilderService)&&(t.builderCode={},e.x402BuilderWallet&&(t.builderCode.wallet=e.x402BuilderWallet),e.x402BuilderService&&(t.builderCode.service=e.x402BuilderService)),Object.keys(t).length&&j(t)}catch{}}typeof document<"u"&&(Te(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",A,{once:!0}):A(),new MutationObserver(()=>A()).observe(document.documentElement,{childList:!0,subtree:!0})),typeof window<"u"&&(window.X402=Object.freeze({pay:Z,init:A,configure:j,version:te,tokens:Object.freeze({USDC_MINT_SOLANA:T,THREE_MINT:P,KNOWN_SOLANA_TOKENS:B})}));export{B as KNOWN_SOLANA_TOKENS,P as THREE_MINT,T as USDC_MINT_SOLANA,j as configure,A as init,Z as pay};
505
+ `;const i=this.bodyEl.querySelector("[data-done]");i.addEventListener("click",()=>this.close("done")),requestAnimationFrame(()=>i.focus())}async start(){this.bodyEl.innerHTML=this.renderSteps("discover"),this.priceEl.innerHTML='<span class="x402-skeleton" style="display:inline-block;width:92px;height:26px;vertical-align:middle"></span>',this.networkEl.innerHTML='<span class="x402-skeleton" style="display:inline-block;width:58px;height:11px;border-radius:99px"></span>',ie().catch(()=>{});try{const e=await Le(this.opts);this.challenge=e,this.siwx=ke(e),this.payFlowOverride=!1,this.siwxFallbackNotice=null;const t=F(e),r=V(t);this.solanaAccept=r;const o=e.accepts.find(K),s=typeof window<"u"&&(window.solana?.isPhantom||window.phantom?.solana);this.accept=s&&r||o||e.accepts[0],this.setPrice(this.accept),this.renderConnect()}catch(e){this.renderError("discover",e.message||String(e))}}async runSolana(e,t){this.accept=e,this.setPrice(e);const r=t||window.phantom?.solana||window.solana,o=r?.isPhantom?"Phantom":this._solWallets?.find(s=>s.provider===r)?.name||"wallet";this.renderProgress("connect",{text:`Opening ${o}\u2026`});try{if(!r)throw new Error("No Solana wallet detected");const a=((await r.connect())?.publicKey||r.publicKey)?.toString();if(!a)throw new Error("Phantom did not return a public key");this.payerAddress=a;const i=G({accept:e,caps:this.opts.caps,address:a});if(i.abort){this.renderError("authorize",i.reason);return}this.spendReservation=i.reservation||null,this.renderProgress("authorize",{text:`Building Solana payment for ${a.slice(0,6)}\u2026${a.slice(-4)}`});const l=await ce(`${U()}?action=prepare`,{accept:e,buyer:a});this.renderProgress("authorize",{text:"Confirm in Phantom\u2026"});const c=Me(l.tx_base64),h=(await ie()).VersionedTransaction.deserialize(c),y=await r.signTransaction(h),$=je(y.serialize()),S=X(this.challenge),A=await ce(`${U()}?action=encode`,{accept:e,signed_tx_base64:$,resource_url:new URL(this.opts.endpoint,location.href).href,...S?{builder_code:S}:{}});await this.executePaid(A.x_payment)}catch(s){this.spendReservation&&(D(this.spendReservation),this.spendReservation=null),this.renderError(this.payerAddress?"authorize":"connect",E(s))}}async runEvm(e,t){this.accept=e,this.setPrice(e),this.renderProgress("connect",{text:"Opening browser wallet\u2026"});try{const r=t||window.ethereum;if(!r)throw new Error("No EVM wallet detected");const s=(await r.request({method:"eth_requestAccounts"}))?.[0];if(!s)throw new Error("Wallet did not return an account");this.payerAddress=s;const a=G({accept:e,caps:this.opts.caps,address:s});if(a.abort){this.renderError("authorize",a.reason);return}this.spendReservation=a.reservation||null;const i=z[e.network];if(!i)throw new Error(`Unknown EVM network ${e.network}`);const l=await r.request({method:"eth_chainId"}),c="0x"+i.chainId.toString(16);if(l!==c){this.renderProgress("connect",{text:`Switch wallet to ${i.name}\u2026`});try{await r.request({method:"wallet_switchEthereumChain",params:[{chainId:c}]})}catch{throw new Error(`Wallet is on ${l}; please switch to ${i.name} (${c}) and retry`)}}this.renderProgress("authorize",{text:`Authorize ${C(e.amount)} USDC\u2026`});const w=0,h=Math.floor(Date.now()/1e3)+(e.maxTimeoutSeconds||600),y="0x"+se(32),$={name:e.extra?.name||"USD Coin",version:e.extra?.version||"2",chainId:i.chainId,verifyingContract:e.asset},S={EIP712Domain:[{name:"name",type:"string"},{name:"version",type:"string"},{name:"chainId",type:"uint256"},{name:"verifyingContract",type:"address"}],TransferWithAuthorization:[{name:"from",type:"address"},{name:"to",type:"address"},{name:"value",type:"uint256"},{name:"validAfter",type:"uint256"},{name:"validBefore",type:"uint256"},{name:"nonce",type:"bytes32"}]},A={from:s,to:e.payTo,value:e.amount,validAfter:w,validBefore:h,nonce:y},x={primaryType:"TransferWithAuthorization",types:S,domain:$,message:A},d=await r.request({method:"eth_signTypedData_v4",params:[s,JSON.stringify(x)]}),f={x402Version:2,scheme:"exact",network:e.network,resource:{url:this.opts.endpoint,mimeType:"application/json"},accepted:e,payload:{signature:d,authorization:{from:s,to:e.payTo,value:e.amount,validAfter:String(w),validBefore:String(h),nonce:y}}},b=X(this.challenge);b&&(f.extensions={"builder-code":b});const g=be(f);await this.executePaid(g)}catch(r){this.spendReservation&&(D(this.spendReservation),this.spendReservation=null),this.renderError(this.payerAddress?"authorize":"connect",E(r))}}async executePaid(e,t=0){this.renderProgress("verify",{text:t?"Retrying after upstream throttle\u2026":"Calling merchant endpoint\u2026"}),this.idempotencyKey||(this.idempotencyKey=`x402-${se(16)}`);try{const r=await fetch(this.opts.endpoint,{method:this.opts.method||"GET",headers:{...this.opts.headers||{},...this.opts.body&&!this.opts.headers?.["content-type"]?{"content-type":"application/json"}:{},"X-PAYMENT":e,"Idempotency-Key":this.idempotencyKey,"X-Idempotency-Key":this.idempotencyKey},body:this.opts.body?typeof this.opts.body=="string"?this.opts.body:JSON.stringify(this.opts.body):void 0}),o=r.headers.get("content-type")||"",s=await r.text();let a;if(o.includes("json"))try{a=JSON.parse(s)}catch{a=s}else a=s;if(!r.ok){if(r.status===429&&t<_e)return await this.waitForThrottle(ze(r,a)),this.executePaid(e,t+1);const c=a&&typeof a=="object"&&(a.error_description||a.error)||`HTTP ${r.status}`;throw new Error(c)}const i=r.headers.get("x-payment-response"),l=q(i)||{};this.spendReservation=null,this.renderDone({result:a,payment:l}),this.resolve?.({ok:!0,result:a,payment:l,response:{status:r.status,headers:oe(r.headers)}})}catch(r){this.spendReservation&&(D(this.spendReservation),this.spendReservation=null),this.renderError("verify",E(r))}}async waitForThrottle(e){const t=Math.max(1,Math.min(30,Math.round(e)||6));for(let r=t;r>0;r--)this.renderProgress("verify",{text:`Generator is busy \u2014 retrying in ${r}s\u2026`}),await new Promise(o=>setTimeout(o,1e3));this.renderProgress("verify",{text:"Retrying\u2026"})}async runSiwxEvm(e){this.renderProgress("connect",{text:"Opening browser wallet\u2026"});try{const t=window.ethereum;if(!t)throw new Error("No EVM wallet detected");const o=(await t.request({method:"eth_requestAccounts"}))?.[0];if(!o)throw new Error("Wallet did not return an account");const a=(await $e())(o);this.payerAddress=a,this.renderProgress("authorize",{text:`Sign sign-in message as ${a.slice(0,6)}\u2026${a.slice(-4)}`});const i=Q(this.siwx.info,e,a),l=await t.request({method:"personal_sign",params:[i,a]}),c=this.siwx.info,w={domain:c.domain,address:a,...c.statement?{statement:c.statement}:{},uri:c.uri,version:c.version||"1",chainId:e.chainId,type:"eip191",nonce:c.nonce,issuedAt:c.issuedAt,...c.expirationTime?{expirationTime:c.expirationTime}:{},...c.notBefore?{notBefore:c.notBefore}:{},...c.requestId!==void 0&&c.requestId!==null?{requestId:c.requestId}:{},...Array.isArray(c.resources)?{resources:c.resources}:{},signatureScheme:"eip191",signature:l};await this.executeSiwx(w,e.chainId)}catch(t){this.renderError(this.payerAddress?"authorize":"connect",E(t))}}async runSiwxSolana(e){this.renderProgress("connect",{text:"Opening Phantom\u2026"});try{const t=window.phantom?.solana||window.solana;if(!t)throw new Error("Phantom wallet not detected");const s=((await t.connect())?.publicKey||t.publicKey)?.toString();if(!s)throw new Error("Phantom did not return a public key");this.payerAddress=s,this.renderProgress("authorize",{text:`Sign sign-in message as ${s.slice(0,6)}\u2026${s.slice(-4)}`});const a=Q(this.siwx.info,e,s),i=new TextEncoder().encode(a),l=await t.signMessage(i,"utf8"),c=l?.signature instanceof Uint8Array?l.signature:new Uint8Array(l?.signature||l);if(!c||!c.length)throw new Error("Phantom did not return a signature");const w=Ee(c),h=this.siwx.info,y={domain:h.domain,address:s,...h.statement?{statement:h.statement}:{},uri:h.uri,version:h.version||"1",chainId:e.chainId,type:"ed25519",nonce:h.nonce,issuedAt:h.issuedAt,...h.expirationTime?{expirationTime:h.expirationTime}:{},...h.notBefore?{notBefore:h.notBefore}:{},...h.requestId!==void 0&&h.requestId!==null?{requestId:h.requestId}:{},...Array.isArray(h.resources)?{resources:h.resources}:{},signatureScheme:"siws",signature:w};await this.executeSiwx(y,e.chainId)}catch(t){this.renderError(this.payerAddress?"authorize":"connect",E(t))}}async executeSiwx(e,t){this.renderProgress("verify",{text:"Verifying sign-in\u2026"});const r=Se(e);let o;try{o=await fetch(this.opts.endpoint,{method:this.opts.method||"GET",headers:{...this.opts.headers||{},...this.opts.body&&!this.opts.headers?.["content-type"]?{"content-type":"application/json"}:{},[xe]:r},body:this.opts.body?typeof this.opts.body=="string"?this.opts.body:JSON.stringify(this.opts.body):void 0})}catch(a){this.renderError("verify",E(a));return}if(o.status===200){const a=o.headers.get("content-type")||"",i=await o.text();let l;if(a.includes("json"))try{l=JSON.parse(i)}catch{l=i}else l=i;const c={address:e.address,network:t};this.renderDone({result:l,siwx:c}),this.resolve?.({ok:!0,result:l,siwx:c,response:{status:o.status,headers:oe(o.headers)}});return}if(o.status===401||o.status===402){let a=null;try{a=await o.clone().json()}catch{}const i=a?.code||a?.error;this.siwx=null,this.payerAddress=null,this.payFlowOverride=!1,this.siwxFallbackNotice=i==="siwx_not_paid"||o.status===402?"You haven't paid for this yet \u2014 pay now to unlock re-entry.":"Sign-in not accepted \u2014 please pay to continue.",!this.challenge||!Array.isArray(this.challenge.accepts)||!this.challenge.accepts.length?this.start():this.renderConnect();return}const s=await o.text().catch(()=>"");this.renderError("verify",`SIWX retry failed: HTTP ${o.status}${s?` \xB7 ${s.slice(0,120)}`:""}`)}}function u(n){return String(n??"").replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}function oe(n){const e={};return n.forEach((t,r)=>e[r]=t),e}const _e=2;function ze(n,e,t=6){const r=Number.parseInt(n.headers.get("retry-after")||"",10);if(Number.isFinite(r)&&r>0)return r;const o=e&&typeof e=="object"?Number(e.retry_after):NaN;return Number.isFinite(o)&&o>0?o:t}function E(n){const e=n?.shortMessage||n?.message||String(n);return/user rejected|user denied|reject/i.test(e)?"cancelled in wallet":/throttl|rate.?limit|too many requests|less than \$|in credit|\b429\b/i.test(e)?"The service is briefly busy and your payment was not taken \u2014 retry in a few seconds.":/dynamically imported module|esm\.sh|module script failed/i.test(e)?"A component this wallet path needs (loaded from esm.sh) was blocked \u2014 often by a strict host security policy. Pay with MetaMask on Base instead; it needs no third-party code.":e.slice(0,240)}function Me(n){if(typeof Buffer<"u")return new Uint8Array(Buffer.from(n,"base64"));const e=atob(n),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t}function je(n){if(typeof Buffer<"u")return Buffer.from(n).toString("base64");let e="";for(let t=0;t<n.length;t++)e+=String.fromCharCode(n[t]);return btoa(e)}function se(n){const e=new Uint8Array(n);return crypto.getRandomValues(e),Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}async function ae(n,e,t){const r=new Set,o=[n,...e].filter(a=>a&&!r.has(a)&&r.add(a));let s;for(const a of o)try{return await Promise.race([import(a),new Promise((i,l)=>setTimeout(()=>l(new Error(`timed out loading ${t} from ${a}`)),ue))])}catch(i){s=i}throw s||new Error(`could not load ${t} from any CDN`)}let I=null;async function ie(){return I||(I=await ae(p.esm.solanaWeb3,H.solanaWeb3,"@solana/web3.js"),I)}async function ce(n,e){const t=await fetch(n,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)}),r=await t.text();let o;try{o=JSON.parse(r)}catch{o={error:"parse_error",error_description:r.slice(0,200)}}if(!t.ok){const s=new Error(o.error_description||o.error||`HTTP ${t.status}`);throw s.status=t.status,s.data=o,s}return o}async function Le(n){const e={...n.headers||{}},t={method:n.method||"GET",headers:e,body:n.body?typeof n.body=="string"?n.body:JSON.stringify(n.body):void 0};t.body&&!e["content-type"]&&(e["content-type"]="application/json");const r=await fetch(n.endpoint,t),o=r.headers.get("payment-required"),s=r.status===401&&!!o;if(r.status!==402&&!s){const i=await r.text();throw new Error(`Endpoint did not return 402 (got ${r.status}). Body: ${i.slice(0,120)}`)}let a=s?q(o):await r.json().catch(()=>null);if(!a||!Array.isArray(a.accepts)||!a.accepts.length){const i=q(o);i&&Array.isArray(i.accepts)&&i.accepts.length&&(a=i)}if(!a||!Array.isArray(a.accepts)||!a.accepts.length)throw new Error("Endpoint returned 402 but no `accepts` array could be found in body or header");return a}async function le(n){if(!n?.endpoint)throw new Error("X402.pay: endpoint is required");const e=new Ie(n),t=e.mount();return queueMicrotask(()=>e.start()),t}function Oe(n){n.dataset.x402Bound!=="1"&&(n.dataset.x402Bound="1",n.addEventListener("click",async e=>{e.preventDefault();const t=qe(n);try{const r=await le(t);r?.siwx&&n.dispatchEvent(new CustomEvent("x402:siwx-signed",{detail:r.siwx,bubbles:!0})),n.dispatchEvent(new CustomEvent("x402:result",{detail:r,bubbles:!0}))}catch(r){if(r?.code==="cancelled")return;n.dispatchEvent(new CustomEvent("x402:error",{detail:{error:r?.message||String(r)},bubbles:!0}))}}))}function qe(n){const e=n.dataset;let t=e.x402Body;if(t)try{t=JSON.parse(t)}catch{}let r=e.x402Headers;if(r)try{r=JSON.parse(r)}catch{r=void 0}return{endpoint:e.x402Endpoint,method:e.x402Method||(t?"POST":"GET"),body:t,headers:r,merchant:e.x402Merchant,action:e.x402Action||n.textContent?.trim().slice(0,60)}}function _(){document.querySelectorAll("[data-x402-endpoint]").forEach(Oe)}function De(){try{const e=(document.currentScript||document.querySelector('script[src*="x402"][type="module"]')||document.querySelector("script[data-x402-checkout-origin]"))?.dataset;if(!e)return;const t={};e.x402CheckoutOrigin&&(t.checkoutOrigin=e.x402CheckoutOrigin),e.x402CheckoutPath&&(t.checkoutPath=e.x402CheckoutPath),e.x402FooterNote&&(t.footerNote=e.x402FooterNote),(e.x402BrandName||e.x402BrandUrl)&&(t.brand={},e.x402BrandName&&(t.brand.name=e.x402BrandName),e.x402BrandUrl&&(t.brand.url=e.x402BrandUrl)),(e.x402BuilderWallet||e.x402BuilderService)&&(t.builderCode={},e.x402BuilderWallet&&(t.builderCode.wallet=e.x402BuilderWallet),e.x402BuilderService&&(t.builderCode.service=e.x402BuilderService)),Object.keys(t).length&&W(t)}catch{}}typeof document<"u"&&(De(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",_,{once:!0}):_(),new MutationObserver(()=>_()).observe(document.documentElement,{childList:!0,subtree:!0})),typeof window<"u"&&(window.X402=Object.freeze({pay:le,init:_,configure:W,version:de,tokens:Object.freeze({USDC_MINT_SOLANA:M,THREE_MINT:j,KNOWN_SOLANA_TOKENS:L})}));export{L as KNOWN_SOLANA_TOKENS,j as THREE_MINT,M as USDC_MINT_SOLANA,W as configure,_ as init,le as pay};