@nowramp/sdk 0.1.28 → 0.1.30
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.d.ts +357 -169
- 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})$/,description:"Bitcoin address must be a valid legacy, SegWit, or native SegWit format"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},other:{pattern:/^.{10,100}$/,description:"Address format varies by network (10-100 characters)"}},t=["https:"],r=["localhost","127.0.0.1"],s={public:"pk_",secret:"sk_"};function i(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 o(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 n(t,r){if(!t)return{valid:!0};const s=t.trim();if(r){const t=r.toLowerCase(),i=e[t];if(i){const{pattern:e,description:t}=i;return e.test(s)?{valid:!0}:{valid:!1,error:t}}return s.length>=10&&s.length<=100?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=100?{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=i(this.config.apiKey);if(!e.valid)throw new Error(`RampWidget: ${e.error}`);if(this.config.redirectUrl){const e=o(this.config.redirectUrl);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}if(this.config.walletAddress){const e=n(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}}}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.default=c,exports.getCurrencies=async function(e){return new d(e).getCurrencies()},exports.getRate=async function(e,t){return new d(e).getRate(t)},exports.getSupportedNetworks=async function(e){return new d({apiKey:"",projectId:"",...e}).getSupportedNetworks()},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.validateApiKey=i,exports.validateMessageOrigin=a,exports.validateRedirectUrl=o,exports.validateWalletAddress=n;
|
|
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})$/,description:"Bitcoin address must be a valid legacy, SegWit, or native SegWit format"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},other:{pattern:/^.{10,100}$/,description:"Address format varies by network (10-100 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<=100?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=100?{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=new URLSearchParams({projectId:this.config.projectId});e&&t.set("orderType",e);const r=await fetch(`${this.baseUrl}/public/v1/onramp/supported?${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 supported config: ${t}`)}const s=await r.json();return s.data?.attributes||s.data||s}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.d.ts
CHANGED
|
@@ -416,6 +416,319 @@ interface SessionWithSecret extends Session {
|
|
|
416
416
|
/** Client secret for session confirmation (only returned once) */
|
|
417
417
|
clientSecret: string;
|
|
418
418
|
}
|
|
419
|
+
/**
|
|
420
|
+
* Gateway (provider) information
|
|
421
|
+
*/
|
|
422
|
+
interface Gateway {
|
|
423
|
+
/** Gateway ID (e.g., 'banxa', 'wert') */
|
|
424
|
+
id: string;
|
|
425
|
+
/** Display name */
|
|
426
|
+
name: string;
|
|
427
|
+
/** Gateway logo URL */
|
|
428
|
+
logo: string;
|
|
429
|
+
/** Whether this gateway is enabled */
|
|
430
|
+
enabled: boolean;
|
|
431
|
+
/** Gateway capabilities */
|
|
432
|
+
features: GatewayFeatures;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Gateway feature flags
|
|
436
|
+
*/
|
|
437
|
+
interface GatewayFeatures {
|
|
438
|
+
/** Supports iframe checkout */
|
|
439
|
+
supportsIframe: boolean;
|
|
440
|
+
/** Supports widget checkout */
|
|
441
|
+
supportsWidget: boolean;
|
|
442
|
+
/** Supports buying crypto */
|
|
443
|
+
supportsBuy: boolean;
|
|
444
|
+
/** Supports selling crypto */
|
|
445
|
+
supportsSell: boolean;
|
|
446
|
+
/** Supports recurring purchases */
|
|
447
|
+
supportsRecurring: boolean;
|
|
448
|
+
/** KYC is handled by the gateway */
|
|
449
|
+
kycHandledByProvider: boolean;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Fiat currency with provider-specific details
|
|
453
|
+
*/
|
|
454
|
+
interface SupportedFiat {
|
|
455
|
+
/** Currency code (e.g., 'USD') */
|
|
456
|
+
code: string;
|
|
457
|
+
/** Display name (e.g., 'US Dollar') */
|
|
458
|
+
name: string;
|
|
459
|
+
/** Symbol (e.g., '$') */
|
|
460
|
+
symbol: string;
|
|
461
|
+
/** Minimum amount */
|
|
462
|
+
minAmount: string;
|
|
463
|
+
/** Maximum amount */
|
|
464
|
+
maxAmount: string;
|
|
465
|
+
/** Supported payment methods */
|
|
466
|
+
paymentMethods: string[];
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Crypto currency with network info
|
|
470
|
+
*/
|
|
471
|
+
interface SupportedCrypto {
|
|
472
|
+
/** Currency code (e.g., 'ETH') */
|
|
473
|
+
code: string;
|
|
474
|
+
/** Display name (e.g., 'Ethereum') */
|
|
475
|
+
name: string;
|
|
476
|
+
/** Available networks */
|
|
477
|
+
networks: SupportedNetworkInfo[];
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Blockchain network
|
|
481
|
+
*/
|
|
482
|
+
interface SupportedNetworkInfo {
|
|
483
|
+
/** Network ID (e.g., 'ethereum', 'polygon') */
|
|
484
|
+
id: string;
|
|
485
|
+
/** Display name (e.g., 'Ethereum Mainnet') */
|
|
486
|
+
name: string;
|
|
487
|
+
/** Minimum amount */
|
|
488
|
+
minAmount: string;
|
|
489
|
+
/** Maximum amount */
|
|
490
|
+
maxAmount: string;
|
|
491
|
+
/** Is the default network for this crypto */
|
|
492
|
+
isDefault: boolean;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Payment method
|
|
496
|
+
*/
|
|
497
|
+
interface SupportedPaymentMethod {
|
|
498
|
+
/** Method ID (e.g., 'debit-credit-card') */
|
|
499
|
+
id: string;
|
|
500
|
+
/** Display name */
|
|
501
|
+
name: string;
|
|
502
|
+
/** Description */
|
|
503
|
+
description?: string;
|
|
504
|
+
/** Supported fiat currencies */
|
|
505
|
+
supportedFiats: string[];
|
|
506
|
+
/** Icon URL */
|
|
507
|
+
icon?: string;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Onramp supported configuration (currencies, gateways, payment methods)
|
|
511
|
+
*/
|
|
512
|
+
interface OnrampSupported {
|
|
513
|
+
/** Available gateways */
|
|
514
|
+
gateways: Gateway[];
|
|
515
|
+
/** Supported fiat currencies */
|
|
516
|
+
fiats: SupportedFiat[];
|
|
517
|
+
/** Supported crypto currencies */
|
|
518
|
+
cryptos: SupportedCrypto[];
|
|
519
|
+
/** Available payment methods */
|
|
520
|
+
paymentMethods: SupportedPaymentMethod[];
|
|
521
|
+
/** Default gateway ID for this project (e.g., 'banxa') */
|
|
522
|
+
defaultGateway?: string | null;
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Quote fee breakdown
|
|
526
|
+
*/
|
|
527
|
+
interface QuoteFees {
|
|
528
|
+
/** Processing fee in fiat */
|
|
529
|
+
processingFee: string;
|
|
530
|
+
/** Network/gas fee in fiat */
|
|
531
|
+
networkFee: string;
|
|
532
|
+
/** Total fees in fiat */
|
|
533
|
+
totalFee: string;
|
|
534
|
+
/** Fee as percentage (e.g., '2.5') */
|
|
535
|
+
feePercentage: string;
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Quote from a single provider
|
|
539
|
+
*/
|
|
540
|
+
interface Quote {
|
|
541
|
+
/** Gateway ID */
|
|
542
|
+
gatewayId: string;
|
|
543
|
+
/** Gateway display name */
|
|
544
|
+
gatewayName: string;
|
|
545
|
+
/** Gateway logo URL */
|
|
546
|
+
gatewayLogo: string;
|
|
547
|
+
/** Whether this gateway can service this request */
|
|
548
|
+
available: boolean;
|
|
549
|
+
/** Reason if unavailable */
|
|
550
|
+
unavailableReason?: string;
|
|
551
|
+
/** Fiat amount */
|
|
552
|
+
fiatAmount: string;
|
|
553
|
+
/** Fiat currency code */
|
|
554
|
+
fiatCurrency: string;
|
|
555
|
+
/** Crypto amount to receive */
|
|
556
|
+
cryptoAmount: string;
|
|
557
|
+
/** Crypto currency code */
|
|
558
|
+
cryptoCurrency: string;
|
|
559
|
+
/** Network ID */
|
|
560
|
+
network: string;
|
|
561
|
+
/** Fee breakdown */
|
|
562
|
+
fees: QuoteFees;
|
|
563
|
+
/** Exchange rate (1 crypto = X fiat) */
|
|
564
|
+
exchangeRate: string;
|
|
565
|
+
/** Estimated processing time (e.g., '5-10 minutes') */
|
|
566
|
+
estimatedTime: string;
|
|
567
|
+
/** KYC requirements: none, light, or full */
|
|
568
|
+
kycRequired: 'none' | 'light' | 'full';
|
|
569
|
+
/** Quote expiry timestamp (ms) */
|
|
570
|
+
expiresAt: number;
|
|
571
|
+
/** Ranking position (1 = best) */
|
|
572
|
+
rank?: number;
|
|
573
|
+
/** Is this the best rate? */
|
|
574
|
+
isBestRate?: boolean;
|
|
575
|
+
/** Is this the recommended (default) gateway? */
|
|
576
|
+
isRecommended?: boolean;
|
|
577
|
+
/** Routing score (0-100) */
|
|
578
|
+
score?: number;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Gateway that couldn't provide a quote
|
|
582
|
+
*/
|
|
583
|
+
interface UnavailableGateway {
|
|
584
|
+
/** Gateway ID */
|
|
585
|
+
gatewayId: string;
|
|
586
|
+
/** Gateway name */
|
|
587
|
+
gatewayName: string;
|
|
588
|
+
/** Reason why unavailable */
|
|
589
|
+
reason: string;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Quotes response from all gateways
|
|
593
|
+
*/
|
|
594
|
+
interface QuotesResponse {
|
|
595
|
+
/** All available quotes, ranked by crypto amount */
|
|
596
|
+
quotes: Quote[];
|
|
597
|
+
/** Best rate quote */
|
|
598
|
+
bestQuote: Quote | null;
|
|
599
|
+
/** Fastest processing quote */
|
|
600
|
+
fastestQuote: Quote | null;
|
|
601
|
+
/** Lowest fees quote */
|
|
602
|
+
cheapestFees: Quote | null;
|
|
603
|
+
/** Gateways that couldn't quote */
|
|
604
|
+
unavailableGateways: UnavailableGateway[];
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Parameters for getting quotes
|
|
608
|
+
*/
|
|
609
|
+
interface GetQuotesParams {
|
|
610
|
+
/** Fiat currency code (e.g., 'USD') */
|
|
611
|
+
fiatCurrency: string;
|
|
612
|
+
/** Fiat amount (required for buy, optional for sell) */
|
|
613
|
+
fiatAmount?: string;
|
|
614
|
+
/** Crypto amount (required for sell, optional for buy) */
|
|
615
|
+
cryptoAmount?: string;
|
|
616
|
+
/** Crypto currency code (e.g., 'ETH') */
|
|
617
|
+
cryptoCurrency: string;
|
|
618
|
+
/** Network ID (e.g., 'ethereum') */
|
|
619
|
+
network: string;
|
|
620
|
+
/** Order type: buy (fiat→crypto) or sell (crypto→fiat) */
|
|
621
|
+
orderType?: FlowType;
|
|
622
|
+
/** Payment method ID (optional) */
|
|
623
|
+
paymentMethodId?: string;
|
|
624
|
+
/** Country code (optional, for region-specific pricing) */
|
|
625
|
+
country?: string;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Routing factor with weight
|
|
629
|
+
*/
|
|
630
|
+
interface RoutingFactor {
|
|
631
|
+
/** Factor name */
|
|
632
|
+
factor: string;
|
|
633
|
+
/** Weight (0-1) */
|
|
634
|
+
weight: number;
|
|
635
|
+
/** Human-readable description */
|
|
636
|
+
description: string;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Checkout configuration
|
|
640
|
+
*/
|
|
641
|
+
interface Checkout {
|
|
642
|
+
/** Checkout method */
|
|
643
|
+
method: 'iframe' | 'redirect' | 'widget';
|
|
644
|
+
/** Checkout URL */
|
|
645
|
+
url: string;
|
|
646
|
+
/** URL expiry timestamp (ms) */
|
|
647
|
+
expiresAt?: number;
|
|
648
|
+
/** Allowed iframe features */
|
|
649
|
+
allowedFeatures?: string[];
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Created checkout intent
|
|
653
|
+
*/
|
|
654
|
+
interface CheckoutIntent {
|
|
655
|
+
/** Internal order ID */
|
|
656
|
+
orderId: string;
|
|
657
|
+
/** Gateway ID */
|
|
658
|
+
gateway: string;
|
|
659
|
+
/** Order status */
|
|
660
|
+
status: string;
|
|
661
|
+
/** Checkout configuration */
|
|
662
|
+
checkout: Checkout;
|
|
663
|
+
/** Gateway-specific widget config */
|
|
664
|
+
widgetConfig?: Record<string, unknown>;
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Parameters for creating a checkout intent
|
|
668
|
+
*/
|
|
669
|
+
interface CreateCheckoutIntentParams {
|
|
670
|
+
/** Gateway ID to use */
|
|
671
|
+
gateway: string;
|
|
672
|
+
/** External customer ID (optional — backend will auto-create guest if omitted) */
|
|
673
|
+
customerId?: string;
|
|
674
|
+
/** Fiat currency code */
|
|
675
|
+
fiatCurrency: string;
|
|
676
|
+
/** Fiat amount (required for buy, optional for sell) */
|
|
677
|
+
fiatAmount?: string;
|
|
678
|
+
/** Crypto amount (required for sell, optional for buy) */
|
|
679
|
+
cryptoAmount?: string;
|
|
680
|
+
/** Crypto currency code */
|
|
681
|
+
cryptoCurrency: string;
|
|
682
|
+
/** Network ID */
|
|
683
|
+
network: string;
|
|
684
|
+
/** Destination wallet address (required for buy, optional for sell) */
|
|
685
|
+
walletAddress?: string;
|
|
686
|
+
/** Order type: buy (fiat→crypto) or sell (crypto→fiat) */
|
|
687
|
+
orderType?: FlowType;
|
|
688
|
+
/** Payment method ID */
|
|
689
|
+
paymentMethodId?: string;
|
|
690
|
+
/** Customer email */
|
|
691
|
+
email?: string;
|
|
692
|
+
/** Redirect URL after completion */
|
|
693
|
+
redirectUrl?: string;
|
|
694
|
+
/** Custom metadata */
|
|
695
|
+
metadata?: Record<string, string>;
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Normalized transaction status
|
|
699
|
+
*/
|
|
700
|
+
type TransactionStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled' | 'expired' | 'refunded';
|
|
701
|
+
/**
|
|
702
|
+
* Transaction status details
|
|
703
|
+
*/
|
|
704
|
+
interface Transaction {
|
|
705
|
+
/** Internal order ID */
|
|
706
|
+
orderId: string;
|
|
707
|
+
/** Gateway ID */
|
|
708
|
+
gateway: string;
|
|
709
|
+
/** Normalized status */
|
|
710
|
+
status: TransactionStatus;
|
|
711
|
+
/** Gateway's original status */
|
|
712
|
+
gatewayStatus: string;
|
|
713
|
+
/** Fiat amount */
|
|
714
|
+
fiatAmount: string;
|
|
715
|
+
/** Fiat currency */
|
|
716
|
+
fiatCurrency: string;
|
|
717
|
+
/** Crypto amount (if available) */
|
|
718
|
+
cryptoAmount?: string;
|
|
719
|
+
/** Crypto currency */
|
|
720
|
+
cryptoCurrency: string;
|
|
721
|
+
/** Network */
|
|
722
|
+
network: string;
|
|
723
|
+
/** Wallet address */
|
|
724
|
+
walletAddress: string;
|
|
725
|
+
/** Transaction hash (if available) */
|
|
726
|
+
transactionHash?: string;
|
|
727
|
+
/** Creation timestamp */
|
|
728
|
+
createdAt: string;
|
|
729
|
+
/** Completion timestamp (if completed) */
|
|
730
|
+
completedAt?: string;
|
|
731
|
+
}
|
|
419
732
|
|
|
420
733
|
/**
|
|
421
734
|
* SDK Validation Utilities
|
|
@@ -467,6 +780,15 @@ declare function validateRedirectUrl(url: string): ValidationResult;
|
|
|
467
780
|
* @param chainType - Chain type from API (evm, solana, bitcoin, tezos, other)
|
|
468
781
|
*/
|
|
469
782
|
declare function validateWalletAddress(address: string, chainType?: ChainType): ValidationResult;
|
|
783
|
+
/**
|
|
784
|
+
* Validate fiat amount against min/max limits
|
|
785
|
+
*
|
|
786
|
+
* @param amount - The fiat amount as a string
|
|
787
|
+
* @param minAmount - Minimum allowed amount
|
|
788
|
+
* @param maxAmount - Maximum allowed amount
|
|
789
|
+
* @param currency - Optional currency code to include in error messages
|
|
790
|
+
*/
|
|
791
|
+
declare function validateAmount(amount: string, minAmount: number, maxAmount: number, currency?: string): ValidationResult;
|
|
470
792
|
/**
|
|
471
793
|
* Validate message origin against expected widget URL
|
|
472
794
|
*
|
|
@@ -617,216 +939,82 @@ declare class RampApi {
|
|
|
617
939
|
private getPublicCurrencies;
|
|
618
940
|
/**
|
|
619
941
|
* Validate a wallet address
|
|
620
|
-
*
|
|
621
|
-
* @param params - Address validation parameters
|
|
622
|
-
* @returns Validation result with details
|
|
623
|
-
*
|
|
624
|
-
* @example
|
|
625
|
-
* ```typescript
|
|
626
|
-
* // Validate EVM address
|
|
627
|
-
* const result = await api.validateAddress({
|
|
628
|
-
* address: '0x742d35Cc6634C0532925a3b844Bc9e7595f1bD21',
|
|
629
|
-
* network: 'ethereum',
|
|
630
|
-
* });
|
|
631
|
-
*
|
|
632
|
-
* if (result.isValid) {
|
|
633
|
-
* console.log('Normalized address:', result.normalizedAddress);
|
|
634
|
-
* }
|
|
635
|
-
*
|
|
636
|
-
* // Auto-detect chain type
|
|
637
|
-
* const autoResult = await api.validateAddress({
|
|
638
|
-
* address: 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq',
|
|
639
|
-
* });
|
|
640
|
-
* console.log('Chain type:', autoResult.chainType); // 'bitcoin'
|
|
641
|
-
* ```
|
|
642
942
|
*/
|
|
643
943
|
validateAddress(params: ValidateAddressParams): Promise<AddressValidationResult>;
|
|
644
944
|
/**
|
|
645
945
|
* Validate multiple wallet addresses in batch
|
|
646
|
-
*
|
|
647
|
-
* @param addresses - Array of address validation parameters (max 20)
|
|
648
|
-
* @returns Batch validation results
|
|
649
|
-
*
|
|
650
|
-
* @example
|
|
651
|
-
* ```typescript
|
|
652
|
-
* const results = await api.validateAddressBatch([
|
|
653
|
-
* { address: '0x742d35Cc6634C0532925a3b844Bc9e7595f1bD21', network: 'ethereum' },
|
|
654
|
-
* { address: 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq', chainType: 'bitcoin' },
|
|
655
|
-
* { address: 'tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb' },
|
|
656
|
-
* ]);
|
|
657
|
-
*
|
|
658
|
-
* console.log(`Valid: ${results.validCount}, Invalid: ${results.invalidCount}`);
|
|
659
|
-
* ```
|
|
660
946
|
*/
|
|
661
947
|
validateAddressBatch(addresses: ValidateAddressParams[]): Promise<AddressValidationBatchResult>;
|
|
662
948
|
/**
|
|
663
949
|
* Get list of supported networks for address validation
|
|
664
|
-
*
|
|
665
|
-
* @returns Supported networks with chain type information
|
|
666
|
-
*
|
|
667
|
-
* @example
|
|
668
|
-
* ```typescript
|
|
669
|
-
* const networks = await api.getSupportedNetworks();
|
|
670
|
-
*
|
|
671
|
-
* console.log('EVM networks:', networks.grouped.evm.map(n => n.name));
|
|
672
|
-
* console.log('Total networks:', networks.total);
|
|
673
|
-
* ```
|
|
674
950
|
*/
|
|
675
951
|
getSupportedNetworks(): Promise<SupportedNetworksResult>;
|
|
676
952
|
/**
|
|
677
953
|
* Create a session for secure widget initialization
|
|
678
|
-
*
|
|
679
|
-
* Sessions follow the Stripe security model:
|
|
680
|
-
* 1. Partner backend creates session with secret key (sk_)
|
|
681
|
-
* 2. Widget is initialized with sessionId + clientSecret
|
|
682
|
-
* 3. Public key alone cannot create customers, orders, or initiate KYC
|
|
683
|
-
*
|
|
684
|
-
* @param params - Session parameters
|
|
685
|
-
* @returns Session with client secret (only returned once!)
|
|
686
|
-
*
|
|
687
|
-
* @example
|
|
688
|
-
* ```typescript
|
|
689
|
-
* // On your backend (using secret key)
|
|
690
|
-
* const session = await api.createSession({
|
|
691
|
-
* externalCustomerId: 'user_123',
|
|
692
|
-
* sourceAmount: 100,
|
|
693
|
-
* sourceCurrency: 'USD',
|
|
694
|
-
* destinationCurrency: 'ETH',
|
|
695
|
-
* network: 'ethereum',
|
|
696
|
-
* redirectUrl: 'https://yourapp.com/success',
|
|
697
|
-
* });
|
|
698
|
-
*
|
|
699
|
-
* // Return sessionId and clientSecret to frontend
|
|
700
|
-
* return { sessionId: session.sessionId, clientSecret: session.clientSecret };
|
|
701
|
-
*
|
|
702
|
-
* // On your frontend (using public key)
|
|
703
|
-
* const widget = new RampWidget({
|
|
704
|
-
* apiKey: 'pk_xxx',
|
|
705
|
-
* projectId: 'proj_xxx',
|
|
706
|
-
* sessionId: session.sessionId,
|
|
707
|
-
* clientSecret: session.clientSecret,
|
|
708
|
-
* });
|
|
709
|
-
* ```
|
|
710
954
|
*/
|
|
711
955
|
createSession(params: CreateSessionParams): Promise<SessionWithSecret>;
|
|
712
956
|
/**
|
|
713
957
|
* Get session by ID
|
|
714
|
-
*
|
|
715
|
-
* @param sessionId - Session ID (sess_xxx)
|
|
716
|
-
* @returns Session data
|
|
717
|
-
*
|
|
718
|
-
* @example
|
|
719
|
-
* ```typescript
|
|
720
|
-
* const session = await api.getSession('sess_abc123');
|
|
721
|
-
* console.log('Status:', session.status);
|
|
722
|
-
* ```
|
|
723
958
|
*/
|
|
724
959
|
getSession(sessionId: string): Promise<Session>;
|
|
725
960
|
/**
|
|
726
961
|
* Cancel a session
|
|
727
|
-
*
|
|
728
|
-
* Can only cancel sessions in 'pending' or 'confirmed' status.
|
|
729
|
-
* Requires secret key (sk_).
|
|
730
|
-
*
|
|
731
|
-
* @param sessionId - Session ID to cancel
|
|
732
|
-
* @returns Updated session data
|
|
733
|
-
*
|
|
734
|
-
* @example
|
|
735
|
-
* ```typescript
|
|
736
|
-
* const session = await api.cancelSession('sess_abc123');
|
|
737
|
-
* console.log('Status:', session.status); // 'cancelled'
|
|
738
|
-
* ```
|
|
739
962
|
*/
|
|
740
963
|
cancelSession(sessionId: string): Promise<Session>;
|
|
964
|
+
/**
|
|
965
|
+
* Get supported configuration
|
|
966
|
+
* Returns available gateways, currencies, and payment methods
|
|
967
|
+
*/
|
|
968
|
+
getSupported(orderType?: 'buy' | 'sell'): Promise<OnrampSupported>;
|
|
969
|
+
/**
|
|
970
|
+
* Get quotes from all gateways
|
|
971
|
+
*/
|
|
972
|
+
getQuotes(params: GetQuotesParams): Promise<QuotesResponse>;
|
|
973
|
+
/**
|
|
974
|
+
* Create a checkout intent with a specific gateway
|
|
975
|
+
*/
|
|
976
|
+
createCheckoutIntent(params: CreateCheckoutIntentParams): Promise<CheckoutIntent>;
|
|
977
|
+
/**
|
|
978
|
+
* Get transaction status
|
|
979
|
+
*/
|
|
980
|
+
getTransaction(transactionId: string): Promise<Transaction>;
|
|
741
981
|
}
|
|
742
982
|
/**
|
|
743
983
|
* Standalone function to get conversion rate
|
|
744
|
-
* Convenience wrapper for one-off rate checks
|
|
745
|
-
*
|
|
746
|
-
* @example
|
|
747
|
-
* ```typescript
|
|
748
|
-
* import { getRate } from '@nowramp/sdk';
|
|
749
|
-
*
|
|
750
|
-
* const rate = await getRate(
|
|
751
|
-
* { apiKey: 'ramp_pk_xxx', projectId: 'proj_xxx' },
|
|
752
|
-
* { from: 'USD', to: 'ETH', amount: 100 }
|
|
753
|
-
* );
|
|
754
|
-
* ```
|
|
755
984
|
*/
|
|
756
985
|
declare function getRate(config: RampApiConfig, params: GetRateParams): Promise<RateResult>;
|
|
757
986
|
/**
|
|
758
987
|
* Standalone function to get available currencies
|
|
759
|
-
* Convenience wrapper for one-off currency fetching
|
|
760
|
-
*
|
|
761
|
-
* @example
|
|
762
|
-
* ```typescript
|
|
763
|
-
* import { getCurrencies } from '@nowramp/sdk';
|
|
764
|
-
*
|
|
765
|
-
* const currencies = await getCurrencies({
|
|
766
|
-
* apiKey: 'ramp_pk_xxx',
|
|
767
|
-
* projectId: 'proj_xxx'
|
|
768
|
-
* });
|
|
769
|
-
* ```
|
|
770
988
|
*/
|
|
771
989
|
declare function getCurrencies(config: RampApiConfig): Promise<AvailableCurrencies>;
|
|
772
990
|
/**
|
|
773
991
|
* Standalone function to validate a wallet address
|
|
774
|
-
* Convenience wrapper for one-off address validation
|
|
775
|
-
*
|
|
776
|
-
* Note: This is a public endpoint that doesn't require authentication
|
|
777
|
-
*
|
|
778
|
-
* @example
|
|
779
|
-
* ```typescript
|
|
780
|
-
* import { validateAddress } from '@nowramp/sdk';
|
|
781
|
-
*
|
|
782
|
-
* const result = await validateAddress(
|
|
783
|
-
* { apiUrl: 'https://api.nowramp.com' },
|
|
784
|
-
* { address: '0x742d35Cc6634C0532925a3b844Bc9e7595f1bD21', network: 'ethereum' }
|
|
785
|
-
* );
|
|
786
|
-
*
|
|
787
|
-
* if (result.isValid) {
|
|
788
|
-
* console.log('Address is valid!', result.normalizedAddress);
|
|
789
|
-
* }
|
|
790
|
-
* ```
|
|
791
992
|
*/
|
|
792
993
|
declare function validateAddress(config: Pick<RampApiConfig, 'apiUrl'>, params: ValidateAddressParams): Promise<AddressValidationResult>;
|
|
793
994
|
/**
|
|
794
995
|
* Standalone function to validate multiple wallet addresses
|
|
795
|
-
* Convenience wrapper for one-off batch validation
|
|
796
|
-
*
|
|
797
|
-
* Note: This is a public endpoint that doesn't require authentication
|
|
798
|
-
*
|
|
799
|
-
* @example
|
|
800
|
-
* ```typescript
|
|
801
|
-
* import { validateAddressBatch } from '@nowramp/sdk';
|
|
802
|
-
*
|
|
803
|
-
* const results = await validateAddressBatch(
|
|
804
|
-
* { apiUrl: 'https://api.nowramp.com' },
|
|
805
|
-
* [
|
|
806
|
-
* { address: '0x742d35Cc6634C0532925a3b844Bc9e7595f1bD21', network: 'ethereum' },
|
|
807
|
-
* { address: 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq', chainType: 'bitcoin' },
|
|
808
|
-
* ]
|
|
809
|
-
* );
|
|
810
|
-
*
|
|
811
|
-
* console.log(`Valid: ${results.validCount}, Invalid: ${results.invalidCount}`);
|
|
812
|
-
* ```
|
|
813
996
|
*/
|
|
814
997
|
declare function validateAddressBatch(config: Pick<RampApiConfig, 'apiUrl'>, addresses: ValidateAddressParams[]): Promise<AddressValidationBatchResult>;
|
|
815
998
|
/**
|
|
816
999
|
* Standalone function to get supported networks for validation
|
|
817
|
-
* Convenience wrapper for one-off network listing
|
|
818
|
-
*
|
|
819
|
-
* Note: This is a public endpoint that doesn't require authentication
|
|
820
|
-
*
|
|
821
|
-
* @example
|
|
822
|
-
* ```typescript
|
|
823
|
-
* import { getSupportedNetworks } from '@nowramp/sdk';
|
|
824
|
-
*
|
|
825
|
-
* const networks = await getSupportedNetworks({ apiUrl: 'https://api.nowramp.com' });
|
|
826
|
-
* console.log('EVM networks:', networks.grouped.evm.map(n => n.name));
|
|
827
|
-
* ```
|
|
828
1000
|
*/
|
|
829
1001
|
declare function getSupportedNetworks(config: Pick<RampApiConfig, 'apiUrl'>): Promise<SupportedNetworksResult>;
|
|
1002
|
+
/**
|
|
1003
|
+
* Standalone function to get supported configuration
|
|
1004
|
+
*/
|
|
1005
|
+
declare function getSupported(config: Pick<RampApiConfig, 'apiUrl' | 'projectId'>, orderType?: 'buy' | 'sell'): Promise<OnrampSupported>;
|
|
1006
|
+
/**
|
|
1007
|
+
* Standalone function to get quotes from all gateways
|
|
1008
|
+
*/
|
|
1009
|
+
declare function getQuotes(config: Pick<RampApiConfig, 'apiUrl' | 'projectId'>, params: GetQuotesParams): Promise<QuotesResponse>;
|
|
1010
|
+
/**
|
|
1011
|
+
* Standalone function to create a checkout intent
|
|
1012
|
+
*/
|
|
1013
|
+
declare function createCheckoutIntent(config: Pick<RampApiConfig, 'apiUrl' | 'projectId'>, params: CreateCheckoutIntentParams): Promise<CheckoutIntent>;
|
|
1014
|
+
/**
|
|
1015
|
+
* Standalone function to get transaction status
|
|
1016
|
+
*/
|
|
1017
|
+
declare function getTransaction(config: Pick<RampApiConfig, 'apiUrl'>, transactionId: string): Promise<Transaction>;
|
|
830
1018
|
|
|
831
1019
|
/**
|
|
832
1020
|
* NowRamp Widget SDK
|
|
@@ -853,5 +1041,5 @@ declare function getSupportedNetworks(config: Pick<RampApiConfig, 'apiUrl'>): Pr
|
|
|
853
1041
|
*/
|
|
854
1042
|
declare const VERSION: string;
|
|
855
1043
|
|
|
856
|
-
export { ADDRESS_PATTERNS, ALLOWED_PROTOCOLS, API_KEY_PREFIXES, DEV_ALLOWED_HOSTNAMES, RampApi, RampWidget, VERSION, RampWidget as default, getCurrencies, getRate, getSupportedNetworks, validateAddress, validateAddressBatch, validateApiKey, validateMessageOrigin, validateRedirectUrl, validateWalletAddress };
|
|
857
|
-
export type { AddressValidationBatchResult, AddressValidationResult, AvailableCurrencies, ChainType, CreateSessionParams, CryptoCurrency, ErrorData, FiatCurrency, FlowType, GetRateParams, Locale, OrderData, QuoteData, RampApiConfig, RampWidgetConfig, RateResult, Session, SessionStatus, SessionType, SessionWithSecret, SupportedNetwork, SupportedNetworksResult, Theme, ValidateAddressParams, ValidationChainType, ValidationDetails, ValidationResult, WidgetEventType, WidgetMessage };
|
|
1044
|
+
export { ADDRESS_PATTERNS, ALLOWED_PROTOCOLS, API_KEY_PREFIXES, DEV_ALLOWED_HOSTNAMES, RampApi, RampWidget, VERSION, createCheckoutIntent, RampWidget as default, getCurrencies, getQuotes, getRate, getSupported, getSupportedNetworks, getTransaction, validateAddress, validateAddressBatch, validateAmount, validateApiKey, validateMessageOrigin, validateRedirectUrl, validateWalletAddress };
|
|
1045
|
+
export type { AddressValidationBatchResult, AddressValidationResult, AvailableCurrencies, ChainType, Checkout, CheckoutIntent, CreateCheckoutIntentParams, CreateSessionParams, CryptoCurrency, ErrorData, FiatCurrency, FieldLockConfig, FieldLocksConfig, FlowType, Gateway, GatewayFeatures, GetQuotesParams, GetRateParams, Locale, OnrampSupported, OrderData, Quote, QuoteData, QuoteFees, QuotesResponse, RampApiConfig, RampWidgetConfig, RateResult, RoutingFactor, Session, SessionStatus, SessionType, SessionWithSecret, SupportedCrypto, SupportedFiat, SupportedNetwork, SupportedNetworkInfo, SupportedNetworksResult, SupportedPaymentMethod, Theme, Transaction, TransactionStatus, UnavailableGateway, ValidateAddressParams, ValidationChainType, ValidationDetails, ValidationResult, WidgetEventType, WidgetMessage };
|
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})$/,description:"Bitcoin address must be a valid legacy, SegWit, or native SegWit format"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},other:{pattern:/^.{10,100}$/,description:"Address format varies by network (10-100 characters)"}},t=["https:"],r=["localhost","127.0.0.1"],s={public:"pk_",secret:"sk_"};function i(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 o(t,r){if(!t)return{valid:!0};const s=t.trim();if(r){const t=r.toLowerCase(),i=e[t];if(i){const{pattern:e,description:t}=i;return e.test(s)?{valid:!0}:{valid:!1,error:t}}return s.length>=10&&s.length<=100?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=100?{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=i(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=o(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 function l(e,t){return new d(e).getRate(t)}async function h(e){return new d(e).getCurrencies()}async function u(e,t){return new d({apiKey:"",projectId:"",...e}).validateAddress(t)}async function p(e,t){return new d({apiKey:"",projectId:"",...e}).validateAddressBatch(t)}async function m(e){return new d({apiKey:"",projectId:"",...e}).getSupportedNetworks()}const f="0.1.13";export{e as ADDRESS_PATTERNS,t as ALLOWED_PROTOCOLS,s as API_KEY_PREFIXES,r as DEV_ALLOWED_HOSTNAMES,d as RampApi,c as RampWidget,f as VERSION,c as default,h as getCurrencies,l as getRate,m as getSupportedNetworks,u as validateAddress,p as validateAddressBatch,i as validateApiKey,a as validateMessageOrigin,n as validateRedirectUrl,o 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})$/,description:"Bitcoin address must be a valid legacy, SegWit, or native SegWit format"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},other:{pattern:/^.{10,100}$/,description:"Address format varies by network (10-100 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<=100?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=100?{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 l{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=new URLSearchParams({projectId:this.config.projectId});e&&t.set("orderType",e);const r=await fetch(`${this.baseUrl}/public/v1/onramp/supported?${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 supported config: ${t}`)}const s=await r.json();return s.data?.attributes||s.data||s}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 u(e,t){return new l(e).getRate(t)}async function h(e){return new l(e).getCurrencies()}async function p(e,t){return new l({apiKey:"",projectId:"",...e}).validateAddress(t)}async function m(e,t){return new l({apiKey:"",projectId:"",...e}).validateAddressBatch(t)}async function f(e){return new l({apiKey:"",projectId:"",...e}).getSupportedNetworks()}async function g(e,t){return new l({apiKey:"",...e}).getSupported(t)}async function w(e,t){return new l({apiKey:"",...e}).getQuotes(t)}async function y(e,t){return new l({apiKey:"",...e}).createCheckoutIntent(t)}async function b(e,t){return new l({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,l as RampApi,d as RampWidget,A as VERSION,y as createCheckoutIntent,d as default,h as getCurrencies,w as getQuotes,u 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})$/,description:"Bitcoin address must be a valid legacy, SegWit, or native SegWit format"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},other:{pattern:/^.{10,100}$/,description:"Address format varies by network (10-100 characters)"}},r=["https:"],s=["localhost","127.0.0.1"],i={public:"pk_",secret:"sk_"};function n(e){return e?e.includes(i.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(i.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 o(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(),i=t[e];if(i){const{pattern:e,description:t}=i;return e.test(s)?{valid:!0}:{valid:!1,error:t}}return s.length>=10&&s.length<=100?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=100?{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=o(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 l{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}}}e.ADDRESS_PATTERNS=t,e.ALLOWED_PROTOCOLS=r,e.API_KEY_PREFIXES=i,e.DEV_ALLOWED_HOSTNAMES=s,e.RampApi=l,e.RampWidget=d,e.VERSION="0.1.13",e.default=d,e.getCurrencies=async function(e){return new l(e).getCurrencies()},e.getRate=async function(e,t){return new l(e).getRate(t)},e.getSupportedNetworks=async function(e){return new l({apiKey:"",projectId:"",...e}).getSupportedNetworks()},e.validateAddress=async function(e,t){return new l({apiKey:"",projectId:"",...e}).validateAddress(t)},e.validateAddressBatch=async function(e,t){return new l({apiKey:"",projectId:"",...e}).validateAddressBatch(t)},e.validateApiKey=n,e.validateMessageOrigin=c,e.validateRedirectUrl=o,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})$/,description:"Bitcoin address must be a valid legacy, SegWit, or native SegWit format"},tezos:{pattern:/^(tz[123]|KT1)[a-zA-Z0-9]{33}$/,description:"Tezos address must start with tz1/tz2/tz3 (implicit) or KT1 (contract)"},other:{pattern:/^.{10,100}$/,description:"Address format varies by network (10-100 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<=100?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return s.length>=10&&s.length<=100?{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 l{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=new URLSearchParams({projectId:this.config.projectId});e&&t.set("orderType",e);const r=await fetch(`${this.baseUrl}/public/v1/onramp/supported?${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 supported config: ${t}`)}const s=await r.json();return s.data?.attributes||s.data||s}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=l,e.RampWidget=d,e.VERSION="0.1.13",e.createCheckoutIntent=async function(e,t){return new l({apiKey:"",...e}).createCheckoutIntent(t)},e.default=d,e.getCurrencies=async function(e){return new l(e).getCurrencies()},e.getQuotes=async function(e,t){return new l({apiKey:"",...e}).getQuotes(t)},e.getRate=async function(e,t){return new l(e).getRate(t)},e.getSupported=async function(e,t){return new l({apiKey:"",...e}).getSupported(t)},e.getSupportedNetworks=async function(e){return new l({apiKey:"",projectId:"",...e}).getSupportedNetworks()},e.getTransaction=async function(e,t){return new l({apiKey:"",projectId:"",...e}).getTransaction(t)},e.validateAddress=async function(e,t){return new l({apiKey:"",projectId:"",...e}).validateAddress(t)},e.validateAddressBatch=async function(e,t){return new l({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})});
|