@nowramp/sdk 0.1.9 → 0.1.11
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 +2 -2
- package/dist/index.d.ts +215 -11
- package/dist/index.js +2 -2
- package/dist/sdk.umd.js +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @nowramp/sdk v0.1.
|
|
2
|
+
* @nowramp/sdk v0.1.11
|
|
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"}},t={ETH:"evm",USDC:"evm",USDT:"evm",DAI:"evm",WETH:"evm",WBTC:"evm",MATIC:"evm",SOL:"solana",BTC:"bitcoin"},i=["https:"],r=["localhost","127.0.0.1"],n={public:"pk_",secret:"sk_"};function o(e){return e?e.includes(n.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(n.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 s(e){if(!e)return{valid:!0};try{const t=new URL(e);return i.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(i,r){if(!i)return{valid:!0};const n=i.trim();if(r){const i=t[r.toUpperCase()];if(i){const{pattern:t,description:r}=e[i];return t.test(n)?{valid:!0}:{valid:!1,error:r}}}for(const{pattern:t}of Object.values(e))if(t.test(n))return{valid:!0};return n.length>=10&&n.length<=100?{valid:!0}:{valid:!1,error:"walletAddress format is not recognized"}}function c(e,t){if(!t)return!0;try{if(e===new URL(t).origin)return!0;const i=new URL(e);return"localhost"===i.hostname||"127.0.0.1"===i.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.externalUserId)throw new Error("RampWidget: externalUserId is required");const e=o(this.config.apiKey);if(!e.valid)throw new Error(`RampWidget: ${e.error}`);if(this.config.redirectUrl){const e=s(this.config.redirectUrl);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}if(this.config.walletAddress){const e=a(this.config.walletAddress,this.config.destinationCurrency);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}}buildWidgetUrl(){const e=new URLSearchParams({apiKey:this.config.apiKey,projectId:this.config.projectId,externalUserId:this.config.externalUserId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return 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 i=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},i)}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(()=>({})),i=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${i}`)}const i=await t.json(),r=i.data?.attributes||i.data||i;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(()=>({})),i=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${i}`)}const t=await e.json(),i=t.data?.attributes||t.data||t;return{fiat:i.fiat||[],crypto:i.crypto||[],provider:i.provider||"unknown"}}}exports.ADDRESS_PATTERNS=e,exports.ALLOWED_PROTOCOLS=i,exports.API_KEY_PREFIXES=n,exports.CURRENCY_CHAIN_MAP=t,exports.DEV_ALLOWED_HOSTNAMES=r,exports.RampApi=l,exports.RampWidget=d,exports.VERSION="0.1.9",exports.default=d,exports.getCurrencies=async function(e){return new l(e).getCurrencies()},exports.getRate=async function(e,t){return new l(e).getRate(t)},exports.validateApiKey=o,exports.validateMessageOrigin=c,exports.validateRedirectUrl=s,exports.validateWalletAddress=a;
|
|
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"],i={public:"pk_",secret:"sk_"};function s(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 n(e){if(!e)return{valid:!0};try{const i=new URL(e);return t.includes(i.protocol)||"http:"===i.protocol&&r.includes(i.hostname)?{valid:!0}:{valid:!1,error:`redirectUrl must use HTTPS (got ${i.protocol})`}}catch{return{valid:!1,error:"redirectUrl is not a valid URL"}}}function o(t,r){if(!t)return{valid:!0};const i=t.trim();if(r){const t=r.toLowerCase(),s=e[t];if(s){const{pattern:e,description:t}=s;return e.test(i)?{valid:!0}:{valid:!1,error:t}}return i.length>=10&&i.length<=100?{valid:!0}:{valid:!1,error:"Address format not recognized"}}return i.length>=10&&i.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.externalUserId)throw new Error("RampWidget: externalUserId is required");const e=s(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,externalUserId:this.config.externalUserId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return 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(),i=r.data?.attributes||r.data||r;return{rate:i.rate,sourceAmount:i.sourceAmount,sourceCurrency:i.sourceCurrency,destinationAmount:i.destinationAmount,destinationCurrency:i.destinationCurrency,fees:{processingFee:i.fees?.processingFee||0,processingFeePercent:i.fees?.processingFeePercent||0,networkFee:i.fees?.networkFee||0,totalFee:i.fees?.totalFee||0},provider:i.provider||"unknown",expiresAt:i.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}}exports.ADDRESS_PATTERNS=e,exports.ALLOWED_PROTOCOLS=t,exports.API_KEY_PREFIXES=i,exports.DEV_ALLOWED_HOSTNAMES=r,exports.RampApi=c,exports.RampWidget=d,exports.VERSION="0.1.11",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=s,exports.validateMessageOrigin=a,exports.validateRedirectUrl=n,exports.validateWalletAddress=o;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
type FlowType = 'buy' | 'sell';
|
|
5
5
|
type Theme = 'light' | 'dark';
|
|
6
6
|
type Locale = 'en' | 'es' | 'fr' | 'de';
|
|
7
|
-
type ChainType = 'evm' | 'solana' | 'bitcoin';
|
|
7
|
+
type ChainType = 'evm' | 'solana' | 'bitcoin' | 'tezos' | 'other';
|
|
8
|
+
/**
|
|
9
|
+
* Extended chain type for validation API (includes all supported chains)
|
|
10
|
+
*/
|
|
11
|
+
type ValidationChainType = 'evm' | 'solana' | 'bitcoin' | 'tezos' | 'other';
|
|
8
12
|
interface QuoteData {
|
|
9
13
|
id: string;
|
|
10
14
|
sourceAmount: number;
|
|
@@ -180,6 +184,94 @@ interface AvailableCurrencies {
|
|
|
180
184
|
crypto: CryptoCurrency[];
|
|
181
185
|
/** Provider that returned these currencies */
|
|
182
186
|
provider: string;
|
|
187
|
+
/** Environment mode (sandbox or production) */
|
|
188
|
+
environment: 'sandbox' | 'production';
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Parameters for validating a wallet address
|
|
192
|
+
*/
|
|
193
|
+
interface ValidateAddressParams {
|
|
194
|
+
/** The wallet address to validate */
|
|
195
|
+
address: string;
|
|
196
|
+
/** Network identifier (e.g., 'ethereum', 'polygon', 'bitcoin') */
|
|
197
|
+
network?: string;
|
|
198
|
+
/** Chain type override (e.g., 'evm', 'solana', 'bitcoin', 'tezos', 'other') */
|
|
199
|
+
chainType?: ValidationChainType;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Detailed validation information
|
|
203
|
+
*/
|
|
204
|
+
interface ValidationDetails {
|
|
205
|
+
/** Whether the address format is valid */
|
|
206
|
+
formatValid: boolean;
|
|
207
|
+
/** Human-readable message about the format validation */
|
|
208
|
+
formatMessage: string;
|
|
209
|
+
/** Whether the checksum is valid (EVM only) */
|
|
210
|
+
checksumValid?: boolean;
|
|
211
|
+
/** Bitcoin address type: 'legacy' | 'segwit' | 'native-segwit' | 'taproot' */
|
|
212
|
+
addressType?: string;
|
|
213
|
+
/** Tezos account type: 'implicit' | 'contract' */
|
|
214
|
+
accountType?: string;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Result of validating a wallet address
|
|
218
|
+
*/
|
|
219
|
+
interface AddressValidationResult {
|
|
220
|
+
/** Whether the address is valid for the specified network/chain */
|
|
221
|
+
isValid: boolean;
|
|
222
|
+
/** The original address submitted */
|
|
223
|
+
address: string;
|
|
224
|
+
/** The network ID if specified or detected */
|
|
225
|
+
network: string | null;
|
|
226
|
+
/** The chain type if specified or detected */
|
|
227
|
+
chainType: ValidationChainType | null;
|
|
228
|
+
/** Checksummed/normalized address if applicable (EVM addresses) */
|
|
229
|
+
normalizedAddress: string | null;
|
|
230
|
+
/** Detailed validation information */
|
|
231
|
+
details: ValidationDetails;
|
|
232
|
+
/** Warning messages (non-blocking issues) */
|
|
233
|
+
warnings: string[];
|
|
234
|
+
/** Error messages (blocking issues) */
|
|
235
|
+
errors: string[];
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Result of batch address validation
|
|
239
|
+
*/
|
|
240
|
+
interface AddressValidationBatchResult {
|
|
241
|
+
/** Individual validation results */
|
|
242
|
+
results: AddressValidationResult[];
|
|
243
|
+
/** Number of valid addresses */
|
|
244
|
+
validCount: number;
|
|
245
|
+
/** Number of invalid addresses */
|
|
246
|
+
invalidCount: number;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Supported network information
|
|
250
|
+
*/
|
|
251
|
+
interface SupportedNetwork {
|
|
252
|
+
/** Network identifier */
|
|
253
|
+
id: string;
|
|
254
|
+
/** Display name */
|
|
255
|
+
name: string;
|
|
256
|
+
/** Chain type */
|
|
257
|
+
chainType: ValidationChainType;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Result of getting supported networks
|
|
261
|
+
*/
|
|
262
|
+
interface SupportedNetworksResult {
|
|
263
|
+
/** List of all supported networks */
|
|
264
|
+
networks: SupportedNetwork[];
|
|
265
|
+
/** Networks grouped by chain type */
|
|
266
|
+
grouped: {
|
|
267
|
+
evm: SupportedNetwork[];
|
|
268
|
+
solana: SupportedNetwork[];
|
|
269
|
+
bitcoin: SupportedNetwork[];
|
|
270
|
+
tezos: SupportedNetwork[];
|
|
271
|
+
other: SupportedNetwork[];
|
|
272
|
+
};
|
|
273
|
+
/** Total count of networks */
|
|
274
|
+
total: number;
|
|
183
275
|
}
|
|
184
276
|
|
|
185
277
|
/**
|
|
@@ -195,10 +287,6 @@ declare const ADDRESS_PATTERNS: Record<ChainType, {
|
|
|
195
287
|
pattern: RegExp;
|
|
196
288
|
description: string;
|
|
197
289
|
}>;
|
|
198
|
-
/**
|
|
199
|
-
* Currency to chain type mapping
|
|
200
|
-
*/
|
|
201
|
-
declare const CURRENCY_CHAIN_MAP: Record<string, ChainType>;
|
|
202
290
|
/**
|
|
203
291
|
* Allowed protocols for redirect URLs
|
|
204
292
|
*/
|
|
@@ -230,12 +318,12 @@ declare function validateApiKey(apiKey: string): ValidationResult;
|
|
|
230
318
|
*/
|
|
231
319
|
declare function validateRedirectUrl(url: string): ValidationResult;
|
|
232
320
|
/**
|
|
233
|
-
* Validate wallet address format
|
|
321
|
+
* Validate wallet address format based on chain type
|
|
234
322
|
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
323
|
+
* @param address - The wallet address to validate
|
|
324
|
+
* @param chainType - Chain type from API (evm, solana, bitcoin, tezos, other)
|
|
237
325
|
*/
|
|
238
|
-
declare function validateWalletAddress(address: string,
|
|
326
|
+
declare function validateWalletAddress(address: string, chainType?: ChainType): ValidationResult;
|
|
239
327
|
/**
|
|
240
328
|
* Validate message origin against expected widget URL
|
|
241
329
|
*
|
|
@@ -357,6 +445,64 @@ declare class RampApi {
|
|
|
357
445
|
* ```
|
|
358
446
|
*/
|
|
359
447
|
getCurrencies(): Promise<AvailableCurrencies>;
|
|
448
|
+
/**
|
|
449
|
+
* Validate a wallet address
|
|
450
|
+
*
|
|
451
|
+
* @param params - Address validation parameters
|
|
452
|
+
* @returns Validation result with details
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* ```typescript
|
|
456
|
+
* // Validate EVM address
|
|
457
|
+
* const result = await api.validateAddress({
|
|
458
|
+
* address: '0x742d35Cc6634C0532925a3b844Bc9e7595f1bD21',
|
|
459
|
+
* network: 'ethereum',
|
|
460
|
+
* });
|
|
461
|
+
*
|
|
462
|
+
* if (result.isValid) {
|
|
463
|
+
* console.log('Normalized address:', result.normalizedAddress);
|
|
464
|
+
* }
|
|
465
|
+
*
|
|
466
|
+
* // Auto-detect chain type
|
|
467
|
+
* const autoResult = await api.validateAddress({
|
|
468
|
+
* address: 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq',
|
|
469
|
+
* });
|
|
470
|
+
* console.log('Chain type:', autoResult.chainType); // 'bitcoin'
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
473
|
+
validateAddress(params: ValidateAddressParams): Promise<AddressValidationResult>;
|
|
474
|
+
/**
|
|
475
|
+
* Validate multiple wallet addresses in batch
|
|
476
|
+
*
|
|
477
|
+
* @param addresses - Array of address validation parameters (max 20)
|
|
478
|
+
* @returns Batch validation results
|
|
479
|
+
*
|
|
480
|
+
* @example
|
|
481
|
+
* ```typescript
|
|
482
|
+
* const results = await api.validateAddressBatch([
|
|
483
|
+
* { address: '0x742d35Cc6634C0532925a3b844Bc9e7595f1bD21', network: 'ethereum' },
|
|
484
|
+
* { address: 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq', chainType: 'bitcoin' },
|
|
485
|
+
* { address: 'tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb' },
|
|
486
|
+
* ]);
|
|
487
|
+
*
|
|
488
|
+
* console.log(`Valid: ${results.validCount}, Invalid: ${results.invalidCount}`);
|
|
489
|
+
* ```
|
|
490
|
+
*/
|
|
491
|
+
validateAddressBatch(addresses: ValidateAddressParams[]): Promise<AddressValidationBatchResult>;
|
|
492
|
+
/**
|
|
493
|
+
* Get list of supported networks for address validation
|
|
494
|
+
*
|
|
495
|
+
* @returns Supported networks with chain type information
|
|
496
|
+
*
|
|
497
|
+
* @example
|
|
498
|
+
* ```typescript
|
|
499
|
+
* const networks = await api.getSupportedNetworks();
|
|
500
|
+
*
|
|
501
|
+
* console.log('EVM networks:', networks.grouped.evm.map(n => n.name));
|
|
502
|
+
* console.log('Total networks:', networks.total);
|
|
503
|
+
* ```
|
|
504
|
+
*/
|
|
505
|
+
getSupportedNetworks(): Promise<SupportedNetworksResult>;
|
|
360
506
|
}
|
|
361
507
|
/**
|
|
362
508
|
* Standalone function to get conversion rate
|
|
@@ -388,6 +534,64 @@ declare function getRate(config: RampApiConfig, params: GetRateParams): Promise<
|
|
|
388
534
|
* ```
|
|
389
535
|
*/
|
|
390
536
|
declare function getCurrencies(config: RampApiConfig): Promise<AvailableCurrencies>;
|
|
537
|
+
/**
|
|
538
|
+
* Standalone function to validate a wallet address
|
|
539
|
+
* Convenience wrapper for one-off address validation
|
|
540
|
+
*
|
|
541
|
+
* Note: This is a public endpoint that doesn't require authentication
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* ```typescript
|
|
545
|
+
* import { validateAddress } from '@nowramp/sdk';
|
|
546
|
+
*
|
|
547
|
+
* const result = await validateAddress(
|
|
548
|
+
* { apiUrl: 'https://api.nowramp.com' },
|
|
549
|
+
* { address: '0x742d35Cc6634C0532925a3b844Bc9e7595f1bD21', network: 'ethereum' }
|
|
550
|
+
* );
|
|
551
|
+
*
|
|
552
|
+
* if (result.isValid) {
|
|
553
|
+
* console.log('Address is valid!', result.normalizedAddress);
|
|
554
|
+
* }
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
557
|
+
declare function validateAddress(config: Pick<RampApiConfig, 'apiUrl'>, params: ValidateAddressParams): Promise<AddressValidationResult>;
|
|
558
|
+
/**
|
|
559
|
+
* Standalone function to validate multiple wallet addresses
|
|
560
|
+
* Convenience wrapper for one-off batch validation
|
|
561
|
+
*
|
|
562
|
+
* Note: This is a public endpoint that doesn't require authentication
|
|
563
|
+
*
|
|
564
|
+
* @example
|
|
565
|
+
* ```typescript
|
|
566
|
+
* import { validateAddressBatch } from '@nowramp/sdk';
|
|
567
|
+
*
|
|
568
|
+
* const results = await validateAddressBatch(
|
|
569
|
+
* { apiUrl: 'https://api.nowramp.com' },
|
|
570
|
+
* [
|
|
571
|
+
* { address: '0x742d35Cc6634C0532925a3b844Bc9e7595f1bD21', network: 'ethereum' },
|
|
572
|
+
* { address: 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq', chainType: 'bitcoin' },
|
|
573
|
+
* ]
|
|
574
|
+
* );
|
|
575
|
+
*
|
|
576
|
+
* console.log(`Valid: ${results.validCount}, Invalid: ${results.invalidCount}`);
|
|
577
|
+
* ```
|
|
578
|
+
*/
|
|
579
|
+
declare function validateAddressBatch(config: Pick<RampApiConfig, 'apiUrl'>, addresses: ValidateAddressParams[]): Promise<AddressValidationBatchResult>;
|
|
580
|
+
/**
|
|
581
|
+
* Standalone function to get supported networks for validation
|
|
582
|
+
* Convenience wrapper for one-off network listing
|
|
583
|
+
*
|
|
584
|
+
* Note: This is a public endpoint that doesn't require authentication
|
|
585
|
+
*
|
|
586
|
+
* @example
|
|
587
|
+
* ```typescript
|
|
588
|
+
* import { getSupportedNetworks } from '@nowramp/sdk';
|
|
589
|
+
*
|
|
590
|
+
* const networks = await getSupportedNetworks({ apiUrl: 'https://api.nowramp.com' });
|
|
591
|
+
* console.log('EVM networks:', networks.grouped.evm.map(n => n.name));
|
|
592
|
+
* ```
|
|
593
|
+
*/
|
|
594
|
+
declare function getSupportedNetworks(config: Pick<RampApiConfig, 'apiUrl'>): Promise<SupportedNetworksResult>;
|
|
391
595
|
|
|
392
596
|
/**
|
|
393
597
|
* NowRamp Widget SDK
|
|
@@ -414,5 +618,5 @@ declare function getCurrencies(config: RampApiConfig): Promise<AvailableCurrenci
|
|
|
414
618
|
*/
|
|
415
619
|
declare const VERSION: string;
|
|
416
620
|
|
|
417
|
-
export { ADDRESS_PATTERNS, ALLOWED_PROTOCOLS, API_KEY_PREFIXES,
|
|
418
|
-
export type { AvailableCurrencies, ChainType, CryptoCurrency, ErrorData, FiatCurrency, FlowType, GetRateParams, Locale, OrderData, QuoteData, RampApiConfig, RampWidgetConfig, RateResult, Theme, ValidationResult, WidgetEventType, WidgetMessage };
|
|
621
|
+
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 };
|
|
622
|
+
export type { AddressValidationBatchResult, AddressValidationResult, AvailableCurrencies, ChainType, CryptoCurrency, ErrorData, FiatCurrency, FlowType, GetRateParams, Locale, OrderData, QuoteData, RampApiConfig, RampWidgetConfig, RateResult, SupportedNetwork, SupportedNetworksResult, Theme, ValidateAddressParams, ValidationChainType, ValidationDetails, ValidationResult, WidgetEventType, WidgetMessage };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @nowramp/sdk v0.1.
|
|
2
|
+
* @nowramp/sdk v0.1.11
|
|
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"}},t={ETH:"evm",USDC:"evm",USDT:"evm",DAI:"evm",WETH:"evm",WBTC:"evm",MATIC:"evm",SOL:"solana",BTC:"bitcoin"},i=["https:"],n=["localhost","127.0.0.1"],r={public:"pk_",secret:"sk_"};function o(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 s(e){if(!e)return{valid:!0};try{const t=new URL(e);return i.includes(t.protocol)||"http:"===t.protocol&&n.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(i,n){if(!i)return{valid:!0};const r=i.trim();if(n){const i=t[n.toUpperCase()];if(i){const{pattern:t,description:n}=e[i];return t.test(r)?{valid:!0}:{valid:!1,error:n}}}for(const{pattern:t}of Object.values(e))if(t.test(r))return{valid:!0};return r.length>=10&&r.length<=100?{valid:!0}:{valid:!1,error:"walletAddress format is not recognized"}}function c(e,t){if(!t)return!0;try{if(e===new URL(t).origin)return!0;const i=new URL(e);return"localhost"===i.hostname||"127.0.0.1"===i.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.externalUserId)throw new Error("RampWidget: externalUserId is required");const e=o(this.config.apiKey);if(!e.valid)throw new Error(`RampWidget: ${e.error}`);if(this.config.redirectUrl){const e=s(this.config.redirectUrl);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}if(this.config.walletAddress){const e=a(this.config.walletAddress,this.config.destinationCurrency);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}}buildWidgetUrl(){const e=new URLSearchParams({apiKey:this.config.apiKey,projectId:this.config.projectId,externalUserId:this.config.externalUserId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return 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 i=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},i)}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(()=>({})),i=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${i}`)}const i=await t.json(),n=i.data?.attributes||i.data||i;return{rate:n.rate,sourceAmount:n.sourceAmount,sourceCurrency:n.sourceCurrency,destinationAmount:n.destinationAmount,destinationCurrency:n.destinationCurrency,fees:{processingFee:n.fees?.processingFee||0,processingFeePercent:n.fees?.processingFeePercent||0,networkFee:n.fees?.networkFee||0,totalFee:n.fees?.totalFee||0},provider:n.provider||"unknown",expiresAt:n.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(()=>({})),i=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${i}`)}const t=await e.json(),i=t.data?.attributes||t.data||t;return{fiat:i.fiat||[],crypto:i.crypto||[],provider:i.provider||"unknown"}}}async function h(e,t){return new l(e).getRate(t)}async function p(e){return new l(e).getCurrencies()}const f="0.1.9";export{e as ADDRESS_PATTERNS,i as ALLOWED_PROTOCOLS,r as API_KEY_PREFIXES,t as CURRENCY_CHAIN_MAP,n as DEV_ALLOWED_HOSTNAMES,l as RampApi,d as RampWidget,f as VERSION,d as default,p as getCurrencies,h as getRate,o as validateApiKey,c as validateMessageOrigin,s as validateRedirectUrl,a 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:"],i=["localhost","127.0.0.1"],r={public:"pk_",secret:"sk_"};function n(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 s(e){if(!e)return{valid:!0};try{const r=new URL(e);return t.includes(r.protocol)||"http:"===r.protocol&&i.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,i){if(!t)return{valid:!0};const r=t.trim();if(i){const t=i.toLowerCase(),n=e[t];if(n){const{pattern:e,description:t}=n;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 i=new URL(e);return"localhost"===i.hostname||"127.0.0.1"===i.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.externalUserId)throw new Error("RampWidget: externalUserId is required");const e=n(this.config.apiKey);if(!e.valid)throw new Error(`RampWidget: ${e.error}`);if(this.config.redirectUrl){const e=s(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,externalUserId:this.config.externalUserId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return 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 i=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},i)}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(()=>({})),i=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${i}`)}const i=await t.json(),r=i.data?.attributes||i.data||i;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(()=>({})),i=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${i}`)}const t=await e.json(),i=t.data?.attributes||t.data||t;return{fiat:i.fiat||[],crypto:i.crypto||[],provider:i.provider||"unknown",environment:i.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(()=>({})),i=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate address: ${i}`)}const i=await t.json();return i.data?.attributes||i.data||i}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(()=>({})),i=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate addresses: ${i}`)}const i=await t.json();return i.data?.attributes||i.data||i}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(()=>({})),i=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get supported networks: ${i}`)}const t=await e.json();return t.data?.attributes||t.data||t}}async function l(e,t){return new c(e).getRate(t)}async function h(e){return new c(e).getCurrencies()}async function p(e,t){return new c({apiKey:"",projectId:"",...e}).validateAddress(t)}async function u(e,t){return new c({apiKey:"",projectId:"",...e}).validateAddressBatch(t)}async function g(e){return new c({apiKey:"",projectId:"",...e}).getSupportedNetworks()}const f="0.1.11";export{e as ADDRESS_PATTERNS,t as ALLOWED_PROTOCOLS,r as API_KEY_PREFIXES,i as DEV_ALLOWED_HOSTNAMES,c as RampApi,d as RampWidget,f as VERSION,d as default,h as getCurrencies,l as getRate,g as getSupportedNetworks,p as validateAddress,u as validateAddressBatch,n as validateApiKey,a as validateMessageOrigin,s as validateRedirectUrl,o as validateWalletAddress};
|
package/dist/sdk.umd.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @nowramp/sdk v0.1.
|
|
2
|
+
* @nowramp/sdk v0.1.11
|
|
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"}},i={ETH:"evm",USDC:"evm",USDT:"evm",DAI:"evm",WETH:"evm",WBTC:"evm",MATIC:"evm",SOL:"solana",BTC:"bitcoin"},n=["https:"],r=["localhost","127.0.0.1"],o={public:"pk_",secret:"sk_"};function s(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 a(e){if(!e)return{valid:!0};try{const t=new URL(e);return n.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 c(e,n){if(!e)return{valid:!0};const r=e.trim();if(n){const e=i[n.toUpperCase()];if(e){const{pattern:i,description:n}=t[e];return i.test(r)?{valid:!0}:{valid:!1,error:n}}}for(const{pattern:e}of Object.values(t))if(e.test(r))return{valid:!0};return r.length>=10&&r.length<=100?{valid:!0}:{valid:!1,error:"walletAddress format is not recognized"}}function d(e,t){if(!t)return!0;try{if(e===new URL(t).origin)return!0;const i=new URL(e);return"localhost"===i.hostname||"127.0.0.1"===i.hostname}catch{return!1}}class l{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.externalUserId)throw new Error("RampWidget: externalUserId is required");const e=s(this.config.apiKey);if(!e.valid)throw new Error(`RampWidget: ${e.error}`);if(this.config.redirectUrl){const e=a(this.config.redirectUrl);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}if(this.config.walletAddress){const e=c(this.config.walletAddress,this.config.destinationCurrency);if(!e.valid)throw new Error(`RampWidget: ${e.error}`)}}buildWidgetUrl(){const e=new URLSearchParams({apiKey:this.config.apiKey,projectId:this.config.projectId,externalUserId:this.config.externalUserId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return 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 i=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},i)}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 h{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(()=>({})),i=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${i}`)}const i=await t.json(),n=i.data?.attributes||i.data||i;return{rate:n.rate,sourceAmount:n.sourceAmount,sourceCurrency:n.sourceCurrency,destinationAmount:n.destinationAmount,destinationCurrency:n.destinationCurrency,fees:{processingFee:n.fees?.processingFee||0,processingFeePercent:n.fees?.processingFeePercent||0,networkFee:n.fees?.networkFee||0,totalFee:n.fees?.totalFee||0},provider:n.provider||"unknown",expiresAt:n.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(()=>({})),i=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${i}`)}const t=await e.json(),i=t.data?.attributes||t.data||t;return{fiat:i.fiat||[],crypto:i.crypto||[],provider:i.provider||"unknown"}}}e.ADDRESS_PATTERNS=t,e.ALLOWED_PROTOCOLS=n,e.API_KEY_PREFIXES=o,e.CURRENCY_CHAIN_MAP=i,e.DEV_ALLOWED_HOSTNAMES=r,e.RampApi=h,e.RampWidget=l,e.VERSION="0.1.9",e.default=l,e.getCurrencies=async function(e){return new h(e).getCurrencies()},e.getRate=async function(e,t){return new h(e).getRate(t)},e.validateApiKey=s,e.validateMessageOrigin=d,e.validateRedirectUrl=a,e.validateWalletAddress=c,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)"}},i=["https:"],r=["localhost","127.0.0.1"],n={public:"pk_",secret:"sk_"};function s(e){return e?e.includes(n.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(n.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 i.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,i){if(!e)return{valid:!0};const r=e.trim();if(i){const e=i.toLowerCase(),n=t[e];if(n){const{pattern:e,description:t}=n;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 i=new URL(e);return"localhost"===i.hostname||"127.0.0.1"===i.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.externalUserId)throw new Error("RampWidget: externalUserId is required");const e=s(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,externalUserId:this.config.externalUserId,parentOrigin:window.location.origin,flowType:this.config.flowType||"buy",theme:this.config.theme||"light"});return 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 i=this.config.widgetUrl?new URL(this.config.widgetUrl).origin:"*";this.iframe.contentWindow.postMessage({source:"ramp-sdk",type:e,payload:t},i)}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(()=>({})),i=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to get rate: ${i}`)}const i=await t.json(),r=i.data?.attributes||i.data||i;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(()=>({})),i=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get currencies: ${i}`)}const t=await e.json(),i=t.data?.attributes||t.data||t;return{fiat:i.fiat||[],crypto:i.crypto||[],provider:i.provider||"unknown",environment:i.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(()=>({})),i=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate address: ${i}`)}const i=await t.json();return i.data?.attributes||i.data||i}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(()=>({})),i=e.error?.message||e.message||`HTTP ${t.status}`;throw new Error(`Failed to validate addresses: ${i}`)}const i=await t.json();return i.data?.attributes||i.data||i}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(()=>({})),i=t.error?.message||t.message||`HTTP ${e.status}`;throw new Error(`Failed to get supported networks: ${i}`)}const t=await e.json();return t.data?.attributes||t.data||t}}e.ADDRESS_PATTERNS=t,e.ALLOWED_PROTOCOLS=i,e.API_KEY_PREFIXES=n,e.DEV_ALLOWED_HOSTNAMES=r,e.RampApi=l,e.RampWidget=c,e.VERSION="0.1.11",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=s,e.validateMessageOrigin=d,e.validateRedirectUrl=o,e.validateWalletAddress=a,Object.defineProperty(e,"__esModule",{value:!0})});
|