@funnelfox/billing 0.4.3 → 0.5.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-index.cjs.js +25 -50
- package/dist/chunk-index.cjs2.js +84 -0
- package/dist/chunk-index.es.js +25 -50
- package/dist/chunk-index.es2.js +82 -0
- package/dist/funnelfox-billing.cjs.js +302 -121
- package/dist/funnelfox-billing.esm.js +294 -113
- package/dist/funnelfox-billing.js +405 -172
- package/dist/funnelfox-billing.min.js +1 -1
- package/package.json +2 -2
- package/src/types.d.ts +56 -25
|
@@ -206,18 +206,18 @@ function withTimeout(promise, timeoutMs, message = 'Operation timed out') {
|
|
|
206
206
|
return Promise.race([promise, timeoutPromise]);
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
|
|
209
|
+
exports.PaymentMethod = void 0;
|
|
210
210
|
(function (PaymentMethod) {
|
|
211
211
|
PaymentMethod["GOOGLE_PAY"] = "GOOGLE_PAY";
|
|
212
212
|
PaymentMethod["APPLE_PAY"] = "APPLE_PAY";
|
|
213
213
|
PaymentMethod["PAYPAL"] = "PAYPAL";
|
|
214
214
|
PaymentMethod["PAYMENT_CARD"] = "PAYMENT_CARD";
|
|
215
|
-
})(PaymentMethod || (PaymentMethod = {}));
|
|
215
|
+
})(exports.PaymentMethod || (exports.PaymentMethod = {}));
|
|
216
216
|
|
|
217
217
|
/**
|
|
218
218
|
* @fileoverview Constants for Funnefox SDK
|
|
219
219
|
*/
|
|
220
|
-
const SDK_VERSION = '0.
|
|
220
|
+
const SDK_VERSION = '0.5.0-beta.0';
|
|
221
221
|
const DEFAULTS = {
|
|
222
222
|
BASE_URL: 'https://billing.funnelfox.com',
|
|
223
223
|
REGION: 'default',
|
|
@@ -244,9 +244,11 @@ const EVENTS = {
|
|
|
244
244
|
INPUT_ERROR: 'input-error',
|
|
245
245
|
LOADER_CHANGE: 'loader-change',
|
|
246
246
|
METHOD_RENDER: 'method-render',
|
|
247
|
+
METHOD_RENDER_ERROR: 'method-render-error',
|
|
247
248
|
START_PURCHASE: 'start-purchase',
|
|
248
249
|
PURCHASE_FAILURE: 'purchase-failure',
|
|
249
250
|
PURCHASE_COMPLETED: 'purchase-completed',
|
|
251
|
+
PURCHASE_CANCELLED: 'purchase-cancelled',
|
|
250
252
|
};
|
|
251
253
|
const API_ENDPOINTS = {
|
|
252
254
|
CREATE_CLIENT_SESSION: '/v1/checkout/create_client_session',
|
|
@@ -264,12 +266,12 @@ const ERROR_CODES = {
|
|
|
264
266
|
NETWORK_ERROR: 'NETWORK_ERROR',
|
|
265
267
|
};
|
|
266
268
|
const ALLOWED_BUTTON_PAYMENT_METHODS = [
|
|
267
|
-
PaymentMethod.GOOGLE_PAY,
|
|
268
|
-
PaymentMethod.APPLE_PAY,
|
|
269
|
-
PaymentMethod.PAYPAL,
|
|
269
|
+
exports.PaymentMethod.GOOGLE_PAY,
|
|
270
|
+
exports.PaymentMethod.APPLE_PAY,
|
|
271
|
+
exports.PaymentMethod.PAYPAL,
|
|
270
272
|
];
|
|
271
273
|
const ALLOWED_CARD_PAYMENT_METHODS = [
|
|
272
|
-
PaymentMethod.PAYMENT_CARD,
|
|
274
|
+
exports.PaymentMethod.PAYMENT_CARD,
|
|
273
275
|
];
|
|
274
276
|
const ALLOWED_PAYMENT_METHODS = [
|
|
275
277
|
...ALLOWED_BUTTON_PAYMENT_METHODS,
|
|
@@ -322,10 +324,6 @@ class PrimerWrapper {
|
|
|
322
324
|
const primerOptions = merge({
|
|
323
325
|
paymentHandling: 'MANUAL',
|
|
324
326
|
apiVersion: '2.4',
|
|
325
|
-
paypal: {
|
|
326
|
-
buttonColor: 'blue',
|
|
327
|
-
paymentFlow: 'PREFER_VAULT',
|
|
328
|
-
},
|
|
329
327
|
}, options);
|
|
330
328
|
try {
|
|
331
329
|
const headless = await window.Primer.createHeadless(clientToken, primerOptions);
|
|
@@ -353,9 +351,64 @@ class PrimerWrapper {
|
|
|
353
351
|
this.paymentMethodsInterfaces[method].setDisabled(disabled);
|
|
354
352
|
}
|
|
355
353
|
}
|
|
356
|
-
async
|
|
354
|
+
async renderButton(allowedPaymentMethod, { container, }) {
|
|
355
|
+
const containerEl = this.validateContainer(container);
|
|
356
|
+
let button;
|
|
357
|
+
this.ensurePrimerAvailable();
|
|
358
|
+
if (!this.headless) {
|
|
359
|
+
throw new PrimerError('Headless checkout not found');
|
|
360
|
+
}
|
|
361
|
+
try {
|
|
362
|
+
const pmManager = await this.headless.createPaymentMethodManager(allowedPaymentMethod);
|
|
363
|
+
if (!pmManager) {
|
|
364
|
+
throw new Error('Payment method manager is not available');
|
|
365
|
+
}
|
|
366
|
+
button = pmManager.createButton();
|
|
367
|
+
await button.render(containerEl, {});
|
|
368
|
+
this.destroyCallbacks.push(() => button.clean());
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
throw new PrimerError('Failed to initialize Primer checkout', error);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
async initMethod(method, htmlNode, options) {
|
|
375
|
+
if (method === exports.PaymentMethod.PAYMENT_CARD) {
|
|
376
|
+
if (!options.cardElements ||
|
|
377
|
+
!options.onSubmit ||
|
|
378
|
+
!options.onInputChange) {
|
|
379
|
+
throw new PrimerError('Card elements, onSubmit, and onInputChange are required for PAYMENT_CARD method');
|
|
380
|
+
}
|
|
381
|
+
return this.renderCardCheckoutWithElements(options.cardElements, {
|
|
382
|
+
onSubmit: options.onSubmit,
|
|
383
|
+
onInputChange: options.onInputChange,
|
|
384
|
+
onMethodRenderError: options.onMethodRenderError,
|
|
385
|
+
onMethodRender: options.onMethodRender,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
// For button methods, render directly into htmlNode
|
|
390
|
+
this.ensurePrimerAvailable();
|
|
391
|
+
if (!this.headless) {
|
|
392
|
+
throw new PrimerError('Headless checkout not found');
|
|
393
|
+
}
|
|
394
|
+
try {
|
|
395
|
+
const pmManager = await this.headless.createPaymentMethodManager(method);
|
|
396
|
+
if (!pmManager) {
|
|
397
|
+
throw new Error('Payment method manager is not available');
|
|
398
|
+
}
|
|
399
|
+
const button = pmManager.createButton();
|
|
400
|
+
await button.render(htmlNode, {});
|
|
401
|
+
this.destroyCallbacks.push(() => button.clean());
|
|
402
|
+
options.onMethodRender(method);
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
options.onMethodRenderError(method);
|
|
406
|
+
throw new PrimerError('Failed to initialize Primer checkout', error);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
async renderCardCheckoutWithElements(elements, { onSubmit, onInputChange, onMethodRenderError, onMethodRender, }) {
|
|
357
411
|
try {
|
|
358
|
-
const elements = this.initializeCardElements(cardSelectors);
|
|
359
412
|
const pmManager = await this.headless.createPaymentMethodManager('PAYMENT_CARD');
|
|
360
413
|
if (!pmManager) {
|
|
361
414
|
throw new Error('Payment method manager is not available');
|
|
@@ -402,7 +455,7 @@ class PrimerWrapper {
|
|
|
402
455
|
onSubmit(false);
|
|
403
456
|
}
|
|
404
457
|
};
|
|
405
|
-
elements.button
|
|
458
|
+
elements.button?.addEventListener('click', onSubmitHandler);
|
|
406
459
|
await Promise.all([
|
|
407
460
|
cardNumberInput.render(elements.cardNumber, {
|
|
408
461
|
placeholder: '1234 1234 1234 1234',
|
|
@@ -420,10 +473,13 @@ class PrimerWrapper {
|
|
|
420
473
|
style: inputStyle,
|
|
421
474
|
}),
|
|
422
475
|
]);
|
|
423
|
-
|
|
476
|
+
const onDestroy = () => {
|
|
424
477
|
pmManager.removeHostedInputs();
|
|
425
478
|
elements.cardholderName.removeEventListener('change', cardHolderOnChange);
|
|
426
|
-
|
|
479
|
+
elements.button.removeEventListener('click', onSubmitHandler);
|
|
480
|
+
};
|
|
481
|
+
this.destroyCallbacks.push(onDestroy);
|
|
482
|
+
onMethodRender(exports.PaymentMethod.PAYMENT_CARD);
|
|
427
483
|
return {
|
|
428
484
|
setDisabled: (disabled) => {
|
|
429
485
|
cardNumberInput.setDisabled(disabled);
|
|
@@ -431,75 +487,67 @@ class PrimerWrapper {
|
|
|
431
487
|
cvvInput.setDisabled(disabled);
|
|
432
488
|
elements.button.disabled = disabled;
|
|
433
489
|
},
|
|
490
|
+
submit: () => onSubmitHandler(),
|
|
491
|
+
destroy: () => {
|
|
492
|
+
this.destroyCallbacks = this.destroyCallbacks.filter(callback => callback !== onDestroy);
|
|
493
|
+
onDestroy();
|
|
494
|
+
},
|
|
434
495
|
};
|
|
435
496
|
}
|
|
436
497
|
catch (error) {
|
|
437
498
|
throw new PrimerError('Failed to initialize Primer checkout', error);
|
|
438
499
|
}
|
|
439
500
|
}
|
|
440
|
-
async
|
|
441
|
-
const containerEl = this.validateContainer(container);
|
|
442
|
-
let button;
|
|
443
|
-
this.ensurePrimerAvailable();
|
|
444
|
-
if (!this.headless) {
|
|
445
|
-
throw new PrimerError('Headless checkout not found');
|
|
446
|
-
}
|
|
447
|
-
try {
|
|
448
|
-
const pmManager = await this.headless.createPaymentMethodManager(allowedPaymentMethod);
|
|
449
|
-
if (!pmManager) {
|
|
450
|
-
throw new Error('Payment method manager is not available');
|
|
451
|
-
}
|
|
452
|
-
button = pmManager.createButton();
|
|
453
|
-
await button.render(containerEl, {});
|
|
454
|
-
this.destroyCallbacks.push(() => button.clean());
|
|
455
|
-
}
|
|
456
|
-
catch (error) {
|
|
457
|
-
throw new PrimerError('Failed to initialize Primer checkout', error);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
async renderCheckout(clientToken, options) {
|
|
461
|
-
const { cardSelectors, paymentButtonSelectors, container, onTokenizeSuccess, onResumeSuccess, onSubmit, onInputChange, onMethodRender, ...restPrimerOptions } = options;
|
|
501
|
+
async initializeHeadlessCheckout(clientToken, primerOptions) {
|
|
462
502
|
await this.createHeadlessCheckout(clientToken, {
|
|
463
|
-
...
|
|
464
|
-
onTokenizeSuccess: this.wrapTokenizeHandler(onTokenizeSuccess),
|
|
465
|
-
onResumeSuccess: this.wrapResumeHandler(onResumeSuccess),
|
|
503
|
+
...primerOptions,
|
|
504
|
+
onTokenizeSuccess: this.wrapTokenizeHandler(primerOptions.onTokenizeSuccess),
|
|
505
|
+
onResumeSuccess: this.wrapResumeHandler(primerOptions.onResumeSuccess),
|
|
466
506
|
onAvailablePaymentMethodsLoad: (items) => {
|
|
467
507
|
let isApplePayAvailable = false;
|
|
468
508
|
this.availableMethods = ALLOWED_PAYMENT_METHODS.filter(method => {
|
|
469
509
|
return items.some((item) => {
|
|
470
|
-
if (item.type === PaymentMethod.APPLE_PAY) {
|
|
510
|
+
if (item.type === exports.PaymentMethod.APPLE_PAY) {
|
|
471
511
|
isApplePayAvailable = true;
|
|
472
512
|
}
|
|
473
513
|
return item.type === method;
|
|
474
514
|
});
|
|
475
515
|
});
|
|
476
516
|
if (isApplePayAvailable) {
|
|
477
|
-
this.availableMethods = this.availableMethods.filter(method => method !== PaymentMethod.GOOGLE_PAY);
|
|
517
|
+
this.availableMethods = this.availableMethods.filter(method => method !== exports.PaymentMethod.GOOGLE_PAY);
|
|
478
518
|
}
|
|
479
519
|
if (this.availableMethods.length === 0) {
|
|
480
520
|
throw new PrimerError('No allowed payment methods found');
|
|
481
521
|
}
|
|
482
522
|
},
|
|
483
523
|
});
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
onInputChange,
|
|
489
|
-
};
|
|
524
|
+
}
|
|
525
|
+
async renderCheckout(clientToken, checkoutOptions, checkoutRenderOptions) {
|
|
526
|
+
const { cardElements, paymentButtonElements, container, onSubmit, onInputChange, onMethodRender, onMethodRenderError, } = checkoutRenderOptions;
|
|
527
|
+
await this.initializeHeadlessCheckout(clientToken, checkoutOptions);
|
|
490
528
|
for (const method of this.availableMethods) {
|
|
491
|
-
if (method === PaymentMethod.PAYMENT_CARD) {
|
|
492
|
-
|
|
493
|
-
|
|
529
|
+
if (method === exports.PaymentMethod.PAYMENT_CARD) {
|
|
530
|
+
// For card, use the main container
|
|
531
|
+
await this.initMethod(method, container, {
|
|
532
|
+
cardElements,
|
|
533
|
+
onSubmit,
|
|
534
|
+
onInputChange,
|
|
535
|
+
onMethodRender,
|
|
536
|
+
onMethodRenderError,
|
|
537
|
+
});
|
|
494
538
|
}
|
|
495
539
|
else {
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
:
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
540
|
+
const buttonElementsMap = {
|
|
541
|
+
[exports.PaymentMethod.PAYPAL]: paymentButtonElements.paypal,
|
|
542
|
+
[exports.PaymentMethod.GOOGLE_PAY]: paymentButtonElements.googlePay,
|
|
543
|
+
[exports.PaymentMethod.APPLE_PAY]: paymentButtonElements.applePay,
|
|
544
|
+
};
|
|
545
|
+
// For buttons, use the specific button container element
|
|
546
|
+
const buttonElement = buttonElementsMap[method];
|
|
547
|
+
await this.initMethod(method, buttonElement, {
|
|
548
|
+
onMethodRender,
|
|
549
|
+
onMethodRenderError,
|
|
550
|
+
});
|
|
503
551
|
}
|
|
504
552
|
}
|
|
505
553
|
this.isInitialized = true;
|
|
@@ -760,6 +808,12 @@ class APIClient {
|
|
|
760
808
|
}
|
|
761
809
|
throw new APIError('Invalid payment response format', null, { response });
|
|
762
810
|
}
|
|
811
|
+
async oneClick(payload) {
|
|
812
|
+
return (await this.request(`/billing/${this.orgId}/v1/checkout/one_click`, {
|
|
813
|
+
method: 'POST',
|
|
814
|
+
body: JSON.stringify(payload),
|
|
815
|
+
}));
|
|
816
|
+
}
|
|
763
817
|
}
|
|
764
818
|
|
|
765
819
|
var loaderHtml = "<div class=\"ff-sdk-loader-container\">\n <div class=\"ff-sdk-loader\"></div>\n</div>\n";
|
|
@@ -797,6 +851,9 @@ class CheckoutInstance extends EventEmitter {
|
|
|
797
851
|
this.handleMethodRender = (method) => {
|
|
798
852
|
this.emit(EVENTS.METHOD_RENDER, method);
|
|
799
853
|
};
|
|
854
|
+
this.handleMethodRenderError = (method) => {
|
|
855
|
+
this.emit(EVENTS.METHOD_RENDER_ERROR, method);
|
|
856
|
+
};
|
|
800
857
|
this.handleSubmit = (isSubmitting) => {
|
|
801
858
|
this.onLoaderChangeWithRace(isSubmitting);
|
|
802
859
|
this._setState(isSubmitting ? 'processing' : 'ready');
|
|
@@ -869,9 +926,6 @@ class CheckoutInstance extends EventEmitter {
|
|
|
869
926
|
this.primerWrapper = new PrimerWrapper();
|
|
870
927
|
this.isDestroyed = false;
|
|
871
928
|
this._setupCallbackBridges();
|
|
872
|
-
this.initialize().then(() => {
|
|
873
|
-
this.checkoutConfig?.onInitialized?.();
|
|
874
|
-
});
|
|
875
929
|
}
|
|
876
930
|
_setupCallbackBridges() {
|
|
877
931
|
if (this.callbacks.onSuccess) {
|
|
@@ -894,25 +948,10 @@ class CheckoutInstance extends EventEmitter {
|
|
|
894
948
|
try {
|
|
895
949
|
this.showInitializingLoader();
|
|
896
950
|
this._setState('initializing');
|
|
897
|
-
this.
|
|
898
|
-
baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
|
|
899
|
-
orgId: this.orgId,
|
|
900
|
-
timeout: DEFAULTS.REQUEST_TIMEOUT,
|
|
901
|
-
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
902
|
-
});
|
|
903
|
-
const sessionResponse = await this.apiClient.createClientSession({
|
|
904
|
-
priceId: this.checkoutConfig.priceId,
|
|
905
|
-
externalId: this.checkoutConfig.customer.externalId,
|
|
906
|
-
email: this.checkoutConfig.customer.email,
|
|
907
|
-
region: this.region || DEFAULTS.REGION,
|
|
908
|
-
clientMetadata: this.checkoutConfig.clientMetadata,
|
|
909
|
-
countryCode: this.checkoutConfig.customer.countryCode,
|
|
910
|
-
});
|
|
911
|
-
const sessionData = this.apiClient.processSessionResponse(sessionResponse);
|
|
912
|
-
this.orderId = sessionData.orderId;
|
|
913
|
-
this.clientToken = sessionData.clientToken;
|
|
951
|
+
await this.createSession();
|
|
914
952
|
await this._initializePrimerCheckout();
|
|
915
953
|
this._setState('ready');
|
|
954
|
+
this.checkoutConfig?.onInitialized?.();
|
|
916
955
|
return this;
|
|
917
956
|
}
|
|
918
957
|
catch (error) {
|
|
@@ -924,41 +963,90 @@ class CheckoutInstance extends EventEmitter {
|
|
|
924
963
|
this.hideInitializingLoader();
|
|
925
964
|
}
|
|
926
965
|
}
|
|
927
|
-
async
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
966
|
+
async createSession() {
|
|
967
|
+
this.apiClient = new APIClient({
|
|
968
|
+
baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
|
|
969
|
+
orgId: this.orgId,
|
|
970
|
+
timeout: DEFAULTS.REQUEST_TIMEOUT,
|
|
971
|
+
retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
|
|
972
|
+
});
|
|
973
|
+
const sessionResponse = await this.apiClient.createClientSession({
|
|
974
|
+
priceId: this.checkoutConfig.priceId,
|
|
975
|
+
externalId: this.checkoutConfig.customer.externalId,
|
|
976
|
+
email: this.checkoutConfig.customer.email,
|
|
977
|
+
region: this.region || DEFAULTS.REGION,
|
|
978
|
+
clientMetadata: this.checkoutConfig.clientMetadata,
|
|
979
|
+
countryCode: this.checkoutConfig.customer.countryCode,
|
|
980
|
+
});
|
|
981
|
+
const sessionData = this.apiClient.processSessionResponse(sessionResponse);
|
|
982
|
+
this.orderId = sessionData.orderId;
|
|
983
|
+
this.clientToken = sessionData.clientToken;
|
|
984
|
+
}
|
|
985
|
+
convertCardSelectorsToElements(selectors, container) {
|
|
986
|
+
const cardNumber = container.querySelector(selectors.cardNumber);
|
|
987
|
+
const expiryDate = container.querySelector(selectors.expiryDate);
|
|
988
|
+
const cvv = container.querySelector(selectors.cvv);
|
|
989
|
+
const cardholderName = container.querySelector(selectors.cardholderName);
|
|
990
|
+
const button = container.querySelector(selectors.button);
|
|
991
|
+
if (!cardNumber || !expiryDate || !cvv || !button) {
|
|
992
|
+
throw new CheckoutError('Required card input elements not found in container');
|
|
993
|
+
}
|
|
994
|
+
return {
|
|
995
|
+
cardNumber,
|
|
996
|
+
expiryDate,
|
|
997
|
+
cvv,
|
|
998
|
+
cardholderName,
|
|
999
|
+
button,
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
convertPaymentButtonSelectorsToElements(selectors) {
|
|
1003
|
+
const paypal = document.querySelector(selectors.paypal);
|
|
1004
|
+
const googlePay = document.querySelector(selectors.googlePay);
|
|
1005
|
+
const applePay = document.querySelector(selectors.applePay);
|
|
1006
|
+
if (!paypal || !googlePay || !applePay) {
|
|
1007
|
+
throw new CheckoutError('Required payment button elements not found in container');
|
|
1008
|
+
}
|
|
1009
|
+
return {
|
|
1010
|
+
paypal,
|
|
1011
|
+
googlePay,
|
|
1012
|
+
applePay,
|
|
955
1013
|
};
|
|
1014
|
+
}
|
|
1015
|
+
async _initializePrimerCheckout() {
|
|
1016
|
+
// Get container element
|
|
1017
|
+
const containerElement = this.getContainer();
|
|
1018
|
+
if (!containerElement) {
|
|
1019
|
+
throw new CheckoutError(`Checkout container not found: ${this.checkoutConfig.container}`);
|
|
1020
|
+
}
|
|
1021
|
+
// Get selectors (either from config or default skin)
|
|
1022
|
+
let cardElements;
|
|
1023
|
+
let paymentButtonElements;
|
|
1024
|
+
let checkoutOptions;
|
|
956
1025
|
if (!this.checkoutConfig.cardSelectors ||
|
|
957
1026
|
!this.checkoutConfig.paymentButtonSelectors) {
|
|
958
1027
|
const defaultSkinCheckoutOptions = await this.getDefaultSkinCheckoutOptions();
|
|
959
|
-
|
|
1028
|
+
if (!defaultSkinCheckoutOptions.cardElements ||
|
|
1029
|
+
!defaultSkinCheckoutOptions.paymentButtonElements) {
|
|
1030
|
+
throw new CheckoutError('Default skin must provide cardSelectors and paymentButtonSelectors');
|
|
1031
|
+
}
|
|
1032
|
+
cardElements =
|
|
1033
|
+
defaultSkinCheckoutOptions.cardElements;
|
|
1034
|
+
paymentButtonElements = defaultSkinCheckoutOptions.paymentButtonElements;
|
|
1035
|
+
checkoutOptions = this.getCheckoutOptions(defaultSkinCheckoutOptions);
|
|
1036
|
+
}
|
|
1037
|
+
else {
|
|
1038
|
+
cardElements = this.convertCardSelectorsToElements(this.checkoutConfig.cardSelectors, containerElement);
|
|
1039
|
+
paymentButtonElements = this.convertPaymentButtonSelectorsToElements(this.checkoutConfig.paymentButtonSelectors);
|
|
1040
|
+
checkoutOptions = this.getCheckoutOptions({});
|
|
960
1041
|
}
|
|
961
|
-
await this.primerWrapper.renderCheckout(this.clientToken, checkoutOptions
|
|
1042
|
+
await this.primerWrapper.renderCheckout(this.clientToken, checkoutOptions, {
|
|
1043
|
+
container: containerElement,
|
|
1044
|
+
cardElements,
|
|
1045
|
+
paymentButtonElements,
|
|
1046
|
+
onSubmit: this.handleSubmit,
|
|
1047
|
+
onInputChange: this.handleInputChange,
|
|
1048
|
+
onMethodRender: this.handleMethodRender,
|
|
1049
|
+
});
|
|
962
1050
|
}
|
|
963
1051
|
async _processPaymentResult(result, primerHandler) {
|
|
964
1052
|
if (result.orderId) {
|
|
@@ -988,6 +1076,48 @@ class CheckoutInstance extends EventEmitter {
|
|
|
988
1076
|
throw new CheckoutError(`Unknown payment result type: ${result.type}`);
|
|
989
1077
|
}
|
|
990
1078
|
}
|
|
1079
|
+
getCheckoutOptions(options) {
|
|
1080
|
+
let wasPaymentProcessedStarted = false;
|
|
1081
|
+
return {
|
|
1082
|
+
...this.checkoutConfig,
|
|
1083
|
+
...options,
|
|
1084
|
+
onTokenizeSuccess: this.handleTokenizeSuccess,
|
|
1085
|
+
onResumeSuccess: this.handleResumeSuccess,
|
|
1086
|
+
onResumeError: error => {
|
|
1087
|
+
if (error.stack?.includes('PROCESSOR_3DS') &&
|
|
1088
|
+
error.code === 'RESUME_ERROR' &&
|
|
1089
|
+
error.message?.includes('fetch resume key')) {
|
|
1090
|
+
// Ignore 3DS close error, because it is not understandable by user
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
this.emit(EVENTS.PURCHASE_FAILURE, error);
|
|
1094
|
+
},
|
|
1095
|
+
onCheckoutFail: error => {
|
|
1096
|
+
this.emit(EVENTS.PURCHASE_FAILURE, error);
|
|
1097
|
+
},
|
|
1098
|
+
onTokenizeError: error => {
|
|
1099
|
+
this.emit(EVENTS.PURCHASE_FAILURE, error);
|
|
1100
|
+
},
|
|
1101
|
+
onTokenizeShouldStart: data => {
|
|
1102
|
+
this.emit(EVENTS.ERROR, undefined);
|
|
1103
|
+
this.emit(EVENTS.START_PURCHASE, data.paymentMethodType);
|
|
1104
|
+
return true;
|
|
1105
|
+
},
|
|
1106
|
+
onPaymentMethodAction: action => {
|
|
1107
|
+
switch (action) {
|
|
1108
|
+
case 'PAYMENT_METHOD_SELECTED':
|
|
1109
|
+
this.emit(EVENTS.ERROR, undefined);
|
|
1110
|
+
break;
|
|
1111
|
+
case 'PAYMENT_METHOD_UNSELECTED':
|
|
1112
|
+
if (!wasPaymentProcessedStarted) {
|
|
1113
|
+
this.emit(EVENTS.PURCHASE_CANCELLED);
|
|
1114
|
+
}
|
|
1115
|
+
wasPaymentProcessedStarted = false;
|
|
1116
|
+
break;
|
|
1117
|
+
}
|
|
1118
|
+
},
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
991
1121
|
async updatePrice(newPriceId) {
|
|
992
1122
|
this._ensureNotDestroyed();
|
|
993
1123
|
requireString(newPriceId, 'priceId');
|
|
@@ -1078,6 +1208,13 @@ class CheckoutInstance extends EventEmitter {
|
|
|
1078
1208
|
this.on(EVENTS.PURCHASE_COMPLETED, skin.onPurchaseCompleted);
|
|
1079
1209
|
return skin.getCheckoutOptions();
|
|
1080
1210
|
}
|
|
1211
|
+
async getCardDefaultSkinCheckoutOptions(node) {
|
|
1212
|
+
const CardSkin = (await Promise.resolve().then(function () { return require('./chunk-index.cjs2.js'); })).default;
|
|
1213
|
+
const skin = new CardSkin(node);
|
|
1214
|
+
skin.init();
|
|
1215
|
+
this.on(EVENTS.INPUT_ERROR, skin.onInputError);
|
|
1216
|
+
return skin.getCheckoutOptions();
|
|
1217
|
+
}
|
|
1081
1218
|
showInitializingLoader() {
|
|
1082
1219
|
renderLoader(this.checkoutConfig.container);
|
|
1083
1220
|
}
|
|
@@ -1112,19 +1249,14 @@ async function createCheckout(options) {
|
|
|
1112
1249
|
const primerWrapper = new PrimerWrapper();
|
|
1113
1250
|
primerWrapper.ensurePrimerAvailable();
|
|
1114
1251
|
const config = resolveConfig(options, 'createCheckout');
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
checkoutConfig
|
|
1119
|
-
}
|
|
1120
|
-
const checkout = new CheckoutInstance({
|
|
1121
|
-
...config,
|
|
1122
|
-
checkoutConfig: {
|
|
1123
|
-
...checkoutConfig,
|
|
1124
|
-
onInitialized,
|
|
1125
|
-
},
|
|
1126
|
-
});
|
|
1252
|
+
const checkout = new CheckoutInstance({
|
|
1253
|
+
...config,
|
|
1254
|
+
checkoutConfig: {
|
|
1255
|
+
...checkoutConfig,
|
|
1256
|
+
},
|
|
1127
1257
|
});
|
|
1258
|
+
await checkout.initialize();
|
|
1259
|
+
return checkout;
|
|
1128
1260
|
}
|
|
1129
1261
|
async function createClientSession(params) {
|
|
1130
1262
|
const { priceId, externalId, email, clientMetadata, countryCode } = params;
|
|
@@ -1145,6 +1277,54 @@ async function createClientSession(params) {
|
|
|
1145
1277
|
});
|
|
1146
1278
|
return apiClient.processSessionResponse(sessionResponse);
|
|
1147
1279
|
}
|
|
1280
|
+
async function initMethod(method, element, options) {
|
|
1281
|
+
const checkoutInstance = new CheckoutInstance({
|
|
1282
|
+
orgId: options.orgId,
|
|
1283
|
+
baseUrl: options.baseUrl,
|
|
1284
|
+
checkoutConfig: {
|
|
1285
|
+
priceId: options.priceId,
|
|
1286
|
+
customer: {
|
|
1287
|
+
externalId: options.externalId,
|
|
1288
|
+
email: options.email,
|
|
1289
|
+
},
|
|
1290
|
+
container: '',
|
|
1291
|
+
clientMetadata: options.meta,
|
|
1292
|
+
},
|
|
1293
|
+
});
|
|
1294
|
+
checkoutInstance._ensureNotDestroyed();
|
|
1295
|
+
if (!checkoutInstance.isReady()) {
|
|
1296
|
+
await checkoutInstance['createSession']();
|
|
1297
|
+
}
|
|
1298
|
+
checkoutInstance.on(EVENTS.METHOD_RENDER, options.onRenderSuccess);
|
|
1299
|
+
checkoutInstance.on(EVENTS.METHOD_RENDER_ERROR, options.onRenderError);
|
|
1300
|
+
checkoutInstance.on(EVENTS.LOADER_CHANGE, options.onLoaderChange);
|
|
1301
|
+
checkoutInstance.on(EVENTS.SUCCESS, options.onPaymentSuccess);
|
|
1302
|
+
checkoutInstance.on(EVENTS.PURCHASE_FAILURE, options.onPaymentFail);
|
|
1303
|
+
checkoutInstance.on(EVENTS.PURCHASE_CANCELLED, options.onPaymentCancel);
|
|
1304
|
+
checkoutInstance.on(EVENTS.ERROR, options.onErrorMessageChange);
|
|
1305
|
+
if (method === exports.PaymentMethod.PAYMENT_CARD) {
|
|
1306
|
+
const cardDefaultOptions = await checkoutInstance['getCardDefaultSkinCheckoutOptions'](element);
|
|
1307
|
+
const checkoutOptions = checkoutInstance['getCheckoutOptions']({
|
|
1308
|
+
style: options.styles,
|
|
1309
|
+
...cardDefaultOptions,
|
|
1310
|
+
});
|
|
1311
|
+
await checkoutInstance.primerWrapper.initializeHeadlessCheckout(checkoutInstance.clientToken, checkoutOptions);
|
|
1312
|
+
return checkoutInstance.primerWrapper.initMethod(method, element, {
|
|
1313
|
+
cardElements: cardDefaultOptions.cardElements,
|
|
1314
|
+
onSubmit: checkoutInstance['handleSubmit'],
|
|
1315
|
+
onInputChange: checkoutInstance['handleInputChange'],
|
|
1316
|
+
onMethodRender: checkoutInstance['handleMethodRender'],
|
|
1317
|
+
onMethodRenderError: checkoutInstance['handleMethodRenderError'],
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
await checkoutInstance.primerWrapper.initializeHeadlessCheckout(checkoutInstance.clientToken, checkoutInstance['getCheckoutOptions']({
|
|
1321
|
+
style: options.styles,
|
|
1322
|
+
}));
|
|
1323
|
+
return checkoutInstance.primerWrapper.initMethod(method, element, {
|
|
1324
|
+
onMethodRender: checkoutInstance['handleMethodRender'],
|
|
1325
|
+
onMethodRenderError: checkoutInstance['handleMethodRenderError'],
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1148
1328
|
|
|
1149
1329
|
/**
|
|
1150
1330
|
* @fileoverview Main entry point for @funnelfox/billing
|
|
@@ -1153,6 +1333,7 @@ const Billing = {
|
|
|
1153
1333
|
configure: configure,
|
|
1154
1334
|
createCheckout: createCheckout,
|
|
1155
1335
|
createClientSession: createClientSession,
|
|
1336
|
+
initMethod: initMethod,
|
|
1156
1337
|
};
|
|
1157
1338
|
if (typeof window !== 'undefined') {
|
|
1158
1339
|
window.Billing = Billing;
|