@stripe/stripe-react-native 0.70.0 → 0.72.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.
Files changed (168) hide show
  1. package/android/gradle.properties +1 -1
  2. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorElementView.kt +7 -103
  3. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorElementViewManager.kt +1 -5
  4. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementView.kt +0 -26
  5. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementViewManager.kt +6 -21
  6. package/android/src/main/java/com/reactnativestripesdk/LinkControllerManager.kt +59 -18
  7. package/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt +22 -0
  8. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetManager.kt +6 -50
  9. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +38 -187
  10. package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +4 -0
  11. package/android/src/oldarch/java/com/reactnativestripesdk/NativeStripeSdkModuleSpec.java +4 -0
  12. package/android/src/onramp/java/com/reactnativestripesdk/OnrampMappers.kt +1 -0
  13. package/android/src/test/java/com/reactnativestripesdk/mappers/MappersTest.kt +10 -60
  14. package/ios/CurrencySelectorElementView.swift +18 -129
  15. package/ios/Mappers.swift +4 -0
  16. package/ios/PaymentMethodFactory.swift +22 -0
  17. package/ios/StripeSdk.mm +7 -0
  18. package/ios/StripeSdkImpl+Checkout.swift +35 -259
  19. package/ios/StripeSdkImpl+Embedded.swift +5 -28
  20. package/ios/StripeSdkImpl+LinkController.swift +40 -2
  21. package/ios/StripeSdkImpl+PaymentSheet.swift +2 -15
  22. package/ios/StripeSdkImpl.swift +2 -4
  23. package/lib/commonjs/components/AddToWalletButton.js +1 -1
  24. package/lib/commonjs/components/AddToWalletButton.js.map +1 -1
  25. package/lib/commonjs/components/AddressSheet.js +1 -1
  26. package/lib/commonjs/components/AddressSheet.js.map +1 -1
  27. package/lib/commonjs/components/AuBECSDebitForm.js +1 -1
  28. package/lib/commonjs/components/AuBECSDebitForm.js.map +1 -1
  29. package/lib/commonjs/components/CardField.js +1 -1
  30. package/lib/commonjs/components/CardField.js.map +1 -1
  31. package/lib/commonjs/components/CardForm.js +1 -1
  32. package/lib/commonjs/components/CardForm.js.map +1 -1
  33. package/lib/commonjs/components/CurrencySelectorElement.js +1 -1
  34. package/lib/commonjs/components/CurrencySelectorElement.js.map +1 -1
  35. package/lib/commonjs/components/PaymentMethodMessagingElement.js +1 -1
  36. package/lib/commonjs/components/PaymentMethodMessagingElement.js.map +1 -1
  37. package/lib/commonjs/components/PlatformPayButton.js +1 -1
  38. package/lib/commonjs/components/PlatformPayButton.js.map +1 -1
  39. package/lib/commonjs/components/StripeContainer.js +1 -1
  40. package/lib/commonjs/components/StripeContainer.js.map +1 -1
  41. package/lib/commonjs/connect/Components.js +1 -1
  42. package/lib/commonjs/connect/Components.js.map +1 -1
  43. package/lib/commonjs/connect/ConnectComponentsProvider.js +1 -1
  44. package/lib/commonjs/connect/ConnectComponentsProvider.js.map +1 -1
  45. package/lib/commonjs/connect/EmbeddedComponent.js +2 -2
  46. package/lib/commonjs/connect/EmbeddedComponent.js.map +1 -1
  47. package/lib/commonjs/connect/ModalCloseButton.js +1 -1
  48. package/lib/commonjs/connect/ModalCloseButton.js.map +1 -1
  49. package/lib/commonjs/connect/NavigationBar.js +1 -1
  50. package/lib/commonjs/connect/NavigationBar.js.map +1 -1
  51. package/lib/commonjs/functions.js +1 -1
  52. package/lib/commonjs/functions.js.map +1 -1
  53. package/lib/commonjs/helpers.js +1 -1
  54. package/lib/commonjs/hooks/useLinkController.js +1 -1
  55. package/lib/commonjs/hooks/useLinkController.js.map +1 -1
  56. package/lib/commonjs/specs/NativeAddToWalletButton.js +1 -1
  57. package/lib/commonjs/specs/NativeAddressSheet.js +1 -1
  58. package/lib/commonjs/specs/NativeApplePayButton.js +1 -1
  59. package/lib/commonjs/specs/NativeAuBECSDebitForm.js +1 -1
  60. package/lib/commonjs/specs/NativeCardField.js +1 -1
  61. package/lib/commonjs/specs/NativeCardField.js.map +1 -1
  62. package/lib/commonjs/specs/NativeCardForm.js +1 -1
  63. package/lib/commonjs/specs/NativeCardForm.js.map +1 -1
  64. package/lib/commonjs/specs/NativeConnectAccountOnboardingView.js +1 -1
  65. package/lib/commonjs/specs/NativeCurrencySelectorElement.js +1 -1
  66. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js +1 -1
  67. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  68. package/lib/commonjs/specs/NativeGooglePayButton.js +1 -1
  69. package/lib/commonjs/specs/NativeNavigationBar.js +1 -1
  70. package/lib/commonjs/specs/NativePaymentMethodMessagingElement.js +1 -1
  71. package/lib/commonjs/specs/NativeStripeContainer.js +1 -1
  72. package/lib/commonjs/specs/NativeStripeSdkModule.js.map +1 -1
  73. package/lib/commonjs/types/EmbeddedPaymentElement.js +1 -1
  74. package/lib/commonjs/types/EmbeddedPaymentElement.js.map +1 -1
  75. package/lib/commonjs/types/PaymentIntent.js.map +1 -1
  76. package/lib/module/components/AddToWalletButton.js +1 -1
  77. package/lib/module/components/AddToWalletButton.js.map +1 -1
  78. package/lib/module/components/AddressSheet.js +1 -1
  79. package/lib/module/components/AddressSheet.js.map +1 -1
  80. package/lib/module/components/AuBECSDebitForm.js +1 -1
  81. package/lib/module/components/AuBECSDebitForm.js.map +1 -1
  82. package/lib/module/components/CardField.js +1 -1
  83. package/lib/module/components/CardField.js.map +1 -1
  84. package/lib/module/components/CardForm.js +1 -1
  85. package/lib/module/components/CardForm.js.map +1 -1
  86. package/lib/module/components/CurrencySelectorElement.js +1 -1
  87. package/lib/module/components/CurrencySelectorElement.js.map +1 -1
  88. package/lib/module/components/PaymentMethodMessagingElement.js +1 -1
  89. package/lib/module/components/PaymentMethodMessagingElement.js.map +1 -1
  90. package/lib/module/components/PlatformPayButton.js +1 -1
  91. package/lib/module/components/PlatformPayButton.js.map +1 -1
  92. package/lib/module/components/StripeContainer.js +1 -1
  93. package/lib/module/components/StripeContainer.js.map +1 -1
  94. package/lib/module/connect/Components.js +1 -1
  95. package/lib/module/connect/Components.js.map +1 -1
  96. package/lib/module/connect/ConnectComponentsProvider.js +1 -1
  97. package/lib/module/connect/ConnectComponentsProvider.js.map +1 -1
  98. package/lib/module/connect/EmbeddedComponent.js +2 -2
  99. package/lib/module/connect/EmbeddedComponent.js.map +1 -1
  100. package/lib/module/connect/ModalCloseButton.js +1 -1
  101. package/lib/module/connect/ModalCloseButton.js.map +1 -1
  102. package/lib/module/connect/NavigationBar.js +1 -1
  103. package/lib/module/connect/NavigationBar.js.map +1 -1
  104. package/lib/module/functions.js +1 -1
  105. package/lib/module/functions.js.map +1 -1
  106. package/lib/module/helpers.js +1 -1
  107. package/lib/module/hooks/useLinkController.js +1 -1
  108. package/lib/module/hooks/useLinkController.js.map +1 -1
  109. package/lib/module/specs/NativeAddToWalletButton.js +1 -1
  110. package/lib/module/specs/NativeAddressSheet.js +1 -1
  111. package/lib/module/specs/NativeApplePayButton.js +1 -1
  112. package/lib/module/specs/NativeAuBECSDebitForm.js +1 -1
  113. package/lib/module/specs/NativeCardField.js +1 -1
  114. package/lib/module/specs/NativeCardField.js.map +1 -1
  115. package/lib/module/specs/NativeCardForm.js +1 -1
  116. package/lib/module/specs/NativeCardForm.js.map +1 -1
  117. package/lib/module/specs/NativeConnectAccountOnboardingView.js +1 -1
  118. package/lib/module/specs/NativeCurrencySelectorElement.js +1 -1
  119. package/lib/module/specs/NativeEmbeddedPaymentElement.js +1 -1
  120. package/lib/module/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  121. package/lib/module/specs/NativeGooglePayButton.js +1 -1
  122. package/lib/module/specs/NativeNavigationBar.js +1 -1
  123. package/lib/module/specs/NativePaymentMethodMessagingElement.js +1 -1
  124. package/lib/module/specs/NativeStripeContainer.js +1 -1
  125. package/lib/module/specs/NativeStripeSdkModule.js.map +1 -1
  126. package/lib/module/types/EmbeddedPaymentElement.js +1 -1
  127. package/lib/module/types/EmbeddedPaymentElement.js.map +1 -1
  128. package/lib/module/types/PaymentIntent.js.map +1 -1
  129. package/lib/typescript/src/connect/EmbeddedComponent.d.ts +1 -0
  130. package/lib/typescript/src/connect/EmbeddedComponent.d.ts.map +1 -1
  131. package/lib/typescript/src/functions.d.ts +11 -0
  132. package/lib/typescript/src/functions.d.ts.map +1 -1
  133. package/lib/typescript/src/hooks/useLinkController.d.ts +7 -0
  134. package/lib/typescript/src/hooks/useLinkController.d.ts.map +1 -1
  135. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts +4 -0
  136. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts.map +1 -1
  137. package/lib/typescript/src/types/LinkController.d.ts +10 -5
  138. package/lib/typescript/src/types/LinkController.d.ts.map +1 -1
  139. package/lib/typescript/src/types/PaymentIntent.d.ts +17 -1
  140. package/lib/typescript/src/types/PaymentIntent.d.ts.map +1 -1
  141. package/lib/typescript/src/types/PaymentMethod.d.ts +1 -1
  142. package/lib/typescript/src/types/PaymentMethod.d.ts.map +1 -1
  143. package/package.json +1 -1
  144. package/src/connect/EmbeddedComponent.tsx +14 -2
  145. package/src/functions.ts +26 -0
  146. package/src/hooks/useLinkController.tsx +24 -1
  147. package/src/specs/NativeStripeSdkModule.ts +5 -0
  148. package/src/types/LinkController.ts +9 -5
  149. package/src/types/PaymentIntent.ts +21 -1
  150. package/src/types/PaymentMethod.ts +1 -0
  151. package/stripe-react-native.podspec +1 -1
  152. package/android/.idea/AndroidProjectSystem.xml +0 -6
  153. package/android/.idea/caches/deviceStreaming.xml +0 -835
  154. package/android/.idea/compiler.xml +0 -6
  155. package/android/.idea/gradle.xml +0 -17
  156. package/android/.idea/migrations.xml +0 -10
  157. package/android/.idea/misc.xml +0 -10
  158. package/android/.idea/runConfigurations.xml +0 -17
  159. package/android/.idea/vcs.xml +0 -6
  160. package/android/local.properties +0 -8
  161. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorAppearance.kt +0 -229
  162. package/android/src/main/java/com/reactnativestripesdk/utils/CheckoutAddressUpdate.kt +0 -45
  163. package/android/src/main/java/com/reactnativestripesdk/utils/CheckoutMappers.kt +0 -127
  164. package/android/src/test/java/com/reactnativestripesdk/CurrencySelectorAppearanceTest.kt +0 -137
  165. package/android/src/test/java/com/reactnativestripesdk/utils/CheckoutMappersTest.kt +0 -98
  166. package/android/src/test/java/com/reactnativestripesdk/utils/CheckoutTestFixtures.java +0 -57
  167. package/ios/CurrencySelectorAppearance.swift +0 -120
  168. package/ios/Mappers+Checkout.swift +0 -337
