swell-js 3.22.0 → 3.22.2

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/swell.cjs.js CHANGED
@@ -5521,36 +5521,50 @@ function methods$8(request, options) {
5521
5521
  settings: null,
5522
5522
  requested: false,
5523
5523
  pendingRequests: [],
5524
- cacheClear: null,
5524
+ cacheClear: false,
5525
5525
 
5526
5526
  async requestStateChange(method, url, id, data) {
5527
5527
  return this.requestStateSync(async () => {
5528
5528
  const result = await request(method, url, id, data);
5529
+
5529
5530
  if (result && result.errors) {
5530
5531
  return result;
5531
5532
  }
5533
+
5532
5534
  this.state = result;
5533
5535
  return result;
5534
5536
  });
5535
5537
  },
5536
5538
 
5539
+ nextRequest() {
5540
+ if (this.pendingRequests.length <= 0) {
5541
+ this.requested = false;
5542
+ return;
5543
+ }
5544
+
5545
+ const { handler, resolve, reject } = this.pendingRequests.shift();
5546
+
5547
+ return Promise.resolve().then(handler).then(resolve, reject).finally(() => {
5548
+ this.nextRequest();
5549
+ });
5550
+ },
5551
+
5537
5552
  async requestStateSync(handler) {
5538
- if (this.state) {
5539
- return await handler();
5540
- } else if (this.requested) {
5541
- return new Promise((resolve) => {
5542
- this.pendingRequests.push({ handler, resolve });
5553
+ if (this.requested) {
5554
+ return new Promise((resolve, reject) => {
5555
+ this.pendingRequests.push({ handler, resolve, reject });
5543
5556
  });
5544
5557
  }
5545
5558
 
5546
5559
  this.requested = true;
5547
- const result = await handler();
5548
- this.requested = false;
5549
- while (this.pendingRequests.length > 0) {
5550
- const { handler, resolve } = this.pendingRequests.shift();
5551
- resolve(handler());
5560
+
5561
+ try {
5562
+ const result = await handler();
5563
+
5564
+ return result;
5565
+ } finally {
5566
+ this.nextRequest();
5552
5567
  }
5553
- return result;
5554
5568
  },
5555
5569
 
5556
5570
  get() {
@@ -5559,7 +5573,7 @@ function methods$8(request, options) {
5559
5573
  }
5560
5574
  let data;
5561
5575
  if (this.cacheClear) {
5562
- this.cacheClear = null;
5576
+ this.cacheClear = false;
5563
5577
  data = { $cache: false };
5564
5578
  }
5565
5579
  return this.requestStateChange('get', '/cart', undefined, data);
@@ -5653,7 +5667,7 @@ function methods$8(request, options) {
5653
5667
  },
5654
5668
 
5655
5669
  async submitOrder() {
5656
- const result = await request('post', '/cart/order');
5670
+ const result = await this.requestStateChange('post', '/cart/order');
5657
5671
  if (result.errors) {
5658
5672
  return result;
5659
5673
  }
@@ -6367,7 +6381,65 @@ async function loadScripts(scripts) {
6367
6381
  await new Promise((resolve) => setTimeout(resolve, 1000));
6368
6382
  }
6369
6383
 
6384
+ class PaymentMethodDisabledError extends Error {
6385
+ constructor(method) {
6386
+ const message = `${method} payments are disabled. See Payment settings in the Swell dashboard for details`;
6387
+ super(message);
6388
+ }
6389
+ }
6390
+
6391
+ class UnsupportedPaymentMethodError extends Error {
6392
+ constructor(method, gateway) {
6393
+ let message = `Unsupported payment method: ${method}`;
6394
+
6395
+ if (gateway) {
6396
+ message += ` (${gateway})`;
6397
+ }
6398
+
6399
+ super(message);
6400
+ }
6401
+ }
6402
+
6403
+ class UnableAuthenticatePaymentMethodError extends Error {
6404
+ constructor() {
6405
+ const message =
6406
+ 'We are unable to authenticate your payment method. Please choose a different payment method and try again';
6407
+ super(message);
6408
+ }
6409
+ }
6410
+
6411
+ class LibraryNotLoadedError extends Error {
6412
+ constructor(library) {
6413
+ const message = `${library} was not loaded`;
6414
+ super(message);
6415
+ }
6416
+ }
6417
+
6418
+ class MethodPropertyMissingError extends Error {
6419
+ constructor(method, property) {
6420
+ const message = `${method} ${property} is missing`;
6421
+ super(message);
6422
+ }
6423
+ }
6424
+
6425
+ class DomElementNotFoundError extends Error {
6426
+ constructor(elementId) {
6427
+ const message = `DOM element with '${elementId}' ID not found`;
6428
+ super(message);
6429
+ }
6430
+ }
6431
+
6432
+ class PaymentElementNotCreatedError extends Error {
6433
+ constructor(methodName) {
6434
+ const message = `The ${methodName} payment element was not created`;
6435
+ super(message);
6436
+ }
6437
+ }
6438
+
6370
6439
  class Payment {
6440
+ _element = null;
6441
+ _elementContainer = null;
6442
+
6371
6443
  constructor(request, options, params, method) {
6372
6444
  this.request = request;
6373
6445
  this.options = options;
@@ -6375,11 +6447,65 @@ class Payment {
6375
6447
  this.method = method;
6376
6448
  }
6377
6449
 
6450
+ /**
6451
+ * Returns a payment element.
6452
+ *
6453
+ * @returns {any}
6454
+ */
6455
+ get element() {
6456
+ if (!this._element) {
6457
+ throw new PaymentElementNotCreatedError(this.method.name);
6458
+ }
6459
+
6460
+ return this._element;
6461
+ }
6462
+
6463
+ /**
6464
+ * Sets a payment element.
6465
+ *
6466
+ * @param {any} element
6467
+ */
6468
+ set element(element) {
6469
+ this._element = element;
6470
+ }
6471
+
6472
+ /**
6473
+ * Returns a HTMLElement container of the payment element.
6474
+ *
6475
+ * @returns {HTMLElement}
6476
+ */
6477
+ get elementContainer() {
6478
+ return this._elementContainer;
6479
+ }
6480
+
6481
+ /**
6482
+ * Sets a HTMLElement container of the payment element.
6483
+ *
6484
+ * @param {string} elementId
6485
+ */
6486
+ setElementContainer(elementId) {
6487
+ this._elementContainer = document.getElementById(elementId);
6488
+
6489
+ if (!this.elementContainer) {
6490
+ throw new DomElementNotFoundError(elementId);
6491
+ }
6492
+ }
6493
+
6494
+ /**
6495
+ * Loads payment scripts.
6496
+ *
6497
+ * @param {Array<string | object>} scripts
6498
+ */
6378
6499
  async loadScripts(scripts) {
6379
6500
  await this._populateScriptsParams(scripts);
6380
6501
  await loadScripts(scripts);
6381
6502
  }
6382
6503
 
6504
+ /**
6505
+ * Returns a cart.
6506
+ *
6507
+ * @returns {object}
6508
+ */
6383
6509
  async getCart() {
6384
6510
  const cart = await methods$8(this.request, this.options).get();
6385
6511
 
@@ -6390,6 +6516,12 @@ class Payment {
6390
6516
  return this._adjustCart(cart);
6391
6517
  }
6392
6518
 
6519
+ /**
6520
+ * Updates a cart.
6521
+ *
6522
+ * @param {object} data
6523
+ * @returns {object}
6524
+ */
6393
6525
  async updateCart(data) {
6394
6526
  const updateData = cloneDeep(data);
6395
6527
 
@@ -6410,22 +6542,51 @@ class Payment {
6410
6542
  return this._adjustCart(updatedCart);
6411
6543
  }
6412
6544
 
6545
+ /**
6546
+ * Returns the store settings.
6547
+ *
6548
+ * @returns {object}
6549
+ */
6413
6550
  async getSettings() {
6414
6551
  return methods$2(this.request, this.options).get();
6415
6552
  }
6416
6553
 
6554
+ /**
6555
+ * Creates a payment intent.
6556
+ *
6557
+ * @param {object} data
6558
+ * @returns {object}
6559
+ */
6417
6560
  async createIntent(data) {
6418
6561
  return this._vaultRequest('post', '/intent', data);
6419
6562
  }
6420
6563
 
6564
+ /**
6565
+ * Updates a payment intent.
6566
+ *
6567
+ * @param {object} data
6568
+ * @returns {object}
6569
+ */
6421
6570
  async updateIntent(data) {
6422
6571
  return this._vaultRequest('put', '/intent', data);
6423
6572
  }
6424
6573
 
6574
+ /**
6575
+ * Authorizes a payment gateway.
6576
+ *
6577
+ * @param {object} data
6578
+ * @returns {object}
6579
+ */
6425
6580
  async authorizeGateway(data) {
6426
6581
  return this._vaultRequest('post', '/authorization', data);
6427
6582
  }
6428
6583
 
6584
+ /**
6585
+ * Calls the onSuccess handler.
6586
+ *
6587
+ * @param {object | undefined} data
6588
+ * @returns {any}
6589
+ */
6429
6590
  onSuccess(data) {
6430
6591
  const successHandler = get(this.params, 'onSuccess');
6431
6592
 
@@ -6434,6 +6595,11 @@ class Payment {
6434
6595
  }
6435
6596
  }
6436
6597
 
6598
+ /**
6599
+ * Calls the onCancel handler.
6600
+ *
6601
+ * @returns {any}
6602
+ */
6437
6603
  onCancel() {
6438
6604
  const cancelHandler = get(this.params, 'onCancel');
6439
6605
 
@@ -6442,6 +6608,12 @@ class Payment {
6442
6608
  }
6443
6609
  }
6444
6610
 
6611
+ /**
6612
+ * Calls the onError handler.
6613
+ *
6614
+ * @param {Error} error
6615
+ * @returns {any}
6616
+ */
6445
6617
  onError(error) {
6446
6618
  const errorHandler = get(this.params, 'onError');
6447
6619
 
@@ -6452,10 +6624,22 @@ class Payment {
6452
6624
  console.error(error.message);
6453
6625
  }
6454
6626
 
6627
+ /**
6628
+ * Adjusts cart data.
6629
+ *
6630
+ * @param {object} cart
6631
+ * @returns {object}
6632
+ */
6455
6633
  async _adjustCart(cart) {
6456
6634
  return this._ensureCartSettings(cart).then(toSnake);
6457
6635
  }
6458
6636
 
6637
+ /**
6638
+ * Sets the store settings to cart.
6639
+ *
6640
+ * @param {object} cart
6641
+ * @returns {object}
6642
+ */
6459
6643
  async _ensureCartSettings(cart) {
6460
6644
  if (cart.settings) {
6461
6645
  return cart;
@@ -6466,6 +6650,14 @@ class Payment {
6466
6650
  return { ...cart, settings: { ...settings.store } };
6467
6651
  }
6468
6652
 
6653
+ /**
6654
+ * Sends a Vault request.
6655
+ *
6656
+ * @param {string} method
6657
+ * @param {string} url
6658
+ * @param {object} data
6659
+ * @returns {object}
6660
+ */
6469
6661
  async _vaultRequest(method, url, data) {
6470
6662
  const response = await vaultRequest(method, url, data);
6471
6663
 
@@ -6481,12 +6673,22 @@ class Payment {
6481
6673
  return response;
6482
6674
  }
6483
6675
 
6676
+ /**
6677
+ * Sets values for payment scripts.
6678
+ *
6679
+ * @param {Array<string | object>} scripts
6680
+ */
6484
6681
  async _populateScriptsParams(scripts = []) {
6485
6682
  for (const script of scripts) {
6486
6683
  await this._populateScriptWithCartParams(script);
6487
6684
  }
6488
6685
  }
6489
6686
 
6687
+ /**
6688
+ * Sets the cart values to the payment script params.
6689
+ *
6690
+ * @param {string | object} script
6691
+ */
6490
6692
  async _populateScriptWithCartParams(script) {
6491
6693
  const cartParams = get(script, 'params.cart');
6492
6694
 
@@ -6613,6 +6815,7 @@ function setBancontactOwner(source, data) {
6613
6815
  function createElement(type, elements, params) {
6614
6816
  const elementParams = params[type] || params;
6615
6817
  const elementOptions = elementParams.options || {};
6818
+ const elementId = elementParams.elementId || `${type}-element`;
6616
6819
  const element = elements.create(type, elementOptions);
6617
6820
 
6618
6821
  elementParams.onChange && element.on('change', elementParams.onChange);
@@ -6622,7 +6825,7 @@ function createElement(type, elements, params) {
6622
6825
  elementParams.onEscape && element.on('escape', elementParams.onEscape);
6623
6826
  elementParams.onClick && element.on('click', elementParams.onClick);
6624
6827
 
6625
- element.mount(elementParams.elementId || `#${type}-element`);
6828
+ element.mount(`#${elementId}`);
6626
6829
 
6627
6830
  return element;
6628
6831
  }
@@ -6735,54 +6938,6 @@ function isStripeChargeableAmount(amount, currency) {
6735
6938
  return !minAmount || amount >= minAmount;
6736
6939
  }
6737
6940
 
6738
- class PaymentMethodDisabledError extends Error {
6739
- constructor(method) {
6740
- const message = `${method} payments are disabled. See Payment settings in the Swell dashboard for details`;
6741
- super(message);
6742
- }
6743
- }
6744
-
6745
- class UnsupportedPaymentMethodError extends Error {
6746
- constructor(method, gateway) {
6747
- let message = `Unsupported payment method: ${method}`;
6748
-
6749
- if (gateway) {
6750
- message += ` (${gateway})`;
6751
- }
6752
-
6753
- super(message);
6754
- }
6755
- }
6756
-
6757
- class UnableAuthenticatePaymentMethodError extends Error {
6758
- constructor() {
6759
- const message =
6760
- 'We are unable to authenticate your payment method. Please choose a different payment method and try again';
6761
- super(message);
6762
- }
6763
- }
6764
-
6765
- class LibraryNotLoadedError extends Error {
6766
- constructor(library) {
6767
- const message = `${library} was not loaded`;
6768
- super(message);
6769
- }
6770
- }
6771
-
6772
- class MethodPropertyMissingError extends Error {
6773
- constructor(method, property) {
6774
- const message = `${method} ${property} is missing`;
6775
- super(message);
6776
- }
6777
- }
6778
-
6779
- class DomElementNotFoundError extends Error {
6780
- constructor(elementId) {
6781
- const message = `DOM element with '${elementId}' ID not found`;
6782
- super(message);
6783
- }
6784
- }
6785
-
6786
6941
  class StripeCardPayment extends Payment {
6787
6942
  constructor(request, options, params, methods) {
6788
6943
  super(request, options, params, methods.card);
@@ -6819,6 +6974,8 @@ class StripeCardPayment extends Payment {
6819
6974
  }
6820
6975
 
6821
6976
  async createElements() {
6977
+ await this.loadScripts(this.scripts);
6978
+
6822
6979
  const elements = this.stripe.elements(this.params.config);
6823
6980
 
6824
6981
  if (this.params.separateElements) {
@@ -6835,6 +6992,8 @@ class StripeCardPayment extends Payment {
6835
6992
  throw new Error('Stripe payment element is not defined');
6836
6993
  }
6837
6994
 
6995
+ await this.loadScripts(this.scripts);
6996
+
6838
6997
  const cart = await this.getCart();
6839
6998
  const paymentMethod = await createPaymentMethod(
6840
6999
  this.stripe,
@@ -6889,6 +7048,8 @@ class StripeCardPayment extends Payment {
6889
7048
  throw new Error(intent.error.message);
6890
7049
  }
6891
7050
 
7051
+ await this.loadScripts(this.scripts);
7052
+
6892
7053
  return this._confirmCardPayment(intent);
6893
7054
  }
6894
7055
 
@@ -6985,6 +7146,8 @@ class StripeIDealPayment extends Payment {
6985
7146
  }
6986
7147
 
6987
7148
  async createElements() {
7149
+ await this.loadScripts(this.scripts);
7150
+
6988
7151
  const elements = this.stripe.elements(this.params.config);
6989
7152
 
6990
7153
  this.stripeElement = createElement('idealBank', elements, this.params);
@@ -6995,6 +7158,8 @@ class StripeIDealPayment extends Payment {
6995
7158
  throw new Error('Stripe payment element is not defined');
6996
7159
  }
6997
7160
 
7161
+ await this.loadScripts(this.scripts);
7162
+
6998
7163
  const cart = await this.getCart();
6999
7164
  const { paymentMethod, error: paymentMethodError } =
7000
7165
  await createIDealPaymentMethod(this.stripe, this.stripeElement, cart);
@@ -7090,6 +7255,8 @@ class StripeBancontactPayment extends Payment {
7090
7255
  }
7091
7256
 
7092
7257
  async tokenize() {
7258
+ await this.loadScripts(this.scripts);
7259
+
7093
7260
  const cart = await this.getCart();
7094
7261
  const { source, error: sourceError } = await createBancontactSource(
7095
7262
  this.stripe,
@@ -7152,6 +7319,9 @@ class StripeKlarnaPayment extends Payment {
7152
7319
  gateway: 'stripe',
7153
7320
  intent: getKlarnaIntentDetails(cart),
7154
7321
  });
7322
+
7323
+ await this.loadScripts(this.scripts);
7324
+
7155
7325
  const { error } = await this.stripe.confirmKlarnaPayment(
7156
7326
  intent.client_secret,
7157
7327
  getKlarnaConfirmationDetails(cart),
@@ -7292,10 +7462,19 @@ class StripeGooglePayment extends Payment {
7292
7462
  }
7293
7463
 
7294
7464
  async createElements() {
7465
+ const {
7466
+ elementId = 'googlepay-button',
7467
+ locale = 'en',
7468
+ style: { color = 'black', type = 'buy', sizeMode = 'fill' } = {},
7469
+ } = this.params;
7470
+
7295
7471
  if (!this.method.merchant_id) {
7296
7472
  throw new Error('Google merchant ID is not defined');
7297
7473
  }
7298
7474
 
7475
+ this.setElementContainer(elementId);
7476
+ await this.loadScripts(this.scripts);
7477
+
7299
7478
  const isReadyToPay = await this.googleClient.isReadyToPay({
7300
7479
  apiVersion: API_VERSION$1,
7301
7480
  apiVersionMinor: API_MINOR_VERSION$1,
@@ -7312,7 +7491,24 @@ class StripeGooglePayment extends Payment {
7312
7491
  const cart = await this.getCart();
7313
7492
  const paymentRequestData = this._createPaymentRequestData(cart);
7314
7493
 
7315
- this._renderButton(paymentRequestData);
7494
+ this.element = this.googleClient.createButton({
7495
+ buttonColor: color,
7496
+ buttonType: type,
7497
+ buttonSizeMode: sizeMode,
7498
+ buttonLocale: locale,
7499
+ onClick: this._onClick.bind(this, paymentRequestData),
7500
+ });
7501
+ }
7502
+
7503
+ mountElements() {
7504
+ const { classes = {} } = this.params;
7505
+ const container = this.elementContainer;
7506
+
7507
+ container.appendChild(this.element);
7508
+
7509
+ if (classes.base) {
7510
+ container.classList.add(classes.base);
7511
+ }
7316
7512
  }
7317
7513
 
7318
7514
  _createPaymentRequestData(cart) {
@@ -7344,35 +7540,6 @@ class StripeGooglePayment extends Payment {
7344
7540
  };
7345
7541
  }
7346
7542
 
7347
- _renderButton(paymentRequestData) {
7348
- const {
7349
- elementId = 'googlepay-button',
7350
- locale = 'en',
7351
- style: { color = 'black', type = 'buy', sizeMode = 'fill' } = {},
7352
- classes = {},
7353
- } = this.params;
7354
-
7355
- const container = document.getElementById(elementId);
7356
-
7357
- if (!container) {
7358
- throw new DomElementNotFoundError(elementId);
7359
- }
7360
-
7361
- if (classes.base) {
7362
- container.classList.add(classes.base);
7363
- }
7364
-
7365
- const button = this.googleClient.createButton({
7366
- buttonColor: color,
7367
- buttonType: type,
7368
- buttonSizeMode: sizeMode,
7369
- buttonLocale: locale,
7370
- onClick: this._onClick.bind(this, paymentRequestData),
7371
- });
7372
-
7373
- container.appendChild(button);
7374
- }
7375
-
7376
7543
  async _onClick(paymentRequestData) {
7377
7544
  try {
7378
7545
  const paymentData = await this.googleClient.loadPaymentData(
@@ -7472,6 +7639,14 @@ class StripeApplePayment extends Payment {
7472
7639
  }
7473
7640
 
7474
7641
  async createElements() {
7642
+ const {
7643
+ elementId = 'applepay-button',
7644
+ style: { type = 'default', theme = 'dark', height = '40px' } = {},
7645
+ classes = {},
7646
+ } = this.params;
7647
+
7648
+ this.setElementContainer(elementId);
7649
+ await this.loadScripts(this.scripts);
7475
7650
  await this._authorizeDomain();
7476
7651
 
7477
7652
  const cart = await this.getCart();
@@ -7484,7 +7659,21 @@ class StripeApplePayment extends Payment {
7484
7659
  );
7485
7660
  }
7486
7661
 
7487
- this._renderButton(paymentRequest);
7662
+ this.element = this.stripe.elements().create('paymentRequestButton', {
7663
+ paymentRequest,
7664
+ style: {
7665
+ paymentRequestButton: {
7666
+ type,
7667
+ theme,
7668
+ height,
7669
+ },
7670
+ },
7671
+ classes,
7672
+ });
7673
+ }
7674
+
7675
+ mountElements() {
7676
+ this.element.mount(`#${this.elementContainer.id}`);
7488
7677
  }
7489
7678
 
7490
7679
  async _authorizeDomain() {
@@ -7526,34 +7715,6 @@ class StripeApplePayment extends Payment {
7526
7715
  return paymentRequest;
7527
7716
  }
7528
7717
 
7529
- _renderButton(paymentRequest) {
7530
- const {
7531
- elementId = 'applepay-button',
7532
- style: { type = 'default', theme = 'dark', height = '40px' } = {},
7533
- classes = {},
7534
- } = this.params;
7535
-
7536
- const container = document.getElementById(elementId);
7537
-
7538
- if (!container) {
7539
- throw new DomElementNotFoundError(elementId);
7540
- }
7541
-
7542
- const button = this.stripe.elements().create('paymentRequestButton', {
7543
- paymentRequest,
7544
- style: {
7545
- paymentRequestButton: {
7546
- type,
7547
- theme,
7548
- height,
7549
- },
7550
- },
7551
- classes,
7552
- });
7553
-
7554
- button.mount(`#${elementId}`);
7555
- }
7556
-
7557
7718
  _getPaymentRequestData(cart) {
7558
7719
  const {
7559
7720
  currency,
@@ -7753,7 +7914,6 @@ class BraintreePaypalPayment extends Payment {
7753
7914
  }
7754
7915
 
7755
7916
  async createElements() {
7756
- const cart = await this.getCart();
7757
7917
  const {
7758
7918
  elementId = 'paypal-button',
7759
7919
  locale = 'en_US',
@@ -7765,13 +7925,9 @@ class BraintreePaypalPayment extends Payment {
7765
7925
  label = 'paypal',
7766
7926
  tagline = false,
7767
7927
  } = {},
7768
- classes = {},
7769
7928
  } = this.params;
7770
- const container = document.getElementById(elementId);
7771
7929
 
7772
- if (!container) {
7773
- throw new DomElementNotFoundError(elementId);
7774
- }
7930
+ this.setElementContainer(elementId);
7775
7931
 
7776
7932
  const authorization = await this.authorizeGateway({
7777
7933
  gateway: 'braintree',
@@ -7781,18 +7937,17 @@ class BraintreePaypalPayment extends Payment {
7781
7937
  throw new Error(authorization.error.message);
7782
7938
  }
7783
7939
 
7940
+ await this.loadScripts(this.scripts);
7941
+
7784
7942
  const braintreeClient = await this.braintree.client.create({
7785
7943
  authorization,
7786
7944
  });
7787
7945
  const paypalCheckout = await this.braintreePaypalCheckout.create({
7788
7946
  client: braintreeClient,
7789
7947
  });
7948
+ const cart = await this.getCart();
7790
7949
 
7791
- if (classes.base) {
7792
- container.classList.add(classes.base);
7793
- }
7794
-
7795
- const button = this.paypal.Buttons({
7950
+ this.element = this.paypal.Buttons({
7796
7951
  locale,
7797
7952
  style: {
7798
7953
  layout,
@@ -7812,8 +7967,17 @@ class BraintreePaypalPayment extends Payment {
7812
7967
  onCancel: this.onCancel.bind(this),
7813
7968
  onError: this.onError.bind(this),
7814
7969
  });
7970
+ }
7971
+
7972
+ mountElements() {
7973
+ const { classes = {} } = this.params;
7974
+ const container = this.elementContainer;
7975
+
7976
+ this.element.render(`#${container.id}`);
7815
7977
 
7816
- button.render(`#${elementId}`);
7978
+ if (classes.base) {
7979
+ container.classList.add(classes.base);
7980
+ }
7817
7981
  }
7818
7982
 
7819
7983
  _createBillingAgreement(paypalCheckout, cart) {
@@ -7951,10 +8115,19 @@ class BraintreeGooglePayment extends Payment {
7951
8115
  }
7952
8116
 
7953
8117
  async createElements() {
8118
+ const {
8119
+ elementId = 'googlepay-button',
8120
+ locale = 'en',
8121
+ style: { color = 'black', type = 'buy', sizeMode = 'fill' } = {},
8122
+ } = this.params;
8123
+
7954
8124
  if (!this.method.merchant_id) {
7955
8125
  throw new Error('Google merchant ID is not defined');
7956
8126
  }
7957
8127
 
8128
+ this.setElementContainer(elementId);
8129
+ await this.loadScripts(this.scripts);
8130
+
7958
8131
  const isReadyToPay = await this.googleClient.isReadyToPay({
7959
8132
  apiVersion: API_VERSION,
7960
8133
  apiVersionMinor: API_MINOR_VERSION,
@@ -7979,7 +8152,24 @@ class BraintreeGooglePayment extends Payment {
7979
8152
  const paymentDataRequest =
7980
8153
  googlePayment.createPaymentDataRequest(paymentRequestData);
7981
8154
 
7982
- this._renderButton(googlePayment, paymentDataRequest);
8155
+ this.element = this.googleClient.createButton({
8156
+ buttonColor: color,
8157
+ buttonType: type,
8158
+ buttonSizeMode: sizeMode,
8159
+ buttonLocale: locale,
8160
+ onClick: this._onClick.bind(this, googlePayment, paymentDataRequest),
8161
+ });
8162
+ }
8163
+
8164
+ mountElements() {
8165
+ const { classes = {} } = this.params;
8166
+ const container = this.elementContainer;
8167
+
8168
+ container.appendChild(this.element);
8169
+
8170
+ if (classes.base) {
8171
+ container.classList.add(classes.base);
8172
+ }
7983
8173
  }
7984
8174
 
7985
8175
  async _createBraintreeClient() {
@@ -8025,35 +8215,6 @@ class BraintreeGooglePayment extends Payment {
8025
8215
  };
8026
8216
  }
8027
8217
 
8028
- _renderButton(googlePayment, paymentDataRequest) {
8029
- const {
8030
- elementId = 'googlepay-button',
8031
- locale = 'en',
8032
- style: { color = 'black', type = 'buy', sizeMode = 'fill' } = {},
8033
- classes = {},
8034
- } = this.params;
8035
-
8036
- const container = document.getElementById(elementId);
8037
-
8038
- if (!container) {
8039
- throw new DomElementNotFoundError(elementId);
8040
- }
8041
-
8042
- if (classes.base) {
8043
- container.classList.add(classes.base);
8044
- }
8045
-
8046
- const button = this.googleClient.createButton({
8047
- buttonColor: color,
8048
- buttonType: type,
8049
- buttonSizeMode: sizeMode,
8050
- buttonLocale: locale,
8051
- onClick: this._onClick.bind(this, googlePayment, paymentDataRequest),
8052
- });
8053
-
8054
- container.appendChild(button);
8055
- }
8056
-
8057
8218
  async _onClick(googlePayment, paymentDataRequest) {
8058
8219
  try {
8059
8220
  const paymentData = await this.googleClient.loadPaymentData(
@@ -8147,6 +8308,11 @@ class BraintreeApplePayment extends Payment {
8147
8308
  }
8148
8309
 
8149
8310
  async createElements() {
8311
+ const { elementId = 'applepay-button' } = this.params;
8312
+
8313
+ this.setElementContainer(elementId);
8314
+ await this.loadScripts(this.scripts);
8315
+
8150
8316
  if (!this.ApplePaySession.canMakePayments()) {
8151
8317
  throw new Error(
8152
8318
  'This device is not capable of making Apple Pay payments',
@@ -8160,24 +8326,23 @@ class BraintreeApplePayment extends Payment {
8160
8326
  });
8161
8327
  const paymentRequest = await this._createPaymentRequest(cart, applePayment);
8162
8328
 
8163
- this._renderButton(applePayment, paymentRequest);
8329
+ this.element = this._createButton(applePayment, paymentRequest);
8164
8330
  }
8165
8331
 
8166
- _renderButton(applePayment, paymentRequest) {
8167
- const {
8168
- elementId = 'applepay-button',
8169
- style: { type = 'plain', theme = 'black', height = '40px' } = {},
8170
- classes = {},
8171
- } = this.params;
8172
- const container = document.getElementById(elementId);
8332
+ mountElements() {
8333
+ const { classes = {} } = this.params;
8334
+ const container = this.elementContainer;
8173
8335
 
8174
- if (!container) {
8175
- throw new DomElementNotFoundError(elementId);
8176
- }
8336
+ container.appendChild(this.element);
8177
8337
 
8178
8338
  if (classes.base) {
8179
8339
  container.classList.add(classes.base);
8180
8340
  }
8341
+ }
8342
+
8343
+ _createButton(applePayment, paymentRequest) {
8344
+ const { style: { type = 'plain', theme = 'black', height = '40px' } = {} } =
8345
+ this.params;
8181
8346
 
8182
8347
  const button = document.createElement('div');
8183
8348
 
@@ -8191,7 +8356,7 @@ class BraintreeApplePayment extends Payment {
8191
8356
  this._createPaymentSession.bind(this, applePayment, paymentRequest),
8192
8357
  );
8193
8358
 
8194
- container.appendChild(button);
8359
+ return button;
8195
8360
  }
8196
8361
 
8197
8362
  async _createBraintreeClient() {
@@ -8654,21 +8819,6 @@ class PaypalDirectPayment extends Payment {
8654
8819
  }
8655
8820
 
8656
8821
  async createElements() {
8657
- const cart = await this.getCart();
8658
- const hasSubscriptionProduct = Boolean(cart.subscription_delivery);
8659
-
8660
- if (hasSubscriptionProduct && !this.method.ppcp) {
8661
- throw new Error(
8662
- 'Subscriptions are only supported by PayPal Commerce Platform. See Payment settings in the Swell dashboard to enable PayPal Commerce Platform',
8663
- );
8664
- }
8665
-
8666
- if (!(cart.capture_total > 0)) {
8667
- throw new Error(
8668
- 'Invalid PayPal button amount. Value should be greater than zero.',
8669
- );
8670
- }
8671
-
8672
8822
  const {
8673
8823
  elementId = 'paypal-button',
8674
8824
  locale = 'en_US',
@@ -8680,15 +8830,16 @@ class PaypalDirectPayment extends Payment {
8680
8830
  label = 'paypal',
8681
8831
  tagline = false,
8682
8832
  } = {},
8683
- classes = {},
8684
8833
  } = this.params;
8685
- const container = document.getElementById(elementId);
8686
8834
 
8687
- if (!container) {
8688
- throw new DomElementNotFoundError(elementId);
8689
- }
8835
+ this.setElementContainer(elementId);
8836
+
8837
+ const cart = await this.getCart();
8838
+
8839
+ this._validateCart(cart);
8840
+ await this.loadScripts(this.scripts);
8690
8841
 
8691
- const button = this.paypal.Buttons({
8842
+ this.element = this.paypal.Buttons({
8692
8843
  locale,
8693
8844
  style: {
8694
8845
  layout,
@@ -8703,14 +8854,35 @@ class PaypalDirectPayment extends Payment {
8703
8854
  onApprove: this._onApprove.bind(this),
8704
8855
  onError: this.onError.bind(this),
8705
8856
  });
8857
+ }
8858
+
8859
+ mountElements() {
8860
+ const { classes = {} } = this.params;
8861
+ const container = this.elementContainer;
8706
8862
 
8707
- button.render(`#${elementId}`);
8863
+ this.element.render(`#${container.id}`);
8708
8864
 
8709
8865
  if (classes.base) {
8710
8866
  container.classList.add(classes.base);
8711
8867
  }
8712
8868
  }
8713
8869
 
8870
+ _validateCart(cart) {
8871
+ const hasSubscriptionProduct = Boolean(cart.subscription_delivery);
8872
+
8873
+ if (hasSubscriptionProduct && !this.method.ppcp) {
8874
+ throw new Error(
8875
+ 'Subscriptions are only supported by PayPal Commerce Platform. See Payment settings in the Swell dashboard to enable PayPal Commerce Platform',
8876
+ );
8877
+ }
8878
+
8879
+ if (!(cart.capture_total > 0)) {
8880
+ throw new Error(
8881
+ 'Invalid PayPal button amount. Value should be greater than zero.',
8882
+ );
8883
+ }
8884
+ }
8885
+
8714
8886
  async _onCreateOrder(cart, data, actions) {
8715
8887
  const { require: { shipping: requireShipping = true } = {} } = this.params;
8716
8888
  const { capture_total, currency, subscription_delivery } = cart;
@@ -8923,31 +9095,46 @@ class AmazonDirectPayment extends Payment {
8923
9095
  }
8924
9096
 
8925
9097
  async createElements() {
9098
+ const {
9099
+ elementId = 'amazonpay-button',
9100
+ locale = 'en_US',
9101
+ placement = 'Checkout',
9102
+ style: { color = 'Gold' } = {},
9103
+ require: { shipping: requireShipping } = {},
9104
+ } = this.params;
9105
+
9106
+ this.setElementContainer(elementId);
9107
+
8926
9108
  const cart = await this.getCart();
8927
- const returnUrl = this.returnUrl;
8928
- const isSubscription = Boolean(cart.subscription_delivery);
8929
- const session = await this.authorizeGateway({
8930
- gateway: 'amazon',
8931
- params: {
8932
- chargePermissionType: isSubscription ? 'Recurring' : 'OneTime',
8933
- ...(isSubscription
8934
- ? {
8935
- recurringMetadata: {
8936
- frequency: {
8937
- unit: 'Variable',
8938
- value: '0',
8939
- },
8940
- },
8941
- }
8942
- : {}),
8943
- webCheckoutDetails: {
8944
- checkoutReviewReturnUrl: `${returnUrl}&redirect_status=succeeded`,
8945
- checkoutCancelUrl: `${returnUrl}&redirect_status=canceled`,
8946
- },
9109
+ const session = await this._createSession(cart);
9110
+
9111
+ await this.loadScripts(this.scripts);
9112
+
9113
+ this.element = {
9114
+ ledgerCurrency: cart.currency,
9115
+ checkoutLanguage: locale,
9116
+ productType: Boolean(requireShipping) ? 'PayAndShip' : 'PayOnly',
9117
+ buttonColor: color,
9118
+ placement,
9119
+ merchantId: this.merchantId,
9120
+ publicKeyId: this.publicKeyId,
9121
+ createCheckoutSessionConfig: {
9122
+ payloadJSON: session.payload,
9123
+ signature: session.signature,
8947
9124
  },
8948
- });
9125
+ };
9126
+ }
9127
+
9128
+ mountElements() {
9129
+ const { classes = {} } = this.params;
9130
+ const container = this.elementContainer;
9131
+ const amazon = this.amazon;
9132
+
9133
+ amazon.Pay.renderButton(`#${container.id}`, this.element);
8949
9134
 
8950
- this._renderButton(cart, session);
9135
+ if (classes.base) {
9136
+ container.classList.add(classes.base);
9137
+ }
8951
9138
  }
8952
9139
 
8953
9140
  async tokenize() {
@@ -9003,43 +9190,30 @@ class AmazonDirectPayment extends Payment {
9003
9190
  }
9004
9191
  }
9005
9192
 
9006
- _renderButton(cart, session) {
9007
- const amazon = this.amazon;
9008
- const merchantId = this.merchantId;
9009
- const publicKeyId = this.publicKeyId;
9010
- const { payload: payloadJSON, signature } = session;
9011
- const {
9012
- elementId = 'amazonpay-button',
9013
- locale = 'en_US',
9014
- placement = 'Checkout',
9015
- style: { color = 'Gold' } = {},
9016
- require: { shipping: requireShipping } = {},
9017
- classes = {},
9018
- } = this.params;
9019
-
9020
- const container = document.getElementById(elementId);
9021
-
9022
- if (!container) {
9023
- throw new DomElementNotFoundError(elementId);
9024
- }
9193
+ _createSession(cart) {
9194
+ const returnUrl = this.returnUrl;
9195
+ const isSubscription = Boolean(cart.subscription_delivery);
9025
9196
 
9026
- amazon.Pay.renderButton(`#${elementId}`, {
9027
- ledgerCurrency: cart.currency,
9028
- checkoutLanguage: locale,
9029
- productType: Boolean(requireShipping) ? 'PayAndShip' : 'PayOnly',
9030
- buttonColor: color,
9031
- placement,
9032
- merchantId,
9033
- publicKeyId,
9034
- createCheckoutSessionConfig: {
9035
- payloadJSON,
9036
- signature,
9197
+ return this.authorizeGateway({
9198
+ gateway: 'amazon',
9199
+ params: {
9200
+ chargePermissionType: isSubscription ? 'Recurring' : 'OneTime',
9201
+ ...(isSubscription
9202
+ ? {
9203
+ recurringMetadata: {
9204
+ frequency: {
9205
+ unit: 'Variable',
9206
+ value: '0',
9207
+ },
9208
+ },
9209
+ }
9210
+ : {}),
9211
+ webCheckoutDetails: {
9212
+ checkoutReviewReturnUrl: `${returnUrl}&redirect_status=succeeded`,
9213
+ checkoutCancelUrl: `${returnUrl}&redirect_status=canceled`,
9214
+ },
9037
9215
  },
9038
9216
  });
9039
-
9040
- if (classes.base) {
9041
- container.classList.add(classes.base);
9042
- }
9043
9217
  }
9044
9218
 
9045
9219
  async _handleSuccessfulRedirect(queryParams) {
@@ -9060,6 +9234,68 @@ class AmazonDirectPayment extends Payment {
9060
9234
  }
9061
9235
  }
9062
9236
 
9237
+ function adjustConfig(params) {
9238
+ if (!params.config) {
9239
+ return;
9240
+ }
9241
+
9242
+ if (params.card) {
9243
+ console.warn('Please move the "config" field to the "card.config"');
9244
+
9245
+ params.card.config = params.config;
9246
+ }
9247
+
9248
+ if (params.ideal) {
9249
+ console.warn('Please move the "config" field to the "ideal.config"');
9250
+
9251
+ params.ideal.config = params.config;
9252
+ }
9253
+
9254
+ delete params.config;
9255
+ }
9256
+
9257
+ function adjustElementId(methodParams) {
9258
+ if (methodParams.cardNumber) {
9259
+ adjustElementId(methodParams.cardNumber);
9260
+ }
9261
+
9262
+ if (methodParams.cardExpiry) {
9263
+ adjustElementId(methodParams.cardExpiry);
9264
+ }
9265
+
9266
+ if (methodParams.cardCvc) {
9267
+ adjustElementId(methodParams.cardCvc);
9268
+ }
9269
+
9270
+ if (!methodParams.elementId) {
9271
+ return;
9272
+ }
9273
+
9274
+ if (methodParams.elementId.startsWith('#')) {
9275
+ console.warn(
9276
+ `Please remove the "#" sign from the "${methodParams.elementId}" element ID`,
9277
+ );
9278
+
9279
+ methodParams.elementId = methodParams.elementId.substring(1);
9280
+ }
9281
+ }
9282
+
9283
+ function adjustParams(_params) {
9284
+ const params = { ..._params };
9285
+
9286
+ adjustConfig(params);
9287
+
9288
+ return params;
9289
+ }
9290
+
9291
+ function adjustMethodParams(_methodParams) {
9292
+ const methodParams = { ..._methodParams };
9293
+
9294
+ adjustElementId(methodParams);
9295
+
9296
+ return methodParams;
9297
+ }
9298
+
9063
9299
  class PaymentController {
9064
9300
  constructor(request, options) {
9065
9301
  this.request = request;
@@ -9087,7 +9323,12 @@ class PaymentController {
9087
9323
  throw new Error('Payment element parameters are not provided');
9088
9324
  }
9089
9325
 
9090
- this._performPaymentAction('createElements');
9326
+ const paymentInstances = await this._createPaymentInstances();
9327
+
9328
+ await this._performPaymentAction(paymentInstances, 'createElements').then(
9329
+ (paymentInstances) =>
9330
+ this._performPaymentAction(paymentInstances, 'mountElements'),
9331
+ );
9091
9332
  }
9092
9333
 
9093
9334
  async tokenize(params = this.params) {
@@ -9097,7 +9338,9 @@ class PaymentController {
9097
9338
  throw new Error('Tokenization parameters are not provided');
9098
9339
  }
9099
9340
 
9100
- this._performPaymentAction('tokenize');
9341
+ const paymentInstances = await this._createPaymentInstances();
9342
+
9343
+ await this._performPaymentAction(paymentInstances, 'tokenize');
9101
9344
  }
9102
9345
 
9103
9346
  async handleRedirect(params = this.params) {
@@ -9114,7 +9357,14 @@ class PaymentController {
9114
9357
  }
9115
9358
 
9116
9359
  removeUrlParams();
9117
- this._performPaymentAction('handleRedirect', queryParams);
9360
+
9361
+ const paymentInstances = await this._createPaymentInstances();
9362
+
9363
+ await this._performPaymentAction(
9364
+ paymentInstances,
9365
+ 'handleRedirect',
9366
+ queryParams,
9367
+ );
9118
9368
  }
9119
9369
 
9120
9370
  async authenticate(id) {
@@ -9165,28 +9415,6 @@ class PaymentController {
9165
9415
  return this._vaultRequest('post', '/authorization', data);
9166
9416
  }
9167
9417
 
9168
- _normalizeParams() {
9169
- if (!this.params) {
9170
- return;
9171
- }
9172
-
9173
- if (this.params.config) {
9174
- console.warn(
9175
- 'Please move the "config" field to the payment method parameters ("card.config" or/and "ideal.config").',
9176
- );
9177
-
9178
- if (this.params.card) {
9179
- this.params.card.config = this.params.config;
9180
- }
9181
-
9182
- if (this.params.ideal) {
9183
- this.params.ideal.config = this.params.config;
9184
- }
9185
-
9186
- delete this.params.config;
9187
- }
9188
- }
9189
-
9190
9418
  async _getPaymentMethods() {
9191
9419
  const paymentMethods = await methods$2(
9192
9420
  this.request,
@@ -9219,16 +9447,17 @@ class PaymentController {
9219
9447
  return response;
9220
9448
  }
9221
9449
 
9222
- async _performPaymentAction(action, ...args) {
9450
+ async _createPaymentInstances() {
9223
9451
  const paymentMethods = await this._getPaymentMethods();
9452
+ const params = adjustParams(this.params);
9224
9453
 
9225
- this._normalizeParams();
9226
-
9227
- Object.entries(this.params).forEach(([method, params]) => {
9454
+ return Object.entries(params).reduce((acc, [method, params]) => {
9228
9455
  const methodSettings = paymentMethods[method];
9229
9456
 
9230
9457
  if (!methodSettings) {
9231
- return console.error(new PaymentMethodDisabledError(method));
9458
+ console.error(new PaymentMethodDisabledError(method));
9459
+
9460
+ return acc;
9232
9461
  }
9233
9462
 
9234
9463
  const PaymentClass = this._getPaymentClass(
@@ -9237,27 +9466,51 @@ class PaymentController {
9237
9466
  );
9238
9467
 
9239
9468
  if (!PaymentClass) {
9240
- return console.error(
9469
+ console.error(
9241
9470
  new UnsupportedPaymentMethodError(method, methodSettings.gateway),
9242
9471
  );
9472
+
9473
+ return acc;
9243
9474
  }
9244
9475
 
9476
+ const methodParams = adjustMethodParams(params);
9477
+
9245
9478
  try {
9246
- const payment = new PaymentClass(
9479
+ const paymentInstance = new PaymentClass(
9247
9480
  this.request,
9248
9481
  this.options,
9249
- params,
9482
+ methodParams,
9250
9483
  paymentMethods,
9251
9484
  );
9252
9485
 
9253
- payment
9254
- .loadScripts(payment.scripts)
9255
- .then(payment[action].bind(payment, ...args))
9256
- .catch(payment.onError.bind(payment));
9486
+ acc.push(paymentInstance);
9257
9487
  } catch (error) {
9258
- return console.error(error.message);
9488
+ console.error(error);
9259
9489
  }
9260
- });
9490
+
9491
+ return acc;
9492
+ }, []);
9493
+ }
9494
+
9495
+ async _performPaymentAction(paymentInstances, action, ...args) {
9496
+ const nextPaymentInstances = [];
9497
+
9498
+ for (const paymentInstance of paymentInstances) {
9499
+ try {
9500
+ const paymentAction = paymentInstance[action];
9501
+
9502
+ if (paymentAction) {
9503
+ await paymentAction.call(paymentInstance, ...args);
9504
+ nextPaymentInstances.push(paymentInstance);
9505
+ }
9506
+ } catch (error) {
9507
+ const onPaymentError = paymentInstance.onError.bind(paymentInstance);
9508
+
9509
+ onPaymentError(error);
9510
+ }
9511
+ }
9512
+
9513
+ return nextPaymentInstances;
9261
9514
  }
9262
9515
 
9263
9516
  _getPaymentClass(method, gateway) {
@@ -9614,7 +9867,7 @@ const options = {
9614
9867
  };
9615
9868
 
9616
9869
  const api = {
9617
- version: '3.22.0',
9870
+ version: '3.22.2',
9618
9871
  options,
9619
9872
  request,
9620
9873