@stripe/stripe-react-native 0.68.0 → 0.70.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 (218) hide show
  1. package/android/.idea/AndroidProjectSystem.xml +6 -0
  2. package/android/.idea/caches/deviceStreaming.xml +835 -0
  3. package/android/.idea/compiler.xml +6 -0
  4. package/android/.idea/gradle.xml +17 -0
  5. package/android/.idea/migrations.xml +10 -0
  6. package/android/.idea/misc.xml +10 -0
  7. package/android/.idea/runConfigurations.xml +17 -0
  8. package/android/.idea/vcs.xml +6 -0
  9. package/android/gradle.properties +1 -1
  10. package/android/local.properties +8 -0
  11. package/android/src/main/java/com/reactnativestripesdk/LinkControllerManager.kt +175 -0
  12. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +31 -24
  13. package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +7 -8
  14. package/android/src/oldarch/java/com/reactnativestripesdk/NativeOnrampSdkModuleSpec.java +8 -0
  15. package/android/src/oldarch/java/com/reactnativestripesdk/NativeStripeSdkModuleSpec.java +8 -4
  16. package/android/src/onramp/java/com/reactnativestripesdk/OnrampErrors.kt +30 -35
  17. package/android/src/onramp/java/com/reactnativestripesdk/OnrampMappers.kt +48 -0
  18. package/android/src/onramp/java/com/reactnativestripesdk/OnrampSdkModule.kt +65 -2
  19. package/android/src/test/java/com/reactnativestripesdk/OnrampErrorsTest.kt +106 -27
  20. package/android/src/test/java/com/reactnativestripesdk/mappers/OnrampMappersTest.kt +37 -0
  21. package/android/src/test/java/com/reactnativestripesdk/mappers/PaymentMethodMappersTest.kt +110 -0
  22. package/ios/CurrencySelectorElementView.swift +1 -1
  23. package/ios/Mappers+Checkout.swift +3 -3
  24. package/ios/Mappers.swift +19 -0
  25. package/ios/OnrampErrors.swift +21 -19
  26. package/ios/StripeOnrampSdk.mm +16 -0
  27. package/ios/StripeSdk.mm +15 -15
  28. package/ios/StripeSdkImpl+Checkout.swift +15 -39
  29. package/ios/StripeSdkImpl+LinkController.swift +108 -0
  30. package/ios/StripeSdkImpl.swift +64 -3
  31. package/jest/setup.js +2 -0
  32. package/lib/commonjs/components/AddToWalletButton.js +1 -1
  33. package/lib/commonjs/components/AddToWalletButton.js.map +1 -1
  34. package/lib/commonjs/components/AddressSheet.js +1 -1
  35. package/lib/commonjs/components/AddressSheet.js.map +1 -1
  36. package/lib/commonjs/components/AuBECSDebitForm.js +1 -1
  37. package/lib/commonjs/components/AuBECSDebitForm.js.map +1 -1
  38. package/lib/commonjs/components/CardField.js +1 -1
  39. package/lib/commonjs/components/CardField.js.map +1 -1
  40. package/lib/commonjs/components/CardForm.js +1 -1
  41. package/lib/commonjs/components/CardForm.js.map +1 -1
  42. package/lib/commonjs/components/CurrencySelectorElement.js +1 -1
  43. package/lib/commonjs/components/CurrencySelectorElement.js.map +1 -1
  44. package/lib/commonjs/components/PaymentMethodMessagingElement.js +1 -1
  45. package/lib/commonjs/components/PaymentMethodMessagingElement.js.map +1 -1
  46. package/lib/commonjs/components/PlatformPayButton.js +1 -1
  47. package/lib/commonjs/components/PlatformPayButton.js.map +1 -1
  48. package/lib/commonjs/components/StripeContainer.js +1 -1
  49. package/lib/commonjs/components/StripeContainer.js.map +1 -1
  50. package/lib/commonjs/components/StripeProvider.js +1 -1
  51. package/lib/commonjs/components/StripeProvider.js.map +1 -1
  52. package/lib/commonjs/connect/Components.js +1 -1
  53. package/lib/commonjs/connect/Components.js.map +1 -1
  54. package/lib/commonjs/connect/ConnectComponentsProvider.js +1 -1
  55. package/lib/commonjs/connect/ConnectComponentsProvider.js.map +1 -1
  56. package/lib/commonjs/connect/EmbeddedComponent.js +1 -1
  57. package/lib/commonjs/connect/EmbeddedComponent.js.map +1 -1
  58. package/lib/commonjs/connect/ModalCloseButton.js +1 -1
  59. package/lib/commonjs/connect/ModalCloseButton.js.map +1 -1
  60. package/lib/commonjs/connect/NavigationBar.js +1 -1
  61. package/lib/commonjs/connect/NavigationBar.js.map +1 -1
  62. package/lib/commonjs/functions.js +1 -1
  63. package/lib/commonjs/functions.js.map +1 -1
  64. package/lib/commonjs/helpers.js +1 -1
  65. package/lib/commonjs/hooks/useCheckout.js +1 -1
  66. package/lib/commonjs/hooks/useCheckout.js.map +1 -1
  67. package/lib/commonjs/hooks/useLinkController.js +2 -0
  68. package/lib/commonjs/hooks/useLinkController.js.map +1 -0
  69. package/lib/commonjs/hooks/useOnramp.js +1 -1
  70. package/lib/commonjs/hooks/useOnramp.js.map +1 -1
  71. package/lib/commonjs/index.js +1 -1
  72. package/lib/commonjs/index.js.map +1 -1
  73. package/lib/commonjs/specs/NativeAddToWalletButton.js +1 -1
  74. package/lib/commonjs/specs/NativeAddressSheet.js +1 -1
  75. package/lib/commonjs/specs/NativeApplePayButton.js +1 -1
  76. package/lib/commonjs/specs/NativeAuBECSDebitForm.js +1 -1
  77. package/lib/commonjs/specs/NativeCardField.js +1 -1
  78. package/lib/commonjs/specs/NativeCardField.js.map +1 -1
  79. package/lib/commonjs/specs/NativeCardForm.js +1 -1
  80. package/lib/commonjs/specs/NativeCardForm.js.map +1 -1
  81. package/lib/commonjs/specs/NativeConnectAccountOnboardingView.js +1 -1
  82. package/lib/commonjs/specs/NativeCurrencySelectorElement.js +1 -1
  83. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js +1 -1
  84. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  85. package/lib/commonjs/specs/NativeGooglePayButton.js +1 -1
  86. package/lib/commonjs/specs/NativeNavigationBar.js +1 -1
  87. package/lib/commonjs/specs/NativeOnrampSdkModule.js.map +1 -1
  88. package/lib/commonjs/specs/NativePaymentMethodMessagingElement.js +1 -1
  89. package/lib/commonjs/specs/NativeStripeContainer.js +1 -1
  90. package/lib/commonjs/specs/NativeStripeSdkModule.js.map +1 -1
  91. package/lib/commonjs/types/EmbeddedPaymentElement.js +1 -1
  92. package/lib/commonjs/types/EmbeddedPaymentElement.js.map +1 -1
  93. package/lib/commonjs/types/Errors.js +1 -1
  94. package/lib/commonjs/types/Errors.js.map +1 -1
  95. package/lib/commonjs/types/LinkController.js +2 -0
  96. package/lib/commonjs/types/LinkController.js.map +1 -0
  97. package/lib/commonjs/types/Onramp.js +1 -1
  98. package/lib/commonjs/types/Onramp.js.map +1 -1
  99. package/lib/commonjs/types/index.js +1 -1
  100. package/lib/commonjs/types/index.js.map +1 -1
  101. package/lib/module/components/AddToWalletButton.js +1 -1
  102. package/lib/module/components/AddToWalletButton.js.map +1 -1
  103. package/lib/module/components/AddressSheet.js +1 -1
  104. package/lib/module/components/AddressSheet.js.map +1 -1
  105. package/lib/module/components/AuBECSDebitForm.js +1 -1
  106. package/lib/module/components/AuBECSDebitForm.js.map +1 -1
  107. package/lib/module/components/CardField.js +1 -1
  108. package/lib/module/components/CardField.js.map +1 -1
  109. package/lib/module/components/CardForm.js +1 -1
  110. package/lib/module/components/CardForm.js.map +1 -1
  111. package/lib/module/components/CurrencySelectorElement.js +1 -1
  112. package/lib/module/components/CurrencySelectorElement.js.map +1 -1
  113. package/lib/module/components/PaymentMethodMessagingElement.js +1 -1
  114. package/lib/module/components/PaymentMethodMessagingElement.js.map +1 -1
  115. package/lib/module/components/PlatformPayButton.js +1 -1
  116. package/lib/module/components/PlatformPayButton.js.map +1 -1
  117. package/lib/module/components/StripeContainer.js +1 -1
  118. package/lib/module/components/StripeContainer.js.map +1 -1
  119. package/lib/module/components/StripeProvider.js +1 -1
  120. package/lib/module/components/StripeProvider.js.map +1 -1
  121. package/lib/module/connect/Components.js +1 -1
  122. package/lib/module/connect/Components.js.map +1 -1
  123. package/lib/module/connect/ConnectComponentsProvider.js +1 -1
  124. package/lib/module/connect/ConnectComponentsProvider.js.map +1 -1
  125. package/lib/module/connect/EmbeddedComponent.js +1 -1
  126. package/lib/module/connect/EmbeddedComponent.js.map +1 -1
  127. package/lib/module/connect/ModalCloseButton.js +1 -1
  128. package/lib/module/connect/ModalCloseButton.js.map +1 -1
  129. package/lib/module/connect/NavigationBar.js +1 -1
  130. package/lib/module/connect/NavigationBar.js.map +1 -1
  131. package/lib/module/functions.js +1 -1
  132. package/lib/module/functions.js.map +1 -1
  133. package/lib/module/helpers.js +1 -1
  134. package/lib/module/hooks/useCheckout.js +1 -1
  135. package/lib/module/hooks/useCheckout.js.map +1 -1
  136. package/lib/module/hooks/useLinkController.js +2 -0
  137. package/lib/module/hooks/useLinkController.js.map +1 -0
  138. package/lib/module/hooks/useOnramp.js +1 -1
  139. package/lib/module/hooks/useOnramp.js.map +1 -1
  140. package/lib/module/index.js +1 -1
  141. package/lib/module/index.js.map +1 -1
  142. package/lib/module/specs/NativeAddToWalletButton.js +1 -1
  143. package/lib/module/specs/NativeAddressSheet.js +1 -1
  144. package/lib/module/specs/NativeApplePayButton.js +1 -1
  145. package/lib/module/specs/NativeAuBECSDebitForm.js +1 -1
  146. package/lib/module/specs/NativeCardField.js +1 -1
  147. package/lib/module/specs/NativeCardField.js.map +1 -1
  148. package/lib/module/specs/NativeCardForm.js +1 -1
  149. package/lib/module/specs/NativeCardForm.js.map +1 -1
  150. package/lib/module/specs/NativeConnectAccountOnboardingView.js +1 -1
  151. package/lib/module/specs/NativeCurrencySelectorElement.js +1 -1
  152. package/lib/module/specs/NativeEmbeddedPaymentElement.js +1 -1
  153. package/lib/module/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  154. package/lib/module/specs/NativeGooglePayButton.js +1 -1
  155. package/lib/module/specs/NativeNavigationBar.js +1 -1
  156. package/lib/module/specs/NativeOnrampSdkModule.js.map +1 -1
  157. package/lib/module/specs/NativePaymentMethodMessagingElement.js +1 -1
  158. package/lib/module/specs/NativeStripeContainer.js +1 -1
  159. package/lib/module/specs/NativeStripeSdkModule.js.map +1 -1
  160. package/lib/module/types/EmbeddedPaymentElement.js +1 -1
  161. package/lib/module/types/EmbeddedPaymentElement.js.map +1 -1
  162. package/lib/module/types/Errors.js +1 -1
  163. package/lib/module/types/Errors.js.map +1 -1
  164. package/lib/module/types/LinkController.js +2 -0
  165. package/lib/module/types/LinkController.js.map +1 -0
  166. package/lib/module/types/Onramp.js +1 -1
  167. package/lib/module/types/Onramp.js.map +1 -1
  168. package/lib/module/types/index.js +1 -1
  169. package/lib/module/types/index.js.map +1 -1
  170. package/lib/typescript/src/components/StripeProvider.d.ts.map +1 -1
  171. package/lib/typescript/src/connect/Components.d.ts +1 -1
  172. package/lib/typescript/src/connect/Components.d.ts.map +1 -1
  173. package/lib/typescript/src/functions.d.ts +19 -1
  174. package/lib/typescript/src/functions.d.ts.map +1 -1
  175. package/lib/typescript/src/hooks/useCheckout.d.ts.map +1 -1
  176. package/lib/typescript/src/hooks/useLinkController.d.ts +28 -0
  177. package/lib/typescript/src/hooks/useLinkController.d.ts.map +1 -0
  178. package/lib/typescript/src/hooks/useOnramp.d.ts +18 -0
  179. package/lib/typescript/src/hooks/useOnramp.d.ts.map +1 -1
  180. package/lib/typescript/src/index.d.ts +1 -0
  181. package/lib/typescript/src/index.d.ts.map +1 -1
  182. package/lib/typescript/src/specs/NativeOnrampSdkModule.d.ts +2 -0
  183. package/lib/typescript/src/specs/NativeOnrampSdkModule.d.ts.map +1 -1
  184. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts +5 -2
  185. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts.map +1 -1
  186. package/lib/typescript/src/types/Checkout.d.ts +1 -14
  187. package/lib/typescript/src/types/Checkout.d.ts.map +1 -1
  188. package/lib/typescript/src/types/Errors.d.ts +8 -0
  189. package/lib/typescript/src/types/Errors.d.ts.map +1 -1
  190. package/lib/typescript/src/types/LinkController.d.ts +71 -0
  191. package/lib/typescript/src/types/LinkController.d.ts.map +1 -0
  192. package/lib/typescript/src/types/Onramp.d.ts +82 -21
  193. package/lib/typescript/src/types/Onramp.d.ts.map +1 -1
  194. package/lib/typescript/src/types/index.d.ts +2 -1
  195. package/lib/typescript/src/types/index.d.ts.map +1 -1
  196. package/package.json +1 -1
  197. package/src/components/StripeProvider.tsx +0 -2
  198. package/src/connect/Components.tsx +10 -0
  199. package/src/functions.ts +48 -0
  200. package/src/hooks/useCheckout.tsx +0 -14
  201. package/src/hooks/useLinkController.tsx +54 -0
  202. package/src/hooks/useOnramp.tsx +50 -83
  203. package/src/index.tsx +1 -0
  204. package/src/specs/NativeOnrampSdkModule.ts +8 -0
  205. package/src/specs/NativeStripeSdkModule.ts +11 -7
  206. package/src/types/Checkout.ts +1 -19
  207. package/src/types/Errors.ts +9 -0
  208. package/src/types/LinkController.ts +75 -0
  209. package/src/types/Onramp.ts +98 -21
  210. package/src/types/index.ts +2 -0
  211. package/stripe-react-native.podspec +1 -1
  212. package/lib/commonjs/internal/stripeConfig.js +0 -2
  213. package/lib/commonjs/internal/stripeConfig.js.map +0 -1
  214. package/lib/module/internal/stripeConfig.js +0 -2
  215. package/lib/module/internal/stripeConfig.js.map +0 -1
  216. package/lib/typescript/src/internal/stripeConfig.d.ts +0 -3
  217. package/lib/typescript/src/internal/stripeConfig.d.ts.map +0 -1
  218. package/src/internal/stripeConfig.ts +0 -9
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="CompilerConfiguration">
4
+ <bytecodeTargetLevel target="1.6" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="GradleSettings">
4
+ <option name="linkedExternalProjectsSettings">
5
+ <GradleProjectSettings>
6
+ <option name="testRunner" value="CHOOSE_PER_TEST" />
7
+ <option name="externalProjectPath" value="$PROJECT_DIR$" />
8
+ <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
9
+ <option name="modules">
10
+ <set>
11
+ <option value="$PROJECT_DIR$" />
12
+ </set>
13
+ </option>
14
+ </GradleProjectSettings>
15
+ </option>
16
+ </component>
17
+ </project>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectMigrations">
4
+ <option name="MigrateToGradleLocalJavaHome">
5
+ <set>
6
+ <option value="$PROJECT_DIR$" />
7
+ </set>
8
+ </option>
9
+ </component>
10
+ </project>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ExternalStorageConfigurationManager" enabled="true" />
4
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
5
+ <output url="file://$PROJECT_DIR$/build/classes" />
6
+ </component>
7
+ <component name="ProjectType">
8
+ <option name="id" value="Android" />
9
+ </component>
10
+ </project>
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="RunConfigurationProducerService">
4
+ <option name="ignoredProducers">
5
+ <set>
6
+ <option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
7
+ <option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
8
+ <option value="com.intellij.execution.junit.PatternConfigurationProducer" />
9
+ <option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
10
+ <option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
11
+ <option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
12
+ <option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
13
+ <option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
14
+ </set>
15
+ </option>
16
+ </component>
17
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
5
+ </component>
6
+ </project>
@@ -3,4 +3,4 @@ StripeSdk_compileSdkVersion=36
3
3
  StripeSdk_targetSdkVersion=36
