@nowramp/sdk 0.1.16 → 0.1.17

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 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 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 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=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.provider&&e.set("provider",this.config.provider),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",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals");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=document.createElement("div");e.style.cssText="\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: white;\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n ",this.iframe&&e.appendChild(this.iframe),this.modalContainer.appendChild(e),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 c{constructor(e){this.config=e,this.baseUrl=e.apiUrl||"https://api.nowramp.com"}async getRate(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 getCurrencies(){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 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){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){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,orderId:s.orderId,expiresAt:s.expiresAt,confirmedAt:s.confirmedAt,completedAt:s.completedAt,createdAt:s.createdAt}}async cancelSession(e){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=c,exports.RampWidget=d,exports.VERSION="0.1.13",exports.default=d,exports.getCurrencies=async function(e){return new c(e).getCurrencies()},exports.getRate=async function(e,t){return new c(e).getRate(t)},exports.getSupportedNetworks=async function(e){return new c({apiKey:"",projectId:"",...e}).getSupportedNetworks()},exports.validateAddress=async function(e,t){return new c({apiKey:"",projectId:"",...e}).validateAddress(t)},exports.validateAddressBatch=async function(e,t){return new c({apiKey:"",projectId:"",...e}).validateAddressBatch(t)},exports.validateApiKey=i,exports.validateMessageOrigin=a,exports.validateRedirectUrl=n,exports.validateWalletAddress=o;
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 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.provider&&e.set("provider",this.config.provider),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",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals");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=document.createElement("div");e.style.cssText="\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: white;\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n ",this.iframe&&e.appendChild(this.iframe),this.modalContainer.appendChild(e),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,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=n,exports.validateWalletAddress=o;
package/dist/index.d.ts CHANGED
@@ -149,12 +149,30 @@ interface RateResult {
149
149
  }
150
150
  /**
151
151
  * Configuration for standalone API calls (not widget)
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * // Authenticated usage (full access)
156
+ * const api = new RampApi({ apiKey: 'pk_xxx', projectId: 'proj_xxx' });
157
+ *
158
+ * // Public usage (rate limited, no auth required)
159
+ * const publicApi = new RampApi({ projectId: 'proj_xxx' });
160
+ * const rate = await publicApi.getRate({ from: 'USD', to: 'ETH', amount: 100 });
161
+ * ```
152
162
  */
153
163
  interface RampApiConfig {
154
- /** Partner API key (required) */
155
- apiKey: string;
156
- /** Project ID (required) */
157
- projectId: string;
164
+ /**
165
+ * Partner API key (optional)
166
+ * - If provided: uses authenticated endpoints with higher rate limits
167
+ * - If omitted: uses public endpoints with stricter rate limits
168
+ */
169
+ apiKey?: string;
170
+ /**
171
+ * Project ID
172
+ * - Required for getCurrencies() when using public endpoints
173
+ * - Optional for getRate() when using public endpoints
174
+ */
175
+ projectId?: string;
158
176
  /** API base URL (optional, defaults to https://api.nowramp.com) */
159
177
  apiUrl?: string;
160
178
  }
@@ -534,6 +552,10 @@ declare class RampApi {
534
552
  /**
535
553
  * Get conversion rate from configured payment provider
536
554
  *
555
+ * Auto-detects authentication:
556
+ * - If API key provided: uses authenticated /v1/rates/convert endpoint
557
+ * - If no API key: uses public /public/wert/convert endpoint (rate limited)
558
+ *
537
559
  * @param params - Rate request parameters
538
560
  * @returns Conversion rate with fee breakdown
539
561
  *
@@ -554,13 +576,26 @@ declare class RampApi {
554
576
  * amount: 0.1,
555
577
  * flowType: 'sell',
556
578
  * });
579
+ *
580
+ * // Public usage (no API key) - uses rate-limited public endpoint
581
+ * const publicApi = new RampApi({ projectId: 'proj_xxx' });
582
+ * const rate = await publicApi.getRate({ from: 'USD', to: 'ETH', amount: 100 });
557
583
  * ```
558
584
  */
559
585
  getRate(params: GetRateParams): Promise<RateResult>;
586
+ /**
587
+ * Internal: Get rate from public endpoint (no auth required)
588
+ * Rate limited to 60 requests/minute per IP
589
+ */
590
+ private getPublicRate;
560
591
  /**
561
592
  * Get available currencies from configured payment provider
562
593
  * Returns fiat and crypto currencies filtered by project settings
563
594
  *
595
+ * Auto-detects authentication:
596
+ * - If API key provided: uses authenticated /v1/rates/currencies endpoint
597
+ * - If no API key: uses public /public/projects/:projectId/currencies endpoint (rate limited)
598
+ *
564
599
  * @returns Available fiat and crypto currencies
565
600
  *
566
601
  * @example
@@ -569,9 +604,19 @@ declare class RampApi {
569
604
  *
570
605
  * console.log('Available fiat:', currencies.fiat.map(f => f.code));
571
606
  * console.log('Available crypto:', currencies.crypto.map(c => c.symbol));
607
+ *
608
+ * // Public usage (no API key) - requires projectId
609
+ * const publicApi = new RampApi({ projectId: 'proj_xxx' });
610
+ * const currencies = await publicApi.getCurrencies();
572
611
  * ```
573
612
  */
574
613
  getCurrencies(): Promise<AvailableCurrencies>;
614
+ /**
615
+ * Internal: Get currencies from public endpoint (no auth required)
616
+ * Rate limited to 30 requests/minute per IP
617
+ * Requires projectId to be set in config
618
+ */
619
+ private getPublicCurrencies;
575
620
  /**
576
621
  * Validate a wallet address
577
622
  *
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:"],s=["localhost","127.0.0.1"],r={public:"pk_",secret:"sk_"};function i(e){return e?e.includes(r.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(r.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 r=new URL(e);return t.includes(r.protocol)||"http:"===r.protocol&&s.includes(r.hostname)?{valid:!0}:{valid:!1,error:`redirectUrl must use HTTPS (got ${r.protocol})`}}catch{return{valid:!1,error:"redirectUrl is not a valid URL"}}}function o(t,s){if(!t)return{valid:!0};const r=t.trim();if(s){const t=s.toLowerCase(),i=e[t];if(i){const{pattern:e,description:t}=i;return e.test(r)?{valid:!0}:{valid:!1,error:t}}return r.length>=10&&r.length<=100?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return r.length>=10&&r.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 s=new URL(e);return"localhost"===s.hostname||"127.0.0.1"===s.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=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.provider&&e.set("provider",this.config.provider),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",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals");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=document.createElement("div");e.style.cssText="\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: white;\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n ",this.iframe&&e.appendChild(this.iframe),this.modalContainer.appendChild(e),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 s=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},s)}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 c{constructor(e){this.config=e,this.baseUrl=e.apiUrl||"https://api.nowramp.com"}async getRate(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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${s}`)}const s=await t.json(),r=s.data?.attributes||s.data||s;return{rate:r.rate,sourceAmount:r.sourceAmount,sourceCurrency:r.sourceCurrency,destinationAmount:r.destinationAmount,destinationCurrency:r.destinationCurrency,fees:{processingFee:r.fees?.processingFee||0,processingFeePercent:r.fees?.processingFeePercent||0,networkFee:r.fees?.networkFee||0,totalFee:r.fees?.totalFee||0},provider:r.provider||"unknown",expiresAt:r.expiresAt}}async getCurrencies(){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(()=>({})),s=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${s}`)}const t=await e.json(),s=t.data?.attributes||t.data||t;return{fiat:s.fiat||[],crypto:s.crypto||[],provider:s.provider||"unknown",environment:s.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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate address: ${s}`)}const s=await t.json();return s.data?.attributes||s.data||s}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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate addresses: ${s}`)}const s=await t.json();return s.data?.attributes||s.data||s}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(()=>({})),s=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get supported networks: ${s}`)}const t=await e.json();return t.data?.attributes||t.data||t}async createSession(e){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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to create session: ${s}`)}const s=await t.json(),r=s.data?.attributes||s.data||s;return{sessionId:s.data?.id||r.sessionId,clientSecret:r.clientSecret,type:r.type||"onramp",status:r.status||"pending",customerId:r.customerId,externalCustomerId:r.externalCustomerId,sourceAmount:r.sourceAmount,sourceCurrency:r.sourceCurrency,destinationCurrency:r.destinationCurrency,destinationAddress:r.destinationAddress,network:r.network,redirectUrl:r.redirectUrl,metadata:r.metadata,expiresAt:r.expiresAt,createdAt:r.createdAt}}async getSession(e){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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get session: ${s}`)}const s=await t.json(),r=s.data?.attributes||s.data||s;return{sessionId:s.data?.id||r.sessionId,type:r.type||"onramp",status:r.status||"pending",customerId:r.customerId,externalCustomerId:r.externalCustomerId,sourceAmount:r.sourceAmount,sourceCurrency:r.sourceCurrency,destinationCurrency:r.destinationCurrency,destinationAddress:r.destinationAddress,network:r.network,redirectUrl:r.redirectUrl,metadata:r.metadata,orderId:r.orderId,expiresAt:r.expiresAt,confirmedAt:r.confirmedAt,completedAt:r.completedAt,createdAt:r.createdAt}}async cancelSession(e){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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to cancel session: ${s}`)}const s=await t.json(),r=s.data?.attributes||s.data||s;return{sessionId:s.data?.id||r.sessionId,type:r.type||"onramp",status:r.status||"cancelled",customerId:r.customerId,externalCustomerId:r.externalCustomerId,sourceAmount:r.sourceAmount,sourceCurrency:r.sourceCurrency,destinationCurrency:r.destinationCurrency,destinationAddress:r.destinationAddress,network:r.network,redirectUrl:r.redirectUrl,metadata:r.metadata,orderId:r.orderId,expiresAt:r.expiresAt,confirmedAt:r.confirmedAt,completedAt:r.completedAt,createdAt:r.createdAt}}}async function l(e,t){return new c(e).getRate(t)}async function h(e){return new c(e).getCurrencies()}async function u(e,t){return new c({apiKey:"",projectId:"",...e}).validateAddress(t)}async function p(e,t){return new c({apiKey:"",projectId:"",...e}).validateAddressBatch(t)}async function m(e){return new c({apiKey:"",projectId:"",...e}).getSupportedNetworks()}const g="0.1.13";export{e as ADDRESS_PATTERNS,t as ALLOWED_PROTOCOLS,r as API_KEY_PREFIXES,s as DEV_ALLOWED_HOSTNAMES,c as RampApi,d as RampWidget,g as VERSION,d 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 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.provider&&e.set("provider",this.config.provider),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",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals");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=document.createElement("div");e.style.cssText="\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: white;\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n ",this.iframe&&e.appendChild(this.iframe),this.modalContainer.appendChild(e),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,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};
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)"}},s=["https:"],r=["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 s.includes(t.protocol)||"http:"===t.protocol&&r.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,s){if(!e)return{valid:!0};const r=e.trim();if(s){const e=s.toLowerCase(),i=t[e];if(i){const{pattern:e,description:t}=i;return e.test(r)?{valid:!0}:{valid:!1,error:t}}return r.length>=10&&r.length<=100?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return r.length>=10&&r.length<=100?{valid:!0}:{valid:!1,error:"Address format not recognized"}}function d(e,t){if(!t)return!0;try{if(e===new URL(t).origin)return!0;const s=new URL(e);return"localhost"===s.hostname||"127.0.0.1"===s.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=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.provider&&e.set("provider",this.config.provider),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",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals");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=document.createElement("div");e.style.cssText="\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: white;\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n ",this.iframe&&e.appendChild(this.iframe),this.modalContainer.appendChild(e),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(!d(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 s=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},s)}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){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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${s}`)}const s=await t.json(),r=s.data?.attributes||s.data||s;return{rate:r.rate,sourceAmount:r.sourceAmount,sourceCurrency:r.sourceCurrency,destinationAmount:r.destinationAmount,destinationCurrency:r.destinationCurrency,fees:{processingFee:r.fees?.processingFee||0,processingFeePercent:r.fees?.processingFeePercent||0,networkFee:r.fees?.networkFee||0,totalFee:r.fees?.totalFee||0},provider:r.provider||"unknown",expiresAt:r.expiresAt}}async getCurrencies(){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(()=>({})),s=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${s}`)}const t=await e.json(),s=t.data?.attributes||t.data||t;return{fiat:s.fiat||[],crypto:s.crypto||[],provider:s.provider||"unknown",environment:s.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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate address: ${s}`)}const s=await t.json();return s.data?.attributes||s.data||s}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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate addresses: ${s}`)}const s=await t.json();return s.data?.attributes||s.data||s}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(()=>({})),s=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get supported networks: ${s}`)}const t=await e.json();return t.data?.attributes||t.data||t}async createSession(e){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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to create session: ${s}`)}const s=await t.json(),r=s.data?.attributes||s.data||s;return{sessionId:s.data?.id||r.sessionId,clientSecret:r.clientSecret,type:r.type||"onramp",status:r.status||"pending",customerId:r.customerId,externalCustomerId:r.externalCustomerId,sourceAmount:r.sourceAmount,sourceCurrency:r.sourceCurrency,destinationCurrency:r.destinationCurrency,destinationAddress:r.destinationAddress,network:r.network,redirectUrl:r.redirectUrl,metadata:r.metadata,expiresAt:r.expiresAt,createdAt:r.createdAt}}async getSession(e){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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get session: ${s}`)}const s=await t.json(),r=s.data?.attributes||s.data||s;return{sessionId:s.data?.id||r.sessionId,type:r.type||"onramp",status:r.status||"pending",customerId:r.customerId,externalCustomerId:r.externalCustomerId,sourceAmount:r.sourceAmount,sourceCurrency:r.sourceCurrency,destinationCurrency:r.destinationCurrency,destinationAddress:r.destinationAddress,network:r.network,redirectUrl:r.redirectUrl,metadata:r.metadata,orderId:r.orderId,expiresAt:r.expiresAt,confirmedAt:r.confirmedAt,completedAt:r.completedAt,createdAt:r.createdAt}}async cancelSession(e){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(()=>({})),s=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to cancel session: ${s}`)}const s=await t.json(),r=s.data?.attributes||s.data||s;return{sessionId:s.data?.id||r.sessionId,type:r.type||"onramp",status:r.status||"cancelled",customerId:r.customerId,externalCustomerId:r.externalCustomerId,sourceAmount:r.sourceAmount,sourceCurrency:r.sourceCurrency,destinationCurrency:r.destinationCurrency,destinationAddress:r.destinationAddress,network:r.network,redirectUrl:r.redirectUrl,metadata:r.metadata,orderId:r.orderId,expiresAt:r.expiresAt,confirmedAt:r.confirmedAt,completedAt:r.completedAt,createdAt:r.createdAt}}}e.ADDRESS_PATTERNS=t,e.ALLOWED_PROTOCOLS=s,e.API_KEY_PREFIXES=i,e.DEV_ALLOWED_HOSTNAMES=r,e.RampApi=l,e.RampWidget=c,e.VERSION="0.1.13",e.default=c,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=d,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"],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.provider&&e.set("provider",this.config.provider),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",this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-modals");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=document.createElement("div");e.style.cssText="\n position: relative;\n width: 100%;\n max-width: 440px;\n height: 90vh;\n max-height: 700px;\n background: white;\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n ",this.iframe&&e.appendChild(this.iframe),this.modalContainer.appendChild(e),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,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})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nowramp/sdk",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "Official SDK for embedding the NowRamp fiat-to-crypto widget",
5
5
  "author": "NowRamp <support@nowramp.com>",
6
6
  "license": "MIT",