@@ -36,7 +36,6 @@ import com.reactnativestripesdk.utils.GooglePayErrorType
36
36
  import com.reactnativestripesdk.utils.RetrievePaymentIntentErrorType
37
37
  import com.reactnativestripesdk.utils.RetrieveSetupIntentErrorType
38
38
  import com.reactnativestripesdk.utils.StripeUIManager
39
- import com.reactnativestripesdk.utils.buildCheckoutAddressUpdate
40
39
  import com.reactnativestripesdk.utils.createCanAddCardResult
41
40
  import com.reactnativestripesdk.utils.createError
42
41
  import com.reactnativestripesdk.utils.createMissingActivityError
@@ -46,7 +45,6 @@ import com.reactnativestripesdk.utils.getBooleanOr
46
45
  import com.reactnativestripesdk.utils.getIntOrNull
47
46
  import com.reactnativestripesdk.utils.getLongOrNull
48
47
  import com.reactnativestripesdk.utils.getValOr
49
- import com.reactnativestripesdk.utils.mapFromCheckoutState
50
48
  import com.reactnativestripesdk.utils.mapFromPaymentIntentResult
51
49
  import com.reactnativestripesdk.utils.mapFromPaymentMethod
52
50
  import com.reactnativestripesdk.utils.mapFromSetupIntentResult
