@nowramp/sdk 0.1.68 → 0.1.69
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/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/sdk.umd.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* (c) 2026 NowRamp
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
6
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e={evm:{pattern:/^0x[a-fA-F0-9]{40}$/,description:"EVM address must start with 0x followed by 40 hexadecimal characters"},solana:{pattern:/^[1-9A-HJ-NP-Za-km-z]{32,44}$/,description:"Solana address must be 32-44 base58 characters"},bitcoin:{pattern:/^(1[a-km-zA-HJ-NP-Z1-9]{25,34}|3[a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{39,59}|[LM][a-km-zA-HJ-NP-Z1-9]{25,34}|ltc1[a-z0-9]{39,59}|D[a-km-zA-HJ-NP-Z1-9]{25,34})$/i,description:"Bitcoin-family address (BTC, LTC, DOGE, BCH)"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},tron:{pattern:/^T[1-9A-HJ-NP-Za-km-z]{33}$/,description:"Tron address must start with T followed by 33 base58 characters"},cosmos:{pattern:/^[a-z]{1,20}1[a-z0-9]{38,58}$/,description:"Cosmos address must be bech32 encoded with chain-specific HRP"},substrate:{pattern:/^[1-9A-HJ-NP-Za-km-z]{46,50}$/,description:"Substrate/Polkadot address must be SS58 encoded (46-50 base58 characters)"},other:{pattern:/^.{10,200}$/,description:"Address format varies by network (10-200 characters)"}},t=["https:"],r=["localhost","127.0.0.1"],s={public:"pk_",secret:"sk_"};function o(e){return e?e.includes(s.secret)?{valid:!1,error:"Secret API keys (sk_) cannot be used in the SDK. Use a public key (pk_) instead. Secret keys should only be used in backend server code."}:(e.includes(s.public)||console.warn("RampWidget: API key does not have a public key prefix (pk_). For security, please generate a new public key for frontend use."),{valid:!0}):{valid:!1,error:"apiKey is required"}}function n(e){if(!e)return{valid:!0};try{const s=new URL(e);return t.includes(s.protocol)||"http:"===s.protocol&&r.includes(s.hostname)?{valid:!0}:{valid:!1,error:`redirectUrl must use HTTPS (got ${s.protocol})`}}catch{return{valid:!1,error:"redirectUrl is not a valid URL"}}}function i(t,r){if(!t)return{valid:!0};const s=t.trim();if(r){const t=r.toLowerCase(),o=e[t];if(o){const{pattern:e,description:t}=o;return e.test(s)?{valid:!0}:{valid:!1,error:t}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}function a(e,t){if(!t)return!0;try{if(e===new URL(t).origin)return!0;const r=new URL(e);return"localhost"===r.hostname||"127.0.0.1"===r.hostname}catch{return!1}}class c{constructor(e){this.iframe=null,this.modalContainer=null,this.boundMessageHandler=null,this.isOpen=!1,this.config={widgetUrl:e.widgetUrl||"https://widget.nowramp.com/widget/latest/index.html",apiUrl:e.apiUrl||"https://api.nowramp.com",flowType:"buy",theme:"light",...e},this.validateConfig()}open(){this.isOpen?console.warn("RampWidget: Widget is already open"):(this.isOpen=!0,this.setupMessageListener(),this.createIframe())}close(){this.isOpen&&(this.isOpen=!1,this.cleanup(),this.config.onClose?.())}setAmount(e){this.sendCommand("SET_AMOUNT",e)}setTheme(e){this.sendCommand("SET_THEME",e)}refreshQuote(){this.sendCommand("REFRESH_QUOTE")}validateConfig(){if(!this.config.apiKey)throw new Error("RampWidget: apiKey is required");if(!this.config.projectId)throw new Error("RampWidget: projectId is required");if(!!(!this.config.sessionId||!this.config.clientSecret)&&!this.config.externalUserId)throw new Error("RampWidget: Either externalUserId (legacy) or sessionId + clientSecret (recommended) is required");if(this.config.sessionId&&!this.config.clientSecret)throw new Error("RampWidget: clientSecret is required when using sessionId");const e=o(this.config.apiKey);if(!e.valid)throw new Error(`RampWidget: ${e.error}`);if(this.config.redirectUrl){const e=n(this.config.redirectUrl);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}if(this.config.walletAddress){const e=i(this.config.walletAddress,void 0);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}}buildWidgetUrl(){const e=new URLSearchParams({apiKey:this.config.apiKey,projectId:this.config.projectId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return this.config.sessionId&&this.config.clientSecret&&(e.set("sessionId",this.config.sessionId),e.set("clientSecret",this.config.clientSecret)),this.config.externalUserId&&e.set("externalUserId",this.config.externalUserId),this.config.apiUrl&&e.set("apiUrl",this.config.apiUrl),this.config.locale&&e.set("locale",this.config.locale),void 0!==this.config.amount&&e.set("amount",String(this.config.amount)),this.config.sourceCurrency&&e.set("sourceCurrency",this.config.sourceCurrency),this.config.destinationCurrency&&e.set("destinationCurrency",this.config.destinationCurrency),this.config.walletAddress&&e.set("walletAddress",this.config.walletAddress),this.config.network&&e.set("network",this.config.network),this.config.redirectUrl&&e.set("redirectUrl",this.config.redirectUrl),!1===this.config.autoRedirect&&e.set("autoRedirect","false"),`${this.config.widgetUrl}?${e.toString()}`}createIframe(){this.iframe=document.createElement("iframe"),this.iframe.src=this.buildWidgetUrl(),this.iframe.style.border="none",this.iframe.style.width="100%",this.iframe.style.height="100%",this.iframe.allow="camera *; microphone *; geolocation *; encrypted-media *; clipboard-read; clipboard-write; payment *",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals allow-popups-without-user-activation allow-top-navigation allow-downloads");const e=this.getContainer();e?e.appendChild(this.iframe):this.createModal()}getContainer(){return this.config.container?"string"==typeof this.config.container?document.querySelector(this.config.container):this.config.container:null}createModal(){this.modalContainer=document.createElement("div"),this.modalContainer.style.cssText="\n position: fixed;\n inset: 0;\n z-index: 9999;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n ";const e="dark"===this.config.theme,t=document.createElement("div");t.style.cssText=`\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: ${e?"#000000":"white"};\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n `,this.iframe&&t.appendChild(this.iframe),this.modalContainer.appendChild(t),this.modalContainer.onclick=e=>{e.target===this.modalContainer&&this.close()};document.addEventListener("keydown",e=>{"Escape"===e.key&&this.close()}),document.body.appendChild(this.modalContainer),document.body.style.overflow="hidden"}setupMessageListener(){this.boundMessageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.boundMessageHandler)}handleMessage(e){if(!a(e.origin,this.config.widgetUrl))return;const t=e.data;if(t&&"ramp-widget"===t.source)switch(t.type){case"WIDGET_READY":this.config.onReady?.();break;case"WIDGET_CLOSE":this.close();break;case"STEP_CHANGE":this.config.onStepChange?.(t.payload.step);break;case"QUOTE_CREATED":this.config.onQuoteCreated?.(t.payload);break;case"ORDER_CREATED":this.config.onOrderCreated?.(t.payload);break;case"ORDER_COMPLETED":this.config.onSuccess?.(t.payload);break;case"ERROR":this.config.onError?.(t.payload)}}sendCommand(e,t){if(!this.iframe?.contentWindow)return void console.warn("RampWidget: Cannot send command, widget not open");const r=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},r)}cleanup(){this.boundMessageHandler&&(window.removeEventListener("message",this.boundMessageHandler),this.boundMessageHandler=null),this.iframe?.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.modalContainer?.parentNode&&(this.modalContainer.parentNode.removeChild(this.modalContainer),document.body.style.overflow=""),this.modalContainer=null}}class d{constructor(e){this.config=e,this.baseUrl=e.apiUrl||"https://api.nowramp.com"}async getRate(e){if(!this.config.apiKey)return this.getPublicRate(e);const t=await fetch(`${this.baseUrl}/v1/rates/convert`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.rate,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationAmount:s.destinationAmount,destinationCurrency:s.destinationCurrency,fees:{processingFee:s.fees?.processingFee||0,processingFeePercent:s.fees?.processingFeePercent||0,networkFee:s.fees?.networkFee||0,totalFee:s.fees?.totalFee||0},provider:s.provider||"unknown",expiresAt:s.expiresAt}}async getPublicRate(e){const t=await fetch(`${this.baseUrl}/public/wert/convert`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.ticker||s.rate,sourceAmount:s.currencyAmount||s.sourceAmount||e.amount,sourceCurrency:e.from,destinationAmount:s.commodityAmount||s.destinationAmount,destinationCurrency:e.to,fees:{processingFee:s.feeAmount||s.fees?.processingFee||0,processingFeePercent:s.feePercent||s.fees?.processingFeePercent||0,networkFee:s.currencyMinerFee||s.fees?.networkFee||0,totalFee:(s.feeAmount||0)+(s.currencyMinerFee||0)||s.fees?.totalFee||0},provider:"wert",expiresAt:s.expiresAt}}async getCurrencies(){if(!this.config.apiKey)return this.getPublicCurrencies();const e=await fetch(`${this.baseUrl}/v1/rates/currencies`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async getPublicCurrencies(){if(!this.config.projectId)throw new Error("projectId is required to fetch currencies without an API key");const e=await fetch(`${this.baseUrl}/public/projects/${this.config.projectId}/currencies`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async validateAddress(e){const t=await fetch(`${this.baseUrl}/public/validate/address`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate address: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async validateAddressBatch(e){if(e.length>20)throw new Error("Maximum 20 addresses per batch");const t=await fetch(`${this.baseUrl}/public/validate/address/batch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({addresses:e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate addresses: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getSupportedNetworks(){const e=await fetch(`${this.baseUrl}/public/validate/networks`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get supported networks: ${r}`)}const t=await e.json();return t.data?.attributes||t.data||t}async createSession(e){if(!this.config.apiKey)throw new Error("API key is required to create sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to create session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,clientSecret:s.clientSecret,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,expiresAt:s.expiresAt,createdAt:s.createdAt}}async getSession(e){if(!this.config.apiKey)throw new Error("API key is required to get session details.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,fieldLocks:s.fieldLocks,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async cancelSession(e){if(!this.config.apiKey)throw new Error("API key is required to cancel sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}/cancel`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to cancel session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"cancelled",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async getSupported(e){if(!this.config.projectId)throw new Error("projectId is required to get supported config");const t="string"==typeof e?{orderType:e}:e,r=new URLSearchParams({projectId:this.config.projectId});t?.orderType&&r.set("orderType",t.orderType),t?.country&&r.set("country",t.country);const s=await fetch(`${this.baseUrl}/public/v1/onramp/supported?${r}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!s.ok){const e=await s.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${s.status}`;throw new Error(`Failed to get supported config: ${t}`)}const o=await s.json();return o.data?.attributes||o.data||o}async getQuotes(e){if(!this.config.projectId)throw new Error("projectId is required to get quotes");const t=new URLSearchParams({projectId:this.config.projectId,fiatCurrency:e.fiatCurrency,cryptoCurrency:e.cryptoCurrency,network:e.network});e.fiatAmount&&t.set("fiatAmount",e.fiatAmount),e.cryptoAmount&&t.set("cryptoAmount",e.cryptoAmount),e.orderType&&t.set("orderType",e.orderType),e.paymentMethodId&&t.set("paymentMethodId",e.paymentMethodId),e.country&&t.set("country",e.country);const r=await fetch(`${this.baseUrl}/public/v1/onramp/quotes?${t}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){const e=await r.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${r.status}`;throw new Error(`Failed to get quotes: ${t}`)}const s=await r.json();return s.data?.attributes||s.data||s}async createCheckoutIntent(e){if(!this.config.projectId)throw new Error("projectId is required to create checkout intents");const t=await fetch(`${this.baseUrl}/public/v1/onramp/checkout-intent`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:this.config.projectId,...e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=("string"==typeof e.error?e.error:e.error?.message)||e.message||`HTTP ${t.status}`;let s="";if(e.details)try{const t="string"==typeof e.details?JSON.parse(e.details):e.details;if(t.errors&&"object"==typeof t.errors){const e=Object.values(t.errors).flat().filter(Boolean);e.length&&(s=e.join("; "))}}catch{}throw new Error(`Failed to create checkout intent: ${s||r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getTransaction(e){const t=await fetch(`${this.baseUrl}/public/v1/onramp/transactions/${e}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get transaction: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}}exports.ADDRESS_PATTERNS=e,exports.ALLOWED_PROTOCOLS=t,exports.API_KEY_PREFIXES=s,exports.DEV_ALLOWED_HOSTNAMES=r,exports.RampApi=d,exports.RampWidget=c,exports.VERSION="0.1.13",exports.createCheckoutIntent=async function(e,t){return new d({apiKey:"",...e}).createCheckoutIntent(t)},exports.default=c,exports.getCurrencies=async function(e){return new d(e).getCurrencies()},exports.getQuotes=async function(e,t){return new d({apiKey:"",...e}).getQuotes(t)},exports.getRate=async function(e,t){return new d(e).getRate(t)},exports.getSupported=async function(e,t){return new d({apiKey:"",...e}).getSupported(t)},exports.getSupportedNetworks=async function(e){return new d({apiKey:"",projectId:"",...e}).getSupportedNetworks()},exports.getTransaction=async function(e,t){return new d({apiKey:"",projectId:"",...e}).getTransaction(t)},exports.validateAddress=async function(e,t){return new d({apiKey:"",projectId:"",...e}).validateAddress(t)},exports.validateAddressBatch=async function(e,t){return new d({apiKey:"",projectId:"",...e}).validateAddressBatch(t)},exports.validateAmount=function(e,t,r,s){if(!e||""===e.trim())return{valid:!1,error:"Amount is required"};const o=parseFloat(e);if(isNaN(o))return{valid:!1,error:"Amount must be a valid number"};if(o<=0)return{valid:!1,error:"Amount must be greater than zero"};const n=s?` ${s}`:"";return o<t?{valid:!1,error:`Minimum amount is ${t}${n}`}:o>r?{valid:!1,error:`Maximum amount is ${r}${n}`}:{valid:!0}},exports.validateApiKey=o,exports.validateMessageOrigin=a,exports.validateRedirectUrl=n,exports.validateWalletAddress=i;
|
|
6
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e={evm:{pattern:/^0x[a-fA-F0-9]{40}$/,description:"EVM address must start with 0x followed by 40 hexadecimal characters"},solana:{pattern:/^[1-9A-HJ-NP-Za-km-z]{32,44}$/,description:"Solana address must be 32-44 base58 characters"},bitcoin:{pattern:/^(1[a-km-zA-HJ-NP-Z1-9]{25,34}|3[a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{39,59}|[LM][a-km-zA-HJ-NP-Z1-9]{25,34}|ltc1[a-z0-9]{39,59}|D[a-km-zA-HJ-NP-Z1-9]{25,34})$/i,description:"Bitcoin-family address (BTC, LTC, DOGE, BCH)"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},tron:{pattern:/^T[1-9A-HJ-NP-Za-km-z]{33}$/,description:"Tron address must start with T followed by 33 base58 characters"},cosmos:{pattern:/^[a-z]{1,20}1[a-z0-9]{38,58}$/,description:"Cosmos address must be bech32 encoded with chain-specific HRP"},substrate:{pattern:/^[1-9A-HJ-NP-Za-km-z]{46,50}$/,description:"Substrate/Polkadot address must be SS58 encoded (46-50 base58 characters)"},other:{pattern:/^.{10,200}$/,description:"Address format varies by network (10-200 characters)"}},t=["https:"],r=["localhost","127.0.0.1"],s={public:"pk_",secret:"sk_"};function o(e){return e?e.includes(s.secret)?{valid:!1,error:"Secret API keys (sk_) cannot be used in the SDK. Use a public key (pk_) instead. Secret keys should only be used in backend server code."}:(e.includes(s.public)||console.warn("RampWidget: API key does not have a public key prefix (pk_). For security, please generate a new public key for frontend use."),{valid:!0}):{valid:!1,error:"apiKey is required"}}function n(e){if(!e)return{valid:!0};try{const s=new URL(e);return t.includes(s.protocol)||"http:"===s.protocol&&r.includes(s.hostname)?{valid:!0}:{valid:!1,error:`redirectUrl must use HTTPS (got ${s.protocol})`}}catch{return{valid:!1,error:"redirectUrl is not a valid URL"}}}function i(t,r){if(!t)return{valid:!0};const s=t.trim();if(r){const t=r.toLowerCase(),o=e[t];if(o){const{pattern:e,description:t}=o;return e.test(s)?{valid:!0}:{valid:!1,error:t}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}function a(e,t){if(!t)return!0;try{if(e===new URL(t).origin)return!0;if("undefined"!=typeof process&&"production"===process.env?.NODE_ENV)return!1;const r=new URL(e);return"localhost"===r.hostname||"127.0.0.1"===r.hostname}catch{return!1}}class c{constructor(e){this.iframe=null,this.modalContainer=null,this.boundMessageHandler=null,this.isOpen=!1,this.config={widgetUrl:e.widgetUrl||"https://widget.nowramp.com/widget/latest/index.html",apiUrl:e.apiUrl||"https://api.nowramp.com",flowType:"buy",theme:"light",...e},this.validateConfig()}open(){this.isOpen?console.warn("RampWidget: Widget is already open"):(this.isOpen=!0,this.setupMessageListener(),this.createIframe())}close(){this.isOpen&&(this.isOpen=!1,this.cleanup(),this.config.onClose?.())}setAmount(e){this.sendCommand("SET_AMOUNT",e)}setTheme(e){this.sendCommand("SET_THEME",e)}refreshQuote(){this.sendCommand("REFRESH_QUOTE")}validateConfig(){if(!this.config.apiKey)throw new Error("RampWidget: apiKey is required");if(!this.config.projectId)throw new Error("RampWidget: projectId is required");if(!!(!this.config.sessionId||!this.config.clientSecret)&&!this.config.externalUserId)throw new Error("RampWidget: Either externalUserId (legacy) or sessionId + clientSecret (recommended) is required");if(this.config.sessionId&&!this.config.clientSecret)throw new Error("RampWidget: clientSecret is required when using sessionId");const e=o(this.config.apiKey);if(!e.valid)throw new Error(`RampWidget: ${e.error}`);if(this.config.redirectUrl){const e=n(this.config.redirectUrl);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}if(this.config.walletAddress){const e=i(this.config.walletAddress,void 0);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}}buildWidgetUrl(){const e=new URLSearchParams({apiKey:this.config.apiKey,projectId:this.config.projectId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return this.config.sessionId&&this.config.clientSecret&&(e.set("sessionId",this.config.sessionId),e.set("clientSecret",this.config.clientSecret)),this.config.externalUserId&&e.set("externalUserId",this.config.externalUserId),this.config.apiUrl&&e.set("apiUrl",this.config.apiUrl),this.config.locale&&e.set("locale",this.config.locale),void 0!==this.config.amount&&e.set("amount",String(this.config.amount)),this.config.sourceCurrency&&e.set("sourceCurrency",this.config.sourceCurrency),this.config.destinationCurrency&&e.set("destinationCurrency",this.config.destinationCurrency),this.config.walletAddress&&e.set("walletAddress",this.config.walletAddress),this.config.network&&e.set("network",this.config.network),this.config.redirectUrl&&e.set("redirectUrl",this.config.redirectUrl),!1===this.config.autoRedirect&&e.set("autoRedirect","false"),`${this.config.widgetUrl}?${e.toString()}`}createIframe(){this.iframe=document.createElement("iframe"),this.iframe.src=this.buildWidgetUrl(),this.iframe.style.border="none",this.iframe.style.width="100%",this.iframe.style.height="100%",this.iframe.allow="camera *; microphone *; geolocation *; encrypted-media *; clipboard-read; clipboard-write; payment *",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals allow-popups-without-user-activation allow-top-navigation allow-downloads");const e=this.getContainer();e?e.appendChild(this.iframe):this.createModal()}getContainer(){return this.config.container?"string"==typeof this.config.container?document.querySelector(this.config.container):this.config.container:null}createModal(){this.modalContainer=document.createElement("div"),this.modalContainer.style.cssText="\n position: fixed;\n inset: 0;\n z-index: 9999;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n ";const e="dark"===this.config.theme,t=document.createElement("div");t.style.cssText=`\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: ${e?"#000000":"white"};\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n `,this.iframe&&t.appendChild(this.iframe),this.modalContainer.appendChild(t),this.modalContainer.onclick=e=>{e.target===this.modalContainer&&this.close()};document.addEventListener("keydown",e=>{"Escape"===e.key&&this.close()}),document.body.appendChild(this.modalContainer),document.body.style.overflow="hidden"}setupMessageListener(){this.boundMessageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.boundMessageHandler)}handleMessage(e){if(!a(e.origin,this.config.widgetUrl))return;const t=e.data;if(t&&"ramp-widget"===t.source)switch(t.type){case"WIDGET_READY":this.config.onReady?.();break;case"WIDGET_CLOSE":this.close();break;case"STEP_CHANGE":this.config.onStepChange?.(t.payload.step);break;case"QUOTE_CREATED":this.config.onQuoteCreated?.(t.payload);break;case"ORDER_CREATED":this.config.onOrderCreated?.(t.payload);break;case"ORDER_COMPLETED":this.config.onSuccess?.(t.payload);break;case"ERROR":this.config.onError?.(t.payload)}}sendCommand(e,t){if(!this.iframe?.contentWindow)return void console.warn("RampWidget: Cannot send command, widget not open");const r=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},r)}cleanup(){this.boundMessageHandler&&(window.removeEventListener("message",this.boundMessageHandler),this.boundMessageHandler=null),this.iframe?.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.modalContainer?.parentNode&&(this.modalContainer.parentNode.removeChild(this.modalContainer),document.body.style.overflow=""),this.modalContainer=null}}class d{constructor(e){this.config=e,this.baseUrl=e.apiUrl||"https://api.nowramp.com"}async getRate(e){if(!this.config.apiKey)return this.getPublicRate(e);const t=await fetch(`${this.baseUrl}/v1/rates/convert`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.rate,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationAmount:s.destinationAmount,destinationCurrency:s.destinationCurrency,fees:{processingFee:s.fees?.processingFee||0,processingFeePercent:s.fees?.processingFeePercent||0,networkFee:s.fees?.networkFee||0,totalFee:s.fees?.totalFee||0},provider:s.provider||"unknown",expiresAt:s.expiresAt}}async getPublicRate(e){const t=await fetch(`${this.baseUrl}/public/wert/convert`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.ticker||s.rate,sourceAmount:s.currencyAmount||s.sourceAmount||e.amount,sourceCurrency:e.from,destinationAmount:s.commodityAmount||s.destinationAmount,destinationCurrency:e.to,fees:{processingFee:s.feeAmount||s.fees?.processingFee||0,processingFeePercent:s.feePercent||s.fees?.processingFeePercent||0,networkFee:s.currencyMinerFee||s.fees?.networkFee||0,totalFee:(s.feeAmount||0)+(s.currencyMinerFee||0)||s.fees?.totalFee||0},provider:"wert",expiresAt:s.expiresAt}}async getCurrencies(){if(!this.config.apiKey)return this.getPublicCurrencies();const e=await fetch(`${this.baseUrl}/v1/rates/currencies`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async getPublicCurrencies(){if(!this.config.projectId)throw new Error("projectId is required to fetch currencies without an API key");const e=await fetch(`${this.baseUrl}/public/projects/${this.config.projectId}/currencies`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async validateAddress(e){const t=await fetch(`${this.baseUrl}/public/validate/address`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate address: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async validateAddressBatch(e){if(e.length>20)throw new Error("Maximum 20 addresses per batch");const t=await fetch(`${this.baseUrl}/public/validate/address/batch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({addresses:e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate addresses: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getSupportedNetworks(){const e=await fetch(`${this.baseUrl}/public/validate/networks`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get supported networks: ${r}`)}const t=await e.json();return t.data?.attributes||t.data||t}async createSession(e){if(!this.config.apiKey)throw new Error("API key is required to create sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to create session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,clientSecret:s.clientSecret,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,expiresAt:s.expiresAt,createdAt:s.createdAt}}async getSession(e){if(!this.config.apiKey)throw new Error("API key is required to get session details.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,fieldLocks:s.fieldLocks,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async cancelSession(e){if(!this.config.apiKey)throw new Error("API key is required to cancel sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}/cancel`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to cancel session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"cancelled",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async getSupported(e){if(!this.config.projectId)throw new Error("projectId is required to get supported config");const t="string"==typeof e?{orderType:e}:e,r=new URLSearchParams({projectId:this.config.projectId});t?.orderType&&r.set("orderType",t.orderType),t?.country&&r.set("country",t.country);const s=await fetch(`${this.baseUrl}/public/v1/onramp/supported?${r}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!s.ok){const e=await s.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${s.status}`;throw new Error(`Failed to get supported config: ${t}`)}const o=await s.json();return o.data?.attributes||o.data||o}async getQuotes(e){if(!this.config.projectId)throw new Error("projectId is required to get quotes");const t=new URLSearchParams({projectId:this.config.projectId,fiatCurrency:e.fiatCurrency,cryptoCurrency:e.cryptoCurrency,network:e.network});e.fiatAmount&&t.set("fiatAmount",e.fiatAmount),e.cryptoAmount&&t.set("cryptoAmount",e.cryptoAmount),e.orderType&&t.set("orderType",e.orderType),e.paymentMethodId&&t.set("paymentMethodId",e.paymentMethodId),e.country&&t.set("country",e.country);const r=await fetch(`${this.baseUrl}/public/v1/onramp/quotes?${t}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){const e=await r.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${r.status}`;throw new Error(`Failed to get quotes: ${t}`)}const s=await r.json();return s.data?.attributes||s.data||s}async createCheckoutIntent(e){if(!this.config.projectId)throw new Error("projectId is required to create checkout intents");const t=await fetch(`${this.baseUrl}/public/v1/onramp/checkout-intent`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:this.config.projectId,...e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=("string"==typeof e.error?e.error:e.error?.message)||e.message||`HTTP ${t.status}`;let s="";if(e.details)try{const t="string"==typeof e.details?JSON.parse(e.details):e.details;if(t.errors&&"object"==typeof t.errors){const e=Object.values(t.errors).flat().filter(Boolean);e.length&&(s=e.join("; "))}}catch{}throw new Error(`Failed to create checkout intent: ${s||r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getTransaction(e){const t=await fetch(`${this.baseUrl}/public/v1/onramp/transactions/${e}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get transaction: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}}exports.ADDRESS_PATTERNS=e,exports.ALLOWED_PROTOCOLS=t,exports.API_KEY_PREFIXES=s,exports.DEV_ALLOWED_HOSTNAMES=r,exports.RampApi=d,exports.RampWidget=c,exports.VERSION="0.1.13",exports.createCheckoutIntent=async function(e,t){return new d({apiKey:"",...e}).createCheckoutIntent(t)},exports.default=c,exports.getCurrencies=async function(e){return new d(e).getCurrencies()},exports.getQuotes=async function(e,t){return new d({apiKey:"",...e}).getQuotes(t)},exports.getRate=async function(e,t){return new d(e).getRate(t)},exports.getSupported=async function(e,t){return new d({apiKey:"",...e}).getSupported(t)},exports.getSupportedNetworks=async function(e){return new d({apiKey:"",projectId:"",...e}).getSupportedNetworks()},exports.getTransaction=async function(e,t){return new d({apiKey:"",projectId:"",...e}).getTransaction(t)},exports.validateAddress=async function(e,t){return new d({apiKey:"",projectId:"",...e}).validateAddress(t)},exports.validateAddressBatch=async function(e,t){return new d({apiKey:"",projectId:"",...e}).validateAddressBatch(t)},exports.validateAmount=function(e,t,r,s){if(!e||""===e.trim())return{valid:!1,error:"Amount is required"};const o=parseFloat(e);if(isNaN(o))return{valid:!1,error:"Amount must be a valid number"};if(o<=0)return{valid:!1,error:"Amount must be greater than zero"};const n=s?` ${s}`:"";return o<t?{valid:!1,error:`Minimum amount is ${t}${n}`}:o>r?{valid:!1,error:`Maximum amount is ${r}${n}`}:{valid:!0}},exports.validateApiKey=o,exports.validateMessageOrigin=a,exports.validateRedirectUrl=n,exports.validateWalletAddress=i;
|
package/dist/index.js
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* (c) 2026 NowRamp
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
6
|
-
const e={evm:{pattern:/^0x[a-fA-F0-9]{40}$/,description:"EVM address must start with 0x followed by 40 hexadecimal characters"},solana:{pattern:/^[1-9A-HJ-NP-Za-km-z]{32,44}$/,description:"Solana address must be 32-44 base58 characters"},bitcoin:{pattern:/^(1[a-km-zA-HJ-NP-Z1-9]{25,34}|3[a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{39,59}|[LM][a-km-zA-HJ-NP-Z1-9]{25,34}|ltc1[a-z0-9]{39,59}|D[a-km-zA-HJ-NP-Z1-9]{25,34})$/i,description:"Bitcoin-family address (BTC, LTC, DOGE, BCH)"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},tron:{pattern:/^T[1-9A-HJ-NP-Za-km-z]{33}$/,description:"Tron address must start with T followed by 33 base58 characters"},cosmos:{pattern:/^[a-z]{1,20}1[a-z0-9]{38,58}$/,description:"Cosmos address must be bech32 encoded with chain-specific HRP"},substrate:{pattern:/^[1-9A-HJ-NP-Za-km-z]{46,50}$/,description:"Substrate/Polkadot address must be SS58 encoded (46-50 base58 characters)"},other:{pattern:/^.{10,200}$/,description:"Address format varies by network (10-200 characters)"}},t=["https:"],r=["localhost","127.0.0.1"],s={public:"pk_",secret:"sk_"};function o(e){return e?e.includes(s.secret)?{valid:!1,error:"Secret API keys (sk_) cannot be used in the SDK. Use a public key (pk_) instead. Secret keys should only be used in backend server code."}:(e.includes(s.public)||console.warn("RampWidget: API key does not have a public key prefix (pk_). For security, please generate a new public key for frontend use."),{valid:!0}):{valid:!1,error:"apiKey is required"}}function n(e){if(!e)return{valid:!0};try{const s=new URL(e);return t.includes(s.protocol)||"http:"===s.protocol&&r.includes(s.hostname)?{valid:!0}:{valid:!1,error:`redirectUrl must use HTTPS (got ${s.protocol})`}}catch{return{valid:!1,error:"redirectUrl is not a valid URL"}}}function i(t,r){if(!t)return{valid:!0};const s=t.trim();if(r){const t=r.toLowerCase(),o=e[t];if(o){const{pattern:e,description:t}=o;return e.test(s)?{valid:!0}:{valid:!1,error:t}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}function a(e,t,r,s){if(!e||""===e.trim())return{valid:!1,error:"Amount is required"};const o=parseFloat(e);if(isNaN(o))return{valid:!1,error:"Amount must be a valid number"};if(o<=0)return{valid:!1,error:"Amount must be greater than zero"};const n=s?` ${s}`:"";return o<t?{valid:!1,error:`Minimum amount is ${t}${n}`}:o>r?{valid:!1,error:`Maximum amount is ${r}${n}`}:{valid:!0}}function c(e,t){if(!t)return!0;try{if(e===new URL(t).origin)return!0;const r=new URL(e);return"localhost"===r.hostname||"127.0.0.1"===r.hostname}catch{return!1}}class d{constructor(e){this.iframe=null,this.modalContainer=null,this.boundMessageHandler=null,this.isOpen=!1,this.config={widgetUrl:e.widgetUrl||"https://widget.nowramp.com/widget/latest/index.html",apiUrl:e.apiUrl||"https://api.nowramp.com",flowType:"buy",theme:"light",...e},this.validateConfig()}open(){this.isOpen?console.warn("RampWidget: Widget is already open"):(this.isOpen=!0,this.setupMessageListener(),this.createIframe())}close(){this.isOpen&&(this.isOpen=!1,this.cleanup(),this.config.onClose?.())}setAmount(e){this.sendCommand("SET_AMOUNT",e)}setTheme(e){this.sendCommand("SET_THEME",e)}refreshQuote(){this.sendCommand("REFRESH_QUOTE")}validateConfig(){if(!this.config.apiKey)throw new Error("RampWidget: apiKey is required");if(!this.config.projectId)throw new Error("RampWidget: projectId is required");if(!!(!this.config.sessionId||!this.config.clientSecret)&&!this.config.externalUserId)throw new Error("RampWidget: Either externalUserId (legacy) or sessionId + clientSecret (recommended) is required");if(this.config.sessionId&&!this.config.clientSecret)throw new Error("RampWidget: clientSecret is required when using sessionId");const e=o(this.config.apiKey);if(!e.valid)throw new Error(`RampWidget: ${e.error}`);if(this.config.redirectUrl){const e=n(this.config.redirectUrl);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}if(this.config.walletAddress){const e=i(this.config.walletAddress,void 0);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}}buildWidgetUrl(){const e=new URLSearchParams({apiKey:this.config.apiKey,projectId:this.config.projectId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return this.config.sessionId&&this.config.clientSecret&&(e.set("sessionId",this.config.sessionId),e.set("clientSecret",this.config.clientSecret)),this.config.externalUserId&&e.set("externalUserId",this.config.externalUserId),this.config.apiUrl&&e.set("apiUrl",this.config.apiUrl),this.config.locale&&e.set("locale",this.config.locale),void 0!==this.config.amount&&e.set("amount",String(this.config.amount)),this.config.sourceCurrency&&e.set("sourceCurrency",this.config.sourceCurrency),this.config.destinationCurrency&&e.set("destinationCurrency",this.config.destinationCurrency),this.config.walletAddress&&e.set("walletAddress",this.config.walletAddress),this.config.network&&e.set("network",this.config.network),this.config.redirectUrl&&e.set("redirectUrl",this.config.redirectUrl),!1===this.config.autoRedirect&&e.set("autoRedirect","false"),`${this.config.widgetUrl}?${e.toString()}`}createIframe(){this.iframe=document.createElement("iframe"),this.iframe.src=this.buildWidgetUrl(),this.iframe.style.border="none",this.iframe.style.width="100%",this.iframe.style.height="100%",this.iframe.allow="camera *; microphone *; geolocation *; encrypted-media *; clipboard-read; clipboard-write; payment *",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals allow-popups-without-user-activation allow-top-navigation allow-downloads");const e=this.getContainer();e?e.appendChild(this.iframe):this.createModal()}getContainer(){return this.config.container?"string"==typeof this.config.container?document.querySelector(this.config.container):this.config.container:null}createModal(){this.modalContainer=document.createElement("div"),this.modalContainer.style.cssText="\n position: fixed;\n inset: 0;\n z-index: 9999;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n ";const e="dark"===this.config.theme,t=document.createElement("div");t.style.cssText=`\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: ${e?"#000000":"white"};\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n `,this.iframe&&t.appendChild(this.iframe),this.modalContainer.appendChild(t),this.modalContainer.onclick=e=>{e.target===this.modalContainer&&this.close()};document.addEventListener("keydown",e=>{"Escape"===e.key&&this.close()}),document.body.appendChild(this.modalContainer),document.body.style.overflow="hidden"}setupMessageListener(){this.boundMessageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.boundMessageHandler)}handleMessage(e){if(!c(e.origin,this.config.widgetUrl))return;const t=e.data;if(t&&"ramp-widget"===t.source)switch(t.type){case"WIDGET_READY":this.config.onReady?.();break;case"WIDGET_CLOSE":this.close();break;case"STEP_CHANGE":this.config.onStepChange?.(t.payload.step);break;case"QUOTE_CREATED":this.config.onQuoteCreated?.(t.payload);break;case"ORDER_CREATED":this.config.onOrderCreated?.(t.payload);break;case"ORDER_COMPLETED":this.config.onSuccess?.(t.payload);break;case"ERROR":this.config.onError?.(t.payload)}}sendCommand(e,t){if(!this.iframe?.contentWindow)return void console.warn("RampWidget: Cannot send command, widget not open");const r=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},r)}cleanup(){this.boundMessageHandler&&(window.removeEventListener("message",this.boundMessageHandler),this.boundMessageHandler=null),this.iframe?.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.modalContainer?.parentNode&&(this.modalContainer.parentNode.removeChild(this.modalContainer),document.body.style.overflow=""),this.modalContainer=null}}class u{constructor(e){this.config=e,this.baseUrl=e.apiUrl||"https://api.nowramp.com"}async getRate(e){if(!this.config.apiKey)return this.getPublicRate(e);const t=await fetch(`${this.baseUrl}/v1/rates/convert`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.rate,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationAmount:s.destinationAmount,destinationCurrency:s.destinationCurrency,fees:{processingFee:s.fees?.processingFee||0,processingFeePercent:s.fees?.processingFeePercent||0,networkFee:s.fees?.networkFee||0,totalFee:s.fees?.totalFee||0},provider:s.provider||"unknown",expiresAt:s.expiresAt}}async getPublicRate(e){const t=await fetch(`${this.baseUrl}/public/wert/convert`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.ticker||s.rate,sourceAmount:s.currencyAmount||s.sourceAmount||e.amount,sourceCurrency:e.from,destinationAmount:s.commodityAmount||s.destinationAmount,destinationCurrency:e.to,fees:{processingFee:s.feeAmount||s.fees?.processingFee||0,processingFeePercent:s.feePercent||s.fees?.processingFeePercent||0,networkFee:s.currencyMinerFee||s.fees?.networkFee||0,totalFee:(s.feeAmount||0)+(s.currencyMinerFee||0)||s.fees?.totalFee||0},provider:"wert",expiresAt:s.expiresAt}}async getCurrencies(){if(!this.config.apiKey)return this.getPublicCurrencies();const e=await fetch(`${this.baseUrl}/v1/rates/currencies`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async getPublicCurrencies(){if(!this.config.projectId)throw new Error("projectId is required to fetch currencies without an API key");const e=await fetch(`${this.baseUrl}/public/projects/${this.config.projectId}/currencies`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async validateAddress(e){const t=await fetch(`${this.baseUrl}/public/validate/address`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate address: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async validateAddressBatch(e){if(e.length>20)throw new Error("Maximum 20 addresses per batch");const t=await fetch(`${this.baseUrl}/public/validate/address/batch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({addresses:e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate addresses: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getSupportedNetworks(){const e=await fetch(`${this.baseUrl}/public/validate/networks`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get supported networks: ${r}`)}const t=await e.json();return t.data?.attributes||t.data||t}async createSession(e){if(!this.config.apiKey)throw new Error("API key is required to create sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to create session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,clientSecret:s.clientSecret,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,expiresAt:s.expiresAt,createdAt:s.createdAt}}async getSession(e){if(!this.config.apiKey)throw new Error("API key is required to get session details.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,fieldLocks:s.fieldLocks,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async cancelSession(e){if(!this.config.apiKey)throw new Error("API key is required to cancel sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}/cancel`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to cancel session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"cancelled",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async getSupported(e){if(!this.config.projectId)throw new Error("projectId is required to get supported config");const t="string"==typeof e?{orderType:e}:e,r=new URLSearchParams({projectId:this.config.projectId});t?.orderType&&r.set("orderType",t.orderType),t?.country&&r.set("country",t.country);const s=await fetch(`${this.baseUrl}/public/v1/onramp/supported?${r}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!s.ok){const e=await s.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${s.status}`;throw new Error(`Failed to get supported config: ${t}`)}const o=await s.json();return o.data?.attributes||o.data||o}async getQuotes(e){if(!this.config.projectId)throw new Error("projectId is required to get quotes");const t=new URLSearchParams({projectId:this.config.projectId,fiatCurrency:e.fiatCurrency,cryptoCurrency:e.cryptoCurrency,network:e.network});e.fiatAmount&&t.set("fiatAmount",e.fiatAmount),e.cryptoAmount&&t.set("cryptoAmount",e.cryptoAmount),e.orderType&&t.set("orderType",e.orderType),e.paymentMethodId&&t.set("paymentMethodId",e.paymentMethodId),e.country&&t.set("country",e.country);const r=await fetch(`${this.baseUrl}/public/v1/onramp/quotes?${t}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){const e=await r.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${r.status}`;throw new Error(`Failed to get quotes: ${t}`)}const s=await r.json();return s.data?.attributes||s.data||s}async createCheckoutIntent(e){if(!this.config.projectId)throw new Error("projectId is required to create checkout intents");const t=await fetch(`${this.baseUrl}/public/v1/onramp/checkout-intent`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:this.config.projectId,...e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=("string"==typeof e.error?e.error:e.error?.message)||e.message||`HTTP ${t.status}`;let s="";if(e.details)try{const t="string"==typeof e.details?JSON.parse(e.details):e.details;if(t.errors&&"object"==typeof t.errors){const e=Object.values(t.errors).flat().filter(Boolean);e.length&&(s=e.join("; "))}}catch{}throw new Error(`Failed to create checkout intent: ${s||r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getTransaction(e){const t=await fetch(`${this.baseUrl}/public/v1/onramp/transactions/${e}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get transaction: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}}async function l(e,t){return new u(e).getRate(t)}async function h(e){return new u(e).getCurrencies()}async function p(e,t){return new u({apiKey:"",projectId:"",...e}).validateAddress(t)}async function m(e,t){return new u({apiKey:"",projectId:"",...e}).validateAddressBatch(t)}async function f(e){return new u({apiKey:"",projectId:"",...e}).getSupportedNetworks()}async function g(e,t){return new u({apiKey:"",...e}).getSupported(t)}async function w(e,t){return new u({apiKey:"",...e}).getQuotes(t)}async function y(e,t){return new u({apiKey:"",...e}).createCheckoutIntent(t)}async function b(e,t){return new u({apiKey:"",projectId:"",...e}).getTransaction(t)}const A="0.1.13";export{e as ADDRESS_PATTERNS,t as ALLOWED_PROTOCOLS,s as API_KEY_PREFIXES,r as DEV_ALLOWED_HOSTNAMES,u as RampApi,d as RampWidget,A as VERSION,y as createCheckoutIntent,d as default,h as getCurrencies,w as getQuotes,l as getRate,g as getSupported,f as getSupportedNetworks,b as getTransaction,p as validateAddress,m as validateAddressBatch,a as validateAmount,o as validateApiKey,c as validateMessageOrigin,n as validateRedirectUrl,i as validateWalletAddress};
|
|
6
|
+
const e={evm:{pattern:/^0x[a-fA-F0-9]{40}$/,description:"EVM address must start with 0x followed by 40 hexadecimal characters"},solana:{pattern:/^[1-9A-HJ-NP-Za-km-z]{32,44}$/,description:"Solana address must be 32-44 base58 characters"},bitcoin:{pattern:/^(1[a-km-zA-HJ-NP-Z1-9]{25,34}|3[a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{39,59}|[LM][a-km-zA-HJ-NP-Z1-9]{25,34}|ltc1[a-z0-9]{39,59}|D[a-km-zA-HJ-NP-Z1-9]{25,34})$/i,description:"Bitcoin-family address (BTC, LTC, DOGE, BCH)"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},tron:{pattern:/^T[1-9A-HJ-NP-Za-km-z]{33}$/,description:"Tron address must start with T followed by 33 base58 characters"},cosmos:{pattern:/^[a-z]{1,20}1[a-z0-9]{38,58}$/,description:"Cosmos address must be bech32 encoded with chain-specific HRP"},substrate:{pattern:/^[1-9A-HJ-NP-Za-km-z]{46,50}$/,description:"Substrate/Polkadot address must be SS58 encoded (46-50 base58 characters)"},other:{pattern:/^.{10,200}$/,description:"Address format varies by network (10-200 characters)"}},t=["https:"],r=["localhost","127.0.0.1"],s={public:"pk_",secret:"sk_"};function o(e){return e?e.includes(s.secret)?{valid:!1,error:"Secret API keys (sk_) cannot be used in the SDK. Use a public key (pk_) instead. Secret keys should only be used in backend server code."}:(e.includes(s.public)||console.warn("RampWidget: API key does not have a public key prefix (pk_). For security, please generate a new public key for frontend use."),{valid:!0}):{valid:!1,error:"apiKey is required"}}function n(e){if(!e)return{valid:!0};try{const s=new URL(e);return t.includes(s.protocol)||"http:"===s.protocol&&r.includes(s.hostname)?{valid:!0}:{valid:!1,error:`redirectUrl must use HTTPS (got ${s.protocol})`}}catch{return{valid:!1,error:"redirectUrl is not a valid URL"}}}function i(t,r){if(!t)return{valid:!0};const s=t.trim();if(r){const t=r.toLowerCase(),o=e[t];if(o){const{pattern:e,description:t}=o;return e.test(s)?{valid:!0}:{valid:!1,error:t}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}function a(e,t,r,s){if(!e||""===e.trim())return{valid:!1,error:"Amount is required"};const o=parseFloat(e);if(isNaN(o))return{valid:!1,error:"Amount must be a valid number"};if(o<=0)return{valid:!1,error:"Amount must be greater than zero"};const n=s?` ${s}`:"";return o<t?{valid:!1,error:`Minimum amount is ${t}${n}`}:o>r?{valid:!1,error:`Maximum amount is ${r}${n}`}:{valid:!0}}function c(e,t){if(!t)return!0;try{if(e===new URL(t).origin)return!0;if("undefined"!=typeof process&&"production"===process.env?.NODE_ENV)return!1;const r=new URL(e);return"localhost"===r.hostname||"127.0.0.1"===r.hostname}catch{return!1}}class d{constructor(e){this.iframe=null,this.modalContainer=null,this.boundMessageHandler=null,this.isOpen=!1,this.config={widgetUrl:e.widgetUrl||"https://widget.nowramp.com/widget/latest/index.html",apiUrl:e.apiUrl||"https://api.nowramp.com",flowType:"buy",theme:"light",...e},this.validateConfig()}open(){this.isOpen?console.warn("RampWidget: Widget is already open"):(this.isOpen=!0,this.setupMessageListener(),this.createIframe())}close(){this.isOpen&&(this.isOpen=!1,this.cleanup(),this.config.onClose?.())}setAmount(e){this.sendCommand("SET_AMOUNT",e)}setTheme(e){this.sendCommand("SET_THEME",e)}refreshQuote(){this.sendCommand("REFRESH_QUOTE")}validateConfig(){if(!this.config.apiKey)throw new Error("RampWidget: apiKey is required");if(!this.config.projectId)throw new Error("RampWidget: projectId is required");if(!!(!this.config.sessionId||!this.config.clientSecret)&&!this.config.externalUserId)throw new Error("RampWidget: Either externalUserId (legacy) or sessionId + clientSecret (recommended) is required");if(this.config.sessionId&&!this.config.clientSecret)throw new Error("RampWidget: clientSecret is required when using sessionId");const e=o(this.config.apiKey);if(!e.valid)throw new Error(`RampWidget: ${e.error}`);if(this.config.redirectUrl){const e=n(this.config.redirectUrl);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}if(this.config.walletAddress){const e=i(this.config.walletAddress,void 0);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}}buildWidgetUrl(){const e=new URLSearchParams({apiKey:this.config.apiKey,projectId:this.config.projectId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return this.config.sessionId&&this.config.clientSecret&&(e.set("sessionId",this.config.sessionId),e.set("clientSecret",this.config.clientSecret)),this.config.externalUserId&&e.set("externalUserId",this.config.externalUserId),this.config.apiUrl&&e.set("apiUrl",this.config.apiUrl),this.config.locale&&e.set("locale",this.config.locale),void 0!==this.config.amount&&e.set("amount",String(this.config.amount)),this.config.sourceCurrency&&e.set("sourceCurrency",this.config.sourceCurrency),this.config.destinationCurrency&&e.set("destinationCurrency",this.config.destinationCurrency),this.config.walletAddress&&e.set("walletAddress",this.config.walletAddress),this.config.network&&e.set("network",this.config.network),this.config.redirectUrl&&e.set("redirectUrl",this.config.redirectUrl),!1===this.config.autoRedirect&&e.set("autoRedirect","false"),`${this.config.widgetUrl}?${e.toString()}`}createIframe(){this.iframe=document.createElement("iframe"),this.iframe.src=this.buildWidgetUrl(),this.iframe.style.border="none",this.iframe.style.width="100%",this.iframe.style.height="100%",this.iframe.allow="camera *; microphone *; geolocation *; encrypted-media *; clipboard-read; clipboard-write; payment *",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals allow-popups-without-user-activation allow-top-navigation allow-downloads");const e=this.getContainer();e?e.appendChild(this.iframe):this.createModal()}getContainer(){return this.config.container?"string"==typeof this.config.container?document.querySelector(this.config.container):this.config.container:null}createModal(){this.modalContainer=document.createElement("div"),this.modalContainer.style.cssText="\n position: fixed;\n inset: 0;\n z-index: 9999;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n ";const e="dark"===this.config.theme,t=document.createElement("div");t.style.cssText=`\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: ${e?"#000000":"white"};\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n `,this.iframe&&t.appendChild(this.iframe),this.modalContainer.appendChild(t),this.modalContainer.onclick=e=>{e.target===this.modalContainer&&this.close()};document.addEventListener("keydown",e=>{"Escape"===e.key&&this.close()}),document.body.appendChild(this.modalContainer),document.body.style.overflow="hidden"}setupMessageListener(){this.boundMessageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.boundMessageHandler)}handleMessage(e){if(!c(e.origin,this.config.widgetUrl))return;const t=e.data;if(t&&"ramp-widget"===t.source)switch(t.type){case"WIDGET_READY":this.config.onReady?.();break;case"WIDGET_CLOSE":this.close();break;case"STEP_CHANGE":this.config.onStepChange?.(t.payload.step);break;case"QUOTE_CREATED":this.config.onQuoteCreated?.(t.payload);break;case"ORDER_CREATED":this.config.onOrderCreated?.(t.payload);break;case"ORDER_COMPLETED":this.config.onSuccess?.(t.payload);break;case"ERROR":this.config.onError?.(t.payload)}}sendCommand(e,t){if(!this.iframe?.contentWindow)return void console.warn("RampWidget: Cannot send command, widget not open");const r=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},r)}cleanup(){this.boundMessageHandler&&(window.removeEventListener("message",this.boundMessageHandler),this.boundMessageHandler=null),this.iframe?.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.modalContainer?.parentNode&&(this.modalContainer.parentNode.removeChild(this.modalContainer),document.body.style.overflow=""),this.modalContainer=null}}class u{constructor(e){this.config=e,this.baseUrl=e.apiUrl||"https://api.nowramp.com"}async getRate(e){if(!this.config.apiKey)return this.getPublicRate(e);const t=await fetch(`${this.baseUrl}/v1/rates/convert`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.rate,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationAmount:s.destinationAmount,destinationCurrency:s.destinationCurrency,fees:{processingFee:s.fees?.processingFee||0,processingFeePercent:s.fees?.processingFeePercent||0,networkFee:s.fees?.networkFee||0,totalFee:s.fees?.totalFee||0},provider:s.provider||"unknown",expiresAt:s.expiresAt}}async getPublicRate(e){const t=await fetch(`${this.baseUrl}/public/wert/convert`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.ticker||s.rate,sourceAmount:s.currencyAmount||s.sourceAmount||e.amount,sourceCurrency:e.from,destinationAmount:s.commodityAmount||s.destinationAmount,destinationCurrency:e.to,fees:{processingFee:s.feeAmount||s.fees?.processingFee||0,processingFeePercent:s.feePercent||s.fees?.processingFeePercent||0,networkFee:s.currencyMinerFee||s.fees?.networkFee||0,totalFee:(s.feeAmount||0)+(s.currencyMinerFee||0)||s.fees?.totalFee||0},provider:"wert",expiresAt:s.expiresAt}}async getCurrencies(){if(!this.config.apiKey)return this.getPublicCurrencies();const e=await fetch(`${this.baseUrl}/v1/rates/currencies`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async getPublicCurrencies(){if(!this.config.projectId)throw new Error("projectId is required to fetch currencies without an API key");const e=await fetch(`${this.baseUrl}/public/projects/${this.config.projectId}/currencies`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async validateAddress(e){const t=await fetch(`${this.baseUrl}/public/validate/address`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate address: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async validateAddressBatch(e){if(e.length>20)throw new Error("Maximum 20 addresses per batch");const t=await fetch(`${this.baseUrl}/public/validate/address/batch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({addresses:e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate addresses: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getSupportedNetworks(){const e=await fetch(`${this.baseUrl}/public/validate/networks`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get supported networks: ${r}`)}const t=await e.json();return t.data?.attributes||t.data||t}async createSession(e){if(!this.config.apiKey)throw new Error("API key is required to create sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to create session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,clientSecret:s.clientSecret,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,expiresAt:s.expiresAt,createdAt:s.createdAt}}async getSession(e){if(!this.config.apiKey)throw new Error("API key is required to get session details.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,fieldLocks:s.fieldLocks,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async cancelSession(e){if(!this.config.apiKey)throw new Error("API key is required to cancel sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}/cancel`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to cancel session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"cancelled",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async getSupported(e){if(!this.config.projectId)throw new Error("projectId is required to get supported config");const t="string"==typeof e?{orderType:e}:e,r=new URLSearchParams({projectId:this.config.projectId});t?.orderType&&r.set("orderType",t.orderType),t?.country&&r.set("country",t.country);const s=await fetch(`${this.baseUrl}/public/v1/onramp/supported?${r}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!s.ok){const e=await s.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${s.status}`;throw new Error(`Failed to get supported config: ${t}`)}const o=await s.json();return o.data?.attributes||o.data||o}async getQuotes(e){if(!this.config.projectId)throw new Error("projectId is required to get quotes");const t=new URLSearchParams({projectId:this.config.projectId,fiatCurrency:e.fiatCurrency,cryptoCurrency:e.cryptoCurrency,network:e.network});e.fiatAmount&&t.set("fiatAmount",e.fiatAmount),e.cryptoAmount&&t.set("cryptoAmount",e.cryptoAmount),e.orderType&&t.set("orderType",e.orderType),e.paymentMethodId&&t.set("paymentMethodId",e.paymentMethodId),e.country&&t.set("country",e.country);const r=await fetch(`${this.baseUrl}/public/v1/onramp/quotes?${t}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){const e=await r.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${r.status}`;throw new Error(`Failed to get quotes: ${t}`)}const s=await r.json();return s.data?.attributes||s.data||s}async createCheckoutIntent(e){if(!this.config.projectId)throw new Error("projectId is required to create checkout intents");const t=await fetch(`${this.baseUrl}/public/v1/onramp/checkout-intent`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:this.config.projectId,...e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=("string"==typeof e.error?e.error:e.error?.message)||e.message||`HTTP ${t.status}`;let s="";if(e.details)try{const t="string"==typeof e.details?JSON.parse(e.details):e.details;if(t.errors&&"object"==typeof t.errors){const e=Object.values(t.errors).flat().filter(Boolean);e.length&&(s=e.join("; "))}}catch{}throw new Error(`Failed to create checkout intent: ${s||r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getTransaction(e){const t=await fetch(`${this.baseUrl}/public/v1/onramp/transactions/${e}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get transaction: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}}async function l(e,t){return new u(e).getRate(t)}async function h(e){return new u(e).getCurrencies()}async function p(e,t){return new u({apiKey:"",projectId:"",...e}).validateAddress(t)}async function m(e,t){return new u({apiKey:"",projectId:"",...e}).validateAddressBatch(t)}async function f(e){return new u({apiKey:"",projectId:"",...e}).getSupportedNetworks()}async function g(e,t){return new u({apiKey:"",...e}).getSupported(t)}async function w(e,t){return new u({apiKey:"",...e}).getQuotes(t)}async function y(e,t){return new u({apiKey:"",...e}).createCheckoutIntent(t)}async function b(e,t){return new u({apiKey:"",projectId:"",...e}).getTransaction(t)}const A="0.1.13";export{e as ADDRESS_PATTERNS,t as ALLOWED_PROTOCOLS,s as API_KEY_PREFIXES,r as DEV_ALLOWED_HOSTNAMES,u as RampApi,d as RampWidget,A as VERSION,y as createCheckoutIntent,d as default,h as getCurrencies,w as getQuotes,l as getRate,g as getSupported,f as getSupportedNetworks,b as getTransaction,p as validateAddress,m as validateAddressBatch,a as validateAmount,o as validateApiKey,c as validateMessageOrigin,n as validateRedirectUrl,i as validateWalletAddress};
|
package/dist/sdk.umd.js
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* (c) 2026 NowRamp
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
6
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).NowRamp={})}(this,function(e){"use strict";const t={evm:{pattern:/^0x[a-fA-F0-9]{40}$/,description:"EVM address must start with 0x followed by 40 hexadecimal characters"},solana:{pattern:/^[1-9A-HJ-NP-Za-km-z]{32,44}$/,description:"Solana address must be 32-44 base58 characters"},bitcoin:{pattern:/^(1[a-km-zA-HJ-NP-Z1-9]{25,34}|3[a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{39,59}|[LM][a-km-zA-HJ-NP-Z1-9]{25,34}|ltc1[a-z0-9]{39,59}|D[a-km-zA-HJ-NP-Z1-9]{25,34})$/i,description:"Bitcoin-family address (BTC, LTC, DOGE, BCH)"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},tron:{pattern:/^T[1-9A-HJ-NP-Za-km-z]{33}$/,description:"Tron address must start with T followed by 33 base58 characters"},cosmos:{pattern:/^[a-z]{1,20}1[a-z0-9]{38,58}$/,description:"Cosmos address must be bech32 encoded with chain-specific HRP"},substrate:{pattern:/^[1-9A-HJ-NP-Za-km-z]{46,50}$/,description:"Substrate/Polkadot address must be SS58 encoded (46-50 base58 characters)"},other:{pattern:/^.{10,200}$/,description:"Address format varies by network (10-200 characters)"}},r=["https:"],s=["localhost","127.0.0.1"],o={public:"pk_",secret:"sk_"};function n(e){return e?e.includes(o.secret)?{valid:!1,error:"Secret API keys (sk_) cannot be used in the SDK. Use a public key (pk_) instead. Secret keys should only be used in backend server code."}:(e.includes(o.public)||console.warn("RampWidget: API key does not have a public key prefix (pk_). For security, please generate a new public key for frontend use."),{valid:!0}):{valid:!1,error:"apiKey is required"}}function i(e){if(!e)return{valid:!0};try{const t=new URL(e);return r.includes(t.protocol)||"http:"===t.protocol&&s.includes(t.hostname)?{valid:!0}:{valid:!1,error:`redirectUrl must use HTTPS (got ${t.protocol})`}}catch{return{valid:!1,error:"redirectUrl is not a valid URL"}}}function a(e,r){if(!e)return{valid:!0};const s=e.trim();if(r){const e=r.toLowerCase(),o=t[e];if(o){const{pattern:e,description:t}=o;return e.test(s)?{valid:!0}:{valid:!1,error:t}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}function c(e,t){if(!t)return!0;try{if(e===new URL(t).origin)return!0;const r=new URL(e);return"localhost"===r.hostname||"127.0.0.1"===r.hostname}catch{return!1}}class d{constructor(e){this.iframe=null,this.modalContainer=null,this.boundMessageHandler=null,this.isOpen=!1,this.config={widgetUrl:e.widgetUrl||"https://widget.nowramp.com/widget/latest/index.html",apiUrl:e.apiUrl||"https://api.nowramp.com",flowType:"buy",theme:"light",...e},this.validateConfig()}open(){this.isOpen?console.warn("RampWidget: Widget is already open"):(this.isOpen=!0,this.setupMessageListener(),this.createIframe())}close(){this.isOpen&&(this.isOpen=!1,this.cleanup(),this.config.onClose?.())}setAmount(e){this.sendCommand("SET_AMOUNT",e)}setTheme(e){this.sendCommand("SET_THEME",e)}refreshQuote(){this.sendCommand("REFRESH_QUOTE")}validateConfig(){if(!this.config.apiKey)throw new Error("RampWidget: apiKey is required");if(!this.config.projectId)throw new Error("RampWidget: projectId is required");if(!!(!this.config.sessionId||!this.config.clientSecret)&&!this.config.externalUserId)throw new Error("RampWidget: Either externalUserId (legacy) or sessionId + clientSecret (recommended) is required");if(this.config.sessionId&&!this.config.clientSecret)throw new Error("RampWidget: clientSecret is required when using sessionId");const e=n(this.config.apiKey);if(!e.valid)throw new Error(`RampWidget: ${e.error}`);if(this.config.redirectUrl){const e=i(this.config.redirectUrl);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}if(this.config.walletAddress){const e=a(this.config.walletAddress,void 0);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}}buildWidgetUrl(){const e=new URLSearchParams({apiKey:this.config.apiKey,projectId:this.config.projectId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return this.config.sessionId&&this.config.clientSecret&&(e.set("sessionId",this.config.sessionId),e.set("clientSecret",this.config.clientSecret)),this.config.externalUserId&&e.set("externalUserId",this.config.externalUserId),this.config.apiUrl&&e.set("apiUrl",this.config.apiUrl),this.config.locale&&e.set("locale",this.config.locale),void 0!==this.config.amount&&e.set("amount",String(this.config.amount)),this.config.sourceCurrency&&e.set("sourceCurrency",this.config.sourceCurrency),this.config.destinationCurrency&&e.set("destinationCurrency",this.config.destinationCurrency),this.config.walletAddress&&e.set("walletAddress",this.config.walletAddress),this.config.network&&e.set("network",this.config.network),this.config.redirectUrl&&e.set("redirectUrl",this.config.redirectUrl),!1===this.config.autoRedirect&&e.set("autoRedirect","false"),`${this.config.widgetUrl}?${e.toString()}`}createIframe(){this.iframe=document.createElement("iframe"),this.iframe.src=this.buildWidgetUrl(),this.iframe.style.border="none",this.iframe.style.width="100%",this.iframe.style.height="100%",this.iframe.allow="camera *; microphone *; geolocation *; encrypted-media *; clipboard-read; clipboard-write; payment *",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals allow-popups-without-user-activation allow-top-navigation allow-downloads");const e=this.getContainer();e?e.appendChild(this.iframe):this.createModal()}getContainer(){return this.config.container?"string"==typeof this.config.container?document.querySelector(this.config.container):this.config.container:null}createModal(){this.modalContainer=document.createElement("div"),this.modalContainer.style.cssText="\n position: fixed;\n inset: 0;\n z-index: 9999;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n ";const e="dark"===this.config.theme,t=document.createElement("div");t.style.cssText=`\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: ${e?"#000000":"white"};\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n `,this.iframe&&t.appendChild(this.iframe),this.modalContainer.appendChild(t),this.modalContainer.onclick=e=>{e.target===this.modalContainer&&this.close()};document.addEventListener("keydown",e=>{"Escape"===e.key&&this.close()}),document.body.appendChild(this.modalContainer),document.body.style.overflow="hidden"}setupMessageListener(){this.boundMessageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.boundMessageHandler)}handleMessage(e){if(!c(e.origin,this.config.widgetUrl))return;const t=e.data;if(t&&"ramp-widget"===t.source)switch(t.type){case"WIDGET_READY":this.config.onReady?.();break;case"WIDGET_CLOSE":this.close();break;case"STEP_CHANGE":this.config.onStepChange?.(t.payload.step);break;case"QUOTE_CREATED":this.config.onQuoteCreated?.(t.payload);break;case"ORDER_CREATED":this.config.onOrderCreated?.(t.payload);break;case"ORDER_COMPLETED":this.config.onSuccess?.(t.payload);break;case"ERROR":this.config.onError?.(t.payload)}}sendCommand(e,t){if(!this.iframe?.contentWindow)return void console.warn("RampWidget: Cannot send command, widget not open");const r=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},r)}cleanup(){this.boundMessageHandler&&(window.removeEventListener("message",this.boundMessageHandler),this.boundMessageHandler=null),this.iframe?.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.modalContainer?.parentNode&&(this.modalContainer.parentNode.removeChild(this.modalContainer),document.body.style.overflow=""),this.modalContainer=null}}class u{constructor(e){this.config=e,this.baseUrl=e.apiUrl||"https://api.nowramp.com"}async getRate(e){if(!this.config.apiKey)return this.getPublicRate(e);const t=await fetch(`${this.baseUrl}/v1/rates/convert`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.rate,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationAmount:s.destinationAmount,destinationCurrency:s.destinationCurrency,fees:{processingFee:s.fees?.processingFee||0,processingFeePercent:s.fees?.processingFeePercent||0,networkFee:s.fees?.networkFee||0,totalFee:s.fees?.totalFee||0},provider:s.provider||"unknown",expiresAt:s.expiresAt}}async getPublicRate(e){const t=await fetch(`${this.baseUrl}/public/wert/convert`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.ticker||s.rate,sourceAmount:s.currencyAmount||s.sourceAmount||e.amount,sourceCurrency:e.from,destinationAmount:s.commodityAmount||s.destinationAmount,destinationCurrency:e.to,fees:{processingFee:s.feeAmount||s.fees?.processingFee||0,processingFeePercent:s.feePercent||s.fees?.processingFeePercent||0,networkFee:s.currencyMinerFee||s.fees?.networkFee||0,totalFee:(s.feeAmount||0)+(s.currencyMinerFee||0)||s.fees?.totalFee||0},provider:"wert",expiresAt:s.expiresAt}}async getCurrencies(){if(!this.config.apiKey)return this.getPublicCurrencies();const e=await fetch(`${this.baseUrl}/v1/rates/currencies`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async getPublicCurrencies(){if(!this.config.projectId)throw new Error("projectId is required to fetch currencies without an API key");const e=await fetch(`${this.baseUrl}/public/projects/${this.config.projectId}/currencies`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async validateAddress(e){const t=await fetch(`${this.baseUrl}/public/validate/address`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate address: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async validateAddressBatch(e){if(e.length>20)throw new Error("Maximum 20 addresses per batch");const t=await fetch(`${this.baseUrl}/public/validate/address/batch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({addresses:e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate addresses: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getSupportedNetworks(){const e=await fetch(`${this.baseUrl}/public/validate/networks`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get supported networks: ${r}`)}const t=await e.json();return t.data?.attributes||t.data||t}async createSession(e){if(!this.config.apiKey)throw new Error("API key is required to create sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to create session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,clientSecret:s.clientSecret,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,expiresAt:s.expiresAt,createdAt:s.createdAt}}async getSession(e){if(!this.config.apiKey)throw new Error("API key is required to get session details.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,fieldLocks:s.fieldLocks,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async cancelSession(e){if(!this.config.apiKey)throw new Error("API key is required to cancel sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}/cancel`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to cancel session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"cancelled",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async getSupported(e){if(!this.config.projectId)throw new Error("projectId is required to get supported config");const t="string"==typeof e?{orderType:e}:e,r=new URLSearchParams({projectId:this.config.projectId});t?.orderType&&r.set("orderType",t.orderType),t?.country&&r.set("country",t.country);const s=await fetch(`${this.baseUrl}/public/v1/onramp/supported?${r}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!s.ok){const e=await s.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${s.status}`;throw new Error(`Failed to get supported config: ${t}`)}const o=await s.json();return o.data?.attributes||o.data||o}async getQuotes(e){if(!this.config.projectId)throw new Error("projectId is required to get quotes");const t=new URLSearchParams({projectId:this.config.projectId,fiatCurrency:e.fiatCurrency,cryptoCurrency:e.cryptoCurrency,network:e.network});e.fiatAmount&&t.set("fiatAmount",e.fiatAmount),e.cryptoAmount&&t.set("cryptoAmount",e.cryptoAmount),e.orderType&&t.set("orderType",e.orderType),e.paymentMethodId&&t.set("paymentMethodId",e.paymentMethodId),e.country&&t.set("country",e.country);const r=await fetch(`${this.baseUrl}/public/v1/onramp/quotes?${t}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){const e=await r.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${r.status}`;throw new Error(`Failed to get quotes: ${t}`)}const s=await r.json();return s.data?.attributes||s.data||s}async createCheckoutIntent(e){if(!this.config.projectId)throw new Error("projectId is required to create checkout intents");const t=await fetch(`${this.baseUrl}/public/v1/onramp/checkout-intent`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:this.config.projectId,...e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=("string"==typeof e.error?e.error:e.error?.message)||e.message||`HTTP ${t.status}`;let s="";if(e.details)try{const t="string"==typeof e.details?JSON.parse(e.details):e.details;if(t.errors&&"object"==typeof t.errors){const e=Object.values(t.errors).flat().filter(Boolean);e.length&&(s=e.join("; "))}}catch{}throw new Error(`Failed to create checkout intent: ${s||r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getTransaction(e){const t=await fetch(`${this.baseUrl}/public/v1/onramp/transactions/${e}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get transaction: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}}e.ADDRESS_PATTERNS=t,e.ALLOWED_PROTOCOLS=r,e.API_KEY_PREFIXES=o,e.DEV_ALLOWED_HOSTNAMES=s,e.RampApi=u,e.RampWidget=d,e.VERSION="0.1.13",e.createCheckoutIntent=async function(e,t){return new u({apiKey:"",...e}).createCheckoutIntent(t)},e.default=d,e.getCurrencies=async function(e){return new u(e).getCurrencies()},e.getQuotes=async function(e,t){return new u({apiKey:"",...e}).getQuotes(t)},e.getRate=async function(e,t){return new u(e).getRate(t)},e.getSupported=async function(e,t){return new u({apiKey:"",...e}).getSupported(t)},e.getSupportedNetworks=async function(e){return new u({apiKey:"",projectId:"",...e}).getSupportedNetworks()},e.getTransaction=async function(e,t){return new u({apiKey:"",projectId:"",...e}).getTransaction(t)},e.validateAddress=async function(e,t){return new u({apiKey:"",projectId:"",...e}).validateAddress(t)},e.validateAddressBatch=async function(e,t){return new u({apiKey:"",projectId:"",...e}).validateAddressBatch(t)},e.validateAmount=function(e,t,r,s){if(!e||""===e.trim())return{valid:!1,error:"Amount is required"};const o=parseFloat(e);if(isNaN(o))return{valid:!1,error:"Amount must be a valid number"};if(o<=0)return{valid:!1,error:"Amount must be greater than zero"};const n=s?` ${s}`:"";return o<t?{valid:!1,error:`Minimum amount is ${t}${n}`}:o>r?{valid:!1,error:`Maximum amount is ${r}${n}`}:{valid:!0}},e.validateApiKey=n,e.validateMessageOrigin=c,e.validateRedirectUrl=i,e.validateWalletAddress=a,Object.defineProperty(e,"__esModule",{value:!0})});
|
|
6
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).NowRamp={})}(this,function(e){"use strict";const t={evm:{pattern:/^0x[a-fA-F0-9]{40}$/,description:"EVM address must start with 0x followed by 40 hexadecimal characters"},solana:{pattern:/^[1-9A-HJ-NP-Za-km-z]{32,44}$/,description:"Solana address must be 32-44 base58 characters"},bitcoin:{pattern:/^(1[a-km-zA-HJ-NP-Z1-9]{25,34}|3[a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{39,59}|[LM][a-km-zA-HJ-NP-Z1-9]{25,34}|ltc1[a-z0-9]{39,59}|D[a-km-zA-HJ-NP-Z1-9]{25,34})$/i,description:"Bitcoin-family address (BTC, LTC, DOGE, BCH)"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},tron:{pattern:/^T[1-9A-HJ-NP-Za-km-z]{33}$/,description:"Tron address must start with T followed by 33 base58 characters"},cosmos:{pattern:/^[a-z]{1,20}1[a-z0-9]{38,58}$/,description:"Cosmos address must be bech32 encoded with chain-specific HRP"},substrate:{pattern:/^[1-9A-HJ-NP-Za-km-z]{46,50}$/,description:"Substrate/Polkadot address must be SS58 encoded (46-50 base58 characters)"},other:{pattern:/^.{10,200}$/,description:"Address format varies by network (10-200 characters)"}},r=["https:"],s=["localhost","127.0.0.1"],o={public:"pk_",secret:"sk_"};function n(e){return e?e.includes(o.secret)?{valid:!1,error:"Secret API keys (sk_) cannot be used in the SDK. Use a public key (pk_) instead. Secret keys should only be used in backend server code."}:(e.includes(o.public)||console.warn("RampWidget: API key does not have a public key prefix (pk_). For security, please generate a new public key for frontend use."),{valid:!0}):{valid:!1,error:"apiKey is required"}}function i(e){if(!e)return{valid:!0};try{const t=new URL(e);return r.includes(t.protocol)||"http:"===t.protocol&&s.includes(t.hostname)?{valid:!0}:{valid:!1,error:`redirectUrl must use HTTPS (got ${t.protocol})`}}catch{return{valid:!1,error:"redirectUrl is not a valid URL"}}}function a(e,r){if(!e)return{valid:!0};const s=e.trim();if(r){const e=r.toLowerCase(),o=t[e];if(o){const{pattern:e,description:t}=o;return e.test(s)?{valid:!0}:{valid:!1,error:t}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=200?{valid:!0}:{valid:!1,error:"Address format not recognized"}}function c(e,t){if(!t)return!0;try{if(e===new URL(t).origin)return!0;if("undefined"!=typeof process&&"production"===process.env?.NODE_ENV)return!1;const r=new URL(e);return"localhost"===r.hostname||"127.0.0.1"===r.hostname}catch{return!1}}class d{constructor(e){this.iframe=null,this.modalContainer=null,this.boundMessageHandler=null,this.isOpen=!1,this.config={widgetUrl:e.widgetUrl||"https://widget.nowramp.com/widget/latest/index.html",apiUrl:e.apiUrl||"https://api.nowramp.com",flowType:"buy",theme:"light",...e},this.validateConfig()}open(){this.isOpen?console.warn("RampWidget: Widget is already open"):(this.isOpen=!0,this.setupMessageListener(),this.createIframe())}close(){this.isOpen&&(this.isOpen=!1,this.cleanup(),this.config.onClose?.())}setAmount(e){this.sendCommand("SET_AMOUNT",e)}setTheme(e){this.sendCommand("SET_THEME",e)}refreshQuote(){this.sendCommand("REFRESH_QUOTE")}validateConfig(){if(!this.config.apiKey)throw new Error("RampWidget: apiKey is required");if(!this.config.projectId)throw new Error("RampWidget: projectId is required");if(!!(!this.config.sessionId||!this.config.clientSecret)&&!this.config.externalUserId)throw new Error("RampWidget: Either externalUserId (legacy) or sessionId + clientSecret (recommended) is required");if(this.config.sessionId&&!this.config.clientSecret)throw new Error("RampWidget: clientSecret is required when using sessionId");const e=n(this.config.apiKey);if(!e.valid)throw new Error(`RampWidget: ${e.error}`);if(this.config.redirectUrl){const e=i(this.config.redirectUrl);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}if(this.config.walletAddress){const e=a(this.config.walletAddress,void 0);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}}buildWidgetUrl(){const e=new URLSearchParams({apiKey:this.config.apiKey,projectId:this.config.projectId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return this.config.sessionId&&this.config.clientSecret&&(e.set("sessionId",this.config.sessionId),e.set("clientSecret",this.config.clientSecret)),this.config.externalUserId&&e.set("externalUserId",this.config.externalUserId),this.config.apiUrl&&e.set("apiUrl",this.config.apiUrl),this.config.locale&&e.set("locale",this.config.locale),void 0!==this.config.amount&&e.set("amount",String(this.config.amount)),this.config.sourceCurrency&&e.set("sourceCurrency",this.config.sourceCurrency),this.config.destinationCurrency&&e.set("destinationCurrency",this.config.destinationCurrency),this.config.walletAddress&&e.set("walletAddress",this.config.walletAddress),this.config.network&&e.set("network",this.config.network),this.config.redirectUrl&&e.set("redirectUrl",this.config.redirectUrl),!1===this.config.autoRedirect&&e.set("autoRedirect","false"),`${this.config.widgetUrl}?${e.toString()}`}createIframe(){this.iframe=document.createElement("iframe"),this.iframe.src=this.buildWidgetUrl(),this.iframe.style.border="none",this.iframe.style.width="100%",this.iframe.style.height="100%",this.iframe.allow="camera *; microphone *; geolocation *; encrypted-media *; clipboard-read; clipboard-write; payment *",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals allow-popups-without-user-activation allow-top-navigation allow-downloads");const e=this.getContainer();e?e.appendChild(this.iframe):this.createModal()}getContainer(){return this.config.container?"string"==typeof this.config.container?document.querySelector(this.config.container):this.config.container:null}createModal(){this.modalContainer=document.createElement("div"),this.modalContainer.style.cssText="\n position: fixed;\n inset: 0;\n z-index: 9999;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n ";const e="dark"===this.config.theme,t=document.createElement("div");t.style.cssText=`\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: ${e?"#000000":"white"};\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n `,this.iframe&&t.appendChild(this.iframe),this.modalContainer.appendChild(t),this.modalContainer.onclick=e=>{e.target===this.modalContainer&&this.close()};document.addEventListener("keydown",e=>{"Escape"===e.key&&this.close()}),document.body.appendChild(this.modalContainer),document.body.style.overflow="hidden"}setupMessageListener(){this.boundMessageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.boundMessageHandler)}handleMessage(e){if(!c(e.origin,this.config.widgetUrl))return;const t=e.data;if(t&&"ramp-widget"===t.source)switch(t.type){case"WIDGET_READY":this.config.onReady?.();break;case"WIDGET_CLOSE":this.close();break;case"STEP_CHANGE":this.config.onStepChange?.(t.payload.step);break;case"QUOTE_CREATED":this.config.onQuoteCreated?.(t.payload);break;case"ORDER_CREATED":this.config.onOrderCreated?.(t.payload);break;case"ORDER_COMPLETED":this.config.onSuccess?.(t.payload);break;case"ERROR":this.config.onError?.(t.payload)}}sendCommand(e,t){if(!this.iframe?.contentWindow)return void console.warn("RampWidget: Cannot send command, widget not open");const r=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},r)}cleanup(){this.boundMessageHandler&&(window.removeEventListener("message",this.boundMessageHandler),this.boundMessageHandler=null),this.iframe?.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,this.modalContainer?.parentNode&&(this.modalContainer.parentNode.removeChild(this.modalContainer),document.body.style.overflow=""),this.modalContainer=null}}class u{constructor(e){this.config=e,this.baseUrl=e.apiUrl||"https://api.nowramp.com"}async getRate(e){if(!this.config.apiKey)return this.getPublicRate(e);const t=await fetch(`${this.baseUrl}/v1/rates/convert`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.rate,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationAmount:s.destinationAmount,destinationCurrency:s.destinationCurrency,fees:{processingFee:s.fees?.processingFee||0,processingFeePercent:s.fees?.processingFeePercent||0,networkFee:s.fees?.networkFee||0,totalFee:s.fees?.totalFee||0},provider:s.provider||"unknown",expiresAt:s.expiresAt}}async getPublicRate(e){const t=await fetch(`${this.baseUrl}/public/wert/convert`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({from:e.from,to:e.to,amount:e.amount,flowType:e.flowType||"buy"})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{rate:s.ticker||s.rate,sourceAmount:s.currencyAmount||s.sourceAmount||e.amount,sourceCurrency:e.from,destinationAmount:s.commodityAmount||s.destinationAmount,destinationCurrency:e.to,fees:{processingFee:s.feeAmount||s.fees?.processingFee||0,processingFeePercent:s.feePercent||s.fees?.processingFeePercent||0,networkFee:s.currencyMinerFee||s.fees?.networkFee||0,totalFee:(s.feeAmount||0)+(s.currencyMinerFee||0)||s.fees?.totalFee||0},provider:"wert",expiresAt:s.expiresAt}}async getCurrencies(){if(!this.config.apiKey)return this.getPublicCurrencies();const e=await fetch(`${this.baseUrl}/v1/rates/currencies`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async getPublicCurrencies(){if(!this.config.projectId)throw new Error("projectId is required to fetch currencies without an API key");const e=await fetch(`${this.baseUrl}/public/projects/${this.config.projectId}/currencies`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${r}`)}const t=await e.json(),r=t.data?.attributes||t.data||t;return{fiat:r.fiat||[],crypto:r.crypto||[],provider:r.provider||"unknown",environment:r.environment||"sandbox"}}async validateAddress(e){const t=await fetch(`${this.baseUrl}/public/validate/address`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate address: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async validateAddressBatch(e){if(e.length>20)throw new Error("Maximum 20 addresses per batch");const t=await fetch(`${this.baseUrl}/public/validate/address/batch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({addresses:e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate addresses: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getSupportedNetworks(){const e=await fetch(`${this.baseUrl}/public/validate/networks`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.json().catch(()=>({})),r=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get supported networks: ${r}`)}const t=await e.json();return t.data?.attributes||t.data||t}async createSession(e){if(!this.config.apiKey)throw new Error("API key is required to create sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify(e)});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to create session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,clientSecret:s.clientSecret,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,expiresAt:s.expiresAt,createdAt:s.createdAt}}async getSession(e){if(!this.config.apiKey)throw new Error("API key is required to get session details.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}`,{method:"GET",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"pending",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,fieldLocks:s.fieldLocks,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async cancelSession(e){if(!this.config.apiKey)throw new Error("API key is required to cancel sessions. Use a secret key (sk_) for this operation.");const t=await fetch(`${this.baseUrl}/v1/sessions/${e}/cancel`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to cancel session: ${r}`)}const r=await t.json(),s=r.data?.attributes||r.data||r;return{sessionId:r.data?.id||s.sessionId,type:s.type||"onramp",status:s.status||"cancelled",customerId:s.customerId,externalCustomerId:s.externalCustomerId,sourceAmount:s.sourceAmount,sourceCurrency:s.sourceCurrency,destinationCurrency:s.destinationCurrency,destinationAddress:s.destinationAddress,network:s.network,redirectUrl:s.redirectUrl,metadata:s.metadata,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async getSupported(e){if(!this.config.projectId)throw new Error("projectId is required to get supported config");const t="string"==typeof e?{orderType:e}:e,r=new URLSearchParams({projectId:this.config.projectId});t?.orderType&&r.set("orderType",t.orderType),t?.country&&r.set("country",t.country);const s=await fetch(`${this.baseUrl}/public/v1/onramp/supported?${r}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!s.ok){const e=await s.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${s.status}`;throw new Error(`Failed to get supported config: ${t}`)}const o=await s.json();return o.data?.attributes||o.data||o}async getQuotes(e){if(!this.config.projectId)throw new Error("projectId is required to get quotes");const t=new URLSearchParams({projectId:this.config.projectId,fiatCurrency:e.fiatCurrency,cryptoCurrency:e.cryptoCurrency,network:e.network});e.fiatAmount&&t.set("fiatAmount",e.fiatAmount),e.cryptoAmount&&t.set("cryptoAmount",e.cryptoAmount),e.orderType&&t.set("orderType",e.orderType),e.paymentMethodId&&t.set("paymentMethodId",e.paymentMethodId),e.country&&t.set("country",e.country);const r=await fetch(`${this.baseUrl}/public/v1/onramp/quotes?${t}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!r.ok){const e=await r.json().catch(()=>({})),t=e.error?.message||e.message||`HTTP ${r.status}`;throw new Error(`Failed to get quotes: ${t}`)}const s=await r.json();return s.data?.attributes||s.data||s}async createCheckoutIntent(e){if(!this.config.projectId)throw new Error("projectId is required to create checkout intents");const t=await fetch(`${this.baseUrl}/public/v1/onramp/checkout-intent`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:this.config.projectId,...e})});if(!t.ok){const e=await t.json().catch(()=>({})),r=("string"==typeof e.error?e.error:e.error?.message)||e.message||`HTTP ${t.status}`;let s="";if(e.details)try{const t="string"==typeof e.details?JSON.parse(e.details):e.details;if(t.errors&&"object"==typeof t.errors){const e=Object.values(t.errors).flat().filter(Boolean);e.length&&(s=e.join("; "))}}catch{}throw new Error(`Failed to create checkout intent: ${s||r}`)}const r=await t.json();return r.data?.attributes||r.data||r}async getTransaction(e){const t=await fetch(`${this.baseUrl}/public/v1/onramp/transactions/${e}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!t.ok){const e=await t.json().catch(()=>({})),r=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get transaction: ${r}`)}const r=await t.json();return r.data?.attributes||r.data||r}}e.ADDRESS_PATTERNS=t,e.ALLOWED_PROTOCOLS=r,e.API_KEY_PREFIXES=o,e.DEV_ALLOWED_HOSTNAMES=s,e.RampApi=u,e.RampWidget=d,e.VERSION="0.1.13",e.createCheckoutIntent=async function(e,t){return new u({apiKey:"",...e}).createCheckoutIntent(t)},e.default=d,e.getCurrencies=async function(e){return new u(e).getCurrencies()},e.getQuotes=async function(e,t){return new u({apiKey:"",...e}).getQuotes(t)},e.getRate=async function(e,t){return new u(e).getRate(t)},e.getSupported=async function(e,t){return new u({apiKey:"",...e}).getSupported(t)},e.getSupportedNetworks=async function(e){return new u({apiKey:"",projectId:"",...e}).getSupportedNetworks()},e.getTransaction=async function(e,t){return new u({apiKey:"",projectId:"",...e}).getTransaction(t)},e.validateAddress=async function(e,t){return new u({apiKey:"",projectId:"",...e}).validateAddress(t)},e.validateAddressBatch=async function(e,t){return new u({apiKey:"",projectId:"",...e}).validateAddressBatch(t)},e.validateAmount=function(e,t,r,s){if(!e||""===e.trim())return{valid:!1,error:"Amount is required"};const o=parseFloat(e);if(isNaN(o))return{valid:!1,error:"Amount must be a valid number"};if(o<=0)return{valid:!1,error:"Amount must be greater than zero"};const n=s?` ${s}`:"";return o<t?{valid:!1,error:`Minimum amount is ${t}${n}`}:o>r?{valid:!1,error:`Maximum amount is ${r}${n}`}:{valid:!0}},e.validateApiKey=n,e.validateMessageOrigin=c,e.validateRedirectUrl=i,e.validateWalletAddress=a,Object.defineProperty(e,"__esModule",{value:!0})});
|