@coinflowlabs/angular 1.7.2 → 1.8.0

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/README.md CHANGED
@@ -4,6 +4,12 @@ This library was generated with [Angular CLI](https://github.com/angular/angular
4
4
 
5
5
  # Changelog
6
6
 
7
+ ## 1.8.0
8
+
9
+ - New `CoinflowCardForm` component — simple card input with a single `tokenize()` call and full theme support
10
+ - Added theme options for `fontSize`and placeholder text
11
+ - Improved security for iframe communication
12
+
7
13
  ## 1.7.2
8
14
 
9
15
  - Fixed typing for sessionKey being not present when passing the wallet object
@@ -67,8 +67,8 @@ var PaymentMethods;
67
67
  PaymentMethods["applePay"] = "applePay";
68
68
  PaymentMethods["credits"] = "credits";
69
69
  PaymentMethods["crypto"] = "crypto";
70
- PaymentMethods["instantBankTransfer"] = "instantBankTransfer";
71
70
  PaymentMethods["wire"] = "wire";
71
+ PaymentMethods["cashApp"] = "cashApp";
72
72
  })(PaymentMethods || (PaymentMethods = {}));
73
73
  const paymentMethodLabels = {
74
74
  [PaymentMethods.card]: 'Card',
@@ -81,8 +81,8 @@ const paymentMethodLabels = {
81
81
  [PaymentMethods.applePay]: 'Apple Pay',
82
82
  [PaymentMethods.credits]: 'Credits',
83
83
  [PaymentMethods.crypto]: 'Crypto',
84
- [PaymentMethods.instantBankTransfer]: 'Instant Bank Transfer',
85
84
  [PaymentMethods.wire]: 'Wire Transfer',
85
+ [PaymentMethods.cashApp]: 'CashApp',
86
86
  };
87
87
  var CardType;
88
88
  (function (CardType) {
@@ -483,8 +483,20 @@ function getCurrencyDecimals(currency) {
483
483
  function isTypedCurrencyCents(cents, currency) {
484
484
  return cents.currency === currency;
485
485
  }
486
+ function invertRate(ex) {
487
+ return {
488
+ base: ex.to,
489
+ rate: 1 / ex.rate,
490
+ to: ex.base,
491
+ };
492
+ }
486
493
 
487
- function fun() {
494
+ function getNSureDeviceId() {
495
+ if (typeof window !== 'undefined') {
496
+ const urlDeviceId = new URLSearchParams(window.location.search).get('deviceId');
497
+ if (urlDeviceId)
498
+ return urlDeviceId;
499
+ }
488
500
  if (nsureSDK)
489
501
  return nsureSDK.getDeviceId();
490
502
  return null;
@@ -604,7 +616,7 @@ class CoinflowUtils {
604
616
  url.searchParams.append('deviceId', deviceId);
605
617
  }
606
618
  else {
607
- const deviceId = fun();
619
+ const deviceId = getNSureDeviceId();
608
620
  if (deviceId)
609
621
  url.searchParams.append('deviceId', deviceId);
610
622
  }
@@ -719,6 +731,12 @@ class CoinflowUtils {
719
731
  const { transaction } = props;
720
732
  return LZString.compressToEncodedURIComponent(JSON.stringify(transaction));
721
733
  },
734
+ tempo: () => {
735
+ if (!('transaction' in props))
736
+ return undefined;
737
+ const { transaction } = props;
738
+ return LZString.compressToEncodedURIComponent(JSON.stringify(transaction));
739
+ },
722
740
  user: () => {
723
741
  return undefined;
724
742
  },
@@ -740,6 +758,8 @@ class CoinflowUtils {
740
758
  return args.stellar;
741
759
  case 'monad':
742
760
  return args.monad;
761
+ case 'tempo':
762
+ return args.tempo;
743
763
  case 'user':
744
764
  return args.user;
745
765
  default:
@@ -766,6 +786,18 @@ function getCustomerName(info) {
766
786
  };
767
787
  return undefined;
768
788
  }
789
+ function recordFrontendError({ event, error, env, merchantId, }) {
790
+ const isError = error instanceof Error;
791
+ const message = isError ? error.message : error;
792
+ const stackTrace = isError ? error.stack : '';
793
+ fetch(`${CoinflowUtils.getCoinflowApiUrl(env)}/api/telemetry/frontend-error`, {
794
+ method: 'POST',
795
+ body: JSON.stringify({ message, stackTrace, merchantId, event }),
796
+ headers: {
797
+ 'Content-Type': 'application/json',
798
+ },
799
+ }).catch(() => { });
800
+ }
769
801
 
770
802
  var IFrameMessageMethods;
771
803
  (function (IFrameMessageMethods) {
@@ -777,6 +809,7 @@ var IFrameMessageMethods;
777
809
  IFrameMessageMethods["AuthDeclined"] = "authDeclined";
778
810
  IFrameMessageMethods["Loaded"] = "loaded";
779
811
  IFrameMessageMethods["AccountLinked"] = "accountLinked";
812
+ IFrameMessageMethods["Redirect"] = "redirect";
780
813
  })(IFrameMessageMethods || (IFrameMessageMethods = {}));
781
814
  function getWalletPubkey(input) {
782
815
  let wallet;
@@ -840,6 +873,9 @@ function handleIFrameMessage(rawMessage, handlers, handleHeightChangeId) {
840
873
  return;
841
874
  case IFrameMessageMethods.AccountLinked:
842
875
  return;
876
+ case IFrameMessageMethods.Redirect:
877
+ window.open(data, '_blank');
878
+ return;
843
879
  }
844
880
  console.warn(`Didn't expect to get here, handleIFrameMessage method:${method} is not one of ${Object.values(IFrameMessageMethods)}`);
845
881
  }
@@ -909,6 +945,11 @@ function getHandlers(props) {
909
945
  onSuccess: props.onSuccess,
910
946
  onAuthDeclined: props.onAuthDeclined,
911
947
  }),
948
+ tempo: () => getEvmWalletHandlers({
949
+ wallet: wallet,
950
+ onSuccess: props.onSuccess,
951
+ onAuthDeclined: props.onAuthDeclined,
952
+ }),
912
953
  user: () => getSessionKeyHandlers(props),
913
954
  })();
914
955
  }
@@ -1228,6 +1269,96 @@ var nftCartItem;
1228
1269
  })(productType = nftCartItem.productType || (nftCartItem.productType = {}));
