From 34fa0176639e6f88f4dc666781ac16c6f11db408 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Mon, 18 Dec 2023 18:33:59 +0100 Subject: [PATCH 01/54] PAYSHIP-2609 no capture for canceled order --- src/PayPal/Order/EventSubscriber/PayPalOrderEventSubscriber.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PayPal/Order/EventSubscriber/PayPalOrderEventSubscriber.php b/src/PayPal/Order/EventSubscriber/PayPalOrderEventSubscriber.php index f27f134e7..5cf29b9a9 100644 --- a/src/PayPal/Order/EventSubscriber/PayPalOrderEventSubscriber.php +++ b/src/PayPal/Order/EventSubscriber/PayPalOrderEventSubscriber.php @@ -214,7 +214,7 @@ public function capturePayPalOrder(PayPalOrderApprovedEvent $event) return; } - if ($psCheckoutCart->getPaypalStatus() === PayPalOrderStatus::COMPLETED) { + if (in_array($psCheckoutCart->getPaypalStatus(), [PayPalOrderStatus::COMPLETED, PayPalOrderStatus::CANCELED], true)) { return; } From 845e5541abbdabae4f110266410b11bdcf2c5426 Mon Sep 17 00:00:00 2001 From: Laurynas Date: Fri, 22 Dec 2023 17:48:16 +0200 Subject: [PATCH 02/54] Initial commit --- .../common/card-fields.component.js | 211 ++++++++++++++++++ .../common/payment-option.component.js | 30 ++- _dev/js/front/src/service/paypal.service.js | 191 +++++++++++++++- .../extra/types/paypal-sdk.typedef.doc.js | 1 + .../PayPalSdkLink/PayPalSdkLinkBuilder.php | 2 + views/css/payments.css | 2 +- views/css/payments16.css | 2 +- views/templates/hook/displayPayment.tpl | 7 +- views/templates/hook/paymentOptions.tpl | 7 +- 9 files changed, 442 insertions(+), 11 deletions(-) create mode 100644 _dev/js/front/src/components/common/card-fields.component.js diff --git a/_dev/js/front/src/components/common/card-fields.component.js b/_dev/js/front/src/components/common/card-fields.component.js new file mode 100644 index 000000000..154094982 --- /dev/null +++ b/_dev/js/front/src/components/common/card-fields.component.js @@ -0,0 +1,211 @@ +/** + * Copyright since 2007 PrestaShop SA and Contributors + * PrestaShop is an International Registered Trademark & Property of PrestaShop SA + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License 3.0 (AFL-3.0) + * that is bundled with this package in the file LICENSE.md. + * It is also available through the world-wide-web at this URL: + * https://opensource.org/licenses/AFL-3.0 + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@prestashop.com so we can send you a copy immediately. + * + * @author PrestaShop SA + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) + */ +import { BaseComponent } from '../../core/dependency-injection/base.component'; + +export class CardFieldsComponent extends BaseComponent { + static Inject = { + config: 'PsCheckoutConfig', + payPalService: 'PayPalService', + psCheckoutApi: 'PsCheckoutApi', + psCheckoutService: 'PsCheckoutService' + }; + + created() { + this.data.name = this.props.fundingSource.name; + this.data.validity = false; + + this.data.HTMLElement = this.props.HTMLElement; + this.data.HTMLElementBaseButton = this.getBaseButton(); + this.data.HTMLElementButton = null; + this.data.HTMLElementButtonWrapper = this.getButtonWrapper(); + this.data.HTMLElementCardHolderName = this.getCardHolderName(); + this.data.HTMLElementCardNumber = this.getCardNumber(); + this.data.HTMLElementCardCVV = this.getCardCVV(); + this.data.HTMLElementCardExpirationDate = this.getCardExpirationDate(); + this.data.HTMLElementSection = this.getSection(); + } + + getBaseButton() { + const buttonSelector = `#payment-confirmation button`; + return document.querySelector(buttonSelector); + } + + getButtonWrapper() { + const buttonWrapper = `.ps_checkout-button[data-funding-source=${this.data.name}]`; + return document.querySelector(buttonWrapper); + } + + getCardHolderName() { + const cardHolderNameId = '#ps_checkout-hosted-fields-card-holder-name'; + return document.getElementById(cardHolderNameId); + } + getCardNumber() { + const cardNumberId = '#ps_checkout-hosted-fields-card-number'; + return document.getElementById(cardNumberId); + } + + getCardCVV() { + const cardCVVId = '#ps_checkout-hosted-fields-card-cvv'; + return document.getElementById(cardCVVId); + } + + getCardExpirationDate() { + const cardExpirationDateId = + '#ps_checkout-hosted-fields-card-expiration-date'; + return document.getElementById(cardExpirationDateId); + } + + getSection() { + const sectionSelector = `.js-payment-ps_checkout-${this.data.name}`; + return document.querySelector(sectionSelector); + } + + getContingencies() { + switch (this.config.cardFieldsContingencies) { + case '3D_SECURE': + case 'SCA_ALWAYS': + return ['SCA_ALWAYS']; + case 'NONE': + return undefined; + default: + return ['SCA_WHEN_REQUIRED']; + } + } + + isSubmittable() { + return this.data.conditions + ? this.data.conditions.isChecked() && this.data.validity + : this.data.validity; + } + + renderPayPalCardFields() { + this.payPalService + .getCardFields( + { + name: '#ps_checkout-hosted-fields-card-holder-name', + number: '#ps_checkout-hosted-fields-card-number', + cvv: '#ps_checkout-hosted-fields-card-cvv', + expirationDate: '#ps_checkout-hosted-fields-card-expiration-date' + }, + { + createOrder: async (data) => + this.psCheckoutApi + .postCreateOrder({ + ...data, + fundingSource: this.data.name, + isCardFields: true, + // vault: storeCardInVault + }) + .catch(error => { + this.data.notification.showError( + `${error.message} ${error.name}` + ); + }) + } + ) + .then(cardFields => { + if (this.data.HTMLElement !== null) { + cardFields.on('validityChange', event => { + this.data.validity = + Object.keys(event.fields) + .map(name => event.fields[name]) + .map(({ isValid }) => { + return isValid; + }) + .filter(validity => validity === false).length === 0; + + this.data.HTMLElementSection.classList.toggle( + 'disabled', + !this.isSubmittable() + ); + + this.isSubmittable() + ? this.data.HTMLElementButton.removeAttribute('disabled') + : this.data.HTMLElementButton.setAttribute('disabled', ''); + }); + + this.data.HTMLElementButton.addEventListener('click', event => { + event.preventDefault(); + this.data.loader.show(); + // this.data.HTMLElementButton.classList.toggle('disabled', true); + this.data.HTMLElementButton.setAttribute('disabled', ''); + + cardFields + .submit({ + contingencies: this.getContingencies() + }) + .then(payload => { + const data = payload; + + // Backend requirement + data.orderID = data.orderId; + delete data.orderId; + + return this.psCheckoutApi.postValidateOrder({ + ...data, + fundingSource: this.data.name, + isHostedFields: true + }); + }) + .catch(error => { + let message = error.message || ''; + + if (!message) { + message = `Unknown error, code: ${error.code || 'none'}, description: ${error.description || 'none'}`; + } + + this.data.loader.hide(); + this.data.notification.showError(message); + this.data.HTMLElementButton.removeAttribute('disabled'); + }); + }); + } + }); + } + + renderButton() { + this.data.HTMLElementButton = this.data.HTMLElementBaseButton.cloneNode( + true + ); + + this.data.HTMLElementButtonWrapper.append(this.data.HTMLElementButton); + this.data.HTMLElementButton.classList.remove('disabled'); + this.data.HTMLElementButton.style.display = ''; + this.data.HTMLElementButton.disabled = !this.isSubmittable(); + + this.data.conditions && + this.data.conditions.onChange(() => { + // In some PS versions, the handler fails to disable the button because of the timing. + setTimeout(() => { + this.data.HTMLElementButton.disabled = !this.isSubmittable(); + }, 0); + }); + } + + render() { + this.data.conditions = this.app.root.children.conditionsCheckbox; + this.data.notification = this.app.root.children.notification; + this.data.loader = this.app.root.children.loader; + + this.renderButton(); + this.renderPayPalCardFields(); + + return this; + } +} diff --git a/_dev/js/front/src/components/common/payment-option.component.js b/_dev/js/front/src/components/common/payment-option.component.js index c207c5c51..78db6351b 100644 --- a/_dev/js/front/src/components/common/payment-option.component.js +++ b/_dev/js/front/src/components/common/payment-option.component.js @@ -22,6 +22,7 @@ import { HostedFieldsComponent } from './hosted-fields.component'; import { MarkComponent } from './marker.component'; import { SmartButtonComponent } from './smart-button.component'; import { PaymentFieldsComponent } from "./payment-fields.component"; +import {CardFieldsComponent} from "./card-fields.component"; /** * @typedef PaymentOptionComponentProps @@ -48,6 +49,7 @@ export class PaymentOptionComponent extends BaseComponent { this.data.HTMLElementMark = this.props.HTMLElementMark || null; this.data.HTMLElementHostedFields = this.getHostedFields(); + this.data.HTMLElementCardFields = this.getCardFields(); this.data.HTMLElementSmartButton = this.getSmartButton(); this.data.HTMLElementPaymentFields = this.getPaymentFields(); } @@ -67,6 +69,16 @@ export class PaymentOptionComponent extends BaseComponent { ); } + getCardFields() { + const cardFieldsFormId = 'ps_checkout-hosted-fields-form'; + + return ( + this.data.name === 'card' + && this.config.hostedFieldsEnabled + && document.getElementById(cardFieldsFormId) + ); + } + getPaymentFields() { const container = `pay-with-${this.data.HTMLElement.id}-form`; const APM = ['bancontact', 'blik', 'eps', 'giropay', 'ideal', 'mybank', 'p24', 'sofort']; @@ -165,7 +177,17 @@ export class PaymentOptionComponent extends BaseComponent { this.data.HTMLElementHostedFields.style.display = 'none'; } - if (this.data.HTMLElementHostedFields && isHostedFieldsEligible) { + let isCardFieldsEligible = this.payPalService.isCardFieldsEligible(); + if (this.data.HTMLElementCardFields && !isCardFieldsEligible) { + this.data.HTMLElementCardFields.style.display = 'none'; + } + + if (this.data.HTMLElementCardFields && isCardFieldsEligible) { + this.children.cardFields = new CardFieldsComponent(this.app, { + fundingSource: this.props.fundingSource, + HTMLElement: this.data.HTMLElementCardFields + }).render(); + } else if (this.data.HTMLElementHostedFields && isHostedFieldsEligible) { this.children.hostedFields = new HostedFieldsComponent(this.app, { fundingSource: this.props.fundingSource, @@ -185,9 +207,11 @@ export class PaymentOptionComponent extends BaseComponent { fundingSource: this.data.name, HTMLElement: this.data.HTMLElement, HTMLElementContainer: this.data.HTMLElementContainer, - HTMLElementBinary: this.data.HTMLElementHostedFields && isHostedFieldsEligible + HTMLElementBinary: this.data.HTMLElementCardFields && isCardFieldsEligible ? + this.children.cardFields.data.HTMLElementButton.parentElement : + (this.data.HTMLElementHostedFields && isHostedFieldsEligible ? this.children.hostedFields.data.HTMLElementButton.parentElement - : this.data.HTMLElementSmartButton + : this.data.HTMLElementSmartButton) } }) ); diff --git a/_dev/js/front/src/service/paypal.service.js b/_dev/js/front/src/service/paypal.service.js index 8ec33bc13..4786c8d51 100644 --- a/_dev/js/front/src/service/paypal.service.js +++ b/_dev/js/front/src/service/paypal.service.js @@ -244,7 +244,7 @@ export class PayPalService extends BaseClass { // Change card bg depending on card type if (event.cards.length === 1) { - document.querySelector('.defautl-credit-card').style.display = + document.querySelector('.default-credit-card').style.display = 'none'; const cardImage = document.getElementById('card-image'); @@ -262,7 +262,7 @@ export class PayPalService extends BaseClass { }); } } else { - document.querySelector('.defautl-credit-card').style.display = + document.querySelector('.default-credit-card').style.display = 'block'; const cardImage = document.getElementById('card-image'); cardImage.className = ''; @@ -279,6 +279,184 @@ export class PayPalService extends BaseClass { }); } + /** + * @param {*} fieldSelectors + * @param {string} fieldSelectors.number + * @param {string} fieldSelectors.cvv + * @param {string} fieldSelectors.expirationDate + * @param {PaypalHostedFieldsEvents} events + * @returns {*} + */ + getCardFields(fieldSelectors, events) { + const style = { + ...{ + input: { + 'font-size': '17px', + 'font-family': 'helvetica, tahoma, calibri, sans-serif', + color: '#3a3a3a' + }, + ':focus': { + color: 'black' + } + }, + ...(this.configPayPal.hostedFieldsCustomization || {}), + ...(window.ps_checkout.hostedFieldsCustomization || {}) + }; + + return this.sdk.CardFields(events).render({ + styles: style, + fields: { + name: { + selector: fieldSelectors.name, + placeholder: this.$('paypal.hosted-fields.placeholder.card-number') + }, + number: { + selector: fieldSelectors.number, + placeholder: this.$('paypal.hosted-fields.placeholder.card-number') + }, + cvv: { + selector: fieldSelectors.cvv, + placeholder: this.$('paypal.hosted-fields.placeholder.cvv') + }, + expirationDate: { + selector: fieldSelectors.expirationDate, + placeholder: this.$( + 'paypal.hosted-fields.placeholder.expiration-date' + ) + } + }, + ...events + }) + .then(cardFields => { + const nameField = document.querySelector(fieldSelectors.name); + const numberField = document.querySelector(fieldSelectors.number); + const cvvField = document.querySelector(fieldSelectors.cvv); + const expirationDateField = document.querySelector( + fieldSelectors.expirationDate + ); + + const cardNameField = cardFields.NameField(); + const cardNumberField = cardFields.NumberField(); + const cardExpiryField = cardFields.ExpiryField(); + const cardCvvField = cardFields.CVVField(); + + try { + cardNameField.render(nameField); + cardNumberField.render(numberField); + cardCvvField.render(cvvField); + cardExpiryField.render(expirationDateField); + } catch (e) { + return console.error("Failed to render CardFields", e); + } + + const cardHolderNameLabel = document.querySelector( + `label[for="${c.id}"]` + ); + const numberLabel = document.querySelector( + `label[for="${numberField.id}"]` + ); + const cvvLabel = document.querySelector(`label[for="${cvvField.id}"]`); + const expirationDateLabel = document.querySelector( + `label[for="${expirationDateField.id}"]` + ); + + numberLabel.innerHTML = this.$( + 'paypal.hosted-fields.label.card-number' + ); + cvvLabel.innerHTML = this.$('paypal.hosted-fields.label.cvv'); + expirationDateLabel.innerHTML = this.$( + 'paypal.hosted-fields.label.expiration-date' + ); + + return cardFields; + }) + .then(cardFields => { + cardFields.on('focus', event => { + window.ps_checkout.events.dispatchEvent( + new CustomEvent('hostedFieldsFocus', { + detail: { ps_checkout: window.ps_checkout, event: event } + }) + ); + }); + cardFields.on('blur', event => { + window.ps_checkout.events.dispatchEvent( + new CustomEvent('hostedFieldsBlur', { + detail: { ps_checkout: window.ps_checkout, event: event } + }) + ); + }); + cardFields.on('empty', event => { + window.ps_checkout.events.dispatchEvent( + new CustomEvent('hostedFieldsEmpty', { + detail: { ps_checkout: window.ps_checkout, event: event } + }) + ); + }); + cardFields.on('notEmpty', event => { + window.ps_checkout.events.dispatchEvent( + new CustomEvent('hostedFieldsNotEmpty', { + detail: { ps_checkout: window.ps_checkout, event: event } + }) + ); + }); + cardFields.on('validityChange', event => { + window.ps_checkout.events.dispatchEvent( + new CustomEvent('hostedFieldsValidityChange', { + detail: { ps_checkout: window.ps_checkout, event: event } + }) + ); + }); + cardFields.on('inputSubmitRequest', () => { + window.ps_checkout.events.dispatchEvent( + new CustomEvent('hostedFieldsInputSubmitRequest', { + detail: { ps_checkout: window.ps_checkout } + }) + ); + }); + cardFields.on('cardTypeChange', event => { + window.ps_checkout.events.dispatchEvent( + new CustomEvent('hostedFieldsCardTypeChange', { + detail: { ps_checkout: window.ps_checkout, event: event } + }) + ); + + // Change card bg depending on card type + if (event.cards.length === 1) { + document.querySelector('.default-credit-card').style.display = + 'none'; + + const cardImage = document.getElementById('card-image'); + cardImage.className = ''; + cardImage.classList.add(event.cards[0].type); + + document.querySelector('header').classList.add('header-slide'); + + // Change the CVV length for AmericanExpress cards + if (event.cards[0].code.size === 4) { + cardFields.setAttribute({ + field: 'cvv', + attribute: 'placeholder', + value: 'XXXX' + }); + } + } else { + document.querySelector('.default-credit-card').style.display = + 'block'; + const cardImage = document.getElementById('card-image'); + cardImage.className = ''; + + cardFields.setAttribute({ + field: 'cvv', + attribute: 'placeholder', + value: 'XXX' + }); + } + }); + + return cardFields; + }); + } + getEligibleFundingSources(cache = false) { if (!this.eligibleFundingSources || cache) { const paypalFundingSources = this.sdk.getFundingSources(); @@ -293,8 +471,9 @@ export class PayPalService extends BaseClass { mark: this.sdk.Marks({ fundingSource }) })) .filter((fundingSource) => { - if (fundingSource.name === 'card' && this.configPrestaShop.hostedFieldsEnabled && !this.isHostedFieldsEligible()) { - console.error('Hosted Fields (CCF) eligibility is declined. Switching to PayPal branded card fields (SCF)'); + if (fundingSource.name === 'card' && this.configPrestaShop.hostedFieldsEnabled && !this.isCardFieldsEligible()) { + console.log(this.configPrestaShop.hostedFieldsEnabled, this.isCardFieldsEligible()); + console.error('Card Fields (CCF) eligibility is declined. Switching to PayPal branded card fields (SCF)'); } console.log(fundingSource.name, fundingSource.mark.isEligible()); @@ -313,6 +492,10 @@ export class PayPalService extends BaseClass { return this.sdk.HostedFields && this.sdk.HostedFields.isEligible(); } + isCardFieldsEligible() { + return this.sdk.CardFields && this.sdk.CardFields().isEligible(); + } + /** * @param {string} placement * @param {string} amount diff --git a/_dev/js/front/src/utils/extra/types/paypal-sdk.typedef.doc.js b/_dev/js/front/src/utils/extra/types/paypal-sdk.typedef.doc.js index a46949c77..a521325bc 100644 --- a/_dev/js/front/src/utils/extra/types/paypal-sdk.typedef.doc.js +++ b/_dev/js/front/src/utils/extra/types/paypal-sdk.typedef.doc.js @@ -38,6 +38,7 @@ * @property {function} Marks.isEligible * @property {function} Marks.render * @property {object} HostedFields + * @property {object} CardFields * @property {function} HostedFields.isEligible * @property {function} HostedFields.render * @property {object} Messages diff --git a/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php b/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php index 80319694e..33d8b8e0f 100644 --- a/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php +++ b/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php @@ -87,6 +87,7 @@ public function buildLink() if ($this->shouldIncludeHostedFieldsComponent()) { $components[] = 'hosted-fields'; + $components[] = 'card-fields'; } if ($this->shouldIncludeMessagesComponent()) { @@ -106,6 +107,7 @@ public function buildLink() if ('SANDBOX' === $this->configuration->getPaymentMode()) { $params['debug'] = 'true'; // $params['buyer-country'] = $this->getCountry(); + $params['buyer-country'] = 'US'; } $fundingSourcesDisabled = $this->getFundingSourcesDisabled(); diff --git a/views/css/payments.css b/views/css/payments.css index 45f1a259f..4c9f8758e 100755 --- a/views/css/payments.css +++ b/views/css/payments.css @@ -181,7 +181,7 @@ backface-visibility: hidden; } -.defautl-credit-card { +.default-credit-card { position: absolute; top: 2px; right: 10px; diff --git a/views/css/payments16.css b/views/css/payments16.css index 3ebf26025..152579c2d 100644 --- a/views/css/payments16.css +++ b/views/css/payments16.css @@ -198,7 +198,7 @@ backface-visibility: hidden; } -#ps_checkout-hosted-fields-form .defautl-credit-card { +#ps_checkout-hosted-fields-form .default-credit-card { position: absolute; top: 2px; right: 10px; diff --git a/views/templates/hook/displayPayment.tpl b/views/templates/hook/displayPayment.tpl index f609fb529..14a952c96 100644 --- a/views/templates/hook/displayPayment.tpl +++ b/views/templates/hook/displayPayment.tpl @@ -50,11 +50,16 @@ {if $fundingSource == 'card' && $isHostedFieldsAvailable}
+
+ +
+
+
- +
diff --git a/views/templates/hook/paymentOptions.tpl b/views/templates/hook/paymentOptions.tpl index 80c346b1f..f329f1583 100644 --- a/views/templates/hook/paymentOptions.tpl +++ b/views/templates/hook/paymentOptions.tpl @@ -28,11 +28,16 @@ *} +
+ +
+
+
- +
From 848405f15500b0c522536bf8b244e08585ab1d07 Mon Sep 17 00:00:00 2001 From: Laurynas Date: Wed, 10 Jan 2024 16:26:57 +0200 Subject: [PATCH 03/54] Working cardfields component --- _dev/js/front/src/api/ps-checkout.api.js | 2 +- .../common/card-fields.component.js | 299 ++++++++++++++---- _dev/js/front/src/service/paypal.service.js | 240 +++++--------- .../extra/types/paypal-sdk.typedef.doc.js | 20 ++ ps_checkout.php | 2 + views/css/payments.css | 30 +- views/templates/hook/displayPayment.tpl | 4 +- views/templates/hook/paymentOptions.tpl | 22 +- 8 files changed, 386 insertions(+), 233 deletions(-) diff --git a/_dev/js/front/src/api/ps-checkout.api.js b/_dev/js/front/src/api/ps-checkout.api.js index 43ab71fe4..3e641867b 100644 --- a/_dev/js/front/src/api/ps-checkout.api.js +++ b/_dev/js/front/src/api/ps-checkout.api.js @@ -216,7 +216,7 @@ export class PsCheckoutApi extends BaseClass { paypal_transaction ); - window.location.href = confirmationUrl.toString(); + // window.location.href = confirmationUrl.toString(); } if (response.error && 'INSTRUMENT_DECLINED' === response.error) { diff --git a/_dev/js/front/src/components/common/card-fields.component.js b/_dev/js/front/src/components/common/card-fields.component.js index 154094982..6f8d0e693 100644 --- a/_dev/js/front/src/components/common/card-fields.component.js +++ b/_dev/js/front/src/components/common/card-fields.component.js @@ -16,21 +16,60 @@ * @copyright Since 2007 PrestaShop SA and Contributors * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) */ + +/** + * @typedef PaypalCardFieldCardField + * @type {*} + * + * @property {boolean} isEmpty + * @property {boolean} isValid + * @property {boolean} isPotentiallyValid + * @property {boolean} isFocused + */ + +/** + * @typedef PaypalCardFieldsEvent + * @type {*} + * + * @property {string} emittedBy + * @property {boolean} isFormValid + * @property {String[]} errors + * @property {*} fields + * @property {PaypalCardFieldCardField} fields.cardCvvField + * @property {PaypalCardFieldCardField} fields.cardExpiryField + * @property {PaypalCardFieldCardField} fields.cardNameField + * @property {PaypalCardFieldCardField} fields.cardNumberField + */ + import { BaseComponent } from '../../core/dependency-injection/base.component'; export class CardFieldsComponent extends BaseComponent { static Inject = { config: 'PsCheckoutConfig', + configPayPal: 'PayPalSdkConfig', payPalService: 'PayPalService', psCheckoutApi: 'PsCheckoutApi', - psCheckoutService: 'PsCheckoutService' + psCheckoutService: 'PsCheckoutService', + sdk: 'PayPalSDK', }; created() { this.data.name = this.props.fundingSource.name; this.data.validity = false; + /** + * @property {PaypalCardFieldsEvent} data.cardFieldsState + */ + this.data.cardFieldsState = {}; + + this.data.cardFieldsFocused = { + name: false, + number: false, + expiry: false, + cvv: false, + } this.data.HTMLElement = this.props.HTMLElement; + this.data.HTMLElementCardForm = this.getCardForm(); this.data.HTMLElementBaseButton = this.getBaseButton(); this.data.HTMLElementButton = null; this.data.HTMLElementButtonWrapper = this.getButtonWrapper(); @@ -39,45 +78,67 @@ export class CardFieldsComponent extends BaseComponent { this.data.HTMLElementCardCVV = this.getCardCVV(); this.data.HTMLElementCardExpirationDate = this.getCardExpirationDate(); this.data.HTMLElementSection = this.getSection(); + + this.data.clearCardFields = () => {console.log('CLEAR CARD FIELDS')}; } + + getCardForm() { + const cardFromSelector = `#ps_checkout-hosted-fields-form`; + return document.querySelector(cardFromSelector); + } getBaseButton() { const buttonSelector = `#payment-confirmation button`; return document.querySelector(buttonSelector); } - getButtonWrapper() { const buttonWrapper = `.ps_checkout-button[data-funding-source=${this.data.name}]`; return document.querySelector(buttonWrapper); } getCardHolderName() { - const cardHolderNameId = '#ps_checkout-hosted-fields-card-holder-name'; + const cardHolderNameId = '#ps_checkout-hosted-fields-card-name'; return document.getElementById(cardHolderNameId); } getCardNumber() { const cardNumberId = '#ps_checkout-hosted-fields-card-number'; return document.getElementById(cardNumberId); } - getCardCVV() { const cardCVVId = '#ps_checkout-hosted-fields-card-cvv'; return document.getElementById(cardCVVId); } - getCardExpirationDate() { const cardExpirationDateId = '#ps_checkout-hosted-fields-card-expiration-date'; return document.getElementById(cardExpirationDateId); } - getSection() { const sectionSelector = `.js-payment-ps_checkout-${this.data.name}`; return document.querySelector(sectionSelector); } + getCardNameFieldError() { + const cardNameErrorSelector = `#ps_checkout-hosted-fields-error-name`; + return document.querySelector(cardNameErrorSelector); + } + + getCardNumberFieldError() { + const cardNameErrorSelector = `#ps_checkout-hosted-fields-error-number`; + return document.querySelector(cardNameErrorSelector); + } + + getCardExpiryFieldError() { + const cardNameErrorSelector = `#ps_checkout-hosted-fields-error-expiry`; + return document.querySelector(cardNameErrorSelector); + } + + getCardCvvFieldError() { + const cardNameErrorSelector = `#ps_checkout-hosted-fields-error-cvv`; + return document.querySelector(cardNameErrorSelector); + } getContingencies() { - switch (this.config.cardFieldsContingencies) { + switch (this.config.hostedFieldsContingencies) { case '3D_SECURE': case 'SCA_ALWAYS': return ['SCA_ALWAYS']; @@ -94,91 +155,213 @@ export class CardFieldsComponent extends BaseComponent { : this.data.validity; } + setFieldFocus(fieldName) { + this.data.cardFieldsFocused[fieldName] = true; + } + + toggleCardNameFieldError() { + const { isFocused, isEmpty, isValid, isPotentiallyValid } = + this.data.cardFieldsState.fields.cardNameField; + const hideError = isFocused || !this.data.cardFieldsFocused.name || isValid || isPotentiallyValid; + + this.getCardNameFieldError().classList.toggle('hidden', hideError) + } + + toggleCardNumberFieldError() { + const { isFocused, isEmpty, isValid, isPotentiallyValid } = + this.data.cardFieldsState.fields.cardNumberField; + const hideError = isPotentiallyValid && (isFocused || !this.data.cardFieldsFocused.number || isValid); + + this.getCardNumberFieldError().classList.toggle('hidden', hideError) + } + + toggleCardExpiryFieldError() { + const { isFocused, isEmpty, isValid, isPotentiallyValid } = + this.data.cardFieldsState.fields.cardExpiryField; + const hideError = isPotentiallyValid && (isFocused || !this.data.cardFieldsFocused.expiry || isValid); + + this.getCardExpiryFieldError().classList.toggle('hidden', hideError) + } + toggleCardCvvFieldError() { + const { isFocused, isEmpty, isValid, isPotentiallyValid } = + this.data.cardFieldsState.fields.cardCvvField; + const hideError = isPotentiallyValid && (isFocused || !this.data.cardFieldsFocused.cvv || isValid); + + this.getCardCvvFieldError().classList.toggle('hidden', hideError) + } + + toggleCardFieldErrors() { + this.toggleCardNameFieldError(); + this.toggleCardNumberFieldError(); + this.toggleCardExpiryFieldError(); + this.toggleCardCvvFieldError(); + } + + /** + * @param {PaypalCardFieldsEvent} event + */ + updateCardFieldsState(event) { + this.setFieldFocus(event.emittedBy); + this.data.validity = event.isFormValid; + this.data.cardFieldsState = event; + + this.isSubmittable() + ? this.data.HTMLElementButton.removeAttribute('disabled') + : this.data.HTMLElementButton.setAttribute('disabled', ''); + + this.toggleCardFieldErrors(); + } + + clearCardFields() { + console.log('CARD-FIELDS', this.data.cardFields); + if (this.data.cardFields) { + this.data.cardFields.NameField.clear(); + this.data.card.NumberField.clear() + this.data.card.CVVField.clear() + this.data.card.ExpiryField.clear() + } + } + renderPayPalCardFields() { + this.data.HTMLElementCardForm.classList.toggle('loading', true); + + const style = { + ...{ + input: { + 'font-size': '17px', + 'font-family': 'helvetica, tahoma, calibri, sans-serif', + color: '#3a3a3a' + }, + ':focus': { + color: 'black' + } + }, + ...(this.configPayPal.hostedFieldsCustomization || {}), + ...(window.ps_checkout.hostedFieldsCustomization || {}) + }; + this.payPalService .getCardFields( { - name: '#ps_checkout-hosted-fields-card-holder-name', + name: '#ps_checkout-hosted-fields-card-name', number: '#ps_checkout-hosted-fields-card-number', cvv: '#ps_checkout-hosted-fields-card-cvv', expirationDate: '#ps_checkout-hosted-fields-card-expiration-date' }, { - createOrder: async (data) => - this.psCheckoutApi + style, + createOrder: async (data) => { + console.log('createOrder', data); + this.data.HTMLElementButton.setAttribute('disabled', true); + + return this.psCheckoutApi .postCreateOrder({ ...data, fundingSource: this.data.name, isCardFields: true, // vault: storeCardInVault }) + .then(data => { + return data; + }) .catch(error => { this.data.notification.showError( `${error.message} ${error.name}` ); }) - } - ) - .then(cardFields => { - if (this.data.HTMLElement !== null) { - cardFields.on('validityChange', event => { - this.data.validity = - Object.keys(event.fields) - .map(name => event.fields[name]) - .map(({ isValid }) => { - return isValid; - }) - .filter(validity => validity === false).length === 0; + }, + onApprove: async (data) => { + console.log('onApprove', data); + return this.psCheckoutApi.postValidateOrder({ + ...data, + fundingSource: this.data.name, + isHostedFields: true + }) + .then(data => { + this.clearCardFields(); + return data; + }) + .catch(error => { + let message = error.message || ''; - this.data.HTMLElementSection.classList.toggle( - 'disabled', - !this.isSubmittable() - ); + if (!message) { + message = `Unknown error, code: ${error.code || 'none'}, description: ${error.description || 'none'}`; + } - this.isSubmittable() - ? this.data.HTMLElementButton.removeAttribute('disabled') - : this.data.HTMLElementButton.setAttribute('disabled', ''); - }); + this.data.loader.hide(); + this.data.notification.showError(message); + this.data.HTMLElementButton.removeAttribute('disabled'); + }) + }, + onError: async (error) => { + console.log('onError', error); + let message = error.message || ''; + this.data.notification.showError(message); + this.data.HTMLElementButton.removeAttribute('disabled'); + }, + inputEvents: { + /** + * @param {PaypalCardFieldsEvent} event + */ + onChange: (event) => { + this.updateCardFieldsState(event); + this.data.cardFields = event; + }, + /** + * @param {PaypalCardFieldsEvent} event + */ + onFocus: (event) => { + this.updateCardFieldsState(event); + window.ps_checkout.events.dispatchEvent( + new CustomEvent('hostedFieldsFocus', { + detail: { ps_checkout: window.ps_checkout, event } + }) + ); + }, + /** + * @param {PaypalCardFieldsEvent} event + */ + onBlur: (event) => { + this.updateCardFieldsState(event); + this.data.clearCardFields(); + window.ps_checkout.events.dispatchEvent( + new CustomEvent('hostedFieldsBlur', { + detail: { ps_checkout: window.ps_checkout, event } + }) + ); + }, + /** + * @param {PaypalCardFieldsEvent} event + */ + onInputSubmitRequest: (event) => { + this.updateCardFieldsState(event); + console.log('SUBMIT', event, this.sdk.CardFields()); + }, + } + }, + ) + .then(cardFields => { + this.data.clearCardFields = cardFields.clear; + console.log(cardFields, this.data.cardFields); + this.data.HTMLElementCardForm.classList.toggle('loading', false); + if (this.data.HTMLElement !== null) { this.data.HTMLElementButton.addEventListener('click', event => { event.preventDefault(); this.data.loader.show(); // this.data.HTMLElementButton.classList.toggle('disabled', true); this.data.HTMLElementButton.setAttribute('disabled', ''); - cardFields - .submit({ - contingencies: this.getContingencies() - }) - .then(payload => { - const data = payload; - - // Backend requirement - data.orderID = data.orderId; - delete data.orderId; - - return this.psCheckoutApi.postValidateOrder({ - ...data, - fundingSource: this.data.name, - isHostedFields: true - }); - }) - .catch(error => { - let message = error.message || ''; - - if (!message) { - message = `Unknown error, code: ${error.code || 'none'}, description: ${error.description || 'none'}`; - } - - this.data.loader.hide(); - this.data.notification.showError(message); - this.data.HTMLElementButton.removeAttribute('disabled'); - }); + cardFields.submit({contingencies: this.getContingencies()}).then((data) => { + console.log(this.data.cardFields); + }); }); } }); } + + renderButton() { this.data.HTMLElementButton = this.data.HTMLElementBaseButton.cloneNode( true diff --git a/_dev/js/front/src/service/paypal.service.js b/_dev/js/front/src/service/paypal.service.js index 4786c8d51..b0a2b6571 100644 --- a/_dev/js/front/src/service/paypal.service.js +++ b/_dev/js/front/src/service/paypal.service.js @@ -45,6 +45,17 @@ * @property {string} text.align */ +/** + * @typedef PayPayCardFieldsOptions + * @type {*} + * + * @property {function} createOrder + * @property {function} onApprove + * @property {function} onError + * @property {function} inputEvents + * @property {object} style + */ + /** * @typedef PaypalPayLaterOfferEvents * @type {*} @@ -281,180 +292,85 @@ export class PayPalService extends BaseClass { /** * @param {*} fieldSelectors + * @param {string} fieldSelectors.name * @param {string} fieldSelectors.number * @param {string} fieldSelectors.cvv * @param {string} fieldSelectors.expirationDate - * @param {PaypalHostedFieldsEvents} events - * @returns {*} + * + * @param {PayPayCardFieldsOptions} options + * + * @returns {PayPalSdk.CardFields} */ - getCardFields(fieldSelectors, events) { - const style = { - ...{ - input: { - 'font-size': '17px', - 'font-family': 'helvetica, tahoma, calibri, sans-serif', - color: '#3a3a3a' - }, - ':focus': { - color: 'black' - } - }, - ...(this.configPayPal.hostedFieldsCustomization || {}), - ...(window.ps_checkout.hostedFieldsCustomization || {}) - }; - - return this.sdk.CardFields(events).render({ - styles: style, - fields: { - name: { - selector: fieldSelectors.name, - placeholder: this.$('paypal.hosted-fields.placeholder.card-number') - }, - number: { - selector: fieldSelectors.number, - placeholder: this.$('paypal.hosted-fields.placeholder.card-number') - }, - cvv: { - selector: fieldSelectors.cvv, - placeholder: this.$('paypal.hosted-fields.placeholder.cvv') - }, - expirationDate: { - selector: fieldSelectors.expirationDate, - placeholder: this.$( - 'paypal.hosted-fields.placeholder.expiration-date' - ) - } - }, - ...events - }) - .then(cardFields => { - const nameField = document.querySelector(fieldSelectors.name); - const numberField = document.querySelector(fieldSelectors.number); - const cvvField = document.querySelector(fieldSelectors.cvv); - const expirationDateField = document.querySelector( - fieldSelectors.expirationDate - ); - - const cardNameField = cardFields.NameField(); - const cardNumberField = cardFields.NumberField(); - const cardExpiryField = cardFields.ExpiryField(); - const cardCvvField = cardFields.CVVField(); - - try { - cardNameField.render(nameField); - cardNumberField.render(numberField); - cardCvvField.render(cvvField); - cardExpiryField.render(expirationDateField); - } catch (e) { - return console.error("Failed to render CardFields", e); - } + async getCardFields(fieldSelectors, options) { + const cardFields = this.sdk.CardFields(options); - const cardHolderNameLabel = document.querySelector( - `label[for="${c.id}"]` - ); - const numberLabel = document.querySelector( - `label[for="${numberField.id}"]` - ); - const cvvLabel = document.querySelector(`label[for="${cvvField.id}"]`); - const expirationDateLabel = document.querySelector( - `label[for="${expirationDateField.id}"]` - ); + const nameFieldSelector = document.querySelector(fieldSelectors.name); + const numberFieldSelector = document.querySelector(fieldSelectors.number); + const expiryFieldSelector = document.querySelector( + fieldSelectors.expirationDate + ); + const cvvFieldSelector = document.querySelector(fieldSelectors.cvv); - numberLabel.innerHTML = this.$( - 'paypal.hosted-fields.label.card-number' - ); - cvvLabel.innerHTML = this.$('paypal.hosted-fields.label.cvv'); - expirationDateLabel.innerHTML = this.$( - 'paypal.hosted-fields.label.expiration-date' - ); - return cardFields; - }) - .then(cardFields => { - cardFields.on('focus', event => { - window.ps_checkout.events.dispatchEvent( - new CustomEvent('hostedFieldsFocus', { - detail: { ps_checkout: window.ps_checkout, event: event } - }) - ); - }); - cardFields.on('blur', event => { - window.ps_checkout.events.dispatchEvent( - new CustomEvent('hostedFieldsBlur', { - detail: { ps_checkout: window.ps_checkout, event: event } - }) - ); - }); - cardFields.on('empty', event => { - window.ps_checkout.events.dispatchEvent( - new CustomEvent('hostedFieldsEmpty', { - detail: { ps_checkout: window.ps_checkout, event: event } - }) - ); - }); - cardFields.on('notEmpty', event => { - window.ps_checkout.events.dispatchEvent( - new CustomEvent('hostedFieldsNotEmpty', { - detail: { ps_checkout: window.ps_checkout, event: event } - }) - ); - }); - cardFields.on('validityChange', event => { - window.ps_checkout.events.dispatchEvent( - new CustomEvent('hostedFieldsValidityChange', { - detail: { ps_checkout: window.ps_checkout, event: event } - }) - ); - }); - cardFields.on('inputSubmitRequest', () => { - window.ps_checkout.events.dispatchEvent( - new CustomEvent('hostedFieldsInputSubmitRequest', { - detail: { ps_checkout: window.ps_checkout } - }) - ); - }); - cardFields.on('cardTypeChange', event => { - window.ps_checkout.events.dispatchEvent( - new CustomEvent('hostedFieldsCardTypeChange', { - detail: { ps_checkout: window.ps_checkout, event: event } - }) - ); - - // Change card bg depending on card type - if (event.cards.length === 1) { - document.querySelector('.default-credit-card').style.display = - 'none'; + const nameField = cardFields.NameField({ + placeholder: this.$('paypal.hosted-fields.placeholder.card-name') + }); + const numberField = cardFields.NumberField({ + placeholder: this.$('paypal.hosted-fields.placeholder.card-number') + }); + const expiryField = cardFields.ExpiryField({ + placeholder: this.$('paypal.hosted-fields.placeholder.expiration-date') + }); + const cvvField = cardFields.CVVField({ + placeholder: this.$( + 'paypal.hosted-fields.placeholder.cvv' + ) + }); - const cardImage = document.getElementById('card-image'); - cardImage.className = ''; - cardImage.classList.add(event.cards[0].type); - document.querySelector('header').classList.add('header-slide'); + // await Promise.all( + // [ + // cardNameField.render(nameField), + // cardNumberField.render(numberField), + // cardCvvField.render(cvvField), + // cardExpiryField.render(expirationDateField) + // ] + // ).catch(e => { + // return console.error("Failed to render CardFields", e); + // }) ; + + try { + await numberField.render(numberFieldSelector); + await expiryField.render(expiryFieldSelector); + await cvvField.render(cvvFieldSelector); + await nameField.render(nameFieldSelector); + } catch (e) { + return console.error("Failed to render CardFields", e); + } - // Change the CVV length for AmericanExpress cards - if (event.cards[0].code.size === 4) { - cardFields.setAttribute({ - field: 'cvv', - attribute: 'placeholder', - value: 'XXXX' - }); - } - } else { - document.querySelector('.default-credit-card').style.display = - 'block'; - const cardImage = document.getElementById('card-image'); - cardImage.className = ''; + const nameLabel = document.querySelector( + `label[for="${nameFieldSelector.id}"]` + ); + const numberLabel = document.querySelector( + `label[for="${numberFieldSelector.id}"]` + ); + const cvvLabel = document.querySelector(`label[for="${cvvFieldSelector.id}"]`); + const expirationDateLabel = document.querySelector( + `label[for="${expiryFieldSelector.id}"]` + ); - cardFields.setAttribute({ - field: 'cvv', - attribute: 'placeholder', - value: 'XXX' - }); - } - }); + nameLabel.innerHTML = this.$( + 'paypal.hosted-fields.label.card-name' + ); + numberLabel.innerHTML = this.$( + 'paypal.hosted-fields.label.card-number' + ); + cvvLabel.innerHTML = this.$('paypal.hosted-fields.label.cvv'); + expirationDateLabel.innerHTML = this.$( + 'paypal.hosted-fields.label.expiration-date' + ); - return cardFields; - }); + return cardFields; } getEligibleFundingSources(cache = false) { diff --git a/_dev/js/front/src/utils/extra/types/paypal-sdk.typedef.doc.js b/_dev/js/front/src/utils/extra/types/paypal-sdk.typedef.doc.js index a521325bc..75dbdfaed 100644 --- a/_dev/js/front/src/utils/extra/types/paypal-sdk.typedef.doc.js +++ b/_dev/js/front/src/utils/extra/types/paypal-sdk.typedef.doc.js @@ -21,6 +21,19 @@ * This file exists only for documentative purposes */ +/** + * @typedef PayPalCardField + * + * @property {function} addClass + * @property {function} clear + * @property {function} focus + * @property {function} removeAttribute + * @property {function} removeClass + * @property {function} render + * @property {function} setAttribute + * @property {function} setMessage + */ + /** * @typedef PayPalSdk * @type {object} @@ -39,6 +52,13 @@ * @property {function} Marks.render * @property {object} HostedFields * @property {object} CardFields + * @property {PayPalCardField} CardFields.CVVField + * @property {PayPalCardField} CardFields.ExpiryField + * @property {PayPalCardField} CardFields.NameField + * @property {PayPalCardField} CardFields.NumberField + * @property {function} CardFields.getState + * @property {function} CardFields.isEligible + * @property {function} CardFields.submit * @property {function} HostedFields.isEligible * @property {function} HostedFields.render * @property {object} Messages diff --git a/ps_checkout.php b/ps_checkout.php index 74e721f4e..3e4f7c862 100755 --- a/ps_checkout.php +++ b/ps_checkout.php @@ -1125,6 +1125,8 @@ public function hookActionFrontControllerSetMedia() 'checkout.order.amount.total' => $this->l('The total amount of your order comes to'), 'checkout.order.included.tax' => $this->l('(tax incl.)'), 'checkout.order.confirm.label' => $this->l('Please confirm your order by clicking "I confirm my order".'), + 'paypal.hosted-fields.label.card-name' => $this->l('Card holder name'), + 'paypal.hosted-fields.placeholder.card-name' => $this->l('Card holder name'), 'paypal.hosted-fields.label.card-number' => $this->l('Card number'), 'paypal.hosted-fields.placeholder.card-number' => $this->l('Card number'), 'paypal.hosted-fields.label.expiration-date' => $this->l('Expiry date'), diff --git a/views/css/payments.css b/views/css/payments.css index 4c9f8758e..616de4b4e 100755 --- a/views/css/payments.css +++ b/views/css/payments.css @@ -323,17 +323,22 @@ margin: 0 0.25em; } +#ps_checkout-hosted-fields-card-name { + position: relative; + /*height: 45px;*/ + margin-top: 6px; +} #ps_checkout-hosted-fields-card-number { position: relative; - height: 45px; + /*height: 45px;*/ margin-top: 6px; } #ps_checkout-hosted-fields-card-expiration-date { - height: 45px; + /*height: 45px;*/ margin-top: 6px; } #ps_checkout-hosted-fields-card-cvv { - height: 45px; + /*height: 45px;*/ margin-top: 6px; } @@ -506,6 +511,14 @@ label[for="ps_checkout-hosted-fields-card-cvv"] { display: table-cell; } +#ps_checkout-hosted-fields-form.loading > *:not(#ps_checkout-hosted-fields-form-loader){ + display: none; +} + +#ps_checkout-hosted-fields-form:not(.loading) > #ps_checkout-hosted-fields-form-loader{ + display: none; +} + #cart .ps-checkout-express-separator { text-align: center; } @@ -513,3 +526,14 @@ label[for="ps_checkout-hosted-fields-card-cvv"] { .cart-detailed-totals + #ps-checkout-pp-message-container{ padding: 0 1rem 1rem; } + +#ps_checkout-hosted-fields-error-name.hidden, +#ps_checkout-hosted-fields-error-number.hidden, +#ps_checkout-hosted-fields-error-expiry.hidden, +#ps_checkout-hosted-fields-error-cvv.hidden { + display: none; +} + +#ps_checkout-hosted-fields-form-loader { + text-align: center; +} diff --git a/views/templates/hook/displayPayment.tpl b/views/templates/hook/displayPayment.tpl index 14a952c96..88c84466e 100644 --- a/views/templates/hook/displayPayment.tpl +++ b/views/templates/hook/displayPayment.tpl @@ -51,8 +51,8 @@ {if $fundingSource == 'card' && $isHostedFieldsAvailable}
- -
+ +
diff --git a/views/templates/hook/paymentOptions.tpl b/views/templates/hook/paymentOptions.tpl index f329f1583..21c96bdac 100644 --- a/views/templates/hook/paymentOptions.tpl +++ b/views/templates/hook/paymentOptions.tpl @@ -26,16 +26,18 @@ * * Script tags will be removed and some HTML5 element can cause an Exception due to DOMDocument class *} - - + +
+ +
- -
+ +
-
+
@@ -44,7 +46,7 @@
-
+
@@ -56,9 +58,15 @@
-
+
+
+ + + + +
From 1ff4f0d402e6a631c421cbc8c421cde8a22971e7 Mon Sep 17 00:00:00 2001 From: Laurynas Date: Tue, 23 Jan 2024 16:11:04 +0200 Subject: [PATCH 07/54] Fixed card fields styling --- .../js/front/src/components/common/card-fields.component.js | 6 +++++- .../front/src/components/common/payment-option.component.js | 1 - .../default-selectors/default-selectors-ps1_6.js | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/_dev/js/front/src/components/common/card-fields.component.js b/_dev/js/front/src/components/common/card-fields.component.js index 66b7da85c..adc16e41f 100644 --- a/_dev/js/front/src/components/common/card-fields.component.js +++ b/_dev/js/front/src/components/common/card-fields.component.js @@ -170,10 +170,14 @@ export class CardFieldsComponent extends BaseComponent { input: { 'font-size': '17px', 'font-family': 'helvetica, tahoma, calibri, sans-serif', - color: '#3a3a3a' + color: '#3a3a3a', + padding: '8px 12px' }, ':focus': { color: 'black' + }, + body: { + padding: '0px' } }, ...(this.configPayPal.hostedFieldsCustomization || {}), diff --git a/_dev/js/front/src/components/common/payment-option.component.js b/_dev/js/front/src/components/common/payment-option.component.js index 5648b80b0..76cb926c7 100644 --- a/_dev/js/front/src/components/common/payment-option.component.js +++ b/_dev/js/front/src/components/common/payment-option.component.js @@ -18,7 +18,6 @@ */ import { BaseComponent } from '../../core/dependency-injection/base.component'; -import { HostedFieldsComponent } from './hosted-fields.component'; import { MarkComponent } from './marker.component'; import { SmartButtonComponent } from './smart-button.component'; import { PaymentFieldsComponent } from "./payment-fields.component"; diff --git a/_dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_6.js b/_dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_6.js index 45a6117c9..9651d76c4 100644 --- a/_dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_6.js +++ b/_dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_6.js @@ -45,6 +45,7 @@ export const DefaultSelectors1_6 = { PAY_LATER_BANNER_CONTAINER: '.header-container', CARD_FIELDS: { + FORM: '#ps_checkout-card-fields-form', NAME: '#ps_checkout-card-fields-card-name', NUMBER: '#ps_checkout-card-fields-card-number', EXPIRY: '#ps_checkout-card-fields-card-expiry', From 847bb43fb80a8eef107d3cac9f36b38cd2723626 Mon Sep 17 00:00:00 2001 From: Laurynas Date: Wed, 31 Jan 2024 17:45:23 +0200 Subject: [PATCH 08/54] Added payment_source and supplementary_data to order creation --- .../common/card-fields.component.js | 2 +- controllers/front/check.php | 2 +- controllers/front/create.php | 2 +- .../Payload/CreateOrderPayloadBuilder.php | 90 ++++++++++--- src/Builder/Payload/OrderPayloadBuilder.php | 127 +++++++++++++++--- src/Handler/CreatePaypalOrderHandler.php | 35 ++--- .../Builder/CreateOrderPayloadBuilderTest.php | 77 +++++++++++ views/templates/markup/cardFields.tpl | 8 +- 8 files changed, 275 insertions(+), 68 deletions(-) diff --git a/_dev/js/front/src/components/common/card-fields.component.js b/_dev/js/front/src/components/common/card-fields.component.js index adc16e41f..4836c3cfa 100644 --- a/_dev/js/front/src/components/common/card-fields.component.js +++ b/_dev/js/front/src/components/common/card-fields.component.js @@ -201,7 +201,7 @@ export class CardFieldsComponent extends BaseComponent { .postCreateOrder({ ...data, fundingSource: this.data.name, - isCardFields: true, + isHostedFields: true, // vault: storeCardInVault }) .then(data => { diff --git a/controllers/front/check.php b/controllers/front/check.php index 3a4cc0896..7f38cc04e 100644 --- a/controllers/front/check.php +++ b/controllers/front/check.php @@ -100,7 +100,7 @@ public function postProcess() if (false === empty($psCheckoutCart->paypal_order)) { $paypalOrder = new CreatePaypalOrderHandler($this->context); - $response = $paypalOrder->handle($isExpressCheckout || empty($this->context->cart->id_address_delivery), true, $psCheckoutCart->paypal_order); + $response = $paypalOrder->handle($isExpressCheckout || empty($this->context->cart->id_address_delivery), $psCheckoutCart->paypal_funding === 'card', true, $psCheckoutCart->paypal_order); if (false === $response['status']) { $this->module->getLogger()->error( diff --git a/controllers/front/create.php b/controllers/front/create.php index 066250cfd..182b4da49 100755 --- a/controllers/front/create.php +++ b/controllers/front/create.php @@ -131,7 +131,7 @@ public function postProcess() } $paypalOrder = new CreatePaypalOrderHandler($this->context); - $response = $paypalOrder->handle($isExpressCheckout); + $response = $paypalOrder->handle($isExpressCheckout, isset($bodyValues['fundingSource']) && $bodyValues['fundingSource'] === 'card'); if (false === $response['status']) { throw new PsCheckoutException($response['exceptionMessage'], (int) $response['exceptionCode']); diff --git a/src/Builder/Payload/CreateOrderPayloadBuilder.php b/src/Builder/Payload/CreateOrderPayloadBuilder.php index d100cfb8d..d0f04af7c 100644 --- a/src/Builder/Payload/CreateOrderPayloadBuilder.php +++ b/src/Builder/Payload/CreateOrderPayloadBuilder.php @@ -57,6 +57,11 @@ public function buildFullPayload() if (empty($this->data['ps_checkout']['isUpdate'])) { $this->buildApplicationContextNode(); } + + if ($this->data['ps_checkout']['isCard']) { + $this->buildPaymentSourceNode(); + $this->buildSupplementaryDataNode(); + } } /** @@ -127,14 +132,7 @@ public function buildShippingNode() . (!empty($this->data['deliveryAddress']['lastname']) ? $this->data['deliveryAddress']['lastname'] : '') ), ], - 'address' => [ - 'address_line_1' => !empty($this->data['deliveryAddress']['address1']) ? $this->data['deliveryAddress']['address1'] : '', - 'address_line_2' => !empty($this->data['deliveryAddress']['address2']) ? $this->data['deliveryAddress']['address2'] : '', - 'admin_area_1' => !empty($this->data['deliveryAddressState']['name']) ? $this->data['deliveryAddressState']['name'] : '', - 'admin_area_2' => !empty($this->data['deliveryAddress']['city']) ? $this->data['deliveryAddress']['city'] : '', - 'country_code' => !empty($this->data['deliveryAddressCountry']['iso_code']) ? $this->data['deliveryAddressCountry']['iso_code'] : '', - 'postal_code' => !empty($this->data['deliveryAddress']['postcode']) ? $this->data['deliveryAddress']['postcode'] : '', - ], + 'address' => $this->getAddressPortable('deliveryAddress'), ]; $this->getPayload()->addAndMergeItems($node); @@ -151,14 +149,7 @@ public function buildPayerNode() 'surname' => !empty($this->data['invoiceAddress']['lastname']) ? $this->data['invoiceAddress']['lastname'] : '', ], 'email_address' => !empty($this->data['customer']['email']) ? $this->data['customer']['email'] : '', - 'address' => [ - 'address_line_1' => !empty($this->data['invoiceAddress']['address1']) ? $this->data['invoiceAddress']['address1'] : '', - 'address_line_2' => !empty($this->data['invoiceAddress']['address2']) ? $this->data['invoiceAddress']['address2'] : '', - 'admin_area_1' => !empty($this->data['invoiceAddressState']['name']) ? $this->data['invoiceAddressState']['name'] : '', - 'admin_area_2' => !empty($this->data['invoiceAddress']['city']) ? $this->data['invoiceAddress']['city'] : '', - 'country_code' => !empty($this->data['invoiceAddressCountry']['iso_code']) ? $this->data['invoiceAddressCountry']['iso_code'] : '', - 'postal_code' => !empty($this->data['invoiceAddress']['postcode']) ? $this->data['invoiceAddress']['postcode'] : '', - ], + 'address' => $this->getAddressPortable('invoiceAddress'), ]; // Add optional birthdate if provided @@ -282,6 +273,71 @@ public function buildAmountBreakdownNode() $this->getPayload()->addAndMergeItems($node); } + private function buildPaymentSourceNode() + { + $node = [ + 'payment_source' => [ + 'card' => [ + 'name' => $this->data['invoiceAddress']['firstname'] . ' ' . $this->data['invoiceAddress']['lastname'], + 'billing_address' => $this->getAddressPortable('invoiceAddress'), + 'attributes' => [ + 'verification' => [ + 'method' => $this->data['ps_checkout']['3DS'], + ], + ], + ], + ], + ]; + + $this->getPayload()->addAndMergeItems($node); + } + + private function buildSupplementaryDataNode() + { + $payload = $this->getPayload()->getArray(); + $node = [ + 'supplementary_data' => [ + 'card' => [ + 'level_2' => [ +// 'invoice_id' => '', + 'tax_total' => $payload['amount']['breakdown']['tax_total'], + ], + 'level_3' => [ + 'shipping_amount' => $payload['amount']['breakdown']['shipping'], + 'duty_amount' => [ + 'currency_code' => $payload['amount']['currency_code'], + 'value' => $payload['amount']['value'], + ], + 'discount_amount' => $payload['amount']['breakdown']['discount'], + 'shipping_address' => $this->getAddressPortable('deliveryAddress'), + 'line_items' => $payload['items'], + ], + ], + ], + ]; + + $this->getPayload()->addAndMergeItems($node); + } + + /** + * @param "deliveryAddress"|"invoiceAddress" $addressType + * + * @return string[] + */ + private function getAddressPortable($addressType) + { + $address = $this->data[$addressType]; + + return [ + 'address_line_1' => !empty($address['address1']) ? $address['address1'] : '', + 'address_line_2' => !empty($address['address2']) ? $address['address2'] : '', + 'admin_area_1' => !empty($this->data["{$addressType}State"]['name']) ? $this->data["{$addressType}State"]['name'] : '', + 'admin_area_2' => !empty($address['city']) ? $address['city'] : '', + 'country_code' => !empty($this->data["{$addressType}Country"]['iso_code']) ? $this->data["{$addressType}Country"]['iso_code'] : '', + 'postal_code' => !empty($address['postcode']) ? $address['postcode'] : '', + ]; + } + /** * Get decimal to round correspondent to the payment currency used * Advise from PayPal: Always round to 2 decimals except for HUF, JPY and TWD @@ -305,7 +361,7 @@ private function getNbDecimalToRound() */ private function formatAmount($amount) { - return sprintf("%01.{$this->getNbDecimalToRound()}f", $amount); + return sprintf("%01.{$this->getNbDecimalToRound()}F", $amount); } /** diff --git a/src/Builder/Payload/OrderPayloadBuilder.php b/src/Builder/Payload/OrderPayloadBuilder.php index 65b2903f0..b3fc263cd 100644 --- a/src/Builder/Payload/OrderPayloadBuilder.php +++ b/src/Builder/Payload/OrderPayloadBuilder.php @@ -65,6 +65,11 @@ class OrderPayloadBuilder extends Builder implements PayloadBuilderInterface */ private $isPatch; + /** + * @var bool + */ + private $isCard = false; + /** * @param array $cart * @param bool $isPatch @@ -102,6 +107,11 @@ public function buildFullPayload() if (false === $this->isUpdate) { $this->buildApplicationContextNode(); } + + if ($this->isCard) { + $this->buildPaymentSourceNode(); + $this->buildSupplementaryDataNode(); + } } /** @@ -128,6 +138,11 @@ public function buildMinimalPayload() if (false === $this->isUpdate) { $this->buildApplicationContextNode(); } + + if ($this->isCard) { + $this->buildPaymentSourceNode(); + $this->buildSupplementaryDataNode(); + } } /** @@ -190,9 +205,6 @@ public function buildBaseNode() */ public function buildShippingNode() { - $countryCodeMatrice = new PaypalCountryCodeMatrice(); - $shippingCountryIsoCode = $this->getCountryIsoCodeById($this->cart['addresses']['shipping']->id_country); - $gender = new \Gender($this->cart['customer']->id_gender, $this->cart['language']->id); $genderName = $gender->name; @@ -200,14 +212,7 @@ public function buildShippingNode() 'name' => [ 'full_name' => $genderName . ' ' . $this->cart['addresses']['shipping']->lastname . ' ' . $this->cart['addresses']['shipping']->firstname, ], - 'address' => [ - 'address_line_1' => (string) $this->cart['addresses']['shipping']->address1, - 'address_line_2' => (string) $this->cart['addresses']['shipping']->address2, - 'admin_area_1' => (string) $this->getStateNameById($this->cart['addresses']['shipping']->id_state), - 'admin_area_2' => (string) $this->cart['addresses']['shipping']->city, - 'country_code' => (string) $countryCodeMatrice->getPaypalIsoCode($shippingCountryIsoCode), - 'postal_code' => (string) $this->cart['addresses']['shipping']->postcode, - ], + 'address' => $this->getAddressPortable('shipping'), ]; $this->getPayload()->addAndMergeItems($node); @@ -218,7 +223,6 @@ public function buildShippingNode() */ public function buildPayerNode() { - $countryCodeMatrice = new PaypalCountryCodeMatrice(); $payerCountryIsoCode = $this->getCountryIsoCodeById($this->cart['addresses']['invoice']->id_country); /** @var \Ps_checkout $module */ $module = \Module::getInstanceByName('ps_checkout'); @@ -229,14 +233,7 @@ public function buildPayerNode() 'surname' => (string) $this->cart['addresses']['invoice']->lastname, ], 'email_address' => (string) $this->cart['customer']->email, - 'address' => [ - 'address_line_1' => (string) $this->cart['addresses']['invoice']->address1, - 'address_line_2' => (string) $this->cart['addresses']['invoice']->address2, - 'admin_area_1' => (string) $this->getStateNameById($this->cart['addresses']['invoice']->id_state), //The highest level sub-division in a country, which is usually a province, state, or ISO-3166-2 subdivision. - 'admin_area_2' => (string) $this->cart['addresses']['invoice']->city, // A city, town, or village. Smaller than admin_area_level_1 - 'country_code' => (string) $countryCodeMatrice->getPaypalIsoCode($payerCountryIsoCode), - 'postal_code' => (string) $this->cart['addresses']['invoice']->postcode, - ], + 'address' => $this->getAddressPortable('invoice'), ]; // Add optional birthdate if provided @@ -406,6 +403,78 @@ public function buildAmountBreakdownNode() $this->getPayload()->addAndMergeItems($node); } + private function buildPaymentSourceNode() + { + /** @var \Ps_checkout $module */ + $module = \Module::getInstanceByName('ps_checkout'); + /** @var PayPalConfiguration $paypalConfiguration */ + $paypalConfiguration = $module->getService('ps_checkout.paypal.configuration'); + + $node = [ + 'payment_source' => [ + 'card' => [ + 'name' => $this->cart['addresses']['invoice']->firstname . ' ' . $this->cart['addresses']['invoice']->lastname, + 'billing_address' => $this->getAddressPortable('invoice'), + 'attributes' => [ + 'verification' => [ + 'method' => $paypalConfiguration->getHostedFieldsContingencies(), + ], + ], + ], + ], + ]; + + $this->getPayload()->addAndMergeItems($node); + } + + private function buildSupplementaryDataNode() + { + $payload = $this->getPayload()->getArray(); + $node = [ + 'supplementary_data' => [ + 'card' => [ + 'level_2' => [ +// 'invoice_id' => '', + 'tax_total' => $payload['amount']['breakdown']['tax_total'], + ], + 'level_3' => [ + 'shipping_amount' => $payload['amount']['breakdown']['shipping'], + 'duty_amount' => [ + 'currency_code' => $payload['amount']['currency_code'], + 'value' => $payload['amount']['value'], + ], + 'discount_amount' => $payload['amount']['breakdown']['discount'], + 'shipping_address' => $this->getAddressPortable('shipping'), + 'line_items' => $payload['items'], + ], + ], + ], + ]; + + $this->getPayload()->addAndMergeItems($node); + } + + /** + * @param "shipping"|"invoice" $addressType + * + * @return string[] + */ + private function getAddressPortable($addressType) + { + $countryCodeMatrice = new PaypalCountryCodeMatrice(); + $address = $this->cart['addresses'][$addressType]; + $payerCountryIsoCode = $this->getCountryIsoCodeById($address->id_country); + + return [ + 'address_line_1' => $address->address1, + 'address_line_2' => $address->address2, + 'admin_area_1' => (string) $this->getStateNameById($address->id_state), + 'admin_area_2' => $address->city, + 'country_code' => (string) $countryCodeMatrice->getPaypalIsoCode($payerCountryIsoCode), + 'postal_code' => $address->postcode, + ]; + } + /** * Function that allow to truncate fields to match the * paypal api requirements @@ -447,7 +516,7 @@ private function getNbDecimalToRound() */ private function formatAmount($amount) { - return sprintf("%01.{$this->getNbDecimalToRound()}f", $amount); + return sprintf("%01.{$this->getNbDecimalToRound()}F", $amount); } /** @@ -514,6 +583,22 @@ public function setPaypalOrderId($id) $this->paypalOrderId = $id; } + /** + * @return bool + */ + public function isCard() + { + return $this->isCard; + } + + /** + * @param bool $isCard + */ + public function setIsCard($isCard) + { + $this->isCard = $isCard; + } + /** * Getter $paypalOrderId */ diff --git a/src/Handler/CreatePaypalOrderHandler.php b/src/Handler/CreatePaypalOrderHandler.php index 4831ce300..d7599d2b0 100644 --- a/src/Handler/CreatePaypalOrderHandler.php +++ b/src/Handler/CreatePaypalOrderHandler.php @@ -57,7 +57,7 @@ public function __construct(Context $context = null) * * @throws PsCheckoutException */ - public function handle($expressCheckout = false, $updateOrder = false, $paypalOrderId = null) + public function handle($expressCheckout = false, $isCardPayment = false, $updateOrder = false, $paypalOrderId = null) { // Present an improved cart in order to create the payload $cartPresenter = (new CartPresenter())->present(); @@ -70,32 +70,21 @@ public function handle($expressCheckout = false, $updateOrder = false, $paypalOr /** @var ShopContext $shopContext */ $shopContext = $module->getService('ps_checkout.context.shop'); - // Build full payload in 1.7 - if ($shopContext->isShop17()) { - // enable express checkout mode if in express checkout - if (true === $expressCheckout) { - $builder->setExpressCheckout(true); - } + $builder->setIsCard($isCardPayment); - // enable update mode if we build an order for update it - if (true === $updateOrder) { - $builder->setIsUpdate(true); - $builder->setPaypalOrderId($paypalOrderId); - } + // enable express checkout mode if in express checkout + $builder->setExpressCheckout($expressCheckout); + + // enable update mode if we build an order for update it + $builder->setIsUpdate($updateOrder); + if ($updateOrder) { + $builder->setPaypalOrderId($paypalOrderId); + } + if ($shopContext->isShop17()) { + // Build full payload in 1.7 $builder->buildFullPayload(); } else { - // enable express checkout mode if in express checkout - if (true === $expressCheckout) { - $builder->setExpressCheckout(true); - } - - // enable update mode if we build an order for update it - if (true === $updateOrder) { - $builder->setIsUpdate(true); - $builder->setPaypalOrderId($paypalOrderId); - } - // if on 1.6 always build minimal payload $builder->buildMinimalPayload(); } diff --git a/tests/Unit/Builder/CreateOrderPayloadBuilderTest.php b/tests/Unit/Builder/CreateOrderPayloadBuilderTest.php index 544f1f407..20e6fb25a 100644 --- a/tests/Unit/Builder/CreateOrderPayloadBuilderTest.php +++ b/tests/Unit/Builder/CreateOrderPayloadBuilderTest.php @@ -46,6 +46,81 @@ public function testOneProductWithPaidShippingRoundingCompliant() } } + public function testPaymentSourceAppearsInPayload() + { + foreach ($this->cartDataProvider() as $scenario => $cartData) { + $orderPayloadBuilder = new CreateOrderPayloadBuilder(array_merge( + $cartData, + $this->shippingAddressDataProvider(), + $this->invoiceAddressDataProvider(), + $this->customerDataProvider(), + $this->currencyDataProvider(), + $this->languageDataProvider(), + $this->shopDataProvider(), + $this->moduleDataProvider() + )); + $orderPayloadBuilder->buildFullPayload(); + $payload = $orderPayloadBuilder->presentPayload()->getArray(); + + echo 'Starting ' . $scenario . PHP_EOL; + $this->assertArrayHasKey('payment_source', $payload); + $this->assertEquals($this->moduleDataProvider()['ps_checkout']['3DS'], $payload['payment_source']['card']['attributes']['verification']['method']); + } + } + + public function testSupplementaryDataAppearsInPayload() + { + foreach ($this->cartDataProvider() as $scenario => $cartData) { + $orderPayloadBuilder = new CreateOrderPayloadBuilder(array_merge( + $cartData, + $this->shippingAddressDataProvider(), + $this->invoiceAddressDataProvider(), + $this->customerDataProvider(), + $this->currencyDataProvider(), + $this->languageDataProvider(), + $this->shopDataProvider(), + $this->moduleDataProvider() + )); + $orderPayloadBuilder->buildFullPayload(); + $payload = $orderPayloadBuilder->presentPayload()->getArray(); + + echo 'Starting ' . $scenario . PHP_EOL; + $this->assertArrayHasKey('supplementary_data', $payload); + $this->assertEquals($payload['amount']['breakdown']['tax_total'], $payload['supplementary_data']['card']['level_2']['tax_total']); + $this->assertEquals($payload['amount']['currency_code'], $payload['supplementary_data']['card']['level_3']['duty_amount']['currency_code']); + $this->assertEquals($payload['amount']['value'], $payload['supplementary_data']['card']['level_3']['duty_amount']['value']); + $this->assertEquals($payload['amount']['breakdown']['shipping'], $payload['supplementary_data']['card']['level_3']['shipping_amount']); + $this->assertEquals($payload['amount']['breakdown']['discount'], $payload['supplementary_data']['card']['level_3']['discount_amount']); + $this->assertEquals($payload['shipping']['address'], $payload['supplementary_data']['card']['level_3']['shipping_address']); + $this->assertEquals($payload['items'], $payload['supplementary_data']['card']['level_3']['line_items']); + } + } + + public function testPaymentIsNotCard() + { + foreach ($this->cartDataProvider() as $scenario => $cartData) { + $orderPayloadBuilder = new CreateOrderPayloadBuilder(array_merge( + $cartData, + $this->shippingAddressDataProvider(), + $this->invoiceAddressDataProvider(), + $this->customerDataProvider(), + $this->currencyDataProvider(), + $this->languageDataProvider(), + $this->shopDataProvider(), + array_replace_recursive($this->moduleDataProvider(), ['ps_checkout' => [ + 'isCard' => false, + ]]) + )); + $orderPayloadBuilder->buildFullPayload(); + $payload = $orderPayloadBuilder->presentPayload()->getArray(); + + echo 'Starting ' . $scenario . PHP_EOL; + + $this->assertArrayNotHasKey('payment_source', $payload); + $this->assertArrayNotHasKey('supplementary_data', $payload); + } + } + private function checkAmountCalculation(array $payload) { $itemTotalAmount = 0; @@ -5516,6 +5591,8 @@ private function moduleDataProvider() 'roundType' => '1', 'roundMode' => '2', 'isExpressCheckout' => false, + 'isCard' => true, + '3DS' => 'SCA_WHEN_REQUIRED', ], ]; } diff --git a/views/templates/markup/cardFields.tpl b/views/templates/markup/cardFields.tpl index ad645ed95..0443c5718 100644 --- a/views/templates/markup/cardFields.tpl +++ b/views/templates/markup/cardFields.tpl @@ -30,24 +30,24 @@
-
+
-
+
-
+
-
+
i From 61600266bac039b2e31e53af56b74dac77cbc796 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Thu, 1 Feb 2024 16:46:41 +0100 Subject: [PATCH 09/54] Remove PayPal Client Token --- config/common.yml | 13 -- controllers/front/token.php | 11 -- ps_checkout.php | 14 +-- src/Api/Payment/Order.php | 70 ----------- .../Event/PayPalClientTokenUpdatedEvent.php | 111 ------------------ .../PayPalIdentityEventSubscriber.php | 50 -------- .../Query/GetClientTokenPayPalQuery.php | 68 ----------- .../Query/GetClientTokenPayPalQueryResult.php | 90 -------------- .../GetClientTokenPayPalQueryHandler.php | 82 ------------- src/PayPal/PayPalClientTokenProvider.php | 82 ------------- src/Validator/FrontControllerValidator.php | 21 ---- 11 files changed, 1 insertion(+), 611 deletions(-) delete mode 100644 src/PayPal/Identity/Event/PayPalClientTokenUpdatedEvent.php delete mode 100644 src/PayPal/Identity/EventSubscriber/PayPalIdentityEventSubscriber.php delete mode 100644 src/PayPal/Identity/Query/GetClientTokenPayPalQuery.php delete mode 100644 src/PayPal/Identity/Query/GetClientTokenPayPalQueryResult.php delete mode 100644 src/PayPal/Identity/QueryHandler/GetClientTokenPayPalQueryHandler.php delete mode 100644 src/PayPal/PayPalClientTokenProvider.php diff --git a/config/common.yml b/config/common.yml index d1f5fd08b..5727a740b 100644 --- a/config/common.yml +++ b/config/common.yml @@ -351,12 +351,6 @@ services: arguments: - "@ps_checkout.cache.paypal.order" - ps_checkout.paypal.provider.client_token: - class: 'PrestaShop\Module\PrestashopCheckout\PayPal\PayPalClientTokenProvider' - public: true - arguments: - - "@ps_checkout.repository.pscheckoutcart" - ps_checkout.prestashop.router: class: 'PrestaShop\Module\PrestashopCheckout\Routing\Router' public: true @@ -469,7 +463,6 @@ services: PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentRefundedQuery: "ps_checkout.query.handler.order.get_order_for_payment_refunded" PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentReversedQuery: "ps_checkout.query.handler.order.get_order_for_payment_reversed" PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForApprovalReversedQuery: "ps_checkout.query.handler.order.get_order_for_approval_reversed" - PrestaShop\Module\PrestashopCheckout\PayPal\Identity\Query\GetClientTokenPayPalQuery: "ps_checkout.query.handler.paypal.identity.get_client_token" PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetCurrentPayPalOrderStatusQuery: "ps_checkout.query.handler.paypal.order.get_current_paypal_order_status" PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetPayPalOrderForCheckoutCompletedQuery: "ps_checkout.query.handler.paypal.order.get_paypal_order_for_checkout_completed" PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetPayPalOrderForOrderConfirmationQuery: "ps_checkout.query.handler.paypal.order.get_paypal_order_for_order_confirmation" @@ -618,12 +611,6 @@ services: arguments: - "@ps_checkout.repository.pscheckoutcart" - ps_checkout.query.handler.paypal.identity.get_client_token: - class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Identity\QueryHandler\GetClientTokenPayPalQueryHandler' - public: true - arguments: - - "@ps_checkout.event.dispatcher" - ps_checkout.query.handler.paypal.order.get_paypal_order_for_checkout_completed: class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\QueryHandler\GetPayPalOrderForCheckoutCompletedQueryHandler' public: true diff --git a/controllers/front/token.php b/controllers/front/token.php index e315d37be..9e0f238c9 100644 --- a/controllers/front/token.php +++ b/controllers/front/token.php @@ -19,7 +19,6 @@ */ use PrestaShop\Module\PrestashopCheckout\Controller\AbstractFrontController; -use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalClientTokenProvider; /** * This controller receive ajax call to retrieve a PayPal Client Token @@ -46,9 +45,6 @@ public function postProcess() ]); } - /** @var PayPalClientTokenProvider $clientTokenProvider */ - $clientTokenProvider = $this->module->getService('ps_checkout.paypal.provider.client_token'); - /** @var \PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository $psCheckoutCartRepository */ $psCheckoutCartRepository = $this->module->getService('ps_checkout.repository.pscheckoutcart'); @@ -60,13 +56,6 @@ public function postProcess() $psCheckoutCart->id_cart = (int) $this->context->cart->id; } - if ($psCheckoutCart->isPaypalClientTokenExpired()) { - $psCheckoutCart->paypal_order = ''; - $psCheckoutCart->paypal_token = $clientTokenProvider->getPayPalClientToken(); - $psCheckoutCart->paypal_token_expire = (new DateTime())->modify('+3550 seconds')->format('Y-m-d H:i:s'); - $psCheckoutCartRepository->save($psCheckoutCart); - } - $this->exitWithResponse([ 'status' => true, 'httpCode' => 200, diff --git a/ps_checkout.php b/ps_checkout.php index c543dd8f7..e89c217db 100755 --- a/ps_checkout.php +++ b/ps_checkout.php @@ -1055,22 +1055,10 @@ public function hookActionFrontControllerSetMedia() if (false !== $psCheckoutCart && $psCheckoutCart->isOrderAvailable()) { $payPalOrderId = $psCheckoutCart->getPaypalOrderId(); $cartFundingSource = $psCheckoutCart->getPaypalFundingSource(); + $payPalClientToken = $psCheckoutCart->getPaypalClientToken(); } // END To be refactored in services - if ($frontControllerValidator->shouldGeneratePayPalClientToken($controller) - && $payPalConfiguration->isHostedFieldsEnabled() && in_array($payPalConfiguration->getCardHostedFieldsStatus(), ['SUBSCRIBED', 'LIMITED'], true) - ) { - try { - /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\PayPalClientTokenProvider $clientTokenProvider */ - $clientTokenProvider = $this->getService('ps_checkout.paypal.provider.client_token'); - - $payPalClientToken = $clientTokenProvider->getPayPalClientToken(); - } catch (Exception $exception) { - $this->getLogger()->warning('Unable to retrieve PayPal Client Token', ['exception' => $exception]); - } - } - Media::addJsDef([ $this->name . 'Version' => $version->getSemVersion(), $this->name . 'AutoRenderDisabled' => (bool) Configuration::get('PS_CHECKOUT_AUTO_RENDER_DISABLED'), diff --git a/src/Api/Payment/Order.php b/src/Api/Payment/Order.php index e76528aa0..9b4b9db89 100644 --- a/src/Api/Payment/Order.php +++ b/src/Api/Payment/Order.php @@ -22,7 +22,6 @@ namespace PrestaShop\Module\PrestashopCheckout\Api\Payment; use PrestaShop\Module\PrestashopCheckout\Api\Payment\Client\PaymentClient; -use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; /** * Handle order requests @@ -122,73 +121,4 @@ public function patch($payload) return $this->post($payload); } - - /** - * @param string $merchantId - * - * @return string - * - * @throws PsCheckoutException - */ - public function generateClientToken($merchantId) - { - $this->setRoute('/payments/order/generate_client_token'); - - $response = $this->post([ - 'return_payload' => true, - 'payee' => [ - 'merchant_id' => $merchantId, - ], - ]); - - if (empty($response['body']) || empty($response['body']['client_token'])) { - $exception = null; - - if (!empty($response['exceptionMessage'])) { - $exception = new \Exception($response['exceptionMessage'], $response['exceptionCode']); - } - - throw new PsCheckoutException('Unable to retrieve PayPal Client Token', PsCheckoutException::MISSING_PAYPAL_CLIENT_TOKEN, $exception); - } - - return $response['body']['client_token']; - } - - /** - * @param string $merchantId - * @param int|null $customerId - * - * @return array{client_token:string, id_token: string, expires_in: int} - * - * @throws PsCheckoutException - */ - public function getClientToken($merchantId, $customerId = null) - { - $this->setRoute('/payments/order/generate_client_token'); - - $payload = [ - 'return_payload' => true, - 'payee' => [ - 'merchant_id' => $merchantId, - ], - ]; - - if ($customerId) { - $payload['customer_id'] = $customerId; - } - - $response = $this->post($payload); - - if (empty($response['body']) || empty($response['body']['client_token'])) { - $exception = null; - - if (!empty($response['exceptionMessage'])) { - $exception = new \Exception($response['exceptionMessage'], $response['exceptionCode']); - } - - throw new PsCheckoutException('Unable to retrieve PayPal Client Token', PsCheckoutException::MISSING_PAYPAL_CLIENT_TOKEN, $exception); - } - - return $response['body']; - } } diff --git a/src/PayPal/Identity/Event/PayPalClientTokenUpdatedEvent.php b/src/PayPal/Identity/Event/PayPalClientTokenUpdatedEvent.php deleted file mode 100644 index 296f9a53f..000000000 --- a/src/PayPal/Identity/Event/PayPalClientTokenUpdatedEvent.php +++ /dev/null @@ -1,111 +0,0 @@ - - * @copyright Since 2007 PrestaShop SA and Contributors - * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 - */ - -namespace PrestaShop\Module\PrestashopCheckout\PayPal\Identity\Event; - -use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; -use PrestaShop\Module\PrestashopCheckout\Cart\ValueObject\CartId; -use PrestaShop\Module\PrestashopCheckout\Event\Event; - -class PayPalClientTokenUpdatedEvent extends Event -{ - /** - * @var CartId - */ - private $cartId; - - /** - * @var string - */ - private $token; - - /** - * @var string - */ - private $tokenId; - - /** - * @var int - */ - private $expireIn; - - /** - * @var int - */ - private $createdAt; - - /** - * @param int $cartId - * @param string $token - * @param string $tokenId - * @param int $expireIn - * @param int $createdAt - * - * @throws CartException - */ - public function __construct($cartId, $token, $tokenId, $expireIn, $createdAt) - { - $this->cartId = new CartId($cartId); - $this->token = $token; - $this->tokenId = $tokenId; - $this->expireIn = $expireIn; - $this->createdAt = $createdAt; - } - - /** - * @return CartId - */ - public function getCartId() - { - return $this->cartId; - } - - /** - * @return string - */ - public function getToken() - { - return $this->token; - } - - /** - * @return string - */ - public function getIdToken() - { - return $this->tokenId; - } - - /** - * @return int - */ - public function getExpireIn() - { - return $this->expireIn; - } - - /** - * @return int - */ - public function getCreatedAt() - { - return $this->createdAt; - } -} diff --git a/src/PayPal/Identity/EventSubscriber/PayPalIdentityEventSubscriber.php b/src/PayPal/Identity/EventSubscriber/PayPalIdentityEventSubscriber.php deleted file mode 100644 index a0b5c15d4..000000000 --- a/src/PayPal/Identity/EventSubscriber/PayPalIdentityEventSubscriber.php +++ /dev/null @@ -1,50 +0,0 @@ - - * @copyright Since 2007 PrestaShop SA and Contributors - * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 - */ - -namespace PrestaShop\Module\PrestashopCheckout\PayPal\Identity\EventSubscriber; - -use PrestaShop\Module\PrestashopCheckout\CommandBus\CommandBusInterface; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; - -class PayPalIdentityEventSubscriber implements EventSubscriberInterface -{ - /** - * @var CommandBusInterface - */ - private $commandBus; - - /** - * @param CommandBusInterface $commandBus - */ - public function __construct(CommandBusInterface $commandBus) - { - $this->commandBus = $commandBus; - } - - /** - * {@inheritdoc} - */ - public static function getSubscribedEvents() - { - return [ - //PayPalClientTokenUpdatedEvent::class => '', - ]; - } -} diff --git a/src/PayPal/Identity/Query/GetClientTokenPayPalQuery.php b/src/PayPal/Identity/Query/GetClientTokenPayPalQuery.php deleted file mode 100644 index ac7c5c1d9..000000000 --- a/src/PayPal/Identity/Query/GetClientTokenPayPalQuery.php +++ /dev/null @@ -1,68 +0,0 @@ - - * @copyright Since 2007 PrestaShop SA and Contributors - * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 - */ - -namespace PrestaShop\Module\PrestashopCheckout\PayPal\Identity\Query; - -use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; -use PrestaShop\Module\PrestashopCheckout\Cart\ValueObject\CartId; -use PrestaShop\Module\PrestashopCheckout\Customer\Exception\CustomerException; -use PrestaShop\Module\PrestashopCheckout\Customer\ValueObject\CustomerId; - -class GetClientTokenPayPalQuery -{ - /** - * @var CartId - */ - private $cartId; - - /** - * @var CustomerId|null - */ - private $customerId; - - /** - * @param int $cartId - * @param int|null $customerId - * - * @throws CartException - * @throws CustomerException - */ - public function __construct($cartId, $customerId = null) - { - $this->cartId = new CartId($cartId); - $this->customerId = $customerId ? new CustomerId($customerId) : null; - } - - /** - * @return CartId - */ - public function getCartId() - { - return $this->cartId; - } - - /** - * @return CustomerId|null - */ - public function getCustomerId() - { - return $this->customerId; - } -} diff --git a/src/PayPal/Identity/Query/GetClientTokenPayPalQueryResult.php b/src/PayPal/Identity/Query/GetClientTokenPayPalQueryResult.php deleted file mode 100644 index 500a6069d..000000000 --- a/src/PayPal/Identity/Query/GetClientTokenPayPalQueryResult.php +++ /dev/null @@ -1,90 +0,0 @@ - - * @copyright Since 2007 PrestaShop SA and Contributors - * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 - */ - -namespace PrestaShop\Module\PrestashopCheckout\PayPal\Identity\Query; - -class GetClientTokenPayPalQueryResult -{ - /** - * @var string - */ - private $clientToken; - - /** - * @var string - */ - private $idToken; - - /** - * @var int - */ - private $expiresIn; - - /** - * @var int - */ - private $createdAt; - - /** - * @param string $clientToken - * @param string $idToken - * @param int $expiresIn - * @param int $createdAt - */ - public function __construct($clientToken, $idToken, $expiresIn, $createdAt) - { - $this->clientToken = $clientToken; - $this->idToken = $idToken; - $this->expiresIn = $expiresIn; - $this->createdAt = $createdAt; - } - - /** - * @return string - */ - public function getClientToken() - { - return $this->clientToken; - } - - /** - * @return string - */ - public function getIdToken() - { - return $this->idToken; - } - - /** - * @return int - */ - public function getExpiresIn() - { - return $this->expiresIn; - } - - /** - * @return int - */ - public function getCreatedAt() - { - return $this->createdAt; - } -} diff --git a/src/PayPal/Identity/QueryHandler/GetClientTokenPayPalQueryHandler.php b/src/PayPal/Identity/QueryHandler/GetClientTokenPayPalQueryHandler.php deleted file mode 100644 index 507571f00..000000000 --- a/src/PayPal/Identity/QueryHandler/GetClientTokenPayPalQueryHandler.php +++ /dev/null @@ -1,82 +0,0 @@ - - * @copyright Since 2007 PrestaShop SA and Contributors - * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 - */ - -namespace PrestaShop\Module\PrestashopCheckout\PayPal\Identity\QueryHandler; - -use Configuration; -use Context; -use PrestaShop\Module\PrestashopCheckout\Api\Payment\Order; -use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; -use PrestaShop\Module\PrestashopCheckout\Event\EventDispatcherInterface; -use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; -use PrestaShop\Module\PrestashopCheckout\PayPal\Identity\Event\PayPalClientTokenUpdatedEvent; -use PrestaShop\Module\PrestashopCheckout\PayPal\Identity\Query\GetClientTokenPayPalQuery; -use PrestaShop\Module\PrestashopCheckout\PayPal\Identity\Query\GetClientTokenPayPalQueryResult; - -class GetClientTokenPayPalQueryHandler -{ - /** - * @var EventDispatcherInterface - */ - private $eventDispatcher; - - /** - * @param EventDispatcherInterface $eventDispatcher - */ - public function __construct(EventDispatcherInterface $eventDispatcher) - { - $this->eventDispatcher = $eventDispatcher; - } - - /** - * @param GetClientTokenPayPalQuery $clientTokenPayPalQuery - * - * @return GetClientTokenPayPalQueryResult - * - * @throws CartException - * @throws PsCheckoutException - */ - public function handle(GetClientTokenPayPalQuery $clientTokenPayPalQuery) - { - $createdAt = time(); - $context = Context::getContext(); - $merchantId = Configuration::get('PS_CHECKOUT_PAYPAL_ID_MERCHANT', null, null, $context->shop->id); - $customerId = $clientTokenPayPalQuery->getCustomerId()->getValue(); - $apiOrder = new Order($context->link); - $response = $apiOrder->getClientToken($merchantId, $customerId); - - $this->eventDispatcher->dispatch( - new PayPalClientTokenUpdatedEvent( - $clientTokenPayPalQuery->getCartId()->getValue(), - $response['client_token'], - $response['id_token'], - (int) $response['expires_in'], - $createdAt - ) - ); - - return new GetClientTokenPayPalQueryResult( - $response['client_token'], - $response['id_token'], - (int) $response['expires_in'], - $createdAt - ); - } -} diff --git a/src/PayPal/PayPalClientTokenProvider.php b/src/PayPal/PayPalClientTokenProvider.php deleted file mode 100644 index 9d8119794..000000000 --- a/src/PayPal/PayPalClientTokenProvider.php +++ /dev/null @@ -1,82 +0,0 @@ - - * @copyright Since 2007 PrestaShop SA and Contributors - * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 - */ - -namespace PrestaShop\Module\PrestashopCheckout\PayPal; - -use Configuration; -use Context; -use DateTime; -use PrestaShop\Module\PrestashopCheckout\Api\Payment\Order; -use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; -use PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository; -use PrestaShopDatabaseException; -use PrestaShopException; -use PsCheckoutCart; -use Validate; - -class PayPalClientTokenProvider -{ - /** - * @var PsCheckoutCartRepository - */ - private $psCheckoutCartRepository; - - public function __construct(PsCheckoutCartRepository $psCheckoutCartRepository) - { - $this->psCheckoutCartRepository = $psCheckoutCartRepository; - } - - /** - * @return string - * - * @throws PsCheckoutException - * @throws PrestaShopDatabaseException - * @throws PrestaShopException - */ - public function getPayPalClientToken() - { - $context = Context::getContext(); - - if (!Validate::isLoadedObject($context->cart)) { - return ''; - } - - $psCheckoutCart = $this->psCheckoutCartRepository->findOneByCartId((int) $context->cart->id); - - if ($psCheckoutCart && !$psCheckoutCart->isPaypalClientTokenExpired()) { - return $psCheckoutCart->getPaypalClientToken(); - } - - $apiOrder = new Order($context->link); - $merchantId = Configuration::get('PS_CHECKOUT_PAYPAL_ID_MERCHANT', null, null, $context->shop->id); - $clientToken = $apiOrder->generateClientToken($merchantId); - - if (!$psCheckoutCart) { - $psCheckoutCart = new PsCheckoutCart(); - $psCheckoutCart->id_cart = (int) $context->cart->id; - } - - $psCheckoutCart->paypal_token = $clientToken; - $psCheckoutCart->paypal_token_expire = (new DateTime())->modify('+3550 seconds')->format('Y-m-d H:i:s'); - $this->psCheckoutCartRepository->save($psCheckoutCart); - - return $clientToken; - } -} diff --git a/src/Validator/FrontControllerValidator.php b/src/Validator/FrontControllerValidator.php index f50e5fba8..55cee0ddc 100644 --- a/src/Validator/FrontControllerValidator.php +++ b/src/Validator/FrontControllerValidator.php @@ -120,25 +120,4 @@ public function shouldLoadFrontCss($controller) return false; } - - /** - * @param string $controller - * - * @return bool - */ - public function shouldGeneratePayPalClientToken($controller) - { - if (false === $this->merchantValidator->merchantIsValid()) { - return false; - } - - switch ($controller) { - // Payment step - case 'orderopc': - case 'order': - return true; - } - - return false; - } } From 39a183581f35f2063bbf71ddc54714d2940f5061 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Thu, 1 Feb 2024 17:22:04 +0100 Subject: [PATCH 10/54] Bump version to 8.3.6.0 --- config.xml | 2 +- ps_checkout.php | 4 +- upgrade/upgrade-8.3.6.0.php | 75 +++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 upgrade/upgrade-8.3.6.0.php diff --git a/config.xml b/config.xml index 53e4406a8..742ae303a 100644 --- a/config.xml +++ b/config.xml @@ -2,7 +2,7 @@ ps_checkout - + diff --git a/ps_checkout.php b/ps_checkout.php index e89c217db..da4baccef 100755 --- a/ps_checkout.php +++ b/ps_checkout.php @@ -123,7 +123,7 @@ class Ps_checkout extends PaymentModule // Needed in order to retrieve the module version easier (in api call headers) than instanciate // the module each time to get the version - const VERSION = '8.3.5.3'; + const VERSION = '8.3.6.0'; const INTEGRATION_DATE = '2022-14-06'; @@ -144,7 +144,7 @@ public function __construct() // We cannot use the const VERSION because the const is not computed by addons marketplace // when the zip is uploaded - $this->version = '8.3.5.3'; + $this->version = '8.3.6.0'; $this->author = 'PrestaShop'; $this->currencies = true; $this->currencies_mode = 'checkbox'; diff --git a/upgrade/upgrade-8.3.6.0.php b/upgrade/upgrade-8.3.6.0.php new file mode 100644 index 000000000..2c11c9813 --- /dev/null +++ b/upgrade/upgrade-8.3.6.0.php @@ -0,0 +1,75 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ +if (!defined('_PS_VERSION_')) { + exit; +} + +/** + * Update main function for module version 8.3.6.0 + * + * @param Ps_checkout $module + * + * @return bool + */ +function upgrade_module_8_3_6_0($module) +{ + // Force PrestaShop to upgrade for all shop to avoid issues + $savedShopContext = Shop::getContext(); + $savedShopId = Shop::getContextShopID(); + $savedGroupShopId = Shop::getContextShopGroupID(); + Shop::setContext(Shop::CONTEXT_ALL); + + try { + $shopsList = Shop::getShops(false, null, true); + + foreach ($shopsList as $shopId) { + // Require the liability shift for all shops + Configuration::updateValue('PS_CHECKOUT_LIABILITY_SHIFT_REQ', '1', false, null, (int) $shopId); + + // Update global value only if it is not already set to SCA_ALWAYS + if (Configuration::get('PS_CHECKOUT_HOSTEDFIELDS_CONTINGENCIES', null, null, $shopId) !== 'SCA_ALWAYS') { + Configuration::updateValue('PS_CHECKOUT_HOSTEDFIELDS_CONTINGENCIES', 'SCA_WHEN_REQUIRED', false, null, (int) $shopId); + } + } + + // Require the liability shift for all shops + Configuration::updateGlobalValue('PS_CHECKOUT_LIABILITY_SHIFT_REQ', '1'); + + // Update global value only if it is not already set to SCA_ALWAYS + if (Configuration::getGlobalValue('PS_CHECKOUT_HOSTEDFIELDS_CONTINGENCIES') !== 'SCA_ALWAYS') { + Configuration::updateGlobalValue('PS_CHECKOUT_HOSTEDFIELDS_CONTINGENCIES', 'SCA_WHEN_REQUIRED'); + } + } catch (Exception $exception) { + PrestaShopLogger::addLog($exception->getMessage(), 3, $exception->getCode(), 'Module', $module->id); + + return false; + } + + // Restore initial PrestaShop shop context + if (Shop::CONTEXT_SHOP === $savedShopContext) { + Shop::setContext($savedShopContext, $savedShopId); + } elseif (Shop::CONTEXT_GROUP === $savedShopContext) { + Shop::setContext($savedShopContext, $savedGroupShopId); + } else { + Shop::setContext($savedShopContext); + } + + return true; +} From cc4a93258d8f01aabf619dbbb85435d42f94ac04 Mon Sep 17 00:00:00 2001 From: Laurynas Date: Tue, 6 Feb 2024 10:33:45 +0200 Subject: [PATCH 11/54] Removed hosted-fields component from sdk link --- src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php b/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php index 0e2758a50..3a1aa5351 100644 --- a/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php +++ b/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php @@ -89,7 +89,6 @@ public function buildLink() } if ($this->shouldIncludeHostedFieldsComponent()) { - $components[] = 'hosted-fields'; $components[] = 'card-fields'; } From 11d85632e67491b90cd213f70d8d9dbf5f036832 Mon Sep 17 00:00:00 2001 From: Bastien Tafforeau Date: Mon, 18 Dec 2023 10:45:34 +0100 Subject: [PATCH 12/54] Load PayPal SDK with PayPal package --- _dev/js/front/package.json | 1 + .../components/common/paypal-sdk.component.js | 49 ++++++------------- .../common/paypal-sdk.component.spec.js | 16 +++++- _dev/js/front/src/config/paypal-sdk.config.js | 38 +++++++------- .../html-templates/prestashop-site-1_7.js | 12 +++++ 5 files changed, 62 insertions(+), 54 deletions(-) diff --git a/_dev/js/front/package.json b/_dev/js/front/package.json index 2c0715c3c..859d3dc00 100644 --- a/_dev/js/front/package.json +++ b/_dev/js/front/package.json @@ -33,6 +33,7 @@ "webpack-merge": "^5.3.0" }, "dependencies": { + "@paypal/paypal-js": "^7.1.1", "@ungap/event-target": "^0.2.2", "classlist-polyfill": "^1.2.0", "promise-polyfill": "8.1.3", diff --git a/_dev/js/front/src/components/common/paypal-sdk.component.js b/_dev/js/front/src/components/common/paypal-sdk.component.js index 154a5d454..53e54bc8d 100644 --- a/_dev/js/front/src/components/common/paypal-sdk.component.js +++ b/_dev/js/front/src/components/common/paypal-sdk.component.js @@ -17,6 +17,7 @@ * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) */ import { BaseComponent } from '../../core/dependency-injection/base.component'; +import { loadScript } from '@paypal/paypal-js'; export class PayPalSdkComponent extends BaseComponent { static Inject = { @@ -29,44 +30,22 @@ export class PayPalSdkComponent extends BaseComponent { } render() { - const script = document.createElement('script'); - - script.setAttribute('async', ''); - script.setAttribute('id', this.config.id); - script.setAttribute('src', this.config.src); - script.setAttribute('data-namespace', this.config.namespace); - - if (this.config.card3dsEnabled) { - script.setAttribute('data-enable-3ds', ''); - } - - if (this.config.cspNonce) { - script.setAttribute('data-csp-nonce', this.config.cspNonce); - } - - if (this.config.orderId) { - script.setAttribute('data-order-id', this.config.orderId); - } - - if (this.config.partnerAttributionId) { - script.setAttribute('data-partner-attribution-id', this.config.partnerAttributionId); - } - - script.setAttribute('data-client-token', this.props.token); - - document.head.appendChild(script); - this.promise = new Promise((resolve, reject) => { - script.onload = () => { - this.sdk = window[this.config.namespace]; - resolve(this.sdk); - }; - - script.onerror = () => { - reject(); - }; + loadScript(this.config.sdkConfig) + .then((paypal) => { + this.sdk = paypal; + resolve(this.sdk); + }) + .catch((error) => { + console.error('Unable to load the PayPal JavaScript SDK.', error); + reject(); + }); }); return this; } + + reload() { + this.render(); + } } diff --git a/_dev/js/front/src/components/common/paypal-sdk.component.spec.js b/_dev/js/front/src/components/common/paypal-sdk.component.spec.js index 942fdcbda..1ebc3543e 100644 --- a/_dev/js/front/src/components/common/paypal-sdk.component.spec.js +++ b/_dev/js/front/src/components/common/paypal-sdk.component.spec.js @@ -18,12 +18,15 @@ */ import { PayPalSdkConfig } from '../../config/paypal-sdk.config'; import { PayPalSdkComponent } from './paypal-sdk.component'; +import * as PrestashopSite1_7 from '../../../test/mocks/html-templates/prestashop-site-1_7'; function buildDIContainerMock() { + PrestashopSite1_7.mockCheckoutVars(); + const payPalSdkConfig = new PayPalSdkConfig(); return { container: { PayPalSdkConfig: { - ...PayPalSdkConfig, + ...payPalSdkConfig, id: 'foo', src: 'url', namespace: 'fooNamespace' @@ -129,4 +132,15 @@ describe('src/components/common/paypal-sdk.component.spec.js', () => { } }); }); + + test('::render() with new Sdk', () => { + const diContainer = buildDIContainerMock(); + const payPalSdkComponent = new PayPalSdkComponent(diContainer); + + expect(payPalSdkComponent.render()).toBe(payPalSdkComponent); + + return payPalSdkComponent.promise.then(() => { + expect(payPalSdkComponent.sdk).toBeDefined(); + }); + }); }); diff --git a/_dev/js/front/src/config/paypal-sdk.config.js b/_dev/js/front/src/config/paypal-sdk.config.js index 1b5a07ab8..51161f92a 100644 --- a/_dev/js/front/src/config/paypal-sdk.config.js +++ b/_dev/js/front/src/config/paypal-sdk.config.js @@ -16,22 +16,24 @@ * @copyright Since 2007 PrestaShop SA and Contributors * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) */ -export const PayPalSdkConfig = { - id: 'ps_checkoutPayPalSdkScript', - namespace: 'ps_checkoutPayPalSdkInstance', - src: window.ps_checkoutPayPalSdkUrl, - card3dsEnabled: window.ps_checkout3dsEnabled, - cspNonce: window.ps_checkoutCspNonce, - orderId: window.ps_checkoutPayPalOrderId, - fundingSource: window.ps_checkoutFundingSource, - clientToken: window.ps_checkoutPayPalClientToken, - buttonCustomization: window.ps_checkoutPayPalButtonConfiguration, - paymentFieldsCustomization: window.ps_checkout.paymentFieldsCustomization, - expressCheckoutButtonCustomization: - window.ps_checkoutExpressCheckoutButtonCustomization, - hostedFieldsCustomization: - window.ps_checkoutHostedFieldsCustomizationConfiguration, - payLaterOfferMessageCustomization: window.ps_checkoutPayLaterOfferMessageCustomization, - payLaterOfferBannerCustomization: window.ps_checkoutPayLaterOfferBannerCustomization, - partnerAttributionId: window.ps_checkoutPartnerAttributionId +export const PayPalSdkConfig = () => { + return { + sdkConfig: { + dataNamespace: 'ps_checkoutPayPalSdkInstance', + orderId: window.ps_checkoutPayPalOrderId, + dataClientToken: window.ps_checkoutPayPalClientToken, + ...window.ps_checkoutPayPalSdkConfig + }, + buttonCustomization: window.ps_checkoutPayPalButtonConfiguration, + paymentFieldsCustomization: window.ps_checkout.paymentFieldsCustomization, + expressCheckoutButtonCustomization: + window.ps_checkoutExpressCheckoutButtonCustomization, + hostedFieldsCustomization: + window.ps_checkoutHostedFieldsCustomizationConfiguration, + payLaterOfferMessageCustomization: + window.ps_checkoutPayLaterOfferMessageCustomization, + payLaterOfferBannerCustomization: + window.ps_checkoutPayLaterOfferBannerCustomization, + partnerAttributionId: window.ps_checkoutPartnerAttributionId + }; }; diff --git a/_dev/js/front/test/mocks/html-templates/prestashop-site-1_7.js b/_dev/js/front/test/mocks/html-templates/prestashop-site-1_7.js index 16f2b5793..c1a3735c8 100644 --- a/_dev/js/front/test/mocks/html-templates/prestashop-site-1_7.js +++ b/_dev/js/front/test/mocks/html-templates/prestashop-site-1_7.js @@ -33,3 +33,15 @@ export function mockProductPage() { .getElementById('product-details') .setAttribute('data-product', JSON.stringify(PRODUCT_DATASET)); } + +export function mockCheckoutVars() { + window.ps_checkoutPayPalOrderId = ''; + window.ps_checkoutPayPalClientToken = ''; + window.ps_checkoutPayPalSdkConfig = { + clientId: 'test', + currency: 'EUR', + intent: 'capture', + integrationDate: '2022-14-06', + components: 'marks,funding-eligibility,buttons' + }; +} From 1d2c229a9db3694396de5e9da000a4ff34e561fc Mon Sep 17 00:00:00 2001 From: Laurynas Date: Mon, 2 Oct 2023 17:30:36 +0300 Subject: [PATCH 13/54] Replaced paypal script creation with using paypal npm lib --- _dev/js/front/package-lock.json | 10562 +--------------- .../common/payment-option.component.js | 2 +- _dev/js/front/src/service/paypal.service.js | 66 +- .../prestashop-ps1_7.service.js | 2 +- .../default-selectors-ps1_7-hummingbird.js | 47 + .../query-selector-ps1_7.service.js | 5 +- config/common.yml | 5 +- ps_checkout.php | 44 +- .../PayPalSdkConfigurationBuilder.php} | 37 +- .../index.php | 0 views/css/payments.css | 7 +- .../hook/displayPaymentByBinaries.tpl | 2 +- views/templates/hook/displayPaymentReturn.tpl | 2 +- views/templates/hook/header.tpl | 21 - 14 files changed, 164 insertions(+), 10638 deletions(-) create mode 100644 _dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_7-hummingbird.js rename src/Builder/{PayPalSdkLink/PayPalSdkLinkBuilder.php => PayPalSdkConfiguration/PayPalSdkConfigurationBuilder.php} (93%) rename src/Builder/{PayPalSdkLink => PayPalSdkConfiguration}/index.php (100%) delete mode 100644 views/templates/hook/header.tpl diff --git a/_dev/js/front/package-lock.json b/_dev/js/front/package-lock.json index 29e3b08db..6f1ba4611 100644 --- a/_dev/js/front/package-lock.json +++ b/_dev/js/front/package-lock.json @@ -1,10512 +1,7 @@ { "name": "ps_checkout-frontoffice", - "lockfileVersion": 2, "requires": true, - "packages": { - "": { - "name": "ps_checkout-frontoffice", - "license": "AFL-3.0", - "dependencies": { - "@ungap/event-target": "^0.2.2", - "classlist-polyfill": "^1.2.0", - "promise-polyfill": "8.1.3", - "url-polyfill": "^1.1.9", - "whatwg-fetch": "^3.0.0" - }, - "devDependencies": { - "@babel/core": "^7.12.3", - "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/preset-env": "^7.12.1", - "babel-eslint": "^10.1.0", - "babel-jest": "^26.6.3", - "babel-loader": "^8.1.0", - "bottlejs": "^2.0.0", - "core-js": "^3.7.0", - "eslint": "^7.12.1", - "eslint-plugin-babel": "^5.3.1", - "eslint-plugin-prettier": "^3.1.4", - "jest": "^26.6.3", - "prettier": "^2.1.2", - "regenerator-runtime": "^0.13.7", - "terser-webpack-plugin": "^4.2.3", - "webpack": "^4.44.2", - "webpack-cli": "^4.1.0", - "webpack-merge": "^5.3.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.1.tgz", - "integrity": "sha512-725AQupWJZ8ba0jbKceeFblZTY90McUBWMwHhkFQ9q1zKPJ95GUktljFcgcsIVwRnTnRKlcYzfiNImg5G9m6ZQ==", - "dev": true - }, - "node_modules/@babel/core": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.3.tgz", - "integrity": "sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.1", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.1", - "@babel/parser": "^7.12.3", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.1.tgz", - "integrity": "sha512-DB+6rafIdc9o72Yc3/Ph5h+6hUjeOp66pF0naQBgUFFuPqzQwIlPTm3xZR7YNvduIMtkDIj2t21LSQwnbCrXvg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.1", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", - "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.10.4" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", - "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", - "dev": true, - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.1.tgz", - "integrity": "sha512-jtBEif7jsPwP27GPHs06v4WBV0KrE8a/P7n0N0sSvHn2hwUCYnolP/CLmz51IzAW4NlN+HuoBtb9QcwnRo9F/g==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.12.1", - "@babel/helper-validator-option": "^7.12.1", - "browserslist": "^4.12.0", - "semver": "^5.5.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz", - "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.10.4" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.1.tgz", - "integrity": "sha512-rsZ4LGvFTZnzdNZR5HZdmJVuXK8834R5QkF3WvcnBhrlVtF0HSIUC6zbreL9MgjTywhKokn8RIYRiq99+DLAxA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-regex": "^7.10.4", - "regexpu-core": "^4.7.1" - } - }, - "node_modules/@babel/helper-define-map": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", - "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz", - "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.1" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", - "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", - "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", - "dev": true, - "dependencies": { - "@babel/types": "^7.10.4" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", - "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.10.4" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz", - "integrity": "sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.1" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.1.tgz", - "integrity": "sha512-ZeC1TlMSvikvJNy1v/wPIazCu3NdOwgYZLIkmIyAsGhqkNpiDoQQRmaCK8YP4Pq3GPTLPV9WXaPCJKvx06JxKA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.1" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", - "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-simple-access": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/helper-validator-identifier": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", - "lodash": "^4.17.19" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.10.4" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", - "dev": true - }, - "node_modules/@babel/helper-regex": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", - "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", - "dev": true, - "dependencies": { - "lodash": "^4.17.19" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz", - "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-wrap-function": "^7.10.4", - "@babel/types": "^7.12.1" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.1.tgz", - "integrity": "sha512-zJjTvtNJnCFsCXVi5rUInstLd/EIVNmIKA1Q9ynESmMBWPWd+7sdR+G4/wdu+Mppfep0XLyG2m7EBPvjCeFyrw==", - "dev": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", - "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.1" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", - "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.1" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", - "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.11.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz", - "integrity": "sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==", - "dev": true - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz", - "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "node_modules/@babel/helpers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.1.tgz", - "integrity": "sha512-9JoDSBGoWtmbay98efmT2+mySkwjzeFeAL9BuWNoVQpkPFQF8SIIFUfY5os9u8wVzglzoiPRSW7cuJmBDUt43g==", - "dev": true, - "dependencies": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1" - } - }, - "node_modules/@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.3.tgz", - "integrity": "sha512-kFsOS0IbsuhO5ojF8Hc8z/8vEIOkylVBrjiZUbLTE3XFe0Qi+uu6HjzQixkFaqr0ZPAMZcBVxEwmsnsLPZ2Xsw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz", - "integrity": "sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.12.1", - "@babel/plugin-syntax-async-generators": "^7.8.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz", - "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", - "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz", - "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz", - "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz", - "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz", - "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.1.tgz", - "integrity": "sha512-MR7Ok+Af3OhNTCxYVjJZHS0t97ydnJZt/DbR4WISO39iDnhiD8XHrY12xuSJ90FFEGjir0Fzyyn7g/zY6hxbxA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz", - "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.1.tgz", - "integrity": "sha512-c2uRpY6WzaVDzynVY9liyykS+kVU+WRZPMPYpkelXH8KBt1oXoI89kPbZKKG/jDT5UK92FTW2fZkZaJhdiBabw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", - "@babel/plugin-syntax-optional-chaining": "^7.8.0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz", - "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz", - "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", - "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", - "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz", - "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz", - "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.12.1" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz", - "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz", - "integrity": "sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz", - "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-define-map": "^7.10.4", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.10.4", - "globals": "^11.1.0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz", - "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz", - "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz", - "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz", - "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz", - "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz", - "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz", - "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz", - "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz", - "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz", - "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz", - "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-simple-access": "^7.12.1", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz", - "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==", - "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.10.4", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-validator-identifier": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz", - "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz", - "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz", - "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz", - "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz", - "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz", - "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz", - "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==", - "dev": true, - "dependencies": { - "regenerator-transform": "^0.14.2" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz", - "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz", - "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz", - "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.1.tgz", - "integrity": "sha512-CiUgKQ3AGVk7kveIaPEET1jNDhZZEl1RPMWdTBE1799bdz++SwqDHStmxfCtDfBhQgCl38YRiSnrMuUMZIWSUQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-regex": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz", - "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz", - "integrity": "sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz", - "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz", - "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.1.tgz", - "integrity": "sha512-H8kxXmtPaAGT7TyBvSSkoSTUK6RHh61So05SyEbpmr0MCZrsNYn7mGMzzeYoOUCdHzww61k8XBft2TaES+xPLg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.12.1", - "@babel/helper-compilation-targets": "^7.12.1", - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-validator-option": "^7.12.1", - "@babel/plugin-proposal-async-generator-functions": "^7.12.1", - "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/plugin-proposal-dynamic-import": "^7.12.1", - "@babel/plugin-proposal-export-namespace-from": "^7.12.1", - "@babel/plugin-proposal-json-strings": "^7.12.1", - "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", - "@babel/plugin-proposal-numeric-separator": "^7.12.1", - "@babel/plugin-proposal-object-rest-spread": "^7.12.1", - "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", - "@babel/plugin-proposal-optional-chaining": "^7.12.1", - "@babel/plugin-proposal-private-methods": "^7.12.1", - "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", - "@babel/plugin-syntax-async-generators": "^7.8.0", - "@babel/plugin-syntax-class-properties": "^7.12.1", - "@babel/plugin-syntax-dynamic-import": "^7.8.0", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.0", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0", - "@babel/plugin-syntax-top-level-await": "^7.12.1", - "@babel/plugin-transform-arrow-functions": "^7.12.1", - "@babel/plugin-transform-async-to-generator": "^7.12.1", - "@babel/plugin-transform-block-scoped-functions": "^7.12.1", - "@babel/plugin-transform-block-scoping": "^7.12.1", - "@babel/plugin-transform-classes": "^7.12.1", - "@babel/plugin-transform-computed-properties": "^7.12.1", - "@babel/plugin-transform-destructuring": "^7.12.1", - "@babel/plugin-transform-dotall-regex": "^7.12.1", - "@babel/plugin-transform-duplicate-keys": "^7.12.1", - "@babel/plugin-transform-exponentiation-operator": "^7.12.1", - "@babel/plugin-transform-for-of": "^7.12.1", - "@babel/plugin-transform-function-name": "^7.12.1", - "@babel/plugin-transform-literals": "^7.12.1", - "@babel/plugin-transform-member-expression-literals": "^7.12.1", - "@babel/plugin-transform-modules-amd": "^7.12.1", - "@babel/plugin-transform-modules-commonjs": "^7.12.1", - "@babel/plugin-transform-modules-systemjs": "^7.12.1", - "@babel/plugin-transform-modules-umd": "^7.12.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", - "@babel/plugin-transform-new-target": "^7.12.1", - "@babel/plugin-transform-object-super": "^7.12.1", - "@babel/plugin-transform-parameters": "^7.12.1", - "@babel/plugin-transform-property-literals": "^7.12.1", - "@babel/plugin-transform-regenerator": "^7.12.1", - "@babel/plugin-transform-reserved-words": "^7.12.1", - "@babel/plugin-transform-shorthand-properties": "^7.12.1", - "@babel/plugin-transform-spread": "^7.12.1", - "@babel/plugin-transform-sticky-regex": "^7.12.1", - "@babel/plugin-transform-template-literals": "^7.12.1", - "@babel/plugin-transform-typeof-symbol": "^7.12.1", - "@babel/plugin-transform-unicode-escapes": "^7.12.1", - "@babel/plugin-transform-unicode-regex": "^7.12.1", - "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.12.1", - "core-js-compat": "^3.6.2", - "semver": "^5.5.0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "node_modules/@babel/runtime": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz", - "integrity": "sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.4" - } - }, - "node_modules/@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", - "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "node_modules/@babel/traverse": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.1.tgz", - "integrity": "sha512-MA3WPoRt1ZHo2ZmoGKNqi20YnPt0B1S0GTZEPhhd+hw2KGUzBlHuVunj6K4sNuK+reEvyiPwtp0cpaqLzJDmAw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.1", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.1", - "@babel/types": "^7.12.1", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "node_modules/@babel/types": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.1.tgz", - "integrity": "sha512-BzSY3NJBKM4kyatSOWh3D/JJ2O3CVzBybHWxtgxnggaxEuaSTTDqeiSb/xk9lrkw2Tbqyivw5ZU4rT+EfznQsA==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "dev": true, - "dependencies": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - }, - "bin": { - "watch": "cli.js" - }, - "engines": { - "node": ">=0.1.95" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.1.tgz", - "integrity": "sha512-XRUeBZ5zBWLYgSANMpThFddrZZkEbGHgUdt5UJjZfnlN9BGCiUBrf+nvbRupSjMvqzwnQN0qwCmOxITt1cfywA==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "dependencies": { - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/core/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" - }, - "engines": { - "node": ">= 10.14.2" - }, - "optionalDependencies": { - "node-notifier": "^8.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@npmcli/move-file": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz", - "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==", - "dev": true, - "dependencies": { - "mkdirp": "^1.0.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/move-file/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", - "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.1.12", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", - "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.0.tgz", - "integrity": "sha512-kSjgDMZONiIfSH1Nxcr5JIRMwUetDki63FSQfpTCz8ogF3Ulqm8+mr5f78dUYs6vMiB6gBusQqfQmBvHZj/lwg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", - "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", - "dev": true - }, - "node_modules/@types/node": { - "version": "14.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz", - "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==", - "dev": true - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-DxZZbyMAM9GWEzXL+BMZROWz9oo6A9EilwwOMET2UVu2uZTqMWS5S69KVtuVKaRjCUpcrOXRalet86/OpG4kqw==", - "dev": true - }, - "node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", - "dev": true - }, - "node_modules/@ungap/event-target": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@ungap/event-target/-/event-target-0.2.2.tgz", - "integrity": "sha512-z0bsRd8APns6CDBVEPEj3p82TiFc1UY8uWNhL+T0ydpQqnpHyPVwwgJ4FC5KP85sLbg80+g+h644UTatwKNi/g==" - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", - "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", - "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", - "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", - "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-code-frame": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", - "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", - "dev": true, - "dependencies": { - "@webassemblyjs/wast-printer": "1.9.0" - } - }, - "node_modules/@webassemblyjs/helper-fsm": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", - "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-module-context": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", - "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.9.0" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", - "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", - "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", - "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", - "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", - "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", - "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/helper-wasm-section": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-opt": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "@webassemblyjs/wast-printer": "1.9.0" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", - "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", - "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", - "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" - } - }, - "node_modules/@webassemblyjs/wast-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", - "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/floating-point-hex-parser": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-code-frame": "1.9.0", - "@webassemblyjs/helper-fsm": "1.9.0", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", - "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/info": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.0.2.tgz", - "integrity": "sha512-FEfLQwmN4pXZSYSrtp+KC84rFanoCIxXFpS2wUvviDCE2fnajwxw2GXzbj83IlH4Dl8Wq8kJjavVwvxv3YJmnw==", - "dev": true, - "dependencies": { - "envinfo": "^7.7.3" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.0.1.tgz", - "integrity": "sha512-WGMaTMTK6NOe29Hw1WBEok9vGLfKg5C6jWzNOS/6HH1YadR+RL+TRWRcSyc81Dzulljhk/Ree9mrDM4Np9GGOQ==", - "dev": true - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "node_modules/ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "dev": true - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "dependencies": { - "type-fest": "^0.11.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-back": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", - "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dev": true, - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - }, - "node_modules/assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "dev": true, - "dependencies": { - "object-assign": "^4.1.1", - "util": "0.10.3" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/assert/node_modules/inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - }, - "node_modules/assert/node_modules/util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "dependencies": { - "inherits": "2.0.1" - } - }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true, - "optional": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "node_modules/babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/babel-jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", - "dev": true, - "dependencies": { - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-loader": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", - "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", - "dev": true, - "dependencies": { - "find-cache-dir": "^2.1.0", - "loader-utils": "^1.4.0", - "mkdirp": "^0.5.3", - "pify": "^4.0.1", - "schema-utils": "^2.6.5" - }, - "engines": { - "node": ">= 6.9" - } - }, - "node_modules/babel-loader/node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/babel-loader/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/babel-loader/node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 8.9.0" - } - }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^26.6.2", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", - "dev": true - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/bn.js": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", - "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", - "dev": true - }, - "node_modules/bottlejs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bottlejs/-/bottlejs-2.0.0.tgz", - "integrity": "sha512-Qhz5dd1YPTOHw0gZ1a1WpJ/oEWsq09BMMbxczeAPgubISij+ZFfah7wfOlHFeFQpWLQkS9TGz5C54tV6v0BlFA==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/braces/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dev": true, - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "node_modules/browserify-rsa/node_modules/bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - }, - "node_modules/browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "dev": true, - "dependencies": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, - "dependencies": { - "pako": "~1.0.5" - } - }, - "node_modules/browserslist": { - "version": "4.14.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.6.tgz", - "integrity": "sha512-zeFYcUo85ENhc/zxHbiIp0LGzzTrE2Pv2JhxvS7kpUb9Q9D38kUX6Bie7pGutJ/5iF5rOxE7CepAuWD56xJ33A==", - "dev": true, - "dependencies": { - "caniuse-lite": "^1.0.30001154", - "electron-to-chromium": "^1.3.585", - "escalade": "^3.1.1", - "node-releases": "^1.1.65" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dev": true, - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true - }, - "node_modules/cacache": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", - "dev": true, - "dependencies": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/cacache/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cache-base/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", - "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.0" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001154", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001154.tgz", - "integrity": "sha512-y9DvdSti8NnYB9Be92ddMZQrcOe04kcQtcxtBx4NkB04+qZ+JUWotnXBJTmxlKudhxNTQ3RRknMwNU2YQl/Org==", - "dev": true - }, - "node_modules/capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "dependencies": { - "rsvp": "^4.8.4" - }, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", - "dev": true, - "optional": true, - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - } - }, - "node_modules/chokidar/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "optional": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "optional": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/chokidar/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "optional": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "node_modules/chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", - "dev": true - }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/classlist-polyfill": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz", - "integrity": "sha1-k1vC39lFiodrJ5YXUUY4vKqWSi4=" - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/clone-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clone-deep/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colorette": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", - "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/command-line-usage": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.0.tgz", - "integrity": "sha512-Ew1clU4pkUeo6AFVDFxCbnN7GIZfXl48HIOQeFQnkO3oOqvpI7wdqtLRwv9iOCZ/7A+z4csVZeiDdEcj8g6Wiw==", - "dev": true, - "dependencies": { - "array-back": "^4.0.0", - "chalk": "^2.4.2", - "table-layout": "^1.0.0", - "typical": "^5.2.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/command-line-usage/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/command-line-usage/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/command-line-usage/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/command-line-usage/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/command-line-usage/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/command-line-usage/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/commander": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", - "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", - "dev": true - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/convert-source-map/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "dev": true, - "dependencies": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/core-js": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.7.0.tgz", - "integrity": "sha512-NwS7fI5M5B85EwpWuIwJN4i/fbisQUwLwiSNUWeXlkAZ0sbBjLEvLvFLf1uzAUV66PcEPt4xCGCmOZSxVf3xzA==", - "dev": true, - "hasInstallScript": true - }, - "node_modules/core-js-compat": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", - "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", - "dev": true, - "dependencies": { - "browserslist": "^4.8.5", - "semver": "7.0.0" - } - }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/cross-spawn/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/cross-spawn/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cross-spawn/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cross-spawn/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - }, - "engines": { - "node": "*" - } - }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/cyclist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", - "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", - "dev": true - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", - "dev": true - }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true, - "engines": { - "node": ">=0.4", - "npm": ">=1.2" - } - }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.3.586", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.586.tgz", - "integrity": "sha512-or8FCbQCRlPZHkOoqBULOI9hzTiStVIQqDLgAPt8pzY+swTrW+89vsqd24Zn+Iv4guAJLxRBD6OR5AmbpabGDA==", - "dev": true - }, - "node_modules/elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", - "dev": true, - "dependencies": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", - "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/enhanced-resolve/node_modules/memory-fs": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", - "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", - "dev": true, - "dependencies": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - }, - "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/envinfo": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.7.3.tgz", - "integrity": "sha512-46+j5QxbPWza0PB1i15nZx0xQ4I/EfQxg9J8Had3b408SV63nEtor2e+oiY63amTo9KTuh2a3XLObNwduxYwwA==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.12.1.tgz", - "integrity": "sha512-HlMTEdr/LicJfN08LB3nM1rRYliDXOmfoO4vj39xN6BLpFzF00hbwBoqHk8UcJ2M/3nlARZWy/mslvGEuZFvsg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.2.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.0", - "esquery": "^1.2.0", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/eslint-plugin-babel": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz", - "integrity": "sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g==", - "dev": true, - "dependencies": { - "eslint-rule-composer": "^0.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz", - "integrity": "sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/eslint-rule-composer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "dependencies": { - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/espree": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", - "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/events": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", - "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/exec-sh": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", - "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", - "dev": true - }, - "node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/execa/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", - "dev": true - }, - "node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "dependencies": { - "flat-cache": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "node_modules/flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", - "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "node_modules/growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-value/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hash-base/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "node_modules/iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, - "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", - "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-local/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "optional": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.0.0.tgz", - "integrity": "sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-docker": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", - "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", - "dev": true, - "optional": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", - "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", - "dev": true - }, - "node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", - "dev": true, - "dependencies": { - "@jest/core": "^26.6.3", - "import-local": "^3.0.2", - "jest-cli": "^26.6.3" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-changed-files": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", - "dev": true, - "dependencies": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "prompts": "^2.0.1", - "yargs": "^15.4.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-jsdom": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", - "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2", - "jsdom": "^16.4.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7" - }, - "engines": { - "node": ">= 10.14.2" - }, - "optionalDependencies": { - "fsevents": "^2.1.2" - } - }, - "node_modules/jest-jasmine2": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", - "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^26.6.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", - "dev": true, - "dependencies": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.7.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "source-map-support": "^0.5.6", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.4.1" - }, - "bin": { - "jest-runtime": "bin/jest-runtime.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", - "dev": true, - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "leven": "^3.1.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^26.6.2", - "string-length": "^4.0.1" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "node_modules/jsdom": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", - "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "acorn": "^7.1.1", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.2.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", - "domexception": "^2.0.1", - "escodegen": "^1.14.1", - "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", - "nwsapi": "^2.2.0", - "parse5": "5.1.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.2.3", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "node_modules/json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "node_modules/loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", - "dev": true, - "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" - } - }, - "node_modules/loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/loader-utils/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/make-dir/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "dependencies": { - "tmpl": "1.0.x" - } - }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dev": true, - "dependencies": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/micromatch/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - }, - "node_modules/mime-db": { - "version": "1.45.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", - "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.28", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", - "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", - "dev": true, - "dependencies": { - "mime-db": "1.45.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "dev": true, - "dependencies": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dev": true, - "dependencies": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", - "dev": true, - "optional": true - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node_modules/node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", - "dev": true, - "dependencies": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - } - }, - "node_modules/node-libs-browser/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "node_modules/node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/node-notifier": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", - "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", - "dev": true, - "optional": true, - "dependencies": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" - } - }, - "node_modules/node-notifier/node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "optional": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-notifier/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-releases": { - "version": "1.1.65", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.65.tgz", - "integrity": "sha512-YpzJOe2WFIW0V4ZkJQd/DGR/zdVwc/pI4Nl1CZrBO19FdRcSTmsuhdttw9rsTzzJLrNcSloLiBbEYx1C4f6gpA==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-visit/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.pick/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "node_modules/p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "node_modules/parallel-transform": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", - "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", - "dev": true, - "dependencies": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dev": true, - "dependencies": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", - "dev": true - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", - "dev": true - }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true, - "optional": true - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/pbkdf2": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", - "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", - "dev": true, - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "dependencies": { - "node-modules-regexp": "^1.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", - "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true - }, - "node_modules/promise-polyfill": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz", - "integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==" - }, - "node_modules/prompts": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", - "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, - "dependencies": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, - "node_modules/pumpify/node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "node_modules/react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", - "dev": true - }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dev": true, - "optional": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/rechoir": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", - "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", - "dev": true, - "dependencies": { - "resolve": "^1.9.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/reduce-flatten": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", - "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", - "dev": true - }, - "node_modules/regjsparser": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", - "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "node_modules/repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.19" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "request": "^2.34" - } - }, - "node_modules/request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "engines": { - "node": ">=0.12.0" - }, - "peerDependencies": { - "request": "^2.34" - } - }, - "node_modules/request-promise-native/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", - "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.0.0", - "path-parse": "^1.0.6" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true, - "engines": { - "node": "6.* || >= 7.*" - } - }, - "node_modules/run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "dev": true, - "dependencies": { - "aproba": "^1.1.1" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "dependencies": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "bin": { - "sane": "src/cli.js" - }, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/sane/node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/sane/node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/sane/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/sane/node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/sane/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, - "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true - }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ssri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", - "dev": true, - "dependencies": { - "figgy-pudding": "^3.5.1" - } - }, - "node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "dev": true, - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "node_modules/stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "dev": true, - "dependencies": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", - "dev": true - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/string-length": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", - "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/table-layout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.1.tgz", - "integrity": "sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==", - "dev": true, - "dependencies": { - "array-back": "^4.0.1", - "deep-extend": "~0.6.0", - "typical": "^5.2.0", - "wordwrapjs": "^4.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/tar/node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", - "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", - "dev": true, - "dependencies": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz", - "integrity": "sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==", - "dev": true, - "dependencies": { - "cacache": "^15.0.5", - "find-cache-dir": "^3.3.1", - "jest-worker": "^26.5.0", - "p-limit": "^3.0.2", - "schema-utils": "^3.0.0", - "serialize-javascript": "^5.0.1", - "source-map": "^0.6.1", - "terser": "^5.3.4", - "webpack-sources": "^1.4.3" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/terser-webpack-plugin/node_modules/cacache": { - "version": "15.0.5", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz", - "integrity": "sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==", - "dev": true, - "dependencies": { - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.0", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/terser-webpack-plugin/node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/terser-webpack-plugin/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin/node_modules/p-limit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", - "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/terser-webpack-plugin/node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ssri": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.0.tgz", - "integrity": "sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==", - "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/terser-webpack-plugin/node_modules/terser": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.8.tgz", - "integrity": "sha512-zVotuHoIfnYjtlurOouTazciEfL7V38QMAOhGqpXDEg6yT13cF4+fEP9b0rrCEQTn+tT46uxgFsTZzhygk+CzQ==", - "dev": true, - "dependencies": { - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.19" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin/node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "dev": true - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "dev": true, - "dependencies": { - "setimmediate": "^1.0.4" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "dev": true, - "dependencies": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dev": true, - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "node_modules/url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/url-polyfill": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.12.tgz", - "integrity": "sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==" - }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/util": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "dev": true, - "dependencies": { - "inherits": "2.0.3" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "optional": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", - "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz", - "integrity": "sha512-uXUVqNUCLa0AH1vuVxzi+MI4RfxEOKt9pBgKwHbgH7st8Kv2P1m+jvWNnektzBh5QShF3ODgKmUFCf38LnVz1g==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", - "dev": true - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "dependencies": { - "makeerror": "1.0.x" - } - }, - "node_modules/watchpack": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz", - "integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" - }, - "optionalDependencies": { - "chokidar": "^3.4.1", - "watchpack-chokidar2": "^2.0.0" - } - }, - "node_modules/watchpack-chokidar2": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz", - "integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==", - "dev": true, - "optional": true, - "dependencies": { - "chokidar": "^2.1.8" - }, - "engines": { - "node": "<8.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "optional": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/watchpack-chokidar2/node_modules/anymatch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "optional": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "optional": true, - "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "node_modules/watchpack-chokidar2/node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "nan": "^2.12.1" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "optional": true, - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "optional": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "optional": true, - "dependencies": { - "binary-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "optional": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "optional": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/webpack": { - "version": "4.44.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz", - "integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/wasm-edit": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "acorn": "^6.4.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.3.0", - "eslint-scope": "^4.0.3", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.3", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.3", - "watchpack": "^1.7.4", - "webpack-sources": "^1.4.1" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/webpack-cli": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.1.0.tgz", - "integrity": "sha512-NdhxXMZmoik62Y05t0h1y65LjBM7BwFPq311ihXuMM3RY6dlc4KkCTyHLzTuBEc+bqq6d3xh+CWmU0xRexNJBA==", - "dev": true, - "dependencies": { - "@webpack-cli/info": "^1.0.2", - "@webpack-cli/serve": "^1.0.1", - "ansi-escapes": "^4.3.1", - "colorette": "^1.2.1", - "command-line-usage": "^6.1.0", - "commander": "^6.0.0", - "enquirer": "^2.3.4", - "execa": "^4.0.0", - "import-local": "^3.0.2", - "interpret": "^2.0.0", - "rechoir": "^0.7.0", - "v8-compile-cache": "^2.1.0", - "webpack-merge": "^4.2.2" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack-cli/node_modules/webpack-merge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", - "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", - "dev": true, - "dependencies": { - "lodash": "^4.17.15" - } - }, - "node_modules/webpack-merge": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.3.0.tgz", - "integrity": "sha512-4PtsBAWnmJULIJYviiPq4BxwAykbAgGMheyEVaemj2bJI54h+p/gnlbXZEH2EM0IYC3blOE1Qm6kzKlc06N1UQ==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "node_modules/webpack/node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/terser-webpack-plugin": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", - "dev": true, - "dependencies": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" - }, - "engines": { - "node": ">= 6.9.0" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-fetch": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz", - "integrity": "sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ==" - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^2.0.2", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "node_modules/wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrapjs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.0.tgz", - "integrity": "sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==", - "dev": true, - "dependencies": { - "reduce-flatten": "^2.0.0", - "typical": "^5.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", - "dev": true, - "dependencies": { - "errno": "~0.1.7" - } - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz", - "integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - } - }, + "lockfileVersion": 1, "dependencies": { "@babel/code-frame": { "version": "7.10.4", @@ -11891,6 +1386,21 @@ } } }, + "@paypal/paypal-js": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@paypal/paypal-js/-/paypal-js-7.0.3.tgz", + "integrity": "sha512-Mpq0TGKzypi02Iw4p11eq5+dxVKcuJ+98UDrxLRbqZcr8pBRFPX+jqPFkVq6hzs3sHxwIuMPFCxnrckxxLSznw==", + "requires": { + "promise-polyfill": "^8.3.0" + }, + "dependencies": { + "promise-polyfill": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.3.0.tgz", + "integrity": "sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==" + } + } + }, "@sinonjs/commons": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", @@ -15626,8 +5136,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "26.0.0", @@ -18062,23 +7571,6 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, "string-length": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", @@ -18117,6 +7609,23 @@ } } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", @@ -19281,8 +8790,7 @@ "version": "7.4.3", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz", "integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==", - "dev": true, - "requires": {} + "dev": true }, "xml-name-validator": { "version": "3.0.0", diff --git a/_dev/js/front/src/components/common/payment-option.component.js b/_dev/js/front/src/components/common/payment-option.component.js index 76cb926c7..f09872a22 100644 --- a/_dev/js/front/src/components/common/payment-option.component.js +++ b/_dev/js/front/src/components/common/payment-option.component.js @@ -80,7 +80,7 @@ export class PaymentOptionComponent extends BaseComponent { : this.$('funding-source.name.default'); let element = Array.prototype.slice .call(this.data.HTMLElementContainer.querySelectorAll('*')) - .find(item => item.innerHTML.trim() === label.trim()); + .find(item => item.innerText.trim() === label.trim()); if (!element) { console.error('HTMLElement label "' + label.trim() + '" not found.'); diff --git a/_dev/js/front/src/service/paypal.service.js b/_dev/js/front/src/service/paypal.service.js index 13e39362e..a87c83084 100644 --- a/_dev/js/front/src/service/paypal.service.js +++ b/_dev/js/front/src/service/paypal.service.js @@ -127,7 +127,7 @@ export class PayPalService extends BaseClass { if (fundingSource === 'paypal') { return style; - } else if(fundingSource === 'paylater') { + } else if (fundingSource === 'paylater') { return { shape: style.shape, color: style.color }; } @@ -178,7 +178,7 @@ export class PayPalService extends BaseClass { }, ...events }) - .then(hostedFields => { + .then((hostedFields) => { const numberField = document.querySelector(fieldSelectors.number); const cvvField = document.querySelector(fieldSelectors.cvv); const expirationDateField = document.querySelector( @@ -203,36 +203,36 @@ export class PayPalService extends BaseClass { return hostedFields; }) - .then(hostedFields => { - hostedFields.on('focus', event => { + .then((hostedFields) => { + hostedFields.on('focus', (event) => { window.ps_checkout.events.dispatchEvent( new CustomEvent('hostedFieldsFocus', { detail: { ps_checkout: window.ps_checkout, event: event } }) ); }); - hostedFields.on('blur', event => { + hostedFields.on('blur', (event) => { window.ps_checkout.events.dispatchEvent( new CustomEvent('hostedFieldsBlur', { detail: { ps_checkout: window.ps_checkout, event: event } }) ); }); - hostedFields.on('empty', event => { + hostedFields.on('empty', (event) => { window.ps_checkout.events.dispatchEvent( new CustomEvent('hostedFieldsEmpty', { detail: { ps_checkout: window.ps_checkout, event: event } }) ); }); - hostedFields.on('notEmpty', event => { + hostedFields.on('notEmpty', (event) => { window.ps_checkout.events.dispatchEvent( new CustomEvent('hostedFieldsNotEmpty', { detail: { ps_checkout: window.ps_checkout, event: event } }) ); }); - hostedFields.on('validityChange', event => { + hostedFields.on('validityChange', (event) => { window.ps_checkout.events.dispatchEvent( new CustomEvent('hostedFieldsValidityChange', { detail: { ps_checkout: window.ps_checkout, event: event } @@ -246,7 +246,7 @@ export class PayPalService extends BaseClass { }) ); }); - hostedFields.on('cardTypeChange', event => { + hostedFields.on('cardTypeChange', (event) => { window.ps_checkout.events.dispatchEvent( new CustomEvent('hostedFieldsCardTypeChange', { detail: { ps_checkout: window.ps_checkout, event: event } @@ -304,7 +304,6 @@ export class PayPalService extends BaseClass { async getCardFields(fieldSelectors, options) { const cardFields = this.sdk.CardFields(options); - const nameField = cardFields.NameField({ placeholder: this.$('paypal.hosted-fields.placeholder.card-name') }); @@ -315,12 +314,9 @@ export class PayPalService extends BaseClass { placeholder: this.$('paypal.hosted-fields.placeholder.expiration-date') }); const cvvField = cardFields.CVVField({ - placeholder: this.$( - 'paypal.hosted-fields.placeholder.cvv' - ) + placeholder: this.$('paypal.hosted-fields.placeholder.cvv') }); - // await Promise.all( // [ // cardNameField.render(nameField), @@ -338,7 +334,7 @@ export class PayPalService extends BaseClass { await cvvField.render(fieldSelectors.cvv); await nameField.render(fieldSelectors.name); } catch (e) { - return console.error("Failed to render CardFields", e); + return console.error('Failed to render CardFields', e); } const nameLabel = document.querySelector( @@ -347,7 +343,9 @@ export class PayPalService extends BaseClass { const numberLabel = document.querySelector( `label[for="${fieldSelectors.number.id}"]` ); - const cvvLabel = document.querySelector(`label[for="${fieldSelectors.cvv.id}"]`); + const cvvLabel = document.querySelector( + `label[for="${fieldSelectors.cvv.id}"]` + ); const expirationDateLabel = document.querySelector( `label[for="${fieldSelectors.expiry.id}"]` ); @@ -355,7 +353,9 @@ export class PayPalService extends BaseClass { nameLabel.innerHTML = this.$('paypal.hosted-fields.label.card-name'); numberLabel.innerHTML = this.$('paypal.hosted-fields.label.card-number'); cvvLabel.innerHTML = this.$('paypal.hosted-fields.label.cvv'); - expirationDateLabel.innerHTML = this.$('paypal.hosted-fields.label.expiration-date'); + expirationDateLabel.innerHTML = this.$( + 'paypal.hosted-fields.label.expiration-date' + ); return cardFields; } @@ -367,16 +367,25 @@ export class PayPalService extends BaseClass { this.configPrestaShop.fundingSourcesSorted || paypalFundingSources ) .filter( - fundingSource => paypalFundingSources.indexOf(fundingSource) >= 0 + (fundingSource) => paypalFundingSources.indexOf(fundingSource) >= 0 ) - .map(fundingSource => ({ + .map((fundingSource) => ({ name: fundingSource, mark: this.sdk.Marks({ fundingSource }) })) .filter((fundingSource) => { - if (fundingSource.name === 'card' && this.configPrestaShop.hostedFieldsEnabled && !this.isCardFieldsEligible()) { - console.log(this.configPrestaShop.hostedFieldsEnabled, this.isCardFieldsEligible()); - console.error('Card Fields (CCF) eligibility is declined. Switching to PayPal branded card fields (SCF)'); + if ( + fundingSource.name === 'card' && + this.configPrestaShop.hostedFieldsEnabled && + !this.isCardFieldsEligible() + ) { + console.log( + this.configPrestaShop.hostedFieldsEnabled, + this.isCardFieldsEligible() + ); + console.error( + 'Card Fields (CCF) eligibility is declined. Switching to PayPal branded card fields (SCF)' + ); } console.log(fundingSource.name, fundingSource.mark.isEligible()); @@ -457,11 +466,14 @@ export class PayPalService extends BaseClass { */ getPaymentFields(fundingSource, fields = {}) { console.log(this.sdk.PaymentFields); - return this.sdk.PaymentFields && this.sdk.PaymentFields({ - fundingSource: fundingSource, - style: this.getPaymentFieldsCustomizationStyle(fundingSource), - fields: fields - }); + return ( + this.sdk.PaymentFields && + this.sdk.PaymentFields({ + fundingSource: fundingSource, + style: this.getPaymentFieldsCustomizationStyle(fundingSource), + fields: fields + }) + ); } /** diff --git a/_dev/js/front/src/service/prestashop.service/prestashop-ps1_7.service.js b/_dev/js/front/src/service/prestashop.service/prestashop-ps1_7.service.js index 1f4cbb789..f00d91569 100644 --- a/_dev/js/front/src/service/prestashop.service/prestashop-ps1_7.service.js +++ b/_dev/js/front/src/service/prestashop.service/prestashop-ps1_7.service.js @@ -58,7 +58,7 @@ export class PrestashopPs1_7Service { if (document.body.id !== 'checkout') return false; const step = document.querySelector('#checkout-personal-information-step'); - return step && step.classList.contains('-current'); + return step && (step.classList.contains('-current') || step.classList.contains('step--current')); } static isIframeProductPage() { diff --git a/_dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_7-hummingbird.js b/_dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_7-hummingbird.js new file mode 100644 index 000000000..6a0d68c1b --- /dev/null +++ b/_dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_7-hummingbird.js @@ -0,0 +1,47 @@ +/** + * Copyright since 2007 PrestaShop SA and Contributors + * PrestaShop is an International Registered Trademark & Property of PrestaShop SA + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License 3.0 (AFL-3.0) + * that is bundled with this package in the file LICENSE.md. + * It is also available through the world-wide-web at this URL: + * https://opensource.org/licenses/AFL-3.0 + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@prestashop.com so we can send you a copy immediately. + * + * @author PrestaShop SA + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) + */ +export const DefaultSelectors1_7Hummingbird = { + BASE_PAYMENT_CONFIRMATION: '#payment-confirmation [type="submit"]', + + CONDITIONS_CHECKBOXES: '#conditions-to-approve input[type="checkbox"]', + + LOADER_PARENT: 'body', + + NOTIFICATION_CONDITIONS: '.accept-cgv', + NOTIFICATION_PAYMENT_CANCELLED: '#ps_checkout-canceled', + NOTIFICATION_PAYMENT_ERROR: '#ps_checkout-error', + NOTIFICATION_PAYMENT_ERROR_TEXT: '#ps_checkout-error-text', + + PAYMENT_OPTIONS: '.payment__list', + PAYMENT_OPTIONS_LOADER: '#ps_checkout-loader', + PAYMENT_OPTION_RADIOS: + '.payment__list input[type="radio"][name="payment-option"]', + + EXPRESS_CHECKOUT_CONTAINER_PRODUCT_PAGE: + '#product .product__add-to-cart .product__minimal-quantity', + EXPRESS_CHECKOUT_CONTAINER_CART_PAGE: + '#cart .cart-summary .cart-detailed__actions', + EXPRESS_CHECKOUT_CONTAINER_CHECKOUT_PAGE: + '#checkout-personal-information-step .step__content', + + PAY_LATER_OFFER_MESSAGE_CONTAINER_PRODUCT: '.product__prices', + PAY_LATER_OFFER_MESSAGE_CONTAINER_CART_SUMMARY: '.cart-summary__totals', + + PAY_LATER_BANNER_CONTAINER: '#notifications .container' +}; diff --git a/_dev/js/front/src/service/query-selector.service/query-selector-ps1_7.service.js b/_dev/js/front/src/service/query-selector.service/query-selector-ps1_7.service.js index 77bedc006..49b42f84f 100644 --- a/_dev/js/front/src/service/query-selector.service/query-selector-ps1_7.service.js +++ b/_dev/js/front/src/service/query-selector.service/query-selector-ps1_7.service.js @@ -17,9 +17,12 @@ * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) */ import { DefaultSelectors1_7 } from './default-selectors/default-selectors-ps1_7'; +import { DefaultSelectors1_7Hummingbird } from './default-selectors/default-selectors-ps1_7-hummingbird'; + +const isThemeHummingbird = document.querySelector('body>main#wrapper') !== null; const SELECTORS = { - ...DefaultSelectors1_7, + ...(isThemeHummingbird ? DefaultSelectors1_7Hummingbird : DefaultSelectors1_7), ...(window.ps_checkout.selectors || {}) }; diff --git a/config/common.yml b/config/common.yml index 5727a740b..5f8a6dc35 100644 --- a/config/common.yml +++ b/config/common.yml @@ -114,14 +114,15 @@ services: arguments: - "@ps_checkout.configuration" - ps_checkout.sdk.paypal.linkbuilder: - class: 'PrestaShop\Module\PrestashopCheckout\Builder\PayPalSdkLink\PayPalSdkLinkBuilder' + ps_checkout.sdk.paypal.configurationbuilder: + class: 'PrestaShop\Module\PrestashopCheckout\Builder\PaypalSdkConfiguration\PayPalSdkConfigurationBuilder' public: true arguments: - "@ps_checkout.paypal.configuration" - "@ps_checkout.pay_later.configuration" - "@ps_checkout.funding_source.configuration.repository" - "@ps_checkout.express_checkout.configuration" + - '@ps_checkout.context.shop' ps_checkout.repository.prestashop.account: class: 'PrestaShop\Module\PrestashopCheckout\Repository\PsAccountRepository' diff --git a/ps_checkout.php b/ps_checkout.php index da4baccef..11b4485db 100755 --- a/ps_checkout.php +++ b/ps_checkout.php @@ -42,7 +42,6 @@ class Ps_checkout extends PaymentModule 'displayPaymentTop', 'displayPaymentByBinaries', 'actionFrontControllerSetMedia', - 'displayHeader', 'actionObjectOrderPaymentAddAfter', 'actionObjectOrderPaymentUpdateAfter', 'displayPaymentReturn', @@ -115,7 +114,7 @@ class Ps_checkout extends PaymentModule 'PS_CHECKOUT_LIVE_STEP_VIEWED' => false, 'PS_CHECKOUT_INTEGRATION_DATE' => self::INTEGRATION_DATE, 'PS_CHECKOUT_WEBHOOK_SECRET' => '', - 'PS_CHECKOUT_LIABILITY_SHIFT_REQ' => '0', + 'PS_CHECKOUT_LIABILITY_SHIFT_REQ' => '1', ]; public $confirmUninstall; @@ -1001,8 +1000,8 @@ public function hookActionFrontControllerSetMedia() return; } - /** @var \PrestaShop\Module\PrestashopCheckout\Builder\PayPalSdkLink\PayPalSdkLinkBuilder $payPalSdkLinkBuilder */ - $payPalSdkLinkBuilder = $this->getService('ps_checkout.sdk.paypal.linkbuilder'); + /** @var \PrestaShop\Module\PrestashopCheckout\Builder\PaypalSdkConfiguration\PayPalSdkConfigurationBuilder $payPalSdkConfigurationBuilder */ + $payPalSdkConfigurationBuilder = $this->getService('ps_checkout.sdk.paypal.configurationbuilder'); /** @var \PrestaShop\Module\PrestashopCheckout\ExpressCheckout\ExpressCheckoutConfiguration $expressCheckoutConfiguration */ $expressCheckoutConfiguration = $this->getService('ps_checkout.express_checkout.configuration'); @@ -1073,7 +1072,7 @@ public function hookActionFrontControllerSetMedia() $this->name . 'ExpressCheckoutUrl' => $this->context->link->getModuleLink($this->name, 'ExpressCheckout', [], true), $this->name . 'CheckoutUrl' => $this->getCheckoutPageUrl(), $this->name . 'ConfirmUrl' => $this->context->link->getPageLink('order-confirmation', true, (int) $this->context->language->id), - $this->name . 'PayPalSdkUrl' => $payPalSdkLinkBuilder->buildLink(), + $this->name . 'PayPalSdkConfig' => $payPalSdkConfigurationBuilder->buildConfiguration(), $this->name . 'PayPalClientToken' => $payPalClientToken, $this->name . 'PayPalOrderId' => $payPalOrderId, $this->name . 'FundingSource' => $cartFundingSource, @@ -1586,41 +1585,6 @@ private function getCheckoutPageUrl() ); } - public function hookDisplayHeader() - { - if (!$this->merchantIsValid()) { - return ''; - } - - $controller = Tools::getValue('controller'); - - if (empty($controller) && isset($this->context->controller->php_self)) { - $controller = $this->context->controller->php_self; - } - - /** @var \PrestaShop\Module\PrestashopCheckout\Validator\FrontControllerValidator $frontControllerValidator */ - $frontControllerValidator = $this->getService('ps_checkout.validator.front_controller'); - - if ($frontControllerValidator->shouldLoadFrontJS($controller)) { - // No need to prefetch if script will be loaded - return ''; - } - - /** @var \PrestaShop\Module\PrestashopCheckout\Builder\PayPalSdkLink\PayPalSdkLinkBuilder $payPalSdkLinkBuilder */ - $payPalSdkLinkBuilder = $this->getService('ps_checkout.sdk.paypal.linkbuilder'); - - $this->context->smarty->assign([ - 'contentToPrefetch' => [ - [ - 'link' => $payPalSdkLinkBuilder->buildLink(), - 'type' => 'script', - ], - ], - ]); - - return $this->display(__FILE__, 'views/templates/hook/header.tpl'); - } - /** * When an OrderPayment is created we should update fields payment_method and transaction_id * diff --git a/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php b/src/Builder/PayPalSdkConfiguration/PayPalSdkConfigurationBuilder.php similarity index 93% rename from src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php rename to src/Builder/PayPalSdkConfiguration/PayPalSdkConfigurationBuilder.php index 3a1aa5351..b5b2dc249 100644 --- a/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php +++ b/src/Builder/PayPalSdkConfiguration/PayPalSdkConfigurationBuilder.php @@ -18,18 +18,19 @@ * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 */ -namespace PrestaShop\Module\PrestashopCheckout\Builder\PayPalSdkLink; +namespace PrestaShop\Module\PrestashopCheckout\Builder\PaypalSdkConfiguration; use PrestaShop\Module\PrestashopCheckout\Environment\PaypalEnv; use PrestaShop\Module\PrestashopCheckout\ExpressCheckout\ExpressCheckoutConfiguration; use PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceConfigurationRepository; use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration; use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalPayLaterConfiguration; +use PrestaShop\Module\PrestashopCheckout\ShopContext; /** * Build sdk link */ -class PayPalSdkLinkBuilder +class PayPalSdkConfigurationBuilder { const BASE_LINK = 'https://www.paypal.com/sdk/js'; @@ -51,6 +52,9 @@ class PayPalSdkLinkBuilder /** @var ExpressCheckoutConfiguration */ private $expressCheckoutConfiguration; + /** @var ShopContext */ + private $shopContext; + /** @var array */ private static $cache = []; @@ -64,20 +68,20 @@ public function __construct( PayPalConfiguration $configuration, PayPalPayLaterConfiguration $payLaterConfiguration, FundingSourceConfigurationRepository $fundingSourceConfigurationRepository, - ExpressCheckoutConfiguration $expressCheckoutConfiguration + ExpressCheckoutConfiguration $expressCheckoutConfiguration, + ShopContext $shopContext ) { $this->configuration = $configuration; $this->payLaterConfiguration = $payLaterConfiguration; $this->fundingSourceConfigurationRepository = $fundingSourceConfigurationRepository; $this->expressCheckoutConfiguration = $expressCheckoutConfiguration; + $this->shopContext = $shopContext; } /** - * @todo To be refactored with Service Container and Dependency Injection - * - * @return string + * @return array */ - public function buildLink() + public function buildConfiguration() { $components = [ 'marks', @@ -97,24 +101,27 @@ public function buildLink() } $params = [ - 'client-id' => (new PaypalEnv())->getPaypalClientId(), - 'merchant-id' => $this->configuration->getMerchantId(), + 'clientId' => (new PaypalEnv())->getPaypalClientId(), + 'merchantId' => $this->configuration->getMerchantId(), 'currency' => \Context::getContext()->currency->iso_code, 'intent' => strtolower($this->configuration->getIntent()), 'commit' => 'order' === $this->getPageName() ? 'true' : 'false', 'vault' => 'false', - 'integration-date' => $this->configuration->getIntegrationDate(), + 'integrationDate' => $this->configuration->getIntegrationDate(), + 'dataPartnerAttributionId' => $this->shopContext->getBnCode(), + 'dataCspNonce' => $this->configuration->getCSPNonce(), + 'dataEnable3ds' => $this->configuration->is3dSecureEnabled(), ]; if ('SANDBOX' === $this->configuration->getPaymentMode()) { - $params['debug'] = 'true'; -// $params['buyer-country'] = $this->getCountry(); +// $params['debug'] = 'true'; + $params['buyerCountry'] = $this->getCountry(); } $fundingSourcesDisabled = $this->getFundingSourcesDisabled(); if (false === empty($fundingSourcesDisabled)) { - $params['disable-funding'] = implode(',', $fundingSourcesDisabled); + $params['disableFunding'] = implode(',', $fundingSourcesDisabled); } $eligibleAlternativePaymentMethods = $this->getEligibleAlternativePaymentMethods(); @@ -133,12 +140,12 @@ public function buildLink() } if (false === empty($eligibleAlternativePaymentMethods)) { - $params['enable-funding'] = implode(',', $eligibleAlternativePaymentMethods); + $params['enableFunding'] = implode(',', $eligibleAlternativePaymentMethods); } $params['components'] = implode(',', $components); - return self::BASE_LINK . '?' . urldecode(http_build_query($params)); + return $params; } /** diff --git a/src/Builder/PayPalSdkLink/index.php b/src/Builder/PayPalSdkConfiguration/index.php similarity index 100% rename from src/Builder/PayPalSdkLink/index.php rename to src/Builder/PayPalSdkConfiguration/index.php diff --git a/views/css/payments.css b/views/css/payments.css index 9879fae5e..6863c430f 100755 --- a/views/css/payments.css +++ b/views/css/payments.css @@ -31,6 +31,10 @@ #checkout-personal-information-step #ps-checkout-express-button { display: flex; flex-flow: row wrap; + + /*Fixes z-index problem on hummingbird*/ + position: relative; + z-index: 1; } .product-add-to-cart #ps-checkout-express-button.disabled{ display: none!important; @@ -357,7 +361,8 @@ label[for="ps_checkout-hosted-fields-card-cvv"] { } .js-payment-ps_checkout.disabled .ps_checkout-button[data-funding-source="card"] button:disabled { - opacity: initial; + /*TODO: This causes the button to be seen as not disabled on hummingbird. Do we keep it?*/ + /*opacity: initial;*/ } .ps_checkout.payment-method-logo-block { diff --git a/views/templates/hook/displayPaymentByBinaries.tpl b/views/templates/hook/displayPaymentByBinaries.tpl index 0cd25ca81..6a75819eb 100644 --- a/views/templates/hook/displayPaymentByBinaries.tpl +++ b/views/templates/hook/displayPaymentByBinaries.tpl @@ -18,7 +18,7 @@ *} {foreach from=$paymentOptions item="fundingSource"} -
+

{l s='You must accept the terms and conditions to be able to process your order.' mod='ps_checkout'}

diff --git a/views/templates/hook/displayPaymentReturn.tpl b/views/templates/hook/displayPaymentReturn.tpl index 182d1e906..ff0421437 100644 --- a/views/templates/hook/displayPaymentReturn.tpl +++ b/views/templates/hook/displayPaymentReturn.tpl @@ -22,7 +22,7 @@
-

+

{$translations.blockTitle|escape:'html':'UTF-8'}

diff --git a/views/templates/hook/header.tpl b/views/templates/hook/header.tpl deleted file mode 100644 index 1bd6658f5..000000000 --- a/views/templates/hook/header.tpl +++ /dev/null @@ -1,21 +0,0 @@ -{** - * Copyright since 2007 PrestaShop SA and Contributors - * PrestaShop is an International Registered Trademark & Property of PrestaShop SA - * - * NOTICE OF LICENSE - * - * This source file is subject to the Academic Free License version 3.0 - * that is bundled with this package in the file LICENSE.md. - * It is also available through the world-wide-web at this URL: - * https://opensource.org/licenses/AFL-3.0 - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@prestashop.com so we can send you a copy immediately. - * - * @author PrestaShop SA and Contributors - * @copyright Since 2007 PrestaShop SA and Contributors - * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 - *} -{foreach $contentToPrefetch as $content} - -{/foreach} From 3d2868cd654fdd1f98396ddcf2e6a358b6d2bf80 Mon Sep 17 00:00:00 2001 From: Laurynas Date: Wed, 7 Feb 2024 17:30:27 +0200 Subject: [PATCH 14/54] Added 3DS block in order view --- config/common.yml | 1 + src/PayPal/Card3DSecure.php | 108 ++++- .../CapturePayPalOrderCommandHandler.php | 13 +- ...lOrderForCheckoutCompletedQueryHandler.php | 1 + src/Presenter/Order/OrderPresenter.php | 5 + tests/Unit/PayPal/Card3DSecureTest.php | 456 +++++++++++++++++- views/css/adminOrderView.css | 8 + views/templates/admin/ajaxPayPalOrder.tpl | 42 +- .../templates/admin/ajaxPayPalOrderLegacy.tpl | 386 ++++++++------- 9 files changed, 823 insertions(+), 197 deletions(-) diff --git a/config/common.yml b/config/common.yml index d1f5fd08b..e7eaee31d 100644 --- a/config/common.yml +++ b/config/common.yml @@ -569,6 +569,7 @@ services: public: true arguments: - "@ps_checkout.event.dispatcher" + - "@ps_checkout.cache.paypal.order" ps_checkout.command.handler.paypal.order.save_paypal_order: class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\CommandHandler\SavePayPalOrderCommandHandler' diff --git a/src/PayPal/Card3DSecure.php b/src/PayPal/Card3DSecure.php index 8347f9a5b..091eec299 100644 --- a/src/PayPal/Card3DSecure.php +++ b/src/PayPal/Card3DSecure.php @@ -79,17 +79,13 @@ class Card3DSecure */ public function continueWithAuthorization(array $order) { - if (!isset($order['payment_source'])) { - return static::NO_DECISION; - } - if (!isset($order['payment_source']['card'])) { - return static::NO_DECISION; - } - if (!isset($order['payment_source']['card']['authentication_result'])) { + $cardAuthenticationResult = $this->getAuthenticationResult($order); + + if (!$cardAuthenticationResult) { return static::NO_DECISION; } - $liabilityShift = isset($order['payment_source']['card']['authentication_result']['liability_shift']) ? $order['payment_source']['card']['authentication_result']['liability_shift'] : null; + $liabilityShift = $this->getLiabilityShift($cardAuthenticationResult); if ($liabilityShift === static::LIABILITY_SHIFT_POSSIBLE) { return static::PROCEED; @@ -99,13 +95,50 @@ public function continueWithAuthorization(array $order) return static::RETRY; } - if ($liabilityShift === static::LIABILITY_SHIFT_NO && isset($order['payment_source']['card']['authentication_result']['three_d_secure'])) { - return $this->noLiabilityShift($order['payment_source']['card']['authentication_result']['three_d_secure']); + $threeDSecure = $this->get3DSecure($cardAuthenticationResult); + + if ($liabilityShift === static::LIABILITY_SHIFT_NO && $threeDSecure) { + return $this->noLiabilityShift($cardAuthenticationResult); } return static::NO_DECISION; } + /** + * @param array $order + * + * @return bool + */ + public function is3DSecureAvailable(array $order) + { + $cardAuthenticationResult = $this->getAuthenticationResult($order); + + if (!$cardAuthenticationResult) { + return false; + } + + $threeDSecure = $this->get3DSecure($cardAuthenticationResult); + $enrollmentStatus = $this->getEnrollmentStatus($threeDSecure); + + return $enrollmentStatus === self::ENROLLMENT_STATUS_YES || $enrollmentStatus === self::ENROLLMENT_STATUS_UNAVAILABLE; + } + + /** + * @param array $order + * + * @return bool + */ + public function isLiabilityShifted(array $order) + { + $cardAuthenticationResult = $this->getAuthenticationResult($order); + $liabilityShift = $this->getLiabilityShift($cardAuthenticationResult); + $threeDSecure = $this->get3DSecure($cardAuthenticationResult); + $authenticationStatus = $this->getAuthenticationStatus($threeDSecure); + + return ($liabilityShift === self::LIABILITY_SHIFT_POSSIBLE || $liabilityShift === self::LIABILITY_SHIFT_YES) + && $authenticationStatus === self::AUTHENTICATION_RESULT_YES; + } + /** * @param array{enrollment_status: string, authentication_status: string} $cardAuthenticationResult * @@ -113,8 +146,9 @@ public function continueWithAuthorization(array $order) */ private function noLiabilityShift(array $cardAuthenticationResult) { - $enrollmentStatus = isset($cardAuthenticationResult['enrollment_status']) ? $cardAuthenticationResult['enrollment_status'] : null; - $authenticationStatus = isset($cardAuthenticationResult['authentication_status']) ? $cardAuthenticationResult['authentication_status'] : null; + $threeDSecure = $this->get3DSecure($cardAuthenticationResult); + $enrollmentStatus = $this->getEnrollmentStatus($threeDSecure); + $authenticationStatus = $this->getAuthenticationStatus($threeDSecure); if ($enrollmentStatus === static::ENROLLMENT_STATUS_BYPASS && !$authenticationStatus) { return static::PROCEED; @@ -146,4 +180,54 @@ private function noLiabilityShift(array $cardAuthenticationResult) return static::NO_DECISION; } + + /** + * @param array $order + * + * @return array|null + */ + private function getAuthenticationResult(array $order) + { + return isset($order['payment_source']['card']['authentication_result']) ? $order['payment_source']['card']['authentication_result'] : null; + } + + /** + * @param array|null $cardAuthenticationResult + * + * @return string|null + */ + private function getLiabilityShift($cardAuthenticationResult) + { + return isset($cardAuthenticationResult['liability_shift']) ? $cardAuthenticationResult['liability_shift'] : null; + } + + /** + * @param array|null $cardAuthenticationResult + * + * @return array|null + */ + private function get3DSecure($cardAuthenticationResult) + { + return isset($cardAuthenticationResult['three_d_secure']) ? $cardAuthenticationResult['three_d_secure'] : null; + } + + /** + * @param array|null $threeDSecure + * + * @return string|null + */ + public function getAuthenticationStatus($threeDSecure) + { + return isset($threeDSecure['authentication_status']) ? $threeDSecure['authentication_status'] : null; + } + + /** + * @param array|null $threeDSecure + * + * @return string|null + */ + private function getEnrollmentStatus($threeDSecure) + { + return isset($threeDSecure['enrollment_status']) ? $threeDSecure['enrollment_status'] : null; + } } diff --git a/src/PayPal/Order/CommandHandler/CapturePayPalOrderCommandHandler.php b/src/PayPal/Order/CommandHandler/CapturePayPalOrderCommandHandler.php index fef3eb10f..aafb9c3ba 100644 --- a/src/PayPal/Order/CommandHandler/CapturePayPalOrderCommandHandler.php +++ b/src/PayPal/Order/CommandHandler/CapturePayPalOrderCommandHandler.php @@ -35,6 +35,7 @@ use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\PayPalCaptureStatus; use PrestaShop\Module\PrestashopCheckout\PayPalError; use PrestaShop\Module\PrestashopCheckout\PayPalProcessorResponse; +use Psr\SimpleCache\CacheInterface; class CapturePayPalOrderCommandHandler { @@ -42,10 +43,15 @@ class CapturePayPalOrderCommandHandler * @var EventDispatcherInterface */ private $eventDispatcher; + /** + * @var CacheInterface + */ + private $orderPayPalCache; - public function __construct(EventDispatcherInterface $eventDispatcher) + public function __construct(EventDispatcherInterface $eventDispatcher, CacheInterface $orderPayPalCache) { $this->eventDispatcher = $eventDispatcher; + $this->orderPayPalCache = $orderPayPalCache; } public function handle(CapturePayPalOrderCommand $capturePayPalOrderCommand) @@ -76,6 +82,11 @@ public function handle(CapturePayPalOrderCommand $capturePayPalOrderCommand) } $orderPayPal = $response['body']; + + $payPalOrderFromCache = $this->orderPayPalCache->get($orderPayPal['id']); + + $orderPayPal = array_replace_recursive($payPalOrderFromCache, $orderPayPal); + $capturePayPal = $orderPayPal['purchase_units'][0]['payments']['captures'][0]; if ($orderPayPal['status'] === PayPalOrderStatus::COMPLETED) { diff --git a/src/PayPal/Order/QueryHandler/GetPayPalOrderForCheckoutCompletedQueryHandler.php b/src/PayPal/Order/QueryHandler/GetPayPalOrderForCheckoutCompletedQueryHandler.php index f30b2208a..6c4a439cc 100644 --- a/src/PayPal/Order/QueryHandler/GetPayPalOrderForCheckoutCompletedQueryHandler.php +++ b/src/PayPal/Order/QueryHandler/GetPayPalOrderForCheckoutCompletedQueryHandler.php @@ -55,6 +55,7 @@ public function handle(GetPayPalOrderForCheckoutCompletedQuery $getPayPalOrderQu try { $orderPayPal = new PaypalOrder($getPayPalOrderQuery->getOrderPayPalId()->getValue()); + $this->orderPayPalCache->set($getPayPalOrderQuery->getOrderPayPalId()->getValue(), $orderPayPal->getOrder()); } catch (HttpTimeoutException $exception) { throw $exception; } catch (Exception $exception) { diff --git a/src/Presenter/Order/OrderPresenter.php b/src/Presenter/Order/OrderPresenter.php index 498b39525..9b0ce79e0 100644 --- a/src/Presenter/Order/OrderPresenter.php +++ b/src/Presenter/Order/OrderPresenter.php @@ -21,6 +21,7 @@ namespace PrestaShop\Module\PrestashopCheckout\Presenter\Order; use Module; +use PrestaShop\Module\PrestashopCheckout\PayPal\Card3DSecure; use PrestaShop\Module\PrestashopCheckout\Presenter\Date\DatePresenter; use PsCheckoutCart; @@ -55,12 +56,16 @@ public function present() return []; } + $card3DSecure = new Card3DSecure(); + return array_merge( [ 'id' => $this->orderPayPal['id'], 'intent' => $this->orderPayPal['intent'], 'status' => $this->getOrderStatus(), 'transactions' => $this->getTransactions(), + 'is3DSecureAvailable' => $card3DSecure->is3DSecureAvailable($this->orderPayPal), + 'isLiabilityShifted' => $card3DSecure->isLiabilityShifted($this->orderPayPal), ], $this->getOrderTotals() ); diff --git a/tests/Unit/PayPal/Card3DSecureTest.php b/tests/Unit/PayPal/Card3DSecureTest.php index 1b54404f6..a5689c2c3 100644 --- a/tests/Unit/PayPal/Card3DSecureTest.php +++ b/tests/Unit/PayPal/Card3DSecureTest.php @@ -34,13 +34,33 @@ class Card3DSecureTest extends TestCase /** * @dataProvider orderProvider */ - public function testCard3DSecure(array $order, $expectedResult) + public function testContinueWithAuthorization(array $order, $expectedResult) { $validator = new Card3DSecure(); $actualResult = $validator->continueWithAuthorization($order); $this->assertEquals($expectedResult, $actualResult); } + /** + * @dataProvider orderIsLiabilityShiftedProvider + */ + public function testIsLiabilityShifted(array $order, $expectedResult) + { + $validator = new Card3DSecure(); + $actualResult = $validator->isLiabilityShifted($order); + $this->assertEquals($expectedResult, $actualResult); + } + + /** + * @dataProvider orderIs3DSecureAvailableProvider + */ + public function testIs3DSecureAvailable(array $order, $expectedResult) + { + $validator = new Card3DSecure(); + $actualResult = $validator->is3DSecureAvailable($order); + $this->assertEquals($expectedResult, $actualResult); + } + public function orderProvider() { return [ @@ -257,4 +277,438 @@ public function orderProvider() ], ]; } + + public function orderIsLiabilityShiftedProvider() + { + return [ + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_POSSIBLE, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_YES, + ], + ], + ], + ], + ], + true, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_NO, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_REJECTED, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_POSSIBLE, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_ATTEMPTED, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_UNKNOWN, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_UNABLE, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_UNABLE, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_UNKNOWN, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_CHALLENGE_REQUIRED, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_NO, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_UNAVAILABLE, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_UNKNOWN, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_UNAVAILABLE, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_BYPASS, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_UNKNOWN, + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'last_digits' => '1083', + 'brand' => 'VISA', + 'type' => 'UNKNOWN', + ], + ], + ], + false, + ], + ]; + } + + public function orderIs3DSecureAvailableProvider() + { + return [ + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_POSSIBLE, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_YES, + ], + ], + ], + ], + ], + true, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_NO, + ], + ], + ], + ], + ], + true, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_REJECTED, + ], + ], + ], + ], + ], + true, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_POSSIBLE, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_ATTEMPTED, + ], + ], + ], + ], + ], + true, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_UNKNOWN, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_UNABLE, + ], + ], + ], + ], + ], + true, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_UNABLE, + ], + ], + ], + ], + ], + true, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_UNKNOWN, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + 'authentication_status' => Card3DSecure::AUTHENTICATION_RESULT_CHALLENGE_REQUIRED, + ], + ], + ], + ], + ], + true, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_YES, + ], + ], + ], + ], + ], + true, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_NO, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_UNAVAILABLE, + ], + ], + ], + ], + ], + true, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_UNKNOWN, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_UNAVAILABLE, + ], + ], + ], + ], + ], + true, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_NO, + 'three_d_secure' => [ + 'enrollment_status' => Card3DSecure::ENROLLMENT_STATUS_BYPASS, + ], + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'authentication_result' => [ + 'liability_shift' => Card3DSecure::LIABILITY_SHIFT_UNKNOWN, + ], + ], + ], + ], + false, + ], + [ + [ + 'payment_source' => [ + 'card' => [ + 'last_digits' => '1083', + 'brand' => 'VISA', + 'type' => 'UNKNOWN', + ], + ], + ], + false, + ], + ]; + } } diff --git a/views/css/adminOrderView.css b/views/css/adminOrderView.css index ce7e6e1d0..2e7db1ea3 100755 --- a/views/css/adminOrderView.css +++ b/views/css/adminOrderView.css @@ -351,3 +351,11 @@ .checkout-modal-button .btn { color: #FFFFFF; } + +#ps_checkout .tabpanel__infos .liability-explanation { + font-weight: 400; + background-color: #EEEEEE; + padding: 4px 8px; + margin-top: 5px; + display: inline-block; +} diff --git a/views/templates/admin/ajaxPayPalOrder.tpl b/views/templates/admin/ajaxPayPalOrder.tpl index 6c4e74737..8c77835eb 100755 --- a/views/templates/admin/ajaxPayPalOrder.tpl +++ b/views/templates/admin/ajaxPayPalOrder.tpl @@ -132,12 +132,48 @@
{$orderPayPalTransaction.id}
{l s='Status' mod='ps_checkout'}
- - {$orderPayPalTransaction.status.translated|escape:'html':'UTF-8'} - + + {$orderPayPalTransaction.status.translated|escape:'html':'UTF-8'} +
{l s='Amount (Tax incl.)' mod='ps_checkout'}
{$orderPayPalTransaction.amount} {$orderPayPalTransaction.currency}
+ {if $psCheckoutCart->paypal_funding === 'card'} +
{l s='3D Secure' mod='ps_checkout'}
+
+ {if $orderPayPal.is3DSecureAvailable && $orderPayPal.isLiabilityShifted} + + {l s='Success' mod='ps_checkout'} + + {elseif $orderPayPal.is3DSecureAvailable && !$orderPayPal.isLiabilityShifted} + + {l s='Failed' mod='ps_checkout'} + + {else} + + {l s='Card does not support 3D Secure' mod='ps_checkout'} + + {/if} +
+
{l s='Liability shift' mod='ps_checkout'}
+
+ {if $orderPayPal.isLiabilityShifted} + + {l s='Bank' mod='ps_checkout'} + +
+ {l s='You can safely proceed with the order.' mod='ps_checkout'} +
+ {else} + + {l s='Merchant' mod='ps_checkout'} + +
+ {l s='We advice you not to honor the order immediately, wait a few days in case of chargeback and contact the consumer to ensure authenticity of the transaction. For this type of cases we also recommend to consider Chargeback protection.' mod='ps_checkout'} +
+ {/if} +
+ {/if}
{if $orderPayPalTransaction.gross_amount || $orderPayPalTransaction.paypal_fee || $orderPayPalTransaction.net_amount} diff --git a/views/templates/admin/ajaxPayPalOrderLegacy.tpl b/views/templates/admin/ajaxPayPalOrderLegacy.tpl index 8752e8829..4378c0b32 100755 --- a/views/templates/admin/ajaxPayPalOrderLegacy.tpl +++ b/views/templates/admin/ajaxPayPalOrderLegacy.tpl @@ -60,7 +60,7 @@
{l s='Total' mod='ps_checkout'}
{$orderPayPal.total}
- {l s='Balance' mod='ps_checkout'} + {l s='Balance' mod='ps_checkout'}
{$orderPayPal.balance}
@@ -69,9 +69,9 @@
{if $isProductionEnv} - {l s='Production Environment' mod='ps_checkout'} + {l s='Production Environment' mod='ps_checkout'} {else} - {l s='Test Environment' mod='ps_checkout'} + {l s='Test Environment' mod='ps_checkout'} {/if}
@@ -79,211 +79,237 @@
- {if !empty($orderPayPal.transactions)} -
- -
+ {if !empty($orderPayPal.transactions)} +
+ +
-
-
- {assign var="counter" value=1} - {foreach $orderPayPal.transactions as $orderPayPalTransaction} - - {assign var="counter" value=$counter+1} - {/foreach} -
+ + {assign var="counter" value=$counter+1} + {/foreach} +
-
- {assign var="counter" value=1} - {foreach $orderPayPal.transactions as $orderPayPalTransaction} - {assign var="maxAmountRefundable" value=$orderPayPalTransaction.maxAmountRefundable|string_format:"%.2f"} - {assign var="orderPayPalRefundAmountIdentifier" value='orderPayPalRefundAmount'|cat:$orderPayPalTransaction.id} -
+
+ {assign var="counter" value=1} + {foreach $orderPayPal.transactions as $orderPayPalTransaction} + {assign var="maxAmountRefundable" value=$orderPayPalTransaction.maxAmountRefundable|string_format:"%.2f"} + {assign var="orderPayPalRefundAmountIdentifier" value='orderPayPalRefundAmount'|cat:$orderPayPalTransaction.id} +
+
+
+

{l s='Transaction details' mod='ps_checkout'}

+
+
{l s='Reference' mod='ps_checkout'}
+
{$orderPayPalTransaction.id}
+
{l s='Status' mod='ps_checkout'}
+
+ + {$orderPayPalTransaction.status.translated} + +
+
{l s='Amount (Tax incl.)' mod='ps_checkout'}
+
{$orderPayPalTransaction.amount} {$orderPayPalTransaction.currency}
+ {if $psCheckoutCart->paypal_funding === 'card'} +
{l s='3D Secure' mod='ps_checkout'}
+
+ {if $orderPayPal.is3DSecureAvailable && $orderPayPal.isLiabilityShifted} + {l s='Success' mod='ps_checkout'} + {elseif $orderPayPal.is3DSecureAvailable && !$orderPayPal.isLiabilityShifted} + {l s='Failed' mod='ps_checkout'} + {else} + {l s='Card does not support 3D Secure' mod='ps_checkout'} + {/if} +
+
{l s='Liability shift' mod='ps_checkout'}
+
+ {if $orderPayPal.isLiabilityShifted} + {l s='Bank' mod='ps_checkout'} +
+ {l s='You can safely proceed with the order.' mod='ps_checkout'} +
+ {else} + {l s='Merchant' mod='ps_checkout'} +
+ {l s='We advice you not to honor the order immediately, wait a few days in case of chargeback and contact the consumer to ensure authenticity of the transaction. For this type of cases we also recommend to consider Chargeback protection.' mod='ps_checkout'} +
+ {/if} +
+ {/if} +
+
+ {if $orderPayPalTransaction.gross_amount || $orderPayPalTransaction.paypal_fee || $orderPayPalTransaction.net_amount}
-
-

{l s='Transaction details' mod='ps_checkout'}

-
-
{l s='Reference' mod='ps_checkout'}
-
{$orderPayPalTransaction.id}
-
{l s='Status' mod='ps_checkout'}
-
- - {$orderPayPalTransaction.status.translated} - -
-
{l s='Amount (Tax incl.)' mod='ps_checkout'}
-
{$orderPayPalTransaction.amount} {$orderPayPalTransaction.currency}
-
-
- {if $orderPayPalTransaction.gross_amount || $orderPayPalTransaction.paypal_fee || $orderPayPalTransaction.net_amount} -
-

{l s='Transaction amounts' mod='ps_checkout'}

-
- {if $orderPayPalTransaction.gross_amount} +

{l s='Transaction amounts' mod='ps_checkout'}

+
+ {if $orderPayPalTransaction.gross_amount}
{l s='Gross amount' mod='ps_checkout'}
{$orderPayPalTransaction.gross_amount} {$orderPayPalTransaction.currency}
- {/if} - {if $orderPayPalTransaction.paypal_fee} + {/if} + {if $orderPayPalTransaction.paypal_fee}
{l s='Fees (Tax Incl.)' mod='ps_checkout'}
- {$orderPayPalTransaction.paypal_fee} {$orderPayPalTransaction.currency}
- {/if} - {if $orderPayPalTransaction.net_amount} + {/if} + {if $orderPayPalTransaction.net_amount}
{l s='Net amount' mod='ps_checkout'}
{$orderPayPalTransaction.net_amount} {$orderPayPalTransaction.currency}
- {/if} -
-
- {/if} - - {l s='See on PayPal' mod='ps_checkout'} - - {if $orderPayPalTransaction.isRefundable} - - {l s='Refund' mod='ps_checkout'} - {/if} +
-
+ {/if} +
+ {l s='See on PayPal' mod='ps_checkout'} + + {if $orderPayPalTransaction.isRefundable} + + {l s='Refund' mod='ps_checkout'} + + {/if} +
+
- {if $orderPayPalTransaction.isRefundable} - diff --git a/views/templates/admin/ajaxPayPalOrderLegacy.tpl b/views/templates/admin/ajaxPayPalOrderLegacy.tpl index 4378c0b32..65b0a7f2e 100755 --- a/views/templates/admin/ajaxPayPalOrderLegacy.tpl +++ b/views/templates/admin/ajaxPayPalOrderLegacy.tpl @@ -65,8 +65,12 @@
{$orderPayPal.balance}
{l s='Payment mode' mod='ps_checkout'}
-
{$orderPaymentDisplayName|escape:'html':'UTF-8'} {$orderPaymentDisplayName|escape:'html':'UTF-8'}
+
{$orderPaymentDisplayName|escape:'html':'UTF-8'} {$orderPaymentDisplayName|escape:'html':'UTF-8'}
+ {l s='Environment' mod='ps_checkout'} + +
+
{if $isProductionEnv} {l s='Production Environment' mod='ps_checkout'} @@ -74,9 +78,38 @@ {l s='Test Environment' mod='ps_checkout'} {/if} - -
+ + {if $psCheckoutCart->paypal_funding === 'card'} +
{l s='3D Secure' mod='ps_checkout'}
+
+ {if $orderPayPal.is3DSecureAvailable && $orderPayPal.isLiabilityShifted} + {l s='Success' mod='ps_checkout'} + {elseif $orderPayPal.is3DSecureAvailable && !$orderPayPal.isLiabilityShifted} + {l s='Failed' mod='ps_checkout'} + {else} + {l s='Card does not support 3D Secure' mod='ps_checkout'} + {/if} +
+
{l s='Liability shift' mod='ps_checkout'}
+
+ {if $orderPayPal.isLiabilityShifted} + {l s='Bank' mod='ps_checkout'} + {else} + {l s='Merchant' mod='ps_checkout'} + {/if} +
+ {/if} + {if $psCheckoutCart->paypal_funding === 'card' && !$orderPayPal.isLiabilityShifted} +
+ {l s='The bank issuer declined the liability shift. We advice you not to honor the order immediately, wait a few days in case of chargeback and contact the consumer to ensure authenticity of the transaction. For this type of cases we also recommend to consider Chargeback protection.' mod='ps_checkout'} +
+ {/if} + {if $psCheckoutCart->paypal_funding === 'card' && $orderPayPal.isLiabilityShifted} +
+ {l s='The bank issuer accepted the liability shift. You can safely honor the order.' mod='ps_checkout'} +
+ {/if}
{if !empty($orderPayPal.transactions)} @@ -138,30 +171,15 @@
{l s='Amount (Tax incl.)' mod='ps_checkout'}
{$orderPayPalTransaction.amount} {$orderPayPalTransaction.currency}
- {if $psCheckoutCart->paypal_funding === 'card'} -
{l s='3D Secure' mod='ps_checkout'}
-
- {if $orderPayPal.is3DSecureAvailable && $orderPayPal.isLiabilityShifted} - {l s='Success' mod='ps_checkout'} - {elseif $orderPayPal.is3DSecureAvailable && !$orderPayPal.isLiabilityShifted} - {l s='Failed' mod='ps_checkout'} - {else} - {l s='Card does not support 3D Secure' mod='ps_checkout'} - {/if} -
-
{l s='Liability shift' mod='ps_checkout'}
+ {if !empty($orderPayPalTransaction.seller_protection)} +
+ {l s='Seller protection' mod='ps_checkout'} + +
- {if $orderPayPal.isLiabilityShifted} - {l s='Bank' mod='ps_checkout'} -
- {l s='You can safely proceed with the order.' mod='ps_checkout'} -
- {else} - {l s='Merchant' mod='ps_checkout'} -
- {l s='We advice you not to honor the order immediately, wait a few days in case of chargeback and contact the consumer to ensure authenticity of the transaction. For this type of cases we also recommend to consider Chargeback protection.' mod='ps_checkout'} -
- {/if} + + {$orderPayPalTransaction.seller_protection.translated|escape:'html':'UTF-8'} +
{/if} From f9f9203014e95618214bce89ce50ae748c15fa80 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:42:41 +0100 Subject: [PATCH 39/54] Fix issue with BO order detail --- .../AdminAjaxPrestashopCheckoutController.php | 7 ++++- views/img/sofort.svg | 28 ++++++++++--------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/controllers/admin/AdminAjaxPrestashopCheckoutController.php b/controllers/admin/AdminAjaxPrestashopCheckoutController.php index 10a283ec7..cce1e0ae7 100755 --- a/controllers/admin/AdminAjaxPrestashopCheckoutController.php +++ b/controllers/admin/AdminAjaxPrestashopCheckoutController.php @@ -399,7 +399,12 @@ public function ajaxProcessFetchOrder() /** @var PayPalOrderProvider $paypalOrderProvider */ $paypalOrderProvider = $this->module->getService('ps_checkout.paypal.provider.order'); - $paypalOrder = $paypalOrderProvider->getById($psCheckoutCart->paypal_order); + try { + $paypalOrder = $paypalOrderProvider->getById($psCheckoutCart->paypal_order); + } catch (Exception $exception) { + $paypalOrder = []; + } + if ($paypalOrder === false) { $paypalOrder = []; } diff --git a/views/img/sofort.svg b/views/img/sofort.svg index d2933245c..cb58f5e65 100644 --- a/views/img/sofort.svg +++ b/views/img/sofort.svg @@ -1,14 +1,16 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + From 4292cef9a56c1be61249b9283e1dca9e228ae1b9 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Wed, 21 Feb 2024 18:08:18 +0100 Subject: [PATCH 40/54] Fix phpstan feedback --- src/Presenter/Order/OrderPresenter.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Presenter/Order/OrderPresenter.php b/src/Presenter/Order/OrderPresenter.php index 79589fe02..8592e634d 100644 --- a/src/Presenter/Order/OrderPresenter.php +++ b/src/Presenter/Order/OrderPresenter.php @@ -20,16 +20,16 @@ namespace PrestaShop\Module\PrestashopCheckout\Presenter\Order; -use Module; use PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceTranslationProvider; use PrestaShop\Module\PrestashopCheckout\PayPal\Card3DSecure; use PrestaShop\Module\PrestashopCheckout\Presenter\Date\DatePresenter; +use Ps_checkout; use PsCheckoutCart; class OrderPresenter { /** - * @var Module + * @var Ps_checkout */ private $module; @@ -43,10 +43,10 @@ class OrderPresenter private $fundingSourceTranslationProvider; /** - * @param Module $module + * @param Ps_checkout $module * @param array $orderPayPal */ - public function __construct(Module $module, array $orderPayPal) + public function __construct(Ps_checkout $module, array $orderPayPal) { $this->module = $module; $this->orderPayPal = $orderPayPal; From 415722ba9651e48a22cecf243c8fb19027f5b291 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Wed, 21 Feb 2024 18:26:36 +0100 Subject: [PATCH 41/54] Fix translations --- translations/fr.php | 8 ++++---- views/templates/admin/ajaxPayPalOrder.tpl | 4 ++-- views/templates/admin/ajaxPayPalOrderLegacy.tpl | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/translations/fr.php b/translations/fr.php index e62c4b710..98b266672 100644 --- a/translations/fr.php +++ b/translations/fr.php @@ -109,8 +109,8 @@ $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorderlegacy_ea620d61461a00502599f2e6a064b931'] = 'Moyen de paiement'; $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorderlegacy_0ba29c6a1afacf586b03a26162c72274'] = 'Environnement'; $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorderlegacy_2cacd34854aed29bd7d0959ace917806'] = 'L\'environnement utilisé pour cette transaction: Test ou Production'; -$_MODULE['<{ps_checkout}prestashop>ajaxpaypalorderlegacy_1e9511daad89204a4514d932d652480e'] = 'Production'; -$_MODULE['<{ps_checkout}prestashop>ajaxpaypalorderlegacy_c85d6a8b7427e52b78fd6ea42502f457'] = 'Test'; +$_MODULE['<{ps_checkout}prestashop>ajaxpaypalorderlegacy_756d97bb256b8580d4d71ee0c547804e'] = 'Production'; +$_MODULE['<{ps_checkout}prestashop>ajaxpaypalorderlegacy_0cbc6611f5540bd0809a388dc95a615b'] = 'Test'; $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorderlegacy_ecfa6e92f6b49a55e336afde4c64aa14'] = '3D Secure'; $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorderlegacy_505a83f220c02df2f85c3810cd9ceb38'] = 'Succès'; $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorderlegacy_d7c8c85bf79bbe1b7188497c32c3b0ca'] = 'Échec'; @@ -152,8 +152,8 @@ $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorder_a6f74fff2223803369009919e94f2f96'] = 'Montant à recevoir sur votre compte bancaire : total de la commande moins la commission et les remboursements éventuels'; $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorder_0ba29c6a1afacf586b03a26162c72274'] = 'Environnement'; $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorder_2cacd34854aed29bd7d0959ace917806'] = 'L\'environnement utilisé pour cette transaction: Test ou Production'; -$_MODULE['<{ps_checkout}prestashop>ajaxpaypalorder_1e9511daad89204a4514d932d652480e'] = 'Production'; -$_MODULE['<{ps_checkout}prestashop>ajaxpaypalorder_c85d6a8b7427e52b78fd6ea42502f457'] = 'Test'; +$_MODULE['<{ps_checkout}prestashop>ajaxpaypalorder_756d97bb256b8580d4d71ee0c547804e'] = 'Production'; +$_MODULE['<{ps_checkout}prestashop>ajaxpaypalorder_0cbc6611f5540bd0809a388dc95a615b'] = 'Test'; $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorder_ea620d61461a00502599f2e6a064b931'] = 'Moyen de paiement'; $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorder_ecfa6e92f6b49a55e336afde4c64aa14'] = '3D Secure'; $_MODULE['<{ps_checkout}prestashop>ajaxpaypalorder_505a83f220c02df2f85c3810cd9ceb38'] = 'Succès'; diff --git a/views/templates/admin/ajaxPayPalOrder.tpl b/views/templates/admin/ajaxPayPalOrder.tpl index 36b824644..2f545646a 100755 --- a/views/templates/admin/ajaxPayPalOrder.tpl +++ b/views/templates/admin/ajaxPayPalOrder.tpl @@ -71,9 +71,9 @@
{if $isProductionEnv} - {l s='Production Environment' mod='ps_checkout'} + {l s='Production' mod='ps_checkout'} {else} - {l s='Test Environment' mod='ps_checkout'} + {l s='Test' mod='ps_checkout'} {/if}
diff --git a/views/templates/admin/ajaxPayPalOrderLegacy.tpl b/views/templates/admin/ajaxPayPalOrderLegacy.tpl index 65b0a7f2e..a3f22dba6 100755 --- a/views/templates/admin/ajaxPayPalOrderLegacy.tpl +++ b/views/templates/admin/ajaxPayPalOrderLegacy.tpl @@ -73,9 +73,9 @@
{if $isProductionEnv} - {l s='Production Environment' mod='ps_checkout'} + {l s='Production' mod='ps_checkout'} {else} - {l s='Test Environment' mod='ps_checkout'} + {l s='Test' mod='ps_checkout'} {/if}
From 7966a84e512693a2ad2dfbc249ee51034b0ec9f5 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Thu, 22 Feb 2024 13:29:43 +0100 Subject: [PATCH 42/54] Add PrestaShop module dependencies library --- composer.json | 1 + composer.lock | 55 ++++++++++++++++++++++++- module_dependencies.json | 8 ++++ ps_checkout.php | 9 ++++ views/templates/admin/configuration.tpl | 38 ++++++++++++++++- 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 module_dependencies.json diff --git a/composer.json b/composer.json index 8e81235e6..342eb78b5 100755 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "guzzlehttp/guzzle": "^7.4", "prestashop/decimal": "^1.3", "prestashop/module-lib-guzzle-adapter": "^1.0", + "prestashop/module-lib-mbo-installer": "^2.0", "prestashop/module-lib-service-container": "^1.0", "prestashop/prestashop-accounts-installer": "^1.0", "ramsey/uuid": "^3.8", diff --git a/composer.lock b/composer.lock index 7a2e53a27..707e750e6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "83e53d19b0dc27f33a825b790f2f8fd2", + "content-hash": "1ffed083e7949e1d32cb94eaf11a19ad", "packages": [ { "name": "clue/stream-filter", @@ -984,6 +984,57 @@ }, "time": "2022-09-30T10:25:35+00:00" }, + { + "name": "prestashop/module-lib-mbo-installer", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/PrestaShopCorp/module-lib-mbo-installer.git", + "reference": "58cde161e40ba62638be2dbc5fde3e09f1733d48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PrestaShopCorp/module-lib-mbo-installer/zipball/58cde161e40ba62638be2dbc5fde3e09f1733d48", + "reference": "58cde161e40ba62638be2dbc5fde3e09f1733d48", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.2.5", + "prestashop/module-lib-guzzle-adapter": "^1.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^9.5|^8.5|^5.7", + "prestashop/php-dev-tools": "^4.2|^3.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Prestashop\\ModuleLibMboInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "AFL-3.0" + ], + "authors": [ + { + "name": "PrestaShop SA", + "email": "contact@prestashop.com" + }, + { + "name": "Mikatux", + "email": "mickael@mayeur.eu" + } + ], + "description": "A helper to ease the download PS MBO from the Addons Marketplace", + "support": { + "issues": "https://github.com/PrestaShopCorp/module-lib-mbo-installer/issues", + "source": "https://github.com/PrestaShopCorp/module-lib-mbo-installer/tree/v2.0.0" + }, + "time": "2023-12-05T14:14:13+00:00" + }, { "name": "prestashop/module-lib-service-container", "version": "1.4.0", @@ -5695,5 +5746,5 @@ "platform-overrides": { "php": "7.2.34" }, - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.6.0" } diff --git a/module_dependencies.json b/module_dependencies.json new file mode 100644 index 000000000..6002cd69f --- /dev/null +++ b/module_dependencies.json @@ -0,0 +1,8 @@ +{ + "dependencies": [ + { + "name" : "ps_accounts", + "id": "49648" + } + ] +} diff --git a/ps_checkout.php b/ps_checkout.php index 5a8c21cc1..4b367e558 100755 --- a/ps_checkout.php +++ b/ps_checkout.php @@ -376,6 +376,9 @@ public function uninstallTabs() public function getContent() { try { + $mboInstaller = new \Prestashop\ModuleLibMboInstaller\DependencyBuilder($this); + $requiredDependencies = $mboInstaller->handleDependencies(); + $hasRequiredDependencies = $mboInstaller->areDependenciesMet(); /** @var \PrestaShop\PsAccountsInstaller\Installer\Facade\PsAccounts $psAccountsFacade */ $psAccountsFacade = $this->getService('ps_accounts.facade'); /** @var \PrestaShop\PsAccountsInstaller\Installer\Presenter\InstallerPresenter $psAccountsPresenter */ @@ -384,6 +387,8 @@ public function getContent() $contextPsAccounts = $psAccountsPresenter->present($this->name); } catch (Exception $exception) { $contextPsAccounts = []; + $requiredDependencies = []; + $hasRequiredDependencies = false; $this->getLogger()->error( 'Failed to get PsAccounts context', [ @@ -417,6 +422,10 @@ public function getContent() } $this->context->controller->addJS($boSdkUrl, false); + $this->context->smarty->assign([ + 'requiredDependencies' => $requiredDependencies, + 'hasRequiredDependencies' => $hasRequiredDependencies, + ]); return $this->display(__FILE__, 'views/templates/admin/configuration.tpl'); } diff --git a/views/templates/admin/configuration.tpl b/views/templates/admin/configuration.tpl index 62e1cebb3..434590af1 100755 --- a/views/templates/admin/configuration.tpl +++ b/views/templates/admin/configuration.tpl @@ -17,11 +17,47 @@ * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 *} -
+{if isset($hasRequiredDependencies) && !$hasRequiredDependencies} + +
+ + +{/if} + + + + From da1949adbe22f797b28491d3937f5e1c4c6be2d3 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:55:41 +0100 Subject: [PATCH 43/54] Fix 3D Secure --- src/Builder/Payload/OrderPayloadBuilder.php | 9 ++++----- src/PayPal/PayPalConfiguration.php | 5 ++--- src/PayPal/Sdk/PayPalSdkConfigurationBuilder.php | 5 ++++- upgrade/upgrade-8.3.6.0.php | 8 ++++---- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Builder/Payload/OrderPayloadBuilder.php b/src/Builder/Payload/OrderPayloadBuilder.php index b3fc263cd..61011b1b4 100644 --- a/src/Builder/Payload/OrderPayloadBuilder.php +++ b/src/Builder/Payload/OrderPayloadBuilder.php @@ -415,15 +415,14 @@ private function buildPaymentSourceNode() 'card' => [ 'name' => $this->cart['addresses']['invoice']->firstname . ' ' . $this->cart['addresses']['invoice']->lastname, 'billing_address' => $this->getAddressPortable('invoice'), - 'attributes' => [ - 'verification' => [ - 'method' => $paypalConfiguration->getHostedFieldsContingencies(), - ], - ], ], ], ]; + if ($paypalConfiguration->is3dSecureEnabled()) { + $node['payment_source']['card']['attributes']['verification']['method'] = $paypalConfiguration->getHostedFieldsContingencies(); + } + $this->getPayload()->addAndMergeItems($node); } diff --git a/src/PayPal/PayPalConfiguration.php b/src/PayPal/PayPalConfiguration.php index 8cd165a36..3f6af00c3 100644 --- a/src/PayPal/PayPalConfiguration.php +++ b/src/PayPal/PayPalConfiguration.php @@ -33,8 +33,7 @@ class PayPalConfiguration const PS_ROUND_TYPE = 'PS_ROUND_TYPE'; const PS_PRICE_ROUND_MODE = 'PS_PRICE_ROUND_MODE'; const INTEGRATION_DATE = 'PS_CHECKOUT_INTEGRATION_DATE'; - const HOSTED_FIELDS_3DS_DISABLED = 'PS_CHECKOUT_3DS_DISABLED'; - const HOSTED_FIELDS_CONTINGENCIES = 'PS_CHECKOUT_HOSTEDFIELDS_CONTINGENCIES'; + const HOSTED_FIELDS_CONTINGENCIES = 'PS_CHECKOUT_HOSTED_FIELDS_CONTINGENCIES'; const CSP_NONCE = 'PS_CHECKOUT_CSP_NONCE'; const PS_CHECKOUT_PAYPAL_CB_INLINE = 'PS_CHECKOUT_PAYPAL_CB_INLINE'; const PS_CHECKOUT_PAYPAL_BUTTON = 'PS_CHECKOUT_PAYPAL_BUTTON'; @@ -237,7 +236,7 @@ public function getCSPNonce() */ public function is3dSecureEnabled() { - return false === (bool) $this->configuration->get(static::HOSTED_FIELDS_3DS_DISABLED); + return $this->getHostedFieldsContingencies() !== 'NONE'; } /** diff --git a/src/PayPal/Sdk/PayPalSdkConfigurationBuilder.php b/src/PayPal/Sdk/PayPalSdkConfigurationBuilder.php index d5aa33d7f..6ab5624b2 100644 --- a/src/PayPal/Sdk/PayPalSdkConfigurationBuilder.php +++ b/src/PayPal/Sdk/PayPalSdkConfigurationBuilder.php @@ -109,9 +109,12 @@ public function buildConfiguration() 'integrationDate' => $this->configuration->getIntegrationDate(), 'dataPartnerAttributionId' => $this->shopContext->getBnCode(), 'dataCspNonce' => $this->configuration->getCSPNonce(), - 'dataEnable3ds' => $this->configuration->is3dSecureEnabled(), ]; + if ($this->configuration->is3dSecureEnabled()) { + $params['dataEnable3ds'] = 'true'; + } + if ('SANDBOX' === $this->configuration->getPaymentMode()) { // $params['debug'] = 'true'; $params['buyerCountry'] = $this->getCountry(); diff --git a/upgrade/upgrade-8.3.6.0.php b/upgrade/upgrade-8.3.6.0.php index 3659558ac..7fecdf330 100644 --- a/upgrade/upgrade-8.3.6.0.php +++ b/upgrade/upgrade-8.3.6.0.php @@ -44,8 +44,8 @@ function upgrade_module_8_3_6_0($module) Configuration::updateValue('PS_CHECKOUT_LIABILITY_SHIFT_REQ', '1', false, null, (int) $shopId); // Update global value only if it is not already set to SCA_ALWAYS - if (Configuration::get('PS_CHECKOUT_HOSTEDFIELDS_CONTINGENCIES', null, null, $shopId) !== 'SCA_ALWAYS') { - Configuration::updateValue('PS_CHECKOUT_HOSTEDFIELDS_CONTINGENCIES', 'SCA_WHEN_REQUIRED', false, null, (int) $shopId); + if (Configuration::get('PS_CHECKOUT_HOSTED_FIELDS_CONTINGENCIES', null, null, $shopId) !== 'SCA_ALWAYS') { + Configuration::updateValue('PS_CHECKOUT_HOSTED_FIELDS_CONTINGENCIES', 'SCA_WHEN_REQUIRED', false, null, (int) $shopId); } } @@ -53,8 +53,8 @@ function upgrade_module_8_3_6_0($module) Configuration::updateGlobalValue('PS_CHECKOUT_LIABILITY_SHIFT_REQ', '1'); // Update global value only if it is not already set to SCA_ALWAYS - if (Configuration::getGlobalValue('PS_CHECKOUT_HOSTEDFIELDS_CONTINGENCIES') !== 'SCA_ALWAYS') { - Configuration::updateGlobalValue('PS_CHECKOUT_HOSTEDFIELDS_CONTINGENCIES', 'SCA_WHEN_REQUIRED'); + if (Configuration::getGlobalValue('PS_CHECKOUT_HOSTED_FIELDS_CONTINGENCIES') !== 'SCA_ALWAYS') { + Configuration::updateGlobalValue('PS_CHECKOUT_HOSTED_FIELDS_CONTINGENCIES', 'SCA_WHEN_REQUIRED'); } // Add new configuration for displaying the logo on the product page and the cart From 83c96781ea792cf9a64896d4abba4b2786cfb7f6 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:17:55 +0100 Subject: [PATCH 44/54] Refactor and fix Guzzle5 issues --- .../1_6/payment-options.component.js | 39 +- .../1_7/payment-options.component.js | 36 +- .../common/card-fields.component.js | 9 + .../express-checkout-button.component.js | 16 +- .../common/smart-button.component.js | 51 ++- config/common.yml | 120 ++++- .../AdminAjaxPrestashopCheckoutController.php | 107 ++--- controllers/front/cancel.php | 32 +- controllers/front/check.php | 71 +-- controllers/front/create.php | 100 +---- src/Api/Payment/Order.php | 7 + src/Builder/Payload/OrderPayloadBuilder.php | 4 +- .../Command/CancelCheckoutCommand.php | 128 ++++++ src/Checkout/Command/SaveCheckoutCommand.php | 158 +++++++ .../Command/SavePayPalOrderStatusCommand.php} | 24 +- .../CancelCheckoutCommandHandler.php | 68 +++ .../SaveCheckoutCommandHandler.php | 69 +++ .../SavePayPalOrderStatusCommandHandler.php} | 32 +- src/Controller/AbstractFrontController.php | 7 +- src/Dispatcher/OrderDispatcher.php | 2 +- src/Exception/PayPalException.php | 19 + src/Handler/CreatePaypalOrderHandler.php | 43 +- src/Handler/Response/ResponseApiHandler.php | 3 +- src/Http/CheckoutHttpClient.php | 184 ++++++++ ...CheckoutHttpClientConfigurationBuilder.php | 108 +++++ ...ttpClientConfigurationBuilderInterface.php | 29 ++ src/Http/HttpClientFactory.php | 34 ++ src/Http/HttpClientInterface.php | 50 +++ src/Http/PsrHttpClientAdapter.php | 63 +++ .../Command/CreatePayPalOrderCommand.php | 95 ++++ .../Command/UpdatePayPalOrderCommand.php | 112 +++++ .../CapturePayPalOrderCommandHandler.php | 48 +- .../CreatePayPalOrderCommandHandler.php | 95 ++++ .../UpdatePayPalOrderCommandHandler.php | 104 +++++ .../Order/Event/PayPalOrderCreatedEvent.php | 75 ++++ .../Order/Event/PayPalOrderUpdatedEvent.php | 100 +++++ .../PayPalOrderEventSubscriber.php | 48 +- .../Query/GetPayPalOrderForAdminViewQuery.php | 25 ++ .../GetPayPalOrderForAdminViewQueryResult.php | 25 ++ .../Query/GetPayPalOrderForCartIdQuery.php | 50 +++ .../GetPayPalOrderForCartIdQueryResult.php | 45 ++ ...GetPayPalOrderForAdminViewQueryHandler.php | 32 ++ .../GetPayPalOrderForCartIdQueryHandler.php | 66 +++ .../PayPalCaptureEventSubscriber.php | 31 -- .../Command/RefundPayPalCaptureCommand.php | 109 +++++ .../RefundPayPalCaptureCommandHandler.php | 123 ++++++ .../Event/PayPalCaptureRefundedEvent.php | 4 +- .../Refund/Event/PayPalRefundEvent.php | 82 ++++ .../PayPalRefundEventSubscriber.php | 161 +++++++ .../Exception/PayPalRefundException.php | 32 ++ .../Exception/PayPalRefundFailedException.php | 27 ++ src/PayPalError.php | 307 +++++++------ src/PaypalOrder.php | 42 +- tests/Unit/Http/CheckoutHttpClientTest.php | 417 ++++++++++++++++++ 54 files changed, 3306 insertions(+), 562 deletions(-) create mode 100644 src/Checkout/Command/CancelCheckoutCommand.php create mode 100644 src/Checkout/Command/SaveCheckoutCommand.php rename src/{PayPal/Order/Command/SavePayPalOrderCommand.php => Checkout/Command/SavePayPalOrderStatusCommand.php} (80%) create mode 100644 src/Checkout/CommandHandler/CancelCheckoutCommandHandler.php create mode 100644 src/Checkout/CommandHandler/SaveCheckoutCommandHandler.php rename src/{PayPal/Order/CommandHandler/SavePayPalOrderCommandHandler.php => Checkout/CommandHandler/SavePayPalOrderStatusCommandHandler.php} (52%) create mode 100644 src/Http/CheckoutHttpClient.php create mode 100644 src/Http/CheckoutHttpClientConfigurationBuilder.php create mode 100644 src/Http/HttpClientConfigurationBuilderInterface.php create mode 100644 src/Http/HttpClientFactory.php create mode 100644 src/Http/HttpClientInterface.php create mode 100644 src/Http/PsrHttpClientAdapter.php create mode 100644 src/PayPal/Order/Command/CreatePayPalOrderCommand.php create mode 100644 src/PayPal/Order/Command/UpdatePayPalOrderCommand.php create mode 100644 src/PayPal/Order/CommandHandler/CreatePayPalOrderCommandHandler.php create mode 100644 src/PayPal/Order/CommandHandler/UpdatePayPalOrderCommandHandler.php create mode 100644 src/PayPal/Order/Event/PayPalOrderUpdatedEvent.php create mode 100644 src/PayPal/Order/Query/GetPayPalOrderForAdminViewQuery.php create mode 100644 src/PayPal/Order/Query/GetPayPalOrderForAdminViewQueryResult.php create mode 100644 src/PayPal/Order/Query/GetPayPalOrderForCartIdQuery.php create mode 100644 src/PayPal/Order/Query/GetPayPalOrderForCartIdQueryResult.php create mode 100644 src/PayPal/Order/QueryHandler/GetPayPalOrderForAdminViewQueryHandler.php create mode 100644 src/PayPal/Order/QueryHandler/GetPayPalOrderForCartIdQueryHandler.php create mode 100644 src/PayPal/Payment/Refund/Command/RefundPayPalCaptureCommand.php create mode 100644 src/PayPal/Payment/Refund/CommandHandler/RefundPayPalCaptureCommandHandler.php rename src/PayPal/Payment/{Capture => Refund}/Event/PayPalCaptureRefundedEvent.php (85%) create mode 100644 src/PayPal/Payment/Refund/Event/PayPalRefundEvent.php create mode 100644 src/PayPal/Payment/Refund/EventSubscriber/PayPalRefundEventSubscriber.php create mode 100644 src/PayPal/Payment/Refund/Exception/PayPalRefundException.php create mode 100644 src/PayPal/Payment/Refund/Exception/PayPalRefundFailedException.php create mode 100644 tests/Unit/Http/CheckoutHttpClientTest.php diff --git a/_dev/js/front/src/components/1_6/payment-options.component.js b/_dev/js/front/src/components/1_6/payment-options.component.js index 374d2f41f..076078574 100644 --- a/_dev/js/front/src/components/1_6/payment-options.component.js +++ b/_dev/js/front/src/components/1_6/payment-options.component.js @@ -52,7 +52,8 @@ export class PaymentOptionsComponent extends BaseComponent { } renderPaymentOptionListener() { - const HTMLListenerElements = this.children.paymentOptions.map((paymentOption) => { + const HTMLListenerElements = this.children.paymentOptions.map( + (paymentOption) => { const HTMLElement = paymentOption.data.HTMLElementContainer; const [button, form] = Array.prototype.slice.call( HTMLElement.querySelectorAll('.payment_module') @@ -74,21 +75,28 @@ export class PaymentOptionsComponent extends BaseComponent { this.data.notification.hideError(); }); - if (this.config.expressCheckout.active && (('ps_checkout-' + this.payPalService.getFundingSource()) !== HTMLListenerElements[index].button.dataset.moduleName)) { - this.psCheckoutApi.postCancelOrder( - { + if ( + this.config.expressCheckout.active && + 'ps_checkout-' + this.payPalService.getFundingSource() !== + HTMLListenerElements[index].button.dataset.moduleName + ) { + this.psCheckoutApi + .postCancelOrder({ orderID: this.payPalService.getOrderId(), fundingSource: this.payPalService.getFundingSource(), - isExpressCheckout: true - } - ).then(() => { - this.config.expressCheckout.active = false; + isExpressCheckout: true, + reason: 'payment_option_changed' + }) + .then(() => { + this.config.expressCheckout.active = false; - const expressCheckoutContainer = document.querySelector('#ps_checkout-express-checkout-banner'); - if (expressCheckoutContainer) { - expressCheckoutContainer.style.display = 'none'; - } - }); + const expressCheckoutContainer = document.querySelector( + '#ps_checkout-express-checkout-banner' + ); + if (expressCheckoutContainer) { + expressCheckoutContainer.style.display = 'none'; + } + }); } HTMLListenerElements[index].button.classList.add('open'); @@ -100,7 +108,10 @@ export class PaymentOptionsComponent extends BaseComponent { if (this.config.expressCheckout.active) { HTMLListenerElements.forEach(({ button, form }) => { - if (button.dataset.moduleName === ('ps_checkout-' + this.payPalService.getFundingSource())) { + if ( + button.dataset.moduleName === + 'ps_checkout-' + this.payPalService.getFundingSource() + ) { button.classList.add('open'); button.classList.remove('closed'); form.classList.add('open'); diff --git a/_dev/js/front/src/components/1_7/payment-options.component.js b/_dev/js/front/src/components/1_7/payment-options.component.js index 31a38cc62..a4d47d0bd 100644 --- a/_dev/js/front/src/components/1_7/payment-options.component.js +++ b/_dev/js/front/src/components/1_7/payment-options.component.js @@ -40,7 +40,10 @@ export class PaymentOptionsComponent extends BaseComponent { `[data-module-name^="ps_checkout-${fundingSource.name}"]` ); - if (this.config.expressCheckout.active && this.payPalService.getFundingSource() === fundingSource.name) { + if ( + this.config.expressCheckout.active && + this.payPalService.getFundingSource() === fundingSource.name + ) { HTMLElement.click(); } @@ -63,21 +66,28 @@ export class PaymentOptionsComponent extends BaseComponent { this.data.notification.hideCancelled(); this.data.notification.hideError(); - if (this.config.expressCheckout.active && (('ps_checkout-' + this.payPalService.getFundingSource()) !== radio.dataset.moduleName)) { - this.psCheckoutApi.postCancelOrder( - { + if ( + this.config.expressCheckout.active && + 'ps_checkout-' + this.payPalService.getFundingSource() !== + radio.dataset.moduleName + ) { + this.psCheckoutApi + .postCancelOrder({ orderID: this.payPalService.getOrderId(), fundingSource: this.payPalService.getFundingSource(), - isExpressCheckout: true - } - ).then(() => { - this.config.expressCheckout.active = false; + isExpressCheckout: true, + reason: 'payment_option_changed' + }) + .then(() => { + this.config.expressCheckout.active = false; - const expressCheckoutContainer = document.querySelector('#ps_checkout-express-checkout-banner'); - if (expressCheckoutContainer) { - expressCheckoutContainer.style.display = 'none'; - } - }); + const expressCheckoutContainer = document.querySelector( + '#ps_checkout-express-checkout-banner' + ); + if (expressCheckoutContainer) { + expressCheckoutContainer.style.display = 'none'; + } + }); } }); }); diff --git a/_dev/js/front/src/components/common/card-fields.component.js b/_dev/js/front/src/components/common/card-fields.component.js index 9c91018f3..286638e69 100644 --- a/_dev/js/front/src/components/common/card-fields.component.js +++ b/_dev/js/front/src/components/common/card-fields.component.js @@ -260,6 +260,15 @@ export class CardFieldsComponent extends BaseComponent { let message = error.message || this.$('checkout.form.error.label'); this.data.notification.showError(message); this.data.HTMLElementButton.removeAttribute('disabled'); + + return this.psCheckoutApi + .postCancelOrder({ + fundingSource: this.data.name, + isExpressCheckout: this.config.expressCheckout.active, + reason: 'card_fields_error', + error: error instanceof Error ? error.message : error + }) + .catch((error) => console.error(error)); }, inputEvents: { /** diff --git a/_dev/js/front/src/components/common/express-checkout-button.component.js b/_dev/js/front/src/components/common/express-checkout-button.component.js index 8bdcf624b..583a3fbc6 100644 --- a/_dev/js/front/src/components/common/express-checkout-button.component.js +++ b/_dev/js/front/src/components/common/express-checkout-button.component.js @@ -37,7 +37,7 @@ export class ExpressCheckoutButtonComponent extends BaseComponent { ...data, fundingSource: this.props.fundingSource, isExpressCheckout: true, - orderID: this.payPalService.getOrderId(), + orderID: this.payPalService.getOrderId() }, actions ) @@ -48,7 +48,16 @@ export class ExpressCheckoutButtonComponent extends BaseComponent { } onError(error) { - return console.error(error); + console.error(error); + + return this.psCheckoutApi + .postCancelOrder({ + fundingSource: this.props.fundingSource, + isExpressCheckout: true, + reason: 'express_checkout_error', + error: error instanceof Error ? error.message : error + }) + .catch((error) => console.error(error)); } onApprove(data, actions) { @@ -66,7 +75,8 @@ export class ExpressCheckoutButtonComponent extends BaseComponent { return this.psCheckoutApi.postCancelOrder({ ...data, fundingSource: this.props.fundingSource, - isExpressCheckout: true + isExpressCheckout: true, + reason: 'express_checkout_cancelled' }); } diff --git a/_dev/js/front/src/components/common/smart-button.component.js b/_dev/js/front/src/components/common/smart-button.component.js index 56473d0af..4456eecaf 100644 --- a/_dev/js/front/src/components/common/smart-button.component.js +++ b/_dev/js/front/src/components/common/smart-button.component.js @@ -91,41 +91,53 @@ export class SmartButtonComponent extends BaseComponent { } return this.psCheckoutApi - .postCheckCartOrder({ + .postCheckCartOrder( + { ...data, fundingSource: this.data.name, isExpressCheckout: this.config.expressCheckout.active, - orderID: this.payPalService.getOrderId(), + orderID: this.payPalService.getOrderId() }, actions ) - .catch(error => { + .catch((error) => { this.data.loader.hide(); this.data.notification.showError(error.message); return actions.reject(); }); }, - onError: error => { + onError: (error) => { + let errorMessage = this.handleError(error); console.error(error); this.data.loader.hide(); - this.data.notification.showError(this.handleError(error)); + this.data.notification.showError(errorMessage); + + return this.psCheckoutApi + .postCancelOrder({ + fundingSource: this.data.name, + isExpressCheckout: this.config.expressCheckout.active, + reason: 'checkout_error', + error: errorMessage + }) + .catch((error) => console.error(error)); }, onApprove: (data, actions) => { this.data.loader.show(); return this.psCheckoutApi - .postValidateOrder({ + .postValidateOrder( + { ...data, fundingSource: this.data.name, isExpressCheckout: this.config.expressCheckout.active }, actions ) - .catch(error => { + .catch((error) => { this.data.loader.hide(); this.data.notification.showError(error.message); }); }, - onCancel: data => { + onCancel: (data) => { this.data.loader.hide(); this.data.notification.showCanceled(); @@ -133,21 +145,22 @@ export class SmartButtonComponent extends BaseComponent { .postCancelOrder({ ...data, fundingSource: this.data.name, - isExpressCheckout: this.config.expressCheckout.active + isExpressCheckout: this.config.expressCheckout.active, + reason: 'checkout_cancelled' }) - .catch(error => { + .catch((error) => { this.data.loader.hide(); this.data.notification.showError(error.message); }); }, - createOrder: data => { + createOrder: (data) => { return this.psCheckoutApi .postCreateOrder({ ...data, fundingSource: this.data.name, isExpressCheckout: this.config.expressCheckout.active }) - .catch(error => { + .catch((error) => { this.data.loader.hide(); this.data.notification.showError( `${error.message} ${error.name}` @@ -165,10 +178,16 @@ export class SmartButtonComponent extends BaseComponent { if (error.message) { errorMessage = error.message; - if (error.message.includes('CURRENCY_NOT_SUPPORTED_BY_PAYMENT_SOURCE')) { - errorMessage = 'Provided currency is not supported by the selected payment method.'; - } else if (error.message.includes('COUNTRY_NOT_SUPPORTED_BY_PAYMENT_SOURCE')) { - errorMessage = 'Provided country is not supported by the selected payment method.'; + if ( + error.message.includes('CURRENCY_NOT_SUPPORTED_BY_PAYMENT_SOURCE') + ) { + errorMessage = + 'Provided currency is not supported by the selected payment method.'; + } else if ( + error.message.includes('COUNTRY_NOT_SUPPORTED_BY_PAYMENT_SOURCE') + ) { + errorMessage = + 'Provided country is not supported by the selected payment method.'; } } } diff --git a/config/common.yml b/config/common.yml index da0e5ec26..891cd9802 100644 --- a/config/common.yml +++ b/config/common.yml @@ -236,10 +236,6 @@ services: arguments: - "@ps_checkout.module" - ps_checkout.funding_source.entity: - class: 'PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceEntity' - public: true - ps_checkout.repository.country: class: 'PrestaShop\Module\PrestashopCheckout\Repository\CountryRepository' public: true @@ -367,8 +363,11 @@ services: class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderSummaryViewBuilder' public: true arguments: - - '@ps_checkout.translations.translations' - - '@ps_checkout.funding_source.translation' + - '@ps_checkout.repository.pscheckoutcart' + - '@ps_checkout.paypal.provider.order' + - '@ps_checkout.prestashop.router' + - '@ps_checkout.paypal.order.translations' + - '@ps_checkout.context.shop' ps_checkout.paypal.builder.view_order_summary: class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderSummaryViewBuilder' @@ -456,18 +455,24 @@ services: PrestaShop\Module\PrestashopCheckout\Order\Command\CreateOrderCommand: "ps_checkout.command.handler.order.create_order" PrestaShop\Module\PrestashopCheckout\Order\Command\UpdateOrderStatusCommand: "ps_checkout.command.handler.order.update_order_status" PrestaShop\Module\PrestashopCheckout\Order\Matrice\Command\UpdateOrderMatriceCommand: "ps_checkout.command.handler.order.matrice.update_order_matrice" + PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\CreatePayPalOrderCommand: "ps_checkout.command.handler.paypal.order.create_paypal_order" + PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\UpdatePayPalOrderCommand: "ps_checkout.command.handler.paypal.order.update_paypal_order" PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\CapturePayPalOrderCommand: "ps_checkout.command.handler.paypal.order.capture_paypal_order" - PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\SavePayPalOrderCommand: "ps_checkout.command.handler.paypal.order.save_paypal_order" + PrestaShop\Module\PrestashopCheckout\Checkout\Command\CancelCheckoutCommand: "ps_checkout.command.handler.checkout.cancel_checkout" + PrestaShop\Module\PrestashopCheckout\Checkout\Command\SaveCheckoutCommand: "ps_checkout.command.handler.checkout.save_checkout" + PrestaShop\Module\PrestashopCheckout\Checkout\Command\SavePayPalOrderStatusCommand: "ps_checkout.command.handler.checkout.save_paypal_order_status" PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentCompletedQuery: "ps_checkout.query.handler.order.get_order_for_payment_completed" PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentDeniedQuery: "ps_checkout.query.handler.order.get_order_for_payment_denied" PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentPendingQuery: "ps_checkout.query.handler.order.get_order_for_payment_pending" PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentRefundedQuery: "ps_checkout.query.handler.order.get_order_for_payment_refunded" PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentReversedQuery: "ps_checkout.query.handler.order.get_order_for_payment_reversed" PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForApprovalReversedQuery: "ps_checkout.query.handler.order.get_order_for_approval_reversed" + PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetPayPalOrderForCartIdQuery: "ps_checkout.query.handler.paypal.order.get_paypal_order_for_cart_id" PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetCurrentPayPalOrderStatusQuery: "ps_checkout.query.handler.paypal.order.get_current_paypal_order_status" PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetPayPalOrderForCheckoutCompletedQuery: "ps_checkout.query.handler.paypal.order.get_paypal_order_for_checkout_completed" PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetPayPalOrderForOrderConfirmationQuery: "ps_checkout.query.handler.paypal.order.get_paypal_order_for_order_confirmation" PrestaShop\Module\PrestashopCheckout\Checkout\Command\UpdatePaymentMethodSelectedCommand: "ps_checkout.query.handler.checkout.update_payment_method_selected" + PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Command\RefundPayPalCaptureCommand: 'PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\CommandHandler\RefundPayPalCaptureCommandHandler' ps_checkout.event.dispatcher.factory: class: 'PrestaShop\Module\PrestashopCheckout\Event\SymfonyEventDispatcherFactory' @@ -510,6 +515,16 @@ services: - "@ps_checkout.cache.paypal.order" - "@ps_checkout.order.state.service.order_state_mapper" + PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\EventSubscriber\PayPalRefundEventSubscriber: + class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\EventSubscriber\PayPalRefundEventSubscriber' + arguments: + - '@ps_checkout.module' + - '@ps_checkout.order.service.check_order_amount' + - '@ps_checkout.cache.paypal.capture' + - '@ps_checkout.cache.paypal.order' + - '@ps_checkout.order.state.service.order_state_mapper' + - '@ps_checkout.paypal.provider.order' + ps_checkout.event.dispatcher.symfony: class: 'Symfony\Component\EventDispatcher\EventDispatcherInterface' factory: ["@ps_checkout.event.dispatcher.factory", "create"] @@ -519,6 +534,7 @@ services: "@ps_checkout.event.subscriber.order", "@ps_checkout.event.subscriber.paypal.order", "@ps_checkout.event.subscriber.paypal.capture", + '@PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\EventSubscriber\PayPalRefundEventSubscriber' ] ps_checkout.event.dispatcher: @@ -558,18 +574,29 @@ services: arguments: - "@ps_checkout.event.dispatcher" - ps_checkout.command.handler.paypal.order.capture_paypal_order: - class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\CommandHandler\CapturePayPalOrderCommandHandler' + ps_checkout.command.handler.paypal.order.create_paypal_order: + class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\CommandHandler\CreatePayPalOrderCommandHandler' public: true arguments: + - "@ps_checkout.http.client.checkout" - "@ps_checkout.event.dispatcher" - - "@ps_checkout.cache.paypal.order" + - "@ps_checkout.context.shop" - ps_checkout.command.handler.paypal.order.save_paypal_order: - class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\CommandHandler\SavePayPalOrderCommandHandler' + ps_checkout.command.handler.paypal.order.update_paypal_order: + class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\CommandHandler\UpdatePayPalOrderCommandHandler' public: true arguments: - - "@ps_checkout.repository.pscheckoutcart" + - "@ps_checkout.http.client.checkout" + - "@ps_checkout.event.dispatcher" + - "@ps_checkout.context.shop" + + ps_checkout.command.handler.paypal.order.capture_paypal_order: + class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\CommandHandler\CapturePayPalOrderCommandHandler' + public: true + arguments: + - "@ps_checkout.http.client.checkout" + - "@ps_checkout.event.dispatcher" + - "@ps_checkout.cache.paypal.order" ps_checkout.query.handler.paypal.order.get_current_paypal_order_status: class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\QueryHandler\GetCurrentPayPalOrderStatusQueryHandler' @@ -613,6 +640,13 @@ services: arguments: - "@ps_checkout.repository.pscheckoutcart" + ps_checkout.query.handler.paypal.order.get_paypal_order_for_cart_id: + class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\QueryHandler\GetPayPalOrderForCartIdQueryHandler' + public: true + arguments: + - '@ps_checkout.cache.paypal.order' + - '@ps_checkout.repository.pscheckoutcart' + ps_checkout.query.handler.paypal.order.get_paypal_order_for_checkout_completed: class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\QueryHandler\GetPayPalOrderForCheckoutCompletedQueryHandler' public: true @@ -625,12 +659,41 @@ services: arguments: - "@ps_checkout.cache.paypal.order" + ps_checkout.command.handler.checkout.save_checkout: + class: 'PrestaShop\Module\PrestashopCheckout\Checkout\CommandHandler\SaveCheckoutCommandHandler' + public: true + arguments: + - "@ps_checkout.repository.pscheckoutcart" + + ps_checkout.command.handler.checkout.cancel_checkout: + class: 'PrestaShop\Module\PrestashopCheckout\Checkout\CommandHandler\CancelCheckoutCommandHandler' + public: true + arguments: + - "@ps_checkout.repository.pscheckoutcart" + + ps_checkout.command.handler.checkout.save_paypal_order_status: + class: 'PrestaShop\Module\PrestashopCheckout\Checkout\CommandHandler\SavePayPalOrderStatusCommandHandler' + public: true + arguments: + - "@ps_checkout.repository.pscheckoutcart" + ps_checkout.query.handler.checkout.update_payment_method_selected: class: 'PrestaShop\Module\PrestashopCheckout\Checkout\CommandHandler\UpdatePaymentMethodSelectedCommandHandler' public: true arguments: - "@ps_checkout.repository.pscheckoutcart" + PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\CommandHandler\RefundPayPalCaptureCommandHandler: + class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\CommandHandler\RefundPayPalCaptureCommandHandler' + arguments: + - '@ps_checkout.http.client.checkout' + - '@ps_checkout.paypal.configuration' + - '@ps_checkout.configuration' + - '@ps_checkout.context.prestashop' + - '@ps_checkout.event.dispatcher' + - '@ps_checkout.cache.paypal.order' + - '@ps_checkout.paypal.provider.order' + ps_checkout.paypal.capture.service.check_transition_paypal_capture_status: class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\CheckTransitionPayPalCaptureStatusService' public: true @@ -640,3 +703,34 @@ services: public: true arguments: - "@ps_checkout.logger" + + ps_checkout.environment.payment: + class: 'PrestaShop\Module\PrestashopCheckout\Environment\PaymentEnv' + public: true + + ps_checkout.http.client.configuration: + class: 'PrestaShop\Module\PrestashopCheckout\Http\CheckoutHttpClientConfigurationBuilder' + public: true + arguments: + - "@ps_checkout.environment.payment" + - "@ps_checkout.prestashop.router" + - "@ps_checkout.context.shop" + - "@ps_checkout.repository.prestashop.account" + - "@ps_checkout.context.prestashop" + + ps_checkout.http.client.factory: + class: 'PrestaShop\Module\PrestashopCheckout\Http\HttpClientFactory' + public: true + + ps_checkout.http.client: + class: 'PrestaShop\Module\PrestashopCheckout\Http\HttpClientInterface' + public: true + factory: ["@ps_checkout.http.client.factory", "create"] + arguments: + - "@ps_checkout.http.client.configuration" + + ps_checkout.http.client.checkout: + class: 'PrestaShop\Module\PrestashopCheckout\Http\CheckoutHttpClient' + public: true + arguments: + - "@ps_checkout.http.client" diff --git a/controllers/admin/AdminAjaxPrestashopCheckoutController.php b/controllers/admin/AdminAjaxPrestashopCheckoutController.php index cce1e0ae7..c6630e0b2 100755 --- a/controllers/admin/AdminAjaxPrestashopCheckoutController.php +++ b/controllers/admin/AdminAjaxPrestashopCheckoutController.php @@ -19,6 +19,7 @@ */ use Monolog\Logger; +use PrestaShop\Module\PrestashopCheckout\CommandBus\CommandBusInterface; use PrestaShop\Module\PrestashopCheckout\Configuration\BatchConfigurationProcessor; use PrestaShop\Module\PrestashopCheckout\ExpressCheckout\ExpressCheckoutConfiguration; use PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceConfigurationRepository; @@ -33,6 +34,9 @@ use PrestaShop\Module\PrestashopCheckout\Order\State\OrderStateInstaller; use PrestaShop\Module\PrestashopCheckout\Order\State\Service\OrderStateMapper; use PrestaShop\Module\PrestashopCheckout\PayPal\Mode; +use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Command\RefundPayPalCaptureCommand; +use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Exception\PayPalRefundException; +use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Exception\PayPalRefundFailedException; use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration; use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalOrderProvider; use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalPayLaterConfiguration; @@ -41,7 +45,6 @@ use PrestaShop\Module\PrestashopCheckout\Settings\RoundingSettings; use PrestaShop\Module\PrestashopCheckout\Validator\BatchConfigurationValidator; use PrestaShop\Module\PrestashopCheckout\Webhook\WebhookSecretTokenService; -use Psr\SimpleCache\CacheInterface; class AdminAjaxPrestashopCheckoutController extends ModuleAdminController { @@ -439,92 +442,60 @@ public function ajaxProcessFetchOrder() public function ajaxProcessRefundOrder() { $orderPayPalId = Tools::getValue('orderPayPalRefundOrder'); - $transactionPayPalId = Tools::getValue('orderPayPalRefundTransaction'); + $captureId = Tools::getValue('orderPayPalRefundTransaction'); $amount = Tools::getValue('orderPayPalRefundAmount'); $currency = Tools::getValue('orderPayPalRefundCurrency'); - if (empty($orderPayPalId) || false === Validate::isGenericName($orderPayPalId)) { - http_response_code(400); - $this->ajaxDie(json_encode([ - 'status' => false, - 'errors' => [ - $this->l('PayPal Order is invalid.', 'translations'), - ], - ])); - } + /** @var CommandBusInterface $commandBus */ + $commandBus = $this->module->getService('ps_checkout.bus.command'); - if (empty($transactionPayPalId) || false === Validate::isGenericName($transactionPayPalId)) { - http_response_code(400); - $this->ajaxDie(json_encode([ - 'status' => false, - 'errors' => [ - $this->l('PayPal Transaction is invalid.', 'translations'), - ], - ])); - } + try { + $commandBus->handle(new RefundPayPalCaptureCommand($orderPayPalId, $captureId, $currency, $amount)); - if (empty($amount) || false === Validate::isPrice($amount) || $amount <= 0) { - http_response_code(400); $this->ajaxDie(json_encode([ - 'status' => false, - 'errors' => [ - $this->l('PayPal refund amount is invalid.', 'translations'), - ], + 'status' => true, + 'content' => $this->l('Refund has been processed by PayPal.', 'translations'), ])); - } - - if (empty($currency) || false === in_array($currency, ['AUD', 'BRL', 'CAD', 'CZK', 'DKK', 'EUR', 'HKD', 'HUF', 'INR', 'ILS', 'JPY', 'MYR', 'MXN', 'TWD', 'NZD', 'NOK', 'PHP', 'PLN', 'GBP', 'RUB', 'SGD', 'SEK', 'CHF', 'THB', 'USD'])) { - // https://developer.paypal.com/docs/api/reference/currency-codes/ - http_response_code(400); + } catch (PayPalRefundFailedException $exception) { + http_response_code($exception->getCode()); $this->ajaxDie(json_encode([ 'status' => false, 'errors' => [ - $this->l('PayPal refund currency is invalid.', 'translations'), + $this->l('Refund cannot be processed by PayPal.', 'translations'), ], ])); - } - - /** @var PayPalConfiguration $configurationPayPal */ - $configurationPayPal = $this->module->getService('ps_checkout.paypal.configuration'); - - $response = (new PrestaShop\Module\PrestashopCheckout\Api\Payment\Order($this->context->link))->refund([ - 'orderId' => $orderPayPalId, - 'captureId' => $transactionPayPalId, - 'payee' => [ - 'merchant_id' => $configurationPayPal->getMerchantId(), - ], - 'amount' => [ - 'currency_code' => $currency, - 'value' => $amount, - ], - 'note_to_payer' => 'Refund by ' - . Configuration::get( - 'PS_SHOP_NAME', - null, - null, - (int) Context::getContext()->shop->id - ), - ]); - - if (isset($response['httpCode']) && $response['httpCode'] === 200) { - /** @var CacheInterface $orderPayPalCache */ - $orderPayPalCache = $this->module->getService('ps_checkout.cache.paypal.order'); - if ($orderPayPalCache->has($orderPayPalId)) { - $orderPayPalCache->delete($orderPayPalId); + } catch (PayPalRefundException $invalidArgumentException) { + http_response_code(400); + $error = ''; + switch ($invalidArgumentException->getCode()) { + case PayPalRefundException::INVALID_ORDER_ID: + $error = $this->l('PayPal Order is invalid.', 'translations'); + break; + case PayPalRefundException::INVALID_TRANSACTION_ID: + $error = $this->l('PayPal Transaction is invalid.', 'translations'); + break; + case PayPalRefundException::INVALID_CURRENCY: + $error = $this->l('PayPal refund currency is invalid.', 'translations'); + break; + case PayPalRefundException::INVALID_AMOUNT: + $error = $this->l('PayPal refund amount is invalid.', 'translations'); + break; + default: + break; } - $this->ajaxDie(json_encode([ - 'status' => true, - 'content' => $this->l('Refund has been processed by PayPal.', 'translations'), + 'status' => false, + 'errors' => [$error], ])); - } else { - http_response_code(isset($response['httpCode']) ? (int) $response['httpCode'] : 500); - $this->ajaxDie(json_encode([ + } catch (Exception $exception) { + $this->exitWithResponse([ + 'httpCode' => 500, 'status' => false, 'errors' => [ $this->l('Refund cannot be processed by PayPal.', 'translations'), ], - ])); + 'error' => $exception->getMessage(), + ]); } } diff --git a/controllers/front/cancel.php b/controllers/front/cancel.php index bccd1d7fe..ac4d507e7 100644 --- a/controllers/front/cancel.php +++ b/controllers/front/cancel.php @@ -18,8 +18,9 @@ * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 */ +use PrestaShop\Module\PrestashopCheckout\Checkout\Command\CancelCheckoutCommand; +use PrestaShop\Module\PrestashopCheckout\CommandBus\CommandBusInterface; use PrestaShop\Module\PrestashopCheckout\Controller\AbstractFrontController; -use PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository; /** * This controller receive ajax call on customer canceled payment @@ -68,6 +69,8 @@ public function postProcess() $fundingSource = isset($bodyValues['fundingSource']) ? $bodyValues['fundingSource'] : null; $isExpressCheckout = isset($bodyValues['isExpressCheckout']) && $bodyValues['isExpressCheckout']; $isHostedFields = isset($bodyValues['isHostedFields']) && $bodyValues['isHostedFields']; + $reason = isset($bodyValues['reason']) ? Tools::safeOutput($bodyValues['reason']) : null; + $error = isset($bodyValues['error']) ? Tools::safeOutput($bodyValues['error']) : null; if (empty($orderId)) { $this->exitWithResponse([ @@ -76,27 +79,28 @@ public function postProcess() ]); } - /** @var PsCheckoutCartRepository $psCheckoutCartRepository */ - $psCheckoutCartRepository = $this->module->getService('ps_checkout.repository.pscheckoutcart'); + /** @var CommandBusInterface $commandBus */ + $commandBus = $this->module->getService('ps_checkout.bus.command'); - /** @var PsCheckoutCart|false $psCheckoutCart */ - $psCheckoutCart = $psCheckoutCartRepository->findOneByPayPalOrderId($orderId); + $commandBus->handle(new CancelCheckoutCommand( + $this->context->cart->id, + $orderId, + PsCheckoutCart::STATUS_CANCELED, + $fundingSource, + $isExpressCheckout, + $isHostedFields + )); - if (false !== $psCheckoutCart) { - $psCheckoutCart->paypal_funding = $fundingSource; - $psCheckoutCart->isExpressCheckout = $isExpressCheckout; - $psCheckoutCart->isHostedFields = $isHostedFields; - $psCheckoutCart->paypal_status = PsCheckoutCart::STATUS_CANCELED; - $psCheckoutCartRepository->save($psCheckoutCart); - } - - $this->module->getLogger()->info( + $this->module->getLogger()->log( + $error ? 400 : 200, 'Customer canceled payment', [ 'PayPalOrderId' => $orderId, 'FundingSource' => $fundingSource, 'isExpressCheckout' => $isExpressCheckout, 'isHostedFields' => $isHostedFields, + 'reason' => $reason, + 'error' => $error, ] ); diff --git a/controllers/front/check.php b/controllers/front/check.php index 7f38cc04e..875b107d9 100644 --- a/controllers/front/check.php +++ b/controllers/front/check.php @@ -18,11 +18,11 @@ * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 */ +use PrestaShop\Module\PrestashopCheckout\Checkout\Command\CancelCheckoutCommand; +use PrestaShop\Module\PrestashopCheckout\Checkout\Command\UpdatePaymentMethodSelectedCommand; +use PrestaShop\Module\PrestashopCheckout\CommandBus\CommandBusInterface; use PrestaShop\Module\PrestashopCheckout\Controller\AbstractFrontController; -use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; -use PrestaShop\Module\PrestashopCheckout\Handler\CreatePaypalOrderHandler; -use PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository; -use Psr\SimpleCache\CacheInterface; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\UpdatePayPalOrderCommand; /** * This controller receive ajax call on customer click on a payment button @@ -67,6 +67,7 @@ public function postProcess() ]); } + $cartId = (int) $this->context->cart->id; $fundingSource = isset($bodyValues['fundingSource']) ? $bodyValues['fundingSource'] : 'paypal'; $orderId = isset($bodyValues['orderID']) ? $bodyValues['orderID'] : null; $isExpressCheckout = isset($bodyValues['isExpressCheckout']) && $bodyValues['isExpressCheckout']; @@ -79,52 +80,14 @@ public function postProcess() ]); } - /** @var PsCheckoutCartRepository $psCheckoutCartRepository */ - $psCheckoutCartRepository = $this->module->getService('ps_checkout.repository.pscheckoutcart'); - - /** @var PsCheckoutCart|false $psCheckoutCart */ - $psCheckoutCart = $psCheckoutCartRepository->findOneByPayPalOrderId($orderId); - - if (false === $psCheckoutCart) { - $psCheckoutCart = new PsCheckoutCart(); - $psCheckoutCart->id_cart = (int) $this->context->cart->id; - } - - if ($fundingSource) { - $psCheckoutCart->paypal_funding = $fundingSource; - } - - $psCheckoutCart->isExpressCheckout = $isExpressCheckout; - $psCheckoutCart->isHostedFields = $isHostedFields; - $psCheckoutCartRepository->save($psCheckoutCart); - - if (false === empty($psCheckoutCart->paypal_order)) { - $paypalOrder = new CreatePaypalOrderHandler($this->context); - $response = $paypalOrder->handle($isExpressCheckout || empty($this->context->cart->id_address_delivery), $psCheckoutCart->paypal_funding === 'card', true, $psCheckoutCart->paypal_order); - - if (false === $response['status']) { - $this->module->getLogger()->error( - 'Failed to patch PayPal Order', - [ - 'PayPalOrderId' => $orderId, - 'FundingSource' => $fundingSource, - 'isExpressCheckout' => $isExpressCheckout, - 'isHostedFields' => $isHostedFields, - 'id_cart' => (int) $this->context->cart->id, - 'response' => $response, - ] - ); - $psCheckoutCart->paypal_status = PsCheckoutCart::STATUS_CANCELED; - $psCheckoutCartRepository->save($psCheckoutCart); - throw new PsCheckoutException(sprintf('Unable to patch PayPal Order - Exception %s : %s', $response['exceptionCode'], $response['exceptionMessage']), PsCheckoutException::PSCHECKOUT_UPDATE_ORDER_HANDLE_ERROR); - } - - /** @var CacheInterface $orderPayPalCache */ - $orderPayPalCache = $this->module->getService('ps_checkout.cache.paypal.order'); - $orderPayPalCache->delete($psCheckoutCart->getPaypalOrderId()); - - $this->module->getLogger()->info( - 'PayPal Order patched', + /** @var CommandBusInterface $commandBus */ + $commandBus = $this->module->getService('ps_checkout.bus.command'); + $commandBus->handle(new UpdatePaymentMethodSelectedCommand($cartId, $orderId, $fundingSource, $isExpressCheckout, $isHostedFields)); + try { + $commandBus->handle(new UpdatePayPalOrderCommand($orderId, $cartId, $fundingSource, $isHostedFields, $isExpressCheckout)); + } catch (Exception $exception) { + $this->module->getLogger()->error( + 'Failed to patch PayPal Order', [ 'PayPalOrderId' => $orderId, 'FundingSource' => $fundingSource, @@ -133,6 +96,14 @@ public function postProcess() 'id_cart' => (int) $this->context->cart->id, ] ); + $commandBus->handle(new CancelCheckoutCommand( + $this->context->cart->id, + $orderId, + PsCheckoutCart::STATUS_CANCELED, + $fundingSource, + $isExpressCheckout, + $isHostedFields + )); } $this->exitWithResponse([ diff --git a/controllers/front/create.php b/controllers/front/create.php index 182b4da49..b5fadb430 100755 --- a/controllers/front/create.php +++ b/controllers/front/create.php @@ -19,11 +19,11 @@ * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 */ +use PrestaShop\Module\PrestashopCheckout\CommandBus\CommandBusInterface; use PrestaShop\Module\PrestashopCheckout\Controller\AbstractFrontController; -use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; -use PrestaShop\Module\PrestashopCheckout\Handler\CreatePaypalOrderHandler; -use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration; -use PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\CreatePayPalOrderCommand; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetPayPalOrderForCartIdQuery; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetPayPalOrderForCartIdQueryResult; /** * This controller receive ajax call to create a PayPal Order @@ -93,97 +93,25 @@ public function postProcess() } // END Express Checkout - if (false === Validate::isLoadedObject($this->context->cart)) { - $this->exitWithResponse([ - 'httpCode' => 400, - 'body' => 'No cart found.', - ]); - } - - /** @var PsCheckoutCartRepository $psCheckoutCartRepository */ - $psCheckoutCartRepository = $this->module->getService('ps_checkout.repository.pscheckoutcart'); - - /** @var PsCheckoutCart|false $psCheckoutCart */ - $psCheckoutCart = $psCheckoutCartRepository->findOneByCartId((int) $this->context->cart->id); - - $isExpressCheckout = (isset($bodyValues['isExpressCheckout']) && $bodyValues['isExpressCheckout']) || empty($this->context->cart->id_address_delivery); - - if (false !== $psCheckoutCart && $psCheckoutCart->isExpressCheckout() && $psCheckoutCart->isOrderAvailable()) { - $this->exitWithResponse([ - 'status' => true, - 'httpCode' => 200, - 'body' => [ - 'orderID' => $psCheckoutCart->paypal_order, - ], - 'exceptionCode' => null, - 'exceptionMessage' => null, - ]); - } - - // If we have a PayPal Order Id with a status CREATED or APPROVED or PAYER_ACTION_REQUIRED we mark it as CANCELED and create new one - // This is needed because cart gets updated so we need to update paypal order too - if ( - false !== $psCheckoutCart && $psCheckoutCart->getPaypalOrderId() - ) { - $psCheckoutCart->paypal_status = PsCheckoutCart::STATUS_CANCELED; - $psCheckoutCartRepository->save($psCheckoutCart); - $psCheckoutCart = false; - } - - $paypalOrder = new CreatePaypalOrderHandler($this->context); - $response = $paypalOrder->handle($isExpressCheckout, isset($bodyValues['fundingSource']) && $bodyValues['fundingSource'] === 'card'); + $cartId = (int) $this->context->cart->id; - if (false === $response['status']) { - throw new PsCheckoutException($response['exceptionMessage'], (int) $response['exceptionCode']); - } - - if (empty($response['body']['id'])) { - throw new PsCheckoutException('Paypal order id is missing.', PsCheckoutException::PAYPAL_ORDER_IDENTIFIER_MISSING); - } - - $paymentSource = isset($response['body']['payment_source']) ? key($response['body']['payment_source']) : 'paypal'; - $fundingSource = isset($bodyValues['fundingSource']) ? $bodyValues['fundingSource'] : $paymentSource; - $orderId = isset($bodyValues['orderID']) ? $bodyValues['orderID'] : null; - $isExpressCheckout = isset($bodyValues['isExpressCheckout']) && $bodyValues['isExpressCheckout']; + $fundingSource = isset($bodyValues['fundingSource']) ? $bodyValues['fundingSource'] : 'paypal'; $isHostedFields = isset($bodyValues['isHostedFields']) && $bodyValues['isHostedFields']; - /** @var PayPalConfiguration $configuration */ - $configuration = $this->module->getService('ps_checkout.paypal.configuration'); - - $this->module->getLogger()->info( - 'PayPal Order created', - [ - 'PayPalOrderId' => $orderId, - 'FundingSource' => $fundingSource, - 'isExpressCheckout' => $isExpressCheckout, - 'isHostedFields' => $isHostedFields, - 'id_cart' => (int) $this->context->cart->id, - 'amount' => $this->context->cart->getOrderTotal(true, Cart::BOTH), - 'environment' => $configuration->getPaymentMode(), - 'intent' => $configuration->getIntent(), - ] - ); + $isExpressCheckout = (isset($bodyValues['isExpressCheckout']) && $bodyValues['isExpressCheckout']) || empty($this->context->cart->id_address_delivery); - if (false === $psCheckoutCart) { - $psCheckoutCart = new PsCheckoutCart(); - $psCheckoutCart->id_cart = (int) $this->context->cart->id; - } + /** @var CommandBusInterface $commandBus */ + $commandBus = $this->module->getService('ps_checkout.bus.command'); + $commandBus->handle(new CreatePayPalOrderCommand($cartId, $fundingSource, $isHostedFields, $isExpressCheckout)); - $psCheckoutCart->paypal_funding = $fundingSource; - $psCheckoutCart->paypal_order = $response['body']['id']; - $psCheckoutCart->paypal_status = $response['body']['status']; - $psCheckoutCart->paypal_intent = $configuration->getIntent(); - $psCheckoutCart->paypal_token = $response['body']['client_token']; - $psCheckoutCart->paypal_token_expire = (new DateTime())->modify('+3550 seconds')->format('Y-m-d H:i:s'); - $psCheckoutCart->environment = $configuration->getPaymentMode(); - $psCheckoutCart->isExpressCheckout = isset($bodyValues['isExpressCheckout']) && $bodyValues['isExpressCheckout']; - $psCheckoutCart->isHostedFields = isset($bodyValues['isHostedFields']) && $bodyValues['isHostedFields']; - $psCheckoutCartRepository->save($psCheckoutCart); + /** @var GetPayPalOrderForCartIdQueryResult $getPayPalOrderForCartIdQueryResult */ + $getPayPalOrderForCartIdQueryResult = $commandBus->handle(new GetPayPalOrderForCartIdQuery($cartId)); + $order = $getPayPalOrderForCartIdQueryResult->getOrder(); $this->exitWithResponse([ 'status' => true, 'httpCode' => 200, 'body' => [ - 'orderID' => $psCheckoutCart->paypal_order, + 'orderID' => $order['id'], ], 'exceptionCode' => null, 'exceptionMessage' => null, diff --git a/src/Api/Payment/Order.php b/src/Api/Payment/Order.php index 9b4b9db89..18f97a0d5 100644 --- a/src/Api/Payment/Order.php +++ b/src/Api/Payment/Order.php @@ -25,10 +25,13 @@ /** * Handle order requests + * + * @deprecated */ class Order extends PaymentClient { /** + * @deprecated * Create order to paypal api * * @param array $payload Cart details (json) @@ -43,6 +46,7 @@ public function create($payload) } /** + * @deprecated * Capture order funds * * @param string $orderId paypal @@ -65,6 +69,7 @@ public function capture($orderId, $merchantId, $fundingSource) } /** + * @deprecated * Get paypal order details * * @param string $orderId paypal @@ -95,6 +100,7 @@ public function authorize($orderId, $merchantId) } /** + * @deprecated * Refund an order * * @param array $payload @@ -109,6 +115,7 @@ public function refund($payload) } /** + * @deprecated * Patch paypal order * * @param array $payload diff --git a/src/Builder/Payload/OrderPayloadBuilder.php b/src/Builder/Payload/OrderPayloadBuilder.php index 61011b1b4..7d75a802c 100644 --- a/src/Builder/Payload/OrderPayloadBuilder.php +++ b/src/Builder/Payload/OrderPayloadBuilder.php @@ -109,8 +109,8 @@ public function buildFullPayload() } if ($this->isCard) { - $this->buildPaymentSourceNode(); - $this->buildSupplementaryDataNode(); + //$this->buildPaymentSourceNode(); + //$this->buildSupplementaryDataNode(); } } diff --git a/src/Checkout/Command/CancelCheckoutCommand.php b/src/Checkout/Command/CancelCheckoutCommand.php new file mode 100644 index 000000000..50c7530c5 --- /dev/null +++ b/src/Checkout/Command/CancelCheckoutCommand.php @@ -0,0 +1,128 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\Checkout\Command; + +use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; +use PrestaShop\Module\PrestashopCheckout\Cart\ValueObject\CartId; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\ValueObject\PayPalOrderId; + +class CancelCheckoutCommand +{ + /** + * @var CartId + */ + private $cartId; + + /** + * @var PayPalOrderId + */ + private $orderPayPalId; + + /** + * @var string + */ + private $orderPayPalStatus; + + /** + * @var string + */ + private $fundingSource; + + /** + * @var bool + */ + private $isExpressCheckout; + + /** + * @var bool + */ + private $isHostedFields; + + /** + * @param int $cartId + * @param string $orderPayPalId + * @param string $orderPayPalStatus + * @param string $fundingSource + * @param bool $isExpressCheckout + * @param bool $isHostedFields + * + * @throws CartException + * @throws PayPalOrderException + */ + public function __construct($cartId, $orderPayPalId, $orderPayPalStatus, $fundingSource, $isExpressCheckout, $isHostedFields) + { + $this->cartId = new CartId($cartId); + $this->orderPayPalId = new PayPalOrderId($orderPayPalId); + $this->orderPayPalStatus = $orderPayPalStatus; + $this->fundingSource = $fundingSource; + $this->isExpressCheckout = $isExpressCheckout; + $this->isHostedFields = $isHostedFields; + } + + /** + * @return CartId + */ + public function getCartId() + { + return $this->cartId; + } + + /** + * @return PayPalOrderId + */ + public function getOrderPayPalId() + { + return $this->orderPayPalId; + } + + /** + * @return string + */ + public function getFundingSource() + { + return $this->fundingSource; + } + + /** + * @return bool + */ + public function isExpressCheckout() + { + return $this->isExpressCheckout; + } + + /** + * @return bool + */ + public function isHostedFields() + { + return $this->isHostedFields; + } + + /** + * @return string + */ + public function getOrderPayPalStatus() + { + return $this->orderPayPalStatus; + } +} diff --git a/src/Checkout/Command/SaveCheckoutCommand.php b/src/Checkout/Command/SaveCheckoutCommand.php new file mode 100644 index 000000000..748bdbb07 --- /dev/null +++ b/src/Checkout/Command/SaveCheckoutCommand.php @@ -0,0 +1,158 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\Checkout\Command; + +use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; +use PrestaShop\Module\PrestashopCheckout\Cart\ValueObject\CartId; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\ValueObject\PayPalOrderId; + +class SaveCheckoutCommand +{ + /** + * @var CartId + */ + private $cartId; + + /** + * @var PayPalOrderId + */ + private $orderPayPalId; + + /** + * @var string + */ + private $orderPayPalStatus; + + /** + * @var string + */ + private $intent; + + /** + * @var string + */ + private $fundingSource; + + /** + * @var bool + */ + private $isExpressCheckout; + + /** + * @var bool + */ + private $isHostedFields; + + /** + * @var string + */ + private $environment; + + /** + * @param int $cartId + * @param string $orderPayPalId + * @param string $orderPayPalStatus + * @param string $intent + * @param string $fundingSource + * @param bool $isExpressCheckout + * @param bool $isHostedFields + * @param string $environment + * + * @throws CartException + * @throws PayPalOrderException + */ + public function __construct($cartId, $orderPayPalId, $orderPayPalStatus, $intent, $fundingSource, $isExpressCheckout, $isHostedFields, $environment) + { + $this->cartId = new CartId($cartId); + $this->orderPayPalId = new PayPalOrderId($orderPayPalId); + $this->orderPayPalStatus = $orderPayPalStatus; + $this->intent = $intent; + $this->fundingSource = $fundingSource; + $this->isExpressCheckout = $isExpressCheckout; + $this->isHostedFields = $isHostedFields; + $this->environment = $environment; + } + + /** + * @return CartId + */ + public function getCartId() + { + return $this->cartId; + } + + /** + * @return PayPalOrderId + */ + public function getOrderPayPalId() + { + return $this->orderPayPalId; + } + + /** + * @return string + */ + public function getFundingSource() + { + return $this->fundingSource; + } + + /** + * @return bool + */ + public function isExpressCheckout() + { + return $this->isExpressCheckout; + } + + /** + * @return bool + */ + public function isHostedFields() + { + return $this->isHostedFields; + } + + /** + * @return string + */ + public function getOrderPayPalStatus() + { + return $this->orderPayPalStatus; + } + + /** + * @return string + */ + public function getIntent() + { + return $this->intent; + } + + /** + * @return string + */ + public function getEnvironment() + { + return $this->environment; + } +} diff --git a/src/PayPal/Order/Command/SavePayPalOrderCommand.php b/src/Checkout/Command/SavePayPalOrderStatusCommand.php similarity index 80% rename from src/PayPal/Order/Command/SavePayPalOrderCommand.php rename to src/Checkout/Command/SavePayPalOrderStatusCommand.php index 4533468e8..cdda30214 100644 --- a/src/PayPal/Order/Command/SavePayPalOrderCommand.php +++ b/src/Checkout/Command/SavePayPalOrderStatusCommand.php @@ -1,5 +1,4 @@ orderPayPalId = new PayPalOrderId($orderPayPalId); $this->orderPayPalStatus = $orderPayPalStatus; - $this->orderPayPal = $orderPayPal; } /** @@ -66,16 +58,8 @@ public function getOrderPayPalId() /** * @return string */ - public function getOrderPaypalStatus() + public function getOrderPayPalStatus() { return $this->orderPayPalStatus; } - - /** - * @return array - */ - public function getOrderPayPal() - { - return $this->orderPayPal; - } } diff --git a/src/Checkout/CommandHandler/CancelCheckoutCommandHandler.php b/src/Checkout/CommandHandler/CancelCheckoutCommandHandler.php new file mode 100644 index 000000000..36610d03a --- /dev/null +++ b/src/Checkout/CommandHandler/CancelCheckoutCommandHandler.php @@ -0,0 +1,68 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\Checkout\CommandHandler; + +use Exception; +use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartNotFoundException; +use PrestaShop\Module\PrestashopCheckout\Checkout\Command\CancelCheckoutCommand; +use PrestaShop\Module\PrestashopCheckout\Checkout\Exception\PsCheckoutSessionException; +use PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository; +use PsCheckoutCart; + +class CancelCheckoutCommandHandler +{ + /** + * @var PsCheckoutCartRepository + */ + private $psCheckoutCartRepository; + + public function __construct(PsCheckoutCartRepository $psCheckoutCartRepository) + { + $this->psCheckoutCartRepository = $psCheckoutCartRepository; + } + + /** + * @param CancelCheckoutCommand $command + * + * @throws PsCheckoutSessionException + */ + public function handle(CancelCheckoutCommand $command) + { + try { + /** @var PsCheckoutCart|false $psCheckoutCart */ + $psCheckoutCart = $this->psCheckoutCartRepository->findOneByPayPalOrderId($command->getOrderPayPalId()->getValue()); + + if (false === $psCheckoutCart) { + throw new CartNotFoundException(sprintf('Unable to retrieve PrestaShop Cart #%s', var_export($command->getCartId()->getValue(), true))); + } + + $psCheckoutCart->id_cart = $command->getCartId()->getValue(); + $psCheckoutCart->paypal_order = $command->getOrderPayPalId()->getValue(); + $psCheckoutCart->paypal_funding = $command->getFundingSource(); + $psCheckoutCart->isHostedFields = $command->isHostedFields(); + $psCheckoutCart->isExpressCheckout = $command->isExpressCheckout(); + $psCheckoutCart->paypal_status = $command->getOrderPayPalStatus(); + $this->psCheckoutCartRepository->save($psCheckoutCart); + } catch (Exception $exception) { + throw new PsCheckoutSessionException(sprintf('Unable to update PrestaShop Checkout session #%s', var_export($command->getCartId()->getValue(), true)), PsCheckoutSessionException::UPDATE_FAILED, $exception); + } + } +} diff --git a/src/Checkout/CommandHandler/SaveCheckoutCommandHandler.php b/src/Checkout/CommandHandler/SaveCheckoutCommandHandler.php new file mode 100644 index 000000000..3855f1bbb --- /dev/null +++ b/src/Checkout/CommandHandler/SaveCheckoutCommandHandler.php @@ -0,0 +1,69 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\Checkout\CommandHandler; + +use Exception; +use PrestaShop\Module\PrestashopCheckout\Checkout\Command\SaveCheckoutCommand; +use PrestaShop\Module\PrestashopCheckout\Checkout\Exception\PsCheckoutSessionException; +use PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository; +use PsCheckoutCart; + +class SaveCheckoutCommandHandler +{ + /** + * @var PsCheckoutCartRepository + */ + private $psCheckoutCartRepository; + + public function __construct(PsCheckoutCartRepository $psCheckoutCartRepository) + { + $this->psCheckoutCartRepository = $psCheckoutCartRepository; + } + + /** + * @param SaveCheckoutCommand $command + * + * @throws PsCheckoutSessionException + */ + public function handle(SaveCheckoutCommand $command) + { + try { + /** @var PsCheckoutCart|false $psCheckoutCart */ + $psCheckoutCart = $this->psCheckoutCartRepository->findOneByCartId($command->getCartId()->getValue()); + + if (false === $psCheckoutCart) { + $psCheckoutCart = new PsCheckoutCart(); + } + + $psCheckoutCart->id_cart = $command->getCartId()->getValue(); + $psCheckoutCart->paypal_order = $command->getOrderPayPalId()->getValue(); + $psCheckoutCart->paypal_funding = $command->getFundingSource(); + $psCheckoutCart->isHostedFields = $command->isHostedFields(); + $psCheckoutCart->isExpressCheckout = $command->isExpressCheckout(); + $psCheckoutCart->paypal_status = $command->getOrderPayPalStatus(); + $psCheckoutCart->paypal_intent = $command->getIntent(); + $psCheckoutCart->environment = $command->getEnvironment(); + $this->psCheckoutCartRepository->save($psCheckoutCart); + } catch (Exception $exception) { + throw new PsCheckoutSessionException(sprintf('Unable to update PrestaShop Checkout session #%s', var_export($command->getCartId()->getValue(), true)), PsCheckoutSessionException::UPDATE_FAILED, $exception); + } + } +} diff --git a/src/PayPal/Order/CommandHandler/SavePayPalOrderCommandHandler.php b/src/Checkout/CommandHandler/SavePayPalOrderStatusCommandHandler.php similarity index 52% rename from src/PayPal/Order/CommandHandler/SavePayPalOrderCommandHandler.php rename to src/Checkout/CommandHandler/SavePayPalOrderStatusCommandHandler.php index f083a905f..00483385b 100644 --- a/src/PayPal/Order/CommandHandler/SavePayPalOrderCommandHandler.php +++ b/src/Checkout/CommandHandler/SavePayPalOrderStatusCommandHandler.php @@ -1,5 +1,4 @@ psCheckoutCartRepository = $psCheckoutCartRepository; } - public function handle(SavePayPalOrderCommand $savePayPalOrderCommand) + /** + * @param SavePayPalOrderStatusCommand $command + * + * @throws PsCheckoutSessionException + */ + public function handle(SavePayPalOrderStatusCommand $command) { try { /** @var PsCheckoutCart|false $psCheckoutCart */ - $psCheckoutCart = $this->psCheckoutCartRepository->findOneByPayPalOrderId($savePayPalOrderCommand->getOrderPayPalId()->getValue()); + $psCheckoutCart = $this->psCheckoutCartRepository->findOneByPayPalOrderId($command->getOrderPayPalId()->getValue()); + + if (false === $psCheckoutCart) { + throw new CartNotFoundException(sprintf('Unable to retrieve PayPal Order %s', var_export($command->getOrderPayPalId()->getValue(), true))); + } - $psCheckoutCart->paypal_order = $savePayPalOrderCommand->getOrderPayPalId()->getValue(); - $psCheckoutCart->paypal_status = $savePayPalOrderCommand->getOrderPaypalStatus(); - $psCheckoutCart->paypal_token = null; - $psCheckoutCart->paypal_token_expire = null; + $psCheckoutCart->paypal_order = $command->getOrderPayPalId()->getValue(); + $psCheckoutCart->paypal_status = $command->getOrderPayPalStatus(); $this->psCheckoutCartRepository->save($psCheckoutCart); } catch (Exception $exception) { - throw new PayPalOrderException(sprintf('Unable to retrieve PrestaShop cart #%d', $savePayPalOrderCommand->getOrderPayPalId()->getValue()), PayPalOrderException::SESSION_EXCEPTION, $exception); + $sessionId = isset($psCheckoutCart) ? $psCheckoutCart->getIdCart() : $command->getOrderPayPalId()->getValue(); + throw new PsCheckoutSessionException(sprintf('Unable to update PrestaShop Checkout session #%s', var_export($sessionId, true)), PsCheckoutSessionException::UPDATE_FAILED, $exception); } } } diff --git a/src/Controller/AbstractFrontController.php b/src/Controller/AbstractFrontController.php index f58cb7169..6de73b31c 100644 --- a/src/Controller/AbstractFrontController.php +++ b/src/Controller/AbstractFrontController.php @@ -40,7 +40,12 @@ protected function exitWithExceptionMessage(Exception $exception) $this->exitWithResponse([ 'status' => false, 'httpCode' => 500, - 'body' => '', + 'body' => [ + 'error' => [ + 'code' => $exception->getCode(), + 'message' => $exception->getMessage(), + ], + ], 'exceptionCode' => $exception->getCode(), 'exceptionMessage' => $exception->getMessage(), ]); diff --git a/src/Dispatcher/OrderDispatcher.php b/src/Dispatcher/OrderDispatcher.php index 039ec85c9..d3a91a8ba 100644 --- a/src/Dispatcher/OrderDispatcher.php +++ b/src/Dispatcher/OrderDispatcher.php @@ -30,9 +30,9 @@ use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCaptureCompletedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCaptureDeclinedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCapturePendingEvent; -use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCaptureRefundedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCaptureReversedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Exception\PayPalCaptureException; +use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Event\PayPalCaptureRefundedEvent; use Ps_checkout; use Psr\Log\LoggerInterface; diff --git a/src/Exception/PayPalException.php b/src/Exception/PayPalException.php index 015b0a728..710268a8b 100644 --- a/src/Exception/PayPalException.php +++ b/src/Exception/PayPalException.php @@ -154,4 +154,23 @@ class PayPalException extends PsCheckoutException const CARD_BRAND_NOT_SUPPORTED = 129; const RESOURCE_NOT_FOUND = 130; const PAYMENT_SOURCE_CANNOT_BE_USED = 131; + const CANNOT_PROCESS_REFUNDS = 132; + const INVALID_REFUND_AMOUNT = 133; + const PUI_DUPLICATE_ORDER = 134; + const SAVE_ORDER_NOT_SUPPORTED = 135; + const CARD_CLOSED = 136; + const UNSUPPORTED_SHIPPING_TYPE = 137; + const SHIPPING_TYPE_NOT_SUPPORTED_FOR_CLIENT = 138; + const PAYMENT_SOURCE_INFO_CANNOT_BE_VERIFIED = 139; + const PAYMENT_SOURCE_DECLINED_BY_PROCESSOR = 140; + const MULTIPLE_SHIPPING_TYPE_NOT_SUPPORTED = 141; + const MULTIPLE_ITEM_CATEGORIES = 142; + const MISSING_PICKUP_ADDRESS = 143; + const DONATION_ITEMS_NOT_SUPPORTED = 144; + const CARD_EXPIRED = 145; + const BILLING_ADDRESS_INVALID = 146; + const MALFORMED_REQUEST = 147; + const PERMISSION_DENIED_FOR_DONATION_ITEMS = 148; + const MALFORMED_REQUEST_JSON = 149; + const PAYPAL_REQUEST_ID_REQUIRED = 150; } diff --git a/src/Handler/CreatePaypalOrderHandler.php b/src/Handler/CreatePaypalOrderHandler.php index d7599d2b0..cb34dc75d 100644 --- a/src/Handler/CreatePaypalOrderHandler.php +++ b/src/Handler/CreatePaypalOrderHandler.php @@ -23,9 +23,11 @@ use Context; use Module; -use PrestaShop\Module\PrestashopCheckout\Api\Payment\Order; use PrestaShop\Module\PrestashopCheckout\Builder\Payload\OrderPayloadBuilder; +use PrestaShop\Module\PrestashopCheckout\Exception\PayPalException; use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; +use PrestaShop\Module\PrestashopCheckout\Handler\Response\ResponseApiHandler; +use PrestaShop\Module\PrestashopCheckout\Http\CheckoutHttpClient; use PrestaShop\Module\PrestashopCheckout\Presenter\Cart\CartPresenter; use PrestaShop\Module\PrestashopCheckout\ShopContext; use Ps_checkout; @@ -91,25 +93,36 @@ public function handle($expressCheckout = false, $isCardPayment = false, $update $payload = $builder->presentPayload()->getArray(); - // Create the paypal order or update it - if (true === $updateOrder) { - $paypalOrder = (new Order($this->context->link))->patch($payload); - } else { - $paypalOrder = (new Order($this->context->link))->create($payload); - } - - // Retry with minimal payload when full payload failed (only on 1.7) - if (substr((string) $paypalOrder['httpCode'], 0, 1) === '4' && $shopContext->isShop17()) { - $builder->buildMinimalPayload(); - $payload = $builder->presentPayload()->getArray(); + /** @var CheckoutHttpClient $checkoutHttpClient */ + $checkoutHttpClient = $module->getService('ps_checkout.http.client.checkout'); + // Create the paypal order or update it + try { if (true === $updateOrder) { - $paypalOrder = (new Order($this->context->link))->patch($payload); + $response = $checkoutHttpClient->updateOrder($payload); + } else { + $response = $checkoutHttpClient->createOrder($payload); + } + } catch (PayPalException $exception) { + $previousException = $exception->getPrevious(); + $response = method_exists($previousException, 'getResponse') ? $previousException->getResponse() : null; + // Retry with minimal payload when full payload failed (only on 1.7) + if ($response && substr((string) $response->getStatusCode(), 0, 1) === '4' && $shopContext->isShop17()) { + $builder->buildMinimalPayload(); + $payload = $builder->presentPayload()->getArray(); + + if (true === $updateOrder) { + $response = $checkoutHttpClient->updateOrder($payload); + } else { + $response = $checkoutHttpClient->createOrder($payload); + } } else { - $paypalOrder = (new Order($this->context->link))->create($payload); + throw $exception; } } - return $paypalOrder; + $responseHandler = new ResponseApiHandler(); + + return $responseHandler->handleResponse($response); } } diff --git a/src/Handler/Response/ResponseApiHandler.php b/src/Handler/Response/ResponseApiHandler.php index cff811a43..3531220a8 100644 --- a/src/Handler/Response/ResponseApiHandler.php +++ b/src/Handler/Response/ResponseApiHandler.php @@ -37,8 +37,7 @@ class ResponseApiHandler */ public function handleResponse(ResponseInterface $response) { - $response->getBody()->seek(0); // Rewind Stream to avoid empty body - $responseContents = json_decode($response->getBody()->getContents(), true); + $responseContents = json_decode($response->getBody(), true); return [ 'status' => $this->responseIsSuccessful($responseContents, $response->getStatusCode()), diff --git a/src/Http/CheckoutHttpClient.php b/src/Http/CheckoutHttpClient.php new file mode 100644 index 000000000..0d03828cf --- /dev/null +++ b/src/Http/CheckoutHttpClient.php @@ -0,0 +1,184 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\Http; + +use GuzzleHttp\Psr7\Request; +use Http\Client\Exception\HttpException; +use Http\Client\Exception\NetworkException; +use Http\Client\Exception\RequestException; +use Http\Client\Exception\TransferException; +use PrestaShop\Module\PrestashopCheckout\Exception\PayPalException; +use PrestaShop\Module\PrestashopCheckout\PayPalError; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; + +class CheckoutHttpClient implements HttpClientInterface +{ + /** + * @var HttpClientInterface + */ + private $httpClient; + + public function __construct(HttpClientInterface $httpClient) + { + $this->httpClient = $httpClient; + } + + /** + * @param array $payload + * @param array $options + * + * @return ResponseInterface + * + * @throws NetworkException + * @throws HttpException + * @throws RequestException + * @throws TransferException + * @throws PayPalException + */ + public function createOrder(array $payload, array $options = []) + { + return $this->sendRequest(new Request('POST', '/payments/order/create', $options, json_encode($payload))); + } + + /** + * @param array $payload + * @param array $options + * + * @return ResponseInterface + * + * @throws NetworkException + * @throws HttpException + * @throws RequestException + * @throws TransferException + * @throws PayPalException + */ + public function updateOrder(array $payload, array $options = []) + { + return $this->sendRequest(new Request('POST', '/payments/order/update', $options, json_encode($payload))); + } + + /** + * @param array $payload + * @param array $options + * + * @return ResponseInterface + * + * @throws NetworkException + * @throws HttpException + * @throws RequestException + * @throws TransferException + * @throws PayPalException + */ + public function fetchOrder(array $payload, array $options = []) + { + return $this->sendRequest(new Request('POST', '/payments/order/fetch', $options, json_encode($payload))); + } + + /** + * @param array $payload + * @param array $options + * + * @return ResponseInterface + * + * @throws NetworkException + * @throws HttpException + * @throws RequestException + * @throws TransferException + * @throws PayPalException + */ + public function captureOrder(array $payload, array $options = []) + { + return $this->sendRequest(new Request('POST', '/payments/order/capture', $options, json_encode($payload))); + } + + /** + * @param array $payload + * @param array $options + * + * @return ResponseInterface + * + * @throws NetworkException + * @throws HttpException + * @throws RequestException + * @throws TransferException + * @throws PayPalException + */ + public function refundOrder(array $payload, array $options = []) + { + return $this->sendRequest(new Request('POST', '/payments/order/refund', $options, json_encode($payload))); + } + + /** + * @param RequestInterface $request + * + * @return ResponseInterface + * + * @throws NetworkException + * @throws HttpException + * @throws RequestException + * @throws TransferException + * @throws PayPalException + */ + public function sendRequest(RequestInterface $request) + { + try { + $response = $this->httpClient->sendRequest($request); + } catch (HttpException $exception) { + $response = $exception->getResponse(); + $message = $this->extractMessage(json_decode($response->getBody(), true)); + + if ($message) { + (new PayPalError($message))->throwException($exception); + } + + throw $exception; + } + + return $response; + } + + /** + * @param array $body + * + * @return string + */ + private function extractMessage(array $body) + { + if (isset($body['details'][0]['issue']) && preg_match('/^[0-9A-Z_]+$/', $body['details'][0]['issue']) === 1) { + return $body['details'][0]['issue']; + } + + if (isset($body['error']) && preg_match('/^[0-9A-Z_]+$/', $body['error']) === 1) { + return $body['error']; + } + + if (isset($body['message']) && preg_match('/^[0-9A-Z_]+$/', $body['message']) === 1) { + return $body['message']; + } + + if (isset($body['name']) && preg_match('/^[0-9A-Z_]+$/', $body['name']) === 1) { + return $body['name']; + } + + return ''; + } +} diff --git a/src/Http/CheckoutHttpClientConfigurationBuilder.php b/src/Http/CheckoutHttpClientConfigurationBuilder.php new file mode 100644 index 000000000..03f5bb8b9 --- /dev/null +++ b/src/Http/CheckoutHttpClientConfigurationBuilder.php @@ -0,0 +1,108 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\Http; + +use PrestaShop\Module\PrestashopCheckout\Context\PrestaShopContext; +use PrestaShop\Module\PrestashopCheckout\Environment\PaymentEnv; +use PrestaShop\Module\PrestashopCheckout\Repository\PsAccountRepository; +use PrestaShop\Module\PrestashopCheckout\Routing\Router; +use PrestaShop\Module\PrestashopCheckout\ShopContext; +use Ps_checkout; + +class CheckoutHttpClientConfigurationBuilder implements HttpClientConfigurationBuilderInterface +{ + const TIMEOUT = 10; + + /** + * @var PaymentEnv + */ + private $paymentEnv; + + /** + * @var Router + */ + private $router; + + /** + * @var ShopContext + */ + private $shopContext; + + /** + * @var PsAccountRepository + */ + private $psAccountRepository; + + /** + * @var PrestaShopContext + */ + private $prestaShopContext; + + public function __construct( + PaymentEnv $paymentEnv, + Router $router, + ShopContext $shopContext, + PsAccountRepository $psAccountRepository, + PrestaShopContext $prestaShopContext + ) { + $this->paymentEnv = $paymentEnv; + $this->router = $router; + $this->shopContext = $shopContext; + $this->psAccountRepository = $psAccountRepository; + $this->prestaShopContext = $prestaShopContext; + } + + /** + * @return array + */ + public function build() + { + return [ + 'base_url' => $this->paymentEnv->getPaymentApiUrl(), + 'verify' => $this->getVerify(), + 'timeout' => static::TIMEOUT, + 'headers' => [ + 'Content-Type' => 'application/vnd.checkout.v1+json', // api version to use (psl side) + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . $this->psAccountRepository->getIdToken(), // Token we get from PsAccounts + 'Shop-Id' => $this->psAccountRepository->getShopUuid(), // Shop UUID we get from PsAccounts + 'Hook-Url' => $this->router->getDispatchWebhookLink($this->prestaShopContext->getShopId()), + 'Bn-Code' => $this->shopContext->getBnCode(), + 'Module-Version' => Ps_checkout::VERSION, // version of the module + 'Prestashop-Version' => _PS_VERSION_, // prestashop version + ], + ]; + } + + /** + * @see https://docs.guzzlephp.org/en/5.3/clients.html#verify + * + * @return true|string + */ + protected function getVerify() + { + if (defined('_PS_CACHE_CA_CERT_FILE_') && file_exists(constant('_PS_CACHE_CA_CERT_FILE_'))) { + return constant('_PS_CACHE_CA_CERT_FILE_'); + } + + return true; + } +} diff --git a/src/Http/HttpClientConfigurationBuilderInterface.php b/src/Http/HttpClientConfigurationBuilderInterface.php new file mode 100644 index 000000000..232ab832d --- /dev/null +++ b/src/Http/HttpClientConfigurationBuilderInterface.php @@ -0,0 +1,29 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\Http; + +interface HttpClientConfigurationBuilderInterface +{ + /** + * @return array + */ + public function build(); +} diff --git a/src/Http/HttpClientFactory.php b/src/Http/HttpClientFactory.php new file mode 100644 index 000000000..6c1ca840c --- /dev/null +++ b/src/Http/HttpClientFactory.php @@ -0,0 +1,34 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\Http; + +class HttpClientFactory +{ + /** + * @param HttpClientConfigurationBuilderInterface $httpClientConfigurationBuilder + * + * @return HttpClientInterface + */ + public function create(HttpClientConfigurationBuilderInterface $httpClientConfigurationBuilder) + { + return new PsrHttpClientAdapter($httpClientConfigurationBuilder->build()); + } +} diff --git a/src/Http/HttpClientInterface.php b/src/Http/HttpClientInterface.php new file mode 100644 index 000000000..275432b11 --- /dev/null +++ b/src/Http/HttpClientInterface.php @@ -0,0 +1,50 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\Http; + +use Http\Client\Exception\HttpException; +use Http\Client\Exception\NetworkException; +use Http\Client\Exception\RequestException; +use Http\Client\Exception\TransferException; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; + +/** + * Interface HttpClientInterface + * + * This interface provides a PSR-18 compliant implementation for PHP 5.6 + */ +interface HttpClientInterface +{ + /** + * Sends a PSR-7 request and returns a PSR-7 response. + * + * @param RequestInterface $request + * + * @return ResponseInterface + * + * @throws NetworkException + * @throws HttpException + * @throws RequestException + * @throws TransferException + */ + public function sendRequest(RequestInterface $request); +} diff --git a/src/Http/PsrHttpClientAdapter.php b/src/Http/PsrHttpClientAdapter.php new file mode 100644 index 000000000..fac735f2d --- /dev/null +++ b/src/Http/PsrHttpClientAdapter.php @@ -0,0 +1,63 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\Http; + +use Http\Client\Exception\HttpException; +use Http\Client\Exception\NetworkException; +use Http\Client\Exception\TransferException; +use Prestashop\ModuleLibGuzzleAdapter\ClientFactory; +use Psr\Http\Message\RequestInterface; + +class PsrHttpClientAdapter implements HttpClientInterface +{ + private $client; + + /** + * @param array $configuration + */ + public function __construct(array $configuration) + { + $this->client = (new ClientFactory())->getClient($configuration); + } + + /** + * {@inheritdoc} + */ + public function sendRequest(RequestInterface $request) + { + try { + $response = $this->client->sendRequest($request); + } catch (\GuzzleHttp\Ring\Exception\ConnectException $exception) { + // Guzzle 5.3 use RingPHP for the low level connection + throw new NetworkException($exception->getMessage(), $request, $exception); + } catch (\GuzzleHttp\Ring\Exception\RingException $exception) { + // Guzzle 5.3 use RingPHP for the low level connection + throw new TransferException($exception->getMessage(), 0, $exception); + } + + // Guzzle 5.3 does not throw exceptions on 4xx and 5xx status codes + if ($response->getStatusCode() >= 400) { + throw new HttpException($response->getReasonPhrase(), $request, $response); + } + + return $response; + } +} diff --git a/src/PayPal/Order/Command/CreatePayPalOrderCommand.php b/src/PayPal/Order/Command/CreatePayPalOrderCommand.php new file mode 100644 index 000000000..b3b8998ef --- /dev/null +++ b/src/PayPal/Order/Command/CreatePayPalOrderCommand.php @@ -0,0 +1,95 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command; + +use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; +use PrestaShop\Module\PrestashopCheckout\Cart\ValueObject\CartId; + +class CreatePayPalOrderCommand +{ + /** + * @var CartId + */ + private $cartId; + + /** + * @var string + */ + private $fundingSource; + + /** + * @var bool + */ + private $isHostedFields; + + /** + * @var bool + */ + private $isExpressCheckout; + + /** + * @param int $cartId + * @param string $fundingSource + * @param bool $isHostedFields + * @param bool $isExpressCheckout + * + * @throws CartException + */ + public function __construct($cartId, $fundingSource, $isHostedFields, $isExpressCheckout) + { + $this->cartId = new CartId($cartId); + $this->fundingSource = $fundingSource; + $this->isHostedFields = $isHostedFields; + $this->isExpressCheckout = $isExpressCheckout; + } + + /** + * @return CartId + */ + public function getCartId() + { + return $this->cartId; + } + + /** + * @return string + */ + public function getFundingSource() + { + return $this->fundingSource; + } + + /** + * @return bool + */ + public function isHostedFields() + { + return $this->isHostedFields; + } + + /** + * @return bool + */ + public function isExpressCheckout() + { + return $this->isExpressCheckout; + } +} diff --git a/src/PayPal/Order/Command/UpdatePayPalOrderCommand.php b/src/PayPal/Order/Command/UpdatePayPalOrderCommand.php new file mode 100644 index 000000000..ed125614c --- /dev/null +++ b/src/PayPal/Order/Command/UpdatePayPalOrderCommand.php @@ -0,0 +1,112 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command; + +use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; +use PrestaShop\Module\PrestashopCheckout\Cart\ValueObject\CartId; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\ValueObject\PayPalOrderId; + +class UpdatePayPalOrderCommand +{ + /** + * @var PayPalOrderId + */ + private $orderPayPalId; + + /** + * @var CartId + */ + private $cartId; + + /** + * @var string + */ + private $fundingSource; + + /** + * @var bool + */ + private $isHostedFields; + + /** + * @var bool + */ + private $isExpressCheckout; + + /** + * @param string $orderPayPalId + * @param int $cartId + * @param string $fundingSource + * @param bool $isHostedFields + * @param bool $isExpressCheckout + * + * @throws CartException|PayPalOrderException + */ + public function __construct($orderPayPalId, $cartId, $fundingSource, $isHostedFields, $isExpressCheckout) + { + $this->orderPayPalId = new PayPalOrderId($orderPayPalId); + $this->cartId = new CartId($cartId); + $this->fundingSource = $fundingSource; + $this->isHostedFields = $isHostedFields; + $this->isExpressCheckout = $isExpressCheckout; + } + + /** + * @return PayPalOrderId + */ + public function getPayPalOrderId() + { + return $this->orderPayPalId; + } + + /** + * @return CartId + */ + public function getCartId() + { + return $this->cartId; + } + + /** + * @return string + */ + public function getFundingSource() + { + return $this->fundingSource; + } + + /** + * @return bool + */ + public function isHostedFields() + { + return $this->isHostedFields; + } + + /** + * @return bool + */ + public function isExpressCheckout() + { + return $this->isExpressCheckout; + } +} diff --git a/src/PayPal/Order/CommandHandler/CapturePayPalOrderCommandHandler.php b/src/PayPal/Order/CommandHandler/CapturePayPalOrderCommandHandler.php index af28d2068..7731c10d2 100644 --- a/src/PayPal/Order/CommandHandler/CapturePayPalOrderCommandHandler.php +++ b/src/PayPal/Order/CommandHandler/CapturePayPalOrderCommandHandler.php @@ -23,9 +23,9 @@ use Configuration; use Context; -use PrestaShop\Module\PrestashopCheckout\Api\Payment\Order; use PrestaShop\Module\PrestashopCheckout\Event\EventDispatcherInterface; use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; +use PrestaShop\Module\PrestashopCheckout\Http\CheckoutHttpClient; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\CapturePayPalOrderCommand; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Event\PayPalOrderCompletedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderStatus; @@ -33,7 +33,6 @@ use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCaptureDeclinedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCapturePendingEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\PayPalCaptureStatus; -use PrestaShop\Module\PrestashopCheckout\PayPalError; use PrestaShop\Module\PrestashopCheckout\PayPalProcessorResponse; use Psr\SimpleCache\CacheInterface; @@ -43,13 +42,20 @@ class CapturePayPalOrderCommandHandler * @var EventDispatcherInterface */ private $eventDispatcher; + /** * @var CacheInterface */ private $orderPayPalCache; - public function __construct(EventDispatcherInterface $eventDispatcher, CacheInterface $orderPayPalCache) + /** + * @var CheckoutHttpClient + */ + private $httpClient; + + public function __construct(CheckoutHttpClient $httpClient, EventDispatcherInterface $eventDispatcher, CacheInterface $orderPayPalCache) { + $this->httpClient = $httpClient; $this->eventDispatcher = $eventDispatcher; $this->orderPayPalCache = $orderPayPalCache; } @@ -58,34 +64,16 @@ public function handle(CapturePayPalOrderCommand $capturePayPalOrderCommand) { $context = Context::getContext(); $merchantId = Configuration::get('PS_CHECKOUT_PAYPAL_ID_MERCHANT', null, null, $context->shop->id); - $apiOrder = new Order($context->link); - $response = $apiOrder->capture( - $capturePayPalOrderCommand->getOrderId()->getValue(), - $merchantId, - $capturePayPalOrderCommand->getFundingSource() - ); - - if (false === $response['status']) { - if (isset($response['body']['details'][0]['issue'])) { - (new PayPalError($response['body']['details'][0]['issue']))->throwException(); - } - - if (isset($response['body']['name'])) { - (new PayPalError($response['body']['name']))->throwException(); - } - - if (false === empty($response['body']['message'])) { - (new PayPalError($response['body']['message']))->throwException(); - } - - if (false === empty($response['exceptionMessage']) && false === empty($response['exceptionCode'])) { - throw new PsCheckoutException($response['exceptionMessage'], (int) $response['exceptionCode']); - } - - throw new PsCheckoutException(isset($response['body']['error']) ? $response['body']['error'] : 'Unknown error', PsCheckoutException::UNKNOWN); - } - $orderPayPal = $response['body']; + $response = $this->httpClient->captureOrder([ + 'mode' => $capturePayPalOrderCommand->getFundingSource(), + 'orderId' => $capturePayPalOrderCommand->getOrderId()->getValue(), + 'payee' => [ + 'merchant_id' => $merchantId, + ], + ]); + + $orderPayPal = json_decode($response->getBody(), true); $payPalOrderFromCache = $this->orderPayPalCache->get($orderPayPal['id']); diff --git a/src/PayPal/Order/CommandHandler/CreatePayPalOrderCommandHandler.php b/src/PayPal/Order/CommandHandler/CreatePayPalOrderCommandHandler.php new file mode 100644 index 000000000..d3a9f4233 --- /dev/null +++ b/src/PayPal/Order/CommandHandler/CreatePayPalOrderCommandHandler.php @@ -0,0 +1,95 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\CommandHandler; + +use PrestaShop\Module\PrestashopCheckout\Builder\Payload\OrderPayloadBuilder; +use PrestaShop\Module\PrestashopCheckout\Event\EventDispatcherInterface; +use PrestaShop\Module\PrestashopCheckout\Exception\PayPalException; +use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; +use PrestaShop\Module\PrestashopCheckout\Http\CheckoutHttpClient; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\CreatePayPalOrderCommand; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Event\PayPalOrderCreatedEvent; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException; +use PrestaShop\Module\PrestashopCheckout\Presenter\Cart\CartPresenter; +use PrestaShop\Module\PrestashopCheckout\ShopContext; + +class CreatePayPalOrderCommandHandler +{ + /** + * @var EventDispatcherInterface + */ + private $eventDispatcher; + + /** + * @var CheckoutHttpClient + */ + private $httpClient; + /** + * @var ShopContext + */ + private $shopContext; + + public function __construct( + CheckoutHttpClient $httpClient, + EventDispatcherInterface $eventDispatcher, + ShopContext $shopContext + ) { + $this->httpClient = $httpClient; + $this->eventDispatcher = $eventDispatcher; + $this->shopContext = $shopContext; + } + + /** + * @param CreatePayPalOrderCommand $command + * + * @return void + * + * @throws PayPalException + * @throws PayPalOrderException + * @throws PsCheckoutException + */ + public function handle(CreatePayPalOrderCommand $command) + { + $cartPresenter = (new CartPresenter())->present(); + $builder = new OrderPayloadBuilder($cartPresenter); + $builder->setIsCard($command->getFundingSource() === 'card'); + $builder->setExpressCheckout($command->isExpressCheckout()); + + if ($this->shopContext->isShop17()) { + // Build full payload in 1.7 + $builder->buildFullPayload(); + } else { + // if on 1.6 always build minimal payload + $builder->buildMinimalPayload(); + } + + $response = $this->httpClient->createOrder($builder->presentPayload()->getArray()); + $order = json_decode($response->getBody(), true); + $this->eventDispatcher->dispatch(new PayPalOrderCreatedEvent( + $order['id'], + $order, + $command->getCartId()->getValue(), + $command->isHostedFields(), + $command->isExpressCheckout(), + $command->getFundingSource() + )); + } +} diff --git a/src/PayPal/Order/CommandHandler/UpdatePayPalOrderCommandHandler.php b/src/PayPal/Order/CommandHandler/UpdatePayPalOrderCommandHandler.php new file mode 100644 index 000000000..57eb02a1c --- /dev/null +++ b/src/PayPal/Order/CommandHandler/UpdatePayPalOrderCommandHandler.php @@ -0,0 +1,104 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\CommandHandler; + +use Exception; +use PrestaShop\Module\PrestashopCheckout\Builder\Payload\OrderPayloadBuilder; +use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; +use PrestaShop\Module\PrestashopCheckout\Event\EventDispatcherInterface; +use PrestaShop\Module\PrestashopCheckout\Exception\PayPalException; +use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; +use PrestaShop\Module\PrestashopCheckout\Http\CheckoutHttpClient; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\UpdatePayPalOrderCommand; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Event\PayPalOrderUpdatedEvent; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException; +use PrestaShop\Module\PrestashopCheckout\Presenter\Cart\CartPresenter; +use PrestaShop\Module\PrestashopCheckout\ShopContext; + +class UpdatePayPalOrderCommandHandler +{ + /** + * @var EventDispatcherInterface + */ + private $eventDispatcher; + + /** + * @var CheckoutHttpClient + */ + private $httpClient; + + /** + * @var ShopContext + */ + private $shopContext; + + /** + * @param CheckoutHttpClient $httpClient + * @param EventDispatcherInterface $eventDispatcher + * @param ShopContext $shopContext + */ + public function __construct( + CheckoutHttpClient $httpClient, + EventDispatcherInterface $eventDispatcher, + ShopContext $shopContext + ) { + $this->httpClient = $httpClient; + $this->eventDispatcher = $eventDispatcher; + $this->shopContext = $shopContext; + } + + /** + * @param UpdatePayPalOrderCommand $command + * + * @return void + * + * @throws CartException|PayPalException|PayPalOrderException|PsCheckoutException|Exception + */ + public function handle(UpdatePayPalOrderCommand $command) + { + $cartPresenter = (new CartPresenter())->present(); + $builder = new OrderPayloadBuilder($cartPresenter, true); + $builder->setIsUpdate(true); + $builder->setPaypalOrderId($command->getPayPalOrderId()->getValue()); + $builder->setIsCard($command->getFundingSource() === 'card'); + $builder->setExpressCheckout($command->isExpressCheckout()); + + if ($this->shopContext->isShop17()) { + // Build full payload in 1.7 + $builder->buildFullPayload(); + } else { + // if on 1.6 always build minimal payload + $builder->buildMinimalPayload(); + } + + $response = $this->httpClient->updateOrder($builder->presentPayload()->getArray()); + $order = json_decode($response->getBody(), true); + + $this->eventDispatcher->dispatch(new PayPalOrderUpdatedEvent( + $order['id'], + $order, + $command->getCartId()->getValue(), + $command->isHostedFields(), + $command->isExpressCheckout(), + $command->getFundingSource() + )); + } +} diff --git a/src/PayPal/Order/Event/PayPalOrderCreatedEvent.php b/src/PayPal/Order/Event/PayPalOrderCreatedEvent.php index 375348587..53c1e46ee 100644 --- a/src/PayPal/Order/Event/PayPalOrderCreatedEvent.php +++ b/src/PayPal/Order/Event/PayPalOrderCreatedEvent.php @@ -20,6 +20,81 @@ namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\Event; +use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; +use PrestaShop\Module\PrestashopCheckout\Cart\ValueObject\CartId; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException; + class PayPalOrderCreatedEvent extends PayPalOrderEvent { + /** + * @var CartId + */ + private $cartId; + + /** + * @var bool + */ + private $isHostedFields; + + /** + * @var bool + */ + private $isExpressCheckout; + + /** + * @var string + */ + private $fundingSource; + + /** + * @param string $orderPayPalId + * @param array $orderPayPal + * @param int $cartId + * @param bool $isHostedFields + * @param bool $isExpressCheckout + * @param string $fundingSource + * + * @throws CartException + * @throws PayPalOrderException + */ + public function __construct($orderPayPalId, $orderPayPal, $cartId, $isHostedFields, $isExpressCheckout, $fundingSource) + { + parent::__construct($orderPayPalId, $orderPayPal); + $this->cartId = new CartId($cartId); + $this->isHostedFields = $isHostedFields; + $this->isExpressCheckout = $isExpressCheckout; + $this->fundingSource = $fundingSource; + } + + /** + * @return CartId + */ + public function getCartId() + { + return $this->cartId; + } + + /** + * @return bool + */ + public function isHostedFields() + { + return $this->isHostedFields; + } + + /** + * @return bool + */ + public function isExpressCheckout() + { + return $this->isExpressCheckout; + } + + /** + * @return string + */ + public function getFundingSource() + { + return $this->fundingSource; + } } diff --git a/src/PayPal/Order/Event/PayPalOrderUpdatedEvent.php b/src/PayPal/Order/Event/PayPalOrderUpdatedEvent.php new file mode 100644 index 000000000..cc2f43dbf --- /dev/null +++ b/src/PayPal/Order/Event/PayPalOrderUpdatedEvent.php @@ -0,0 +1,100 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\Event; + +use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; +use PrestaShop\Module\PrestashopCheckout\Cart\ValueObject\CartId; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException; + +class PayPalOrderUpdatedEvent extends PayPalOrderEvent +{ + /** + * @var CartId + */ + private $cartId; + + /** + * @var bool + */ + private $isHostedFields; + + /** + * @var bool + */ + private $isExpressCheckout; + + /** + * @var string + */ + private $fundingSource; + + /** + * @param string $orderPayPalId + * @param array $orderPayPal + * @param int $cartId + * @param bool $isHostedFields + * @param bool $isExpressCheckout + * @param string $fundingSource + * + * @throws CartException + * @throws PayPalOrderException + */ + public function __construct($orderPayPalId, $orderPayPal, $cartId, $isHostedFields, $isExpressCheckout, $fundingSource) + { + parent::__construct($orderPayPalId, $orderPayPal); + $this->cartId = new CartId($cartId); + $this->isHostedFields = $isHostedFields; + $this->isExpressCheckout = $isExpressCheckout; + $this->fundingSource = $fundingSource; + } + + /** + * @return CartId + */ + public function getCartId() + { + return $this->cartId; + } + + /** + * @return bool + */ + public function isHostedFields() + { + return $this->isHostedFields; + } + + /** + * @return bool + */ + public function isExpressCheckout() + { + return $this->isExpressCheckout; + } + + /** + * @return string + */ + public function getFundingSource() + { + return $this->fundingSource; + } +} diff --git a/src/PayPal/Order/EventSubscriber/PayPalOrderEventSubscriber.php b/src/PayPal/Order/EventSubscriber/PayPalOrderEventSubscriber.php index 5cf29b9a9..a4d5328c7 100644 --- a/src/PayPal/Order/EventSubscriber/PayPalOrderEventSubscriber.php +++ b/src/PayPal/Order/EventSubscriber/PayPalOrderEventSubscriber.php @@ -22,6 +22,8 @@ namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\EventSubscriber; use PrestaShop\Module\PrestashopCheckout\Checkout\CheckoutChecker; +use PrestaShop\Module\PrestashopCheckout\Checkout\Command\SaveCheckoutCommand; +use PrestaShop\Module\PrestashopCheckout\Checkout\Command\SavePayPalOrderStatusCommand; use PrestaShop\Module\PrestashopCheckout\CommandBus\CommandBusInterface; use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; use PrestaShop\Module\PrestashopCheckout\Order\Command\UpdateOrderStatusCommand; @@ -32,13 +34,14 @@ use PrestaShop\Module\PrestashopCheckout\Order\State\Service\OrderStateMapper; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\CheckTransitionPayPalOrderStatusService; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\CapturePayPalOrderCommand; -use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\SavePayPalOrderCommand; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Event\PayPalOrderApprovalReversedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Event\PayPalOrderApprovedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Event\PayPalOrderCompletedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Event\PayPalOrderCreatedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Event\PayPalOrderEvent; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Event\PayPalOrderUpdatedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderStatus; +use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration; use PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository; use Ps_checkout; use Psr\SimpleCache\CacheInterface; @@ -122,25 +125,27 @@ public static function getSubscribedEvents() ['setApprovalReversedOrderStatus'], ['clearCache'], ], + PayPalOrderUpdatedEvent::class => [ + ['clearCache'], + ], ]; } public function saveCreatedPayPalOrder(PayPalOrderCreatedEvent $event) { - $psCheckoutCart = $this->psCheckoutCartRepository->findOneByPayPalOrderId($event->getOrderPayPalId()->getValue()); - - if (false === $psCheckoutCart) { - throw new PsCheckoutException(sprintf('PayPal Order %s is not linked to a cart', $event->getOrderPayPalId()->getValue()), PsCheckoutException::PRESTASHOP_CART_NOT_FOUND); - } - - if (!$this->checkTransitionPayPalOrderStatusService->checkAvailableStatus($psCheckoutCart->getPaypalStatus(), PayPalOrderStatus::CREATED)) { - return; - } + /** @var PayPalConfiguration $configuration */ + $configuration = $this->module->getService('ps_checkout.paypal.configuration'); + $order = $event->getOrderPayPal(); - $this->commandBus->handle(new SavePayPalOrderCommand( + $this->commandBus->handle(new SaveCheckoutCommand( + $event->getCartId()->getValue(), $event->getOrderPayPalId()->getValue(), - PayPalOrderStatus::CREATED, - $event->getOrderPayPal() + $order['status'], + $order['intent'], + $event->getFundingSource(), + $event->isExpressCheckout(), + $event->isHostedFields(), + $configuration->getPaymentMode() )); } @@ -156,10 +161,9 @@ public function saveApprovedPayPalOrder(PayPalOrderApprovedEvent $event) return; } - $this->commandBus->handle(new SavePayPalOrderCommand( + $this->commandBus->handle(new SavePayPalOrderStatusCommand( $event->getOrderPayPalId()->getValue(), - PayPalOrderStatus::APPROVED, - $event->getOrderPayPal() + PayPalOrderStatus::APPROVED )); } @@ -175,10 +179,9 @@ public function saveCompletedPayPalOrder(PayPalOrderCompletedEvent $event) return; } - $this->commandBus->handle(new SavePayPalOrderCommand( + $this->commandBus->handle(new SavePayPalOrderStatusCommand( $event->getOrderPayPalId()->getValue(), - PayPalOrderStatus::COMPLETED, - $event->getOrderPayPal() + PayPalOrderStatus::COMPLETED )); } @@ -194,10 +197,9 @@ public function saveApprovalReversedPayPalOrder(PayPalOrderApprovalReversedEvent return; } - $this->commandBus->handle(new SavePayPalOrderCommand( + $this->commandBus->handle(new SavePayPalOrderStatusCommand( $event->getOrderPayPalId()->getValue(), - PayPalOrderStatus::REVERSED, - $event->getOrderPayPal() + PayPalOrderStatus::REVERSED )); } @@ -265,7 +267,7 @@ public function updateCache(PayPalOrderEvent $event) $this->orderPayPalCache->set($event->getOrderPayPalId()->getValue(), $newOrderPayPal); } - public function clearCache(PayPalOrderApprovalReversedEvent $event) + public function clearCache(PayPalOrderEvent $event) { $this->orderPayPalCache->delete($event->getOrderPayPalId()->getValue()); } diff --git a/src/PayPal/Order/Query/GetPayPalOrderForAdminViewQuery.php b/src/PayPal/Order/Query/GetPayPalOrderForAdminViewQuery.php new file mode 100644 index 000000000..345fd6ac2 --- /dev/null +++ b/src/PayPal/Order/Query/GetPayPalOrderForAdminViewQuery.php @@ -0,0 +1,25 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query; + +class GetPayPalOrderForAdminViewQuery +{ +} diff --git a/src/PayPal/Order/Query/GetPayPalOrderForAdminViewQueryResult.php b/src/PayPal/Order/Query/GetPayPalOrderForAdminViewQueryResult.php new file mode 100644 index 000000000..9ee9a9a3b --- /dev/null +++ b/src/PayPal/Order/Query/GetPayPalOrderForAdminViewQueryResult.php @@ -0,0 +1,25 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query; + +class GetPayPalOrderForAdminViewQueryResult +{ +} diff --git a/src/PayPal/Order/Query/GetPayPalOrderForCartIdQuery.php b/src/PayPal/Order/Query/GetPayPalOrderForCartIdQuery.php new file mode 100644 index 000000000..c9232288d --- /dev/null +++ b/src/PayPal/Order/Query/GetPayPalOrderForCartIdQuery.php @@ -0,0 +1,50 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query; + +use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; +use PrestaShop\Module\PrestashopCheckout\Cart\ValueObject\CartId; + +class GetPayPalOrderForCartIdQuery +{ + /** + * @var CartId + */ + private $cartId; + + /** + * @param int $cartId + * + * @throws CartException + */ + public function __construct($cartId) + { + $this->cartId = new CartId($cartId); + } + + /** + * @return CartId + */ + public function getCartId() + { + return $this->cartId; + } +} diff --git a/src/PayPal/Order/Query/GetPayPalOrderForCartIdQueryResult.php b/src/PayPal/Order/Query/GetPayPalOrderForCartIdQueryResult.php new file mode 100644 index 000000000..ea663dbf4 --- /dev/null +++ b/src/PayPal/Order/Query/GetPayPalOrderForCartIdQueryResult.php @@ -0,0 +1,45 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query; + +class GetPayPalOrderForCartIdQueryResult +{ + /** + * @var array + */ + private $order; + + /** + * @param array{id: string, status: string, intent: string, payment_source: array, purchase_units: array, payer: array, create_time: string, links: array} $order + */ + public function __construct(array $order) + { + $this->order = $order; + } + + /** + * @return array{id: string, status: string, intent: string, payment_source: array, purchase_units: array, payer: array, create_time: string, links: array} + */ + public function getOrder() + { + return $this->order; + } +} diff --git a/src/PayPal/Order/QueryHandler/GetPayPalOrderForAdminViewQueryHandler.php b/src/PayPal/Order/QueryHandler/GetPayPalOrderForAdminViewQueryHandler.php new file mode 100644 index 000000000..c41d2f7a4 --- /dev/null +++ b/src/PayPal/Order/QueryHandler/GetPayPalOrderForAdminViewQueryHandler.php @@ -0,0 +1,32 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\QueryHandler; + +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetPayPalOrderForAdminViewQuery; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetPayPalOrderForAdminViewQueryResult; + +class GetPayPalOrderForAdminViewQueryHandler +{ + public function handle(GetPayPalOrderForAdminViewQuery $query) + { + return new GetPayPalOrderForAdminViewQueryResult(); + } +} diff --git a/src/PayPal/Order/QueryHandler/GetPayPalOrderForCartIdQueryHandler.php b/src/PayPal/Order/QueryHandler/GetPayPalOrderForCartIdQueryHandler.php new file mode 100644 index 000000000..256e36a68 --- /dev/null +++ b/src/PayPal/Order/QueryHandler/GetPayPalOrderForCartIdQueryHandler.php @@ -0,0 +1,66 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Order\QueryHandler; + +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetPayPalOrderForCartIdQuery; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Query\GetPayPalOrderForCartIdQueryResult; +use PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository; +use Psr\SimpleCache\CacheInterface; + +class GetPayPalOrderForCartIdQueryHandler +{ + /** + * @var CacheInterface + */ + private $orderPayPalCache; + /** + * @var PsCheckoutCartRepository + */ + private $checkoutCartRepository; + + public function __construct(CacheInterface $orderPayPalCache, PsCheckoutCartRepository $checkoutCartRepository) + { + $this->orderPayPalCache = $orderPayPalCache; + $this->checkoutCartRepository = $checkoutCartRepository; + } + + /** + * @param GetPayPalOrderForCartIdQuery $getPayPalOrderQuery + * + * @return GetPayPalOrderForCartIdQueryResult + * + * @throws PayPalOrderException + */ + public function handle(GetPayPalOrderForCartIdQuery $getPayPalOrderQuery) + { + $psCheckoutCart = $this->checkoutCartRepository->findOneByCartId($getPayPalOrderQuery->getCartId()->getValue()); + + /** @var array $order */ + $order = $this->orderPayPalCache->get($psCheckoutCart->getPaypalOrderId()); + + if (empty($order)) { + throw new PayPalOrderException('PayPal order not found', PayPalOrderException::CANNOT_RETRIEVE_ORDER); + } + + return new GetPayPalOrderForCartIdQueryResult($order); + } +} diff --git a/src/PayPal/Payment/Capture/EventSubscriber/PayPalCaptureEventSubscriber.php b/src/PayPal/Payment/Capture/EventSubscriber/PayPalCaptureEventSubscriber.php index c4979cc41..eefa235de 100644 --- a/src/PayPal/Payment/Capture/EventSubscriber/PayPalCaptureEventSubscriber.php +++ b/src/PayPal/Payment/Capture/EventSubscriber/PayPalCaptureEventSubscriber.php @@ -31,8 +31,6 @@ use PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentDeniedQueryResult; use PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentPendingQuery; use PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentPendingQueryResult; -use PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentRefundedQuery; -use PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentRefundedQueryResult; use PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentReversedQuery; use PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentReversedQueryResult; use PrestaShop\Module\PrestashopCheckout\Order\Service\CheckOrderAmount; @@ -42,7 +40,6 @@ use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCaptureDeclinedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCaptureEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCapturePendingEvent; -use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCaptureRefundedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event\PayPalCaptureReversedEvent; use Ps_checkout; use Psr\SimpleCache\CacheInterface; @@ -116,10 +113,6 @@ public static function getSubscribedEvents() ['setPaymentPendingOrderStatus'], ['updateCache'], ], - PayPalCaptureRefundedEvent::class => [ - ['setPaymentRefundedOrderStatus'], - ['updateCache'], - ], PayPalCaptureReversedEvent::class => [ ['setPaymentReversedOrderStatus'], ['updateCache'], @@ -216,30 +209,6 @@ public function setPaymentDeclinedOrderStatus(PayPalCaptureDeclinedEvent $event) $this->commandBus->handle(new UpdateOrderStatusCommand($order->getOrderId()->getValue(), $this->orderStateMapper->getIdByKey(OrderStateConfigurationKeys::PS_CHECKOUT_STATE_ERROR))); } - public function setPaymentRefundedOrderStatus(PayPalCaptureRefundedEvent $event) - { - try { - /** @var GetOrderForPaymentRefundedQueryResult $order */ - $order = $this->commandBus->handle(new GetOrderForPaymentRefundedQuery($event->getPayPalOrderId()->getValue())); - } catch (OrderNotFoundException $exception) { - return; - } - - if (!$order->hasBeenPaid() || $order->hasBeenTotallyRefund()) { - return; - } - - $capture = $event->getCapture(); - // In case there no OrderSlip for this refund, we use the refund amount from payload - $totalRefunded = $order->getTotalRefund() ? $order->getTotalRefund() : $capture['amount']['value']; - - if ($this->checkOrderAmount->checkAmount($order->getTotalAmount(), $totalRefunded) === CheckOrderAmount::ORDER_NOT_FULL_PAID) { - $this->commandBus->handle(new UpdateOrderStatusCommand($order->getOrderId()->getValue(), $this->orderStateMapper->getIdByKey(OrderStateConfigurationKeys::PS_CHECKOUT_STATE_PARTIALLY_REFUNDED))); - } else { - $this->commandBus->handle(new UpdateOrderStatusCommand($order->getOrderId()->getValue(), $this->orderStateMapper->getIdByKey(OrderStateConfigurationKeys::PS_CHECKOUT_STATE_REFUNDED))); - } - } - public function setPaymentReversedOrderStatus(PayPalCaptureReversedEvent $event) { try { diff --git a/src/PayPal/Payment/Refund/Command/RefundPayPalCaptureCommand.php b/src/PayPal/Payment/Refund/Command/RefundPayPalCaptureCommand.php new file mode 100644 index 000000000..8e2ec5452 --- /dev/null +++ b/src/PayPal/Payment/Refund/Command/RefundPayPalCaptureCommand.php @@ -0,0 +1,109 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Command; + +use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Exception\PayPalRefundException; +use Validate; + +class RefundPayPalCaptureCommand +{ + /** + * @var string + */ + private $orderPayPalId; + /** + * @var string + */ + private $captureId; + /** + * @var string + */ + private $currencyCode; + /** + * @var string + */ + private $amount; + + /** + * @param string $orderPayPalId + * @param string $captureId + * @param string $currencyCode + * @param mixed $amount + * + * @throws PayPalRefundException + */ + public function __construct($orderPayPalId, $captureId, $currencyCode, $amount) + { + if (empty($orderPayPalId) || !Validate::isGenericName($orderPayPalId)) { + throw new PayPalRefundException('', PayPalRefundException::INVALID_ORDER_ID); + } + + if (empty($captureId) || !Validate::isGenericName($captureId)) { + throw new PayPalRefundException('', PayPalRefundException::INVALID_TRANSACTION_ID); + } + + // https://developer.paypal.com0/docs/api/reference/currency-codes/ + if (empty($currencyCode) || !in_array($currencyCode, ['AUD', 'BRL', 'CAD', 'CZK', 'DKK', 'EUR', 'HKD', 'HUF', 'INR', 'ILS', 'JPY', 'MYR', 'MXN', 'TWD', 'NZD', 'NOK', 'PHP', 'PLN', 'GBP', 'RUB', 'SGD', 'SEK', 'CHF', 'THB', 'USD'])) { + throw new PayPalRefundException('', PayPalRefundException::INVALID_CURRENCY); + } + + if (empty($amount) || !Validate::isPrice($amount) || $amount <= 0) { + throw new PayPalRefundException('', PayPalRefundException::INVALID_AMOUNT); + } + + $this->orderPayPalId = $orderPayPalId; + $this->captureId = $captureId; + $this->currencyCode = $currencyCode; + $this->amount = $amount; + } + + /** + * @return string + */ + public function getOrderPayPalId() + { + return $this->orderPayPalId; + } + + /** + * @return string + */ + public function getCaptureId() + { + return $this->captureId; + } + + /** + * @return string + */ + public function getCurrencyCode() + { + return $this->currencyCode; + } + + /** + * @return mixed + */ + public function getAmount() + { + return $this->amount; + } +} diff --git a/src/PayPal/Payment/Refund/CommandHandler/RefundPayPalCaptureCommandHandler.php b/src/PayPal/Payment/Refund/CommandHandler/RefundPayPalCaptureCommandHandler.php new file mode 100644 index 000000000..291984583 --- /dev/null +++ b/src/PayPal/Payment/Refund/CommandHandler/RefundPayPalCaptureCommandHandler.php @@ -0,0 +1,123 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\CommandHandler; + +use PrestaShop\Module\PrestashopCheckout\Configuration\PrestaShopConfiguration; +use PrestaShop\Module\PrestashopCheckout\Context\PrestaShopContext; +use PrestaShop\Module\PrestashopCheckout\Event\EventDispatcherInterface; +use PrestaShop\Module\PrestashopCheckout\Exception\PayPalException; +use PrestaShop\Module\PrestashopCheckout\Handler\Response\ResponseApiHandler; +use PrestaShop\Module\PrestashopCheckout\Http\CheckoutHttpClient; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException; +use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Command\RefundPayPalCaptureCommand; +use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Event\PayPalCaptureRefundedEvent; +use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Exception\PayPalRefundFailedException; +use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration; +use Psr\SimpleCache\CacheInterface; + +class RefundPayPalCaptureCommandHandler +{ + /** + * @var CheckoutHttpClient + */ + private $checkoutHttpClient; + /** + * @var PayPalConfiguration + */ + private $payPalConfiguration; + /** + * @var PrestaShopConfiguration + */ + private $prestaShopConfiguration; + /** + * @var PrestaShopContext + */ + private $prestaShopContext; + /** + * @var EventDispatcherInterface + */ + private $eventDispatcher; + /** + * @var CacheInterface + */ + private $orderPayPalCache; + + public function __construct( + CheckoutHttpClient $checkoutHttpClient, + PayPalConfiguration $payPalConfiguration, + PrestaShopConfiguration $prestaShopConfiguration, + PrestaShopContext $prestaShopContext, + EventDispatcherInterface $eventDispatcher, + CacheInterface $orderPayPalCache + ) { + $this->checkoutHttpClient = $checkoutHttpClient; + $this->payPalConfiguration = $payPalConfiguration; + $this->prestaShopConfiguration = $prestaShopConfiguration; + $this->prestaShopContext = $prestaShopContext; + $this->eventDispatcher = $eventDispatcher; + $this->orderPayPalCache = $orderPayPalCache; + } + + /** + * @param RefundPayPalCaptureCommand $command + * + * @throws PayPalException + * @throws PayPalRefundFailedException + * @throws PayPalOrderException + */ + public function handle(RefundPayPalCaptureCommand $command) + { + $response = $this->checkoutHttpClient->refundOrder([ + 'orderId' => $command->getOrderPayPalId(), + 'captureId' => $command->getCaptureId(), + 'payee' => [ + 'merchant_id' => $this->payPalConfiguration->getMerchantId(), + ], + 'amount' => [ + 'currency_code' => $command->getCurrencyCode(), + 'value' => $command->getAmount(), + ], + 'note_to_payer' => 'Refund by ' + . $this->prestaShopConfiguration->get( + 'PS_SHOP_NAME', + ['id_shop' => $this->prestaShopContext->getShopId()] + ), + ]); + $responseHandler = new ResponseApiHandler(); + $response = $responseHandler->handleResponse($response); + + if (isset($response['httpCode']) && $response['httpCode'] === 200) { + if ($this->orderPayPalCache->has($command->getOrderPayPalId())) { + $this->orderPayPalCache->delete($command->getOrderPayPalId()); + } + } else { + throw new PayPalRefundFailedException('', isset($response['httpCode']) ? $response['httpCode'] : 500); + } + + $this->eventDispatcher->dispatch( + new PayPalCaptureRefundedEvent( + $response['body']['id'], + $command->getOrderPayPalId(), + $response['body'] + ) + ); + } +} diff --git a/src/PayPal/Payment/Capture/Event/PayPalCaptureRefundedEvent.php b/src/PayPal/Payment/Refund/Event/PayPalCaptureRefundedEvent.php similarity index 85% rename from src/PayPal/Payment/Capture/Event/PayPalCaptureRefundedEvent.php rename to src/PayPal/Payment/Refund/Event/PayPalCaptureRefundedEvent.php index a281444a8..c7e010544 100644 --- a/src/PayPal/Payment/Capture/Event/PayPalCaptureRefundedEvent.php +++ b/src/PayPal/Payment/Refund/Event/PayPalCaptureRefundedEvent.php @@ -18,8 +18,8 @@ * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 */ -namespace PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\Event; +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Event; -class PayPalCaptureRefundedEvent extends PayPalCaptureEvent +class PayPalCaptureRefundedEvent extends PayPalRefundEvent { } diff --git a/src/PayPal/Payment/Refund/Event/PayPalRefundEvent.php b/src/PayPal/Payment/Refund/Event/PayPalRefundEvent.php new file mode 100644 index 000000000..5f67c1954 --- /dev/null +++ b/src/PayPal/Payment/Refund/Event/PayPalRefundEvent.php @@ -0,0 +1,82 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Event; + +use PrestaShop\Module\PrestashopCheckout\Event\Event; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException; +use PrestaShop\Module\PrestashopCheckout\PayPal\Order\ValueObject\PayPalOrderId; + +abstract class PayPalRefundEvent extends Event +{ + /** + * @var string + */ + private $refundId; + + /** + * @var PayPalOrderId + */ + private $paypalOrderId; + + /** + * @var array{id: string, status: string, amount: array, create_time: string, update_time: string, custom_id: string, note_to_payer: string, payer: array, seller_payable_breakdown: array, links: array} + */ + private $refund; + + /** + * @param string $refundId + * @param string $paypalOrderId + * @param array{id: string, status: string, amount: array, create_time: string, update_time: string, custom_id: string, note_to_payer: string, payer: array, seller_payable_breakdown: array, links: array} $refund + * + * @throws PayPalOrderException + */ + public function __construct($refundId, $paypalOrderId, array $refund) + { + $this->refundId = $refundId; + $this->paypalOrderId = new PayPalOrderId($paypalOrderId); + $this->refund = $refund; + } + + /** + * @return string + */ + public function getPayPalRefundId() + { + return $this->refundId; + } + + /** + * @return PayPalOrderId + */ + public function getPayPalOrderId() + { + return $this->paypalOrderId; + } + + /** + * @return array{id: string, status: string, amount: array, create_time: string, update_time: string, custom_id: string, note_to_payer: string, payer: array, seller_payable_breakdown: array, links: array} + */ + public function getRefund() + { + return $this->refund; + } +} diff --git a/src/PayPal/Payment/Refund/EventSubscriber/PayPalRefundEventSubscriber.php b/src/PayPal/Payment/Refund/EventSubscriber/PayPalRefundEventSubscriber.php new file mode 100644 index 000000000..2c9fdeeec --- /dev/null +++ b/src/PayPal/Payment/Refund/EventSubscriber/PayPalRefundEventSubscriber.php @@ -0,0 +1,161 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\EventSubscriber; + +use PrestaShop\Module\PrestashopCheckout\CommandBus\CommandBusInterface; +use PrestaShop\Module\PrestashopCheckout\Order\Command\UpdateOrderStatusCommand; +use PrestaShop\Module\PrestashopCheckout\Order\Exception\OrderNotFoundException; +use PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentRefundedQuery; +use PrestaShop\Module\PrestashopCheckout\Order\Query\GetOrderForPaymentRefundedQueryResult; +use PrestaShop\Module\PrestashopCheckout\Order\Service\CheckOrderAmount; +use PrestaShop\Module\PrestashopCheckout\Order\State\OrderStateConfigurationKeys; +use PrestaShop\Module\PrestashopCheckout\Order\State\Service\OrderStateMapper; +use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Event\PayPalCaptureRefundedEvent; +use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Event\PayPalRefundEvent; +use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalOrderProvider; +use Ps_checkout; +use Psr\SimpleCache\CacheInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +class PayPalRefundEventSubscriber implements EventSubscriberInterface +{ + /** + * @var Ps_checkout + */ + private $module; + + /** + * @var CheckOrderAmount + */ + private $checkOrderAmount; + + /** + * @var CommandBusInterface + */ + private $commandBus; + + /** + * @var CacheInterface + */ + private $capturePayPalCache; + + /** + * @var CacheInterface + */ + private $orderPayPalCache; + + /** + * @var OrderStateMapper + */ + private $orderStateMapper; + /** + * @var PayPalOrderProvider + */ + private $orderProvider; + + public function __construct( + Ps_checkout $module, + CheckOrderAmount $checkOrderAmount, + CacheInterface $capturePayPalCache, + CacheInterface $orderPayPalCache, + OrderStateMapper $orderStateMapper, + PayPalOrderProvider $orderProvider + ) { + $this->module = $module; + $this->checkOrderAmount = $checkOrderAmount; + $this->commandBus = $this->module->getService('ps_checkout.bus.command'); + $this->capturePayPalCache = $capturePayPalCache; + $this->orderPayPalCache = $orderPayPalCache; + $this->orderStateMapper = $orderStateMapper; + $this->orderProvider = $orderProvider; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return [ + PayPalCaptureRefundedEvent::class => [ + ['setPaymentRefundedOrderStatus'], + ['updateCache'], + ], + ]; + } + + public function setPaymentRefundedOrderStatus(PayPalCaptureRefundedEvent $event) + { + try { + /** @var GetOrderForPaymentRefundedQueryResult $order */ + $order = $this->commandBus->handle(new GetOrderForPaymentRefundedQuery($event->getPayPalOrderId()->getValue())); + } catch (OrderNotFoundException $exception) { + return; + } + + if (!$order->hasBeenPaid() || $order->hasBeenTotallyRefund()) { + return; + } + + $orderPayPal = $this->orderProvider->getById($event->getPayPalOrderId()->getValue()); + + if (empty($orderPayPal['purchase_units'][0]['payments']['refunds'])) { + return; + } + + $totalRefunded = array_reduce($orderPayPal['purchase_units'][0]['payments']['refunds'], function ($totalRefunded, $refund) { + return $totalRefunded + (float) $refund['amount']['value']; + }); + + $orderFullyRefunded = (float) $order->getTotalAmount() <= (float) $totalRefunded; + + $this->commandBus->handle( + new UpdateOrderStatusCommand( + $order->getOrderId()->getValue(), + $this->orderStateMapper->getIdByKey($orderFullyRefunded ? OrderStateConfigurationKeys::PS_CHECKOUT_STATE_REFUNDED : OrderStateConfigurationKeys::PS_CHECKOUT_STATE_PARTIALLY_REFUNDED) + ) + ); + } + + public function updateCache(PayPalRefundEvent $event) + { + if ($this->orderPayPalCache->has($event->getPayPalOrderId()->getValue())) { + $this->orderPayPalCache->delete($event->getPayPalOrderId()->getValue()); + } +// $this->capturePayPalCache->set($event->getPayPalCaptureId()->getValue(), $event->getCapture()); +// +// $needToClearOrderPayPalCache = true; +// $orderPayPalCache = $this->orderPayPalCache->get($event->getPayPalOrderId()->getValue()); +// +// if ($orderPayPalCache && isset($orderPayPalCache['purchase_units'][0]['payments']['captures'])) { +// foreach ($orderPayPalCache['purchase_units'][0]['payments']['captures'] as $key => $capture) { +// if ($capture['id'] === $event->getPayPalCaptureId()->getValue()) { +// $needToClearOrderPayPalCache = false; +// $orderPayPalCache['purchase_units'][0]['payments']['captures'][$key] = $event->getCapture(); +// $this->orderPayPalCache->set($event->getPayPalOrderId()->getValue(), $orderPayPalCache); +// } +// } +// } +// +// if ($needToClearOrderPayPalCache) { +// $this->orderPayPalCache->delete($event->getPayPalOrderId()->getValue()); +// } + } +} diff --git a/src/PayPal/Payment/Refund/Exception/PayPalRefundException.php b/src/PayPal/Payment/Refund/Exception/PayPalRefundException.php new file mode 100644 index 000000000..ee2efdede --- /dev/null +++ b/src/PayPal/Payment/Refund/Exception/PayPalRefundException.php @@ -0,0 +1,32 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Exception; + +use Exception; + +class PayPalRefundException extends Exception +{ + const INVALID_ORDER_ID = 1; + const INVALID_TRANSACTION_ID = 2; + const INVALID_CURRENCY = 3; + const INVALID_AMOUNT = 4; + const INVALID_REFUND_ID = 4; +} diff --git a/src/PayPal/Payment/Refund/Exception/PayPalRefundFailedException.php b/src/PayPal/Payment/Refund/Exception/PayPalRefundFailedException.php new file mode 100644 index 000000000..c037a864f --- /dev/null +++ b/src/PayPal/Payment/Refund/Exception/PayPalRefundFailedException.php @@ -0,0 +1,27 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Exception; + +use Exception; + +class PayPalRefundFailedException extends Exception +{ +} diff --git a/src/PayPalError.php b/src/PayPalError.php index 7d30d09c1..643346fa2 100644 --- a/src/PayPalError.php +++ b/src/PayPalError.php @@ -20,6 +20,7 @@ namespace PrestaShop\Module\PrestashopCheckout; +use Http\Client\Exception\HttpException; use PrestaShop\Module\PrestashopCheckout\Exception\PayPalException; class PayPalError @@ -38,275 +39,315 @@ public function __construct($message) } /** + * @param HttpException|null $previous + * * @throws PayPalException */ - public function throwException() + public function throwException(HttpException $previous = null) { switch ($this->message) { case 'ACTION_DOES_NOT_MATCH_INTENT': - throw new PayPalException('Order was created with an intent to CAPTURE, to complete the transaction, call capture payment for order or create an order with an intent of AUTHORIZE.', PayPalException::ACTION_DOES_NOT_MATCH_INTENT); + throw new PayPalException('Order was created with an intent to CAPTURE, to complete the transaction, call capture payment for order or create an order with an intent of AUTHORIZE.', PayPalException::ACTION_DOES_NOT_MATCH_INTENT, $previous); case 'AGREEMENT_ALREADY_CANCELLED': - throw new PayPalException('The requested agreement is already cancelled, the specified agreement ID cannot be used for this transaction.', PayPalException::AGREEMENT_ALREADY_CANCELLED); + throw new PayPalException('The requested agreement is already cancelled, the specified agreement ID cannot be used for this transaction.', PayPalException::AGREEMENT_ALREADY_CANCELLED, $previous); case 'AMOUNT_CANNOT_BE_SPECIFIED': - throw new PayPalException('An authorization amount can only be specified if an order was saved. Save the order and try again.', PayPalException::AMOUNT_CANNOT_BE_SPECIFIED); + throw new PayPalException('An authorization amount can only be specified if an order was saved. Save the order and try again.', PayPalException::AMOUNT_CANNOT_BE_SPECIFIED, $previous); case 'AMOUNT_MISMATCH': - throw new PayPalException('The amount specified does not match the breakdown : amount must equal item_total + tax_total + shipping + handling + insurance - shipping_discount - discount.', PayPalException::AMOUNT_MISMATCH); + throw new PayPalException('The amount specified does not match the breakdown : amount must equal item_total + tax_total + shipping + handling + insurance - shipping_discount - discount.', PayPalException::AMOUNT_MISMATCH, $previous); case 'AMOUNT_NOT_PATCHABLE': - throw new PayPalException('The amount cannot be updated as the payer has chosen and approved a specific financing offer for a given amount. Create an order with the updated order amount and have the payer approve the new payment terms.', PayPalException::AMOUNT_NOT_PATCHABLE); + throw new PayPalException('The amount cannot be updated as the payer has chosen and approved a specific financing offer for a given amount. Create an order with the updated order amount and have the payer approve the new payment terms.', PayPalException::AMOUNT_NOT_PATCHABLE, $previous); case 'AUTH_CAPTURE_NOT_ENABLED': - throw new PayPalException('The authorization and capture feature is not enabled for the merchant. Make sure that the recipient of the funds is a verified business account.', PayPalException::AUTH_CAPTURE_NOT_ENABLED); + throw new PayPalException('The authorization and capture feature is not enabled for the merchant. Make sure that the recipient of the funds is a verified business account.', PayPalException::AUTH_CAPTURE_NOT_ENABLED, $previous); case 'AUTHENTICATION_FAILURE': - throw new PayPalException('The account validations failed for the user.', PayPalException::AUTHENTICATION_FAILURE); + throw new PayPalException('The account validations failed for the user.', PayPalException::AUTHENTICATION_FAILURE, $previous); case 'AUTHORIZATION_AMOUNT_EXCEEDED': - throw new PayPalException('The currency of the authorization must match the currency of the order that the payer created and approved. Check the currency_code and try the request again.', PayPalException::AUTHORIZATION_AMOUNT_EXCEEDED); + throw new PayPalException('The currency of the authorization must match the currency of the order that the payer created and approved. Check the currency_code and try the request again.', PayPalException::AUTHORIZATION_AMOUNT_EXCEEDED, $previous); case 'BILLING_AGREEMENT_NOT_FOUND': - throw new PayPalException('The requested Billing Agreement token was not found. Verify the token and try the request again.', PayPalException::BILLING_AGREEMENT_NOT_FOUND); + throw new PayPalException('The requested Billing Agreement token was not found. Verify the token and try the request again.', PayPalException::BILLING_AGREEMENT_NOT_FOUND, $previous); case 'CANNOT_BE_NEGATIVE': - throw new PayPalException('Must be greater than or equal to zero. Try the request again with a different value.', PayPalException::CANNOT_BE_NEGATIVE); + throw new PayPalException('Must be greater than or equal to zero. Try the request again with a different value.', PayPalException::CANNOT_BE_NEGATIVE, $previous); case 'CANNOT_BE_ZERO_OR_NEGATIVE': - throw new PayPalException('Must be greater than zero. Try the request again with a different value.', PayPalException::CANNOT_BE_ZERO_OR_NEGATIVE); + throw new PayPalException('Must be greater than zero. Try the request again with a different value.', PayPalException::CANNOT_BE_ZERO_OR_NEGATIVE, $previous); case 'CARD_TYPE_NOT_SUPPORTED': - throw new PayPalException('Processing of this card type is not supported. Use another card type.', PayPalException::CARD_TYPE_NOT_SUPPORTED); + throw new PayPalException('Processing of this card type is not supported. Use another card type.', PayPalException::CARD_TYPE_NOT_SUPPORTED, $previous); case 'INVALID_SECURITY_CODE_LENGTH': - throw new PayPalException('The security_code length is invalid for the specified card type.', PayPalException::INVALID_SECURITY_CODE_LENGTH); + throw new PayPalException('The security_code length is invalid for the specified card type.', PayPalException::INVALID_SECURITY_CODE_LENGTH, $previous); case 'CITY_REQUIRED': - throw new PayPalException('The specified country requires a city (address.admin_area_2). Specify a city and try the request again.', PayPalException::CITY_REQUIRED); + throw new PayPalException('The specified country requires a city (address.admin_area_2). Specify a city and try the request again.', PayPalException::CITY_REQUIRED, $previous); case 'COMPLIANCE_VIOLATION': - throw new PayPalException('Transaction cannot be processed due to a possible compliance violation. To get more information about the transaction, call Customer Support.', PayPalException::COMPLIANCE_VIOLATION); + throw new PayPalException('Transaction cannot be processed due to a possible compliance violation. To get more information about the transaction, call Customer Support.', PayPalException::COMPLIANCE_VIOLATION, $previous); case 'CONSENT_NEEDED': - throw new PayPalException('Authorization failed due to insufficient permissions. To continue with this transaction, the payer must provide consent.', PayPalException::CONSENT_NEEDED); + throw new PayPalException('Authorization failed due to insufficient permissions. To continue with this transaction, the payer must provide consent.', PayPalException::CONSENT_NEEDED, $previous); case 'CURRENCY_NOT_SUPPORTED_FOR_COUNTRY': - throw new PayPalException('Currency code not supported for direct card payments in this country.', PayPalException::CURRENCY_NOT_SUPPORTED_FOR_COUNTRY); + throw new PayPalException('Currency code not supported for direct card payments in this country.', PayPalException::CURRENCY_NOT_SUPPORTED_FOR_COUNTRY, $previous); case 'CURRENCY_NOT_SUPPORTED_FOR_CARD_TYPE': - throw new PayPalException('The currency code is not supported for direct card payments for this card type.', PayPalException::CURRENCY_NOT_SUPPORTED_FOR_CARD_TYPE); + throw new PayPalException('The currency code is not supported for direct card payments for this card type.', PayPalException::CURRENCY_NOT_SUPPORTED_FOR_CARD_TYPE, $previous); case 'DECIMAL_PRECISION': - throw new PayPalException('The value of the field should not be more than two decimal places. Verify the number of decimal places and try the request again.', PayPalException::DECIMAL_PRECISION); + throw new PayPalException('The value of the field should not be more than two decimal places. Verify the number of decimal places and try the request again.', PayPalException::DECIMAL_PRECISION, $previous); case 'DOMESTIC_TRANSACTION_REQUIRED': - throw new PayPalException('This transaction requires the payee and payer to be resident in the same country. To create this payment, a domestic transaction is required.', PayPalException::DOMESTIC_TRANSACTION_REQUIRED); + throw new PayPalException('This transaction requires the payee and payer to be resident in the same country. To create this payment, a domestic transaction is required.', PayPalException::DOMESTIC_TRANSACTION_REQUIRED, $previous); case 'DUPLICATE_INVOICE_ID': - throw new PayPalException('Duplicate Invoice ID detected. To avoid a duplicate transaction, verify that the invoice ID is unique for each transaction.', PayPalException::DUPLICATE_INVOICE_ID); + throw new PayPalException('Duplicate Invoice ID detected. To avoid a duplicate transaction, verify that the invoice ID is unique for each transaction.', PayPalException::DUPLICATE_INVOICE_ID, $previous); case 'DUPLICATE_REQUEST_ID': - throw new PayPalException('The value of PayPal-Request-Id header has already been used. Specify a different value and try the request again.', PayPalException::DUPLICATE_REQUEST_ID); + throw new PayPalException('The value of PayPal-Request-Id header has already been used. Specify a different value and try the request again.', PayPalException::DUPLICATE_REQUEST_ID, $previous); case 'FIELD_NOT_PATCHABLE': - throw new PayPalException('Field cannot be patched. You cannot update this field.', PayPalException::FIELD_NOT_PATCHABLE); + throw new PayPalException('Field cannot be patched. You cannot update this field.', PayPalException::FIELD_NOT_PATCHABLE, $previous); case 'INSTRUMENT_DECLINED': - throw new PayPalException('The funding instrument presented was either declined by the processor or bank. The specified funding instrument cannot be used for this payment.', PayPalException::INSTRUMENT_DECLINED); + throw new PayPalException('The funding instrument presented was either declined by the processor or bank. The specified funding instrument cannot be used for this payment.', PayPalException::INSTRUMENT_DECLINED, $previous); case 'INTERNAL_SERVER_ERROR': - throw new PayPalException('An internal server error has occurred. Retry the request later.', PayPalException::INTERNAL_SERVER_ERROR); + throw new PayPalException('An internal server error has occurred. Retry the request later.', PayPalException::INTERNAL_SERVER_ERROR, $previous); case 'INTERNAL_SERVICE_ERROR': - throw new PayPalException('An internal service error has occurred.', PayPalException::INTERNAL_SERVICE_ERROR); + throw new PayPalException('An internal service error has occurred.', PayPalException::INTERNAL_SERVICE_ERROR, $previous); case 'INVALID_ACCOUNT_STATUS': - throw new PayPalException('Account validations failed for the user. To continue with this transaction, the payer must provide consent.', PayPalException::INVALID_ACCOUNT_STATUS); + throw new PayPalException('Account validations failed for the user. To continue with this transaction, the payer must provide consent.', PayPalException::INVALID_ACCOUNT_STATUS, $previous); case 'INVALID_ARRAY_MAX_ITEMS': - throw new PayPalException('The number of items in an array parameter is too large.', PayPalException::INVALID_ARRAY_MAX_ITEMS); + throw new PayPalException('The number of items in an array parameter is too large.', PayPalException::INVALID_ARRAY_MAX_ITEMS, $previous); case 'INVALID_ARRAY_MIN_ITEMS': - throw new PayPalException('The number of items in an array parameter is too small.', PayPalException::INVALID_ARRAY_MIN_ITEMS); + throw new PayPalException('The number of items in an array parameter is too small.', PayPalException::INVALID_ARRAY_MIN_ITEMS, $previous); case 'INVALID_COUNTRY_CODE': - throw new PayPalException('Country code is invalid.', PayPalException::INVALID_COUNTRY_CODE); + throw new PayPalException('Country code is invalid.', PayPalException::INVALID_COUNTRY_CODE, $previous); case 'INVALID_CURRENCY_CODE': - throw new PayPalException('Currency code is invalid or is not currently supported.', PayPalException::INVALID_CURRENCY_CODE); + throw new PayPalException('Currency code is invalid or is not currently supported.', PayPalException::INVALID_CURRENCY_CODE, $previous); case 'INVALID_JSON_POINTER_FORMAT': - throw new PayPalException('Path should be a valid JavaScript Object Notation (JSON) Pointer that references a location within the request where the operation is performed. The path is not valid.', PayPalException::INVALID_JSON_POINTER_FORMAT); + throw new PayPalException('Path should be a valid JavaScript Object Notation (JSON) Pointer that references a location within the request where the operation is performed. The path is not valid.', PayPalException::INVALID_JSON_POINTER_FORMAT, $previous); case 'INVALID_PARAMETER_SYNTAX': - throw new PayPalException('The value of a field does not conform to the expected format. Verify that the pattern is supported and try the request again.', PayPalException::INVALID_PARAMETER_SYNTAX); + throw new PayPalException('The value of a field does not conform to the expected format. Verify that the pattern is supported and try the request again.', PayPalException::INVALID_PARAMETER_SYNTAX, $previous); case 'INVALID_PARAMETER_VALUE': - throw new PayPalException('The value of a field is invalid. Verify the parameter value and try the request again.', PayPalException::INVALID_PARAMETER_VALUE); + throw new PayPalException('The value of a field is invalid. Verify the parameter value and try the request again.', PayPalException::INVALID_PARAMETER_VALUE, $previous); case 'INVALID_PARAMETER': - throw new PayPalException('Cannot be specified as part of the request. Check that the API supports this parameter and try the request again.', PayPalException::INVALID_PARAMETER); + throw new PayPalException('Cannot be specified as part of the request. Check that the API supports this parameter and try the request again.', PayPalException::INVALID_PARAMETER, $previous); case 'INVALID_PATCH_OPERATION': - throw new PayPalException('Request is not well-formed, syntactically incorrect, or violates schema. The operation cannot be honored. You cannot add a property that is already present. Instead, use replace. You cannot remove a property that is not present. Instead, use add. You cannot replace a property that is not present. Instead, use add.', PayPalException::INVALID_PATCH_OPERATION); + throw new PayPalException('Request is not well-formed, syntactically incorrect, or violates schema. The operation cannot be honored. You cannot add a property that is already present. Instead, use replace. You cannot remove a property that is not present. Instead, use add. You cannot replace a property that is not present. Instead, use add.', PayPalException::INVALID_PATCH_OPERATION, $previous); case 'INVALID_PAYER_ID': - throw new PayPalException('The payer ID is not valid. Verify the payer ID and try the request again.', PayPalException::INVALID_PAYER_ID); + throw new PayPalException('The payer ID is not valid. Verify the payer ID and try the request again.', PayPalException::INVALID_PAYER_ID, $previous); case 'INVALID_RESOURCE_ID': - throw new PayPalException('Specified resource ID does not exist. Verify the resource ID and try the request again.', PayPalException::INVALID_RESOURCE_ID); + throw new PayPalException('Specified resource ID does not exist. Verify the resource ID and try the request again.', PayPalException::INVALID_RESOURCE_ID, $previous); case 'INVALID_STRING_LENGTH': - throw new PayPalException('The value of a field is either too short or too long. Verify the minimum and maximum values and try the request again.', PayPalException::INVALID_STRING_LENGTH); + throw new PayPalException('The value of a field is either too short or too long. Verify the minimum and maximum values and try the request again.', PayPalException::INVALID_STRING_LENGTH, $previous); case 'ITEM_TOTAL_MISMATCH': - throw new PayPalException('Verify the corresponding values and try the request again. The item total should equal the sum of (unit_amount * quantity) across all items for a purchase_unit.', PayPalException::ITEM_TOTAL_MISMATCH); + throw new PayPalException('Verify the corresponding values and try the request again. The item total should equal the sum of (unit_amount * quantity) across all items for a purchase_unit.', PayPalException::ITEM_TOTAL_MISMATCH, $previous); case 'ITEM_TOTAL_REQUIRED': - throw new PayPalException('If item details are specified (items.unit_amount and items.quantity) corresponding amount.breakdown.item_total is required. The amount.breakdown.item_total value was not found.', PayPalException::ITEM_TOTAL_REQUIRED); + throw new PayPalException('If item details are specified (items.unit_amount and items.quantity) corresponding amount.breakdown.item_total is required. The amount.breakdown.item_total value was not found.', PayPalException::ITEM_TOTAL_REQUIRED, $previous); case 'MAX_AUTHORIZATION_COUNT_EXCEEDED': - throw new PayPalException('The maximum number of authorizations that are allowed for the order was reached. To increase your limit, contact Customer Support.', PayPalException::MAX_AUTHORIZATION_COUNT_EXCEEDED); + throw new PayPalException('The maximum number of authorizations that are allowed for the order was reached. To increase your limit, contact Customer Support.', PayPalException::MAX_AUTHORIZATION_COUNT_EXCEEDED, $previous); case 'MAX_NUMBER_OF_PAYMENT_ATTEMPTS_EXCEEDED': - throw new PayPalException('You have exceeded the maximum number of payment attempts. To review the maximum number of payment attempts allowed and retry this transaction, call Customer Support.', PayPalException::MAX_NUMBER_OF_PAYMENT_ATTEMPTS_EXCEEDED); + throw new PayPalException('You have exceeded the maximum number of payment attempts. To review the maximum number of payment attempts allowed and retry this transaction, call Customer Support.', PayPalException::MAX_NUMBER_OF_PAYMENT_ATTEMPTS_EXCEEDED, $previous); case 'MAX_VALUE_EXCEEDED': - throw new PayPalException('Should be less than or equal to 9999999.99 ; try the request again with a different value.', PayPalException::MAX_VALUE_EXCEEDED); + throw new PayPalException('Should be less than or equal to 9999999.99 ; try the request again with a different value.', PayPalException::MAX_VALUE_EXCEEDED, $previous); case 'MISSING_REQUIRED_PARAMETER': - throw new PayPalException('A required field or parameter is missing. Verify that you have specified all required parameters and try the request again.', PayPalException::MISSING_REQUIRED_PARAMETER); + throw new PayPalException('A required field or parameter is missing. Verify that you have specified all required parameters and try the request again.', PayPalException::MISSING_REQUIRED_PARAMETER, $previous); case 'MISSING_SHIPPING_ADDRESS': - throw new PayPalException('The shipping address is required when shipping_preference=SET_PROVIDED_ADDRESS. Verify that you have provided the shipping address and try the request again.', PayPalException::MISSING_SHIPPING_ADDRESS); + throw new PayPalException('The shipping address is required when shipping_preference=SET_PROVIDED_ADDRESS. Verify that you have provided the shipping address and try the request again.', PayPalException::MISSING_SHIPPING_ADDRESS, $previous); case 'MULTI_CURRENCY_ORDER': - throw new PayPalException('Multiple differing values of currency_code are not supported. The entire order request must have the same currency code.', PayPalException::MULTI_CURRENCY_ORDER); + throw new PayPalException('Multiple differing values of currency_code are not supported. The entire order request must have the same currency code.', PayPalException::MULTI_CURRENCY_ORDER, $previous); case 'MULTIPLE_SHIPPING_ADDRESS_NOT_SUPPORTED': - throw new PayPalException('Multiple shipping addresses are not supported. Try the request again with the same shipping_address.', PayPalException::MULTIPLE_SHIPPING_ADDRESS_NOT_SUPPORTED); + throw new PayPalException('Multiple shipping addresses are not supported. Try the request again with the same shipping_address.', PayPalException::MULTIPLE_SHIPPING_ADDRESS_NOT_SUPPORTED, $previous); case 'MULTIPLE_SHIPPING_OPTION_SELECTED': - throw new PayPalException('Only one shipping.option can be set to selected = true.', PayPalException::MULTIPLE_SHIPPING_OPTION_SELECTED); + throw new PayPalException('Only one shipping.option can be set to selected = true.', PayPalException::MULTIPLE_SHIPPING_OPTION_SELECTED, $previous); case 'INVALID_PICKUP_ADDRESS': - throw new PayPalException('Invalid shipping address. If the \'shipping_option.type\' is set as \'PICKUP\' then the \'shipping_detail.name.full_name\' should start with \'S2S\' meaning Ship To Store. Example: \'S2S My Store\'.', PayPalException::INVALID_PICKUP_ADDRESS); + throw new PayPalException('Invalid shipping address. If the \'shipping_option.type\' is set as \'PICKUP\' then the \'shipping_detail.name.full_name\' should start with \'S2S\' meaning Ship To Store. Example: \'S2S My Store\'.', PayPalException::INVALID_PICKUP_ADDRESS, $previous); case 'NOT_AUTHORIZED': - throw new PayPalException('Authorization failed due to insufficient permissions. To check that your application has sufficient permissions, log in to the PayPal Developer Portal.', PayPalException::NOT_AUTHORIZED); + throw new PayPalException('Authorization failed due to insufficient permissions. To check that your application has sufficient permissions, log in to the PayPal Developer Portal.', PayPalException::NOT_AUTHORIZED, $previous); case 'NOT_ENABLED_FOR_CARD_PROCESSING': - throw new PayPalException('The request fails. The API Caller account is not setup to be able to process card payments. Please contact PayPal customer support.', PayPalException::NOT_ENABLED_FOR_CARD_PROCESSING); + throw new PayPalException('The request fails. The API Caller account is not setup to be able to process card payments. Please contact PayPal customer support.', PayPalException::NOT_ENABLED_FOR_CARD_PROCESSING, $previous); case 'NOT_PATCHABLE': - throw new PayPalException('Cannot be patched. You cannot update this field.', PayPalException::NOT_PATCHABLE); + throw new PayPalException('Cannot be patched. You cannot update this field.', PayPalException::NOT_PATCHABLE, $previous); case 'NOT_SUPPORTED': - throw new PayPalException('This field is not currently supported. Specify only supported parameters and try the request again.', PayPalException::NOT_SUPPORTED); + throw new PayPalException('This field is not currently supported. Specify only supported parameters and try the request again.', PayPalException::NOT_SUPPORTED, $previous); case 'ORDER_ALREADY_AUTHORIZED': - throw new PayPalException('Order already authorized. If intent=AUTHORIZE only one authorization per order is allowed. The order was already authorized and you can create only one authorization for an order.', PayPalException::ORDER_ALREADY_AUTHORIZED); + throw new PayPalException('Order already authorized. If intent=AUTHORIZE only one authorization per order is allowed. The order was already authorized and you can create only one authorization for an order.', PayPalException::ORDER_ALREADY_AUTHORIZED, $previous); case 'ORDER_ALREADY_CAPTURED': - throw new PayPalException('Order already captured. If intent=CAPTURE only one capture per order is allowed. The order was already captured and you can capture only one payment for an order.', PayPalException::ORDER_ALREADY_CAPTURED); + throw new PayPalException('Order already captured. If intent=CAPTURE only one capture per order is allowed. The order was already captured and you can capture only one payment for an order.', PayPalException::ORDER_ALREADY_CAPTURED, $previous); case 'ORDER_ALREADY_COMPLETED': - throw new PayPalException('The order cannot be patched after it is completed.', PayPalException::ORDER_ALREADY_COMPLETED); + throw new PayPalException('The order cannot be patched after it is completed.', PayPalException::ORDER_ALREADY_COMPLETED, $previous); case 'ORDER_CANNOT_BE_SAVED': - throw new PayPalException('The option to save an order is only available if the intent is AUTHORIZE and the processing_instruction is ORDER_SAVED_EXPLICITLY. Change the intent to AUTHORIZE and the processing_instruction to ORDER_SAVED_EXPLICITLY and try the request again.', PayPalException::ORDER_CANNOT_BE_SAVED); + throw new PayPalException('The option to save an order is only available if the intent is AUTHORIZE and the processing_instruction is ORDER_SAVED_EXPLICITLY. Change the intent to AUTHORIZE and the processing_instruction to ORDER_SAVED_EXPLICITLY and try the request again.', PayPalException::ORDER_CANNOT_BE_SAVED, $previous); case 'ORDER_COMPLETED_OR_VOIDED': - throw new PayPalException('Order is voided or completed and hence cannot be authorized.', PayPalException::ORDER_COMPLETED_OR_VOIDED); + throw new PayPalException('Order is voided or completed and hence cannot be authorized.', PayPalException::ORDER_COMPLETED_OR_VOIDED, $previous); case 'ORDER_EXPIRED': - throw new PayPalException('Order is expired and hence cannot be authorized. Please contact Customer Support if you need to increase your order validity period.', PayPalException::ORDER_EXPIRED); + throw new PayPalException('Order is expired and hence cannot be authorized. Please contact Customer Support if you need to increase your order validity period.', PayPalException::ORDER_EXPIRED, $previous); case 'ORDER_NOT_APPROVED': - throw new PayPalException('Payer has not yet approved the Order for payment. The payer has not yet approved payment for the order. Redirect the payer to the rel:approve URL that was returned in the HATEOAS links in the create order response or provide a valid payment_source in the request.', PayPalException::ORDER_NOT_APPROVED); + throw new PayPalException('Payer has not yet approved the Order for payment. The payer has not yet approved payment for the order. Redirect the payer to the rel:approve URL that was returned in the HATEOAS links in the create order response or provide a valid payment_source in the request.', PayPalException::ORDER_NOT_APPROVED, $previous); case 'ORDER_NOT_SAVED': - throw new PayPalException('Please save the order or alternately, If you do not intend to save the order, PATCH the order to update the value of processing_instruction to NO_INSTRUCTION.', PayPalException::ORDER_NOT_SAVED); + throw new PayPalException('Please save the order or alternately, If you do not intend to save the order, PATCH the order to update the value of processing_instruction to NO_INSTRUCTION.', PayPalException::ORDER_NOT_SAVED, $previous); case 'ORDER_PREVIOUSLY_VOIDED': - throw new PayPalException('This order has been previously voided and cannot be voided again. Verify the order id and try again.', PayPalException::ORDER_PREVIOUSLY_VOIDED); + throw new PayPalException('This order has been previously voided and cannot be voided again. Verify the order id and try again.', PayPalException::ORDER_PREVIOUSLY_VOIDED, $previous); case 'PARAMETER_VALUE_NOT_SUPPORTED': - throw new PayPalException('The value specified for this field is not currently supported. The specified parameter value is not supported.', PayPalException::PARAMETER_VALUE_NOT_SUPPORTED); + throw new PayPalException('The value specified for this field is not currently supported. The specified parameter value is not supported.', PayPalException::PARAMETER_VALUE_NOT_SUPPORTED, $previous); case 'PATCH_PATH_REQUIRED': - throw new PayPalException('Specify a path for the field for which the operation needs to be performed. To complete the operation for this field, specify a path for the field.', PayPalException::PATCH_PATH_REQUIRED); + throw new PayPalException('Specify a path for the field for which the operation needs to be performed. To complete the operation for this field, specify a path for the field.', PayPalException::PATCH_PATH_REQUIRED, $previous); case 'PATCH_VALUE_REQUIRED': - throw new PayPalException('Please specify a value to for the field that is being patched.', PayPalException::PATCH_VALUE_REQUIRED); + throw new PayPalException('Please specify a value to for the field that is being patched.', PayPalException::PATCH_VALUE_REQUIRED, $previous); case 'PAYEE_ACCOUNT_INVALID': - throw new PayPalException('Payee account specified is invalid. Please check the payee.email_address or payee.merchant_id specified and try again. Ensure that either payee.merchant_id or payee.email_address is specified. Specify either payee.merchant_id or payee.email_address.', PayPalException::PAYEE_ACCOUNT_INVALID); + throw new PayPalException('Payee account specified is invalid. Please check the payee.email_address or payee.merchant_id specified and try again. Ensure that either payee.merchant_id or payee.email_address is specified. Specify either payee.merchant_id or payee.email_address.', PayPalException::PAYEE_ACCOUNT_INVALID, $previous); case 'PAYEE_ACCOUNT_LOCKED_OR_CLOSED': - throw new PayPalException('Payee account is locked or closed. To get more information about the status of the account, call Customer Support.', PayPalException::PAYEE_ACCOUNT_LOCKED_OR_CLOSED); + throw new PayPalException('Payee account is locked or closed. To get more information about the status of the account, call Customer Support.', PayPalException::PAYEE_ACCOUNT_LOCKED_OR_CLOSED, $previous); case 'PAYEE_ACCOUNT_RESTRICTED': - throw new PayPalException('The merchant account is restricted. To get more information about the status of the account, call Customer Support.', PayPalException::PAYEE_ACCOUNT_RESTRICTED); + throw new PayPalException('The merchant account is restricted. To get more information about the status of the account, call Customer Support.', PayPalException::PAYEE_ACCOUNT_RESTRICTED, $previous); case 'PAYEE_BLOCKED_TRANSACTION': - throw new PayPalException('The fraud settings for this seller are such that this payment cannot be executed. Verify the fraud settings. Then, retry the transaction.', PayPalException::PAYEE_BLOCKED_TRANSACTION); + throw new PayPalException('The fraud settings for this seller are such that this payment cannot be executed. Verify the fraud settings. Then, retry the transaction.', PayPalException::PAYEE_BLOCKED_TRANSACTION, $previous); case 'PAYER_ACCOUNT_LOCKED_OR_CLOSED': - throw new PayPalException('Payer account is locked or closed. To get more information about the status of the account, call Customer Support.', PayPalException::PAYER_ACCOUNT_LOCKED_OR_CLOSED); + throw new PayPalException('Payer account is locked or closed. To get more information about the status of the account, call Customer Support.', PayPalException::PAYER_ACCOUNT_LOCKED_OR_CLOSED, $previous); case 'PAYER_ACCOUNT_RESTRICTED': - throw new PayPalException('Payer account is restricted. To get more information about the status of the account, call Customer Support.', PayPalException::PAYER_ACCOUNT_RESTRICTED); + throw new PayPalException('Payer account is restricted. To get more information about the status of the account, call Customer Support.', PayPalException::PAYER_ACCOUNT_RESTRICTED, $previous); case 'PAYER_CANNOT_PAY': - throw new PayPalException('Payer cannot pay for this transaction. Please contact the payer to find other ways to pay for this transaction.', PayPalException::PAYER_CANNOT_PAY); + throw new PayPalException('Payer cannot pay for this transaction. Please contact the payer to find other ways to pay for this transaction.', PayPalException::PAYER_CANNOT_PAY, $previous); case 'PAYER_CONSENT_REQUIRED': - throw new PayPalException('The payer has not provided appropriate consent to proceed with this transaction. To proceed with the transaction, you must get payer consent.', PayPalException::PAYER_CONSENT_REQUIRED); + throw new PayPalException('The payer has not provided appropriate consent to proceed with this transaction. To proceed with the transaction, you must get payer consent.', PayPalException::PAYER_CONSENT_REQUIRED, $previous); case 'PAYER_COUNTRY_NOT_SUPPORTED': - throw new PayPalException('Payer Country is not supported. The Payer country is not supported. Redirect the payer to select another funding source.', PayPalException::PAYER_COUNTRY_NOT_SUPPORTED); + throw new PayPalException('Payer Country is not supported. The Payer country is not supported. Redirect the payer to select another funding source.', PayPalException::PAYER_COUNTRY_NOT_SUPPORTED, $previous); case 'PAYEE_NOT_ENABLED_FOR_CARD_PROCESSING': - throw new PayPalException('The API Caller account is not setup to be able to process card payments. Please contact PayPal customer support.', PayPalException::PAYEE_NOT_ENABLED_FOR_CARD_PROCESSING); + throw new PayPalException('The API Caller account is not setup to be able to process card payments. Please contact PayPal customer support.', PayPalException::PAYEE_NOT_ENABLED_FOR_CARD_PROCESSING, $previous); case 'PAYMENT_INSTRUCTION_REQUIRED': - throw new PayPalException('You must provide the payment instruction when you capture an authorized payment for intent=AUTHORIZE. For details, see Capture authorization. For intent=CAPTURE, send the payment instruction when you create the order.', PayPalException::PAYMENT_INSTRUCTION_REQUIRED); + throw new PayPalException('You must provide the payment instruction when you capture an authorized payment for intent=AUTHORIZE. For details, see Capture authorization. For intent=CAPTURE, send the payment instruction when you create the order.', PayPalException::PAYMENT_INSTRUCTION_REQUIRED, $previous); case 'PERMISSION_DENIED': - throw new PayPalException('You do not have permission to access or perform operations on this resource. If you make API calls on behalf of a merchant or payee, ensure that you have been granted appropriate permissions to continue with this request.', PayPalException::PERMISSION_DENIED); + throw new PayPalException('You do not have permission to access or perform operations on this resource. If you make API calls on behalf of a merchant or payee, ensure that you have been granted appropriate permissions to continue with this request.', PayPalException::PERMISSION_DENIED, $previous); case 'POSTAL_CODE_REQUIRED': - throw new PayPalException('The specified country requires a postal code. Specify a postal code and try the request again.', PayPalException::POSTAL_CODE_REQUIRED); + throw new PayPalException('The specified country requires a postal code. Specify a postal code and try the request again.', PayPalException::POSTAL_CODE_REQUIRED, $previous); case 'PREFERRED_SHIPPING_OPTION_AMOUNT_MISMATCH': - throw new PayPalException('The amount provided in the preferred shipping option should match the amount provided in amount breakdown.', PayPalException::PREFERRED_SHIPPING_OPTION_AMOUNT_MISMATCH); + throw new PayPalException('The amount provided in the preferred shipping option should match the amount provided in amount breakdown.', PayPalException::PREFERRED_SHIPPING_OPTION_AMOUNT_MISMATCH, $previous); case 'REDIRECT_PAYER_FOR_ALTERNATE_FUNDING': - throw new PayPalException('Transaction failed. Redirect the payer to select another funding source.', PayPalException::REDIRECT_PAYER_FOR_ALTERNATE_FUNDING); + throw new PayPalException('Transaction failed. Redirect the payer to select another funding source.', PayPalException::REDIRECT_PAYER_FOR_ALTERNATE_FUNDING, $previous); case 'REFERENCE_ID_NOT_FOUND': - throw new PayPalException('Filter expression value is incorrect. Check the value of the reference_id and try the request again.', PayPalException::REFERENCE_ID_NOT_FOUND); + throw new PayPalException('Filter expression value is incorrect. Check the value of the reference_id and try the request again.', PayPalException::REFERENCE_ID_NOT_FOUND, $previous); case 'REFERENCE_ID_REQUIRED': - throw new PayPalException('\'reference_id\' is required for each \'purchase_unit\' if multiple \'purchase_unit\' are provided. Provide a unique value for reference_id for each purchase_unit and try the request again.', PayPalException::REFERENCE_ID_REQUIRED); + throw new PayPalException('\'reference_id\' is required for each \'purchase_unit\' if multiple \'purchase_unit\' are provided. Provide a unique value for reference_id for each purchase_unit and try the request again.', PayPalException::REFERENCE_ID_REQUIRED, $previous); case 'DUPLICATE_REFERENCE_ID': - throw new PayPalException('reference_id must be unique if multiple purchase_unit are provided. Provide a unique value for reference_id for each purchase_unit and try the request again.', PayPalException::DUPLICATE_REFERENCE_ID); + throw new PayPalException('reference_id must be unique if multiple purchase_unit are provided. Provide a unique value for reference_id for each purchase_unit and try the request again.', PayPalException::DUPLICATE_REFERENCE_ID, $previous); case 'SHIPPING_ADDRESS_INVALID': - throw new PayPalException('Provided shipping address is invalid.', PayPalException::SHIPPING_ADDRESS_INVALID); + throw new PayPalException('Provided shipping address is invalid.', PayPalException::SHIPPING_ADDRESS_INVALID, $previous); case 'SHIPPING_OPTION_NOT_SELECTED': - throw new PayPalException('At least one of the shipping.option values must be selected = true.', PayPalException::SHIPPING_OPTION_NOT_SELECTED); + throw new PayPalException('At least one of the shipping.option values must be selected = true.', PayPalException::SHIPPING_OPTION_NOT_SELECTED, $previous); case 'SHIPPING_OPTIONS_NOT_SUPPORTED': - throw new PayPalException('Shipping options are not supported when application_context.shipping_preference is set as NO_SHIPPING or SET_PROVIDED_ADDRESS.', PayPalException::SHIPPING_OPTIONS_NOT_SUPPORTED); + throw new PayPalException('Shipping options are not supported when application_context.shipping_preference is set as NO_SHIPPING or SET_PROVIDED_ADDRESS.', PayPalException::SHIPPING_OPTIONS_NOT_SUPPORTED, $previous); case 'TAX_TOTAL_MISMATCH': - throw new PayPalException('Should equal sum of (tax * quantity) across all items for a given purchase_unit. The tax total must equal the sum of (tax * quantity) across all items for a purchase_unit.', PayPalException::TAX_TOTAL_MISMATCH); + throw new PayPalException('Should equal sum of (tax * quantity) across all items for a given purchase_unit. The tax total must equal the sum of (tax * quantity) across all items for a purchase_unit.', PayPalException::TAX_TOTAL_MISMATCH, $previous); case 'TAX_TOTAL_REQUIRED': - throw new PayPalException('If item details are specified (items.tax_total and items.quantity), the corresponding amount.breakdown.tax_total is required. The amount.breakdown.tax_total is a required field.', PayPalException::TAX_TOTAL_REQUIRED); + throw new PayPalException('If item details are specified (items.tax_total and items.quantity), the corresponding amount.breakdown.tax_total is required. The amount.breakdown.tax_total is a required field.', PayPalException::TAX_TOTAL_REQUIRED, $previous); case 'TRANSACTION_AMOUNT_EXCEEDS_MONTHLY_MAX_LIMIT': - throw new PayPalException('The transaction amount exceeds monthly maximum limit. To review the monthly transaction limits and retry this transaction, call Customer Support.', PayPalException::TRANSACTION_AMOUNT_EXCEEDS_MONTHLY_MAX_LIMIT); + throw new PayPalException('The transaction amount exceeds monthly maximum limit. To review the monthly transaction limits and retry this transaction, call Customer Support.', PayPalException::TRANSACTION_AMOUNT_EXCEEDS_MONTHLY_MAX_LIMIT, $previous); case 'TRANSACTION_BLOCKED_BY_PAYEE': - throw new PayPalException('The transaction was blocked by the payee’s Fraud Protection settings.', PayPalException::TRANSACTION_BLOCKED_BY_PAYEE); + throw new PayPalException('The transaction was blocked by the payee’s Fraud Protection settings.', PayPalException::TRANSACTION_BLOCKED_BY_PAYEE, $previous); case 'TRANSACTION_LIMIT_EXCEEDED': - throw new PayPalException('Total payment amount exceeded transaction limit. To review the transaction limit and retry this transaction, call Customer Support.', PayPalException::TRANSACTION_LIMIT_EXCEEDED); + throw new PayPalException('Total payment amount exceeded transaction limit. To review the transaction limit and retry this transaction, call Customer Support.', PayPalException::TRANSACTION_LIMIT_EXCEEDED, $previous); case 'TRANSACTION_RECEIVING_LIMIT_EXCEEDED': - throw new PayPalException('The transaction exceeds the payee\'s receiving limit. To review the transaction limit and retry this transaction, call Customer Support.', PayPalException::TRANSACTION_RECEIVING_LIMIT_EXCEEDED); + throw new PayPalException('The transaction exceeds the payee\'s receiving limit. To review the transaction limit and retry this transaction, call Customer Support.', PayPalException::TRANSACTION_RECEIVING_LIMIT_EXCEEDED, $previous); case 'TRANSACTION_REFUSED': - throw new PayPalException('The transaction was refused. Verify the transaction and try the request again.', PayPalException::TRANSACTION_REFUSED); + throw new PayPalException('The transaction was refused. Verify the transaction and try the request again.', PayPalException::TRANSACTION_REFUSED, $previous); case 'UNSUPPORTED_INTENT': - throw new PayPalException('intent=AUTHORIZE is not supported for multiple purchase units. Only intent=CAPTURE is supported.', PayPalException::UNSUPPORTED_INTENT); + throw new PayPalException('intent=AUTHORIZE is not supported for multiple purchase units. Only intent=CAPTURE is supported.', PayPalException::UNSUPPORTED_INTENT, $previous); case 'UNSUPPORTED_PATCH_PARAMETER_VALUE': - throw new PayPalException('The value specified for this field is not currently supported. Try the request again with a different value.', PayPalException::UNSUPPORTED_PATCH_PARAMETER_VALUE); + throw new PayPalException('The value specified for this field is not currently supported. Try the request again with a different value.', PayPalException::UNSUPPORTED_PATCH_PARAMETER_VALUE, $previous); case 'UNSUPPORTED_PAYMENT_INSTRUCTION': - throw new PayPalException('Only supported when the intent=CAPTURE. If intent is AUTHORIZE, you must provide a payment_instruction when you capture payment for the authorization.', PayPalException::UNSUPPORTED_PAYMENT_INSTRUCTION); + throw new PayPalException('Only supported when the intent=CAPTURE. If intent is AUTHORIZE, you must provide a payment_instruction when you capture payment for the authorization.', PayPalException::UNSUPPORTED_PAYMENT_INSTRUCTION, $previous); case 'PAYEE_ACCOUNT_NOT_SUPPORTED': - throw new PayPalException('Payee does not have an account with PayPal. Your current setup requires the \'payee\' to have a verified account with PayPal before you can process transactions on their behalf.', PayPalException::PAYEE_ACCOUNT_NOT_SUPPORTED); + throw new PayPalException('Payee does not have an account with PayPal. Your current setup requires the \'payee\' to have a verified account with PayPal before you can process transactions on their behalf.', PayPalException::PAYEE_ACCOUNT_NOT_SUPPORTED, $previous); case 'PAYEE_ACCOUNT_NOT_VERIFIED': - throw new PayPalException('Payee has not verified their account with PayPal. Your current setup requires the \'payee\' to have an account with PayPal before you can process transactions on their behalf.', PayPalException::PAYEE_ACCOUNT_NOT_VERIFIED); + throw new PayPalException('Payee has not verified their account with PayPal. Your current setup requires the \'payee\' to have an account with PayPal before you can process transactions on their behalf.', PayPalException::PAYEE_ACCOUNT_NOT_VERIFIED, $previous); case 'PAYEE_NOT_CONSENTED': - throw new PayPalException('Payee does not have appropriate consent to allow the API caller to process this type of transaction on their behalf. Your current setup requires the \'payee\' to provide a consent before this transaction can be processed successfully.', PayPalException::PAYEE_NOT_CONSENTED); + throw new PayPalException('Payee does not have appropriate consent to allow the API caller to process this type of transaction on their behalf. Your current setup requires the \'payee\' to provide a consent before this transaction can be processed successfully.', PayPalException::PAYEE_NOT_CONSENTED, $previous); case 'AUTH_CAPTURE_CURRENCY_MISMATCH': - throw new PayPalException('Currency of capture must be the same as currency of authorization. Verify the currency of the capture and try the request again.', PayPalException::AUTH_CAPTURE_CURRENCY_MISMATCH); + throw new PayPalException('Currency of capture must be the same as currency of authorization. Verify the currency of the capture and try the request again.', PayPalException::AUTH_CAPTURE_CURRENCY_MISMATCH, $previous); case 'AUTHORIZATION_ALREADY_CAPTURED': - throw new PayPalException('Authorization has already been captured. If final_capture is set to to true, additional captures are not possible against the authorization.', PayPalException::AUTHORIZATION_ALREADY_CAPTURED); + throw new PayPalException('Authorization has already been captured. If final_capture is set to to true, additional captures are not possible against the authorization.', PayPalException::AUTHORIZATION_ALREADY_CAPTURED, $previous); case 'AUTHORIZATION_DENIED': - throw new PayPalException('A denied authorization cannot be captured. You cannot capture a denied authorization.', PayPalException::AUTHORIZATION_DENIED); + throw new PayPalException('A denied authorization cannot be captured. You cannot capture a denied authorization.', PayPalException::AUTHORIZATION_DENIED, $previous); case 'AUTHORIZATION_EXPIRED': - throw new PayPalException('An expired authorization cannot be captured. You cannot capture an expired authorization.', PayPalException::AUTHORIZATION_EXPIRED); + throw new PayPalException('An expired authorization cannot be captured. You cannot capture an expired authorization.', PayPalException::AUTHORIZATION_EXPIRED, $previous); case 'AUTHORIZATION_VOIDED': - throw new PayPalException('A voided authorization cannot be captured or reauthorized. You cannot capture or reauthorize a voided authorization.', PayPalException::AUTHORIZATION_VOIDED); + throw new PayPalException('A voided authorization cannot be captured or reauthorized. You cannot capture or reauthorize a voided authorization.', PayPalException::AUTHORIZATION_VOIDED, $previous); case 'CANNOT_BE_VOIDED': - throw new PayPalException('A reauthorization cannot be voided. Please void the original parent authorization. You cannot void a reauthorized payment. You must void the original parent authorized payment.', PayPalException::CANNOT_BE_VOIDED); + throw new PayPalException('A reauthorization cannot be voided. Please void the original parent authorization. You cannot void a reauthorized payment. You must void the original parent authorized payment.', PayPalException::CANNOT_BE_VOIDED, $previous); case 'REFUND_NOT_PERMITTED_DUE_TO_CHARGEBACK': - throw new PayPalException('Refunds not allowed on this capture due to a chargeback on the card or bank. Please contact the payee to resolve the chargeback.', PayPalException::REFUND_NOT_PERMITTED_DUE_TO_CHARGEBACK); + throw new PayPalException('Refunds not allowed on this capture due to a chargeback on the card or bank. Please contact the payee to resolve the chargeback.', PayPalException::REFUND_NOT_PERMITTED_DUE_TO_CHARGEBACK, $previous); case 'CAPTURE_DISPUTED_PARTIAL_REFUND_NOT_ALLOWED': - throw new PayPalException('Refund for an amount less than the remaining transaction amount cannot be processed at this time because of an open dispute on the capture. Please visit the PayPal Resolution Center to view the details.', PayPalException::CAPTURE_DISPUTED_PARTIAL_REFUND_NOT_ALLOWED); + throw new PayPalException('Refund for an amount less than the remaining transaction amount cannot be processed at this time because of an open dispute on the capture. Please visit the PayPal Resolution Center to view the details.', PayPalException::CAPTURE_DISPUTED_PARTIAL_REFUND_NOT_ALLOWED, $previous); case 'CAPTURE_FULLY_REFUNDED': - throw new PayPalException('The capture has already been fully refunded. You cannot capture additional refunds against this capture.', PayPalException::CAPTURE_FULLY_REFUNDED); + throw new PayPalException('The capture has already been fully refunded. You cannot capture additional refunds against this capture.', PayPalException::CAPTURE_FULLY_REFUNDED, $previous); case 'DECIMALS_NOT_SUPPORTED': - throw new PayPalException('Currency does not support decimals.', PayPalException::DECIMALS_NOT_SUPPORTED); + throw new PayPalException('Currency does not support decimals.', PayPalException::DECIMALS_NOT_SUPPORTED, $previous); case 'INVALID_PAYEE_ACCOUNT': - throw new PayPalException('Payee account is invalid. Verify the payee account information and try the request again.', PayPalException::INVALID_PAYEE_ACCOUNT); + throw new PayPalException('Payee account is invalid. Verify the payee account information and try the request again.', PayPalException::INVALID_PAYEE_ACCOUNT, $previous); case 'INVALID_PLATFORM_FEES_AMOUNT': - throw new PayPalException('The platform_fees amount cannot be greater than the capture amount. Verify the platform_fees amount and try the request again.', PayPalException::INVALID_PLATFORM_FEES_AMOUNT); + throw new PayPalException('The platform_fees amount cannot be greater than the capture amount. Verify the platform_fees amount and try the request again.', PayPalException::INVALID_PLATFORM_FEES_AMOUNT, $previous); case 'INVALID_STRING_MAX_LENGTH': - throw new PayPalException('The value of a field is too long. The parameter string is too long.', PayPalException::INVALID_STRING_MAX_LENGTH); + throw new PayPalException('The value of a field is too long. The parameter string is too long.', PayPalException::INVALID_STRING_MAX_LENGTH, $previous); case 'MAX_CAPTURE_AMOUNT_EXCEEDED': - throw new PayPalException('Capture amount exceeds allowable limit. Please contact customer service or your account manager to request the change to your overage limit. The default overage limit is 115%, which allows the sum of all captures to be up to 115% of the authorization amount. Specify a different amount and try the request again. Alternately, contact Customer Support to increase your limits.', PayPalException::MAX_CAPTURE_AMOUNT_EXCEEDED); + throw new PayPalException('Capture amount exceeds allowable limit. Please contact customer service or your account manager to request the change to your overage limit. The default overage limit is 115%, which allows the sum of all captures to be up to 115% of the authorization amount. Specify a different amount and try the request again. Alternately, contact Customer Support to increase your limits.', PayPalException::MAX_CAPTURE_AMOUNT_EXCEEDED, $previous); case 'MAX_CAPTURE_COUNT_EXCEEDED': - throw new PayPalException('Maximum number of allowable captures has been reached. No additional captures are possible for this authorization. Please contact customer service or your account manager to change the number of captures that be made for a given authorization. You cannot make additional captures.', PayPalException::MAX_CAPTURE_COUNT_EXCEEDED); + throw new PayPalException('Maximum number of allowable captures has been reached. No additional captures are possible for this authorization. Please contact customer service or your account manager to change the number of captures that be made for a given authorization. You cannot make additional captures.', PayPalException::MAX_CAPTURE_COUNT_EXCEEDED, $previous); case 'MAX_NUMBER_OF_REFUNDS_EXCEEDED': - throw new PayPalException('You have exceeded the number of refunds that can be processed per capture. Please contact customer support or your account manager to review the number of refunds that can be processed per capture.', PayPalException::MAX_NUMBER_OF_REFUNDS_EXCEEDED); + throw new PayPalException('You have exceeded the number of refunds that can be processed per capture. Please contact customer support or your account manager to review the number of refunds that can be processed per capture.', PayPalException::MAX_NUMBER_OF_REFUNDS_EXCEEDED, $previous); case 'PARTIAL_REFUND_NOT_ALLOWED': - throw new PayPalException('You cannot do a refund for an amount less than the original capture amount. Specify an amount equal to the capture amount or omit the amount object from the request. Then, try the request again.', PayPalException::PARTIAL_REFUND_NOT_ALLOWED); + throw new PayPalException('You cannot do a refund for an amount less than the original capture amount. Specify an amount equal to the capture amount or omit the amount object from the request. Then, try the request again.', PayPalException::PARTIAL_REFUND_NOT_ALLOWED, $previous); case 'PENDING_CAPTURE': - throw new PayPalException('Cannot initiate a refund as the capture is pending. Capture is typically pending when the payer has funded the transaction by using an e-check or bank account.', PayPalException::PENDING_CAPTURE); + throw new PayPalException('Cannot initiate a refund as the capture is pending. Capture is typically pending when the payer has funded the transaction by using an e-check or bank account.', PayPalException::PENDING_CAPTURE, $previous); case 'PERMISSION_NOT_GRANTED': - throw new PayPalException('Payee of the authorization has not granted permission to perform capture on the authorization. To make API calls on behalf of a merchant, ensure that you have sufficient permissions to capture the authorization.', PayPalException::PERMISSION_NOT_GRANTED); + throw new PayPalException('Payee of the authorization has not granted permission to perform capture on the authorization. To make API calls on behalf of a merchant, ensure that you have sufficient permissions to capture the authorization.', PayPalException::PERMISSION_NOT_GRANTED, $previous); case 'PREVIOUSLY_CAPTURED': - throw new PayPalException('Authorization has been previously captured and hence cannot be voided. This authorized payment was already captured. You cannot capture it again.', PayPalException::PREVIOUSLY_CAPTURED); + throw new PayPalException('Authorization has been previously captured and hence cannot be voided. This authorized payment was already captured. You cannot capture it again.', PayPalException::PREVIOUSLY_CAPTURED, $previous); case 'PREVIOUSLY_VOIDED': - throw new PayPalException('Authorization has been previously voided and hence cannot be voided again. This authorized payment was already voided. You cannot void it again.', PayPalException::PREVIOUSLY_VOIDED); + throw new PayPalException('Authorization has been previously voided and hence cannot be voided again. This authorized payment was already voided. You cannot void it again.', PayPalException::PREVIOUSLY_VOIDED, $previous); case 'REFUND_AMOUNT_EXCEEDED': - throw new PayPalException('The refund amount must be less than or equal to the capture amount that has not yet been refunded. Verify the refund amount and try the request again.', PayPalException::REFUND_AMOUNT_EXCEEDED); + throw new PayPalException('The refund amount must be less than or equal to the capture amount that has not yet been refunded. Verify the refund amount and try the request again.', PayPalException::REFUND_AMOUNT_EXCEEDED, $previous); case 'REFUND_CAPTURE_CURRENCY_MISMATCH': - throw new PayPalException('Refund must be in the same currency as the capture. Verify the currency of the refund and try the request again.', PayPalException::REFUND_CAPTURE_CURRENCY_MISMATCH); + throw new PayPalException('Refund must be in the same currency as the capture. Verify the currency of the refund and try the request again.', PayPalException::REFUND_CAPTURE_CURRENCY_MISMATCH, $previous); case 'REFUND_FAILED_INSUFFICIENT_FUNDS': - throw new PayPalException('Capture could not be refunded due to insufficient funds. Verify that either you have sufficient funds in your PayPal account or the bank account that is linked to your PayPal account is verified and has sufficient funds.', PayPalException::REFUND_FAILED_INSUFFICIENT_FUNDS); + throw new PayPalException('Capture could not be refunded due to insufficient funds. Verify that either you have sufficient funds in your PayPal account or the bank account that is linked to your PayPal account is verified and has sufficient funds.', PayPalException::REFUND_FAILED_INSUFFICIENT_FUNDS, $previous); case 'REFUND_NOT_ALLOWED': - throw new PayPalException('Full refund refused - partial refund has already been done on this payment. You cannot refund this capture.', PayPalException::REFUND_NOT_ALLOWED); + throw new PayPalException('Full refund refused - partial refund has already been done on this payment. You cannot refund this capture.', PayPalException::REFUND_NOT_ALLOWED, $previous); case 'REFUND_TIME_LIMIT_EXCEEDED': - throw new PayPalException('You are over the time limit to perform a refund on this capture. The refund cannot be issued at this time.', PayPalException::REFUND_TIME_LIMIT_EXCEEDED); + throw new PayPalException('You are over the time limit to perform a refund on this capture. The refund cannot be issued at this time.', PayPalException::REFUND_TIME_LIMIT_EXCEEDED, $previous); case 'NO_EXTERNAL_FUNDING_DETAILS_FOUND': - throw new PayPalException('External funding details not found.', PayPalException::NO_EXTERNAL_FUNDING_DETAILS_FOUND); + throw new PayPalException('External funding details not found.', PayPalException::NO_EXTERNAL_FUNDING_DETAILS_FOUND, $previous); case 'PAYMENT_DENIED': - throw new PayPalException('Payment denied.', PayPalException::PAYMENT_DENIED); + throw new PayPalException('Payment denied.', PayPalException::PAYMENT_DENIED, $previous); case 'CARD_BRAND_NOT_SUPPORTED': - throw new PayPalException('Processing of this card brand is not supported. Use another type of card.', PayPalException::CARD_BRAND_NOT_SUPPORTED); + throw new PayPalException('Processing of this card brand is not supported. Use another type of card.', PayPalException::CARD_BRAND_NOT_SUPPORTED, $previous); case 'RESOURCE_NOT_FOUND': - throw new PayPalException('The specified resource does not exist.', PayPalException::RESOURCE_NOT_FOUND); + throw new PayPalException('The specified resource does not exist.', PayPalException::RESOURCE_NOT_FOUND, $previous); case 'PAYMENT_SOURCE_CANNOT_BE_USED': - throw new PayPalException('The provided payment source cannot be used to pay for the order. Please try again with a different payment source by creating a new order.', PayPalException::PAYMENT_SOURCE_CANNOT_BE_USED); + throw new PayPalException('The provided payment source cannot be used to pay for the order. Please try again with a different payment source by creating a new order.', PayPalException::PAYMENT_SOURCE_CANNOT_BE_USED, $previous); + case 'PAYPAL_REQUEST_ID_REQUIRED': + throw new PayPalException('A PayPal-Request-Id is required if you are trying to process payment for an Order. Please specify a PayPal-Request-Id or Create the Order without a payment_source specified.', PayPalException::PAYPAL_REQUEST_ID_REQUIRED, $previous); + case 'MALFORMED_REQUEST_JSON': + throw new PayPalException('The request JSON is not well formed.', PayPalException::MALFORMED_REQUEST_JSON, $previous); + case 'PERMISSION_DENIED_FOR_DONATION_ITEMS': + throw new PayPalException('The API caller or payee have not been granted appropriate permissions to send items.category as DONATION. Speak to your account manager if you want to process these type of items.', PayPalException::PERMISSION_DENIED_FOR_DONATION_ITEMS, $previous); + case 'MALFORMED_REQUEST': + throw new PayPalException('You\'ve sent a request that our server could not understand.', PayPalException::MALFORMED_REQUEST, $previous); + case 'BILLING_ADDRESS_INVALID': + throw new PayPalException('Provided billing address is invalid.', PayPalException::BILLING_ADDRESS_INVALID, $previous); + case 'CARD_EXPIRED': + throw new PayPalException('The payment card provided is expired.', PayPalException::CARD_EXPIRED, $previous); + case 'DONATION_ITEMS_NOT_SUPPORTED': + throw new PayPalException('If "purchase_unit" has "DONATION" as the "items.category" then the Order can at most have one purchase_unit. Multiple purchase_units are not supported if either of them have at least one items with category as "DONATION".', PayPalException::DONATION_ITEMS_NOT_SUPPORTED, $previous); + case 'MISSING_PICKUP_ADDRESS': + throw new PayPalException('A pickup address (shipping.address) is required for the provided shipping.type. Possible error location: /purchase_units/0/shipping/type', PayPalException::MISSING_PICKUP_ADDRESS, $previous); + case 'MULTIPLE_ITEM_CATEGORIES': + throw new PayPalException('For a given purchase unit, the items.category could be either PHYSICAL_GOODS and\/or DIGITAL_GOODS or just DONATION. items.category as DONATION cannot be combined with items with either PHYSICAL_GOODS or DIGITAL_GOODS.', PayPalException::MULTIPLE_ITEM_CATEGORIES, $previous); + case 'MULTIPLE_SHIPPING_TYPE_NOT_SUPPORTED': + throw new PayPalException('Different shipping.type are not supported across purchase units.', PayPalException::MULTIPLE_SHIPPING_TYPE_NOT_SUPPORTED, $previous); + case 'PAYMENT_SOURCE_DECLINED_BY_PROCESSOR': + throw new PayPalException('The provided payment source is declined by the processor. Please try again with a different payment source by creating a new order.', PayPalException::PAYMENT_SOURCE_DECLINED_BY_PROCESSOR, $previous); + case 'PAYMENT_SOURCE_INFO_CANNOT_BE_VERIFIED': + throw new PayPalException('The provided payment source is declined by the processor. Please try again with a different payment source by creating a new order.', PayPalException::PAYMENT_SOURCE_INFO_CANNOT_BE_VERIFIED, $previous); + case 'SHIPPING_TYPE_NOT_SUPPORTED_FOR_CLIENT': + throw new PayPalException('The API Caller account is not setup to be able to support a shipping.type=PICKUP_IN_PERSON. This feature is only supported for PayPal Commerce Platform for Platforms and Marketplaces.', PayPalException::SHIPPING_TYPE_NOT_SUPPORTED_FOR_CLIENT, $previous); + case 'UNSUPPORTED_SHIPPING_TYPE': + throw new PayPalException('The provided shipping.type is only supported for application_context.shipping_preference=SET_PROVIDED_ADDRESS or NO_SHIPPING. Possible error location: /purchase_units/0/shipping/type.', PayPalException::UNSUPPORTED_SHIPPING_TYPE, $previous); + case 'CARD_CLOSED': + throw new PayPalException('The card is closed with the issuer.', PayPalException::CARD_CLOSED, $previous); + case 'SAVE_ORDER_NOT_SUPPORTED': + throw new PayPalException('The API caller account is setup in a way that does not allow it to be used for saving the order. This functionality is not available for PayPal Commerce Platform for Platforms & Marketplaces.', PayPalException::SAVE_ORDER_NOT_SUPPORTED, $previous); + case 'PUI_DUPLICATE_ORDER': + throw new PayPalException('A Pay Upon Invoice (Rechnungskauf) order with the same payload has already been successfully processed in the last few seconds. To process a new order, please try again in a few seconds.', PayPalException::PUI_DUPLICATE_ORDER, $previous); + case 'CANNOT_PROCESS_REFUNDS': + throw new PayPalException('We can\'t process any refund at this moment due to technical reasons. Please try again later.', PayPalException::CANNOT_PROCESS_REFUNDS, $previous); + case 'INVALID_REFUND_AMOUNT': + throw new PayPalException('The refund amount is invalid. Please check the refund amount and try again.', PayPalException::INVALID_REFUND_AMOUNT, $previous); default: - throw new PayPalException($this->message, PayPalException::UNKNOWN); + throw new PayPalException($this->message, PayPalException::UNKNOWN, $previous); } } } diff --git a/src/PaypalOrder.php b/src/PaypalOrder.php index 831f6c80d..4cc0e6462 100644 --- a/src/PaypalOrder.php +++ b/src/PaypalOrder.php @@ -20,7 +20,11 @@ namespace PrestaShop\Module\PrestashopCheckout; -use PrestaShop\Module\PrestashopCheckout\Api\Payment\Order; +use Module; +use PrestaShop\Module\PrestashopCheckout\Exception\PayPalException; +use PrestaShop\Module\PrestashopCheckout\Handler\Response\ResponseApiHandler; +use PrestaShop\Module\PrestashopCheckout\Http\CheckoutHttpClient; +use Ps_checkout; /** * Allow to instantiate a paypal order @@ -47,20 +51,32 @@ public function __construct($id) */ private function loadOrder($id) { - $response = (new Order(\Context::getContext()->link))->fetch($id); + /** @var Ps_checkout $module */ + $module = Module::getInstanceByName('ps_checkout'); - if (false === $response['status'] && ((isset($response['body']['message']) && $response['body']['message'] === 'INVALID_RESOURCE_ID') || $response['exceptionCode'] === 404)) { - \Db::getInstance()->update( - \PsCheckoutCart::$definition['table'], - [ - 'paypal_status' => \PsCheckoutCart::STATUS_CANCELED, - ], - 'paypal_order = "' . pSQL($id) . '"' - ); - } + /** @var CheckoutHttpClient $checkoutHttpClient */ + $checkoutHttpClient = $module->getService('ps_checkout.http.client.checkout'); + + try { + $response = $checkoutHttpClient->fetchOrder([ + 'orderId' => $id, + ]); + $responseHandler = new ResponseApiHandler(); + $response = $responseHandler->handleResponse($response); - if (true === $response['status'] && !empty($response['body'])) { - $this->setOrder($response['body']); + if (true === $response['status'] && !empty($response['body'])) { + $this->setOrder($response['body']); + } + } catch (PayPalException $exception) { + if ($exception->getCode() === PayPalException::INVALID_RESOURCE_ID) { + \Db::getInstance()->update( + \PsCheckoutCart::$definition['table'], + [ + 'paypal_status' => \PsCheckoutCart::STATUS_CANCELED, + ], + 'paypal_order = "' . pSQL($id) . '"' + ); + } } } diff --git a/tests/Unit/Http/CheckoutHttpClientTest.php b/tests/Unit/Http/CheckoutHttpClientTest.php new file mode 100644 index 000000000..3944e6b34 --- /dev/null +++ b/tests/Unit/Http/CheckoutHttpClientTest.php @@ -0,0 +1,417 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace Tests\Unit\Http; + +use Http\Client\Exception\HttpException; +use PHPUnit\Framework\TestCase; +use PrestaShop\Module\PrestashopCheckout\Exception\PayPalException; +use PrestaShop\Module\PrestashopCheckout\Http\CheckoutHttpClient; +use PrestaShop\Module\PrestashopCheckout\Http\HttpClientInterface; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; + +class CheckoutHttpClientTest extends TestCase +{ + /** + * @dataProvider invalidRequestErrorsProvider + * + * @throws PayPalException + */ + public function testInvalidRequestErrorsCreateOrder($errorName, $errorCode) + { + $this->handleTestErrorsCreateOrder(400, $errorName, $errorCode); + } + + /** + * @dataProvider notAuthorizedErrorsProvider + * + * @throws PayPalException + */ + public function testNotAuthorizedErrorsCreateOrder($errorName, $errorCode) + { + $this->handleTestErrorsCreateOrder(401, $errorName, $errorCode); + } + + /** + * @dataProvider unprocessableEntityErrorsProvider + * + * @throws PayPalException + */ + public function testUnprocessableEntityErrorsCreateOrder($errorName, $errorCode) + { + $this->handleTestErrorsCreateOrder(422, $errorName, $errorCode); + } + + /** + * @dataProvider notFoundErrorsProvider + * + * @throws PayPalException + */ + public function testNotFoundErrorsCreateOrder($errorName, $errorCode) + { + $this->handleTestErrorsCreateOrder(404, $errorName, $errorCode); + } + + /** + * @dataProvider invalidRequestErrorsProvider + * + * @throws PayPalException + */ + public function testInvalidRequestErrorsCreateOrderLegacy($errorName, $errorCode) + { + $this->handleTestErrorsCreateOrder(400, $errorName, $errorCode, true); + } + + /** + * @dataProvider notAuthorizedErrorsProvider + * + * @throws PayPalException + */ + public function testNotAuthorizedErrorsCreateOrderLegacy($errorName, $errorCode) + { + $this->handleTestErrorsCreateOrder(401, $errorName, $errorCode, true); + } + + /** + * @dataProvider unprocessableEntityErrorsProvider + * + * @throws PayPalException + */ + public function testUnprocessableEntityErrorsCreateOrderLegacy($errorName, $errorCode) + { + $this->handleTestErrorsCreateOrder(422, $errorName, $errorCode, true); + } + + /** + * @dataProvider notFoundErrorsProvider + * + * @throws PayPalException + */ + public function testNotFoundErrorsCreateOrderLegacy($errorName, $errorCode) + { + $this->handleTestErrorsCreateOrder(404, $errorName, $errorCode, true); + } + + /** + * @param int $statusCode + * @param string $errorName + * @param int $errorCode + * @param bool $legacy + * + * @throws PayPalException + */ + private function handleTestErrorsCreateOrder($statusCode, $errorName, $errorCode, $legacy = false) + { + $error = $this->getErrorResponse($statusCode, $errorName, $legacy); + $requestMock = $this->createMock(RequestInterface::class); + $streamMock = $this->createMock(StreamInterface::class); + $streamMock->method('__toString')->willReturn(json_encode($error)); + $responseMock = $this->createMock(ResponseInterface::class); + $responseMock->method('getStatusCode')->willReturn($statusCode); + $responseMock->method('getBody')->willReturn($streamMock); + $httpClient = $this->createMock(HttpClientInterface::class); + $httpClient->method('sendRequest')->willThrowException(new HttpException('An error occurred', $requestMock, $responseMock)); + $this->expectExceptionCode($errorCode); + $this->expectException(PayPalException::class); + $checkoutHttpClient = new CheckoutHttpClient($httpClient); + $checkoutHttpClient->createOrder([]); + } + + private function getInvalidRequestError($issueError) + { + return [ + 'name' => 'INVALID_REQUEST', + 'message' => 'Request is not well-formed, syntactically incorrect, or violates schema.', + 'debug_id' => 'b6b9a374802ea', + 'details' => [ + [ + 'field' => '', + 'value' => '', + 'location' => 'body', + 'issue' => $issueError, + 'description' => '', + ], + ], + 'links' => [ + [ + 'href' => 'https://developer.paypal.com/docs/api/orders/v2/#error-INVALID_PARAMETER_VALUE', + 'rel' => 'information_link', + 'encType' => 'application/json', + ], + ], + ]; + } + + /** + * @param int $statusCode + * @param string $errorName + * @param bool $legacy + * + * @return array + */ + private function getErrorResponse($statusCode, $errorName, $legacy) + { + if ($legacy) { + switch ($statusCode) { + case 400: + return $this->getInvalidRequestErrorLegacy($errorName); + case 401: + return $this->getNotAuthorizedErrorLegacy($errorName); + case 404: + return $this->getNotFoundErrorLegacy($errorName); + case 422: + return $this->getUnprocessableEntityErrorLegacy($errorName); + } + } + + switch ($statusCode) { + case 400: + return $this->getInvalidRequestError($errorName); + case 401: + return $this->getNotAuthorizedError($errorName); + case 404: + return $this->getNotFoundError($errorName); + case 422: + return $this->getUnprocessableEntityError($errorName); + } + + return []; + } + + private function getInvalidRequestErrorLegacy($issueError) + { + return [ + 'statusCode' => 400, + 'error' => 'Bad Request', + 'message' => $issueError, + ]; + } + + private function getNotAuthorizedError($issueError) + { + return [ + 'name' => $issueError, + 'message' => 'Authentication failed due to invalid authentication credentials or a missing Authorization header.', + 'links' => [ + [ + 'href' => 'https://developer.paypal.com/docs/api/overview/#error', + 'rel' => 'information_link', + ], + ], + ]; + } + + private function getNotAuthorizedErrorLegacy($issueError) + { + return [ + 'statusCode' => 401, + 'error' => 'Unprocessable Entity', + 'message' => $issueError, + ]; + } + + private function getUnprocessableEntityError($issueError) + { + return [ + 'name' => 'UNPROCESSABLE_ENTITY', + 'details' => [ + [ + 'field' => '', + 'value' => '', + 'issue' => $issueError, + 'description' => '', + ], + ], + 'message' => 'The requested action could not be performed, semantically incorrect, or failed business validation.', + 'debug_id' => 'c9a75b43fc807', + 'links' => [ + [ + 'href' => 'https://developer.paypal.com/docs/api/orders/v2/#error-MAX_VALUE_EXCEEDED', + 'rel' => 'information_link', + 'method' => 'GET', + ], + ], + ]; + } + + private function getUnprocessableEntityErrorLegacy($issueError) + { + return [ + 'statusCode' => 422, + 'error' => 'Unprocessable Entity', + 'message' => $issueError, + ]; + } + + /** + * @param string $errorName + * + * @return array + */ + private function getNotFoundError($errorName) + { + return [ + 'name' => $errorName, + 'message' => 'The specified resource does not exist.', + 'debug_id' => 'b6b9a374802ea', + 'links' => [ + [ + 'href' => 'https://developer.paypal.com/docs/api/orders/v2/#error-' . $errorName, + 'rel' => 'information_link', + 'encType' => 'application/json', + ], + ], + ]; + } + + private function getNotFoundErrorLegacy($issueError) + { + return [ + 'statusCode' => 404, + 'error' => 'Not found', + 'message' => $issueError, + ]; + } + + public function notFoundErrorsProvider() + { + return [ + ['INVALID_RESOURCE_ID', PayPalException::INVALID_RESOURCE_ID], + ]; + } + + public function invalidRequestErrorsProvider() + { + return [ + ['INVALID_ARRAY_MAX_ITEMS', PayPalException::INVALID_ARRAY_MAX_ITEMS], + ['INVALID_ARRAY_MIN_ITEMS', PayPalException::INVALID_ARRAY_MIN_ITEMS], + ['INVALID_COUNTRY_CODE', PayPalException::INVALID_COUNTRY_CODE], + ['INVALID_PARAMETER_SYNTAX', PayPalException::INVALID_PARAMETER_SYNTAX], + ['INVALID_STRING_LENGTH', PayPalException::INVALID_STRING_LENGTH], + ['INVALID_PARAMETER_VALUE', PayPalException::INVALID_PARAMETER_VALUE], + ['MISSING_REQUIRED_PARAMETER', PayPalException::MISSING_REQUIRED_PARAMETER], + ['NOT_SUPPORTED', PayPalException::NOT_SUPPORTED], + ['PAYPAL_REQUEST_ID_REQUIRED', PayPalException::PAYPAL_REQUEST_ID_REQUIRED], + ['MALFORMED_REQUEST_JSON', PayPalException::MALFORMED_REQUEST_JSON], + ['FIELD_NOT_PATCHABLE', PayPalException::FIELD_NOT_PATCHABLE], + ['AMOUNT_NOT_PATCHABLE', PayPalException::AMOUNT_NOT_PATCHABLE], + ['INVALID_PATCH_OPERATION', PayPalException::INVALID_PATCH_OPERATION], + ]; + } + + public function notAuthorizedErrorsProvider() + { + return [ + ['PERMISSION_DENIED', PayPalException::PERMISSION_DENIED], + ['PERMISSION_DENIED_FOR_DONATION_ITEMS', PayPalException::PERMISSION_DENIED_FOR_DONATION_ITEMS], + ['MALFORMED_REQUEST', PayPalException::MALFORMED_REQUEST], + ['PAYEE_ACCOUNT_NOT_SUPPORTED', PayPalException::PAYEE_ACCOUNT_NOT_SUPPORTED], + ['PAYEE_ACCOUNT_NOT_VERIFIED', PayPalException::PAYEE_ACCOUNT_NOT_VERIFIED], + ['PAYEE_NOT_CONSENTED', PayPalException::PAYEE_NOT_CONSENTED], + ['CONSENT_NEEDED', PayPalException::CONSENT_NEEDED], + ['INVALID_ACCOUNT_STATUS', PayPalException::INVALID_ACCOUNT_STATUS], + ]; + } + + public function unprocessableEntityErrorsProvider() + { + return [ + ['AMOUNT_MISMATCH', PayPalException::AMOUNT_MISMATCH], + ['BILLING_ADDRESS_INVALID', PayPalException::BILLING_ADDRESS_INVALID], + ['CANNOT_BE_NEGATIVE', PayPalException::CANNOT_BE_NEGATIVE], + ['CANNOT_BE_ZERO_OR_NEGATIVE', PayPalException::CANNOT_BE_ZERO_OR_NEGATIVE], + ['CARD_EXPIRED', PayPalException::CARD_EXPIRED], + ['CITY_REQUIRED', PayPalException::CITY_REQUIRED], + ['DECIMAL_PRECISION', PayPalException::DECIMAL_PRECISION], + ['DONATION_ITEMS_NOT_SUPPORTED', PayPalException::DONATION_ITEMS_NOT_SUPPORTED], + ['DUPLICATE_REFERENCE_ID', PayPalException::DUPLICATE_REFERENCE_ID], + ['INVALID_CURRENCY_CODE', PayPalException::INVALID_CURRENCY_CODE], + ['INVALID_PAYER_ID', PayPalException::INVALID_PAYER_ID], + ['ITEM_TOTAL_MISMATCH', PayPalException::ITEM_TOTAL_MISMATCH], + ['ITEM_TOTAL_REQUIRED', PayPalException::ITEM_TOTAL_REQUIRED], + ['MAX_VALUE_EXCEEDED', PayPalException::MAX_VALUE_EXCEEDED], + ['MISSING_PICKUP_ADDRESS', PayPalException::MISSING_PICKUP_ADDRESS], + ['MULTIPLE_ITEM_CATEGORIES', PayPalException::MULTIPLE_ITEM_CATEGORIES], + ['MULTIPLE_SHIPPING_ADDRESS_NOT_SUPPORTED', PayPalException::MULTIPLE_SHIPPING_ADDRESS_NOT_SUPPORTED], + ['MULTIPLE_SHIPPING_TYPE_NOT_SUPPORTED', PayPalException::MULTIPLE_SHIPPING_TYPE_NOT_SUPPORTED], + ['PAYEE_ACCOUNT_INVALID', PayPalException::PAYEE_ACCOUNT_INVALID], + ['PAYEE_ACCOUNT_LOCKED_OR_CLOSED', PayPalException::PAYEE_ACCOUNT_LOCKED_OR_CLOSED], + ['PAYEE_ACCOUNT_RESTRICTED', PayPalException::PAYEE_ACCOUNT_RESTRICTED], + ['REFERENCE_ID_REQUIRED', PayPalException::REFERENCE_ID_REQUIRED], + ['PAYMENT_SOURCE_CANNOT_BE_USED', PayPalException::PAYMENT_SOURCE_CANNOT_BE_USED], + ['PAYMENT_SOURCE_DECLINED_BY_PROCESSOR', PayPalException::PAYMENT_SOURCE_DECLINED_BY_PROCESSOR], + ['PAYMENT_SOURCE_INFO_CANNOT_BE_VERIFIED', PayPalException::PAYMENT_SOURCE_INFO_CANNOT_BE_VERIFIED], + ['POSTAL_CODE_REQUIRED', PayPalException::POSTAL_CODE_REQUIRED], + ['SHIPPING_ADDRESS_INVALID', PayPalException::SHIPPING_ADDRESS_INVALID], + ['TAX_TOTAL_MISMATCH', PayPalException::TAX_TOTAL_MISMATCH], + ['TAX_TOTAL_REQUIRED', PayPalException::TAX_TOTAL_REQUIRED], + ['UNSUPPORTED_INTENT', PayPalException::UNSUPPORTED_INTENT], + ['UNSUPPORTED_PAYMENT_INSTRUCTION', PayPalException::UNSUPPORTED_PAYMENT_INSTRUCTION], + ['SHIPPING_TYPE_NOT_SUPPORTED_FOR_CLIENT', PayPalException::SHIPPING_TYPE_NOT_SUPPORTED_FOR_CLIENT], + ['UNSUPPORTED_SHIPPING_TYPE', PayPalException::UNSUPPORTED_SHIPPING_TYPE], + ['SHIPPING_OPTION_NOT_SELECTED', PayPalException::SHIPPING_OPTION_NOT_SELECTED], + ['SHIPPING_OPTIONS_NOT_SUPPORTED', PayPalException::SHIPPING_OPTIONS_NOT_SUPPORTED], + ['MULTIPLE_SHIPPING_OPTION_SELECTED', PayPalException::MULTIPLE_SHIPPING_OPTION_SELECTED], + ['PREFERRED_SHIPPING_OPTION_AMOUNT_MISMATCH', PayPalException::PREFERRED_SHIPPING_OPTION_AMOUNT_MISMATCH], + ['CARD_CLOSED', PayPalException::CARD_CLOSED], + ['ORDER_CANNOT_BE_SAVED', PayPalException::ORDER_CANNOT_BE_SAVED], + ['SAVE_ORDER_NOT_SUPPORTED', PayPalException::SAVE_ORDER_NOT_SUPPORTED], + ['PUI_DUPLICATE_ORDER', PayPalException::PUI_DUPLICATE_ORDER], + ['INVALID_JSON_POINTER_FORMAT', PayPalException::INVALID_JSON_POINTER_FORMAT], + ['INVALID_PARAMETER', PayPalException::INVALID_PARAMETER], + ['NOT_PATCHABLE', PayPalException::NOT_PATCHABLE], + ['UNSUPPORTED_PATCH_PARAMETER_VALUE', PayPalException::UNSUPPORTED_PATCH_PARAMETER_VALUE], + ['PATCH_VALUE_REQUIRED', PayPalException::PATCH_VALUE_REQUIRED], + ['PATCH_PATH_REQUIRED', PayPalException::PATCH_PATH_REQUIRED], + ['REFERENCE_ID_NOT_FOUND', PayPalException::REFERENCE_ID_NOT_FOUND], + ['MULTI_CURRENCY_ORDER', PayPalException::MULTI_CURRENCY_ORDER], + ['ORDER_ALREADY_COMPLETED', PayPalException::ORDER_ALREADY_COMPLETED], + ['AGREEMENT_ALREADY_CANCELLED', PayPalException::AGREEMENT_ALREADY_CANCELLED], + ['BILLING_AGREEMENT_NOT_FOUND', PayPalException::BILLING_AGREEMENT_NOT_FOUND], + ['COMPLIANCE_VIOLATION', PayPalException::COMPLIANCE_VIOLATION], + ['DOMESTIC_TRANSACTION_REQUIRED', PayPalException::DOMESTIC_TRANSACTION_REQUIRED], + ['DUPLICATE_INVOICE_ID', PayPalException::DUPLICATE_INVOICE_ID], + ['INSTRUMENT_DECLINED', PayPalException::INSTRUMENT_DECLINED], + ['ORDER_NOT_APPROVED', PayPalException::ORDER_NOT_APPROVED], + ['MAX_NUMBER_OF_PAYMENT_ATTEMPTS_EXCEEDED', PayPalException::MAX_NUMBER_OF_PAYMENT_ATTEMPTS_EXCEEDED], + ['PAYEE_BLOCKED_TRANSACTION', PayPalException::PAYEE_BLOCKED_TRANSACTION], + ['PAYER_ACCOUNT_LOCKED_OR_CLOSED', PayPalException::PAYER_ACCOUNT_LOCKED_OR_CLOSED], + ['PAYER_ACCOUNT_RESTRICTED', PayPalException::PAYER_ACCOUNT_RESTRICTED], + ['PAYER_CANNOT_PAY', PayPalException::PAYER_CANNOT_PAY], + ['TRANSACTION_LIMIT_EXCEEDED', PayPalException::TRANSACTION_LIMIT_EXCEEDED], + ['TRANSACTION_RECEIVING_LIMIT_EXCEEDED', PayPalException::TRANSACTION_RECEIVING_LIMIT_EXCEEDED], + ['TRANSACTION_REFUSED', PayPalException::TRANSACTION_REFUSED], + ['REDIRECT_PAYER_FOR_ALTERNATE_FUNDING', PayPalException::REDIRECT_PAYER_FOR_ALTERNATE_FUNDING], + ['ORDER_ALREADY_CAPTURED', PayPalException::ORDER_ALREADY_CAPTURED], + ['TRANSACTION_BLOCKED_BY_PAYEE', PayPalException::TRANSACTION_BLOCKED_BY_PAYEE], + ['ORDER_ALREADY_CAPTURED', PayPalException::ORDER_ALREADY_CAPTURED], + ['AUTH_CAPTURE_NOT_ENABLED', PayPalException::AUTH_CAPTURE_NOT_ENABLED], + ['NOT_ENABLED_FOR_CARD_PROCESSING', PayPalException::NOT_ENABLED_FOR_CARD_PROCESSING], + ['PAYEE_NOT_ENABLED_FOR_CARD_PROCESSING', PayPalException::PAYEE_NOT_ENABLED_FOR_CARD_PROCESSING], + ['INVALID_PICKUP_ADDRESS', PayPalException::INVALID_PICKUP_ADDRESS], + ['SHIPPING_ADDRESS_INVALID', PayPalException::SHIPPING_ADDRESS_INVALID], + ['CANNOT_PROCESS_REFUNDS', PayPalException::CANNOT_PROCESS_REFUNDS], + ['INVALID_REFUND_AMOUNT', PayPalException::INVALID_REFUND_AMOUNT], + ['PAYMENT_DENIED', PayPalException::PAYMENT_DENIED], + ]; + } +} From 53f93eb01addfb696075d973096b685ecc76194e Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Wed, 28 Feb 2024 18:11:15 +0100 Subject: [PATCH 45/54] Send card supplementary data --- src/Builder/Payload/OrderPayloadBuilder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Builder/Payload/OrderPayloadBuilder.php b/src/Builder/Payload/OrderPayloadBuilder.php index 7d75a802c..61011b1b4 100644 --- a/src/Builder/Payload/OrderPayloadBuilder.php +++ b/src/Builder/Payload/OrderPayloadBuilder.php @@ -109,8 +109,8 @@ public function buildFullPayload() } if ($this->isCard) { - //$this->buildPaymentSourceNode(); - //$this->buildSupplementaryDataNode(); + $this->buildPaymentSourceNode(); + $this->buildSupplementaryDataNode(); } } From 4266855b964cf74c02fc4b9b6a6198ce09b5f55d Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Wed, 28 Feb 2024 19:02:36 +0100 Subject: [PATCH 46/54] Restore http logger --- config/common.yml | 2 + ...CheckoutHttpClientConfigurationBuilder.php | 52 ++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/config/common.yml b/config/common.yml index 891cd9802..7123a9afd 100644 --- a/config/common.yml +++ b/config/common.yml @@ -717,6 +717,8 @@ services: - "@ps_checkout.context.shop" - "@ps_checkout.repository.prestashop.account" - "@ps_checkout.context.prestashop" + - "@ps_checkout.logger.configuration" + - "@ps_checkout.logger" ps_checkout.http.client.factory: class: 'PrestaShop\Module\PrestashopCheckout\Http\HttpClientFactory' diff --git a/src/Http/CheckoutHttpClientConfigurationBuilder.php b/src/Http/CheckoutHttpClientConfigurationBuilder.php index 03f5bb8b9..e5bd032fc 100644 --- a/src/Http/CheckoutHttpClientConfigurationBuilder.php +++ b/src/Http/CheckoutHttpClientConfigurationBuilder.php @@ -20,12 +20,19 @@ namespace PrestaShop\Module\PrestashopCheckout\Http; +use GuzzleHttp\Event\Emitter; +use GuzzleHttp\HandlerStack; +use GuzzleHttp\Subscriber\Log\Formatter; +use GuzzleHttp\Subscriber\Log\LogSubscriber; +use GuzzleLogMiddleware\LogMiddleware; use PrestaShop\Module\PrestashopCheckout\Context\PrestaShopContext; use PrestaShop\Module\PrestashopCheckout\Environment\PaymentEnv; +use PrestaShop\Module\PrestashopCheckout\Logger\LoggerConfiguration; use PrestaShop\Module\PrestashopCheckout\Repository\PsAccountRepository; use PrestaShop\Module\PrestashopCheckout\Routing\Router; use PrestaShop\Module\PrestashopCheckout\ShopContext; use Ps_checkout; +use Psr\Log\LoggerInterface; class CheckoutHttpClientConfigurationBuilder implements HttpClientConfigurationBuilderInterface { @@ -56,18 +63,32 @@ class CheckoutHttpClientConfigurationBuilder implements HttpClientConfigurationB */ private $prestaShopContext; + /** + * @var LoggerConfiguration + */ + private $loggerConfiguration; + + /** + * @var LoggerInterface + */ + private $logger; + public function __construct( PaymentEnv $paymentEnv, Router $router, ShopContext $shopContext, PsAccountRepository $psAccountRepository, - PrestaShopContext $prestaShopContext + PrestaShopContext $prestaShopContext, + LoggerConfiguration $loggerConfiguration, + LoggerInterface $logger ) { $this->paymentEnv = $paymentEnv; $this->router = $router; $this->shopContext = $shopContext; $this->psAccountRepository = $psAccountRepository; $this->prestaShopContext = $prestaShopContext; + $this->loggerConfiguration = $loggerConfiguration; + $this->logger = $logger; } /** @@ -75,7 +96,7 @@ public function __construct( */ public function build() { - return [ + $configuration = [ 'base_url' => $this->paymentEnv->getPaymentApiUrl(), 'verify' => $this->getVerify(), 'timeout' => static::TIMEOUT, @@ -90,6 +111,33 @@ public function build() 'Prestashop-Version' => _PS_VERSION_, // prestashop version ], ]; + + if ( + $this->loggerConfiguration->isHttpEnabled() + && defined('\GuzzleHttp\ClientInterface::MAJOR_VERSION') + && class_exists(HandlerStack::class) + && class_exists(LogMiddleware::class) + ) { + $handlerStack = HandlerStack::create(); + $handlerStack->push(new LogMiddleware($this->logger)); + $configuration['handler'] = $handlerStack; + } elseif ( + $this->loggerConfiguration->isHttpEnabled() + && defined('\GuzzleHttp\ClientInterface::VERSION') + && class_exists(Emitter::class) + && class_exists(LogSubscriber::class) + && class_exists(Formatter::class) + ) { + $emitter = new Emitter(); + $emitter->attach(new LogSubscriber( + $this->logger, + Formatter::DEBUG + )); + + $configuration['emitter'] = $emitter; + } + + return $configuration; } /** From 20733faa1c166489175e80749ab4fda4027a9ba6 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:17:28 +0100 Subject: [PATCH 47/54] Add user-friendly message for popup closed --- _dev/js/front/src/components/common/smart-button.component.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/_dev/js/front/src/components/common/smart-button.component.js b/_dev/js/front/src/components/common/smart-button.component.js index 4456eecaf..695c8a4e9 100644 --- a/_dev/js/front/src/components/common/smart-button.component.js +++ b/_dev/js/front/src/components/common/smart-button.component.js @@ -188,6 +188,9 @@ export class SmartButtonComponent extends BaseComponent { ) { errorMessage = 'Provided country is not supported by the selected payment method.'; + } else if (error.message.includes('Detected popup close')) { + errorMessage = + 'The payment failed because the payment window has been closed before the end of the payment process.'; } } } From e493da036e8b46be48144f4e886743271aaafada Mon Sep 17 00:00:00 2001 From: Laurynas Date: Thu, 29 Feb 2024 16:40:27 +0200 Subject: [PATCH 48/54] Added a fix for order cancel for card-fields and changed refund status event emitting --- .../1_6/express-button-cart.component.js | 18 ++-- .../1_6/express-button-checkout.component.js | 11 +-- .../1_6/express-button-product.component.js | 32 +++---- .../1_6/pay-later-button-cart.component.js | 14 ++- .../pay-later-button-checkout.component.js | 17 ++-- .../1_6/pay-later-button-product.component.js | 36 ++++---- .../1_7/express-button-cart.component.js | 12 +-- .../1_7/express-button-checkout.component.js | 12 +-- .../1_7/express-button-product.component.js | 46 +++++----- .../1_7/pay-later-button-cart.component.js | 14 ++- .../pay-later-button-checkout.component.js | 14 ++- .../1_7/pay-later-button-product.component.js | 50 ++++++----- .../common/card-fields.component.js | 3 + .../express-checkout-button.component.js | 89 +++++++++++++++---- .../common/smart-button.component.js | 6 ++ config/common.yml | 3 +- .../AdminAjaxPrestashopCheckoutController.php | 41 ++++++--- .../UpdateOrderStatusCommandHandler.php | 4 +- .../RefundPayPalCaptureCommandHandler.php | 25 +----- .../PayPalRefundEventSubscriber.php | 22 +---- 20 files changed, 238 insertions(+), 231 deletions(-) diff --git a/_dev/js/front/src/components/1_6/express-button-cart.component.js b/_dev/js/front/src/components/1_6/express-button-cart.component.js index 98d627e00..f555e8459 100644 --- a/_dev/js/front/src/components/1_6/express-button-cart.component.js +++ b/_dev/js/front/src/components/1_6/express-button-cart.component.js @@ -28,7 +28,8 @@ export class ExpressButtonCartComponent extends BaseComponent { }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerCart(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerCart(); } renderComponent() { @@ -50,14 +51,7 @@ export class ExpressButtonCartComponent extends BaseComponent { this.app, { fundingSource: 'paypal', - // TODO: Move this to constant when ExpressCheckoutButton component is created - querySelector: '#ps_checkout-express-button-cart', - createOrder: (data) => - this.psCheckoutApi.postCreateOrder({ - ...data, - fundingSource: 'paypal', - isExpressCheckout: true - }) + querySelector: '#ps_checkout-express-button-cart' } ).render(); } @@ -67,9 +61,9 @@ export class ExpressButtonCartComponent extends BaseComponent { this.renderComponent(); this.prestashopService.onUpdatedShoppingCartExtra(() => { - if (null === document.querySelector('#ps_checkout-express-button-cart')) { - this.renderComponent(); - } + if (null === document.querySelector('#ps_checkout-express-button-cart')) { + this.renderComponent(); + } }); return this; diff --git a/_dev/js/front/src/components/1_6/express-button-checkout.component.js b/_dev/js/front/src/components/1_6/express-button-checkout.component.js index 4ef5a6c74..6296b816b 100644 --- a/_dev/js/front/src/components/1_6/express-button-checkout.component.js +++ b/_dev/js/front/src/components/1_6/express-button-checkout.component.js @@ -28,7 +28,8 @@ export class ExpressButtonCheckoutComponent extends BaseComponent { }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerCheckout(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerCheckout(); } renderTitle() { @@ -53,13 +54,7 @@ export class ExpressButtonCheckoutComponent extends BaseComponent { this.app, { fundingSource: 'paypal', - querySelector: '#ps_checkout-express-button-checkout', - createOrder: (data) => - this.psCheckoutApi.postCreateOrder({ - ...data, - fundingSource: 'paypal', - isExpressCheckout: true - }) + querySelector: '#ps_checkout-express-button-checkout' } ).render(); diff --git a/_dev/js/front/src/components/1_6/express-button-product.component.js b/_dev/js/front/src/components/1_6/express-button-product.component.js index 5a3a09d42..7d7c164a0 100644 --- a/_dev/js/front/src/components/1_6/express-button-product.component.js +++ b/_dev/js/front/src/components/1_6/express-button-product.component.js @@ -27,7 +27,8 @@ export class ExpressButtonProductComponent extends BaseComponent { }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerProduct(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerProduct(); } render() { @@ -42,28 +43,23 @@ export class ExpressButtonProductComponent extends BaseComponent { buttonContainer.append(this.checkoutExpressButton); + const { + id_product, + id_product_attribute, + id_customization, + quantity_wanted + } = this.prestashopService.getProductDetails(); + this.children.expressCheckoutButton = new ExpressCheckoutButtonComponent( this.app, { fundingSource: 'paypal', - // TODO: Move this to constant when ExpressCheckoutButton component is created querySelector: '#ps-checkout-express-button', - createOrder: () => { - const { - id_product, - id_product_attribute, - id_customization, - quantity_wanted - } = this.prestashopService.getProductDetails(); - - return this.psCheckoutApi.postCreateOrder({ - id_product, - id_product_attribute, - id_customization, - quantity_wanted, - fundingSource: 'paypal', - isExpressCheckout: true - }); + data: { + id_product, + id_product_attribute, + id_customization, + quantity_wanted } } ).render(); diff --git a/_dev/js/front/src/components/1_6/pay-later-button-cart.component.js b/_dev/js/front/src/components/1_6/pay-later-button-cart.component.js index 8929c8f6c..bf3c724a5 100644 --- a/_dev/js/front/src/components/1_6/pay-later-button-cart.component.js +++ b/_dev/js/front/src/components/1_6/pay-later-button-cart.component.js @@ -24,11 +24,14 @@ export class PayLaterButtonCartComponent extends BaseComponent { querySelectorService: 'QuerySelectorService', prestashopService: 'PrestashopService', psCheckoutApi: 'PsCheckoutApi', + payPalService: 'PayPalService', $: '$' }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerCart(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerCart(); + this.data.orderId = this.payPalService.getOrderId(); } renderComponent() { @@ -52,14 +55,7 @@ export class PayLaterButtonCartComponent extends BaseComponent { this.app, { fundingSource: 'paylater', - // TODO: Move this to constant when ExpressCheckoutButton component is created - querySelector: '#ps_checkout-express-button-cart', - createOrder: (data) => - this.psCheckoutApi.postCreateOrder({ - ...data, - fundingSource: 'paylater', - isExpressCheckout: true - }) + querySelector: '#ps_checkout-express-button-cart' } ).render(); } diff --git a/_dev/js/front/src/components/1_6/pay-later-button-checkout.component.js b/_dev/js/front/src/components/1_6/pay-later-button-checkout.component.js index bbe9989aa..0989d7a73 100644 --- a/_dev/js/front/src/components/1_6/pay-later-button-checkout.component.js +++ b/_dev/js/front/src/components/1_6/pay-later-button-checkout.component.js @@ -24,11 +24,14 @@ export class PayLaterButtonCheckoutComponent extends BaseComponent { querySelectorService: 'QuerySelectorService', prestashopService: 'PrestashopService', psCheckoutApi: 'PsCheckoutApi', + payPalService: 'PayPalService', $: '$' }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerCheckout(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerCheckout(); + this.data.orderId = this.payPalService.getOrderId(); } renderTitle() { @@ -55,19 +58,13 @@ export class PayLaterButtonCheckoutComponent extends BaseComponent { this.app, { fundingSource: 'paylater', - querySelector: '#ps_checkout-express-button-checkout', - createOrder: (data) => - this.psCheckoutApi.postCreateOrder({ - ...data, - fundingSource: 'paylater', - isExpressCheckout: true - }) + querySelector: '#ps_checkout-express-button-checkout' } ).render(); if ( - this.prestashopService.isNativeOnePageCheckoutPage() - && !document.getElementById('ps_checkout-express-button-checkout') + this.prestashopService.isNativeOnePageCheckoutPage() && + !document.getElementById('ps_checkout-express-button-checkout') ) { const separatorText = document.createElement('div'); separatorText.classList.add('ps_checkout-express-separator'); diff --git a/_dev/js/front/src/components/1_6/pay-later-button-product.component.js b/_dev/js/front/src/components/1_6/pay-later-button-product.component.js index f7c5ceb5c..eb07a9093 100644 --- a/_dev/js/front/src/components/1_6/pay-later-button-product.component.js +++ b/_dev/js/front/src/components/1_6/pay-later-button-product.component.js @@ -23,11 +23,14 @@ export class PayLaterButtonProductComponent extends BaseComponent { static Inject = { querySelectorService: 'QuerySelectorService', psCheckoutApi: 'PsCheckoutApi', - prestashopService: 'PrestashopService' + prestashopService: 'PrestashopService', + payPalService: 'PayPalService' }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerProduct(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerProduct(); + this.data.orderId = this.payPalService.getOrderId(); } render() { @@ -44,28 +47,23 @@ export class PayLaterButtonProductComponent extends BaseComponent { buttonContainer.append(this.checkoutExpressButton); } + const { + id_product, + id_product_attribute, + id_customization, + quantity_wanted + } = this.prestashopService.getProductDetails(); + this.children.expressCheckoutButton = new ExpressCheckoutButtonComponent( this.app, { fundingSource: 'paylater', - // TODO: Move this to constant when ExpressCheckoutButton component is created querySelector: '#ps-checkout-express-button', - createOrder: () => { - const { - id_product, - id_product_attribute, - id_customization, - quantity_wanted - } = this.prestashopService.getProductDetails(); - - return this.psCheckoutApi.postCreateOrder({ - id_product, - id_product_attribute, - id_customization, - quantity_wanted, - fundingSource: 'paylater', - isExpressCheckout: true - }); + data: { + id_product, + id_product_attribute, + id_customization, + quantity_wanted } } ).render(); diff --git a/_dev/js/front/src/components/1_7/express-button-cart.component.js b/_dev/js/front/src/components/1_7/express-button-cart.component.js index 96e14af6f..66dafe5d2 100644 --- a/_dev/js/front/src/components/1_7/express-button-cart.component.js +++ b/_dev/js/front/src/components/1_7/express-button-cart.component.js @@ -27,7 +27,8 @@ export class ExpressButtonCartComponent extends BaseComponent { }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerCart(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerCart(); } render() { @@ -47,14 +48,7 @@ export class ExpressButtonCartComponent extends BaseComponent { this.app, { fundingSource: 'paypal', - // TODO: Move this to constant when ExpressCheckoutButton component is created - querySelector: '#ps-checkout-express-button', - createOrder: (data) => - this.psCheckoutApi.postCreateOrder({ - ...data, - fundingSource: 'paypal', - isExpressCheckout: true - }) + querySelector: '#ps-checkout-express-button' } ).render(); return this; diff --git a/_dev/js/front/src/components/1_7/express-button-checkout.component.js b/_dev/js/front/src/components/1_7/express-button-checkout.component.js index ab9ccc1cf..12ebd9384 100644 --- a/_dev/js/front/src/components/1_7/express-button-checkout.component.js +++ b/_dev/js/front/src/components/1_7/express-button-checkout.component.js @@ -27,7 +27,8 @@ export class ExpressButtonCheckoutComponent extends BaseComponent { }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerCheckout(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerCheckout(); } renderTitle() { @@ -60,14 +61,7 @@ export class ExpressButtonCheckoutComponent extends BaseComponent { this.app, { fundingSource: 'paypal', - // TODO: Move this to constant when ExpressCheckoutButton component is created - querySelector: '#ps-checkout-express-button', - createOrder: (data) => - this.psCheckoutApi.postCreateOrder({ - ...data, - fundingSource: 'paypal', - isExpressCheckout: true - }) + querySelector: '#ps-checkout-express-button' } ).render(); return this; diff --git a/_dev/js/front/src/components/1_7/express-button-product.component.js b/_dev/js/front/src/components/1_7/express-button-product.component.js index 9fedc1eb1..aba07b87a 100644 --- a/_dev/js/front/src/components/1_7/express-button-product.component.js +++ b/_dev/js/front/src/components/1_7/express-button-product.component.js @@ -29,14 +29,16 @@ export class ExpressButtonProductComponent extends BaseComponent { }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerProduct(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerProduct(); } render() { this.checkoutExpressButton = document.createElement('div'); this.checkoutExpressButton.id = BUTTON_CONTAINER_SELECTOR; - const productQuantityHTMLElement = this.buttonReferenceContainer.nextElementSibling; + const productQuantityHTMLElement = + this.buttonReferenceContainer.nextElementSibling; this.buttonReferenceContainer.parentNode.insertBefore( this.checkoutExpressButton, @@ -49,28 +51,23 @@ export class ExpressButtonProductComponent extends BaseComponent { this.updateButtonContainerVisibility(); }); + const { + id_product, + id_product_attribute, + id_customization, + quantity_wanted + } = this.prestashopService.getProductDetails(); + this.children.expressCheckoutButton = new ExpressCheckoutButtonComponent( this.app, { fundingSource: 'paypal', - // TODO: Move this to constant when ExpressCheckoutButton component is created querySelector: `#${BUTTON_CONTAINER_SELECTOR}`, - createOrder: () => { - const { - id_product, - id_product_attribute, - id_customization, - quantity_wanted - } = this.prestashopService.getProductDetails(); - - return this.psCheckoutApi.postCreateOrder({ - id_product, - id_product_attribute, - id_customization, - quantity_wanted, - fundingSource: 'paypal', - isExpressCheckout: true - }); + data: { + id_product, + id_product_attribute, + id_customization, + quantity_wanted } } ).render(); @@ -78,12 +75,15 @@ export class ExpressButtonProductComponent extends BaseComponent { return this; } - updateButtonContainerVisibility() - { + updateButtonContainerVisibility() { if (this.prestashopService.isAddToCartButtonDisabled()) { - document.getElementById(BUTTON_CONTAINER_SELECTOR).classList.add('disabled'); + document + .getElementById(BUTTON_CONTAINER_SELECTOR) + .classList.add('disabled'); } else { - document.getElementById(BUTTON_CONTAINER_SELECTOR).classList.remove('disabled'); + document + .getElementById(BUTTON_CONTAINER_SELECTOR) + .classList.remove('disabled'); } } } diff --git a/_dev/js/front/src/components/1_7/pay-later-button-cart.component.js b/_dev/js/front/src/components/1_7/pay-later-button-cart.component.js index 0a468f2fc..b9ee83180 100644 --- a/_dev/js/front/src/components/1_7/pay-later-button-cart.component.js +++ b/_dev/js/front/src/components/1_7/pay-later-button-cart.component.js @@ -23,11 +23,14 @@ export class PayLaterButtonCartComponent extends BaseComponent { static Inject = { querySelectorService: 'QuerySelectorService', psCheckoutApi: 'PsCheckoutApi', + payPalService: 'PayPalService', $: '$' }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerCart(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerCart(); + this.data.orderId = this.payPalService.getOrderId(); } render() { @@ -49,14 +52,7 @@ export class PayLaterButtonCartComponent extends BaseComponent { this.app, { fundingSource: 'paylater', - // TODO: Move this to constant when ExpressCheckoutButton component is created - querySelector: '#ps-checkout-express-button', - createOrder: (data) => - this.psCheckoutApi.postCreateOrder({ - ...data, - fundingSource: 'paylater', - isExpressCheckout: true - }) + querySelector: '#ps-checkout-express-button' } ).render(); return this; diff --git a/_dev/js/front/src/components/1_7/pay-later-button-checkout.component.js b/_dev/js/front/src/components/1_7/pay-later-button-checkout.component.js index a6b7dab25..aaa245d3c 100644 --- a/_dev/js/front/src/components/1_7/pay-later-button-checkout.component.js +++ b/_dev/js/front/src/components/1_7/pay-later-button-checkout.component.js @@ -23,11 +23,14 @@ export class PayLaterButtonCheckoutComponent extends BaseComponent { static Inject = { querySelectorService: 'QuerySelectorService', psCheckoutApi: 'PsCheckoutApi', + payPalService: 'PayPalService', $: '$' }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerCheckout(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerCheckout(); + this.data.orderId = this.payPalService.getOrderId(); } renderTitle() { @@ -62,14 +65,7 @@ export class PayLaterButtonCheckoutComponent extends BaseComponent { this.app, { fundingSource: 'paylater', - // TODO: Move this to constant when ExpressCheckoutButton component is created - querySelector: '#ps-checkout-express-button', - createOrder: (data) => - this.psCheckoutApi.postCreateOrder({ - ...data, - fundingSource: 'paylater', - isExpressCheckout: true - }) + querySelector: '#ps-checkout-express-button' } ).render(); return this; diff --git a/_dev/js/front/src/components/1_7/pay-later-button-product.component.js b/_dev/js/front/src/components/1_7/pay-later-button-product.component.js index 2605b7431..49b3956e1 100644 --- a/_dev/js/front/src/components/1_7/pay-later-button-product.component.js +++ b/_dev/js/front/src/components/1_7/pay-later-button-product.component.js @@ -25,11 +25,14 @@ export class PayLaterButtonProductComponent extends BaseComponent { static Inject = { querySelectorService: 'QuerySelectorService', psCheckoutApi: 'PsCheckoutApi', - prestashopService: 'PrestashopService' + prestashopService: 'PrestashopService', + payPalService: 'PayPalService' }; created() { - this.buttonReferenceContainer = this.querySelectorService.getExpressCheckoutButtonContainerProduct(); + this.buttonReferenceContainer = + this.querySelectorService.getExpressCheckoutButtonContainerProduct(); + this.data.orderId = this.payPalService.getOrderId(); } render() { @@ -37,7 +40,8 @@ export class PayLaterButtonProductComponent extends BaseComponent { this.checkoutExpressButton = document.createElement('div'); this.checkoutExpressButton.id = BUTTON_CONTAINER_SELECTOR; - const productQuantityHTMLElement = this.buttonReferenceContainer.nextElementSibling; + const productQuantityHTMLElement = + this.buttonReferenceContainer.nextElementSibling; this.buttonReferenceContainer.parentNode.insertBefore( this.checkoutExpressButton, @@ -51,28 +55,23 @@ export class PayLaterButtonProductComponent extends BaseComponent { this.updateButtonContainerVisibility(); }); + const { + id_product, + id_product_attribute, + id_customization, + quantity_wanted + } = this.prestashopService.getProductDetails(); + this.children.expressCheckoutButton = new ExpressCheckoutButtonComponent( this.app, { fundingSource: 'paylater', - // TODO: Move this to constant when ExpressCheckoutButton component is created querySelector: `#${BUTTON_CONTAINER_SELECTOR}`, - createOrder: () => { - const { - id_product, - id_product_attribute, - id_customization, - quantity_wanted - } = this.prestashopService.getProductDetails(); - - return this.psCheckoutApi.postCreateOrder({ - id_product, - id_product_attribute, - id_customization, - quantity_wanted, - fundingSource: 'paylater', - isExpressCheckout: true - }); + data: { + id_product, + id_product_attribute, + id_customization, + quantity_wanted } } ).render(); @@ -80,12 +79,15 @@ export class PayLaterButtonProductComponent extends BaseComponent { return this; } - updateButtonContainerVisibility() - { + updateButtonContainerVisibility() { if (this.prestashopService.isAddToCartButtonDisabled()) { - document.getElementById(BUTTON_CONTAINER_SELECTOR).classList.add('disabled'); + document + .getElementById(BUTTON_CONTAINER_SELECTOR) + .classList.add('disabled'); } else { - document.getElementById(BUTTON_CONTAINER_SELECTOR).classList.remove('disabled'); + document + .getElementById(BUTTON_CONTAINER_SELECTOR) + .classList.remove('disabled'); } } } diff --git a/_dev/js/front/src/components/common/card-fields.component.js b/_dev/js/front/src/components/common/card-fields.component.js index 286638e69..07cbbdf03 100644 --- a/_dev/js/front/src/components/common/card-fields.component.js +++ b/_dev/js/front/src/components/common/card-fields.component.js @@ -56,6 +56,7 @@ export class CardFieldsComponent extends BaseComponent { created() { this.data.name = this.props.fundingSource.name; this.data.validity = false; + this.data.orderId = null; /** * @property {PaypalCardFieldsEvent} data.cardFieldsState */ @@ -228,6 +229,7 @@ export class CardFieldsComponent extends BaseComponent { // vault: storeCardInVault }) .then((data) => { + this.data.orderId = data; return data; }) .catch((error) => { @@ -263,6 +265,7 @@ export class CardFieldsComponent extends BaseComponent { return this.psCheckoutApi .postCancelOrder({ + orderID: this.data.orderId, fundingSource: this.data.name, isExpressCheckout: this.config.expressCheckout.active, reason: 'card_fields_error', diff --git a/_dev/js/front/src/components/common/express-checkout-button.component.js b/_dev/js/front/src/components/common/express-checkout-button.component.js index 583a3fbc6..4cd49629a 100644 --- a/_dev/js/front/src/components/common/express-checkout-button.component.js +++ b/_dev/js/front/src/components/common/express-checkout-button.component.js @@ -25,37 +25,43 @@ export class ExpressCheckoutButtonComponent extends BaseComponent { $: '$' }; + created() { + this.data.orderId = this.payPalService.getOrderId(); + } + onInit(data, actions) { return actions.enable(); } onClick(data, actions) { - return ( - this.psCheckoutApi - .postCheckCartOrder( - { - ...data, - fundingSource: this.props.fundingSource, - isExpressCheckout: true, - orderID: this.payPalService.getOrderId() - }, - actions - ) - // TODO: Error notification - .catch(() => actions.reject()) - ); - // TODO: [PAYSHIP-605] Error handling + return this.psCheckoutApi + .postCheckCartOrder( + { + ...data, + fundingSource: this.props.fundingSource, + isExpressCheckout: true, + orderID: this.data.orderId + }, + actions + ) + .catch((error) => { + actions.reject(); + throw error; + }); } onError(error) { + const errorText = error?.message ? error.message : error; + this.notifyError(errorText); console.error(error); return this.psCheckoutApi .postCancelOrder({ + orderID: this.data.orderId, fundingSource: this.props.fundingSource, isExpressCheckout: true, reason: 'express_checkout_error', - error: error instanceof Error ? error.message : error + error: errorText }) .catch((error) => console.error(error)); } @@ -74,6 +80,7 @@ export class ExpressCheckoutButtonComponent extends BaseComponent { onCancel(data) { return this.psCheckoutApi.postCancelOrder({ ...data, + orderID: this.data.orderId, fundingSource: this.props.fundingSource, isExpressCheckout: true, reason: 'express_checkout_cancelled' @@ -81,9 +88,55 @@ export class ExpressCheckoutButtonComponent extends BaseComponent { } createOrder(data) { - if (this.props.createOrder) { - return this.props.createOrder(data); + const extraData = this.props?.data ? this.props.data : {}; + + return this.psCheckoutApi + .postCreateOrder({ + ...data, + ...extraData + }) + .then((data) => { + this.data.orderId = data; + return data; + }) + .catch((error) => { + throw error; + }); + } + + notifyError(message) { + const expressCheckoutContainer = document.querySelector( + this.props.querySelector + ); + const notificationContainerIdentifier = + 'ps_checkout-product-notification-container'; + let notificationContainerElement = document.getElementById( + notificationContainerIdentifier + ); + + if (!notificationContainerElement) { + notificationContainerElement = document.createElement('div'); + notificationContainerElement.id = notificationContainerIdentifier; + expressCheckoutContainer.prepend(notificationContainerElement); + } + + const notificationIdentifier = 'ps_checkout-product-notification-container'; + const currentNotificationElement = document.querySelector( + '#' + notificationContainerIdentifier + ' .' + notificationIdentifier + ); + + if (currentNotificationElement) { + return (currentNotificationElement.textContent = message); } + + const notificationElement = document.createElement('div'); + notificationElement.classList.add( + 'alert', + 'alert-danger', + notificationIdentifier + ); + notificationElement.textContent = message; + notificationContainerElement.appendChild(notificationElement); } renderPayPalButton() { diff --git a/_dev/js/front/src/components/common/smart-button.component.js b/_dev/js/front/src/components/common/smart-button.component.js index 695c8a4e9..146ea21de 100644 --- a/_dev/js/front/src/components/common/smart-button.component.js +++ b/_dev/js/front/src/components/common/smart-button.component.js @@ -37,6 +37,7 @@ export class SmartButtonComponent extends BaseComponent { created() { this.data.name = this.props.fundingSource.name; + this.data.orderId = null; this.data.HTMLElement = this.props.HTMLElement; @@ -114,6 +115,7 @@ export class SmartButtonComponent extends BaseComponent { return this.psCheckoutApi .postCancelOrder({ + orderID: this.data.orderId, fundingSource: this.data.name, isExpressCheckout: this.config.expressCheckout.active, reason: 'checkout_error', @@ -160,6 +162,10 @@ export class SmartButtonComponent extends BaseComponent { fundingSource: this.data.name, isExpressCheckout: this.config.expressCheckout.active }) + .then((data) => { + this.data.orderId = data; + return data; + }) .catch((error) => { this.data.loader.hide(); this.data.notification.showError( diff --git a/config/common.yml b/config/common.yml index 7123a9afd..f94a67ac5 100644 --- a/config/common.yml +++ b/config/common.yml @@ -685,14 +685,13 @@ services: PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\CommandHandler\RefundPayPalCaptureCommandHandler: class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\CommandHandler\RefundPayPalCaptureCommandHandler' + public: true arguments: - '@ps_checkout.http.client.checkout' - '@ps_checkout.paypal.configuration' - '@ps_checkout.configuration' - '@ps_checkout.context.prestashop' - '@ps_checkout.event.dispatcher' - - '@ps_checkout.cache.paypal.order' - - '@ps_checkout.paypal.provider.order' ps_checkout.paypal.capture.service.check_transition_paypal_capture_status: class: 'PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Capture\CheckTransitionPayPalCaptureStatusService' diff --git a/controllers/admin/AdminAjaxPrestashopCheckoutController.php b/controllers/admin/AdminAjaxPrestashopCheckoutController.php index c6630e0b2..79c0a487a 100755 --- a/controllers/admin/AdminAjaxPrestashopCheckoutController.php +++ b/controllers/admin/AdminAjaxPrestashopCheckoutController.php @@ -30,6 +30,7 @@ use PrestaShop\Module\PrestashopCheckout\Logger\LoggerFileReader; use PrestaShop\Module\PrestashopCheckout\OnBoarding\Step\LiveStep; use PrestaShop\Module\PrestashopCheckout\OnBoarding\Step\ValueBanner; +use PrestaShop\Module\PrestashopCheckout\Order\Exception\OrderException; use PrestaShop\Module\PrestashopCheckout\Order\State\Exception\OrderStateException; use PrestaShop\Module\PrestashopCheckout\Order\State\OrderStateInstaller; use PrestaShop\Module\PrestashopCheckout\Order\State\Service\OrderStateMapper; @@ -451,21 +452,15 @@ public function ajaxProcessRefundOrder() try { $commandBus->handle(new RefundPayPalCaptureCommand($orderPayPalId, $captureId, $currency, $amount)); - - $this->ajaxDie(json_encode([ - 'status' => true, - 'content' => $this->l('Refund has been processed by PayPal.', 'translations'), - ])); } catch (PayPalRefundFailedException $exception) { - http_response_code($exception->getCode()); - $this->ajaxDie(json_encode([ + $this->exitWithResponse([ + 'httpCode' => $exception->getCode(), 'status' => false, 'errors' => [ $this->l('Refund cannot be processed by PayPal.', 'translations'), ], - ])); + ]); } catch (PayPalRefundException $invalidArgumentException) { - http_response_code(400); $error = ''; switch ($invalidArgumentException->getCode()) { case PayPalRefundException::INVALID_ORDER_ID: @@ -483,10 +478,28 @@ public function ajaxProcessRefundOrder() default: break; } - $this->ajaxDie(json_encode([ + $this->exitWithResponse([ + 'httpCode' => 400, 'status' => false, 'errors' => [$error], - ])); + ]); + } catch (OrderException $exception) { + if ($exception->getCode() === OrderException::FAILED_UPDATE_ORDER_STATUS) { + $this->exitWithResponse([ + 'httpCode' => 200, + 'status' => true, + 'content' => $this->l('Refund has been processed by PayPal, but order status change or email sending failed.', 'translations'), + ]); + } elseif ($exception->getCode() !== OrderException::ORDER_HAS_ALREADY_THIS_STATUS) { + $this->exitWithResponse([ + 'httpCode' => 500, + 'status' => false, + 'errors' => [ + $exception->getMessage(), + ], + 'error' => $exception->getMessage(), + ]); + } } catch (Exception $exception) { $this->exitWithResponse([ 'httpCode' => 500, @@ -497,6 +510,12 @@ public function ajaxProcessRefundOrder() 'error' => $exception->getMessage(), ]); } + + $this->exitWithResponse([ + 'httpCode' => 200, + 'status' => true, + 'content' => $this->l('Refund has been processed by PayPal.', 'translations'), + ]); } /** diff --git a/src/Order/CommandHandler/UpdateOrderStatusCommandHandler.php b/src/Order/CommandHandler/UpdateOrderStatusCommandHandler.php index 741d9b6bd..199d1735a 100644 --- a/src/Order/CommandHandler/UpdateOrderStatusCommandHandler.php +++ b/src/Order/CommandHandler/UpdateOrderStatusCommandHandler.php @@ -73,11 +73,11 @@ public function handle(UpdateOrderStatusCommand $command) // Save all changes $historyAdded = $history->addWithemail(true); } catch (Exception $exception) { - throw new OrderException(sprintf('Failed to update status or sent email when changing OrderState #%d of Order #%d.', $command->getNewOrderStatusId()->getValue(), $command->getOrderId()->getValue()), OrderException::FAILED_UPDATE_ORDER_STATUS, $exception); + throw new OrderException(sprintf('Failed to update status or send email when changing OrderState #%d of Order #%d.', $command->getNewOrderStatusId()->getValue(), $command->getOrderId()->getValue()), OrderException::FAILED_UPDATE_ORDER_STATUS, $exception); } if (!$historyAdded) { - throw new OrderException(sprintf('Failed to update status or sent email when changing OrderState #%d of Order #%d.', $command->getNewOrderStatusId()->getValue(), $command->getOrderId()->getValue()), OrderException::FAILED_UPDATE_ORDER_STATUS); + throw new OrderException(sprintf('Failed to update status or send email when changing OrderState #%d of Order #%d.', $command->getNewOrderStatusId()->getValue(), $command->getOrderId()->getValue()), OrderException::FAILED_UPDATE_ORDER_STATUS); } $this->eventDispatcher->dispatch(new OrderStatusUpdatedEvent($orderStateId)); diff --git a/src/PayPal/Payment/Refund/CommandHandler/RefundPayPalCaptureCommandHandler.php b/src/PayPal/Payment/Refund/CommandHandler/RefundPayPalCaptureCommandHandler.php index 291984583..82a7c9ee6 100644 --- a/src/PayPal/Payment/Refund/CommandHandler/RefundPayPalCaptureCommandHandler.php +++ b/src/PayPal/Payment/Refund/CommandHandler/RefundPayPalCaptureCommandHandler.php @@ -24,14 +24,12 @@ use PrestaShop\Module\PrestashopCheckout\Context\PrestaShopContext; use PrestaShop\Module\PrestashopCheckout\Event\EventDispatcherInterface; use PrestaShop\Module\PrestashopCheckout\Exception\PayPalException; -use PrestaShop\Module\PrestashopCheckout\Handler\Response\ResponseApiHandler; use PrestaShop\Module\PrestashopCheckout\Http\CheckoutHttpClient; use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Command\RefundPayPalCaptureCommand; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Event\PayPalCaptureRefundedEvent; use PrestaShop\Module\PrestashopCheckout\PayPal\Payment\Refund\Exception\PayPalRefundFailedException; use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration; -use Psr\SimpleCache\CacheInterface; class RefundPayPalCaptureCommandHandler { @@ -55,25 +53,19 @@ class RefundPayPalCaptureCommandHandler * @var EventDispatcherInterface */ private $eventDispatcher; - /** - * @var CacheInterface - */ - private $orderPayPalCache; public function __construct( CheckoutHttpClient $checkoutHttpClient, PayPalConfiguration $payPalConfiguration, PrestaShopConfiguration $prestaShopConfiguration, PrestaShopContext $prestaShopContext, - EventDispatcherInterface $eventDispatcher, - CacheInterface $orderPayPalCache + EventDispatcherInterface $eventDispatcher ) { $this->checkoutHttpClient = $checkoutHttpClient; $this->payPalConfiguration = $payPalConfiguration; $this->prestaShopConfiguration = $prestaShopConfiguration; $this->prestaShopContext = $prestaShopContext; $this->eventDispatcher = $eventDispatcher; - $this->orderPayPalCache = $orderPayPalCache; } /** @@ -101,22 +93,13 @@ public function handle(RefundPayPalCaptureCommand $command) ['id_shop' => $this->prestaShopContext->getShopId()] ), ]); - $responseHandler = new ResponseApiHandler(); - $response = $responseHandler->handleResponse($response); - - if (isset($response['httpCode']) && $response['httpCode'] === 200) { - if ($this->orderPayPalCache->has($command->getOrderPayPalId())) { - $this->orderPayPalCache->delete($command->getOrderPayPalId()); - } - } else { - throw new PayPalRefundFailedException('', isset($response['httpCode']) ? $response['httpCode'] : 500); - } + $refund = json_decode($response->getBody()->getContents(), true); $this->eventDispatcher->dispatch( new PayPalCaptureRefundedEvent( - $response['body']['id'], + $refund['id'], $command->getOrderPayPalId(), - $response['body'] + $refund ) ); } diff --git a/src/PayPal/Payment/Refund/EventSubscriber/PayPalRefundEventSubscriber.php b/src/PayPal/Payment/Refund/EventSubscriber/PayPalRefundEventSubscriber.php index 2c9fdeeec..19699c7d7 100644 --- a/src/PayPal/Payment/Refund/EventSubscriber/PayPalRefundEventSubscriber.php +++ b/src/PayPal/Payment/Refund/EventSubscriber/PayPalRefundEventSubscriber.php @@ -110,6 +110,10 @@ public function setPaymentRefundedOrderStatus(PayPalCaptureRefundedEvent $event) return; } + if ($this->orderPayPalCache->has($event->getPayPalOrderId()->getValue())) { + $this->orderPayPalCache->delete($event->getPayPalOrderId()->getValue()); + } + if (!$order->hasBeenPaid() || $order->hasBeenTotallyRefund()) { return; } @@ -139,23 +143,5 @@ public function updateCache(PayPalRefundEvent $event) if ($this->orderPayPalCache->has($event->getPayPalOrderId()->getValue())) { $this->orderPayPalCache->delete($event->getPayPalOrderId()->getValue()); } -// $this->capturePayPalCache->set($event->getPayPalCaptureId()->getValue(), $event->getCapture()); -// -// $needToClearOrderPayPalCache = true; -// $orderPayPalCache = $this->orderPayPalCache->get($event->getPayPalOrderId()->getValue()); -// -// if ($orderPayPalCache && isset($orderPayPalCache['purchase_units'][0]['payments']['captures'])) { -// foreach ($orderPayPalCache['purchase_units'][0]['payments']['captures'] as $key => $capture) { -// if ($capture['id'] === $event->getPayPalCaptureId()->getValue()) { -// $needToClearOrderPayPalCache = false; -// $orderPayPalCache['purchase_units'][0]['payments']['captures'][$key] = $event->getCapture(); -// $this->orderPayPalCache->set($event->getPayPalOrderId()->getValue(), $orderPayPalCache); -// } -// } -// } -// -// if ($needToClearOrderPayPalCache) { -// $this->orderPayPalCache->delete($event->getPayPalOrderId()->getValue()); -// } } } From 04f1d10da1b103e0f3c49e752ffb396d748a9cbf Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Fri, 1 Mar 2024 14:37:08 +0100 Subject: [PATCH 49/54] Update readme.md --- README.md | 49 ++++++++++++------------------------------------- 1 file changed, 12 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 0aa0823cb..5ed7e4b7d 100755 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ -

PrestaShop Checkout

- # PrestaShop Checkout ![PHP tests](https://github.com/PrestaShopCorp/ps_checkout/workflows/PHP%20tests/badge.svg) -![NodeJS tests](https://github.com/PrestaShopCorp/ps_checkout/workflows/NodeJS%20tests/badge.svg) ![JS tests](https://github.com/PrestaShopCorp/ps_checkout/workflows/JS%20tests/badge.svg) ![Build & Release draft](https://github.com/PrestaShopCorp/ps_checkout/workflows/Build%20&%20Release%20draft/badge.svg) ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/prestashopcorp/ps_checkout) @@ -15,48 +12,27 @@ PrestaShop official payment module in partnership with PayPal. ## Reporting issues -In order to contact the team, please use the link available in the +In order to contact the team, please use the [link][contact-us] available in the back-office once logged to your PrestaShop account. -## Building the module - -### Direct download +## Direct download If you want to get a zip ready to install on your shop. You can directly download it by clicking [here][direct-download]. -### Production - -1. Clone this repo `git clone git@github.com:PrestaShop/ps_checkout.git` -2. `make build-prod-zip` - -The zip will be generated in the root directory of the module. - -### Development - -1. Clone this repo -2. `make docker-build` -3. `make watch-front` - -I also recommend you to install the [vuejs-devtools][vuejs-devtools]. - -#### Switch on sanbox (Advanced) - -PayPal offers a sandbox mode in which an order can be created without -involving actual money. - -To enable it, reach the module configuration page, then replace `#...` at the end of the URL with `#/experimental`. - -This route allow you to acces to some experimental features (like paypal sandbox). Don't use them in a production environment until these features are officially released. - ## Contributing PrestaShop modules are open source extensions to the PrestaShop e-commerce solution. Everyone is welcome and even encouraged to contribute with their own improvements. ### Requirements +There 3 main branches on the repository: +- `prestashop/8.x` is the branch for PrestaShop v8.x +- `prestashop/1.7.x` is the branch for PrestaShop v1.7.x +- `prestashop/1.6.1.x` is the branch for PrestaShop v1.6.1.x + Contributors **must** follow the following rules: -* **Make your Pull Request on the "dev" branch**, NOT the "master" branch. +* Use the main branch `prestashop/8.x` * Do not update the module's version number. * Follow [the coding standards][1]. @@ -66,11 +42,11 @@ Contributors wishing to edit a module's files should follow the following proces 1. Create your GitHub account, if you do not have one already. 2. Fork this project to your GitHub account. -3. Clone your fork to your local machine in the ```/modules``` directory of your PrestaShop installation. +3. Clone your fork to your local machine in the `/modules` directory of your PrestaShop installation. 4. Create a branch in your local clone of the module for your changes. 5. Change the files in your branch. Be sure to follow the [coding standards][1]! 6. Push your changed branch to your fork in your GitHub account. -7. Create a pull request for your changes **on the _'dev'_ branch** of the module's project. Be sure to follow the [contribution guidelines][2] in your pull request. If you need help to make a pull request, read the [GitHub help page about creating pull requests][3]. +7. Create a pull request for your changes on the `prestashop/8.x` branch of the module's project. Be sure to follow the [contribution guidelines][2] in your pull request. If you need help to make a pull request, read the [GitHub help page about creating pull requests][3]. 8. Wait for one of the core developers either to include your change in the codebase, or to comment on possible improvements you should make to your code. That's it: you have contributed to this open source project! Congratulations! @@ -79,9 +55,8 @@ That's it: you have contributed to this open source project! Congratulations! This module is released under the [Academic Free License 3.0][AFL-3.0] -[vuejs]: https://vuejs.org/ -[vuejs-devtools]: https://github.com/vuejs/vue-devtools -[direct-download]: https://github.com/PrestaShop/ps_checkout/releases/latest/download/ps_checkout.zip +[contact-us]: https://help-center.prestashop.com/contact?psx=ps_checkout +[direct-download]: https://github.com/PrestaShopCorp/ps_checkout/releases [1]: https://devdocs.prestashop.com/1.7/development/coding-standards/ [2]: https://devdocs.prestashop.com/1.7/contribute/contribution-guidelines/ [3]: https://help.github.com/articles/using-pull-requests From ae9af0c514d6e9dcfdc246702f9796b219526589 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Mon, 4 Mar 2024 09:57:44 +0100 Subject: [PATCH 50/54] Fix phpstan --- .github/workflows/php.yml | 5 + composer.json | 3 +- composer.lock | 441 ++++++++++++++++++------------ src/Http/PsrHttpClientAdapter.php | 8 +- 4 files changed, 276 insertions(+), 181 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index c781a322d..8e90cf09e 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -92,6 +92,11 @@ jobs: - name: Checkout uses: actions/checkout@v2 + - name: Setup PHP 7.4 + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + - name: Cache vendor folder uses: actions/cache@v1 with: diff --git a/composer.json b/composer.json index 342eb78b5..8082a38dc 100755 --- a/composer.json +++ b/composer.json @@ -36,7 +36,8 @@ }, "require-dev": { "phpunit/phpunit": "~5.7", - "prestashop/php-dev-tools": "~3.0" + "prestashop/php-dev-tools": "~3.0", + "monolog/monolog": "^1.27.1" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 707e750e6..de9931dc0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,27 +4,27 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1ffed083e7949e1d32cb94eaf11a19ad", + "content-hash": "38c3ff6e8b0ad69217d568aacbee4d1e", "packages": [ { "name": "clue/stream-filter", - "version": "v1.6.0", + "version": "v1.7.0", "source": { "type": "git", "url": "https://github.com/clue/stream-filter.git", - "reference": "d6169430c7731d8509da7aecd0af756a5747b78e" + "reference": "049509fef80032cb3f051595029ab75b49a3c2f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/clue/stream-filter/zipball/d6169430c7731d8509da7aecd0af756a5747b78e", - "reference": "d6169430c7731d8509da7aecd0af756a5747b78e", + "url": "https://api.github.com/repos/clue/stream-filter/zipball/049509fef80032cb3f051595029ab75b49a3c2f7", + "reference": "049509fef80032cb3f051595029ab75b49a3c2f7", "shasum": "" }, "require": { "php": ">=5.3" }, "require-dev": { - "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36" + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" }, "type": "library", "autoload": { @@ -46,7 +46,7 @@ } ], "description": "A simple and modern approach to stream filtering in PHP", - "homepage": "https://github.com/clue/php-stream-filter", + "homepage": "https://github.com/clue/stream-filter", "keywords": [ "bucket brigade", "callback", @@ -58,7 +58,7 @@ ], "support": { "issues": "https://github.com/clue/stream-filter/issues", - "source": "https://github.com/clue/stream-filter/tree/v1.6.0" + "source": "https://github.com/clue/stream-filter/tree/v1.7.0" }, "funding": [ { @@ -70,20 +70,20 @@ "type": "github" } ], - "time": "2022-02-21T13:15:14+00:00" + "time": "2023-12-20T15:40:13+00:00" }, { "name": "giggsey/libphonenumber-for-php", - "version": "8.13.14", + "version": "8.13.31", "source": { "type": "git", "url": "https://github.com/giggsey/libphonenumber-for-php.git", - "reference": "31b94ef2aa349b76bb725f375e9cfa2e398a1620" + "reference": "a4934bddda4672d12f21728e08bd575913bdc310" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/giggsey/libphonenumber-for-php/zipball/31b94ef2aa349b76bb725f375e9cfa2e398a1620", - "reference": "31b94ef2aa349b76bb725f375e9cfa2e398a1620", + "url": "https://api.github.com/repos/giggsey/libphonenumber-for-php/zipball/a4934bddda4672d12f21728e08bd575913bdc310", + "reference": "a4934bddda4672d12f21728e08bd575913bdc310", "shasum": "" }, "require": { @@ -142,20 +142,20 @@ "issues": "https://github.com/giggsey/libphonenumber-for-php/issues", "source": "https://github.com/giggsey/libphonenumber-for-php" }, - "time": "2023-06-13T08:08:40+00:00" + "time": "2024-02-26T08:31:45+00:00" }, { "name": "giggsey/locale", - "version": "2.4", + "version": "2.5", "source": { "type": "git", "url": "https://github.com/giggsey/Locale.git", - "reference": "a6b33dfc9e8949b7e28133c4628b29cd9f1850bb" + "reference": "e6d4540109a01dd2bc7334cdc842d6a6a67cf239" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/giggsey/Locale/zipball/a6b33dfc9e8949b7e28133c4628b29cd9f1850bb", - "reference": "a6b33dfc9e8949b7e28133c4628b29cd9f1850bb", + "url": "https://api.github.com/repos/giggsey/Locale/zipball/e6d4540109a01dd2bc7334cdc842d6a6a67cf239", + "reference": "e6d4540109a01dd2bc7334cdc842d6a6a67cf239", "shasum": "" }, "require": { @@ -194,9 +194,9 @@ "description": "Locale functions required by libphonenumber-for-php", "support": { "issues": "https://github.com/giggsey/Locale/issues", - "source": "https://github.com/giggsey/Locale/tree/2.4" + "source": "https://github.com/giggsey/Locale/tree/2.5" }, - "time": "2023-04-13T07:40:58+00:00" + "time": "2023-11-01T17:19:48+00:00" }, { "name": "gmponos/guzzle_logger", @@ -272,22 +272,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.7.0", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5" + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/fb7566caccf22d74d1ab270de3551f72a58399f5", - "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0", - "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", + "guzzlehttp/promises": "^1.5.3 || ^2.0.1", + "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -296,11 +296,11 @@ "psr/http-client-implementation": "1.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", + "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { @@ -378,7 +378,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.7.0" + "source": "https://github.com/guzzle/guzzle/tree/7.8.1" }, "funding": [ { @@ -394,28 +394,28 @@ "type": "tidelift" } ], - "time": "2023-05-21T14:04:53+00:00" + "time": "2023-12-03T20:35:24+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.0.0", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6" + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/3a494dc7dc1d7d12e511890177ae2d0e6c107da6", - "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6", + "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "type": "library", "extra": { @@ -461,7 +461,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.0" + "source": "https://github.com/guzzle/promises/tree/2.0.2" }, "funding": [ { @@ -477,20 +477,20 @@ "type": "tidelift" } ], - "time": "2023-05-21T13:50:22+00:00" + "time": "2023-12-03T20:19:20+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.5.0", + "version": "2.6.2", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6" + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", "shasum": "" }, "require": { @@ -504,9 +504,9 @@ "psr/http-message-implementation": "1.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", + "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -577,7 +577,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.5.0" + "source": "https://github.com/guzzle/psr7/tree/2.6.2" }, "funding": [ { @@ -593,7 +593,7 @@ "type": "tidelift" } ], - "time": "2023-04-17T16:11:26+00:00" + "time": "2023-12-03T20:05:35+00:00" }, { "name": "paragonie/random_compat", @@ -773,31 +773,26 @@ }, { "name": "php-http/promise", - "version": "1.1.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/php-http/promise.git", - "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88" + "reference": "2916a606d3b390f4e9e8e2b8dd68581508be0f07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/promise/zipball/4c4c1f9b7289a2ec57cde7f1e9762a5789506f88", - "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88", + "url": "https://api.github.com/repos/php-http/promise/zipball/2916a606d3b390f4e9e8e2b8dd68581508be0f07", + "reference": "2916a606d3b390f4e9e8e2b8dd68581508be0f07", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "friends-of-phpspec/phpspec-code-coverage": "^4.3.2", - "phpspec/phpspec": "^5.1.2 || ^6.2" + "friends-of-phpspec/phpspec-code-coverage": "^4.3.2 || ^6.3", + "phpspec/phpspec": "^5.1.2 || ^6.2 || ^7.4" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, "autoload": { "psr-4": { "Http\\Promise\\": "src/" @@ -824,9 +819,9 @@ ], "support": { "issues": "https://github.com/php-http/promise/issues", - "source": "https://github.com/php-http/promise/tree/1.1.0" + "source": "https://github.com/php-http/promise/tree/1.3.0" }, - "time": "2020-07-07T09:29:14+00:00" + "time": "2024-01-04T18:49:48+00:00" }, { "name": "prestashop/decimal", @@ -1228,16 +1223,16 @@ }, { "name": "psr/http-client", - "version": "1.0.2", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/php-fig/http-client.git", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", "shasum": "" }, "require": { @@ -1274,9 +1269,9 @@ "psr-18" ], "support": { - "source": "https://github.com/php-fig/http-client/tree/1.0.2" + "source": "https://github.com/php-fig/http-client" }, - "time": "2023-04-10T20:12:12+00:00" + "time": "2023-09-23T14:17:50+00:00" }, { "name": "psr/http-factory", @@ -2231,16 +2226,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.27.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", "shasum": "" }, "require": { @@ -2254,9 +2249,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -2293,7 +2285,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" }, "funding": [ { @@ -2309,20 +2301,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", "shasum": "" }, "require": { @@ -2336,9 +2328,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -2376,7 +2365,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" }, "funding": [ { @@ -2392,7 +2381,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php70", @@ -2464,16 +2453,16 @@ }, { "name": "symfony/polyfill-php73", - "version": "v1.27.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + "reference": "21bd091060673a1177ae842c0ef8fe30893114d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2", + "reference": "21bd091060673a1177ae842c0ef8fe30893114d2", "shasum": "" }, "require": { @@ -2481,9 +2470,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -2523,7 +2509,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.29.0" }, "funding": [ { @@ -2539,20 +2525,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.27.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", "shasum": "" }, "require": { @@ -2560,9 +2546,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -2606,7 +2589,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" }, "funding": [ { @@ -2622,7 +2605,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/service-contracts", @@ -2709,16 +2692,16 @@ }, { "name": "symfony/var-exporter", - "version": "v5.4.21", + "version": "v5.4.35", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "be74908a6942fdd331554b3cec27ff41b45ccad4" + "reference": "abb0a151b62d6b07e816487e20040464af96cae7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/be74908a6942fdd331554b3cec27ff41b45ccad4", - "reference": "be74908a6942fdd331554b3cec27ff41b45ccad4", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/abb0a151b62d6b07e816487e20040464af96cae7", + "reference": "abb0a151b62d6b07e816487e20040464af96cae7", "shasum": "" }, "require": { @@ -2762,7 +2745,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v5.4.21" + "source": "https://github.com/symfony/var-exporter/tree/v5.4.35" }, "funding": [ { @@ -2778,7 +2761,7 @@ "type": "tidelift" } ], - "time": "2023-02-21T19:46:44+00:00" + "time": "2024-01-23T13:51:25+00:00" }, { "name": "symfony/yaml", @@ -2984,16 +2967,16 @@ }, { "name": "composer/semver", - "version": "3.3.2", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", "shasum": "" }, "require": { @@ -3043,9 +3026,9 @@ "versioning" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.3.2" + "source": "https://github.com/composer/semver/tree/3.4.0" }, "funding": [ { @@ -3061,7 +3044,7 @@ "type": "tidelift" } ], - "time": "2022-04-01T19:23:25+00:00" + "time": "2023-08-31T09:50:34+00:00" }, { "name": "composer/xdebug-handler", @@ -3207,16 +3190,16 @@ }, { "name": "doctrine/deprecations", - "version": "v1.1.1", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", "shasum": "" }, "require": { @@ -3248,9 +3231,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" + "source": "https://github.com/doctrine/deprecations/tree/1.1.3" }, - "time": "2023-06-03T09:27:29+00:00" + "time": "2024-01-30T19:34:25+00:00" }, { "name": "doctrine/instantiator", @@ -3324,16 +3307,16 @@ }, { "name": "doctrine/lexer", - "version": "2.1.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" + "reference": "861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6", + "reference": "861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6", "shasum": "" }, "require": { @@ -3341,11 +3324,11 @@ "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^10", + "doctrine/coding-standard": "^9 || ^12", "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^4.11 || ^5.0" + "vimeo/psalm": "^4.11 || ^5.21" }, "type": "library", "autoload": { @@ -3382,7 +3365,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/2.1.0" + "source": "https://github.com/doctrine/lexer/tree/2.1.1" }, "funding": [ { @@ -3398,7 +3381,7 @@ "type": "tidelift" } ], - "time": "2022-12-14T08:49:07+00:00" + "time": "2024-02-05T11:35:39+00:00" }, { "name": "friendsofphp/php-cs-fixer", @@ -3509,6 +3492,92 @@ ], "time": "2021-11-15T17:17:55+00:00" }, + { + "name": "monolog/monolog", + "version": "1.27.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpstan/phpstan": "^0.12.59", + "phpunit/phpunit": "~4.5", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/1.27.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2022-06-09T08:53:42+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.11.1", @@ -4473,16 +4542,16 @@ }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.2", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" + "reference": "92a1a52e86d34cde6caa54f1b5ffa9fda18e5d54" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/92a1a52e86d34cde6caa54f1b5ffa9fda18e5d54", + "reference": "92a1a52e86d34cde6caa54f1b5ffa9fda18e5d54", "shasum": "" }, "require": { @@ -4516,7 +4585,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.3" }, "funding": [ { @@ -4524,7 +4593,7 @@ "type": "github" } ], - "time": "2020-11-30T08:15:22+00:00" + "time": "2024-03-01T13:45:45+00:00" }, { "name": "sebastian/comparator", @@ -5032,16 +5101,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.2", + "version": "3.9.0", "source": { "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/d63cee4890a8afaf86a22e51ad4d97c91dd4579b", + "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b", "shasum": "" }, "require": { @@ -5051,11 +5120,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -5070,22 +5139,45 @@ "authors": [ { "name": "Greg Sherwood", - "role": "lead" + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ "phpcs", "standards", "static analysis" ], "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" }, - "time": "2023-02-22T23:07:41+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-02-16T15:06:51+00:00" }, { "name": "symfony/console", @@ -5326,16 +5418,16 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v1.1.13", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e" + "reference": "761c8b8387cfe5f8026594a75fdf0a4e83ba6974" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e", - "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/761c8b8387cfe5f8026594a75fdf0a4e83ba6974", + "reference": "761c8b8387cfe5f8026594a75fdf0a4e83ba6974", "shasum": "" }, "require": { @@ -5385,7 +5477,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.10.0" }, "funding": [ { @@ -5401,7 +5493,7 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:41:36+00:00" + "time": "2022-07-20T09:59:04+00:00" }, { "name": "symfony/finder", @@ -5535,16 +5627,16 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.27.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25", + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25", "shasum": "" }, "require": { @@ -5552,9 +5644,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5591,7 +5680,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0" }, "funding": [ { @@ -5607,20 +5696,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/process", - "version": "v5.4.24", + "version": "v5.4.36", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "e3c46cc5689c8782944274bb30702106ecbe3b64" + "reference": "4fdf34004f149cc20b2f51d7d119aa500caad975" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/e3c46cc5689c8782944274bb30702106ecbe3b64", - "reference": "e3c46cc5689c8782944274bb30702106ecbe3b64", + "url": "https://api.github.com/repos/symfony/process/zipball/4fdf34004f149cc20b2f51d7d119aa500caad975", + "reference": "4fdf34004f149cc20b2f51d7d119aa500caad975", "shasum": "" }, "require": { @@ -5653,7 +5742,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.24" + "source": "https://github.com/symfony/process/tree/v5.4.36" }, "funding": [ { @@ -5669,20 +5758,20 @@ "type": "tidelift" } ], - "time": "2023-05-17T11:26:05+00:00" + "time": "2024-02-12T15:49:53+00:00" }, { "name": "symfony/stopwatch", - "version": "v5.4.21", + "version": "v5.4.35", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee" + "reference": "887762aa99ff16f65dc8b48aafead415f942d407" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/f83692cd869a6f2391691d40a01e8acb89e76fee", - "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/887762aa99ff16f65dc8b48aafead415f942d407", + "reference": "887762aa99ff16f65dc8b48aafead415f942d407", "shasum": "" }, "require": { @@ -5715,7 +5804,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.4.21" + "source": "https://github.com/symfony/stopwatch/tree/v5.4.35" }, "funding": [ { @@ -5731,7 +5820,7 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:03:56+00:00" + "time": "2024-01-23T13:51:25+00:00" } ], "aliases": [], diff --git a/src/Http/PsrHttpClientAdapter.php b/src/Http/PsrHttpClientAdapter.php index fac735f2d..513f4b5e7 100644 --- a/src/Http/PsrHttpClientAdapter.php +++ b/src/Http/PsrHttpClientAdapter.php @@ -45,12 +45,12 @@ public function sendRequest(RequestInterface $request) { try { $response = $this->client->sendRequest($request); - } catch (\GuzzleHttp\Ring\Exception\ConnectException $exception) { + } catch (\GuzzleHttp\Ring\Exception\ConnectException $exception) { // @phpstan-ignore-line // Guzzle 5.3 use RingPHP for the low level connection - throw new NetworkException($exception->getMessage(), $request, $exception); - } catch (\GuzzleHttp\Ring\Exception\RingException $exception) { + throw new NetworkException($exception->getMessage(), $request, $exception); // @phpstan-ignore-line + } catch (\GuzzleHttp\Ring\Exception\RingException $exception) { // @phpstan-ignore-line // Guzzle 5.3 use RingPHP for the low level connection - throw new TransferException($exception->getMessage(), 0, $exception); + throw new TransferException($exception->getMessage(), 0, $exception); // @phpstan-ignore-line } // Guzzle 5.3 does not throw exceptions on 4xx and 5xx status codes From 725c3204021f1d85a7466d3b2836490826ab35f1 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Mon, 4 Mar 2024 14:07:01 +0100 Subject: [PATCH 51/54] Fix hummingbird --- .../default-selectors-ps1_7-hummingbird.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/_dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_7-hummingbird.js b/_dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_7-hummingbird.js index 6a0d68c1b..22dc2e21e 100644 --- a/_dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_7-hummingbird.js +++ b/_dev/js/front/src/service/query-selector.service/default-selectors/default-selectors-ps1_7-hummingbird.js @@ -43,5 +43,21 @@ export const DefaultSelectors1_7Hummingbird = { PAY_LATER_OFFER_MESSAGE_CONTAINER_PRODUCT: '.product__prices', PAY_LATER_OFFER_MESSAGE_CONTAINER_CART_SUMMARY: '.cart-summary__totals', - PAY_LATER_BANNER_CONTAINER: '#notifications .container' + PAY_LATER_BANNER_CONTAINER: '#notifications .container', + + CARD_FIELDS: { + FORM: '#ps_checkout-card-fields-form', + NAME: '#ps_checkout-card-fields-name', + NUMBER: '#ps_checkout-card-fields-number', + EXPIRY: '#ps_checkout-card-fields-expiry', + CVV: '#ps_checkout-card-fields-cvv', + NAME_ERROR: '#ps_checkout-card-fields-name-error', + NUMBER_ERROR: '#ps_checkout-card-fields-number-error', + VENDOR_ERROR: '#ps_checkout-card-fields-vendor-error', + EXPIRY_ERROR: '#ps_checkout-card-fields-expiry-error', + CVV_ERROR: '#ps_checkout-card-fields-cvv-error', + }, + + PAYMENT_METHOD_LOGO_PRODUCT_CONTAINER: '#product .product-add-to-cart', + PAYMENT_METHOD_LOGO_CART_CONTAINER: '#cart .cart-summary .cart-detailed-actions' }; From 994563c9a7ee38dfc066f29e0467046fdf0649d0 Mon Sep 17 00:00:00 2001 From: Laurynas Date: Mon, 4 Mar 2024 15:47:12 +0200 Subject: [PATCH 52/54] Added wrapper for cvv field and tooltip --- .../src/components/common/card-fields.component.js | 2 +- views/css/payments.css | 8 ++++++++ views/css/payments16.css | 8 ++++++++ views/templates/hook/partials/cardFields.tpl | 12 +++++++----- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/_dev/js/front/src/components/common/card-fields.component.js b/_dev/js/front/src/components/common/card-fields.component.js index 07cbbdf03..db87a7d34 100644 --- a/_dev/js/front/src/components/common/card-fields.component.js +++ b/_dev/js/front/src/components/common/card-fields.component.js @@ -201,7 +201,7 @@ export class CardFieldsComponent extends BaseComponent { color: 'black' }, body: { - padding: '0px' + padding: '0 0 5px 0' } }, ...(this.configPayPal.hostedFieldsCustomization || {}), diff --git a/views/css/payments.css b/views/css/payments.css index d2076bfc4..97db35383 100755 --- a/views/css/payments.css +++ b/views/css/payments.css @@ -503,3 +503,11 @@ label[for="ps_checkout-hosted-fields-card-cvv"] { #cart #ps_checkout-payment-method-logo-block-container { text-align: center; } + +#ps_checkout-card-fields-form .ps_checkout-card-fields-cvv-label-wrapper { + display: table; +} + +#ps_checkout-card-fields-form .ps_checkout-card-fields-cvv-label-wrapper>label { + display: table-cell; +} diff --git a/views/css/payments16.css b/views/css/payments16.css index 152579c2d..e306f4037 100644 --- a/views/css/payments16.css +++ b/views/css/payments16.css @@ -473,3 +473,11 @@ #ps_checkout-canceled img, #ps_checkout-error img{ margin-right: 10px; } + +#ps_checkout-card-fields-form .ps_checkout-card-fields-cvv-label-wrapper { + display: table; +} + +#ps_checkout-card-fields-form .ps_checkout-card-fields-cvv-label-wrapper>label { + display: table-cell; +} diff --git a/views/templates/hook/partials/cardFields.tpl b/views/templates/hook/partials/cardFields.tpl index 0443c5718..69bd482fe 100644 --- a/views/templates/hook/partials/cardFields.tpl +++ b/views/templates/hook/partials/cardFields.tpl @@ -48,12 +48,14 @@
- -
-
i -