@three-ws/x402-modal 0.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/LICENSE +180 -0
- package/README.md +306 -0
- package/TUTORIAL.md +281 -0
- package/dist/x402-modal.mjs +1371 -0
- package/dist/x402-modal.mjs.map +7 -0
- package/dist/x402.global.js +353 -0
- package/dist/x402.global.js.map +7 -0
- package/docs/BACKEND.md +163 -0
- package/docs/CONFIGURATION.md +106 -0
- package/docs/PROTOCOL.md +102 -0
- package/package.json +75 -0
- package/src/global.js +64 -0
- package/src/util.js +147 -0
- package/src/x402-modal.js +1446 -0
- package/types/index.d.ts +149 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"use strict";var X402Modal=(()=>{var O=Object.defineProperty;var oe=Object.getOwnPropertyDescriptor;var ie=Object.getOwnPropertyNames;var ae=Object.prototype.hasOwnProperty;var se=(n,e)=>{for(var t in e)O(n,t,{get:e[t],enumerable:!0})},ce=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of ie(e))!ae.call(n,o)&&o!==t&&O(n,o,{get:()=>e[o],enumerable:!(r=oe(e,o))||r.enumerable});return n};var de=n=>ce(O({},"__esModule",{value:!0}),n);var Ne={};se(Ne,{configure:()=>B,init:()=>m,pay:()=>T,version:()=>H});var v={"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/"}},le=new Set(["usdc","usd coin","usdt","tether","binance-peg usd coin","dai"]);function q(n){if(!n||typeof n!="object")return n;let e=n.amount??n.maxAmountRequired;return e!=null&&n.amount==null?{...n,amount:String(e)}:n}function g(n){return typeof n=="string"&&(n==="solana"||n.startsWith("solana:"))}function ue(n){return typeof n=="string"&&n.startsWith("eip155:")}function U(n){if(!ue(n?.network))return!1;let e=n?.extra?.assetTransferMethod;return!e||e==="eip3009"}function h(n,e){return g(n)?"Solana":v[n]?.name||e?.extra?.name||n}function R(n,e){if(!e)return null;if(g(n))return`https://solscan.io/tx/${e}`;let t=v[n];return t?`${t.explorer}${e}`:null}function k(n,e=6){let 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 j(n){let e=JSON.stringify(n);return typeof Buffer<"u"?Buffer.from(e,"utf8").toString("base64"):btoa(unescape(encodeURIComponent(e)))}function S(n){if(!n)return null;try{let e=typeof Buffer<"u"?Buffer.from(n,"base64").toString("utf8"):decodeURIComponent(escape(atob(n)));return JSON.parse(e)}catch{return null}}var D="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";function W(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=D[Number(t%58n)]+r,t/=58n;for(let o=0;o<e;o++)r=D[0]+r;return r}function F(n,e){let t=BigInt(n),r=Number(e?.extra?.decimals??6),o=String(e?.extra?.name||"").toLowerCase();return le.has(o)?r===6?t:r>6?t/10n**BigInt(r-6):t*10n**BigInt(6-r):t}function J(n=Date.now()){let e=Math.floor(n/36e5),t=Math.floor(n/864e5);return{hour:e,day:t}}function N(n,e,t){let 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(let d of n.resources)a.push(`- ${d}`)}return a.join(`
|
|
2
|
+
`)}var H="0.2.0",x={apiOrigin:null,brand:{label:"Powered by three.ws",href:"https://three.ws"},builderCode:{wallet:"3d_agent",service:"3d_agent_modal"},solanaWeb3Url:"https://esm.sh/@solana/web3.js@1.95.3?bundle",nobleHashesUrl:"https://esm.sh/@noble/hashes@1.4.0/sha3?bundle"},l={apiOrigin:x.apiOrigin,brand:{...x.brand},builderCode:x.builderCode?{...x.builderCode}:null,solanaWeb3Url:x.solanaWeb3Url,nobleHashesUrl:x.nobleHashesUrl};function pe(){try{if(typeof document<"u"){let n=document.currentScript;if(n?.src)return new URL(n.src).origin;let e=document.querySelector('script[src*="x402"]');if(e?.src)return new URL(e.src).origin}}catch{}return typeof location<"u"?location.origin:""}function B(n={}){return!n||typeof n!="object"||(n.apiOrigin!==void 0&&(l.apiOrigin=n.apiOrigin),n.brand&&(l.brand={...l.brand,...n.brand}),n.builderCode===null?l.builderCode=null:n.builderCode&&(l.builderCode={...l.builderCode||{},...n.builderCode}),n.solanaWeb3Url&&(l.solanaWeb3Url=n.solanaWeb3Url),n.nobleHashesUrl&&(l.nobleHashesUrl=n.nobleHashesUrl)),V()}function V(){return{apiOrigin:l.apiOrigin,brand:{...l.brand},builderCode:l.builderCode?{...l.builderCode}:null,solanaWeb3Url:l.solanaWeb3Url,nobleHashesUrl:l.nobleHashesUrl}}function fe(n){return n&&n.apiOrigin!==void 0&&n.apiOrigin!==null?n.apiOrigin:(l.apiOrigin!==null&&l.apiOrigin!==void 0||(l.apiOrigin=pe()),l.apiOrigin)}var he="SIGN-IN-WITH-X",xe="sign-in-with-x",be="x402.spend.";function ee(n,e,t){return`${be}${e}.${n.toLowerCase()}.${t}`}function C(n,e,t){try{let r=localStorage.getItem(ee(n,e,t));return r?BigInt(r):0n}catch{return 0n}}function A(n,e,t,r){try{localStorage.setItem(ee(n,e,t),r.toString())}catch{}}function K({accept:n,caps:e,address:t}){if(!e||!t)return{abort:!1};let r=F(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)`};let a=J(),d=C(t,"hr",a.hour)+r,c=C(t,"day",a.day)+r;return s!=null&&d>s?{abort:!0,reason:`Hourly cap exceeded (${d} > ${s} \xB5USD)`}:i!=null&&c>i?{abort:!0,reason:`Daily cap exceeded (${c} > ${i} \xB5USD)`}:(A(t,"hr",a.hour,d),A(t,"day",a.day,c),{abort:!1,reservation:{address:t,microUsd:r,buckets:a}})}function _(n){if(!n)return;let{address:e,microUsd:t,buckets:r}=n,o=C(e,"hr",r.hour),s=C(e,"day",r.day),i=o-t,a=s-t;A(e,"hr",r.hour,i<0n?0n:i),A(e,"day",r.day,a<0n?0n:a)}var me="builder-code",I=/^[a-z0-9_]{1,32}$/;function Y(n){let e=l.builderCode;if(!e)return null;let r=n?.extensions?.[me]?.info?.a;if(!r||!I.test(r))return null;let o={a:r};return e.service&&I.test(e.service)&&(o.s=[e.service]),e.wallet&&I.test(e.wallet)&&(o.w=e.wallet),o}function ye(n){let e=n?.extensions?.[xe];return!e||!e.info||!Array.isArray(e.supportedChains)||!e.supportedChains.length?null:e}function X(n,e){for(let 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 ge(n){let e=JSON.stringify(n);return typeof Buffer<"u"?Buffer.from(e,"utf8").toString("base64"):btoa(unescape(encodeURIComponent(e)))}var E=null;async function we(){if(E)return E;let e=(await import(l.nobleHashesUrl)).keccak_256;return E=t=>{let r=String(t).toLowerCase().replace(/^0x/,"");if(!/^[0-9a-f]{40}$/.test(r))throw new Error(`invalid EVM address: ${t}`);let o=e(new TextEncoder().encode(r)),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}var G="x402-styles",ve=`
|
|
3
|
+
:root {
|
|
4
|
+
--x402-z: 2147483600;
|
|
5
|
+
}
|
|
6
|
+
.x402-overlay {
|
|
7
|
+
position: fixed; inset: 0;
|
|
8
|
+
background: rgba(8, 10, 18, 0.55);
|
|
9
|
+
backdrop-filter: blur(10px);
|
|
10
|
+
-webkit-backdrop-filter: blur(10px);
|
|
11
|
+
display: flex; align-items: center; justify-content: center;
|
|
12
|
+
z-index: var(--x402-z);
|
|
13
|
+
opacity: 0; transition: opacity 0.16s ease-out;
|
|
14
|
+
font-family: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
15
|
+
-webkit-font-smoothing: antialiased;
|
|
16
|
+
color: #0f0f0f;
|
|
17
|
+
}
|
|
18
|
+
.x402-overlay.x402-open { opacity: 1; }
|
|
19
|
+
.x402-overlay * { box-sizing: border-box; }
|
|
20
|
+
.x402-modal {
|
|
21
|
+
width: calc(100% - 32px); max-width: 420px;
|
|
22
|
+
background: #ffffff;
|
|
23
|
+
border-radius: 18px;
|
|
24
|
+
box-shadow: 0 24px 80px rgba(8, 10, 18, 0.28), 0 4px 16px rgba(8, 10, 18, 0.12);
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
transform: translateY(8px) scale(0.985);
|
|
27
|
+
transition: transform 0.18s ease-out;
|
|
28
|
+
display: flex; flex-direction: column;
|
|
29
|
+
max-height: calc(100dvh - 32px);
|
|
30
|
+
}
|
|
31
|
+
.x402-overlay.x402-open .x402-modal { transform: translateY(0) scale(1); }
|
|
32
|
+
.x402-head {
|
|
33
|
+
padding: 18px 20px 14px;
|
|
34
|
+
border-bottom: 1px solid #eef0f4;
|
|
35
|
+
display: flex; align-items: center; gap: 12px;
|
|
36
|
+
}
|
|
37
|
+
.x402-head .x402-merchant {
|
|
38
|
+
flex: 1; min-width: 0;
|
|
39
|
+
}
|
|
40
|
+
.x402-merchant .x402-name {
|
|
41
|
+
font-size: 12px; color: #5a6378; font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase;
|
|
42
|
+
margin-bottom: 2px;
|
|
43
|
+
}
|
|
44
|
+
.x402-merchant .x402-action {
|
|
45
|
+
font-size: 17px; font-weight: 700; color: #0f0f0f;
|
|
46
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
47
|
+
letter-spacing: -0.01em;
|
|
48
|
+
}
|
|
49
|
+
.x402-close {
|
|
50
|
+
width: 32px; height: 32px;
|
|
51
|
+
border-radius: 8px; border: none; background: #f3f4f7;
|
|
52
|
+
font-size: 16px; color: #5a6378; cursor: pointer;
|
|
53
|
+
display: flex; align-items: center; justify-content: center;
|
|
54
|
+
transition: background 0.12s;
|
|
55
|
+
}
|
|
56
|
+
.x402-close:hover { background: #e7e9ee; color: #0f0f0f; }
|
|
57
|
+
|
|
58
|
+
.x402-price-row {
|
|
59
|
+
padding: 18px 20px;
|
|
60
|
+
display: flex; align-items: baseline; justify-content: space-between;
|
|
61
|
+
background: linear-gradient(180deg, #fafbfc 0%, #ffffff 100%);
|
|
62
|
+
border-bottom: 1px solid #eef0f4;
|
|
63
|
+
}
|
|
64
|
+
.x402-price {
|
|
65
|
+
font-size: 32px; font-weight: 700; letter-spacing: -0.02em; color: #0f0f0f;
|
|
66
|
+
font-variant-numeric: tabular-nums;
|
|
67
|
+
}
|
|
68
|
+
.x402-price .x402-currency { font-size: 14px; color: #5a6378; font-weight: 600; margin-left: 6px; letter-spacing: 0; }
|
|
69
|
+
.x402-network {
|
|
70
|
+
font-size: 12px; color: #5a6378; font-weight: 500;
|
|
71
|
+
background: #f3f4f7; padding: 5px 10px; border-radius: 99px;
|
|
72
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
73
|
+
}
|
|
74
|
+
.x402-network::before {
|
|
75
|
+
content: ''; width: 6px; height: 6px; border-radius: 50%;
|
|
76
|
+
background: #22c55e;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.x402-body {
|
|
80
|
+
padding: 16px 20px 18px;
|
|
81
|
+
flex: 1 1 auto; overflow-y: auto;
|
|
82
|
+
display: flex; flex-direction: column; gap: 10px;
|
|
83
|
+
}
|
|
84
|
+
.x402-step {
|
|
85
|
+
display: flex; gap: 12px; align-items: flex-start;
|
|
86
|
+
padding: 10px 0;
|
|
87
|
+
}
|
|
88
|
+
.x402-step + .x402-step { border-top: 1px solid #f3f4f7; }
|
|
89
|
+
.x402-step-num {
|
|
90
|
+
width: 22px; height: 22px; flex: 0 0 auto;
|
|
91
|
+
border-radius: 50%; border: 1.5px solid #d0d4dd; background: #fff;
|
|
92
|
+
color: #5a6378;
|
|
93
|
+
font-size: 11px; font-weight: 700;
|
|
94
|
+
display: flex; align-items: center; justify-content: center;
|
|
95
|
+
}
|
|
96
|
+
.x402-step.x402-active .x402-step-num {
|
|
97
|
+
border-color: #0a84ff; background: #0a84ff; color: #fff;
|
|
98
|
+
animation: x402-spin 1.2s linear infinite;
|
|
99
|
+
}
|
|
100
|
+
.x402-step.x402-done .x402-step-num {
|
|
101
|
+
border-color: #22c55e; background: #22c55e; color: #fff;
|
|
102
|
+
}
|
|
103
|
+
.x402-step.x402-error .x402-step-num {
|
|
104
|
+
border-color: #ef4444; background: #ef4444; color: #fff;
|
|
105
|
+
}
|
|
106
|
+
@keyframes x402-spin {
|
|
107
|
+
from { box-shadow: 0 0 0 0 rgba(10, 132, 255, 0.4); }
|
|
108
|
+
to { box-shadow: 0 0 0 8px rgba(10, 132, 255, 0); }
|
|
109
|
+
}
|
|
110
|
+
.x402-step-body { flex: 1; min-width: 0; }
|
|
111
|
+
.x402-step-label { font-size: 14px; font-weight: 600; color: #0f0f0f; line-height: 1.35; }
|
|
112
|
+
.x402-step-meta { font-size: 12px; color: #5a6378; margin-top: 2px; font-feature-settings: 'tnum' 1; }
|
|
113
|
+
.x402-step.x402-error .x402-step-meta { color: #ef4444; }
|
|
114
|
+
|
|
115
|
+
.x402-wallet-buttons {
|
|
116
|
+
display: flex; flex-direction: column; gap: 8px;
|
|
117
|
+
margin-top: 4px;
|
|
118
|
+
}
|
|
119
|
+
.x402-wallet-btn {
|
|
120
|
+
width: 100%; padding: 13px 14px;
|
|
121
|
+
background: #ffffff; border: 1.5px solid #e2e5ec; border-radius: 11px;
|
|
122
|
+
font-size: 14px; font-weight: 600; color: #0f0f0f;
|
|
123
|
+
cursor: pointer; font-family: inherit;
|
|
124
|
+
display: flex; align-items: center; gap: 12px;
|
|
125
|
+
transition: border-color 0.12s, background 0.12s, transform 0.05s;
|
|
126
|
+
}
|
|
127
|
+
.x402-wallet-btn:hover:not(:disabled) { border-color: #0a84ff; background: #f7faff; }
|
|
128
|
+
.x402-wallet-btn:active:not(:disabled) { transform: translateY(1px); }
|
|
129
|
+
.x402-wallet-btn:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
130
|
+
.x402-wallet-icon {
|
|
131
|
+
width: 28px; height: 28px; flex: 0 0 auto;
|
|
132
|
+
border-radius: 7px;
|
|
133
|
+
display: flex; align-items: center; justify-content: center;
|
|
134
|
+
font-size: 16px;
|
|
135
|
+
background: #f3f4f7;
|
|
136
|
+
}
|
|
137
|
+
.x402-wallet-icon.x402-phantom { background: linear-gradient(135deg, #ab9ff2, #534bb1); color: #fff; }
|
|
138
|
+
.x402-wallet-icon.x402-metamask { background: linear-gradient(135deg, #f6851b, #e2761b); color: #fff; }
|
|
139
|
+
.x402-wallet-name { flex: 1; text-align: left; }
|
|
140
|
+
.x402-wallet-meta { font-size: 11px; color: #8a90a8; font-weight: 500; }
|
|
141
|
+
|
|
142
|
+
.x402-pay-btn {
|
|
143
|
+
width: 100%; padding: 14px 16px;
|
|
144
|
+
background: #0f0f0f; color: #fff; border: none;
|
|
145
|
+
border-radius: 12px;
|
|
146
|
+
font-size: 15px; font-weight: 700; font-family: inherit;
|
|
147
|
+
cursor: pointer; letter-spacing: -0.005em;
|
|
148
|
+
transition: background 0.12s, transform 0.05s;
|
|
149
|
+
margin-top: 4px;
|
|
150
|
+
display: flex; align-items: center; justify-content: center; gap: 8px;
|
|
151
|
+
}
|
|
152
|
+
.x402-pay-btn:hover:not(:disabled) { background: #1d1d1d; }
|
|
153
|
+
.x402-pay-btn:active:not(:disabled) { transform: translateY(1px); }
|
|
154
|
+
.x402-pay-btn:disabled { background: #c8ccd4; cursor: not-allowed; }
|
|
155
|
+
|
|
156
|
+
.x402-pay-secondary {
|
|
157
|
+
width: 100%; padding: 12px 14px;
|
|
158
|
+
background: #ffffff; color: #0f0f0f;
|
|
159
|
+
border: 1.5px solid #e2e5ec; border-radius: 11px;
|
|
160
|
+
font-size: 14px; font-weight: 600; font-family: inherit;
|
|
161
|
+
cursor: pointer; letter-spacing: -0.005em;
|
|
162
|
+
margin-top: 6px;
|
|
163
|
+
transition: border-color 0.12s, background 0.12s, transform 0.05s;
|
|
164
|
+
}
|
|
165
|
+
.x402-pay-secondary:hover:not(:disabled) { border-color: #0a84ff; background: #f7faff; }
|
|
166
|
+
.x402-pay-secondary:active:not(:disabled) { transform: translateY(1px); }
|
|
167
|
+
|
|
168
|
+
.x402-siwx-hint {
|
|
169
|
+
font-size: 11px; color: #5a6378; text-align: center;
|
|
170
|
+
margin-top: 8px; line-height: 1.4;
|
|
171
|
+
}
|
|
172
|
+
.x402-siwx-fallback {
|
|
173
|
+
font-size: 12px; color: #b45309; line-height: 1.45;
|
|
174
|
+
padding: 8px 10px; border-radius: 8px;
|
|
175
|
+
background: #fffbeb; border: 1px solid #fde68a;
|
|
176
|
+
margin-bottom: 6px;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.x402-error-box {
|
|
180
|
+
padding: 12px 14px; border-radius: 10px;
|
|
181
|
+
background: #fef2f2; border: 1px solid #fecaca; color: #b91c1c;
|
|
182
|
+
font-size: 13px; line-height: 1.45;
|
|
183
|
+
font-family: ui-monospace, "JetBrains Mono", Menlo, monospace;
|
|
184
|
+
word-break: break-word;
|
|
185
|
+
}
|
|
186
|
+
.x402-error-box strong { font-weight: 700; }
|
|
187
|
+
|
|
188
|
+
.x402-receipt {
|
|
189
|
+
padding: 14px 16px; border-radius: 12px;
|
|
190
|
+
background: linear-gradient(180deg, #f0fdf4 0%, #ffffff 100%);
|
|
191
|
+
border: 1px solid #bbf7d0;
|
|
192
|
+
}
|
|
193
|
+
.x402-receipt-title {
|
|
194
|
+
font-size: 11px; font-weight: 700; color: #15803d;
|
|
195
|
+
text-transform: uppercase; letter-spacing: 0.06em;
|
|
196
|
+
margin-bottom: 8px;
|
|
197
|
+
display: flex; align-items: center; gap: 6px;
|
|
198
|
+
}
|
|
199
|
+
.x402-receipt-title::before { content: '\u2713'; font-size: 14px; }
|
|
200
|
+
.x402-receipt-row {
|
|
201
|
+
display: flex; justify-content: space-between; gap: 12px;
|
|
202
|
+
font-size: 12px; padding: 2px 0;
|
|
203
|
+
font-family: ui-monospace, "JetBrains Mono", Menlo, monospace;
|
|
204
|
+
}
|
|
205
|
+
.x402-receipt-row .x402-k { color: #5a6378; }
|
|
206
|
+
.x402-receipt-row .x402-v { color: #0f0f0f; text-align: right; word-break: break-all; }
|
|
207
|
+
.x402-receipt-row a { color: #0a84ff; text-decoration: none; }
|
|
208
|
+
.x402-receipt-row a:hover { text-decoration: underline; }
|
|
209
|
+
|
|
210
|
+
.x402-result {
|
|
211
|
+
padding: 12px 14px; border-radius: 10px;
|
|
212
|
+
background: #fafbfc; border: 1px solid #e2e5ec;
|
|
213
|
+
max-height: 240px; overflow: auto;
|
|
214
|
+
font-family: ui-monospace, "JetBrains Mono", Menlo, monospace;
|
|
215
|
+
font-size: 12px; line-height: 1.5; color: #0f0f0f;
|
|
216
|
+
white-space: pre-wrap; word-break: break-word;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.x402-foot {
|
|
220
|
+
padding: 10px 20px 14px;
|
|
221
|
+
border-top: 1px solid #eef0f4;
|
|
222
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
223
|
+
font-size: 11px; color: #8a90a8;
|
|
224
|
+
}
|
|
225
|
+
.x402-foot a { color: #5a6378; text-decoration: none; font-weight: 600; }
|
|
226
|
+
.x402-foot a:hover { color: #0f0f0f; }
|
|
227
|
+
.x402-foot .x402-secure { display: flex; align-items: center; gap: 5px; }
|
|
228
|
+
.x402-foot .x402-secure::before { content: '\u{1F512}'; font-size: 10px; }
|
|
229
|
+
|
|
230
|
+
@media (max-width: 480px) {
|
|
231
|
+
.x402-modal { max-width: none; width: calc(100% - 16px); border-radius: 16px; }
|
|
232
|
+
.x402-price { font-size: 26px; }
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
@media (prefers-color-scheme: dark) {
|
|
236
|
+
.x402-overlay { color: #e6e8f0; }
|
|
237
|
+
.x402-modal { background: #161616; box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6); }
|
|
238
|
+
.x402-head, .x402-price-row, .x402-foot { border-color: #272727; }
|
|
239
|
+
.x402-step + .x402-step { border-top-color: #272727; }
|
|
240
|
+
.x402-merchant .x402-name { color: #8a90a8; }
|
|
241
|
+
.x402-merchant .x402-action, .x402-price, .x402-step-label { color: #e6e8f0; }
|
|
242
|
+
.x402-step-meta { color: #8a90a8; }
|
|
243
|
+
.x402-close { background: #222222; color: #8a90a8; }
|
|
244
|
+
.x402-close:hover { background: #2e2e2e; color: #e6e8f0; }
|
|
245
|
+
.x402-price-row { background: linear-gradient(180deg, #1d1d1d 0%, #161616 100%); }
|
|
246
|
+
.x402-network { background: #222222; color: #b0b6cc; }
|
|
247
|
+
.x402-wallet-btn { background: #1d1d1d; border-color: #2e2e2e; color: #e6e8f0; }
|
|
248
|
+
.x402-wallet-btn:hover:not(:disabled) { background: #252525; border-color: #0a84ff; }
|
|
249
|
+
.x402-wallet-icon { background: #2e2e2e; }
|
|
250
|
+
.x402-wallet-meta { color: #6b7088; }
|
|
251
|
+
.x402-pay-btn { background: #ffffff; color: #0f0f0f; }
|
|
252
|
+
.x402-pay-btn:hover:not(:disabled) { background: #e7e9ee; }
|
|
253
|
+
.x402-pay-btn:disabled { background: #2e2e2e; color: #5a6378; }
|
|
254
|
+
.x402-pay-secondary { background: #1d1d1d; border-color: #2e2e2e; color: #e6e8f0; }
|
|
255
|
+
.x402-pay-secondary:hover:not(:disabled) { background: #252525; border-color: #0a84ff; }
|
|
256
|
+
.x402-siwx-hint { color: #8a90a8; }
|
|
257
|
+
.x402-siwx-fallback { background: #2a1d10; border-color: #78350f; color: #fcd34d; }
|
|
258
|
+
.x402-step-num { background: #161616; border-color: #2e2e2e; color: #8a90a8; }
|
|
259
|
+
.x402-result { background: #1d1d1d; border-color: #2e2e2e; color: #e6e8f0; }
|
|
260
|
+
.x402-receipt { background: linear-gradient(180deg, #0b1f17 0%, #161616 100%); border-color: #14532d; }
|
|
261
|
+
.x402-receipt-title { color: #4ade80; }
|
|
262
|
+
.x402-receipt-row .x402-k { color: #8a90a8; }
|
|
263
|
+
.x402-receipt-row .x402-v { color: #e6e8f0; }
|
|
264
|
+
.x402-receipt-row a { color: #60a5fa; }
|
|
265
|
+
.x402-error-box { background: #1f1416; border-color: #7f1d1d; color: #fca5a5; }
|
|
266
|
+
.x402-foot a { color: #b0b6cc; }
|
|
267
|
+
.x402-foot a:hover { color: #ffffff; }
|
|
268
|
+
}
|
|
269
|
+
`;function ke(){if(typeof document>"u"||document.getElementById(G))return;let n=document.createElement("style");n.id=G,n.textContent=ve,document.head.appendChild(n)}var z=class{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}_apiOrigin(){return fe(this.opts)}mount(){ke();let e=this.opts.brand||l.brand||{},t=document.createElement("div");t.className="x402-overlay";let r=e.href?`<a href="${p(e.href)}" target="_blank" rel="noopener">${p(e.label||e.href)}</a>`:e.label?`<span>${p(e.label)}</span>`:"";return t.innerHTML=`
|
|
270
|
+
<div class="x402-modal" role="dialog" aria-modal="true" aria-label="x402 payment">
|
|
271
|
+
<div class="x402-head">
|
|
272
|
+
<div class="x402-merchant">
|
|
273
|
+
<div class="x402-name" data-merchant>${p(this.opts.merchant||"Payment")}</div>
|
|
274
|
+
<div class="x402-action" data-action>${p(this.opts.action||"Pay-per-call")}</div>
|
|
275
|
+
</div>
|
|
276
|
+
<button class="x402-close" data-close aria-label="Close">\u2715</button>
|
|
277
|
+
</div>
|
|
278
|
+
<div class="x402-price-row">
|
|
279
|
+
<div class="x402-price" data-price>\u2014<span class="x402-currency"> USDC</span></div>
|
|
280
|
+
<div class="x402-network" data-network>resolving\u2026</div>
|
|
281
|
+
</div>
|
|
282
|
+
<div class="x402-body" data-body></div>
|
|
283
|
+
<div class="x402-foot">
|
|
284
|
+
<span class="x402-secure">x402 \xB7 onchain settled</span>
|
|
285
|
+
${r}
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
288
|
+
`,document.body.appendChild(t),this.overlay=t,this.bodyEl=t.querySelector("[data-body]"),this.priceEl=t.querySelector("[data-price]"),this.networkEl=t.querySelector("[data-network]"),t.querySelector("[data-close]").addEventListener("click",()=>this.close("cancelled")),t.addEventListener("click",o=>{o.target===t&&this.close("cancelled")}),this.onKey=o=>{o.key==="Escape"&&this.close("cancelled")},document.addEventListener("keydown",this.onKey),requestAnimationFrame(()=>t.classList.add("x402-open")),new Promise((o,s)=>{this.resolve=o,this.reject=s})}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)){let t=new Error("cancelled");t.code="cancelled",this.reject(t)}}renderSteps(e,t={}){return this.steps.map(o=>{let 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`]||"",d=s==="done"?"\u2713":s==="error"?"!":o.id===e&&s==="active"?" ":this.steps.findIndex(c=>c.id===o.id)+1;return`<div class="x402-step ${i}">
|
|
289
|
+
<div class="x402-step-num">${d}</div>
|
|
290
|
+
<div class="x402-step-body">
|
|
291
|
+
<div class="x402-step-label">${o.label}</div>
|
|
292
|
+
${a?`<div class="x402-step-meta">${p(a)}</div>`:""}
|
|
293
|
+
</div>
|
|
294
|
+
</div>`}).join("")}setPrice(e){let t=e.extra?.decimals??6,r=k(e.amount,t),o=(e.extra?.name||"USDC").replace(/^USD Coin$/,"USDC");this.priceEl.innerHTML=`${r}<span class="x402-currency"> ${o}</span>`,this.networkEl.textContent=h(e.network,e)}renderConnect(){let e=typeof window<"u"&&(window.solana?.isPhantom||window.phantom?.solana),t=typeof window<"u"&&window.ethereum,r=this.challenge?.accepts.find(d=>g(d.network)),o=this.challenge?.accepts.find(U);if(this.siwx&&!this.payFlowOverride){let d=e?X(this.siwx,"solana"):null,c=t?X(this.siwx,"evm"):null;if(d||c){this.renderSiwxChoice({siwxSolana:d,siwxEvm:c});return}}if(this.opts.autoConnect&&!this.autoConnectTried&&!this.siwxFallbackNotice){this.autoConnectTried=!0;let d=!!(r&&e),c=!!(o&&t);if(d&&!c){this.runSolana(r);return}if(c&&!d){this.runEvm(o);return}}let s=[];r&&s.push(`
|
|
295
|
+
<button class="x402-wallet-btn" data-wallet="phantom" ${e?"":"disabled"}>
|
|
296
|
+
<div class="x402-wallet-icon x402-phantom">P</div>
|
|
297
|
+
<span class="x402-wallet-name">${e?"Phantom":"Phantom (not detected)"}</span>
|
|
298
|
+
<span class="x402-wallet-meta">${h(r.network,r)}</span>
|
|
299
|
+
</button>
|
|
300
|
+
`),o&&s.push(`
|
|
301
|
+
<button class="x402-wallet-btn" data-wallet="evm" ${t?"":"disabled"}>
|
|
302
|
+
<div class="x402-wallet-icon x402-metamask">M</div>
|
|
303
|
+
<span class="x402-wallet-name">${t?"Browser wallet":"No EVM wallet detected"}</span>
|
|
304
|
+
<span class="x402-wallet-meta">${h(o.network,o)}</span>
|
|
305
|
+
</button>
|
|
306
|
+
`);let i=this.siwxFallbackNotice?`<div class="x402-siwx-fallback">${p(this.siwxFallbackNotice)}</div>`:"";this.bodyEl.innerHTML=`
|
|
307
|
+
${this.renderSteps("connect",{discover:"done"})}
|
|
308
|
+
${i}
|
|
309
|
+
<div class="x402-wallet-buttons">${s.join("")}</div>
|
|
310
|
+
`;let a=d=>{let c=d.target.closest("[data-wallet]");if(!c||c.disabled)return;let f=c.dataset.wallet;f==="phantom"?this.runSolana(r):f==="evm"&&this.runEvm(o)};this.bodyEl.querySelectorAll("[data-wallet]").forEach(d=>d.addEventListener("click",a))}renderSiwxChoice({siwxSolana:e,siwxEvm:t}){let r=k(this.accept.amount,this.accept.extra?.decimals??6),o=e?{kind:"solana",chain:e.chain}:{kind:"evm",chain:t.chain},s=o.kind==="solana"?"Sign in with Phantom":"Sign in with wallet";this.bodyEl.innerHTML=`
|
|
311
|
+
${this.renderSteps("connect",{discover:"done"})}
|
|
312
|
+
<button class="x402-pay-btn" data-action="siwx">${s}</button>
|
|
313
|
+
<button class="x402-pay-secondary" data-action="pay">Pay ${r} USDC instead</button>
|
|
314
|
+
<div class="x402-siwx-hint">Already paid for this once? Sign in to re-enter without paying again.</div>
|
|
315
|
+
`;let i=this.bodyEl.querySelector('[data-action="siwx"]'),a=this.bodyEl.querySelector('[data-action="pay"]');i.addEventListener("click",()=>{o.kind==="solana"?this.runSiwxSolana(o.chain):this.runSiwxEvm(o.chain)}),a.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=`
|
|
316
|
+
${this.renderSteps(e,{...e!=="discover"?{discover:"done"}:{},...e==="authorize"||e==="verify"?{connect:"done"}:{},...e==="verify"?{authorize:"done"}:{},[e]:"error",[`${e}_meta`]:"failed"})}
|
|
317
|
+
<div class="x402-error-box"><strong>${p(e)}:</strong> ${p(t)}</div>
|
|
318
|
+
<button class="x402-pay-btn" data-retry>Try again</button>
|
|
319
|
+
`,this.bodyEl.querySelector("[data-retry]").addEventListener("click",()=>this.start())}renderDone({result:e,payment:t,siwx:r}){let o=typeof e=="string"?e:JSON.stringify(e,null,2),s;if(r){let i=r.address?`${r.address.slice(0,8)}\u2026${r.address.slice(-6)}`:"\u2014";s=`
|
|
320
|
+
<div class="x402-receipt">
|
|
321
|
+
<div class="x402-receipt-title">Welcome back!</div>
|
|
322
|
+
<div class="x402-receipt-row">
|
|
323
|
+
<span class="x402-k">network</span>
|
|
324
|
+
<span class="x402-v">${p(h(r.network)||r.network||"\u2014")}</span>
|
|
325
|
+
</div>
|
|
326
|
+
<div class="x402-receipt-row">
|
|
327
|
+
<span class="x402-k">wallet</span>
|
|
328
|
+
<span class="x402-v">${p(i)}</span>
|
|
329
|
+
</div>
|
|
330
|
+
<div class="x402-receipt-row">
|
|
331
|
+
<span class="x402-k">paid</span>
|
|
332
|
+
<span class="x402-v">previously \xB7 re-entered free</span>
|
|
333
|
+
</div>
|
|
334
|
+
</div>
|
|
335
|
+
`}else{let i=R(t?.network,t?.transaction),a=t?.transaction?`${t.transaction.slice(0,8)}\u2026${t.transaction.slice(-6)}`:"\u2014";s=`
|
|
336
|
+
<div class="x402-receipt">
|
|
337
|
+
<div class="x402-receipt-title">Payment confirmed!</div>
|
|
338
|
+
<div class="x402-receipt-row">
|
|
339
|
+
<span class="x402-k">network</span>
|
|
340
|
+
<span class="x402-v">${p(h(t?.network)||"\u2014")}</span>
|
|
341
|
+
</div>
|
|
342
|
+
<div class="x402-receipt-row">
|
|
343
|
+
<span class="x402-k">payer</span>
|
|
344
|
+
<span class="x402-v">${p(t?.payer?`${t.payer.slice(0,8)}\u2026${t.payer.slice(-6)}`:"\u2014")}</span>
|
|
345
|
+
</div>
|
|
346
|
+
${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>`:""}
|
|
347
|
+
</div>
|
|
348
|
+
`}this.bodyEl.innerHTML=`
|
|
349
|
+
${s}
|
|
350
|
+
<div class="x402-result">${p(o).slice(0,4e3)}</div>
|
|
351
|
+
<button class="x402-pay-btn" data-done>Done</button>
|
|
352
|
+
`,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{let e=await Te(this.opts);this.challenge=e,this.siwx=ye(e),this.payFlowOverride=!1,this.siwxFallbackNotice=null;let t=e.accepts.find(s=>g(s.network)),r=e.accepts.find(U),o=typeof window<"u"&&(window.solana?.isPhantom||window.phantom?.solana);this.accept=o&&t||r||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{let t=window.phantom?.solana||window.solana;if(!t)throw new Error("Phantom wallet not detected");let o=((await t.connect())?.publicKey||t.publicKey)?.toString();if(!o)throw new Error("Phantom did not return a public key");this.payerAddress=o;let s=K({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)}`});let i=this._apiOrigin(),a=await Q(`${i}/api/x402-checkout?action=prepare`,{accept:e,buyer:o});this.renderProgress("authorize",{text:"Confirm in Phantom\u2026"});let d=$e(a.tx_base64),f=(await Be()).VersionedTransaction.deserialize(d),u=await t.signTransaction(f),y=Ce(u.serialize()),w=Y(this.challenge),P=await Q(`${i}/api/x402-checkout?action=encode`,{accept:e,signed_tx_base64:y,resource_url:new URL(this.opts.endpoint,location.href).href,...w?{builder_code:w}:{}});await this.executePaid(P.x_payment)}catch(t){this.spendReservation&&(_(this.spendReservation),this.spendReservation=null),this.renderError(this.payerAddress?"authorize":"connect",b(t))}}async runEvm(e){this.accept=e,this.setPrice(e),this.renderProgress("connect",{text:"Opening browser wallet\u2026"});try{let t=window.ethereum;if(!t)throw new Error("No EVM wallet detected");let o=(await t.request({method:"eth_requestAccounts"}))?.[0];if(!o)throw new Error("Wallet did not return an account");this.payerAddress=o;let s=K({accept:e,caps:this.opts.caps,address:o});if(s.abort){this.renderError("authorize",s.reason);return}this.spendReservation=s.reservation||null;let i=v[e.network];if(!i)throw new Error(`Unknown EVM network ${e.network}`);let a=await t.request({method:"eth_chainId"}),d="0x"+i.chainId.toString(16);if(a!==d){this.renderProgress("connect",{text:`Switch wallet to ${i.name}\u2026`});try{await t.request({method:"wallet_switchEthereumChain",params:[{chainId:d}]})}catch{throw new Error(`Wallet is on ${a}; please switch to ${i.name} (${d}) and retry`)}}this.renderProgress("authorize",{text:`Authorize ${k(e.amount)} USDC\u2026`});let c=0,f=Math.floor(Date.now()/1e3)+(e.maxTimeoutSeconds||600),u="0x"+Ae(32),y={name:e.extra?.name||"USD Coin",version:e.extra?.version||"2",chainId:i.chainId,verifyingContract:e.asset},w={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"}]},P={from:o,to:e.payTo,value:e.amount,validAfter:c,validBefore:f,nonce:u},te={primaryType:"TransferWithAuthorization",types:w,domain:y,message:P},ne=await t.request({method:"eth_signTypedData_v4",params:[o,JSON.stringify(te)]}),L={x402Version:2,scheme:"exact",network:e.network,resource:{url:this.opts.endpoint,mimeType:"application/json"},accepted:e,payload:{signature:ne,authorization:{from:o,to:e.payTo,value:e.amount,validAfter:String(c),validBefore:String(f),nonce:u}}},M=Y(this.challenge);M&&(L.extensions={"builder-code":M});let re=j(L);await this.executePaid(re)}catch(t){this.spendReservation&&(_(this.spendReservation),this.spendReservation=null),this.renderError(this.payerAddress?"authorize":"connect",b(t))}}async executePaid(e,t=0){this.renderProgress("verify",{text:t?"Retrying after upstream throttle\u2026":"Calling merchant endpoint\u2026"});try{let 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(),i;if(o.includes("json"))try{i=JSON.parse(s)}catch{i=s}else i=s;if(!r.ok){if(r.status===429&&t<Se)return await this.waitForThrottle(Ee(r,i)),this.executePaid(e,t+1);let c=i&&typeof i=="object"&&(i.error_description||i.error)||`HTTP ${r.status}`;throw new Error(c)}let a=r.headers.get("x-payment-response"),d=S(a)||{};this.spendReservation=null,this.renderDone({result:i,payment:d}),this.resolve?.({ok:!0,result:i,payment:d,response:{status:r.status,headers:Z(r.headers)}})}catch(r){this.spendReservation&&(_(this.spendReservation),this.spendReservation=null),this.renderError("verify",b(r))}}async waitForThrottle(e){let t=Math.max(1,Math.min(30,Math.round(e)||6));for(let r=t;r>0;r--)this.renderProgress("verify",{text:`Service 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{let t=window.ethereum;if(!t)throw new Error("No EVM wallet detected");let o=(await t.request({method:"eth_requestAccounts"}))?.[0];if(!o)throw new Error("Wallet did not return an account");let i=(await we())(o);this.payerAddress=i,this.renderProgress("authorize",{text:`Sign sign-in message as ${i.slice(0,6)}\u2026${i.slice(-4)}`});let a=N(this.siwx.info,e,i),d=await t.request({method:"personal_sign",params:[a,i]}),c=this.siwx.info,f={domain:c.domain,address:i,...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:d};await this.executeSiwx(f,e.chainId)}catch(t){this.renderError(this.payerAddress?"authorize":"connect",b(t))}}async runSiwxSolana(e){this.renderProgress("connect",{text:"Opening Phantom\u2026"});try{let t=window.phantom?.solana||window.solana;if(!t)throw new Error("Phantom wallet not detected");let 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)}`});let i=N(this.siwx.info,e,s),a=new TextEncoder().encode(i),d=await t.signMessage(a,"utf8"),c=d?.signature instanceof Uint8Array?d.signature:new Uint8Array(d?.signature||d);if(!c||!c.length)throw new Error("Phantom did not return a signature");let f=W(c),u=this.siwx.info,y={domain:u.domain,address:s,...u.statement?{statement:u.statement}:{},uri:u.uri,version:u.version||"1",chainId:e.chainId,type:"ed25519",nonce:u.nonce,issuedAt:u.issuedAt,...u.expirationTime?{expirationTime:u.expirationTime}:{},...u.notBefore?{notBefore:u.notBefore}:{},...u.requestId!==void 0&&u.requestId!==null?{requestId:u.requestId}:{},...Array.isArray(u.resources)?{resources:u.resources}:{},signatureScheme:"siws",signature:f};await this.executeSiwx(y,e.chainId)}catch(t){this.renderError(this.payerAddress?"authorize":"connect",b(t))}}async executeSiwx(e,t){this.renderProgress("verify",{text:"Verifying sign-in\u2026"});let r=ge(e),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"}:{},[he]: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",b(i));return}if(o.status===200){let i=o.headers.get("content-type")||"",a=await o.text(),d;if(i.includes("json"))try{d=JSON.parse(a)}catch{d=a}else d=a;let c={address:e.address,network:t};this.renderDone({result:d,siwx:c}),this.resolve?.({ok:!0,result:d,siwx:c,response:{status:o.status,headers:Z(o.headers)}});return}if(o.status===401||o.status===402){let i=null;try{i=await o.clone().json()}catch{}let 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}let s=await o.text().catch(()=>"");this.renderError("verify",`SIWX retry failed: HTTP ${o.status}${s?` \xB7 ${s.slice(0,120)}`:""}`)}};function p(n){return String(n??"").replace(/[&<>"']/g,e=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[e])}function Z(n){let e={};return n.forEach((t,r)=>e[r]=t),e}var Se=2;function Ee(n,e,t=6){let r=Number.parseInt(n.headers.get("retry-after")||"",10);if(Number.isFinite(r)&&r>0)return r;let o=e&&typeof e=="object"?Number(e.retry_after):NaN;return Number.isFinite(o)&&o>0?o:t}function b(n){let 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 a CDN) 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 $e(n){if(typeof Buffer<"u")return new Uint8Array(Buffer.from(n,"base64"));let e=atob(n),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t}function Ce(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 Ae(n){let e=new Uint8Array(n);return crypto.getRandomValues(e),Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}var $=null;async function Be(){return $||($=await import(l.solanaWeb3Url),$)}async function Q(n,e){let t=await fetch(n,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)}),r=await t.text(),o;try{o=JSON.parse(r)}catch{o={error:"parse_error",error_description:r.slice(0,200)}}if(!t.ok){let s=new Error(o.error_description||o.error||`HTTP ${t.status}`);throw s.status=t.status,s.data=o,s}return o}async function Te(n){let 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");let r=await fetch(n.endpoint,t),o=r.headers.get("payment-required"),s=r.status===401&&!!o;if(r.status!==402&&!s){let a=await r.text();throw new Error(`Endpoint did not return 402 (got ${r.status}). Body: ${a.slice(0,120)}`)}let i=s?S(o):await r.json().catch(()=>null);if(!i||!Array.isArray(i.accepts)||!i.accepts.length){let a=S(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.accepts=i.accepts.map(q),i}async function T(n){if(!n?.endpoint)throw new Error("X402.pay: endpoint is required");let e=new z(n),t=e.mount();return queueMicrotask(()=>e.start()),t}function Pe(n){let e=n.dataset,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}let o=e.x402Caps;if(o)try{o=JSON.parse(o)}catch{o=void 0}return{endpoint:e.x402Endpoint,method:e.x402Method||(t?"POST":"GET"),body:t,headers:r,caps:o,apiOrigin:e.x402ApiOrigin,merchant:e.x402Merchant,action:e.x402Action||n.textContent?.trim().slice(0,60)}}function Oe(n){n.dataset.x402Bound!=="1"&&(n.dataset.x402Bound="1",n.addEventListener("click",async e=>{e.preventDefault();let t=Pe(n);try{let r=await T(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 m(){typeof document>"u"||document.querySelectorAll("[data-x402-endpoint]").forEach(Oe)}function Ue(){if(typeof document>"u")return;let e=(document.currentScript||document.querySelector('script[src*="x402.global"], script[src*="/x402.js"]'))?.dataset;if(!e)return;let t={};e.x402ApiOrigin!==void 0&&(t.apiOrigin=e.x402ApiOrigin),(e.x402BrandLabel!==void 0||e.x402BrandHref!==void 0)&&(t.brand={},e.x402BrandLabel!==void 0&&(t.brand.label=e.x402BrandLabel),e.x402BrandHref!==void 0&&(t.brand.href=e.x402BrandHref)),e.x402BuilderDisable==="true"||e.x402BuilderDisable===""?t.builderCode=null:(e.x402BuilderWallet!==void 0||e.x402BuilderService!==void 0)&&(t.builderCode={},e.x402BuilderWallet!==void 0&&(t.builderCode.wallet=e.x402BuilderWallet),e.x402BuilderService!==void 0&&(t.builderCode.service=e.x402BuilderService)),e.x402SolanaWeb3Url&&(t.solanaWeb3Url=e.x402SolanaWeb3Url),e.x402NobleHashesUrl&&(t.nobleHashesUrl=e.x402NobleHashesUrl),Object.keys(t).length&&B(t)}typeof document<"u"&&(Ue(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",m,{once:!0}):m(),new MutationObserver(()=>m()).observe(document.documentElement,{childList:!0,subtree:!0}));typeof window<"u"&&(window.X402=Object.freeze({pay:T,init:m,configure:B,version:H}));return de(Ne);})();
|
|
353
|
+
//# sourceMappingURL=x402.global.js.map
|