1229
1270
  })(nftCartItem || (nftCartItem = {}));
1230
1271
 
1272
+ let cachedSessionId = null;
1273
+ async function initProtectionSession({ merchantId, env, }) {
1274
+ if (cachedSessionId)
1275
+ return;
1276
+ if (typeof window !== 'undefined') {
1277
+ try {
1278
+ const result = await window.Verisoul?.session();
1279
+ if (result?.session_id)
1280
+ cachedSessionId = result.session_id;
1281
+ }
1282
+ catch (e) {
1283
+ console.error(e);
1284
+ recordFrontendError({ event: 'ProtectionInit', env, merchantId, error: e });
1285
+ }
1286
+ }
1287
+ }
1288
+ function getProtectionSessionId() {
1289
+ return cachedSessionId;
1290
+ }
1291
+
1292
+ const DEVICE_ID_HEADER = 'x-device-id';
1293
+ const SESSION_ID_HEADER = 'x-session-id';
1294
+ function getCoinflowProtectionHeaders() {
1295
+ return {
1296
+ [DEVICE_ID_HEADER]: getNSureDeviceId(),
1297
+ [SESSION_ID_HEADER]: getProtectionSessionId(),
1298
+ };
1299
+ }
1300
+
1301
+ const NSURE_APP_IDS = {
1302
+ prod: '9JBW2RHC7JNJN8ZQ',
1303
+ sandbox: 'SANDBOX_CTCE4XK53ZW0R7V1',
1304
+ };
1305
+ const PROTECTION_SESSION_PROJECT_IDS = {
1306
+ prod: '315da543-c486-435a-aa21-53844c469822',
1307
+ sandbox: 'e9f629c4-80ee-4c6d-967e-62af47d8679e',
1308
+ };
1309
+ async function initCoinflowProtection({ coinflowEnv, merchantId, }) {
1310
+ const env = coinflowEnv === 'prod' ? 'prod' : 'sandbox';
1311
+ const hasUrlDeviceId = typeof window !== 'undefined' &&
1312
+ new URLSearchParams(window.location.search).has('deviceId');
1313
+ if (!hasUrlDeviceId) {
1314
+ const partnerId = await new CoinflowUtils(coinflowEnv).getNSurePartnerId(merchantId);
1315
+ if (partnerId) {
1316
+ const appId = NSURE_APP_IDS[env] ?? NSURE_APP_IDS['sandbox'];
1317
+ try {
1318
+ nsureSDK.init(appId, partnerId);
1319
+ }
1320
+ catch (e) {
1321
+ console.error('Failed to initialize nSure SDK:', e);
1322
+ recordFrontendError({
1323
+ event: 'NSureInit',
1324
+ error: e,
1325
+ env: coinflowEnv,
1326
+ merchantId,
1327
+ });
1328
+ }
1329
+ }
1330
+ }
1331
+ // Initialize protection session (Verisoul)
1332
+ if (typeof document !== 'undefined') {
1333
+ const existing = document.querySelector('script[verisoul-project-id]');
1334
+ if (!existing) {
1335
+ const projectId = PROTECTION_SESSION_PROJECT_IDS[env] ??
1336
+ PROTECTION_SESSION_PROJECT_IDS['sandbox'];
1337
+ if (projectId) {
1338
+ await new Promise(resolve => {
1339
+ const script = document.createElement('script');
1340
+ script.src = `https://js.v.coinflow.sh/${env}/bundle.js`;
1341
+ script.async = true;
1342
+ script.setAttribute('verisoul-project-id', projectId);
1343
+ script.onload = () => {
1344
+ initProtectionSession({ merchantId, env: coinflowEnv }).then(resolve);
1345
+ };
1346
+ script.onerror = e => {
1347
+ recordFrontendError({
1348
+ event: 'ProtectionError',
1349
+ error: e,
1350
+ env: coinflowEnv,
1351
+ merchantId,
1352
+ });
1353
+ resolve();
1354
+ };
1355
+ document.head.appendChild(script);
1356
+ });
1357
+ }
1358
+ }
1359
+ }
1360
+ }
1361
+
1231
1362
  class CoinflowIFrameComponent {
1232
1363
  constructor(sanitizer) {
1233
1364
  this.sanitizer = sanitizer;
@@ -1670,6 +1801,125 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
1670
1801
  type: Input
1671
1802
  }] } });
