@funnelfox/billing 0.4.5 → 0.5.0-beta.1

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.
@@ -213,7 +213,7 @@ var PaymentMethod;
213
213
  /**
214
214
  * @fileoverview Constants for Funnefox SDK
215
215
  */
216
- const SDK_VERSION = '0.4.5';
216
+ const SDK_VERSION = '0.5.0-beta.1';
217
217
  const DEFAULTS = {
218
218
  BASE_URL: 'https://billing.funnelfox.com',
219
219
  REGION: 'default',
@@ -240,9 +240,11 @@ const EVENTS = {
240
240
  INPUT_ERROR: 'input-error',
241
241
  LOADER_CHANGE: 'loader-change',
242
242
  METHOD_RENDER: 'method-render',
243
+ METHOD_RENDER_ERROR: 'method-render-error',
243
244
  START_PURCHASE: 'start-purchase',
244
245
  PURCHASE_FAILURE: 'purchase-failure',
245
246
  PURCHASE_COMPLETED: 'purchase-completed',
247
+ PURCHASE_CANCELLED: 'purchase-cancelled',
246
248
  };
247
249
  const API_ENDPOINTS = {
248
250
  CREATE_CLIENT_SESSION: '/v1/checkout/create_client_session',
@@ -318,10 +320,6 @@ class PrimerWrapper {
318
320
  const primerOptions = merge({
319
321
  paymentHandling: 'MANUAL',
320
322
  apiVersion: '2.4',
321
- paypal: {
322
- buttonColor: 'blue',
323
- paymentFlow: 'PREFER_VAULT',
324
- },
325
323
  }, options);
326
324
  try {
327
325
  const headless = await window.Primer.createHeadless(clientToken, primerOptions);
@@ -349,9 +347,64 @@ class PrimerWrapper {
349
347
  this.paymentMethodsInterfaces[method].setDisabled(disabled);
350
348
  }
351
349
  }
352
- async renderCardCheckout({ onSubmit, cardSelectors, onInputChange, }) {
350
+ async renderButton(allowedPaymentMethod, { container, }) {
351
+ const containerEl = this.validateContainer(container);
352
+ let button;
353
+ this.ensurePrimerAvailable();
354
+ if (!this.headless) {
355
+ throw new PrimerError('Headless checkout not found');
356
+ }
357
+ try {
358
+ const pmManager = await this.headless.createPaymentMethodManager(allowedPaymentMethod);
359
+ if (!pmManager) {
360
+ throw new Error('Payment method manager is not available');
361
+ }
362
+ button = pmManager.createButton();
363
+ await button.render(containerEl, {});
364
+ this.destroyCallbacks.push(() => button.clean());
365
+ }
366
+ catch (error) {
367
+ throw new PrimerError('Failed to initialize Primer checkout', error);
368
+ }
369
+ }
370
+ async initMethod(method, htmlNode, options) {
371
+ if (method === PaymentMethod.PAYMENT_CARD) {
372
+ if (!options.cardElements ||
373
+ !options.onSubmit ||
374
+ !options.onInputChange) {
375
+ throw new PrimerError('Card elements, onSubmit, and onInputChange are required for PAYMENT_CARD method');
376
+ }
377
+ return this.renderCardCheckoutWithElements(options.cardElements, {
378
+ onSubmit: options.onSubmit,
379
+ onInputChange: options.onInputChange,
380
+ onMethodRenderError: options.onMethodRenderError,
381
+ onMethodRender: options.onMethodRender,
382
+ });
383
+ }
384
+ else {
385
+ // For button methods, render directly into htmlNode
386
+ this.ensurePrimerAvailable();
387
+ if (!this.headless) {
388
+ throw new PrimerError('Headless checkout not found');
389
+ }
390
+ try {
391
+ const pmManager = await this.headless.createPaymentMethodManager(method);
392
+ if (!pmManager) {
393
+ throw new Error('Payment method manager is not available');
394
+ }
395
+ const button = pmManager.createButton();
396
+ await button.render(htmlNode, {});
397
+ this.destroyCallbacks.push(() => button.clean());
398
+ options.onMethodRender(method);
399
+ }
400
+ catch (error) {
401
+ options.onMethodRenderError(method);
402
+ throw new PrimerError('Failed to initialize Primer checkout', error);
403
+ }
404
+ }
405
+ }
406
+ async renderCardCheckoutWithElements(elements, { onSubmit, onInputChange, onMethodRenderError, onMethodRender, }) {
353
407
  try {
354
- const elements = this.initializeCardElements(cardSelectors);
355
408
  const pmManager = await this.headless.createPaymentMethodManager('PAYMENT_CARD');
356
409
  if (!pmManager) {
357
410
  throw new Error('Payment method manager is not available');
@@ -398,7 +451,7 @@ class PrimerWrapper {
398
451
  onSubmit(false);
399
452
  }
400
453
  };
401
- elements.button.addEventListener('click', onSubmitHandler);
454
+ elements.button?.addEventListener('click', onSubmitHandler);
402
455
  await Promise.all([
403
456
  cardNumberInput.render(elements.cardNumber, {
404
457
  placeholder: '1234 1234 1234 1234',
@@ -416,10 +469,13 @@ class PrimerWrapper {
416
469
  style: inputStyle,
417
470
  }),
418
471
  ]);
419
- this.destroyCallbacks.push(() => {
472
+ const onDestroy = () => {
420
473
  pmManager.removeHostedInputs();
421
474
  elements.cardholderName.removeEventListener('change', cardHolderOnChange);
422
- });
475
+ elements.button.removeEventListener('click', onSubmitHandler);
476
+ };
477
+ this.destroyCallbacks.push(onDestroy);
478
+ onMethodRender(PaymentMethod.PAYMENT_CARD);
423
479
  return {
424
480
  setDisabled: (disabled) => {
425
481
  cardNumberInput.setDisabled(disabled);
@@ -427,38 +483,22 @@ class PrimerWrapper {
427
483
  cvvInput.setDisabled(disabled);
428
484
  elements.button.disabled = disabled;
429
485
  },
486
+ submit: () => onSubmitHandler(),
487
+ destroy: () => {
488
+ this.destroyCallbacks = this.destroyCallbacks.filter(callback => callback !== onDestroy);
489
+ onDestroy();
490
+ },
430
491
  };
431
492
  }
432
493
  catch (error) {
433
494
  throw new PrimerError('Failed to initialize Primer checkout', error);
434
495
  }
435
496
  }
436
- async renderButton(allowedPaymentMethod, { container, }) {
437
- const containerEl = this.validateContainer(container);
438
- let button;
439
- this.ensurePrimerAvailable();
440
- if (!this.headless) {
441
- throw new PrimerError('Headless checkout not found');
442
- }
443
- try {
444
- const pmManager = await this.headless.createPaymentMethodManager(allowedPaymentMethod);
445
- if (!pmManager) {
446
- throw new Error('Payment method manager is not available');
447
- }
448
- button = pmManager.createButton();
449
- await button.render(containerEl, {});
450
- this.destroyCallbacks.push(() => button.clean());
451
- }
452
- catch (error) {
453
- throw new PrimerError('Failed to initialize Primer checkout', error);
454
- }
455
- }
456
- async renderCheckout(clientToken, options) {
457
- const { cardSelectors, paymentButtonSelectors, container, onTokenizeSuccess, onResumeSuccess, onSubmit, onInputChange, onMethodRender, ...restPrimerOptions } = options;
497
+ async initializeHeadlessCheckout(clientToken, primerOptions) {
458
498
  await this.createHeadlessCheckout(clientToken, {
459
- ...restPrimerOptions,
460
- onTokenizeSuccess: this.wrapTokenizeHandler(onTokenizeSuccess),
461
- onResumeSuccess: this.wrapResumeHandler(onResumeSuccess),
499
+ ...primerOptions,
500
+ onTokenizeSuccess: this.wrapTokenizeHandler(primerOptions.onTokenizeSuccess),
501
+ onResumeSuccess: this.wrapResumeHandler(primerOptions.onResumeSuccess),
462
502
  onAvailablePaymentMethodsLoad: (items) => {
463
503
  let isApplePayAvailable = false;
464
504
  this.availableMethods = ALLOWED_PAYMENT_METHODS.filter(method => {
@@ -477,25 +517,33 @@ class PrimerWrapper {
477
517
  }
478
518
  },
479
519
  });
480
- const methodOptions = {
481
- cardSelectors,
482
- container,
483
- onSubmit,
484
- onInputChange,
485
- };
520
+ }
521
+ async renderCheckout(clientToken, checkoutOptions, checkoutRenderOptions) {
522
+ const { cardElements, paymentButtonElements, container, onSubmit, onInputChange, onMethodRender, onMethodRenderError, } = checkoutRenderOptions;
523
+ await this.initializeHeadlessCheckout(clientToken, checkoutOptions);
486
524
  for (const method of this.availableMethods) {
487
525
  if (method === PaymentMethod.PAYMENT_CARD) {
488
- await this.renderCardCheckout(methodOptions);
489
- onMethodRender(PaymentMethod.PAYMENT_CARD);
526
+ // For card, use the main container
527
+ await this.initMethod(method, container, {
528
+ cardElements,
529
+ onSubmit,
530
+ onInputChange,
531
+ onMethodRender,
532
+ onMethodRenderError,
533
+ });
490
534
  }
491
535
  else {
492
- const container = method === PaymentMethod.PAYPAL
493
- ? paymentButtonSelectors.paypal
494
- : method === PaymentMethod.GOOGLE_PAY
495
- ? paymentButtonSelectors.googlePay
496
- : paymentButtonSelectors.applePay;
497
- await this.renderButton(method, { container });
498
- onMethodRender(method);
536
+ const buttonElementsMap = {
537
+ [PaymentMethod.PAYPAL]: paymentButtonElements.paypal,
538
+ [PaymentMethod.GOOGLE_PAY]: paymentButtonElements.googlePay,
539
+ [PaymentMethod.APPLE_PAY]: paymentButtonElements.applePay,
540
+ };
541
+ // For buttons, use the specific button container element
542
+ const buttonElement = buttonElementsMap[method];
543
+ await this.initMethod(method, buttonElement, {
544
+ onMethodRender,
545
+ onMethodRenderError,
546
+ });
499
547
  }
500
548
  }
501
549
  this.isInitialized = true;
@@ -756,6 +804,12 @@ class APIClient {
756
804
  }
757
805
  throw new APIError('Invalid payment response format', null, { response });
758
806
  }
807
+ async oneClick(payload) {
808
+ return (await this.request(`/billing/${this.orgId}/v1/checkout/one_click`, {
809
+ method: 'POST',
810
+ body: JSON.stringify(payload),
811
+ }));
812
+ }
759
813
  }
760
814
 
761
815
  var loaderHtml = "<div class=\"ff-sdk-loader-container\">\n <div class=\"ff-sdk-loader\"></div>\n</div>\n";
@@ -799,6 +853,9 @@ class CheckoutInstance extends EventEmitter {
799
853
  this.handleMethodRender = (method) => {
800
854
  this.emit(EVENTS.METHOD_RENDER, method);
801
855
  };
856
+ this.handleMethodRenderError = (method) => {
857
+ this.emit(EVENTS.METHOD_RENDER_ERROR, method);
858
+ };
802
859
  this.handleSubmit = (isSubmitting) => {
803
860
  this.onLoaderChangeWithRace(isSubmitting);
804
861
  this._setState(isSubmitting ? 'processing' : 'ready');
@@ -871,9 +928,6 @@ class CheckoutInstance extends EventEmitter {
871
928
  this.primerWrapper = new PrimerWrapper();
872
929
  this.isDestroyed = false;
873
930
  this._setupCallbackBridges();
874
- this.initialize().then(() => {
875
- this.checkoutConfig?.onInitialized?.();
876
- });
877
931
  }
878
932
  _setupCallbackBridges() {
879
933
  if (this.callbacks.onSuccess) {
@@ -896,25 +950,10 @@ class CheckoutInstance extends EventEmitter {
896
950
  try {
897
951
  this.showInitializingLoader();
898
952
  this._setState('initializing');
899
- this.apiClient = new APIClient({
900
- baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
901
- orgId: this.orgId,
902
- timeout: DEFAULTS.REQUEST_TIMEOUT,
903
- retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
904
- });
905
- const sessionResponse = await this.apiClient.createClientSession({
906
- priceId: this.checkoutConfig.priceId,
907
- externalId: this.checkoutConfig.customer.externalId,
908
- email: this.checkoutConfig.customer.email,
909
- region: this.region || DEFAULTS.REGION,
910
- clientMetadata: this.checkoutConfig.clientMetadata,
911
- countryCode: this.checkoutConfig.customer.countryCode,
912
- });
913
- const sessionData = this.apiClient.processSessionResponse(sessionResponse);
914
- this.orderId = sessionData.orderId;
915
- this.clientToken = sessionData.clientToken;
953
+ await this.createSession();
916
954
  await this._initializePrimerCheckout();
917
955
  this._setState('ready');
956
+ this.checkoutConfig?.onInitialized?.();
918
957
  return this;
919
958
  }
920
959
  catch (error) {
@@ -926,48 +965,97 @@ class CheckoutInstance extends EventEmitter {
926
965
  this.hideInitializingLoader();
927
966
  }
928
967
  }
929
- async _initializePrimerCheckout() {
930
- const checkoutOptions = {
931
- ...this.checkoutConfig,
932
- onTokenizeSuccess: this.handleTokenizeSuccess,
933
- onResumeSuccess: this.handleResumeSuccess,
934
- onSubmit: this.handleSubmit,
935
- onInputChange: this.handleInputChange,
936
- onMethodRender: this.handleMethodRender,
937
- onResumeError: error => {
938
- if (error.stack?.includes('PROCESSOR_3DS') &&
939
- error.code === 'RESUME_ERROR' &&
940
- error.message?.includes('fetch resume key')) {
941
- // Ignore 3DS close error, because it is not understandable by user
942
- return;
943
- }
944
- this.emit(EVENTS.PURCHASE_FAILURE, error);
945
- },
946
- onCheckoutFail: error => {
947
- this.emit(EVENTS.PURCHASE_FAILURE, error);
948
- },
949
- onTokenizeError: error => {
950
- this.emit(EVENTS.PURCHASE_FAILURE, error);
951
- },
952
- onTokenizeShouldStart: data => {
953
- this.emit(EVENTS.ERROR, undefined);
954
- this.emit(EVENTS.START_PURCHASE, data.paymentMethodType);
955
- return true;
956
- },
968
+ async createSession() {
969
+ this.apiClient = new APIClient({
970
+ baseUrl: this.baseUrl || DEFAULTS.BASE_URL,
971
+ orgId: this.orgId,
972
+ timeout: DEFAULTS.REQUEST_TIMEOUT,
973
+ retryAttempts: DEFAULTS.RETRY_ATTEMPTS,
974
+ });
975
+ const sessionResponse = await this.apiClient.createClientSession({
976
+ priceId: this.checkoutConfig.priceId,
977
+ externalId: this.checkoutConfig.customer.externalId,
978
+ email: this.checkoutConfig.customer.email,
979
+ region: this.region || DEFAULTS.REGION,
980
+ clientMetadata: this.checkoutConfig.clientMetadata,
981
+ countryCode: this.checkoutConfig.customer.countryCode,
982
+ });
983
+ const sessionData = this.apiClient.processSessionResponse(sessionResponse);
984
+ this.orderId = sessionData.orderId;
985
+ this.clientToken = sessionData.clientToken;
986
+ }
987
+ convertCardSelectorsToElements(selectors, container) {
988
+ const cardNumber = container.querySelector(selectors.cardNumber);
989
+ const expiryDate = container.querySelector(selectors.expiryDate);
990
+ const cvv = container.querySelector(selectors.cvv);
991
+ const cardholderName = container.querySelector(selectors.cardholderName);
992
+ const button = container.querySelector(selectors.button);
993
+ if (!cardNumber || !expiryDate || !cvv || !button) {
994
+ throw new CheckoutError('Required card input elements not found in container');
995
+ }
996
+ return {
997
+ cardNumber,
998
+ expiryDate,
999
+ cvv,
1000
+ cardholderName,
1001
+ button,
1002
+ };
1003
+ }
1004
+ convertPaymentButtonSelectorsToElements(selectors) {
1005
+ const paypal = document.querySelector(selectors.paypal);
1006
+ const googlePay = document.querySelector(selectors.googlePay);
1007
+ const applePay = document.querySelector(selectors.applePay);
1008
+ if (!paypal || !googlePay || !applePay) {
1009
+ throw new CheckoutError('Required payment button elements not found in container');
1010
+ }
1011
+ return {
1012
+ paypal,
1013
+ googlePay,
1014
+ applePay,
957
1015
  };
1016
+ }
1017
+ async _initializePrimerCheckout() {
1018
+ // Get container element
1019
+ const containerElement = this.getContainer();
1020
+ if (!containerElement) {
1021
+ throw new CheckoutError(`Checkout container not found: ${this.checkoutConfig.container}`);
1022
+ }
1023
+ // Get selectors (either from config or default skin)
1024
+ let cardElements;
1025
+ let paymentButtonElements;
1026
+ let checkoutOptions;
958
1027
  if (!this.checkoutConfig.cardSelectors ||
959
1028
  !this.checkoutConfig.paymentButtonSelectors) {
960
1029
  if (this.checkoutConfig.paymentMethodOrder) {
961
1030
  this.paymentMethodOrder = this.checkoutConfig.paymentMethodOrder;
962
1031
  }
963
1032
  const defaultSkinCheckoutOptions = await this.getDefaultSkinCheckoutOptions();
964
- Object.assign(checkoutOptions, defaultSkinCheckoutOptions);
1033
+ if (!defaultSkinCheckoutOptions.cardElements ||
1034
+ !defaultSkinCheckoutOptions.paymentButtonElements) {
1035
+ throw new CheckoutError('Default skin must provide cardSelectors and paymentButtonSelectors');
1036
+ }
1037
+ cardElements =
1038
+ defaultSkinCheckoutOptions.cardElements;
1039
+ paymentButtonElements = defaultSkinCheckoutOptions.paymentButtonElements;
1040
+ checkoutOptions = this.getCheckoutOptions(defaultSkinCheckoutOptions);
1041
+ }
1042
+ else {
1043
+ cardElements = this.convertCardSelectorsToElements(this.checkoutConfig.cardSelectors, containerElement);
1044
+ paymentButtonElements = this.convertPaymentButtonSelectorsToElements(this.checkoutConfig.paymentButtonSelectors);
1045
+ checkoutOptions = this.getCheckoutOptions({});
965
1046
  }
966
1047
  if (this.checkoutConfig.paymentMethodOrder) {
967
1048
  // eslint-disable-next-line no-console
968
1049
  console.warn('paymentMethodOrder is using only for default skin and will be ignored if you are using custom checkout');
969
1050
  }
970
- await this.primerWrapper.renderCheckout(this.clientToken, checkoutOptions);
1051
+ await this.primerWrapper.renderCheckout(this.clientToken, checkoutOptions, {
1052
+ container: containerElement,
1053
+ cardElements,
1054
+ paymentButtonElements,
1055
+ onSubmit: this.handleSubmit,
1056
+ onInputChange: this.handleInputChange,
1057
+ onMethodRender: this.handleMethodRender,
1058
+ });
971
1059
  }
972
1060
  async _processPaymentResult(result, primerHandler) {
973
1061
  if (result.orderId) {
@@ -997,6 +1085,48 @@ class CheckoutInstance extends EventEmitter {
997
1085
  throw new CheckoutError(`Unknown payment result type: ${result.type}`);
998
1086
  }
999
1087
  }
1088
+ getCheckoutOptions(options) {
1089
+ let wasPaymentProcessedStarted = false;
1090
+ return {
1091
+ ...this.checkoutConfig,
1092
+ ...options,
1093
+ onTokenizeSuccess: this.handleTokenizeSuccess,
1094
+ onResumeSuccess: this.handleResumeSuccess,
1095
+ onResumeError: error => {
1096
+ if (error.stack?.includes('PROCESSOR_3DS') &&
1097
+ error.code === 'RESUME_ERROR' &&
1098
+ error.message?.includes('fetch resume key')) {
1099
+ // Ignore 3DS close error, because it is not understandable by user
1100
+ return;
1101
+ }
1102
+ this.emit(EVENTS.PURCHASE_FAILURE, error);
1103
+ },
1104
+ onCheckoutFail: error => {
1105
+ this.emit(EVENTS.PURCHASE_FAILURE, error);
1106
+ },
1107
+ onTokenizeError: error => {
1108
+ this.emit(EVENTS.PURCHASE_FAILURE, error);
1109
+ },
1110
+ onTokenizeShouldStart: data => {
1111
+ this.emit(EVENTS.ERROR, undefined);
1112
+ this.emit(EVENTS.START_PURCHASE, data.paymentMethodType);
1113
+ return true;
1114
+ },
1115
+ onPaymentMethodAction: action => {
1116
+ switch (action) {
1117
+ case 'PAYMENT_METHOD_SELECTED':
1118
+ this.emit(EVENTS.ERROR, undefined);
1119
+ break;
1120
+ case 'PAYMENT_METHOD_UNSELECTED':
1121
+ if (!wasPaymentProcessedStarted) {
1122
+ this.emit(EVENTS.PURCHASE_CANCELLED);
1123
+ }
1124
+ wasPaymentProcessedStarted = false;
1125
+ break;
1126
+ }
1127
+ },
1128
+ };
1129
+ }
1000
1130
  async updatePrice(newPriceId) {
1001
1131
  this._ensureNotDestroyed();
1002
1132
  requireString(newPriceId, 'priceId');
@@ -1087,6 +1217,13 @@ class CheckoutInstance extends EventEmitter {
1087
1217
  this.on(EVENTS.PURCHASE_COMPLETED, skin.onPurchaseCompleted);
1088
1218
  return skin.getCheckoutOptions();
1089
1219
  }
1220
+ async getCardDefaultSkinCheckoutOptions(node) {
1221
+ const CardSkin = (await import('./chunk-index.es2.js')).default;
1222
+ const skin = new CardSkin(node);
1223
+ skin.init();
1224
+ this.on(EVENTS.INPUT_ERROR, skin.onInputError);
1225
+ return skin.getCheckoutOptions();
1226
+ }
1090
1227
  showInitializingLoader() {
1091
1228
  renderLoader(this.checkoutConfig.container);
1092
1229
  }
@@ -1121,19 +1258,14 @@ async function createCheckout(options) {
1121
1258
  const primerWrapper = new PrimerWrapper();
1122
1259
  primerWrapper.ensurePrimerAvailable();
1123
1260
  const config = resolveConfig(options, 'createCheckout');
1124
- return new Promise(resolve => {
1125
- const onInitialized = () => {
1126
- resolve(checkout);
1127
- checkoutConfig.onInitialized?.();
1128
- };
1129
- const checkout = new CheckoutInstance({
1130
- ...config,
1131
- checkoutConfig: {
1132
- ...checkoutConfig,
1133
- onInitialized,
1134
- },
1135
- });
1261
+ const checkout = new CheckoutInstance({
1262
+ ...config,
1263
+ checkoutConfig: {
1264
+ ...checkoutConfig,
1265
+ },
1136
1266
  });
1267
+ await checkout.initialize();
1268
+ return checkout;
1137
1269
  }
1138
1270
  async function createClientSession(params) {
1139
1271
  const { priceId, externalId, email, clientMetadata, countryCode } = params;
@@ -1154,6 +1286,54 @@ async function createClientSession(params) {
1154
1286
  });
1155
1287
  return apiClient.processSessionResponse(sessionResponse);
1156
1288
  }
1289
+ async function initMethod(method, element, options) {
1290
+ const checkoutInstance = new CheckoutInstance({
1291
+ orgId: options.orgId,
1292
+ baseUrl: options.baseUrl,
1293
+ checkoutConfig: {
1294
+ priceId: options.priceId,
1295
+ customer: {
1296
+ externalId: options.externalId,
1297
+ email: options.email,
1298
+ },
1299
+ container: '',
1300
+ clientMetadata: options.meta,
1301
+ },
1302
+ });
1303
+ checkoutInstance._ensureNotDestroyed();
1304
+ if (!checkoutInstance.isReady()) {
1305
+ await checkoutInstance['createSession']();
1306
+ }
1307
+ checkoutInstance.on(EVENTS.METHOD_RENDER, options.onRenderSuccess);
1308
+ checkoutInstance.on(EVENTS.METHOD_RENDER_ERROR, options.onRenderError);
1309
+ checkoutInstance.on(EVENTS.LOADER_CHANGE, options.onLoaderChange);
1310
+ checkoutInstance.on(EVENTS.SUCCESS, options.onPaymentSuccess);
1311
+ checkoutInstance.on(EVENTS.PURCHASE_FAILURE, options.onPaymentFail);
1312
+ checkoutInstance.on(EVENTS.PURCHASE_CANCELLED, options.onPaymentCancel);
1313
+ checkoutInstance.on(EVENTS.ERROR, options.onErrorMessageChange);
1314
+ if (method === PaymentMethod.PAYMENT_CARD) {
1315
+ const cardDefaultOptions = await checkoutInstance['getCardDefaultSkinCheckoutOptions'](element);
1316
+ const checkoutOptions = checkoutInstance['getCheckoutOptions']({
1317
+ style: options.styles,
1318
+ ...cardDefaultOptions,
1319
+ });
1320
+ await checkoutInstance.primerWrapper.initializeHeadlessCheckout(checkoutInstance.clientToken, checkoutOptions);
1321
+ return checkoutInstance.primerWrapper.initMethod(method, element, {
1322
+ cardElements: cardDefaultOptions.cardElements,
1323
+ onSubmit: checkoutInstance['handleSubmit'],
1324
+ onInputChange: checkoutInstance['handleInputChange'],
1325
+ onMethodRender: checkoutInstance['handleMethodRender'],
1326
+ onMethodRenderError: checkoutInstance['handleMethodRenderError'],
1327
+ });
1328
+ }
1329
+ await checkoutInstance.primerWrapper.initializeHeadlessCheckout(checkoutInstance.clientToken, checkoutInstance['getCheckoutOptions']({
1330
+ style: options.styles,
1331
+ }));
1332
+ return checkoutInstance.primerWrapper.initMethod(method, element, {
1333
+ onMethodRender: checkoutInstance['handleMethodRender'],
1334
+ onMethodRenderError: checkoutInstance['handleMethodRenderError'],
1335
+ });
1336
+ }
1157
1337
 
1158
1338
  /**
1159
1339
  * @fileoverview Main entry point for @funnelfox/billing
@@ -1162,6 +1342,7 @@ const Billing = {
1162
1342
  configure: configure,
1163
1343
  createCheckout: createCheckout,
1164
1344
  createClientSession: createClientSession,
1345
+ initMethod: initMethod,
1165
1346
  };
1166
1347
  if (typeof window !== 'undefined') {
1167
1348
  window.Billing = Billing;