@@ -57,13 +55,11 @@ import com.reactnativestripesdk.utils.mapToPaymentMethodType
57
55
  import com.reactnativestripesdk.utils.mapToReturnURL
58
56
  import com.reactnativestripesdk.utils.mapToShippingDetails
59
57
  import com.reactnativestripesdk.utils.mapToUICustomization
60
- import com.reactnativestripesdk.utils.toCheckoutAddress
61
58
  import com.stripe.android.ApiResultCallback
62
59
  import com.stripe.android.GooglePayJsonFactory
63
60
  import com.stripe.android.PaymentAuthConfig
64
61
  import com.stripe.android.PaymentConfiguration
65
62
  import com.stripe.android.Stripe
66
- import com.stripe.android.checkout.Checkout
67
63
  import com.stripe.android.core.ApiVersion
68
64
  import com.stripe.android.core.AppInfo
69
65
  import com.stripe.android.core.reactnative.ReactNativeAnalytics
@@ -79,23 +75,26 @@ import com.stripe.android.model.PaymentMethod
79
75
  import com.stripe.android.model.RadarSession
80
76
  import com.stripe.android.model.SetupIntent
81
77
  import com.stripe.android.model.Token
82
- import com.stripe.android.paymentelement.CheckoutSessionPreview
83
78
  import com.stripe.android.payments.bankaccount.CollectBankAccountConfiguration
84
79
  import com.stripe.android.paymentsheet.PaymentSheet
85
- import kotlinx.coroutines.CancellableContinuation
86
80
  import kotlinx.coroutines.CompletableDeferred
87
81
  import kotlinx.coroutines.CoroutineScope
88
82
  import kotlinx.coroutines.Dispatchers
89
- import kotlinx.coroutines.Job
90
- import kotlinx.coroutines.flow.combine
91
- import kotlinx.coroutines.flow.distinctUntilChanged
92
83
  import kotlinx.coroutines.launch
93
- import kotlinx.coroutines.suspendCancellableCoroutine
94
84
  import org.json.JSONObject
95
- import java.util.UUID
85
+
86
+ internal const val CHECKOUT_UNAVAILABLE_MESSAGE =
87
+ "Checkout Sessions are temporarily unavailable while the native integration is being rebuilt."
88
+
89
+ private fun rejectCheckoutUnavailable(promise: Promise) {
90
+ promise.reject(ErrorType.Failed.toString(), CHECKOUT_UNAVAILABLE_MESSAGE)
91
+ }
92
+
93
+ internal fun createCheckoutUnavailableError(): WritableMap =
94
+ createError(ErrorType.Failed.toString(), CHECKOUT_UNAVAILABLE_MESSAGE)
96
95
 