1672
1803
 
1804
+ class CoinflowCardForm {
1805
+ constructor() {
1806
+ this.url = '';
1807
+ this.loaded = false;
1808
+ }
1809
+ ngOnInit() {
1810
+ this.buildUrl();
1811
+ this.messageHandler = (event) => this.handleMessage(event.data, event.origin);
1812
+ window.addEventListener('message', this.messageHandler);
1813
+ }
1814
+ ngOnDestroy() {
1815
+ if (this.messageHandler) {
1816
+ window.removeEventListener('message', this.messageHandler);
1817
+ }
1818
+ }
1819
+ buildUrl() {
1820
+ const baseUrl = CoinflowUtils.getCoinflowBaseUrl(this.args.env);
1821
+ const iframeUrl = new URL(`/form/v2/${this.args.variant}`, baseUrl);
1822
+ iframeUrl.searchParams.append('merchantId', this.args.merchantId);
1823
+ if (this.args.theme) {
1824
+ iframeUrl.searchParams.append('theme', LZString.compressToEncodedURIComponent(JSON.stringify(this.args.theme)));
1825
+ }
1826
+ if (this.args.token) {
1827
+ iframeUrl.searchParams.append('token', this.args.token);
1828
+ }
1829
+ this.url = iframeUrl.toString();
1830
+ }
1831
+ handleMessage(data, origin) {
1832
+ const expectedOrigin = new URL(CoinflowUtils.getCoinflowBaseUrl(this.args.env)).origin;
1833
+ if (origin !== expectedOrigin)
1834
+ return;
1835
+ try {
1836
+ const parsed = JSON.parse(data);
1837
+ if (parsed.method === IFrameMessageMethods.Loaded) {
1838
+ this.loaded = true;
1839
+ this.args.onLoad?.();
1840
+ }
1841
+ }
1842
+ catch {
1843
+ // not JSON
1844
+ }
1845
+ }
1846
+ tokenize() {
1847
+ return new Promise((resolve, reject) => {
1848
+ const iframe = this.iframeRef?.nativeElement;
1849
+ if (!iframe?.contentWindow) {
1850
+ reject(new Error('Card form iframe not loaded'));
1851
+ return;
1852
+ }
1853
+ const handler = (event) => {
1854
+ const { data, origin } = event;
1855
+ const expectedOrigin = new URL(CoinflowUtils.getCoinflowBaseUrl(this.args.env)).origin;
1856
+ if (origin !== expectedOrigin)
1857
+ return;
1858
+ try {
1859
+ const parsed = JSON.parse(data);
1860
+ if (parsed.method !== 'tokenize')
1861
+ return;
1862
+ window.removeEventListener('message', handler);
1863
+ if (typeof parsed.data === 'string' &&
1864
+ parsed.data.startsWith('ERROR')) {
1865
+ reject(new Error(parsed.data.replace('ERROR ', '')));
1866
+ return;
1867
+ }
1868
+ const responseData = typeof parsed.data === 'string'
1869
+ ? JSON.parse(parsed.data)
1870
+ : parsed.data;
1871
+ resolve(responseData);
1872
+ }
1873
+ catch {
1874
+ // not relevant
1875
+ }
1876
+ };
1877
+ window.addEventListener('message', handler);
1878
+ iframe.contentWindow.postMessage('tokenize', '*');
1879
+ });
1880
+ }
1881
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CoinflowCardForm, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1882
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.0", type: CoinflowCardForm, isStandalone: true, selector: "lib-coinflow-card-form", inputs: { args: "args" }, viewQueries: [{ propertyName: "iframeRef", first: true, predicate: ["cardFormIframe"], descendants: true, static: true }], ngImport: i0, template: `<iframe
1883
+ #cardFormIframe
1884
+ [src]="url"
1885
+ title="Card Form"
1886
+ frameBorder="0"
1887
+ allow="payment"
1888
+ [style.width]="'100%'"
1889
+ [style.height]="'60px'"
1890
+ [style.border]="'none'"
1891
+ [style.opacity]="loaded ? 1 : 0"
1892
+ [style.transition]="'opacity 300ms linear'"
1893
+ ></iframe>`, isInline: true }); }
1894
+ }
1895
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CoinflowCardForm, decorators: [{
1896
+ type: Component,
1897
+ args: [{
1898
+ selector: 'lib-coinflow-card-form',
1899
+ standalone: true,
1900
+ imports: [],
1901
+ template: `<iframe
1902
+ #cardFormIframe
1903
+ [src]="url"
1904
+ title="Card Form"
1905
+ frameBorder="0"
1906
+ allow="payment"
1907
+ [style.width]="'100%'"
1908
+ [style.height]="'60px'"
1909
+ [style.border]="'none'"
1910
+ [style.opacity]="loaded ? 1 : 0"
1911
+ [style.transition]="'opacity 300ms linear'"
1912
+ ></iframe>`,
1913
+ }]
1914
+ }], propDecorators: { args: [{
1915
+ type: Input
1916
+ }], iframeRef: [{
1917
+ type: ViewChild,
1918
+ args: ['cardFormIframe', { static: true }]
1919
+ }] } });
1920
+ /** @deprecated Use CoinflowCardForm instead */
1921
+ const CoinflowCardFormV2 = CoinflowCardForm;
1922
+
1673
1923
  class CoinflowMobileWalletButtonComponent {
1674
1924
  constructor() {
1675
1925
  this.opacity = 0.8;
@@ -2036,5 +2286,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
2036
2286
  * Generated bundle index. Do not edit.
2037
2287
  */
2038
2288
 
2039
- export { BankingCurrencies, CARD_TYPE_MAPPING, CardType, ChargebackProtectionAccountType, CoinflowApplePayButtonComponent, CoinflowCardNumberInput, CoinflowCardNumberOnlyInput, CoinflowCvvInputComponent, CoinflowCvvOnlyInputComponent, CoinflowGooglePayButtonComponent, CoinflowIFrameComponent, CoinflowPurchaseComponent, CoinflowPurchaseHistoryComponent, CoinflowPurchaseProtectionComponent, CoinflowUtils, CoinflowWithdrawComponent, CoinflowWithdrawHistoryComponent, Currency, CurrencyToISO4217, EventBus, IFrameMessageMethods, MerchantStyle, PaymentMethods, RN_REDIRECT_MESSAGE_NAME, SettlementType, ThreeDsChallengePreference, TokenExCardNumberIframeId, TokenExCvvContainerID, WithdrawCategory, WithdrawCurrencies, WithdrawSpeed, doInitializeCvvOnlyTokenExIframe, doInitializeTokenExCardOnlyIframe, doInitializeTokenExIframe, getCurrencyDecimals, getCustomerName, getHandlers, getIframeConfig, getWalletPubkey, handleIFrameMessage, isBankingCurrency, isTypedCurrencyCents, isWithdrawCurrency, isZeroAuthSavedPaymentMethods, isZeroAuthVerifyCard, nftCartItem, paymentMethodLabels, setTokenExScriptTag };
2289
+ export { BankingCurrencies, CARD_TYPE_MAPPING, CardType, ChargebackProtectionAccountType, CoinflowApplePayButtonComponent, CoinflowCardForm, CoinflowCardFormV2, CoinflowCardNumberInput, CoinflowCardNumberOnlyInput, CoinflowCvvInputComponent, CoinflowCvvOnlyInputComponent, CoinflowGooglePayButtonComponent, CoinflowIFrameComponent, CoinflowPurchaseComponent, CoinflowPurchaseHistoryComponent, CoinflowPurchaseProtectionComponent, CoinflowUtils, CoinflowWithdrawComponent, CoinflowWithdrawHistoryComponent, Currency, CurrencyToISO4217, DEVICE_ID_HEADER, EventBus, IFrameMessageMethods, MerchantStyle, PaymentMethods, RN_REDIRECT_MESSAGE_NAME, SESSION_ID_HEADER, SettlementType, ThreeDsChallengePreference, TokenExCardNumberIframeId, TokenExCvvContainerID, WithdrawCategory, WithdrawCurrencies, WithdrawSpeed, doInitializeCvvOnlyTokenExIframe, doInitializeTokenExCardOnlyIframe, doInitializeTokenExIframe, getCoinflowProtectionHeaders, getCurrencyDecimals, getCustomerName, getHandlers, getIframeConfig, getWalletPubkey, handleIFrameMessage, initCoinflowProtection, invertRate, isBankingCurrency, isTypedCurrencyCents, isWithdrawCurrency, isZeroAuthSavedPaymentMethods, isZeroAuthVerifyCard, nftCartItem, paymentMethodLabels, recordFrontendError, setTokenExScriptTag };
2040
2290
  //# sourceMappingURL=coinflowlabs-angular.mjs.map