@paystack/checkout-js 1.57.0-beta.5 → 1.57.0-beta.6

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/checkout.js CHANGED
@@ -6519,47 +6519,108 @@ var Paystack = (function (exports) {
6519
6519
  };
6520
6520
 
6521
6521
  /* eslint-env browser */
6522
-
6523
- // `context` is passed through to set the class property of `isListening` to true/false
6524
- // and provide the logAPIResponse analytics function
6525
- // eslint-disable-next-line consistent-return, import/prefer-default-export
6526
- var subscribeToChargeEvents = function subscribeToChargeEvents(options, context, callback) {
6527
- var channel = options.channel,
6528
- paymentMethod = options.paymentMethod;
6529
- var pusher;
6530
- if (window && window.Pusher) {
6531
- pusher = new window.Pusher(configToUse.pusherKey, {
6532
- cluster: 'eu',
6533
- disableStats: true
6534
- });
6535
- }
6536
- var pusherUndefinedError = {
6522
+ var LISTEN_ERRORS = {
6523
+ unavailable: {
6537
6524
  status: 'error',
6538
6525
  message: 'We could not listen for charge response.'
6539
- };
6540
- var pusherSubscriptionError = {
6526
+ },
6527
+ subscriptionFailed: {
6541
6528
  status: 'error',
6542
6529
  message: 'We could not listen for charge response. Use transaction.requery() to check the status.'
6530
+ }
6531
+ };
6532
+
6533
+ // Returns null rather than throwing when Pusher is not on the page, so each
6534
+ // listener can choose what to hand its caller back. The `!window` half only
6535
+ // guards against window being declared and assigned undefined; with window
6536
+ // genuinely absent this throws, which is what both paths already did.
6537
+ var createPusherClient = function createPusherClient() {
6538
+ if (!window || !window.Pusher) {
6539
+ return null;
6540
+ }
6541
+ return new window.Pusher(configToUse.pusherKey, {
6542
+ cluster: 'eu',
6543
+ disableStats: true
6544
+ });
6545
+ };
6546
+
6547
+ // Analytics are logged before the consumer callback runs, so a throwing
6548
+ // callback cannot lose the event.
6549
+ var buildResponseHandler = function buildResponseHandler(_ref) {
6550
+ var context = _ref.context,
6551
+ paymentMethod = _ref.paymentMethod,
6552
+ callback = _ref.callback,
6553
+ teardown = _ref.teardown;
6554
+ return function (response) {
6555
+ var formattedResponse = ChargeResponses.parse(response);
6556
+ context.logAPIResponse(formattedResponse, paymentMethod);
6557
+ callback(formattedResponse, teardown);
6543
6558
  };
6559
+ };
6560
+
6561
+ // The shared listening path for every channel and market. `context` carries the
6562
+ // logAPIResponse analytics function and the isListening flag this path owns.
6563
+ // eslint-disable-next-line consistent-return
6564
+ var subscribeToChargeEvents = function subscribeToChargeEvents(options, context, callback) {
6565
+ var channel = options.channel,
6566
+ paymentMethod = options.paymentMethod;
6567
+ var pusher = createPusherClient();
6568
+ if (!pusher) {
6569
+ return callback(LISTEN_ERRORS.unavailable, noOp);
6570
+ }
6544
6571
  var unsubscribeFromPusher = function unsubscribeFromPusher() {
6545
6572
  pusher.unsubscribe(channel);
6546
6573
  };
6547
- if (!pusher) {
6548
- return callback(pusherUndefinedError, noOp);
6549
- }
6550
6574
  var pusherSubscription = pusher.subscribe(channel);
6551
6575
  pusherSubscription.bind('pusher:subscription_succeeded', function () {
6552
6576
  context.isListening = true;
6553
6577
  });
6554
6578
  pusherSubscription.bind('pusher:subscription_error', function () {
6555
6579
  context.isListening = false;
6556
- callback(pusherSubscriptionError, noOp);
6580
+ callback(LISTEN_ERRORS.subscriptionFailed, noOp);
6557
6581
  });
6558
- pusherSubscription.bind('response', function (response) {
6559
- var formattedResponse = ChargeResponses.parse(response);
6560
- context.logAPIResponse(formattedResponse, paymentMethod);
6561
- callback(formattedResponse, unsubscribeFromPusher);
6582
+ pusherSubscription.bind('response', buildResponseHandler({
6583
+ context: context,
6584
+ paymentMethod: paymentMethod,
6585
+ callback: callback,
6586
+ teardown: unsubscribeFromPusher
6587
+ }));
6588
+ };
6589
+
6590
+ // Dedicated listener for the Ghana mobile money USSD confirmation channel.
6591
+ // Separate from the shared path because this flow needs an unsubscribe before
6592
+ // any event arrives, and because it must not write context.isListening: it runs
6593
+ // alongside the main charge subscription and the two would fight over one flag
6594
+ // on the same transaction.
6595
+ var subscribeToConfirmationEvents = function subscribeToConfirmationEvents(options, context, callback) {
6596
+ var channel = options.channel,
6597
+ paymentMethod = options.paymentMethod;
6598
+ var pusher = createPusherClient();
6599
+ if (!pusher) {
6600
+ callback(LISTEN_ERRORS.unavailable, noOp);
6601
+ return noOp;
6602
+ }
6603
+ var hasUnsubscribed = false;
6604
+ var unsubscribe = function unsubscribe() {
6605
+ if (hasUnsubscribed) {
6606
+ return;
6607
+ }
6608
+ hasUnsubscribed = true;
6609
+ pusher.unsubscribe(channel);
6610
+ pusher.disconnect();
6611
+ };
6612
+ var pusherSubscription = pusher.subscribe(channel);
6613
+ pusherSubscription.bind('pusher:subscription_error', function () {
6614
+ unsubscribe();
6615
+ callback(LISTEN_ERRORS.subscriptionFailed, unsubscribe);
6562
6616
  });
6617
+ pusherSubscription.bind('response', buildResponseHandler({
6618
+ context: context,
6619
+ paymentMethod: paymentMethod,
6620
+ callback: callback,
6621
+ teardown: unsubscribe
6622
+ }));
6623
+ return unsubscribe;
6563
6624
  };
6564
6625
 
6565
6626
  var uncurryThis$7 = functionUncurryThis;
@@ -20386,6 +20447,10 @@ var Paystack = (function (exports) {
20386
20447
  }
20387
20448
  };
20388
20449
 
20450
+ // Charge statuses that leave the transaction with a Pusher channel worth listening on.
20451
+ // `awaiting_ussd_confirmation` is mid-flight, not settled, but it still carries the
20452
+ // `channel_name` the outcome will arrive on.
20453
+ var LISTENABLE_CHARGE_STATUSES = ['success', 'awaiting_ussd_confirmation'];
20389
20454
  function validate$1(phoneNumber) {
20390
20455
  return new Promise(function (resolve, reject) {
20391
20456
  var validation = PhoneNumber.validate(phoneNumber);
@@ -20425,11 +20490,11 @@ var Paystack = (function (exports) {
20425
20490
  mobileMoneyChargeAPI: function mobileMoneyChargeAPI(params) {
20426
20491
  var _this = this;
20427
20492
  return MobileMoneyAPI.charge(params).then(function (response) {
20428
- if (response.status === 'success') {
20493
+ if (LISTENABLE_CHARGE_STATUSES.includes(response.status)) {
20429
20494
  _this.mobileMoney = response;
20430
- if (response.data && response.data.display && response.data.display.otpSentCount === 1) {
20431
- _this.logTokenRequest('mobile money');
20432
- }
20495
+ }
20496
+ if (response.status === 'success' && response.data && response.data.display && response.data.display.otpSentCount === 1) {
20497
+ _this.logTokenRequest('mobile money');
20433
20498
  }
20434
20499
  return response;
20435
20500
  });
@@ -20477,9 +20542,9 @@ var Paystack = (function (exports) {
20477
20542
  deviceFingerprint: _this3.deviceFingerprint
20478
20543
  });
20479
20544
  return MobileMoneyAPI.charge(params).then(function (response) {
20480
- if (response.status === 'success') {
20545
+ if (LISTENABLE_CHARGE_STATUSES.includes(response.status)) {
20481
20546
  _this3.mobileMoney = response;
20482
- if (response.data && response.data.display && response.data.display.otpSentCount === 1) {
20547
+ if (response.status === 'success' && response.data && response.data.display && response.data.display.otpSentCount === 1) {
20483
20548
  _this3.logTokenRequest('mobile money');
20484
20549
  }
20485
20550
  } else if (response.errors && response.errors.data && response.errors.data.status === 'awaiting_registration_token') {
@@ -20502,17 +20567,30 @@ var Paystack = (function (exports) {
20502
20567
  });
20503
20568
  },
20504
20569
  listenForMobileMoneyCharge: function listenForMobileMoneyCharge(callback) {
20505
- if (this.mobileMoney.status !== 'success') {
20570
+ var _ref2 = this.mobileMoney.data || {},
20571
+ channel = _ref2.channel,
20572
+ channelName = _ref2.channel_name;
20573
+ var listenerChannel = channel || channelName;
20574
+ if (!LISTENABLE_CHARGE_STATUSES.includes(this.mobileMoney.status) || !listenerChannel) {
20506
20575
  return Promise.reject(Error('Please start a mobile money charge with Transaction.chargeMobileMoney()'));
20507
20576
  }
20508
- var _this$mobileMoney$dat = this.mobileMoney.data,
20509
- channel = _this$mobileMoney$dat.channel,
20510
- channelName = _this$mobileMoney$dat.channel_name;
20511
20577
  var listenerOptions = {
20512
- channel: channel || channelName,
20578
+ channel: listenerChannel,
20513
20579
  paymentMethod: 'mobile_money'
20514
20580
  };
20515
20581
  return this.listenForCharge(listenerOptions, callback);
20582
+ },
20583
+ listenForMobileMoneyConfirmation: function listenForMobileMoneyConfirmation(callback, pusherChannel) {
20584
+ var data = this.mobileMoney.data;
20585
+ var confirmationChannel = pusherChannel || data && data.confirm_channel_name;
20586
+ if (!confirmationChannel) {
20587
+ throw new Error('Please provide the confirm_channel_name returned by Transaction.chargeMobileMoney()');
20588
+ }
20589
+ var listenerOptions = {
20590
+ channel: confirmationChannel,
20591
+ paymentMethod: 'mobile_money'
20592
+ };
20593
+ return subscribeToConfirmationEvents(listenerOptions, this, callback);
20516
20594
  }
20517
20595
  };
20518
20596
 
package/es/checkout.js CHANGED
@@ -6516,47 +6516,108 @@ var ChargeResponses = {
6516
6516
  };
6517
6517
 
6518
6518
  /* eslint-env browser */
6519
-
6520
- // `context` is passed through to set the class property of `isListening` to true/false
6521
- // and provide the logAPIResponse analytics function
6522
- // eslint-disable-next-line consistent-return, import/prefer-default-export
6523
- var subscribeToChargeEvents = function subscribeToChargeEvents(options, context, callback) {
6524
- var channel = options.channel,
6525
- paymentMethod = options.paymentMethod;
6526
- var pusher;
6527
- if (window && window.Pusher) {
6528
- pusher = new window.Pusher(configToUse.pusherKey, {
6529
- cluster: 'eu',
6530
- disableStats: true
6531
- });
6532
- }
6533
- var pusherUndefinedError = {
6519
+ var LISTEN_ERRORS = {
6520
+ unavailable: {
6534
6521
  status: 'error',
6535
6522
  message: 'We could not listen for charge response.'
6536
- };
6537
- var pusherSubscriptionError = {
6523
+ },
6524
+ subscriptionFailed: {
6538
6525
  status: 'error',
6539
6526
  message: 'We could not listen for charge response. Use transaction.requery() to check the status.'
6527
+ }
6528
+ };
6529
+
6530
+ // Returns null rather than throwing when Pusher is not on the page, so each
6531
+ // listener can choose what to hand its caller back. The `!window` half only
6532
+ // guards against window being declared and assigned undefined; with window
6533
+ // genuinely absent this throws, which is what both paths already did.
6534
+ var createPusherClient = function createPusherClient() {
6535
+ if (!window || !window.Pusher) {
6536
+ return null;
6537
+ }
6538
+ return new window.Pusher(configToUse.pusherKey, {
6539
+ cluster: 'eu',
6540
+ disableStats: true
6541
+ });
6542
+ };
6543
+
6544
+ // Analytics are logged before the consumer callback runs, so a throwing
6545
+ // callback cannot lose the event.
6546
+ var buildResponseHandler = function buildResponseHandler(_ref) {
6547
+ var context = _ref.context,
6548
+ paymentMethod = _ref.paymentMethod,
6549
+ callback = _ref.callback,
6550
+ teardown = _ref.teardown;
6551
+ return function (response) {
6552
+ var formattedResponse = ChargeResponses.parse(response);
6553
+ context.logAPIResponse(formattedResponse, paymentMethod);
6554
+ callback(formattedResponse, teardown);
6540
6555
  };
6556
+ };
6557
+
6558
+ // The shared listening path for every channel and market. `context` carries the
6559
+ // logAPIResponse analytics function and the isListening flag this path owns.
6560
+ // eslint-disable-next-line consistent-return
6561
+ var subscribeToChargeEvents = function subscribeToChargeEvents(options, context, callback) {
6562
+ var channel = options.channel,
6563
+ paymentMethod = options.paymentMethod;
6564
+ var pusher = createPusherClient();
6565
+ if (!pusher) {
6566
+ return callback(LISTEN_ERRORS.unavailable, noOp);
6567
+ }
6541
6568
  var unsubscribeFromPusher = function unsubscribeFromPusher() {
6542
6569
  pusher.unsubscribe(channel);
6543
6570
  };
6544
- if (!pusher) {
6545
- return callback(pusherUndefinedError, noOp);
6546
- }
6547
6571
  var pusherSubscription = pusher.subscribe(channel);
6548
6572
  pusherSubscription.bind('pusher:subscription_succeeded', function () {
6549
6573
  context.isListening = true;
6550
6574
  });
6551
6575
  pusherSubscription.bind('pusher:subscription_error', function () {
6552
6576
  context.isListening = false;
6553
- callback(pusherSubscriptionError, noOp);
6577
+ callback(LISTEN_ERRORS.subscriptionFailed, noOp);
6554
6578
  });
6555
- pusherSubscription.bind('response', function (response) {
6556
- var formattedResponse = ChargeResponses.parse(response);
6557
- context.logAPIResponse(formattedResponse, paymentMethod);
6558
- callback(formattedResponse, unsubscribeFromPusher);
6579
+ pusherSubscription.bind('response', buildResponseHandler({
6580
+ context: context,
6581
+ paymentMethod: paymentMethod,
6582
+ callback: callback,
6583
+ teardown: unsubscribeFromPusher
6584
+ }));
6585
+ };
6586
+
6587
+ // Dedicated listener for the Ghana mobile money USSD confirmation channel.
6588
+ // Separate from the shared path because this flow needs an unsubscribe before
6589
+ // any event arrives, and because it must not write context.isListening: it runs
6590
+ // alongside the main charge subscription and the two would fight over one flag
6591
+ // on the same transaction.
6592
+ var subscribeToConfirmationEvents = function subscribeToConfirmationEvents(options, context, callback) {
6593
+ var channel = options.channel,
6594
+ paymentMethod = options.paymentMethod;
6595
+ var pusher = createPusherClient();
6596
+ if (!pusher) {
6597
+ callback(LISTEN_ERRORS.unavailable, noOp);
6598
+ return noOp;
6599
+ }
6600
+ var hasUnsubscribed = false;
6601
+ var unsubscribe = function unsubscribe() {
6602
+ if (hasUnsubscribed) {
6603
+ return;
6604
+ }
6605
+ hasUnsubscribed = true;
6606
+ pusher.unsubscribe(channel);
6607
+ pusher.disconnect();
6608
+ };
6609
+ var pusherSubscription = pusher.subscribe(channel);
6610
+ pusherSubscription.bind('pusher:subscription_error', function () {
6611
+ unsubscribe();
6612
+ callback(LISTEN_ERRORS.subscriptionFailed, unsubscribe);
6559
6613
  });
6614
+ pusherSubscription.bind('response', buildResponseHandler({
6615
+ context: context,
6616
+ paymentMethod: paymentMethod,
6617
+ callback: callback,
6618
+ teardown: unsubscribe
6619
+ }));
6620
+ return unsubscribe;
6560
6621
  };
6561
6622
 
6562
6623
  var uncurryThis$7 = functionUncurryThis;
@@ -20383,6 +20444,10 @@ var MobileMoneyAPI = {
20383
20444
  }
20384
20445
  };
20385
20446
 
20447
+ // Charge statuses that leave the transaction with a Pusher channel worth listening on.
20448
+ // `awaiting_ussd_confirmation` is mid-flight, not settled, but it still carries the
20449
+ // `channel_name` the outcome will arrive on.
20450
+ var LISTENABLE_CHARGE_STATUSES = ['success', 'awaiting_ussd_confirmation'];
20386
20451
  function validate$1(phoneNumber) {
20387
20452
  return new Promise(function (resolve, reject) {
20388
20453
  var validation = PhoneNumber.validate(phoneNumber);
@@ -20422,11 +20487,11 @@ var MobileMoneyCharge = {
20422
20487
  mobileMoneyChargeAPI: function mobileMoneyChargeAPI(params) {
20423
20488
  var _this = this;
20424
20489
  return MobileMoneyAPI.charge(params).then(function (response) {
20425
- if (response.status === 'success') {
20490
+ if (LISTENABLE_CHARGE_STATUSES.includes(response.status)) {
20426
20491
  _this.mobileMoney = response;
20427
- if (response.data && response.data.display && response.data.display.otpSentCount === 1) {
20428
- _this.logTokenRequest('mobile money');
20429
- }
20492
+ }
20493
+ if (response.status === 'success' && response.data && response.data.display && response.data.display.otpSentCount === 1) {
20494
+ _this.logTokenRequest('mobile money');
20430
20495
  }
20431
20496
  return response;
20432
20497
  });
@@ -20474,9 +20539,9 @@ var MobileMoneyCharge = {
20474
20539
  deviceFingerprint: _this3.deviceFingerprint
20475
20540
  });
20476
20541
  return MobileMoneyAPI.charge(params).then(function (response) {
20477
- if (response.status === 'success') {
20542
+ if (LISTENABLE_CHARGE_STATUSES.includes(response.status)) {
20478
20543
  _this3.mobileMoney = response;
20479
- if (response.data && response.data.display && response.data.display.otpSentCount === 1) {
20544
+ if (response.status === 'success' && response.data && response.data.display && response.data.display.otpSentCount === 1) {
20480
20545
  _this3.logTokenRequest('mobile money');
20481
20546
  }
20482
20547
  } else if (response.errors && response.errors.data && response.errors.data.status === 'awaiting_registration_token') {
@@ -20499,17 +20564,30 @@ var MobileMoneyCharge = {
20499
20564
  });
20500
20565
  },
20501
20566
  listenForMobileMoneyCharge: function listenForMobileMoneyCharge(callback) {
20502
- if (this.mobileMoney.status !== 'success') {
20567
+ var _ref2 = this.mobileMoney.data || {},
20568
+ channel = _ref2.channel,
20569
+ channelName = _ref2.channel_name;
20570
+ var listenerChannel = channel || channelName;
20571
+ if (!LISTENABLE_CHARGE_STATUSES.includes(this.mobileMoney.status) || !listenerChannel) {
20503
20572
  return Promise.reject(Error('Please start a mobile money charge with Transaction.chargeMobileMoney()'));
20504
20573
  }
20505
- var _this$mobileMoney$dat = this.mobileMoney.data,
20506
- channel = _this$mobileMoney$dat.channel,
20507
- channelName = _this$mobileMoney$dat.channel_name;
20508
20574
  var listenerOptions = {
20509
- channel: channel || channelName,
20575
+ channel: listenerChannel,
20510
20576
  paymentMethod: 'mobile_money'
20511
20577
  };
20512
20578
  return this.listenForCharge(listenerOptions, callback);
20579
+ },
20580
+ listenForMobileMoneyConfirmation: function listenForMobileMoneyConfirmation(callback, pusherChannel) {
20581
+ var data = this.mobileMoney.data;
20582
+ var confirmationChannel = pusherChannel || data && data.confirm_channel_name;
20583
+ if (!confirmationChannel) {
20584
+ throw new Error('Please provide the confirm_channel_name returned by Transaction.chargeMobileMoney()');
20585
+ }
20586
+ var listenerOptions = {
20587
+ channel: confirmationChannel,
20588
+ paymentMethod: 'mobile_money'
20589
+ };
20590
+ return subscribeToConfirmationEvents(listenerOptions, this, callback);
20513
20591
  }
20514
20592
  };
20515
20593
 
package/lib/checkout.js CHANGED
@@ -6520,47 +6520,108 @@ var ChargeResponses = {
6520
6520
  };
6521
6521
 
6522
6522
  /* eslint-env browser */
6523
-
6524
- // `context` is passed through to set the class property of `isListening` to true/false
6525
- // and provide the logAPIResponse analytics function
6526
- // eslint-disable-next-line consistent-return, import/prefer-default-export
6527
- var subscribeToChargeEvents = function subscribeToChargeEvents(options, context, callback) {
6528
- var channel = options.channel,
6529
- paymentMethod = options.paymentMethod;
6530
- var pusher;
6531
- if (window && window.Pusher) {
6532
- pusher = new window.Pusher(configToUse.pusherKey, {
6533
- cluster: 'eu',
6534
- disableStats: true
6535
- });
6536
- }
6537
- var pusherUndefinedError = {
6523
+ var LISTEN_ERRORS = {
6524
+ unavailable: {
6538
6525
  status: 'error',
6539
6526
  message: 'We could not listen for charge response.'
6540
- };
6541
- var pusherSubscriptionError = {
6527
+ },
6528
+ subscriptionFailed: {
6542
6529
  status: 'error',
6543
6530
  message: 'We could not listen for charge response. Use transaction.requery() to check the status.'
6531
+ }
6532
+ };
6533
+
6534
+ // Returns null rather than throwing when Pusher is not on the page, so each
6535
+ // listener can choose what to hand its caller back. The `!window` half only
6536
+ // guards against window being declared and assigned undefined; with window
6537
+ // genuinely absent this throws, which is what both paths already did.
6538
+ var createPusherClient = function createPusherClient() {
6539
+ if (!window || !window.Pusher) {
6540
+ return null;
6541
+ }
6542
+ return new window.Pusher(configToUse.pusherKey, {
6543
+ cluster: 'eu',
6544
+ disableStats: true
6545
+ });
6546
+ };
6547
+
6548
+ // Analytics are logged before the consumer callback runs, so a throwing
6549
+ // callback cannot lose the event.
6550
+ var buildResponseHandler = function buildResponseHandler(_ref) {
6551
+ var context = _ref.context,
6552
+ paymentMethod = _ref.paymentMethod,
6553
+ callback = _ref.callback,
6554
+ teardown = _ref.teardown;
6555
+ return function (response) {
6556
+ var formattedResponse = ChargeResponses.parse(response);
6557
+ context.logAPIResponse(formattedResponse, paymentMethod);
6558
+ callback(formattedResponse, teardown);
6544
6559
  };
6560
+ };
6561
+
6562
+ // The shared listening path for every channel and market. `context` carries the
6563
+ // logAPIResponse analytics function and the isListening flag this path owns.
6564
+ // eslint-disable-next-line consistent-return
6565
+ var subscribeToChargeEvents = function subscribeToChargeEvents(options, context, callback) {
6566
+ var channel = options.channel,
6567
+ paymentMethod = options.paymentMethod;
6568
+ var pusher = createPusherClient();
6569
+ if (!pusher) {
6570
+ return callback(LISTEN_ERRORS.unavailable, noOp);
6571
+ }
6545
6572
  var unsubscribeFromPusher = function unsubscribeFromPusher() {
6546
6573
  pusher.unsubscribe(channel);
6547
6574
  };
6548
- if (!pusher) {
6549
- return callback(pusherUndefinedError, noOp);
6550
- }
6551
6575
  var pusherSubscription = pusher.subscribe(channel);
6552
6576
  pusherSubscription.bind('pusher:subscription_succeeded', function () {
6553
6577
  context.isListening = true;
6554
6578
  });
6555
6579
  pusherSubscription.bind('pusher:subscription_error', function () {
6556
6580
  context.isListening = false;
6557
- callback(pusherSubscriptionError, noOp);
6581
+ callback(LISTEN_ERRORS.subscriptionFailed, noOp);
6558
6582
  });
6559
- pusherSubscription.bind('response', function (response) {
6560
- var formattedResponse = ChargeResponses.parse(response);
6561
- context.logAPIResponse(formattedResponse, paymentMethod);
6562
- callback(formattedResponse, unsubscribeFromPusher);
6583
+ pusherSubscription.bind('response', buildResponseHandler({
6584
+ context: context,
6585
+ paymentMethod: paymentMethod,
6586
+ callback: callback,
6587
+ teardown: unsubscribeFromPusher
6588
+ }));
6589
+ };
6590
+
6591
+ // Dedicated listener for the Ghana mobile money USSD confirmation channel.
6592
+ // Separate from the shared path because this flow needs an unsubscribe before
6593
+ // any event arrives, and because it must not write context.isListening: it runs
6594
+ // alongside the main charge subscription and the two would fight over one flag
6595
+ // on the same transaction.
6596
+ var subscribeToConfirmationEvents = function subscribeToConfirmationEvents(options, context, callback) {
6597
+ var channel = options.channel,
6598
+ paymentMethod = options.paymentMethod;
6599
+ var pusher = createPusherClient();
6600
+ if (!pusher) {
6601
+ callback(LISTEN_ERRORS.unavailable, noOp);
6602
+ return noOp;
6603
+ }
6604
+ var hasUnsubscribed = false;
6605
+ var unsubscribe = function unsubscribe() {
6606
+ if (hasUnsubscribed) {
6607
+ return;
6608
+ }
6609
+ hasUnsubscribed = true;
6610
+ pusher.unsubscribe(channel);
6611
+ pusher.disconnect();
6612
+ };
6613
+ var pusherSubscription = pusher.subscribe(channel);
6614
+ pusherSubscription.bind('pusher:subscription_error', function () {
6615
+ unsubscribe();
6616
+ callback(LISTEN_ERRORS.subscriptionFailed, unsubscribe);
6563
6617
  });
6618
+ pusherSubscription.bind('response', buildResponseHandler({
6619
+ context: context,
6620
+ paymentMethod: paymentMethod,
6621
+ callback: callback,
6622
+ teardown: unsubscribe
6623
+ }));
6624
+ return unsubscribe;
6564
6625
  };
6565
6626
 
6566
6627
  var uncurryThis$7 = functionUncurryThis;
@@ -20387,6 +20448,10 @@ var MobileMoneyAPI = {
20387
20448
  }
20388
20449
  };
20389
20450
 
20451
+ // Charge statuses that leave the transaction with a Pusher channel worth listening on.
20452
+ // `awaiting_ussd_confirmation` is mid-flight, not settled, but it still carries the
20453
+ // `channel_name` the outcome will arrive on.
20454
+ var LISTENABLE_CHARGE_STATUSES = ['success', 'awaiting_ussd_confirmation'];
20390
20455
  function validate$1(phoneNumber) {
20391
20456
  return new Promise(function (resolve, reject) {
20392
20457
  var validation = PhoneNumber.validate(phoneNumber);
@@ -20426,11 +20491,11 @@ var MobileMoneyCharge = {
20426
20491
  mobileMoneyChargeAPI: function mobileMoneyChargeAPI(params) {
20427
20492
  var _this = this;
20428
20493
  return MobileMoneyAPI.charge(params).then(function (response) {
20429
- if (response.status === 'success') {
20494
+ if (LISTENABLE_CHARGE_STATUSES.includes(response.status)) {
20430
20495
  _this.mobileMoney = response;
20431
- if (response.data && response.data.display && response.data.display.otpSentCount === 1) {
20432
- _this.logTokenRequest('mobile money');
20433
- }
20496
+ }
20497
+ if (response.status === 'success' && response.data && response.data.display && response.data.display.otpSentCount === 1) {
20498
+ _this.logTokenRequest('mobile money');
20434
20499
  }
20435
20500
  return response;
20436
20501
  });
@@ -20478,9 +20543,9 @@ var MobileMoneyCharge = {
20478
20543
  deviceFingerprint: _this3.deviceFingerprint
20479
20544
  });
20480
20545
  return MobileMoneyAPI.charge(params).then(function (response) {
20481
- if (response.status === 'success') {
20546
+ if (LISTENABLE_CHARGE_STATUSES.includes(response.status)) {
20482
20547
  _this3.mobileMoney = response;
20483
- if (response.data && response.data.display && response.data.display.otpSentCount === 1) {
20548
+ if (response.status === 'success' && response.data && response.data.display && response.data.display.otpSentCount === 1) {
20484
20549
  _this3.logTokenRequest('mobile money');
20485
20550
  }
20486
20551
  } else if (response.errors && response.errors.data && response.errors.data.status === 'awaiting_registration_token') {
@@ -20503,17 +20568,30 @@ var MobileMoneyCharge = {
20503
20568
  });
20504
20569
  },
20505
20570
  listenForMobileMoneyCharge: function listenForMobileMoneyCharge(callback) {
20506
- if (this.mobileMoney.status !== 'success') {
20571
+ var _ref2 = this.mobileMoney.data || {},
20572
+ channel = _ref2.channel,
20573
+ channelName = _ref2.channel_name;
20574
+ var listenerChannel = channel || channelName;
20575
+ if (!LISTENABLE_CHARGE_STATUSES.includes(this.mobileMoney.status) || !listenerChannel) {
20507
20576
  return Promise.reject(Error('Please start a mobile money charge with Transaction.chargeMobileMoney()'));
20508
20577
  }
20509
- var _this$mobileMoney$dat = this.mobileMoney.data,
20510
- channel = _this$mobileMoney$dat.channel,
20511
- channelName = _this$mobileMoney$dat.channel_name;
20512
20578
  var listenerOptions = {
20513
- channel: channel || channelName,
20579
+ channel: listenerChannel,
20514
20580
  paymentMethod: 'mobile_money'
20515
20581
  };
20516
20582
  return this.listenForCharge(listenerOptions, callback);
20583
+ },
20584
+ listenForMobileMoneyConfirmation: function listenForMobileMoneyConfirmation(callback, pusherChannel) {
20585
+ var data = this.mobileMoney.data;
20586
+ var confirmationChannel = pusherChannel || data && data.confirm_channel_name;
20587
+ if (!confirmationChannel) {
20588
+ throw new Error('Please provide the confirm_channel_name returned by Transaction.chargeMobileMoney()');
20589
+ }
20590
+ var listenerOptions = {
20591
+ channel: confirmationChannel,
20592
+ paymentMethod: 'mobile_money'
20593
+ };
20594
+ return subscribeToConfirmationEvents(listenerOptions, this, callback);
20517
20595
  }
20518
20596
  };
20519
20597
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paystack/checkout-js",
3
- "version": "1.57.0-beta.5",
3
+ "version": "1.57.0-beta.6",
4
4
  "description": "Client-side JS library for billing on Paystack",
5
5
  "main": "lib/checkout.js",
6
6
  "module": "es/checkout.js",