@nowramp/sdk 0.1.6 → 0.1.9
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 +197 -2
- 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.9
|
|
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:"],
|
|
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;
|
package/dist/index.d.ts
CHANGED
|
@@ -88,6 +88,99 @@ interface ValidationResult {
|
|
|
88
88
|
valid: boolean;
|
|
89
89
|
error?: string;
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Request parameters for getting conversion rates
|
|
93
|
+
*/
|
|
94
|
+
interface GetRateParams {
|
|
95
|
+
/** Source currency code (e.g., 'USD' for buy, 'ETH' for sell) */
|
|
96
|
+
from: string;
|
|
97
|
+
/** Destination currency code (e.g., 'ETH' for buy, 'USD' for sell) */
|
|
98
|
+
to: string;
|
|
99
|
+
/** Amount in source currency */
|
|
100
|
+
amount: number;
|
|
101
|
+
/** Flow type: buy (fiat->crypto) or sell (crypto->fiat) */
|
|
102
|
+
flowType?: FlowType;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Conversion rate result from the API
|
|
106
|
+
*/
|
|
107
|
+
interface RateResult {
|
|
108
|
+
/** Exchange rate: 1 destination = X source */
|
|
109
|
+
rate: number;
|
|
110
|
+
/** Source currency and amount */
|
|
111
|
+
sourceAmount: number;
|
|
112
|
+
sourceCurrency: string;
|
|
113
|
+
/** Destination currency and amount (after fees) */
|
|
114
|
+
destinationAmount: number;
|
|
115
|
+
destinationCurrency: string;
|
|
116
|
+
/** Fee breakdown */
|
|
117
|
+
fees: {
|
|
118
|
+
/** Processing fee in source currency */
|
|
119
|
+
processingFee: number;
|
|
120
|
+
/** Processing fee as decimal (0.05 = 5%) */
|
|
121
|
+
processingFeePercent: number;
|
|
122
|
+
/** Network fee in source currency */
|
|
123
|
+
networkFee: number;
|
|
124
|
+
/** Total fees in source currency */
|
|
125
|
+
totalFee: number;
|
|
126
|
+
};
|
|
127
|
+
/** Provider that returned this rate */
|
|
128
|
+
provider: string;
|
|
129
|
+
/** Rate expiry timestamp (optional) */
|
|
130
|
+
expiresAt?: string;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Configuration for standalone API calls (not widget)
|
|
134
|
+
*/
|
|
135
|
+
interface RampApiConfig {
|
|
136
|
+
/** Partner API key (required) */
|
|
137
|
+
apiKey: string;
|
|
138
|
+
/** Project ID (required) */
|
|
139
|
+
projectId: string;
|
|
140
|
+
/** API base URL (optional, defaults to https://api.nowramp.com) */
|
|
141
|
+
apiUrl?: string;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Fiat currency info
|
|
145
|
+
*/
|
|
146
|
+
interface FiatCurrency {
|
|
147
|
+
/** Currency code (e.g., USD, EUR) */
|
|
148
|
+
code: string;
|
|
149
|
+
/** Display name */
|
|
150
|
+
name: string;
|
|
151
|
+
/** Currency symbol (e.g., $, €) */
|
|
152
|
+
symbol: string;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Crypto currency info
|
|
156
|
+
*/
|
|
157
|
+
interface CryptoCurrency {
|
|
158
|
+
/** Unique identifier: symbol_network */
|
|
159
|
+
id: string;
|
|
160
|
+
/** Token symbol (e.g., ETH, BTC) */
|
|
161
|
+
symbol: string;
|
|
162
|
+
/** Display name */
|
|
163
|
+
name: string;
|
|
164
|
+
/** Network/chain identifier */
|
|
165
|
+
network: string;
|
|
166
|
+
/** Chain type for address validation (evm, bitcoin, solana) */
|
|
167
|
+
chainType: ChainType;
|
|
168
|
+
/** Address placeholder for UI */
|
|
169
|
+
addressPlaceholder: string;
|
|
170
|
+
/** Example address for UI hint */
|
|
171
|
+
addressExample: string;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Available currencies from the provider
|
|
175
|
+
*/
|
|
176
|
+
interface AvailableCurrencies {
|
|
177
|
+
/** Supported fiat currencies */
|
|
178
|
+
fiat: FiatCurrency[];
|
|
179
|
+
/** Supported crypto currencies */
|
|
180
|
+
crypto: CryptoCurrency[];
|
|
181
|
+
/** Provider that returned these currencies */
|
|
182
|
+
provider: string;
|
|
183
|
+
}
|
|
91
184
|
|
|
92
185
|
/**
|
|
93
186
|
* SDK Validation Utilities
|
|
@@ -194,6 +287,108 @@ declare class RampWidget {
|
|
|
194
287
|
private cleanup;
|
|
195
288
|
}
|
|
196
289
|
|
|
290
|
+
/**
|
|
291
|
+
* NowRamp API Client
|
|
292
|
+
* Provider-agnostic API calls for getting rates and other data
|
|
293
|
+
*/
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* NowRamp API Client for making provider-agnostic API calls
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```typescript
|
|
300
|
+
* import { RampApi } from '@nowramp/sdk';
|
|
301
|
+
*
|
|
302
|
+
* const api = new RampApi({
|
|
303
|
+
* apiKey: 'ramp_pk_xxx',
|
|
304
|
+
* projectId: 'proj_xxx',
|
|
305
|
+
* });
|
|
306
|
+
*
|
|
307
|
+
* const rate = await api.getRate({
|
|
308
|
+
* from: 'USD',
|
|
309
|
+
* to: 'ETH',
|
|
310
|
+
* amount: 100,
|
|
311
|
+
* });
|
|
312
|
+
* console.log(`You'll receive ${rate.destinationAmount} ${rate.destinationCurrency}`);
|
|
313
|
+
* ```
|
|
314
|
+
*/
|
|
315
|
+
declare class RampApi {
|
|
316
|
+
private config;
|
|
317
|
+
private baseUrl;
|
|
318
|
+
constructor(config: RampApiConfig);
|
|
319
|
+
/**
|
|
320
|
+
* Get conversion rate from configured payment provider
|
|
321
|
+
*
|
|
322
|
+
* @param params - Rate request parameters
|
|
323
|
+
* @returns Conversion rate with fee breakdown
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* ```typescript
|
|
327
|
+
* // Get rate for buying ETH with USD
|
|
328
|
+
* const buyRate = await api.getRate({
|
|
329
|
+
* from: 'USD',
|
|
330
|
+
* to: 'ETH',
|
|
331
|
+
* amount: 100,
|
|
332
|
+
* flowType: 'buy',
|
|
333
|
+
* });
|
|
334
|
+
*
|
|
335
|
+
* // Get rate for selling ETH to USD
|
|
336
|
+
* const sellRate = await api.getRate({
|
|
337
|
+
* from: 'ETH',
|
|
338
|
+
* to: 'USD',
|
|
339
|
+
* amount: 0.1,
|
|
340
|
+
* flowType: 'sell',
|
|
341
|
+
* });
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
getRate(params: GetRateParams): Promise<RateResult>;
|
|
345
|
+
/**
|
|
346
|
+
* Get available currencies from configured payment provider
|
|
347
|
+
* Returns fiat and crypto currencies filtered by project settings
|
|
348
|
+
*
|
|
349
|
+
* @returns Available fiat and crypto currencies
|
|
350
|
+
*
|
|
351
|
+
* @example
|
|
352
|
+
* ```typescript
|
|
353
|
+
* const currencies = await api.getCurrencies();
|
|
354
|
+
*
|
|
355
|
+
* console.log('Available fiat:', currencies.fiat.map(f => f.code));
|
|
356
|
+
* console.log('Available crypto:', currencies.crypto.map(c => c.symbol));
|
|
357
|
+
* ```
|
|
358
|
+
*/
|
|
359
|
+
getCurrencies(): Promise<AvailableCurrencies>;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Standalone function to get conversion rate
|
|
363
|
+
* Convenience wrapper for one-off rate checks
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* ```typescript
|
|
367
|
+
* import { getRate } from '@nowramp/sdk';
|
|
368
|
+
*
|
|
369
|
+
* const rate = await getRate(
|
|
370
|
+
* { apiKey: 'ramp_pk_xxx', projectId: 'proj_xxx' },
|
|
371
|
+
* { from: 'USD', to: 'ETH', amount: 100 }
|
|
372
|
+
* );
|
|
373
|
+
* ```
|
|
374
|
+
*/
|
|
375
|
+
declare function getRate(config: RampApiConfig, params: GetRateParams): Promise<RateResult>;
|
|
376
|
+
/**
|
|
377
|
+
* Standalone function to get available currencies
|
|
378
|
+
* Convenience wrapper for one-off currency fetching
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* ```typescript
|
|
382
|
+
* import { getCurrencies } from '@nowramp/sdk';
|
|
383
|
+
*
|
|
384
|
+
* const currencies = await getCurrencies({
|
|
385
|
+
* apiKey: 'ramp_pk_xxx',
|
|
386
|
+
* projectId: 'proj_xxx'
|
|
387
|
+
* });
|
|
388
|
+
* ```
|
|
389
|
+
*/
|
|
390
|
+
declare function getCurrencies(config: RampApiConfig): Promise<AvailableCurrencies>;
|
|
391
|
+
|
|
197
392
|
/**
|
|
198
393
|
* NowRamp Widget SDK
|
|
199
394
|
*
|
|
@@ -219,5 +414,5 @@ declare class RampWidget {
|
|
|
219
414
|
*/
|
|
220
415
|
declare const VERSION: string;
|
|
221
416
|
|
|
222
|
-
export { ADDRESS_PATTERNS, ALLOWED_PROTOCOLS, API_KEY_PREFIXES, CURRENCY_CHAIN_MAP, DEV_ALLOWED_HOSTNAMES, RampWidget, VERSION, RampWidget as default, validateApiKey, validateMessageOrigin, validateRedirectUrl, validateWalletAddress };
|
|
223
|
-
export type { ChainType, ErrorData, FlowType, Locale, OrderData, QuoteData, RampWidgetConfig, Theme, ValidationResult, WidgetEventType, WidgetMessage };
|
|
417
|
+
export { ADDRESS_PATTERNS, ALLOWED_PROTOCOLS, API_KEY_PREFIXES, CURRENCY_CHAIN_MAP, DEV_ALLOWED_HOSTNAMES, RampApi, RampWidget, VERSION, RampWidget as default, getCurrencies, getRate, validateApiKey, validateMessageOrigin, validateRedirectUrl, validateWalletAddress };
|
|
418
|
+
export type { AvailableCurrencies, ChainType, CryptoCurrency, ErrorData, FiatCurrency, FlowType, GetRateParams, Locale, OrderData, QuoteData, RampApiConfig, RampWidgetConfig, RateResult, Theme, ValidationResult, WidgetEventType, WidgetMessage };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @nowramp/sdk v0.1.
|
|
2
|
+
* @nowramp/sdk v0.1.9
|
|
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
|
|
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};
|
package/dist/sdk.umd.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @nowramp/sdk v0.1.
|
|
2
|
+
* @nowramp/sdk v0.1.9
|
|
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
|
|
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})});
|