@funnelfox/billing 0.8.0-ffb-550.38 → 0.8.0-ffb-631.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/chunk-index.cjs.js +240 -8
- package/dist/chunk-index.es.js +240 -9
- package/dist/chunk-stripe-card-form.cjs.js +1 -1
- package/dist/chunk-stripe-card-form.es.js +2 -2
- package/dist/chunk-stripe-wallet.cjs.js +1 -1
- package/dist/chunk-stripe-wallet.es.js +2 -2
- package/dist/funnelfox-billing.js +241 -10
- package/dist/funnelfox-billing.min.js +1 -1
- package/package.json +2 -2
- package/src/types.d.ts +74 -4
package/README.md
CHANGED
|
@@ -421,6 +421,8 @@ try {
|
|
|
421
421
|
console.log('Error Code:', error.errorCode); // e.g., 'double_purchase'
|
|
422
422
|
console.log('Error Type:', error.errorType); // e.g., 'api_exception'
|
|
423
423
|
console.log('Request ID:', error.requestId); // For support
|
|
424
|
+
console.log('Decline Code:', error.declineCode); // e.g., 'INSUFFICIENT_FUNDS', set on failed payments
|
|
425
|
+
console.log('Decline Source:', error.declineCodeSource); // 'primer' | 'stripe' | 'adyen', when the provider reports one
|
|
424
426
|
console.log('Message:', error.message);
|
|
425
427
|
} else if (error instanceof PrimerError) {
|
|
426
428
|
// Primer SDK error
|
|
@@ -634,6 +636,8 @@ const paymentMethod = await Billing.initMethod(
|
|
|
634
636
|
},
|
|
635
637
|
onPaymentFail: error => {
|
|
636
638
|
console.error('Payment failed:', error.message);
|
|
639
|
+
console.log('Decline code:', error.declineCode); // e.g., 'INSUFFICIENT_FUNDS', when the provider reports one
|
|
640
|
+
console.log('Decline source:', error.declineCodeSource); // 'primer' | 'stripe' | 'adyen'
|
|
637
641
|
},
|
|
638
642
|
onPaymentCancel: () => {
|
|
639
643
|
console.log('Payment was cancelled');
|
package/dist/chunk-index.cjs.js
CHANGED
|
@@ -119,6 +119,8 @@ class APIError extends FunnefoxSDKError {
|
|
|
119
119
|
this.errorType = options.errorType || null;
|
|
120
120
|
this.requestId = options.requestId || null;
|
|
121
121
|
this.response = options.response || null;
|
|
122
|
+
this.declineCode = options.declineCode || null;
|
|
123
|
+
this.declineCodeSource = options.declineCodeSource || null;
|
|
122
124
|
}
|
|
123
125
|
}
|
|
124
126
|
class PrimerError extends FunnefoxSDKError {
|
|
@@ -355,6 +357,32 @@ function getVisibleHostedInputError(input) {
|
|
|
355
357
|
return input.touched ? input.error : null;
|
|
356
358
|
}
|
|
357
359
|
function resolveTaxDisplay(source) {
|
|
360
|
+
return {
|
|
361
|
+
...resolveTaxAmount(source),
|
|
362
|
+
...resolveTaxBreakdown(source.tax_breakdown),
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function resolveTaxBreakdown(breakdown) {
|
|
366
|
+
if (!Array.isArray(breakdown)) {
|
|
367
|
+
return {};
|
|
368
|
+
}
|
|
369
|
+
const taxBreakdown = breakdown.map(entry => ({
|
|
370
|
+
amount: entry.amount,
|
|
371
|
+
percentage: entry.percentage,
|
|
372
|
+
inclusive: entry.inclusive,
|
|
373
|
+
taxType: entry.tax_type,
|
|
374
|
+
country: entry.country,
|
|
375
|
+
subdivision: entry.subdivision,
|
|
376
|
+
taxabilityReason: entry.taxability_reason,
|
|
377
|
+
}));
|
|
378
|
+
const percentages = taxBreakdown.map(entry => Number(entry.percentage));
|
|
379
|
+
if (!percentages.length || !percentages.every(Number.isFinite)) {
|
|
380
|
+
return { taxBreakdown };
|
|
381
|
+
}
|
|
382
|
+
const taxRate = Number(percentages.reduce((sum, percentage) => sum + percentage, 0).toFixed(6));
|
|
383
|
+
return { taxBreakdown, taxRate };
|
|
384
|
+
}
|
|
385
|
+
function resolveTaxAmount(source) {
|
|
358
386
|
const taxBehavior = source.tax_behavior ??
|
|
359
387
|
((source.tax_amount ?? 0) > 0 ? 'exclusive' : undefined);
|
|
360
388
|
if (taxBehavior === 'inclusive') {
|
|
@@ -533,7 +561,7 @@ exports.PaymentMethod = void 0;
|
|
|
533
561
|
/**
|
|
534
562
|
* @fileoverview Constants for Funnefox SDK
|
|
535
563
|
*/
|
|
536
|
-
const SDK_VERSION = '0.8.0-ffb-
|
|
564
|
+
const SDK_VERSION = '0.8.0-ffb-631.40';
|
|
537
565
|
const DEFAULTS = {
|
|
538
566
|
BASE_URL: 'https://billing.funnelfox.com',
|
|
539
567
|
REGION: 'default',
|
|
@@ -626,6 +654,7 @@ const DEFAULT_PAYMENT_METHOD_ORDER = [
|
|
|
626
654
|
const DEFAULT_BUTTONS_OPTIONS = {
|
|
627
655
|
[exports.PaymentMethod.APPLE_PAY]: {
|
|
628
656
|
buttonStyle: 'black',
|
|
657
|
+
buttonType: 'continue',
|
|
629
658
|
},
|
|
630
659
|
[exports.PaymentMethod.PAYPAL]: {
|
|
631
660
|
buttonColor: 'gold',
|
|
@@ -670,6 +699,117 @@ function requireString(value, fieldName) {
|
|
|
670
699
|
return true;
|
|
671
700
|
}
|
|
672
701
|
|
|
702
|
+
/**
|
|
703
|
+
* @fileoverview Support for Apple's official <apple-pay-button> custom element.
|
|
704
|
+
*
|
|
705
|
+
* Primer's checkout-web v2 renders the Apple Pay button through the CSS
|
|
706
|
+
* approach (-webkit-appearance: -apple-pay-button), and WebKit only accepts
|
|
707
|
+
* the 7 legacy values for -apple-pay-button-type. Newer types such as
|
|
708
|
+
* 'continue' are silently dropped and fall back to 'plain' (verified in
|
|
709
|
+
* Safari 26 on macOS and iOS, see PRD-1426).
|
|
710
|
+
*
|
|
711
|
+
* Apple's official custom element supports the full set of button types, so
|
|
712
|
+
* for "native-only" types we overlay it on top of the (visually hidden)
|
|
713
|
+
* Primer button and forward clicks, keeping Primer's payment flow untouched.
|
|
714
|
+
*/
|
|
715
|
+
const APPLE_PAY_SDK_URL = 'https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js';
|
|
716
|
+
/** How long to wait for the <apple-pay-button> element definition before
|
|
717
|
+
* giving up and falling back to Primer's own button. */
|
|
718
|
+
const ELEMENT_DEFINITION_TIMEOUT_MS = 4000;
|
|
719
|
+
/**
|
|
720
|
+
* Button types WebKit can render through Primer's CSS approach.
|
|
721
|
+
* Everything outside this list requires the native <apple-pay-button> element.
|
|
722
|
+
*/
|
|
723
|
+
const CSS_RENDERABLE_APPLE_PAY_TYPES = [
|
|
724
|
+
'plain',
|
|
725
|
+
'buy',
|
|
726
|
+
'set-up',
|
|
727
|
+
'donate',
|
|
728
|
+
'check-out',
|
|
729
|
+
'book',
|
|
730
|
+
'subscribe',
|
|
731
|
+
];
|
|
732
|
+
/**
|
|
733
|
+
* Returns true when the requested Apple Pay buttonType can only be rendered
|
|
734
|
+
* with Apple's native <apple-pay-button> element.
|
|
735
|
+
*/
|
|
736
|
+
function isNativeOnlyApplePayButtonType(type) {
|
|
737
|
+
return !!type && !CSS_RENDERABLE_APPLE_PAY_TYPES.includes(type);
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* Loads Apple's apple-pay-sdk.js (defines the <apple-pay-button> custom
|
|
741
|
+
* element). Resolves to true when the element is available.
|
|
742
|
+
*/
|
|
743
|
+
async function loadApplePayButtonElement() {
|
|
744
|
+
if (typeof window === 'undefined' || !window.customElements) {
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
if (window.customElements.get('apple-pay-button')) {
|
|
748
|
+
return true;
|
|
749
|
+
}
|
|
750
|
+
try {
|
|
751
|
+
await loadScript$1({
|
|
752
|
+
src: APPLE_PAY_SDK_URL,
|
|
753
|
+
crossOrigin: 'anonymous',
|
|
754
|
+
appendTo: 'head',
|
|
755
|
+
});
|
|
756
|
+
// Never hang on a script that loaded but did not define the element;
|
|
757
|
+
// fall back to Primer's own button instead.
|
|
758
|
+
const defined = window.customElements
|
|
759
|
+
.whenDefined('apple-pay-button')
|
|
760
|
+
.then(() => true);
|
|
761
|
+
const timeout = new Promise(resolve => {
|
|
762
|
+
setTimeout(() => resolve(false), ELEMENT_DEFINITION_TIMEOUT_MS);
|
|
763
|
+
});
|
|
764
|
+
return await Promise.race([defined, timeout]);
|
|
765
|
+
}
|
|
766
|
+
catch {
|
|
767
|
+
return false;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Renders Apple's native <apple-pay-button> stretched over `wrapper` and
|
|
772
|
+
* forwards clicks to the Primer-rendered <button> inside it. The synchronous
|
|
773
|
+
* forwarded click preserves the user activation required by ApplePaySession.
|
|
774
|
+
*
|
|
775
|
+
* Returns the overlay element, or null when the Apple Pay SDK could not be
|
|
776
|
+
* loaded (callers should keep Primer's own button visible as a fallback).
|
|
777
|
+
*/
|
|
778
|
+
async function overlayNativeApplePayButton(wrapper, options) {
|
|
779
|
+
const available = await loadApplePayButtonElement();
|
|
780
|
+
if (!available) {
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
// The overlay is only safe when Primer's own clickable button is present;
|
|
784
|
+
// otherwise there is nothing to forward the click to.
|
|
785
|
+
if (!wrapper.querySelector('button')) {
|
|
786
|
+
return null;
|
|
787
|
+
}
|
|
788
|
+
const native = document.createElement('apple-pay-button');
|
|
789
|
+
native.setAttribute('type', options.buttonType);
|
|
790
|
+
native.setAttribute('buttonstyle', options.buttonStyle || 'black');
|
|
791
|
+
native.setAttribute('locale', (typeof navigator !== 'undefined' && navigator.language) || 'en-US');
|
|
792
|
+
native.style.cssText = [
|
|
793
|
+
'position:absolute',
|
|
794
|
+
'inset:0',
|
|
795
|
+
'width:100%',
|
|
796
|
+
'height:100%',
|
|
797
|
+
'--apple-pay-button-width:100%',
|
|
798
|
+
'--apple-pay-button-height:100%',
|
|
799
|
+
'--apple-pay-button-border-radius:28px',
|
|
800
|
+
'display:block',
|
|
801
|
+
'cursor:pointer',
|
|
802
|
+
'z-index:1',
|
|
803
|
+
].join(';');
|
|
804
|
+
wrapper.style.position = 'relative';
|
|
805
|
+
native.addEventListener('click', () => {
|
|
806
|
+
const primerButton = wrapper.querySelector('button');
|
|
807
|
+
primerButton?.click();
|
|
808
|
+
});
|
|
809
|
+
wrapper.appendChild(native);
|
|
810
|
+
return native;
|
|
811
|
+
}
|
|
812
|
+
|
|
673
813
|
/**
|
|
674
814
|
* @fileoverview Primer SDK integration wrapper
|
|
675
815
|
*/
|
|
@@ -708,6 +848,7 @@ class PrimerWrapper {
|
|
|
708
848
|
}
|
|
709
849
|
async createHeadlessCheckout(clientToken, options, method) {
|
|
710
850
|
await this.ensurePrimerLoaded();
|
|
851
|
+
this.applePayOptions = options.applePay;
|
|
711
852
|
this.currentHeadless = PrimerWrapper.headlessManager.getOrCreate(clientToken, options, method);
|
|
712
853
|
return this.currentHeadless;
|
|
713
854
|
}
|
|
@@ -754,16 +895,56 @@ class PrimerWrapper {
|
|
|
754
895
|
}
|
|
755
896
|
htmlNode.appendChild(wrapper);
|
|
756
897
|
/* end hack */
|
|
898
|
+
/* PRD-1426: WebKit cannot render newer Apple Pay button types (e.g.
|
|
899
|
+
* 'continue') through the CSS approach Primer v2 uses. For those types
|
|
900
|
+
* we overlay Apple's official <apple-pay-button> element on top of the
|
|
901
|
+
* visually hidden Primer button and forward clicks, keeping Primer's
|
|
902
|
+
* payment flow untouched. The Primer button is hidden BEFORE it renders
|
|
903
|
+
* to avoid a flash of the plain button; if the Apple SDK fails to load,
|
|
904
|
+
* the rule is removed and Primer's own button stays visible (graceful
|
|
905
|
+
* fallback to 'plain'). */
|
|
906
|
+
const applePayConfig = this.applePayOptions;
|
|
907
|
+
const nativeButtonType = allowedPaymentMethod === exports.PaymentMethod.APPLE_PAY &&
|
|
908
|
+
applePayConfig?.buttonType &&
|
|
909
|
+
isNativeOnlyApplePayButtonType(applePayConfig.buttonType)
|
|
910
|
+
? applePayConfig.buttonType
|
|
911
|
+
: null;
|
|
912
|
+
let hideRuleIndex = null;
|
|
913
|
+
if (nativeButtonType && sheet) {
|
|
914
|
+
hideRuleIndex = sheet.insertRule(`
|
|
915
|
+
.${wrapper.className} > button {
|
|
916
|
+
opacity: 0 !important;
|
|
917
|
+
}
|
|
918
|
+
`);
|
|
919
|
+
}
|
|
757
920
|
button = pmManager.createButton();
|
|
758
921
|
await button.render(wrapper, {});
|
|
759
|
-
|
|
922
|
+
let nativeOverlay = null;
|
|
923
|
+
if (nativeButtonType) {
|
|
924
|
+
nativeOverlay = await overlayNativeApplePayButton(wrapper, {
|
|
925
|
+
buttonType: nativeButtonType,
|
|
926
|
+
buttonStyle: applePayConfig?.buttonStyle,
|
|
927
|
+
});
|
|
928
|
+
if (!nativeOverlay && sheet && hideRuleIndex !== null) {
|
|
929
|
+
sheet.deleteRule(hideRuleIndex);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
this.destroyCallbacks.push(() => {
|
|
933
|
+
nativeOverlay?.remove();
|
|
934
|
+
button.clean();
|
|
935
|
+
});
|
|
760
936
|
onMethodRender(allowedPaymentMethod);
|
|
761
937
|
return {
|
|
762
938
|
setDisabled: (disabled) => {
|
|
763
939
|
button.setDisabled(disabled);
|
|
940
|
+
if (nativeOverlay) {
|
|
941
|
+
nativeOverlay.style.pointerEvents = disabled ? 'none' : '';
|
|
942
|
+
nativeOverlay.style.opacity = disabled ? '0.5' : '';
|
|
943
|
+
}
|
|
764
944
|
},
|
|
765
945
|
destroy: () => {
|
|
766
946
|
styleEl.remove();
|
|
947
|
+
nativeOverlay?.remove();
|
|
767
948
|
button.clean();
|
|
768
949
|
},
|
|
769
950
|
};
|
|
@@ -1121,6 +1302,37 @@ class PrimerWrapper {
|
|
|
1121
1302
|
}
|
|
1122
1303
|
PrimerWrapper.headlessManager = new HeadlessManager();
|
|
1123
1304
|
|
|
1305
|
+
/**
|
|
1306
|
+
* @fileoverview Normalization of payment failure errors
|
|
1307
|
+
*/
|
|
1308
|
+
const STRIPE_CARD_ERROR = 'card_error';
|
|
1309
|
+
function declineCodeFromStripeError(error) {
|
|
1310
|
+
const { type, code } = error;
|
|
1311
|
+
if (type !== STRIPE_CARD_ERROR || typeof code !== 'string' || !code) {
|
|
1312
|
+
return null;
|
|
1313
|
+
}
|
|
1314
|
+
return code.toUpperCase();
|
|
1315
|
+
}
|
|
1316
|
+
function toPaymentFailure(error) {
|
|
1317
|
+
const failure = new Error(error?.message || 'Payment processing failed');
|
|
1318
|
+
if (error instanceof APIError) {
|
|
1319
|
+
if (error.declineCode) {
|
|
1320
|
+
failure.declineCode = error.declineCode;
|
|
1321
|
+
}
|
|
1322
|
+
if (error.declineCodeSource) {
|
|
1323
|
+
failure.declineCodeSource = error.declineCodeSource;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
else if (error instanceof Error) {
|
|
1327
|
+
const declineCode = declineCodeFromStripeError(error);
|
|
1328
|
+
if (declineCode) {
|
|
1329
|
+
failure.declineCode = declineCode;
|
|
1330
|
+
failure.declineCodeSource = 'stripe';
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
return failure;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1124
1336
|
/**
|
|
1125
1337
|
* @fileoverview API client for Funnefox backend integration
|
|
1126
1338
|
*/
|
|
@@ -1318,7 +1530,11 @@ class APIClient {
|
|
|
1318
1530
|
status: 'succeeded',
|
|
1319
1531
|
};
|
|
1320
1532
|
case 'failed':
|
|
1321
|
-
throw new APIError(data.failed_message_for_user || 'Payment failed', null, {
|
|
1533
|
+
throw new APIError(data.failed_message_for_user || 'Payment failed', null, {
|
|
1534
|
+
response,
|
|
1535
|
+
declineCode: data.decline_code,
|
|
1536
|
+
declineCodeSource: data.decline_code_source,
|
|
1537
|
+
});
|
|
1322
1538
|
case 'cancelled':
|
|
1323
1539
|
throw new APIError('Payment was cancelled by user', null, {
|
|
1324
1540
|
response,
|
|
@@ -1869,6 +2085,9 @@ class CheckoutInstance extends EventEmitter {
|
|
|
1869
2085
|
this.counter = 0;
|
|
1870
2086
|
this.cachedSessionResponse = null;
|
|
1871
2087
|
this.taxRecalcSeq = 0;
|
|
2088
|
+
// WebKit allows one ApplePaySession per page: a second tap while the sheet is
|
|
2089
|
+
// still opening throws InvalidAccessError, but Primer asks to start first.
|
|
2090
|
+
this.isApplePaySheetOpen = false;
|
|
1872
2091
|
this.cardSessionFieldConfig = {};
|
|
1873
2092
|
this.isTelemetryEnabled = false;
|
|
1874
2093
|
this.telemetryCleanup = null;
|
|
@@ -2031,10 +2250,11 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2031
2250
|
}
|
|
2032
2251
|
catch (error) {
|
|
2033
2252
|
this._setState('error');
|
|
2034
|
-
this.emit(EVENTS.PURCHASE_FAILURE,
|
|
2035
|
-
primerHandler.handleFailure(error
|
|
2253
|
+
this.emit(EVENTS.PURCHASE_FAILURE, toPaymentFailure(error));
|
|
2254
|
+
primerHandler.handleFailure(error?.message || 'Payment processing failed');
|
|
2036
2255
|
}
|
|
2037
2256
|
finally {
|
|
2257
|
+
this.isApplePaySheetOpen = false;
|
|
2038
2258
|
this.onLoaderChangeWithRace(false);
|
|
2039
2259
|
this._setState('ready');
|
|
2040
2260
|
}
|
|
@@ -2056,10 +2276,11 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2056
2276
|
}
|
|
2057
2277
|
catch (error) {
|
|
2058
2278
|
this._setState('error');
|
|
2059
|
-
this.emit(EVENTS.PURCHASE_FAILURE,
|
|
2060
|
-
primerHandler.handleFailure(error
|
|
2279
|
+
this.emit(EVENTS.PURCHASE_FAILURE, toPaymentFailure(error));
|
|
2280
|
+
primerHandler.handleFailure(error?.message || 'Payment processing failed');
|
|
2061
2281
|
}
|
|
2062
2282
|
finally {
|
|
2283
|
+
this.isApplePaySheetOpen = false;
|
|
2063
2284
|
this.emit(EVENTS.PURCHASE_COMPLETED);
|
|
2064
2285
|
this.onLoaderChangeWithRace(false);
|
|
2065
2286
|
this._setState('ready');
|
|
@@ -2384,10 +2605,11 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2384
2605
|
...checkoutConfig,
|
|
2385
2606
|
...options,
|
|
2386
2607
|
card: merge(this.getPrimerCardConfig() || {}, options.card || {}),
|
|
2387
|
-
applePay: merge(
|
|
2608
|
+
applePay: merge(DEFAULT_BUTTONS_OPTIONS[exports.PaymentMethod.APPLE_PAY], options.applePay || {}, this.checkoutConfig.applePay || {}),
|
|
2388
2609
|
onTokenizeSuccess: this.handleTokenizeSuccess,
|
|
2389
2610
|
onResumeSuccess: this.handleResumeSuccess,
|
|
2390
2611
|
onResumeError: error => {
|
|
2612
|
+
this.isApplePaySheetOpen = false;
|
|
2391
2613
|
if (error.stack?.includes('PROCESSOR_3DS') &&
|
|
2392
2614
|
error.code === 'RESUME_ERROR' &&
|
|
2393
2615
|
error.message?.includes('fetch resume key')) {
|
|
@@ -2397,15 +2619,23 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2397
2619
|
this.emit(EVENTS.PURCHASE_FAILURE, error);
|
|
2398
2620
|
},
|
|
2399
2621
|
onCheckoutFail: error => {
|
|
2622
|
+
this.isApplePaySheetOpen = false;
|
|
2400
2623
|
this.emit(EVENTS.PURCHASE_FAILURE, error);
|
|
2401
2624
|
},
|
|
2402
2625
|
onTokenizeError: error => {
|
|
2626
|
+
this.isApplePaySheetOpen = false;
|
|
2403
2627
|
this.emit(EVENTS.PURCHASE_FAILURE, error);
|
|
2404
2628
|
},
|
|
2405
2629
|
onTokenizeStart: () => {
|
|
2406
2630
|
wasPaymentProcessedStarted = true;
|
|
2407
2631
|
},
|
|
2408
2632
|
onTokenizeShouldStart: data => {
|
|
2633
|
+
if (data.paymentMethodType === exports.PaymentMethod.APPLE_PAY) {
|
|
2634
|
+
if (this.isApplePaySheetOpen) {
|
|
2635
|
+
return false;
|
|
2636
|
+
}
|
|
2637
|
+
this.isApplePaySheetOpen = true;
|
|
2638
|
+
}
|
|
2409
2639
|
this.activePaymentMethodType = data.paymentMethodType;
|
|
2410
2640
|
this.emit(EVENTS.ERROR, undefined);
|
|
2411
2641
|
this.emit(EVENTS.START_PURCHASE, data.paymentMethodType);
|
|
@@ -2417,6 +2647,7 @@ class CheckoutInstance extends EventEmitter {
|
|
|
2417
2647
|
this.emit(EVENTS.ERROR, undefined);
|
|
2418
2648
|
break;
|
|
2419
2649
|
case 'PAYMENT_METHOD_UNSELECTED':
|
|
2650
|
+
this.isApplePaySheetOpen = false;
|
|
2420
2651
|
if (!wasPaymentProcessedStarted) {
|
|
2421
2652
|
this.emit(EVENTS.PURCHASE_CANCELLED);
|
|
2422
2653
|
}
|
|
@@ -3011,3 +3242,4 @@ exports.createClientSession = createClientSession;
|
|
|
3011
3242
|
exports.getAvailablePaymentMethods = getAvailablePaymentMethods;
|
|
3012
3243
|
exports.loadStripe = loadStripe;
|
|
3013
3244
|
exports.resolveTaxDisplay = resolveTaxDisplay;
|
|
3245
|
+
exports.toPaymentFailure = toPaymentFailure;
|