97
96
  @ReactModule(name = StripeSdkModule.NAME)
98
- @OptIn(ReactNativeSdkInternal::class, CheckoutSessionPreview::class)
97
+ @OptIn(ReactNativeSdkInternal::class)
99
98
  class StripeSdkModule(
100
99
  reactContext: ReactApplicationContext,
101
100
  ) : NativeStripeSdkModuleSpec(reactContext) {
@@ -117,15 +116,6 @@ class StripeSdkModule(
117
116
  private var financialConnectionsSheetManager: FinancialConnectionsSheetManager? = null
118
117
  private var googlePayLauncherManager: GooglePayLauncherManager? = null
119
118
  private var googlePayPaymentMethodLauncherManager: GooglePayPaymentMethodLauncherManager? = null
120
- internal val checkoutInstances = mutableMapOf<String, Checkout>()
121
- private val serverUpdateContinuations =
122
- mutableMapOf<String, CancellableContinuation<Result<Unit>>>()
123
-
124
- // / Tracks the long-running coroutine that observes each Checkout's
125
- // / `checkoutSession` + `isLoading` flows and forwards transitions to JS as
126
- // / `checkoutSessionDidChangeState` events.
127
- private val checkoutStateObservers = mutableMapOf<String, Job>()
128
-
129
119
  private var customerSheetManager: CustomerSheetManager? = null
130
120
  private var linkControllerManager: LinkControllerManager? = null
131
121
 
@@ -178,9 +168,6 @@ class StripeSdkModule(
178
168
 
179
169
  stripeUIManagers.forEach { it.destroy() }
180
170
  stripeUIManagers.clear()
181
- checkoutStateObservers.values.forEach { it.cancel() }
182
- checkoutStateObservers.clear()
183
- checkoutInstances.clear()
184
171
  linkControllerManager?.destroy()
185
172
  linkControllerManager = null
186
173
  }
@@ -303,7 +290,7 @@ class StripeSdkModule(
303
290
  }
304
291
  } else {
305
292
  paymentSheetManager =
306
- PaymentSheetManager(reactApplicationContext, params, promise, checkoutInstances).also {
293
+ PaymentSheetManager(reactApplicationContext, params, promise).also {
307
294
  registerStripeUIManager(it)
308
295
  }
309
296
  }
@@ -1746,35 +1733,7 @@ class StripeSdkModule(
1746
1733
  configuration: ReadableMap,
1747
1734
  promise: Promise,
1748
1735
  ) {
1749
- val checkoutConfiguration = buildCheckoutConfiguration(configuration)
1750
-
1751
- CoroutineScope(Dispatchers.Main).launch {
1752
- Checkout.configure(
1753
- context = reactApplicationContext,
1754
- checkoutSessionClientSecret = clientSecret,
1755
- configuration = checkoutConfiguration,
1756
- ).fold(
1757
- onSuccess = { checkout ->
1758
- val sessionKey = UUID.randomUUID().toString()
1759
- checkoutInstances[sessionKey] = checkout
1760
- observeCheckoutState(sessionKey, checkout)
1761
-
1762
- promise.resolve(
1763
- Arguments.createMap().apply {
1764
- putString("sessionKey", sessionKey)
1765
- putMap("state", mapFromCheckoutState(checkout))
1766
- },
1767
- )
1768
- },
1769
- onFailure = { error ->
1770
- promise.reject(
1771
- ErrorType.Failed.toString(),
1772
- error.message ?: "Failed to initialize checkout session.",
1773
- error,
1774
- )
1775
- },
1776
- )
1777
- }
1736
+ rejectCheckoutUnavailable(promise)
1778
1737
  }
1779
1738
 
1780
1739
  override fun checkoutUpdateShippingAddress(
@@ -1784,21 +1743,7 @@ class StripeSdkModule(
1784
1743
  phone: String?,
1785
1744
  promise: Promise,
1786
1745
  ) {
1787
- val addressUpdate = buildCheckoutAddressUpdate(name, phone, address) ?: run {
1788
- promise.reject(ErrorType.Failed.toString(), "A shipping address country is required.")
1789
- return
1790
- }
1791
-
1792
- performCheckoutMutation(
1793
- sessionKey = sessionKey,
1794
- promise = promise,
1795
- ) { checkout ->
1796
- checkout.updateShippingAddress(
1797
- name = addressUpdate.name,
1798
- phoneNumber = addressUpdate.phone,
1799
- address = addressUpdate.toCheckoutAddress(),
1800
- )
1801
- }
1746
+ rejectCheckoutUnavailable(promise)
1802
1747
  }
1803
1748
 
1804
1749
  override fun checkoutApplyPromotionCode(
@@ -1806,18 +1751,14 @@ class StripeSdkModule(
1806
1751
  code: String,
1807
1752
  promise: Promise,
1808
1753
  ) {
1809
- performCheckoutMutation(sessionKey, promise) { checkout ->
1810
- checkout.applyPromotionCode(code)
1811
- }
1754
+ rejectCheckoutUnavailable(promise)
1812
1755
  }
1813
1756
 
1814
1757
  override fun checkoutRemovePromotionCode(
1815
1758
  sessionKey: String,
1816
1759
  promise: Promise,
1817
1760
  ) {
1818
- performCheckoutMutation(sessionKey, promise) { checkout ->
1819
- checkout.removePromotionCode()
1820
- }
1761
+ rejectCheckoutUnavailable(promise)
1821
1762
  }
1822
1763
 
1823
1764
  override fun checkoutUpdateLineItemQuantity(
@@ -1826,14 +1767,7 @@ class StripeSdkModule(
1826
1767
  quantity: Double,
1827
1768
  promise: Promise,
1828
1769
  ) {
1829
- if (!quantity.isFinite() || quantity % 1.0 != 0.0) {
1830
- promise.reject(ErrorType.Failed.toString(), "Line item quantity must be an integer.")
1831
- return
1832
- }
1833
-
1834
- performCheckoutMutation(sessionKey, promise) { checkout ->
1835
- checkout.updateLineItemQuantity(lineItemId = lineItemId, quantity = quantity.toInt())
1836
- }
1770
+ rejectCheckoutUnavailable(promise)
1837
1771
  }
1838
1772
 
1839
1773
  override fun checkoutSelectShippingOption(
@@ -1841,35 +1775,14 @@ class StripeSdkModule(
1841
1775
  id: String,
1842
1776
  promise: Promise,
1843
1777
  ) {
1844
- performCheckoutMutation(sessionKey, promise) { checkout ->
1845
- checkout.selectShippingOption(id)
1846
- }
1778
+ rejectCheckoutUnavailable(promise)
1847
1779
  }
1848
1780
 
1849
1781
  override fun checkoutRunServerUpdateStart(
1850
1782
  sessionKey: String,
1851
1783
  promise: Promise,
1852
1784
  ) {
1853
- val checkout = checkoutInstances[sessionKey] ?: run {
1854
- promise.reject(ErrorType.Failed.toString(), "Checkout session not found.")
1855
- return
1856
- }
1857
-
1858
- if (serverUpdateContinuations.containsKey(sessionKey)) {
1859
- promise.reject(ErrorType.Failed.toString(), "A server update is already in progress for this session.")
1860
- return
1861
- }
1862
-
1863
- CoroutineScope(Dispatchers.Main).launch {
1864
- checkout.runServerUpdate {
1865
- suspendCancellableCoroutine { continuation ->
1866
- serverUpdateContinuations[sessionKey] = continuation
1867
- }
1868
- }.fold(
1869
- onSuccess = { promise.resolve(mapFromCheckoutState(checkout)) },
1870
- onFailure = { promise.reject(ErrorType.Failed.toString(), it.message, it) },
1871
- )
1872
- }
1785
+ rejectCheckoutUnavailable(promise)
1873
1786
  }
1874
1787
 
1875
1788
  override fun checkoutRunServerUpdateComplete(
@@ -1877,87 +1790,7 @@ class StripeSdkModule(
1877
1790
  error: String?,
1878
1791
  promise: Promise,
1879
1792
  ) {
1880
- val continuation = serverUpdateContinuations.remove(sessionKey) ?: run {
1881
- promise.reject(ErrorType.Failed.toString(), "No pending server update for this session.")
1882
- return
1883
- }
1884
-
1885
- if (error != null) {
1886
- continuation.resume(Result.failure(Exception(error))) {}
1887
- } else {
1888
- continuation.resume(Result.success(Unit)) {}
1889
- }
1890
- promise.resolve(null)
1891
- }
1892
-
1893
- private fun buildCheckoutConfiguration(configuration: ReadableMap): Checkout.Configuration {
1894
- val checkoutConfiguration = Checkout.Configuration()
1895
- val adaptivePricing = configuration.getMap("adaptivePricing")
1896
- if (adaptivePricing?.hasKey("allowed") == true) {
1897
- checkoutConfiguration.adaptivePricingAllowed(adaptivePricing.getBooleanOr("allowed", false))
1898
- }
1899
- return checkoutConfiguration
1900
- }
1901
-
1902
- /**
1903
- * Forwards the checkout's `(checkoutSession, isLoading)` flow to JS as
1904
- * `checkoutSessionDidChangeState` events. Equivalent to the iOS
1905
- * `CheckoutDelegate` bridge — every native-side mutation (currency selection,
1906
- * promo code, refresh, etc.) goes through one canonical channel that
1907
- * `useCheckout` listens to.
1908
- */
1909
- private fun observeCheckoutState(
1910
- sessionKey: String,
1911
- checkout: Checkout,
1912
- ) {
1913
- checkoutStateObservers[sessionKey]?.cancel()
1914
-
1915
- val job = CoroutineScope(Dispatchers.Main).launch {
1916
- // `combine` re-emits on every upstream tick. `distinctUntilChanged`
1917
- // collapses runs where neither field actually moved — both flows are
1918
- // StateFlows so we'd otherwise see a redundant initial replay when
1919
- // wiring up.
1920
- combine(
1921
- checkout.checkoutSession,
1922
- checkout.isLoading,
1923
- ) { session, isLoading -> session to isLoading }
1924
- .distinctUntilChanged()
1925
- .collect {
1926
- eventEmitter.emitCheckoutSessionDidChangeState(
1927
- Arguments.createMap().apply {
1928
- putString("sessionKey", sessionKey)
1929
- putMap("state", mapFromCheckoutState(checkout))
1930
- },
1931
- )
1932
- }
1933
- }
1934
- checkoutStateObservers[sessionKey] = job
1935
- }
1936
-
1937
- private fun performCheckoutMutation(
1938
- sessionKey: String,
1939
- promise: Promise,
1940
- operation: suspend (Checkout) -> Result<Unit>,
1941
- ) {
1942
- val checkout = checkoutInstances[sessionKey] ?: run {
1943
- promise.reject(ErrorType.Failed.toString(), "Checkout session not found.")
1944
- return
1945
- }
1946
-
1947
- CoroutineScope(Dispatchers.Main).launch {
1948
- operation(checkout).fold(
1949
- onSuccess = {
1950
- promise.resolve(mapFromCheckoutState(checkout))
1951
- },
1952
- onFailure = { error ->
1953
- promise.reject(
1954
- ErrorType.Failed.toString(),
1955
- error.message ?: "Checkout operation failed.",
1956
- error,
1957
- )
1958
- },
1959
- )
1960
- }
1793
+ rejectCheckoutUnavailable(promise)
1961
1794
  }
1962
1795
 
1963
1796
  /**
@@ -2031,6 +1864,24 @@ class StripeSdkModule(
2031
1864
  }
2032
1865
  }
2033
1866
 
1867
+ @ReactMethod
1868
+ override fun confirmLinkControllerSetupIntent(
1869
+ params: ReadableMap,
1870
+ promise: Promise,
1871
+ ) {
1872
+ val manager = linkControllerManager
1873
+ if (manager == null) {
1874
+ promise.resolve(createError(ErrorType.Failed.toString(), LINK_CONTROLLER_NOT_INITIALIZED_ERROR))
1875
+ return
1876
+ }
1877
+ val clientSecret = params.getString("clientSecret")
1878
+ if (clientSecret == null) {
1879
+ promise.resolve(createError(ErrorType.Failed.toString(), "clientSecret is required."))
1880
+ return
1881
+ }
1882
+ manager.confirmSetupIntent(clientSecret, promise)
1883
+ }
1884
+
2034
1885
  /**
2035
1886
  * React native apps do not properly handle activity re-creation so make
2036
1887
  * sure to dismiss any stripe ui when that happens to make sure apps stay
@@ -151,6 +151,8 @@ internal fun mapPaymentMethodType(type: PaymentMethod.Type?): String =
151
151
  PaymentMethod.Type.Affirm -> "Affirm"
152
152
  PaymentMethod.Type.CashAppPay -> "CashApp"
153
153
  PaymentMethod.Type.RevolutPay -> "RevolutPay"
154
+ PaymentMethod.Type.PayByBank -> "PayByBank"
155
+ PaymentMethod.Type.Twint -> "Twint"
154
156
  PaymentMethod.Type.Link -> "Link"
155
157
  else -> "Unknown"
156
158
  }
@@ -182,6 +184,8 @@ internal fun mapToPaymentMethodType(type: String?): PaymentMethod.Type? =
182
184
  "Affirm" -> PaymentMethod.Type.Affirm
183
185
  "CashApp" -> PaymentMethod.Type.CashAppPay
184
186
  "RevolutPay" -> PaymentMethod.Type.RevolutPay
187
+ "PayByBank" -> PaymentMethod.Type.PayByBank
188
+ "Twint" -> PaymentMethod.Type.Twint
185
189
  "Link" -> PaymentMethod.Type.Link
186
190
  else -> null
187
191
  }
@@ -337,6 +337,10 @@ public abstract class NativeStripeSdkModuleSpec extends ReactContextBaseJavaModu
337
337
  @DoNotStrip
338
338
  public abstract void presentLinkController(Promise promise);
339
339
 
340
+ @ReactMethod
341
+ @DoNotStrip
342
+ public abstract void confirmLinkControllerSetupIntent(ReadableMap params, Promise promise);
343
+
340
344
  @ReactMethod
341
345
  @DoNotStrip
342
346
  public abstract void addListener(String eventType);
@@ -333,6 +333,7 @@ private fun mapFromComplianceIdentifierTypes(
333
333
  }
334
334
  }
335
335
 
336
+ @SuppressLint("RestrictedApi")
336
337
  private fun mapFromCountryCodes(
337
338
  countryCodes: List<CountryCode>,
338
339
  ): WritableArray =
@@ -2,7 +2,6 @@ package com.reactnativestripesdk.mappers
2
2
 
3
3
  import android.annotation.SuppressLint
4
4
  import com.facebook.react.bridge.WritableMap
5
- import com.reactnativestripesdk.utils.buildCheckoutAddressUpdate
6
5
  import com.reactnativestripesdk.utils.createCanAddCardResult
7
6
  import com.reactnativestripesdk.utils.mapNextAction
8
7
  import com.reactnativestripesdk.utils.mapPaymentMethodType
@@ -96,6 +95,16 @@ class MappersTest {
96
95
  assertEquals(PaymentMethod.Type.Multibanco, mapToPaymentMethodType("Multibanco"))
97
96
  }
98
97
 
98
+ @Test
99
+ fun mapPaymentMethodType_PayByBank_ReturnsString() {
100
+ assertEquals("PayByBank", mapPaymentMethodType(PaymentMethod.Type.PayByBank))
101
+ }
102
+
103
+ @Test
104
+ fun mapToPaymentMethodType_PayByBank_ReturnsType() {
105
+ assertEquals(PaymentMethod.Type.PayByBank, mapToPaymentMethodType("PayByBank"))
106
+ }
107
+
99
108
  @Test
100
109
  fun mapNextAction_DisplayMultibancoDetails_ReturnsVoucherUrl() {
101
110
  val result =
@@ -349,65 +358,6 @@ class MappersTest {
349
358
  assertEquals("cpmt_valid", result[0].id)
350
359
  }
351
360
 
352
- // ============================================
353
- // buildCheckoutAddressUpdate Tests
354
- // ============================================
355
-
356
- @Test
357
- fun buildCheckoutAddressUpdate_TrimsFields() {
358
- val update =
359
- buildCheckoutAddressUpdate(
360
- name = " Jane Doe ",
361
- phone = " 5551234567 ",
362
- address =
363
- readableMapOf(
364
- "country" to " US ",
365
- "line1" to " 123 Main St ",
366
- "line2" to " Apt 4 ",
367
- "city" to " San Francisco ",
368
- "state" to " CA ",
369
- "postalCode" to " 94111 ",
370
- ),
371
- )
372
-
373
- assertNotNull(update)
374
- assertEquals("Jane Doe", update!!.name)
375
- assertEquals("5551234567", update.phone)
376
- assertEquals("US", update.country)
377
- assertEquals("123 Main St", update.line1)
378
- assertEquals("Apt 4", update.line2)
379
- assertEquals("San Francisco", update.city)
380
- assertEquals("CA", update.state)
381
- assertEquals("94111", update.postalCode)
382
- }
383
-
384
- @Test
385
- fun buildCheckoutAddressUpdate_RequiresCountry() {
386
- val withoutCountry =
387
- buildCheckoutAddressUpdate(
388
- name = "Jane Doe",
389
- phone = "5551234567",
390
- address =
391
- readableMapOf(
392
- "line1" to "123 Main St",
393
- "city" to "San Francisco",
394
- ),
395
- )
396
-
397
- val blankCountry =
398
- buildCheckoutAddressUpdate(
399
- name = "Jane Doe",
400
- phone = "5551234567",
401
- address =
402
- readableMapOf(
403
- "country" to " ",
404
- ),
405
- )
406
-
407
- assertNull(withoutCountry)
408
- assertNull(blankCountry)
409
- }
410
-
411
361
  // ============================================
412
362
  // mapToAddress Tests
413
363
  // ============================================
@@ -5,65 +5,34 @@
5
5
  // Created by Nick Porter on 5/7/26.
6
6
  //
7
7
 
8
- import Combine
9
8
  import Foundation
10
- @_spi(ReactNativeSDK) import StripePaymentSheet
11
9
  import UIKit
12
10
 
13
11
  @objc(StripeCurrencySelectorElementManager)
14
12
  class StripeCurrencySelectorElementManager: RCTViewManager {
15
13
  override static func requiresMainQueueSetup() -> Bool {
16
- return true
14
+ true
17
15
  }
18
16
 
19
17
  override func view() -> UIView! {
20
- return StripeCurrencySelectorElementContainerView(frame: .zero)
18
+ StripeCurrencySelectorElementContainerView(frame: .zero)
21
19
  }
22
20
  }
23
21
 
24
22
  @objc(StripeCurrencySelectorElementContainerView)
25
23
  public class StripeCurrencySelectorElementContainerView: UIView {
24
+ private var hasReportedZeroHeight = false
26
25
 
27
- // MARK: - Bridge-exposed Props
28
-
29
- @objc public var sessionKey: String? {
30
- didSet {
31
- guard sessionKey != oldValue else { return }
32
- attachToSessionIfPossible()
33
- }
34
- }
35
-
36
- @objc public var disabled: Bool = false {
37
- didSet {
38
- selectorView?.isEnabled = !disabled
39
- }
40
- }
41
-
42
- @objc public var appearance: NSDictionary? {
26
+ @objc public var sessionKey: String?
27
+ @objc public var disabled: Bool = false
28
+ @objc public var appearance: NSDictionary?
29
+ @objc public var onHeightChange: RCTDirectEventBlock? {
43
30
  didSet {
44
- selectorAppearance = CurrencySelectorAppearance.buildAppearanceFromParams(params: appearance)
45
- if let checkout = attachedCheckout {
46
- installSelectorView(for: checkout)
47
- }
31
+ hasReportedZeroHeight = false
32
+ reportZeroHeight()
48
33
  }
49
34
  }
50
35
 
51
- /// Fired whenever the inner selector's intrinsic height changes so RN
52
- /// can match it. Session-state changes flow through the central
53
- /// `checkoutSessionDidChangeState` event on `StripeSdk` (see
54
- /// `CheckoutStateBridge`), so this view does not need to push state.
55
- @objc public var onHeightChange: RCTDirectEventBlock?
56
-
57
- // MARK: - Private Properties
58
-
59
- private var selectorView: Checkout.CurrencySelectorView?
60
- private var sessionCancellable: AnyCancellable?
61
- private var lastReportedHeight: CGFloat = -1
62
- private var attachedCheckout: Checkout?
63
- private var selectorAppearance = Checkout.CurrencySelectorView.Appearance()
64
-
65
- // MARK: - Init
66
-
67
36
  override public init(frame: CGRect) {
68
37
  super.init(frame: frame)
69
38
  backgroundColor = .clear
@@ -75,100 +44,20 @@ public class StripeCurrencySelectorElementContainerView: UIView {
75
44
  fatalError("init(coder:) has not been implemented")
76
45
  }
77
46
 
78
- // MARK: - Layout
47
+ public override var intrinsicContentSize: CGSize {
48
+ CGSize(width: UIView.noIntrinsicMetric, height: 0)
49
+ }
79
50
 
80
51
  public override func layoutSubviews() {
81
52
  super.layoutSubviews()
82
- reportHeightIfNeeded()
83
- }
84
-
85
- // MARK: - Setup
86
-
87
- private func attachToSessionIfPossible() {
88
- Task { @MainActor in
89
- guard let key = self.sessionKey,
90
- let checkout = StripeSdkImpl.shared.checkoutInstances[key] else {
91
- self.detach()
92
- return
93
- }
94
-
95
- // Already showing a selector — leave it in place. Re-creating
96
- // would interrupt the inner view's loading animation and reset
97
- // its enabled state mid-API-call.
98
- if self.selectorView != nil {
99
- return
100
- }
101
-
102
- self.attachedCheckout = checkout
103
- self.installSelectorView(for: checkout)
104
- self.subscribeForLayoutUpdates(on: checkout)
105
- }
106
- }
107
-
108
- /// We don't push state to JS here — `CheckoutStateBridge` already does
109
- /// that for the whole session. This subscription only nudges Auto Layout
110
- /// so the caption-text changes after a currency selection are reflected
111
- /// in our reported height back to RN.
112
- private func subscribeForLayoutUpdates(on checkout: Checkout) {
113
- sessionCancellable = checkout.$session
114
- .dropFirst()
115
- .receive(on: DispatchQueue.main)
116
- .sink { [weak self] _ in
117
- guard let self else { return }
118
- self.setNeedsLayout()
119
- self.layoutIfNeeded()
120
- self.reportHeightIfNeeded()
121
- }
122
- }
123
-
124
- private func installSelectorView(for checkout: Checkout) {
125
- selectorView?.removeFromSuperview()
126
-
127
- let view = Checkout.CurrencySelectorView(checkout: checkout, appearance: selectorAppearance)
128
- view.translatesAutoresizingMaskIntoConstraints = false
129
- view.isEnabled = !disabled
130
- addSubview(view)
131
-
132
- NSLayoutConstraint.activate([
133
- view.topAnchor.constraint(equalTo: topAnchor),
134
- view.leadingAnchor.constraint(equalTo: leadingAnchor),
135
- view.trailingAnchor.constraint(equalTo: trailingAnchor),
136
- view.bottomAnchor.constraint(equalTo: bottomAnchor),
137
- ])
138
-
139
- selectorView = view
140
-
141
- // Force an initial height report so RN can lay us out at zero
142
- // when Adaptive Pricing is unavailable.
143
- setNeedsLayout()
144
- layoutIfNeeded()
53
+ reportZeroHeight()
145
54
  }
146
55
 
147
- private func detach() {
148
- sessionCancellable?.cancel()
149
- sessionCancellable = nil
150
- selectorView?.removeFromSuperview()
151
- selectorView = nil
152
- attachedCheckout = nil
153
- lastReportedHeight = -1
154
- }
155
-
156
- // MARK: - Events
157
-
158
- private func reportHeightIfNeeded() {
159
- let desiredHeight: CGFloat
160
- if let selectorView, !selectorView.isHidden {
161
- desiredHeight = selectorView.systemLayoutSizeFitting(
162
- CGSize(width: bounds.width, height: UIView.layoutFittingCompressedSize.height),
163
- withHorizontalFittingPriority: .required,
164
- verticalFittingPriority: .fittingSizeLevel
165
- ).height
166
- } else {
167
- desiredHeight = 0
56
+ private func reportZeroHeight() {
57
+ guard !hasReportedZeroHeight, let onHeightChange else {
58
+ return
168
59
  }
169
-
170
- guard desiredHeight != lastReportedHeight else { return }
171
- lastReportedHeight = desiredHeight
172
- onHeightChange?(["height": desiredHeight])
60
+ hasReportedZeroHeight = true
61
+ onHeightChange(["height": 0])
173
62
  }
174
63
  }
package/ios/Mappers.swift CHANGED
@@ -304,7 +304,9 @@ class Mappers {
304
304
  case STPPaymentMethodType.affirm: return "Affirm"
305
305
  case STPPaymentMethodType.cashApp: return "CashApp"
306
306
  case STPPaymentMethodType.revolutPay: return "RevolutPay"
307
+ case STPPaymentMethodType.payByBank: return "PayByBank"
307
308
  case STPPaymentMethodType.link: return "Link"
309
+ case STPPaymentMethodType.twint: return "Twint"
308
310
  case STPPaymentMethodType.unknown: return "Unknown"
309
311
  default: return "Unknown"
310
312
  }
@@ -337,6 +339,8 @@ class Mappers {
337
339
  case "Affirm": return STPPaymentMethodType.affirm
338
340
  case "CashApp": return STPPaymentMethodType.cashApp
339
341
  case "RevolutPay": return STPPaymentMethodType.revolutPay
342
+ case "PayByBank": return STPPaymentMethodType.payByBank
343
+ case "Twint": return STPPaymentMethodType.twint
340
344
  case "Link": return STPPaymentMethodType.link
341
345
  default: return STPPaymentMethodType.unknown
342
346
  }