4
4
  StripeSdk_minSdkVersion=23
5
5
  # Keep StripeSdk_stripeVersion in sync with https://github.com/stripe/stripe-identity-react-native/blob/main/android/gradle.properties
6
- StripeSdk_stripeVersion=23.11.0
6
+ StripeSdk_stripeVersion=23.12.0
@@ -0,0 +1,8 @@
1
+ ## This file must *NOT* be checked into Version Control Systems,
2
+ # as it contains information specific to your local configuration.
3
+ #
4
+ # Location of the SDK. This is only used by Gradle.
5
+ # For customization when using a Version Control System, please read the
6
+ # header note.
7
+ #Tue Jul 29 21:50:46 PDT 2025
8
+ sdk.dir=/Users/cttsai/Library/Android/sdk
@@ -0,0 +1,175 @@
1
+ package com.reactnativestripesdk
2
+
3
+ import androidx.activity.ComponentActivity
4
+ import androidx.lifecycle.SavedStateHandle
5
+ import androidx.lifecycle.lifecycleScope
6
+ import com.facebook.react.bridge.Arguments
7
+ import com.facebook.react.bridge.Promise
8
+ import com.facebook.react.bridge.ReactApplicationContext
9
+ import com.facebook.react.bridge.ReadableMap
10
+ import com.reactnativestripesdk.utils.ErrorType
11
+ import com.reactnativestripesdk.utils.createError
12
+ import com.reactnativestripesdk.utils.mapFromPaymentMethod
13
+ import com.stripe.android.link.LinkController
14
+ import com.stripe.android.link.LinkControllerPreview
15
+ import kotlinx.coroutines.Dispatchers
16
+ import kotlinx.coroutines.launch
17
+ import kotlinx.coroutines.withContext
18
+
19
+ internal const val LINK_CONTROLLER_NOT_INITIALIZED_ERROR =
20
+ "LinkController has not been initialized. Call initLinkController first."
21
+
22
+ /**
23
+ * Manages [LinkController] initialization and presentation for the React Native bridge.
24
+ *
25
+ * @PrivatePreview
26
+ */
27
+ @OptIn(LinkControllerPreview::class)
28
+ internal class LinkControllerManager(
29
+ private val context: ReactApplicationContext,
30
+ private val publishableKey: String,
31
+ private val stripeAccountId: String?,
32
+ ) {
33
+ private var linkController: LinkController? = null
34
+ private var linkPresenter: LinkController.Presenter? = null
35
+ private var presentPromise: Promise? = null
36
+
37
+ fun configure(params: ReadableMap, promise: Promise) {
38
+ val email = params.getString("email")
39
+ val merchantDisplayName = params.getString("merchantDisplayName")
40
+ if (merchantDisplayName == null) {
41
+ promise.resolve(createError(ErrorType.Failed.toString(), "merchantDisplayName is required."))
42
+ return
43
+ }
44
+
45
+ val activity = context.currentActivity as? ComponentActivity
46
+ if (activity == null) {
47
+ promise.resolve(createError(ErrorType.Failed.toString(), "Activity is not available. Retry this method."))
48
+ return
49
+ }
50
+
51
+ val phoneNumber = params.getString("phoneNumber")
52
+ val allowLogout = if (params.hasKey("allowLogout")) params.getBoolean("allowLogout") else true
53
+ val setupIntentClientSecret = params.getString("setupIntentClientSecret")
54
+
55
+ val supportedTypes = parseSupportedPaymentMethodTypes(params)
56
+
57
+ val config = LinkController.Configuration(
58
+ merchantDisplayName = merchantDisplayName,
59
+ publishableKey = publishableKey,
60
+ stripeAccountId = stripeAccountId
61
+ )
62
+ .also { if (email != null) it.email(email) }
63
+ .phoneNumber(phoneNumber)
64
+ .supportedPaymentMethodTypes(supportedTypes)
65
+ .allowLogout(allowLogout)
66
+ .setupIntentClientSecret(setupIntentClientSecret)
67
+
68
+ // Build a new controller if this is the first call or after a reset.
69
+ // SavedStateHandle() is empty — state will not survive process death, which is
70
+ // the same trade-off made by other Stripe RN SDK APIs.
71
+ if (linkController == null) {
72
+ linkController = LinkController.Builder(
73
+ application = activity.application,
74
+ savedStateHandle = SavedStateHandle()
75
+ ).build()
76
+ }
77
+
78
+ val controller = linkController!!
79
+
80
+ activity.lifecycleScope.launch {
81
+ val result = controller.configure(config)
82
+ if (result.isSuccess) {
83
+ // Create once: presenter may register ActivityResultLaunchers, which must happen before onStart().
84
+ if (linkPresenter == null) {
85
+ linkPresenter = controller.createPresenter(
86
+ activity = activity,
87
+ presentCallback = { presentResult -> handlePresentResult(presentResult) }
88
+ )
89
+ }
90
+ promise.resolve(Arguments.createMap())
91
+ } else {
92
+ promise.resolve(
93
+ createError(
94
+ ErrorType.Failed.toString(),
95
+ result.exceptionOrNull()?.message ?: "LinkController configuration failed."
96
+ )
97
+ )
98
+ }
99
+ }
100
+ }
101
+
102
+ fun present(promise: Promise) {
103
+ val presenter = linkPresenter
104
+ if (presenter == null) {
105
+ promise.resolve(createError(ErrorType.Failed.toString(), LINK_CONTROLLER_NOT_INITIALIZED_ERROR))
106
+ return
107
+ }
108
+
109
+ presentPromise = promise
110
+ presenter.present()
111
+ }
112
+
113
+ fun destroy() {
114
+ linkController = null
115
+ linkPresenter = null
116
+ presentPromise = null
117
+ }
118
+
119
+ private fun parseSupportedPaymentMethodTypes(params: ReadableMap): List<LinkController.PaymentMethodType>? =
120
+ params.getArray("supportedPaymentMethodTypes")?.let { arr ->
121
+ (0 until arr.size()).mapNotNull { i ->
122
+ when (arr.getString(i)) {
123
+ "card" -> LinkController.PaymentMethodType.Card
124
+ "bankAccount" -> LinkController.PaymentMethodType.BankAccount
125
+ else -> null
126
+ }
127
+ }.ifEmpty { null }
128
+ }
129
+
130
+ private fun handlePresentResult(result: LinkController.PresentResult) {
131
+ val promise = presentPromise ?: return
132
+ val controller = linkController ?: return
133
+ when (result) {
134
+ is LinkController.PresentResult.Completed -> {
135
+ val response = Arguments.createMap()
136
+ response.putMap("paymentMethod", mapFromPaymentMethod(result.paymentMethod))
137
+
138
+ val preview = controller.paymentMethodPreview.value
139
+ val currentScope = (context.currentActivity as? ComponentActivity)?.lifecycleScope
140
+ if (preview != null && currentScope != null) {
141
+ currentScope.launch {
142
+ val iconBase64 = withContext(Dispatchers.IO) {
143
+ try {
144
+ convertDrawableToBase64(preview.icon)
145
+ } catch (_: Exception) {
146
+ null
147
+ }
148
+ }
149
+ val previewMap = Arguments.createMap()
150
+ previewMap.putString("label", preview.label)
151
+ preview.sublabel?.let { previewMap.putString("sublabel", it) }
152
+ if (iconBase64 != null) {
153
+ previewMap.putString("icon", "data:image/png;base64,$iconBase64")
154
+ }
155
+ response.putMap("paymentMethodPreview", previewMap)
156
+ promise.resolve(response)
157
+ }
158
+ } else {
159
+ promise.resolve(response)
160
+ }
161
+ }
162
+ is LinkController.PresentResult.Canceled -> {
163
+ promise.resolve(
164
+ createError(
165
+ ErrorType.Canceled.toString(),
166
+ "The customer canceled the Link flow."
167
+ )
168
+ )
169
+ }
170
+ is LinkController.PresentResult.Failed -> {
171
+ promise.resolve(createError(ErrorType.Failed.toString(), result.error))
172
+ }
173
+ }
174
+ }
175
+ }
@@ -127,6 +127,7 @@ class StripeSdkModule(
127
127
  private val checkoutStateObservers = mutableMapOf<String, Job>()
128
128
 
129
129
  private var customerSheetManager: CustomerSheetManager? = null
130
+ private var linkControllerManager: LinkControllerManager? = null
130
131
 
131
132
  internal var embeddedIntentCreationCallback = CompletableDeferred<ReadableMap>()
132
133
  internal var embeddedConfirmationTokenCreationCallback = CompletableDeferred<ReadableMap>()
@@ -180,6 +181,8 @@ class StripeSdkModule(
180
181
  checkoutStateObservers.values.forEach { it.cancel() }
181
182
  checkoutStateObservers.clear()
182
183
  checkoutInstances.clear()
184
+ linkControllerManager?.destroy()
185
+ linkControllerManager = null
183
186
  }
184
187
 
185
188
  private fun registerStripeUIManager(uiManager: StripeUIManager) {
@@ -1798,30 +1801,6 @@ class StripeSdkModule(
1798
1801
  }
1799
1802
  }
1800
1803
 
1801
- override fun checkoutUpdateBillingAddress(
1802
- sessionKey: String,
1803
- address: ReadableMap,
1804
- name: String?,
1805
- phone: String?,
1806
- promise: Promise,
1807
- ) {
1808
- val addressUpdate = buildCheckoutAddressUpdate(name, phone, address) ?: run {
1809
- promise.reject(ErrorType.Failed.toString(), "A billing address country is required.")
1810
- return
1811
- }
1812
-
1813
- performCheckoutMutation(
1814
- sessionKey = sessionKey,
1815
- promise = promise,
1816
- ) { checkout ->
1817
- checkout.updateBillingAddress(
1818
- name = addressUpdate.name,
1819
- phoneNumber = addressUpdate.phone,
1820
- address = addressUpdate.toCheckoutAddress(),
1821
- )
1822
- }
1823
- }
1824
-
1825
1804
  override fun checkoutApplyPromotionCode(
1826
1805
  sessionKey: String,
1827
1806
  code: String,
@@ -2024,6 +2003,34 @@ class StripeSdkModule(
2024
2003
  }
2025
2004
  }
2026
2005
 
2006
+ // LinkController - Private Preview
2007
+
2008
+ @ReactMethod
2009
+ override fun initLinkController(
2010
+ params: ReadableMap,
2011
+ promise: Promise,
2012
+ ) {
2013
+ linkControllerManager?.destroy()
2014
+ linkControllerManager = LinkControllerManager(
2015
+ context = reactApplicationContext,
2016
+ publishableKey = publishableKey,
2017
+ stripeAccountId = stripeAccountId,
2018
+ )
2019
+ linkControllerManager?.configure(params, promise)
2020
+ }
2021
+
2022
+ @ReactMethod
2023
+ override fun presentLinkController(promise: Promise) {
2024
+ val manager = linkControllerManager
2025
+ if (manager == null) {
2026
+ promise.resolve(createError(ErrorType.Failed.toString(), LINK_CONTROLLER_NOT_INITIALIZED_ERROR))
2027
+ return
2028
+ }
2029
+ UiThreadUtil.runOnUiThread {
2030
+ manager.present(promise)
2031
+ }
2032
+ }
2033
+
2027
2034
  /**
2028
2035
  * React native apps do not properly handle activity re-creation so make
2029
2036
  * sure to dismiss any stripe ui when that happens to make sure apps stay
@@ -360,6 +360,11 @@ internal fun mapFromToken(token: Token): WritableMap {
360
360
  return tokenMap
361
361
  }
362
362
 
363
+ private fun mapFromStringList(list: Collection<String>?): WritableArray? =
364
+ list?.let { networks ->
365
+ Arguments.createArray().also { arr -> networks.forEach { arr.pushString(it) } }
366
+ }
367
+
363
368
  internal fun mapFromPaymentMethod(paymentMethod: PaymentMethod): WritableMap {
364
369
  val pm: WritableMap = Arguments.createMap()
365
370
 
@@ -379,13 +384,7 @@ internal fun mapFromPaymentMethod(paymentMethod: PaymentMethod): WritableMap {
379
384
  it.putString("last4", paymentMethod.card?.last4)
380
385
  it.putString("fingerprint", paymentMethod.card?.fingerprint)
381
386
  it.putString("preferredNetwork", paymentMethod.card?.networks?.preferred)
382
- it.putArray(
383
- "availableNetworks",
384
- paymentMethod.card
385
- ?.networks
386
- ?.available
387
- ?.toList() as? ReadableArray,
388
- )
387
+ it.putArray("availableNetworks", mapFromStringList(paymentMethod.card?.networks?.available))
389
388
  it.putMap(
390
389
  "threeDSecureUsage",
391
390
  Arguments.createMap().also { threeDSecureUsageMap ->
@@ -455,7 +454,7 @@ internal fun mapFromPaymentMethod(paymentMethod: PaymentMethod): WritableMap {
455
454
  it.putString("preferredNetworks", paymentMethod.usBankAccount?.networks?.preferred)
456
455
  it.putArray(
457
456
  "supportedNetworks",
458
- paymentMethod.usBankAccount?.networks?.supported as? ReadableArray,
457
+ mapFromStringList(paymentMethod.usBankAccount?.networks?.supported),
459
458
  )
460
459
  },
461
460
  )
@@ -55,6 +55,14 @@ public abstract class NativeOnrampSdkModuleSpec extends ReactContextBaseJavaModu
55
55
  @DoNotStrip
56
56
  public abstract void registerWalletAddress(String walletAddress, String network, Promise promise);
57
57
 
58
+ @ReactMethod
59
+ @DoNotStrip
60
+ public abstract void getWalletOwnershipChallenge(String walletAddress, String network, Promise promise);
61
+
62
+ @ReactMethod
63
+ @DoNotStrip
64
+ public abstract void submitWalletOwnershipSignature(String challengeId, String signature, Promise promise);
65
+
58
66
  @ReactMethod
59
67
  @DoNotStrip
60
68
  public abstract void attachKycInfo(ReadableMap kycInfo, Promise promise);
@@ -305,10 +305,6 @@ public abstract class NativeStripeSdkModuleSpec extends ReactContextBaseJavaModu
305
305
  @DoNotStrip
306
306
  public abstract void checkoutUpdateShippingAddress(String sessionKey, ReadableMap address, @Nullable String name, @Nullable String phone, Promise promise);
307
307
 
308
- @ReactMethod
309
- @DoNotStrip
310
- public abstract void checkoutUpdateBillingAddress(String sessionKey, ReadableMap address, @Nullable String name, @Nullable String phone, Promise promise);
311
-
312
308
  @ReactMethod
313
309
  @DoNotStrip
314
310
  public abstract void checkoutApplyPromotionCode(String sessionKey, String code, Promise promise);
@@ -333,6 +329,14 @@ public abstract class NativeStripeSdkModuleSpec extends ReactContextBaseJavaModu
333
329
  @DoNotStrip
334
330
  public abstract void checkoutRunServerUpdateComplete(String sessionKey, @Nullable String error, Promise promise);
335
331
 
332
+ @ReactMethod
333
+ @DoNotStrip
334
+ public abstract void initLinkController(ReadableMap params, Promise promise);
335
+
336
+ @ReactMethod
337
+ @DoNotStrip
338
+ public abstract void presentLinkController(Promise promise);
339
+
336
340
  @ReactMethod
337
341
  @DoNotStrip
338
342
  public abstract void addListener(String eventType);
@@ -3,14 +3,11 @@
3
3
  package com.reactnativestripesdk
4
4
 
5
5
  import com.facebook.react.bridge.Arguments
6
- import com.facebook.react.bridge.WritableArray
7
6
  import com.facebook.react.bridge.WritableMap
8
7
  import com.reactnativestripesdk.utils.ErrorType
9
8
  import com.stripe.android.core.exception.StripeException
10
9
  import com.stripe.android.crypto.onramp.ExperimentalCryptoOnramp
11
- import com.stripe.android.crypto.onramp.exception.AppAttestationException
12
10
  import com.stripe.android.crypto.onramp.exception.CryptoOnrampApiException
13
- import com.stripe.android.crypto.onramp.exception.SDKVersion
14
11
  import com.stripe.android.crypto.onramp.exception.StripeCryptoOnrampError
15
12
 
16
13
  internal fun createOnrampFailedError(error: Throwable): WritableMap =
@@ -32,29 +29,23 @@ private fun createOnrampError(
32
29
 
33
30
  val stripeError = apiException.stripeError
34
31
  val onrampErrorType = apiException.toOnrampErrorType()
32
+ val apiErrorContext = apiException.apiErrorContext
35
33
 
36
34
  return createOnrampErrorMap(
37
35
  code = code,
38
36
  message = apiException.userMessage,
39
37
  localizedMessage = apiException.localizedMessage,
40
38
  declineCode = stripeError?.declineCode,
41
- type = apiException.context.apiErrorType ?: stripeError?.type,
39
+ type = apiErrorContext.apiErrorType ?: stripeError?.type,
42
40
  stripeErrorCode = apiException.code,
43
41
  ) {
44
- putString("onrampErrorType", onrampErrorType)
45
- putString("developerMessage", apiException.developerMessage)
46
- putString("userMessage", apiException.userMessage)
47
- putString("reason", apiException.context.reason)
48
- putString("operation", apiException.context.operation)
49
- putString("appPackageName", apiException.context.appPackageName)
50
- putString("mode", apiException.context.mode)
51
- putArray("sdkVersions", mapFromSdkVersions(apiException.sdkVersions))
52
- putString("requestId", apiException.context.requestId)
53
- putString("apiErrorCode", apiException.context.apiErrorCode)
54
- putString("apiErrorType", apiException.context.apiErrorType)
55
- putString("apiErrorMessage", apiException.context.apiErrorMessage)
56
- putString("apiUserMessage", apiException.context.apiUserMessage)
57
- putString("docUrl", apiException.context.docUrl)
42
+ putCommonOnrampFields(apiException, onrampErrorType)
43
+ putString("reason", apiErrorContext.reason)
44
+ putString("requestId", apiErrorContext.requestId)
45
+ putString("apiErrorCode", apiErrorContext.apiErrorCode)
46
+ putString("apiErrorType", apiErrorContext.apiErrorType)
47
+ putString("apiErrorMessage", apiErrorContext.apiErrorMessage)
48
+ putString("apiUserMessage", apiErrorContext.apiUserMessage)
58
49
  }
59
50
  }
60
51
 
@@ -72,11 +63,22 @@ private fun createNonApiOnrampError(
72
63
  localizedMessage = error.localizedMessage,
73
64
  stripeErrorCode = onrampError.code,
74
65
  ) {
75
- putString("developerMessage", onrampError.developerMessage)
76
- putString("userMessage", onrampError.userMessage)
66
+ putCommonOnrampFields(onrampError, onrampError.toOnrampErrorType())
77
67
  }
78
68
  }
79
69
 
70
+ private fun WritableMap.putCommonOnrampFields(
71
+ error: StripeCryptoOnrampError,
72
+ onrampErrorType: String? = null,
73
+ ) {
74
+ onrampErrorType?.let {
75
+ putString("onrampErrorType", it)
76
+ }
77
+ putString("developerMessage", error.developerMessage)
78
+ putString("userMessage", error.userMessage)
79
+ putString("docUrl", error.docUrl)
80
+ }
81
+
80
82
  private fun createOnrampMessageError(
81
83
  code: String,
82
84
  message: String?,
@@ -84,12 +86,19 @@ private fun createOnrampMessageError(
84
86
  createOnrampErrorMap(code = code, message = message)
85
87
 
86
88
  private fun CryptoOnrampApiException.toOnrampErrorType(): String =
87
- if (this is AppAttestationException) {
89
+ if (code == "link_failed_to_attest_request") {
88
90
  "AppAttestationError"
89
91
  } else {
90
92
  "UncategorizedApiError"
91
93
  }
92
94
 
95
+ private fun StripeCryptoOnrampError.toOnrampErrorType(): String? =
96
+ if (code == "app_attestation_unavailable") {
97
+ "AppAttestationUnavailableError"
98
+ } else {
99
+ null
100
+ }
101
+
93
102
  private fun createGenericError(
94
103
  code: String,
95
104
  error: Throwable,
@@ -129,17 +138,3 @@ private fun createOnrampErrorMap(
129
138
  map.putMap("error", details)
130
139
  return map
131
140
  }
132
-
133
- private fun mapFromSdkVersions(
134
- sdkVersions: List<SDKVersion>,
135
- ): WritableArray =
136
- Arguments.createArray().apply {
137
- sdkVersions.forEach { sdkVersion ->
138
- pushMap(
139
- Arguments.createMap().apply {
140
- putString("name", sdkVersion.name)
141
- putString("version", sdkVersion.version)
142
- },
143
- )
144
- }
145
- }
@@ -10,10 +10,13 @@ import com.facebook.react.bridge.ReadableMap
10
10
  import com.facebook.react.bridge.WritableArray
11
11
  import com.stripe.android.core.model.CountryCode
12
12
  import com.stripe.android.crypto.onramp.ExperimentalCryptoOnramp
13
+ import com.stripe.android.crypto.onramp.model.CryptoConsumerWallet
14
+ import com.stripe.android.crypto.onramp.model.CryptoNetwork
13
15
  import com.stripe.android.crypto.onramp.exception.SDKVersion
14
16
  import com.stripe.android.crypto.onramp.model.KycInfo
15
17
  import com.stripe.android.crypto.onramp.model.OnrampConfiguration
16
18
  import com.stripe.android.crypto.onramp.model.PaymentMethodDisplayData
19
+ import com.stripe.android.crypto.onramp.model.WalletOwnershipChallenge
17
20
  import com.stripe.android.crypto.onramp.model.compliance.ComplianceIdentifier
18
21
  import com.stripe.android.crypto.onramp.model.compliance.ComplianceIdentifierAlternativeGroup
19
22
  import com.stripe.android.crypto.onramp.model.compliance.ComplianceIdentifierRequirement
@@ -203,6 +206,51 @@ internal fun mapFromKycInfo(kycInfo: KycInfo): ReadableMap {
203
206
  return result
204
207
  }
205
208
 
209
+ internal fun mapFromWalletOwnershipChallenge(challenge: WalletOwnershipChallenge) =
210
+ mapFromWalletOwnershipChallenge(
211
+ challengeId = challenge.challengeId,
212
+ walletAddress = challenge.walletAddress,
213
+ network = challenge.network,
214
+ message = challenge.message,
215
+ expiresAt = challenge.expiresAt,
216
+ )
217
+
218
+ internal fun mapFromWalletOwnershipChallenge(
219
+ challengeId: String,
220
+ walletAddress: String,
221
+ network: CryptoNetwork,
222
+ message: String,
223
+ expiresAt: String,
224
+ ) =
225
+ Arguments.createMap().apply {
226
+ putString("challengeId", challengeId)
227
+ putString("walletAddress", walletAddress)
228
+ putString("network", network.value)
229
+ putString("message", message)
230
+ putString("expiresAt", expiresAt)
231
+ }
232
+
233
+ internal fun mapFromCryptoConsumerWallet(wallet: CryptoConsumerWallet) =
234
+ mapFromCryptoConsumerWallet(
235
+ id = wallet.id,
236
+ network = wallet.network,
237
+ walletAddress = wallet.walletAddress,
238
+ verifiedOwnership = wallet.verifiedOwnership,
239
+ )
240
+
241
+ internal fun mapFromCryptoConsumerWallet(
242
+ id: String,
243
+ network: CryptoNetwork,
244
+ walletAddress: String,
245
+ verifiedOwnership: Boolean,
246
+ ) =
247
+ Arguments.createMap().apply {
248
+ putString("id", id)
249
+ putString("walletAddress", walletAddress)
250
+ putString("network", network.value)
251
+ putBoolean("verifiedOwnership", verifiedOwnership)
252
+ }
253
+
206
254
  internal fun mapToComplianceIdentifiers(identifiers: ReadableArray): List<ComplianceIdentifier> {
207
255
  val complianceIdentifiers = mutableListOf<ComplianceIdentifier>()
208
256