@stripe/stripe-react-native 0.54.1 → 0.55.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +11 -0
  2. package/android/gradle.properties +1 -1
  3. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementView.kt +120 -57
  4. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementViewManager.kt +5 -0
  5. package/android/src/main/java/com/reactnativestripesdk/EventEmitterCompat.kt +4 -0
  6. package/android/src/main/java/com/reactnativestripesdk/PaymentLauncherFragment.kt +1 -0
  7. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetFragment.kt +54 -8
  8. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +18 -0
  9. package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +84 -1
  10. package/android/src/oldarch/java/com/reactnativestripesdk/NativeStripeSdkModuleSpec.java +4 -0
  11. package/ios/Errors.swift +3 -2
  12. package/ios/Mappers.swift +111 -18
  13. package/ios/OldArch/StripeSdkEventEmitterCompat.h +1 -0
  14. package/ios/OldArch/StripeSdkEventEmitterCompat.m +6 -0
  15. package/ios/PaymentSheetAppearance.swift +15 -0
  16. package/ios/StripeSdk.mm +7 -0
  17. package/ios/StripeSdkEmitter.swift +1 -0
  18. package/ios/StripeSdkImpl+Embedded.swift +26 -4
  19. package/ios/StripeSdkImpl+PaymentSheet.swift +37 -15
  20. package/ios/StripeSdkImpl.swift +18 -1
  21. package/lib/commonjs/components/AddToWalletButton.js +1 -1
  22. package/lib/commonjs/components/AddToWalletButton.js.map +1 -1
  23. package/lib/commonjs/components/AddressSheet.js +1 -1
  24. package/lib/commonjs/components/AddressSheet.js.map +1 -1
  25. package/lib/commonjs/components/AuBECSDebitForm.js +1 -1
  26. package/lib/commonjs/components/AuBECSDebitForm.js.map +1 -1
  27. package/lib/commonjs/components/CardField.js +1 -1
  28. package/lib/commonjs/components/CardField.js.map +1 -1
  29. package/lib/commonjs/components/CardForm.js +1 -1
  30. package/lib/commonjs/components/CardForm.js.map +1 -1
  31. package/lib/commonjs/components/PlatformPayButton.js +1 -1
  32. package/lib/commonjs/components/PlatformPayButton.js.map +1 -1
  33. package/lib/commonjs/components/StripeContainer.js +1 -1
  34. package/lib/commonjs/components/StripeContainer.js.map +1 -1
  35. package/lib/commonjs/events.js.map +1 -1
  36. package/lib/commonjs/functions.js +1 -1
  37. package/lib/commonjs/functions.js.map +1 -1
  38. package/lib/commonjs/index.js +1 -1
  39. package/lib/commonjs/index.js.map +1 -1
  40. package/lib/commonjs/specs/NativeStripeSdkModule.js.map +1 -1
  41. package/lib/commonjs/types/ConfirmationToken.js +2 -0
  42. package/lib/commonjs/types/ConfirmationToken.js.map +1 -0
  43. package/lib/commonjs/types/EmbeddedPaymentElement.js +1 -1
  44. package/lib/commonjs/types/EmbeddedPaymentElement.js.map +1 -1
  45. package/lib/commonjs/types/PaymentSheet.js +1 -1
  46. package/lib/commonjs/types/PaymentSheet.js.map +1 -1
  47. package/lib/commonjs/types/index.js +1 -1
  48. package/lib/commonjs/types/index.js.map +1 -1
  49. package/lib/module/components/AddToWalletButton.js +1 -1
  50. package/lib/module/components/AddToWalletButton.js.map +1 -1
  51. package/lib/module/components/AddressSheet.js +1 -1
  52. package/lib/module/components/AddressSheet.js.map +1 -1
  53. package/lib/module/components/AuBECSDebitForm.js +1 -1
  54. package/lib/module/components/AuBECSDebitForm.js.map +1 -1
  55. package/lib/module/components/CardField.js +1 -1
  56. package/lib/module/components/CardField.js.map +1 -1
  57. package/lib/module/components/CardForm.js +1 -1
  58. package/lib/module/components/CardForm.js.map +1 -1
  59. package/lib/module/components/PlatformPayButton.js +1 -1
  60. package/lib/module/components/PlatformPayButton.js.map +1 -1
  61. package/lib/module/components/StripeContainer.js +1 -1
  62. package/lib/module/components/StripeContainer.js.map +1 -1
  63. package/lib/module/events.js.map +1 -1
  64. package/lib/module/functions.js +1 -1
  65. package/lib/module/functions.js.map +1 -1
  66. package/lib/module/index.js +1 -1
  67. package/lib/module/index.js.map +1 -1
  68. package/lib/module/specs/NativeStripeSdkModule.js.map +1 -1
  69. package/lib/module/types/ConfirmationToken.js +2 -0
  70. package/lib/module/types/ConfirmationToken.js.map +1 -0
  71. package/lib/module/types/EmbeddedPaymentElement.js +1 -1
  72. package/lib/module/types/EmbeddedPaymentElement.js.map +1 -1
  73. package/lib/module/types/PaymentSheet.js +1 -1
  74. package/lib/module/types/PaymentSheet.js.map +1 -1
  75. package/lib/module/types/index.js +1 -1
  76. package/lib/module/types/index.js.map +1 -1
  77. package/lib/typescript/src/events.d.ts +4 -0
  78. package/lib/typescript/src/events.d.ts.map +1 -1
  79. package/lib/typescript/src/functions.d.ts.map +1 -1
  80. package/lib/typescript/src/index.d.ts +1 -0
  81. package/lib/typescript/src/index.d.ts.map +1 -1
  82. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts +1 -0
  83. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts.map +1 -1
  84. package/lib/typescript/src/types/ConfirmationToken.d.ts +59 -0
  85. package/lib/typescript/src/types/ConfirmationToken.d.ts.map +1 -0
  86. package/lib/typescript/src/types/EmbeddedPaymentElement.d.ts.map +1 -1
  87. package/lib/typescript/src/types/PaymentSheet.d.ts +52 -3
  88. package/lib/typescript/src/types/PaymentSheet.d.ts.map +1 -1
  89. package/lib/typescript/src/types/index.d.ts +2 -1
  90. package/lib/typescript/src/types/index.d.ts.map +1 -1
  91. package/package.json +1 -1
  92. package/src/events.ts +4 -0
  93. package/src/functions.ts +16 -0
  94. package/src/index.tsx +1 -0
  95. package/src/specs/NativeStripeSdkModule.ts +3 -0
  96. package/src/types/ConfirmationToken.ts +76 -0
  97. package/src/types/EmbeddedPaymentElement.tsx +21 -0
  98. package/src/types/PaymentSheet.ts +60 -11
  99. package/src/types/index.ts +2 -0
  100. package/stripe-react-native.podspec +1 -1
  101. package/android/.idea/AndroidProjectSystem.xml +0 -6
  102. package/android/.idea/caches/deviceStreaming.xml +0 -703
  103. package/android/.idea/compiler.xml +0 -6
  104. package/android/.idea/gradle.xml +0 -18
  105. package/android/.idea/migrations.xml +0 -10
  106. package/android/.idea/misc.xml +0 -10
  107. package/android/.idea/runConfigurations.xml +0 -17
  108. package/android/.idea/vcs.xml +0 -6
  109. package/android/local.properties +0 -8
package/README.md CHANGED
@@ -282,3 +282,14 @@ If you're still having troubles, please [open an issue](https://github.com/strip
282
282
  ### `Apple Pay Is Not Available in "My App Name"`
283
283
 
284
284
  This can occur if you attempt to process an Apple Pay payment on a physical device (even in test mode) without having created **and uploaded** your Apple Pay Certificate to the Stripe Dashboard. Learn how to do that [here](https://stripe.com/docs/apple-pay#csr).
285
+
286
+ ### `UnsupportedModulePropertyParserError` on iOS
287
+
288
+ While installing pods in your iOS project using a Stripe React Native version before 0.52, the old architecture, and a React Native version after 0.74, you may encounter the following error:
289
+
290
+ ```
291
+ UnsupportedModulePropertyParserError: Module NativeStripeSdkModule: TypeScript interfaces extending TurboModule must only contain 'FunctionTypeAnnotation's. Property 'onConfirmHandlerCallback' refers to a 'TSTypeReference'.
292
+ ```
293
+
294
+ If possible, update to version 0.52 or above of the Stripe React Native SDK.
295
+ If you are unable to do so, please follow our [guide to apply the fix patch](https://github.com/stripe/stripe-react-native/tree/master/patches).
@@ -3,4 +3,4 @@ StripeSdk_compileSdkVersion=30
3
3
  StripeSdk_targetSdkVersion=28
4
4
  StripeSdk_minSdkVersion=21
5
5
  # Keep StripeSdk_stripeVersion in sync with https://github.com/stripe/stripe-identity-react-native/blob/main/android/gradle.properties
6
- StripeSdk_stripeVersion=21.26.+
6
+ StripeSdk_stripeVersion=21.29.0
@@ -1,5 +1,6 @@
1
1
  package com.reactnativestripesdk
2
2
 
3
+ import android.annotation.SuppressLint
3
4
  import android.content.Context
4
5
  import android.content.Intent
5
6
  import android.util.Log
@@ -23,6 +24,7 @@ import com.facebook.react.bridge.Arguments
23
24
  import com.facebook.react.uimanager.ThemedReactContext
24
25
  import com.reactnativestripesdk.toWritableMap
25
26
  import com.reactnativestripesdk.utils.KeepJsAwakeTask
27
+ import com.reactnativestripesdk.utils.mapFromConfirmationToken
26
28
  import com.reactnativestripesdk.utils.mapFromCustomPaymentMethod
27
29
  import com.reactnativestripesdk.utils.mapFromPaymentMethod
28
30
  import com.stripe.android.model.PaymentMethod
@@ -63,10 +65,16 @@ class EmbeddedPaymentElementView(
63
65
  var latestElementConfig: EmbeddedPaymentElement.Configuration? = null
64
66
 
65
67
  val rowSelectionBehaviorType = mutableStateOf<RowSelectionBehaviorType?>(null)
68
+ val useConfirmationTokenCallback = mutableStateOf(false)
66
69
 
67
70
  private val reactContext get() = context as ThemedReactContext
68
71
  private val events = Channel<Event>(Channel.UNLIMITED)
69
72
 
73
+ fun setUseConfirmationTokenCallback(value: Boolean) {
74
+ useConfirmationTokenCallback.value = value
75
+ }
76
+
77
+ @SuppressLint("RestrictedApi")
70
78
  @OptIn(ExperimentalCustomPaymentMethodsApi::class)
71
79
  @Composable
72
80
  override fun Content() {
@@ -153,73 +161,128 @@ class EmbeddedPaymentElementView(
153
161
  }
154
162
  }
155
163
 
156
- val builder =
157
- remember(type) {
158
- EmbeddedPaymentElement
159
- .Builder(
160
- createIntentCallback = { paymentMethod, shouldSavePaymentMethod ->
161
- val stripeSdkModule =
162
- try {
163
- requireStripeSdkModule()
164
- } catch (ex: IllegalArgumentException) {
165
- return@Builder CreateIntentResult.Failure(
166
- cause =
167
- Exception(
168
- "Tried to call confirmHandler, but no callback was found. Please file an issue: https://github.com/stripe/stripe-react-native/issues",
169
- ),
170
- displayMessage = "An unexpected error occurred",
171
- )
164
+ val useConfirmationToken by remember { useConfirmationTokenCallback }
165
+
166
+ val resultCallback =
167
+ remember {
168
+ { result: EmbeddedPaymentElement.Result ->
169
+ val map =
170
+ Arguments.createMap().apply {
171
+ when (result) {
172
+ is EmbeddedPaymentElement.Result.Completed -> {
173
+ putString("status", "completed")
172
174
  }
173
175
 
174
- // Make sure that JS is active since the activity will be paused when stripe ui is presented.
175
- val keepJsAwakeTask =
176
- KeepJsAwakeTask(reactContext.reactApplicationContext).apply { start() }
176
+ is EmbeddedPaymentElement.Result.Canceled -> {
177
+ putString("status", "canceled")
178
+ }
177
179
 
178
- val params =
179
- Arguments.createMap().apply {
180
- putMap("paymentMethod", mapFromPaymentMethod(paymentMethod))
181
- putBoolean("shouldSavePaymentMethod", shouldSavePaymentMethod)
180
+ is EmbeddedPaymentElement.Result.Failed -> {
181
+ putString("status", "failed")
182
+ putString("error", result.error.message ?: "Unknown error")
182
183
  }
184
+ }
185
+ }
186
+ requireStripeSdkModule().eventEmitter.emitEmbeddedPaymentElementFormSheetConfirmComplete(map)
187
+ }
188
+ }
183
189
 
184
- stripeSdkModule.eventEmitter.emitOnConfirmHandlerCallback(params)
190
+ val builder =
191
+ remember(type, useConfirmationToken) {
192
+ if (useConfirmationToken) {
193
+ EmbeddedPaymentElement
194
+ .Builder(
195
+ createIntentCallback = { confirmationToken ->
196
+ val stripeSdkModule =
197
+ try {
198
+ requireStripeSdkModule()
199
+ } catch (ex: IllegalArgumentException) {
200
+ return@Builder CreateIntentResult.Failure(
201
+ cause =
202
+ Exception(
203
+ "Tried to call confirmationTokenConfirmHandler, but no callback was found. Please file an issue: https://github.com/stripe/stripe-react-native/issues",
204
+ ),
205
+ displayMessage = "An unexpected error occurred",
206
+ )
207
+ }
185
208
 
186
- val resultFromJavascript = stripeSdkModule.embeddedIntentCreationCallback.await()
187
- // reset the completable
188
- stripeSdkModule.embeddedIntentCreationCallback = CompletableDeferred()
209
+ // Make sure that JS is active since the activity will be paused when stripe ui is presented.
210
+ val keepJsAwakeTask =
211
+ KeepJsAwakeTask(reactContext.reactApplicationContext).apply { start() }
189
212
 
190
- keepJsAwakeTask.stop()
213
+ val params =
214
+ Arguments.createMap().apply {
215
+ putMap("confirmationToken", mapFromConfirmationToken(confirmationToken))
216
+ }
191
217
 
192
- resultFromJavascript.getString("clientSecret")?.let {
193
- CreateIntentResult.Success(clientSecret = it)
194
- } ?: run {
195
- val errorMap = resultFromJavascript.getMap("error")
196
- CreateIntentResult.Failure(
197
- cause = Exception(errorMap?.getString("message")),
198
- displayMessage = errorMap?.getString("localizedMessage"),
199
- )
200
- }
201
- },
202
- resultCallback = { result ->
203
- val map =
204
- Arguments.createMap().apply {
205
- when (result) {
206
- is EmbeddedPaymentElement.Result.Completed -> {
207
- putString("status", "completed")
208
- }
209
-
210
- is EmbeddedPaymentElement.Result.Canceled -> {
211
- putString("status", "canceled")
212
- }
213
-
214
- is EmbeddedPaymentElement.Result.Failed -> {
215
- putString("status", "failed")
216
- putString("error", result.error.message ?: "Unknown error")
217
- }
218
+ stripeSdkModule.eventEmitter.emitOnConfirmationTokenHandlerCallback(params)
219
+
220
+ val resultFromJavascript = stripeSdkModule.embeddedConfirmationTokenCreationCallback.await()
221
+ // reset the completable
222
+ stripeSdkModule.embeddedConfirmationTokenCreationCallback = CompletableDeferred()
223
+
224
+ keepJsAwakeTask.stop()
225
+
226
+ resultFromJavascript.getString("clientSecret")?.let {
227
+ CreateIntentResult.Success(clientSecret = it)
228
+ } ?: run {
229
+ val errorMap = resultFromJavascript.getMap("error")
230
+ CreateIntentResult.Failure(
231
+ cause = Exception(errorMap?.getString("message")),
232
+ displayMessage = errorMap?.getString("localizedMessage"),
233
+ )
234
+ }
235
+ },
236
+ resultCallback = resultCallback,
237
+ )
238
+ } else {
239
+ EmbeddedPaymentElement
240
+ .Builder(
241
+ createIntentCallback = { paymentMethod, shouldSavePaymentMethod ->
242
+ val stripeSdkModule =
243
+ try {
244
+ requireStripeSdkModule()
245
+ } catch (ex: IllegalArgumentException) {
246
+ return@Builder CreateIntentResult.Failure(
247
+ cause =
248
+ Exception(
249
+ "Tried to call confirmHandler, but no callback was found. Please file an issue: https://github.com/stripe/stripe-react-native/issues",
250
+ ),
251
+ displayMessage = "An unexpected error occurred",
252
+ )
218
253
  }
254
+
255
+ // Make sure that JS is active since the activity will be paused when stripe ui is presented.
256
+ val keepJsAwakeTask =
257
+ KeepJsAwakeTask(reactContext.reactApplicationContext).apply { start() }
258
+
259
+ val params =
260
+ Arguments.createMap().apply {
261
+ putMap("paymentMethod", mapFromPaymentMethod(paymentMethod))
262
+ putBoolean("shouldSavePaymentMethod", shouldSavePaymentMethod)
263
+ }
264
+
265
+ stripeSdkModule.eventEmitter.emitOnConfirmHandlerCallback(params)
266
+
267
+ val resultFromJavascript = stripeSdkModule.embeddedIntentCreationCallback.await()
268
+ // reset the completable
269
+ stripeSdkModule.embeddedIntentCreationCallback = CompletableDeferred()
270
+
271
+ keepJsAwakeTask.stop()
272
+
273
+ resultFromJavascript.getString("clientSecret")?.let {
274
+ CreateIntentResult.Success(clientSecret = it)
275
+ } ?: run {
276
+ val errorMap = resultFromJavascript.getMap("error")
277
+ CreateIntentResult.Failure(
278
+ cause = Exception(errorMap?.getString("message")),
279
+ displayMessage = errorMap?.getString("localizedMessage"),
280
+ )
219
281
  }
220
- requireStripeSdkModule().eventEmitter.emitEmbeddedPaymentElementFormSheetConfirmComplete(map)
221
- },
222
- ).confirmCustomPaymentMethodCallback(confirmCustomPaymentMethodCallback)
282
+ },
283
+ resultCallback = resultCallback,
284
+ )
285
+ }.confirmCustomPaymentMethodCallback(confirmCustomPaymentMethodCallback)
223
286
  .rowSelectionBehavior(
224
287
  if (type == RowSelectionBehaviorType.Default) {
225
288
  EmbeddedPaymentElement.RowSelectionBehavior.default()
@@ -80,6 +80,11 @@ class EmbeddedPaymentElementViewManager :
80
80
  ) {
81
81
  val readableMap = cfg.asMap()
82
82
  if (readableMap == null) return
83
+
84
+ // Detect which callback type to use based on the presence of the confirmation token handler
85
+ val useConfirmationTokenCallback = readableMap.hasKey("confirmationTokenConfirmHandler")
86
+ view.setUseConfirmationTokenCallback(useConfirmationTokenCallback)
87
+
83
88
  val intentConfig = parseIntentConfiguration(readableMap)
84
89
  view.latestIntentConfig = intentConfig
85
90
  view.latestElementConfig?.let { elemCfg ->
@@ -24,6 +24,10 @@ class EventEmitterCompat(
24
24
  invoke("onConfirmHandlerCallback", value)
25
25
  }
26
26
 
27
+ fun emitOnConfirmationTokenHandlerCallback(value: ReadableMap?) {
28
+ invoke("onConfirmationTokenHandlerCallback", value)
29
+ }
30
+
27
31
  fun emitOnFinancialConnectionsEvent(value: ReadableMap?) {
28
32
  invoke("onFinancialConnectionsEvent", value)
29
33
  }
@@ -384,6 +384,7 @@ class PaymentLauncherFragment : StripeFragment() {
384
384
  StripeIntent.NextActionType.VerifyWithMicrodeposits,
385
385
  StripeIntent.NextActionType.DisplayMultibancoDetails,
386
386
  StripeIntent.NextActionType.DisplayPayNowDetails,
387
+ StripeIntent.NextActionType.DisplayPromptPayDetails,
387
388
  -> true
388
389
  StripeIntent.NextActionType.RedirectToUrl,
389
390
  StripeIntent.NextActionType.UseStripeSdk,
@@ -1,5 +1,6 @@
1
1
  package com.reactnativestripesdk
2
2
 
3
+ import android.annotation.SuppressLint
3
4
  import android.app.Activity
4
5
  import android.app.Application
5
6
  import android.content.Context
@@ -30,6 +31,7 @@ import com.reactnativestripesdk.utils.PaymentSheetException
30
31
  import com.reactnativestripesdk.utils.StripeFragment
31
32
  import com.reactnativestripesdk.utils.createError
32
33
  import com.reactnativestripesdk.utils.createResult
34
+ import com.reactnativestripesdk.utils.mapFromConfirmationToken
33
35
  import com.reactnativestripesdk.utils.mapFromCustomPaymentMethod
34
36
  import com.reactnativestripesdk.utils.mapFromPaymentMethod
35
37
  import com.reactnativestripesdk.utils.mapToPreferredNetworks
@@ -38,6 +40,7 @@ import com.reactnativestripesdk.utils.removeFragment
38
40
  import com.stripe.android.ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi
39
41
  import com.stripe.android.model.PaymentMethod
40
42
  import com.stripe.android.paymentelement.ConfirmCustomPaymentMethodCallback
43
+ import com.stripe.android.paymentelement.CreateIntentWithConfirmationTokenCallback
41
44
  import com.stripe.android.paymentelement.CustomPaymentMethodResult
42
45
  import com.stripe.android.paymentelement.CustomPaymentMethodResultHandler
43
46
  import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi
@@ -73,8 +76,10 @@ class PaymentSheetFragment :
73
76
  private var presentPromise: Promise? = null
74
77
  private var paymentSheetTimedOut = false
75
78
  internal var paymentSheetIntentCreationCallback = CompletableDeferred<ReadableMap>()
79
+ internal var paymentSheetConfirmationTokenCreationCallback = CompletableDeferred<ReadableMap>()
76
80
  private var keepJsAwake: KeepJsAwakeTask? = null
77
81
 
82
+ @SuppressLint("RestrictedApi")
78
83
  @OptIn(ExperimentalCustomPaymentMethodsApi::class)
79
84
  override fun prepare() {
80
85
  val merchantDisplayName = arguments?.getString("merchantDisplayName").orEmpty()
@@ -102,6 +107,10 @@ class PaymentSheetFragment :
102
107
  initPromise.resolve(createError(ErrorType.Failed.toString(), error))
103
108
  return
104
109
  }
110
+
111
+ // Determine which callback type to use based on what's provided
112
+ val intentConfigBundle = arguments?.getBundle("intentConfiguration")
113
+ val useConfirmationTokenCallback = intentConfigBundle?.containsKey("confirmationTokenConfirmHandler") == true
105
114
  val appearance =
106
115
  try {
107
116
  buildPaymentSheetAppearance(arguments?.getBundle("appearance"), context)
@@ -212,6 +221,32 @@ class PaymentSheetFragment :
212
221
  }
213
222
  }
214
223
 
224
+ val createConfirmationTokenCallback =
225
+ CreateIntentWithConfirmationTokenCallback { confirmationToken ->
226
+ val stripeSdkModule: StripeSdkModule? = context.getNativeModule(StripeSdkModule::class.java)
227
+ val params =
228
+ Arguments.createMap().apply {
229
+ putMap("confirmationToken", mapFromConfirmationToken(confirmationToken))
230
+ }
231
+
232
+ stripeSdkModule?.eventEmitter?.emitOnConfirmationTokenHandlerCallback(params)
233
+
234
+ val resultFromJavascript = paymentSheetConfirmationTokenCreationCallback.await()
235
+ // reset the completable
236
+ paymentSheetConfirmationTokenCreationCallback = CompletableDeferred<ReadableMap>()
237
+
238
+ return@CreateIntentWithConfirmationTokenCallback resultFromJavascript.getString("clientSecret")?.let {
239
+ CreateIntentResult.Success(clientSecret = it)
240
+ }
241
+ ?: run {
242
+ val errorMap = resultFromJavascript.getMap("error")
243
+ CreateIntentResult.Failure(
244
+ cause = Exception(errorMap?.getString("message")),
245
+ displayMessage = errorMap?.getString("localizedMessage"),
246
+ )
247
+ }
248
+ }
249
+
215
250
  val billingDetailsConfig =
216
251
  PaymentSheet.BillingDetailsCollectionConfiguration(
217
252
  name = mapToCollectionMode(billingConfigParams?.getString("name")),
@@ -271,11 +306,18 @@ class PaymentSheetFragment :
271
306
  if (arguments?.getBoolean("customFlow") == true) {
272
307
  flowController =
273
308
  if (intentConfiguration != null) {
274
- PaymentSheet.FlowController
275
- .Builder(
276
- resultCallback = paymentResultCallback,
277
- paymentOptionResultCallback = paymentOptionCallback,
278
- ).createIntentCallback(createIntentCallback)
309
+ val builder =
310
+ PaymentSheet.FlowController
311
+ .Builder(
312
+ resultCallback = paymentResultCallback,
313
+ paymentOptionResultCallback = paymentOptionCallback,
314
+ )
315
+ if (useConfirmationTokenCallback) {
316
+ builder.createIntentCallback(createConfirmationTokenCallback)
317
+ } else {
318
+ builder.createIntentCallback(createIntentCallback)
319
+ }
320
+ builder
279
321
  .confirmCustomPaymentMethodCallback(this)
280
322
  .build(this)
281
323
  } else {
@@ -290,9 +332,13 @@ class PaymentSheetFragment :
290
332
  } else {
291
333
  paymentSheet =
292
334
  if (intentConfiguration != null) {
293
- PaymentSheet
294
- .Builder(paymentResultCallback)
295
- .createIntentCallback(createIntentCallback)
335
+ val builder = PaymentSheet.Builder(paymentResultCallback)
336
+ if (useConfirmationTokenCallback) {
337
+ builder.createIntentCallback(createConfirmationTokenCallback)
338
+ } else {
339
+ builder.createIntentCallback(createIntentCallback)
340
+ }
341
+ builder
296
342
  .confirmCustomPaymentMethodCallback(this)
297
343
  .build(this)
298
344
  } else {
@@ -94,7 +94,9 @@ class StripeSdkModule(
94
94
  private var customerSheetFragment: CustomerSheetFragment? = null
95
95
 
96
96
  internal var embeddedIntentCreationCallback = CompletableDeferred<ReadableMap>()
97
+ internal var embeddedConfirmationTokenCreationCallback = CompletableDeferred<ReadableMap>()
97
98
  internal var customPaymentMethodResultCallback = CompletableDeferred<ReadableMap>()
99
+ internal var paymentSheetConfirmationTokenCreationCallback = CompletableDeferred<ReadableMap>()
98
100
 
99
101
  internal var composeCompatView: StripeAbstractComposeView.CompatView? = null
100
102
 
@@ -323,6 +325,22 @@ class StripeSdkModule(
323
325
  promise?.resolve(null)
324
326
  }
325
327
 
328
+ @ReactMethod
329
+ override fun confirmationTokenCreationCallback(
330
+ params: ReadableMap,
331
+ promise: Promise,
332
+ ) {
333
+ embeddedConfirmationTokenCreationCallback.complete(params)
334
+ paymentSheetConfirmationTokenCreationCallback.complete(params)
335
+
336
+ if (paymentSheetFragment == null) {
337
+ promise.resolve(PaymentSheetFragment.createMissingInitError())
338
+ return
339
+ }
340
+
341
+ paymentSheetFragment?.paymentSheetConfirmationTokenCreationCallback?.complete(params)
342
+ }
343
+
326
344
  @ReactMethod
327
345
  override fun createPaymentMethod(
328
346
  data: ReadableMap,
@@ -18,6 +18,7 @@ import com.stripe.android.model.BankAccountTokenParams
18
18
  import com.stripe.android.model.Card
19
19
  import com.stripe.android.model.CardBrand
20
20
  import com.stripe.android.model.ConfirmPaymentIntentParams
21
+ import com.stripe.android.model.ConfirmationToken
21
22
  import com.stripe.android.model.GooglePayResult
22
23
  import com.stripe.android.model.MicrodepositType
23
24
  import com.stripe.android.model.PaymentIntent
@@ -152,6 +153,7 @@ internal fun mapPaymentMethodType(type: PaymentMethod.Type?): String =
152
153
  PaymentMethod.Type.Affirm -> "Affirm"
153
154
  PaymentMethod.Type.CashAppPay -> "CashApp"
154
155
  PaymentMethod.Type.RevolutPay -> "RevolutPay"
156
+ PaymentMethod.Type.Link -> "Link"
155
157
  else -> "Unknown"
156
158
  }
157
159
 
@@ -183,6 +185,7 @@ internal fun mapToPaymentMethodType(type: String?): PaymentMethod.Type? =
183
185
  "Affirm" -> PaymentMethod.Type.Affirm
184
186
  "CashApp" -> PaymentMethod.Type.CashAppPay
185
187
  "RevolutPay" -> PaymentMethod.Type.RevolutPay
188
+ "Link" -> PaymentMethod.Type.Link
186
189
  else -> null
187
190
  }
188
191
 
@@ -561,6 +564,7 @@ internal fun mapNextAction(
561
564
  NextActionType.UseStripeSdk,
562
565
  NextActionType.UpiAwaitNotification,
563
566
  NextActionType.DisplayPayNowDetails,
567
+ NextActionType.DisplayPromptPayDetails,
564
568
  null,
565
569
  -> {
566
570
  return null
@@ -1028,7 +1032,16 @@ internal fun mapToPreferredNetworks(networksAsInts: ArrayList<Int>?): List<CardB
1028
1032
  internal fun mapFromFinancialConnectionsEvent(event: FinancialConnectionsEvent): WritableMap =
1029
1033
  Arguments.createMap().apply {
1030
1034
  putString("name", event.name.value)
1031
- putMap("metadata", event.metadata.toMap().toReadableMap())
1035
+
1036
+ // We require keys to use pascal case, but the original map uses snake case.
1037
+ val tweakedMap =
1038
+ buildMap {
1039
+ put("institutionName", event.metadata.institutionName)
1040
+ put("manualEntry", event.metadata.manualEntry)
1041
+ put("errorCode", event.metadata.errorCode)
1042
+ }
1043
+
1044
+ putMap("metadata", tweakedMap.toReadableMap())
1032
1045
  }
1033
1046
 
1034
1047
  private fun List<Any?>.toWritableArray(): WritableArray {
@@ -1118,3 +1131,73 @@ internal fun mapFromCustomPaymentMethod(
1118
1131
  )
1119
1132
  putMap("billingDetails", mapFromBillingDetails(billingDetails))
1120
1133
  }
1134
+
1135
+ @SuppressLint("RestrictedApi")
1136
+ internal fun mapFromConfirmationToken(confirmationToken: ConfirmationToken): WritableMap {
1137
+ val token: WritableMap = WritableNativeMap()
1138
+
1139
+ token.putString("id", confirmationToken.id)
1140
+ token.putDouble("created", confirmationToken.created.toDouble())
1141
+ token.putDouble("expiresAt", confirmationToken.expiresAt?.toDouble() ?: 0.0)
1142
+ token.putBoolean("liveMode", confirmationToken.liveMode)
1143
+ token.putString("paymentIntentId", confirmationToken.paymentIntentId)
1144
+ token.putString("setupIntentId", confirmationToken.setupIntentId)
1145
+ token.putString("returnURL", confirmationToken.returnUrl)
1146
+ token.putString("setupFutureUsage", mapFromSetupFutureUsage(confirmationToken.setupFutureUsage))
1147
+
1148
+ // PaymentMethodPreview
1149
+ confirmationToken.paymentMethodPreview?.let { preview ->
1150
+ val paymentMethodPreview = WritableNativeMap()
1151
+ paymentMethodPreview.putString("type", mapPaymentMethodType(preview.type))
1152
+ paymentMethodPreview.putMap("billingDetails", mapFromBillingDetails(preview.billingDetails))
1153
+ paymentMethodPreview.putString("allowRedisplay", mapFromAllowRedisplay(preview.allowRedisplay))
1154
+ paymentMethodPreview.putString("customerId", preview.customerId)
1155
+ token.putMap("paymentMethodPreview", paymentMethodPreview)
1156
+ } ?: run {
1157
+ token.putNull("paymentMethodPreview")
1158
+ }
1159
+
1160
+ // Shipping details
1161
+ confirmationToken.shipping?.let { shippingDetails ->
1162
+ val shipping = WritableNativeMap()
1163
+ shipping.putString("name", shippingDetails.name)
1164
+ shipping.putString("phone", shippingDetails.phone)
1165
+
1166
+ shippingDetails.address?.let { address ->
1167
+ val addressMap = WritableNativeMap()
1168
+ addressMap.putString("city", address.city)
1169
+ addressMap.putString("country", address.country)
1170
+ addressMap.putString("line1", address.line1)
1171
+ addressMap.putString("line2", address.line2)
1172
+ addressMap.putString("postalCode", address.postalCode)
1173
+ addressMap.putString("state", address.state)
1174
+ shipping.putMap("address", addressMap)
1175
+ } ?: run {
1176
+ shipping.putMap("address", WritableNativeMap())
1177
+ }
1178
+
1179
+ token.putMap("shipping", shipping)
1180
+ } ?: run {
1181
+ token.putNull("shipping")
1182
+ }
1183
+
1184
+ return token
1185
+ }
1186
+
1187
+ @SuppressLint("RestrictedApi")
1188
+ private fun mapFromSetupFutureUsage(setupFutureUsage: ConfirmPaymentIntentParams.SetupFutureUsage?): String? =
1189
+ when (setupFutureUsage) {
1190
+ ConfirmPaymentIntentParams.SetupFutureUsage.OnSession -> "on_session"
1191
+ ConfirmPaymentIntentParams.SetupFutureUsage.OffSession -> "off_session"
1192
+ ConfirmPaymentIntentParams.SetupFutureUsage.Blank -> ""
1193
+ ConfirmPaymentIntentParams.SetupFutureUsage.None -> "none"
1194
+ null -> null
1195
+ }
1196
+
1197
+ private fun mapFromAllowRedisplay(allowRedisplay: PaymentMethod.AllowRedisplay?): String? =
1198
+ when (allowRedisplay) {
1199
+ PaymentMethod.AllowRedisplay.ALWAYS -> "always"
1200
+ PaymentMethod.AllowRedisplay.LIMITED -> "limited"
1201
+ PaymentMethod.AllowRedisplay.UNSPECIFIED -> "unspecified"
1202
+ null -> null
1203
+ }
@@ -158,6 +158,10 @@ public abstract class NativeStripeSdkModuleSpec extends ReactContextBaseJavaModu
158
158
  @DoNotStrip
159
159
  public abstract void intentCreationCallback(ReadableMap result, Promise promise);
160
160
 
161
+ @ReactMethod
162
+ @DoNotStrip
163
+ public abstract void confirmationTokenCreationCallback(ReadableMap result, Promise promise);
164
+
161
165
  @ReactMethod
162
166
  @DoNotStrip
163
167
  public abstract void customPaymentMethodResultCallback(ReadableMap result, Promise promise);
package/ios/Errors.swift CHANGED
@@ -14,9 +14,10 @@ class Errors {
14
14
 
15
15
  static internal let isSetiClientSecretValidRegex: NSRegularExpression? = try? NSRegularExpression(
16
16
  pattern: "^seti_[^_]+_secret_[^_]+$", options: [])
17
-
17
+
18
+ // The `uk_` prefix is used by the Stripe Dashboard Mobile App for MOTO
18
19
  static internal let isEKClientSecretValidRegex: NSRegularExpression? = try? NSRegularExpression(
19
- pattern: "^ek_[^_](.)+$", options: [])
20
+ pattern: "^(ek_|uk_)[^_](.)+$", options: [])
20
21
 
21
22
  class func isPIClientSecretValid(clientSecret: String) -> Bool {
22
23
  return (Errors.isPIClientSecretValidRegex?.numberOfMatches(