@stripe/stripe-react-native 0.65.0 → 0.66.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 (239) hide show
  1. package/README.md +2 -2
  2. package/android/detekt/detekt-baseline.xml +1 -76
  3. package/android/gradle.properties +4 -4
  4. package/android/src/main/java/com/reactnativestripesdk/AuBECSDebitFormView.kt +3 -1
  5. package/android/src/main/java/com/reactnativestripesdk/AuBECSDebitFormViewManager.kt +2 -1
  6. package/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt +56 -58
  7. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorElementEvent.kt +26 -0
  8. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorElementView.kt +139 -0
  9. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorElementViewManager.kt +59 -0
  10. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementView.kt +105 -49
  11. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementViewManager.kt +72 -12
  12. package/android/src/main/java/com/reactnativestripesdk/EventEmitterCompat.kt +4 -0
  13. package/android/src/main/java/com/reactnativestripesdk/FinancialConnectionsSheetManager.kt +8 -4
  14. package/android/src/main/java/com/reactnativestripesdk/GooglePayButtonManager.kt +2 -1
  15. package/android/src/main/java/com/reactnativestripesdk/GooglePayButtonView.kt +26 -11
  16. package/android/src/main/java/com/reactnativestripesdk/GooglePayLauncherManager.kt +2 -1
  17. package/android/src/main/java/com/reactnativestripesdk/NavigationBarView.kt +14 -5
  18. package/android/src/main/java/com/reactnativestripesdk/PaymentElementConfig.kt +6 -2
  19. package/android/src/main/java/com/reactnativestripesdk/PaymentLauncherManager.kt +2 -1
  20. package/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt +2 -1
  21. package/android/src/main/java/com/reactnativestripesdk/PaymentMethodMessagingElementConfig.kt +6 -2
  22. package/android/src/main/java/com/reactnativestripesdk/PaymentMethodMessagingElementViewManager.kt +2 -1
  23. package/android/src/main/java/com/reactnativestripesdk/PaymentOptionDisplayDataMapper.kt +8 -4
  24. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt +9 -3
  25. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetManager.kt +118 -48
  26. package/android/src/main/java/com/reactnativestripesdk/StripeAbstractComposeView.kt +1 -0
  27. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +281 -46
  28. package/android/src/main/java/com/reactnativestripesdk/StripeSdkPackage.kt +2 -0
  29. package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressLauncherManager.kt +2 -1
  30. package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressSheetView.kt +3 -1
  31. package/android/src/main/java/com/reactnativestripesdk/customersheet/CustomerSheetManager.kt +8 -18
  32. package/android/src/main/java/com/reactnativestripesdk/customersheet/ReactNativeCustomerAdapter.kt +3 -1
  33. package/android/src/main/java/com/reactnativestripesdk/customersheet/ReactNativeCustomerSessionProvider.kt +2 -1
  34. package/android/src/main/java/com/reactnativestripesdk/pushprovisioning/AddToWalletButtonManager.kt +2 -1
  35. package/android/src/main/java/com/reactnativestripesdk/utils/CheckoutAddressUpdate.kt +45 -0
  36. package/android/src/main/java/com/reactnativestripesdk/utils/CheckoutMappers.kt +127 -0
  37. package/android/src/main/java/com/reactnativestripesdk/utils/DefaultActivityLifecycleCallbacks.kt +41 -0
  38. package/android/src/main/java/com/reactnativestripesdk/utils/Errors.kt +4 -2
  39. package/android/src/main/java/com/reactnativestripesdk/utils/Extensions.kt +5 -1
  40. package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +29 -13
  41. package/android/src/main/java/com/reactnativestripesdk/utils/PostalCodeUtilities.kt +2 -1
  42. package/android/src/oldarch/java/com/facebook/react/viewmanagers/EmbeddedPaymentElementViewManagerDelegate.java +6 -0
  43. package/android/src/oldarch/java/com/facebook/react/viewmanagers/EmbeddedPaymentElementViewManagerInterface.java +2 -0
  44. package/android/src/oldarch/java/com/facebook/react/viewmanagers/StripeCurrencySelectorElementManagerDelegate.java +35 -0
  45. package/android/src/oldarch/java/com/facebook/react/viewmanagers/StripeCurrencySelectorElementManagerInterface.java +18 -0
  46. package/android/src/oldarch/java/com/reactnativestripesdk/NativeOnrampSdkModuleSpec.java +17 -3
  47. package/android/src/oldarch/java/com/reactnativestripesdk/NativeStripeSdkModuleSpec.java +13 -1
  48. package/android/src/onramp/java/com/reactnativestripesdk/OnrampMappers.kt +116 -0
  49. package/android/src/onramp/java/com/reactnativestripesdk/OnrampSdkModule.kt +109 -1
  50. package/android/src/test/java/com/reactnativestripesdk/DrawableLoadingTest.kt +6 -2
  51. package/android/src/test/java/com/reactnativestripesdk/mappers/MappersTest.kt +60 -0
  52. package/android/src/test/java/com/reactnativestripesdk/mappers/OnrampMappersTest.kt +145 -0
  53. package/android/src/test/java/com/reactnativestripesdk/mappers/PaymentOptionDisplayDataMapperTest.kt +9 -4
  54. package/android/src/test/java/com/reactnativestripesdk/utils/CheckoutMappersTest.kt +98 -0
  55. package/android/src/test/java/com/reactnativestripesdk/utils/CheckoutTestFixtures.java +57 -0
  56. package/ios/ConnectAccountOnboarding/ConnectAccountOnboardingViewController.swift +6 -8
  57. package/ios/CurrencySelectorElementManager.m +16 -0
  58. package/ios/CurrencySelectorElementView.swift +159 -0
  59. package/ios/EmbeddedPaymentElementView.swift +1 -1
  60. package/ios/Mappers+Checkout.swift +337 -0
  61. package/ios/Mappers.swift +90 -2
  62. package/ios/NewArch/EmbeddedPaymentElementViewComponentView.mm +16 -2
  63. package/ios/NewArch/StripeCurrencySelectorElementComponentView.h +10 -0
  64. package/ios/NewArch/StripeCurrencySelectorElementComponentView.mm +89 -0
  65. package/ios/OldArch/StripeSdkEventEmitterCompat.h +1 -0
  66. package/ios/OldArch/StripeSdkEventEmitterCompat.m +6 -0
  67. package/ios/PaymentOptionDisplayData+ReactNative.swift +1 -1
  68. package/ios/PaymentSheetAppearance.swift +1 -1
  69. package/ios/StripeOnrampSdk.mm +19 -0
  70. package/ios/StripeSdk.mm +136 -0
  71. package/ios/StripeSdkEmitter.swift +1 -0
  72. package/ios/StripeSdkImpl+Checkout.swift +360 -0
  73. package/ios/StripeSdkImpl+CustomerSheet.swift +1 -1
  74. package/ios/StripeSdkImpl+Embedded.swift +108 -27
  75. package/ios/StripeSdkImpl+PaymentSheet.swift +18 -2
  76. package/ios/StripeSdkImpl.swift +89 -7
  77. package/jest/mock.js +13 -1
  78. package/lib/commonjs/components/AddToWalletButton.js +1 -1
  79. package/lib/commonjs/components/AddToWalletButton.js.map +1 -1
  80. package/lib/commonjs/components/AddressSheet.js +1 -1
  81. package/lib/commonjs/components/AddressSheet.js.map +1 -1
  82. package/lib/commonjs/components/AuBECSDebitForm.js +1 -1
  83. package/lib/commonjs/components/AuBECSDebitForm.js.map +1 -1
  84. package/lib/commonjs/components/CardField.js +1 -1
  85. package/lib/commonjs/components/CardField.js.map +1 -1
  86. package/lib/commonjs/components/CardForm.js +1 -1
  87. package/lib/commonjs/components/CardForm.js.map +1 -1
  88. package/lib/commonjs/components/CurrencySelectorElement.js +2 -0
  89. package/lib/commonjs/components/CurrencySelectorElement.js.map +1 -0
  90. package/lib/commonjs/components/PaymentMethodMessagingElement.js +1 -1
  91. package/lib/commonjs/components/PaymentMethodMessagingElement.js.map +1 -1
  92. package/lib/commonjs/components/PlatformPayButton.js +1 -1
  93. package/lib/commonjs/components/PlatformPayButton.js.map +1 -1
  94. package/lib/commonjs/components/StripeContainer.js +1 -1
  95. package/lib/commonjs/components/StripeContainer.js.map +1 -1
  96. package/lib/commonjs/connect/Components.js +1 -1
  97. package/lib/commonjs/connect/Components.js.map +1 -1
  98. package/lib/commonjs/connect/ConnectComponentsProvider.js +1 -1
  99. package/lib/commonjs/connect/ConnectComponentsProvider.js.map +1 -1
  100. package/lib/commonjs/connect/EmbeddedComponent.js +1 -1
  101. package/lib/commonjs/connect/EmbeddedComponent.js.map +1 -1
  102. package/lib/commonjs/connect/ModalCloseButton.js +1 -1
  103. package/lib/commonjs/connect/ModalCloseButton.js.map +1 -1
  104. package/lib/commonjs/connect/NavigationBar.js +1 -1
  105. package/lib/commonjs/connect/NavigationBar.js.map +1 -1
  106. package/lib/commonjs/events.js.map +1 -1
  107. package/lib/commonjs/functions.js +1 -1
  108. package/lib/commonjs/functions.js.map +1 -1
  109. package/lib/commonjs/helpers.js +1 -1
  110. package/lib/commonjs/hooks/useCheckout.js +1 -1
  111. package/lib/commonjs/hooks/useCheckout.js.map +1 -1
  112. package/lib/commonjs/hooks/useOnramp.js +1 -1
  113. package/lib/commonjs/hooks/useOnramp.js.map +1 -1
  114. package/lib/commonjs/specs/NativeAddToWalletButton.js +1 -1
  115. package/lib/commonjs/specs/NativeAddressSheet.js +1 -1
  116. package/lib/commonjs/specs/NativeApplePayButton.js +1 -1
  117. package/lib/commonjs/specs/NativeAuBECSDebitForm.js +1 -1
  118. package/lib/commonjs/specs/NativeCardField.js +1 -1
  119. package/lib/commonjs/specs/NativeCardField.js.map +1 -1
  120. package/lib/commonjs/specs/NativeCardForm.js +1 -1
  121. package/lib/commonjs/specs/NativeCardForm.js.map +1 -1
  122. package/lib/commonjs/specs/NativeConnectAccountOnboardingView.js +1 -1
  123. package/lib/commonjs/specs/NativeCurrencySelectorElement.js +2 -0
  124. package/lib/commonjs/specs/NativeCurrencySelectorElement.js.map +1 -0
  125. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js +1 -1
  126. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  127. package/lib/commonjs/specs/NativeGooglePayButton.js +1 -1
  128. package/lib/commonjs/specs/NativeNavigationBar.js +1 -1
  129. package/lib/commonjs/specs/NativeOnrampSdkModule.js.map +1 -1
  130. package/lib/commonjs/specs/NativePaymentMethodMessagingElement.js +1 -1
  131. package/lib/commonjs/specs/NativeStripeContainer.js +1 -1
  132. package/lib/commonjs/specs/NativeStripeSdkModule.js.map +1 -1
  133. package/lib/commonjs/types/EmbeddedPaymentElement.js +1 -1
  134. package/lib/commonjs/types/EmbeddedPaymentElement.js.map +1 -1
  135. package/lib/module/components/AddToWalletButton.js +1 -1
  136. package/lib/module/components/AddToWalletButton.js.map +1 -1
  137. package/lib/module/components/AddressSheet.js +1 -1
  138. package/lib/module/components/AddressSheet.js.map +1 -1
  139. package/lib/module/components/AuBECSDebitForm.js +1 -1
  140. package/lib/module/components/AuBECSDebitForm.js.map +1 -1
  141. package/lib/module/components/CardField.js +1 -1
  142. package/lib/module/components/CardField.js.map +1 -1
  143. package/lib/module/components/CardForm.js +1 -1
  144. package/lib/module/components/CardForm.js.map +1 -1
  145. package/lib/module/components/CurrencySelectorElement.js +2 -0
  146. package/lib/module/components/CurrencySelectorElement.js.map +1 -0
  147. package/lib/module/components/PaymentMethodMessagingElement.js +1 -1
  148. package/lib/module/components/PaymentMethodMessagingElement.js.map +1 -1
  149. package/lib/module/components/PlatformPayButton.js +1 -1
  150. package/lib/module/components/PlatformPayButton.js.map +1 -1
  151. package/lib/module/components/StripeContainer.js +1 -1
  152. package/lib/module/components/StripeContainer.js.map +1 -1
  153. package/lib/module/connect/Components.js +1 -1
  154. package/lib/module/connect/Components.js.map +1 -1
  155. package/lib/module/connect/ConnectComponentsProvider.js +1 -1
  156. package/lib/module/connect/ConnectComponentsProvider.js.map +1 -1
  157. package/lib/module/connect/EmbeddedComponent.js +1 -1
  158. package/lib/module/connect/EmbeddedComponent.js.map +1 -1
  159. package/lib/module/connect/ModalCloseButton.js +1 -1
  160. package/lib/module/connect/ModalCloseButton.js.map +1 -1
  161. package/lib/module/connect/NavigationBar.js +1 -1
  162. package/lib/module/connect/NavigationBar.js.map +1 -1
  163. package/lib/module/events.js.map +1 -1
  164. package/lib/module/functions.js +1 -1
  165. package/lib/module/functions.js.map +1 -1
  166. package/lib/module/helpers.js +1 -1
  167. package/lib/module/hooks/useCheckout.js +1 -1
  168. package/lib/module/hooks/useCheckout.js.map +1 -1
  169. package/lib/module/hooks/useOnramp.js +1 -1
  170. package/lib/module/hooks/useOnramp.js.map +1 -1
  171. package/lib/module/specs/NativeAddToWalletButton.js +1 -1
  172. package/lib/module/specs/NativeAddressSheet.js +1 -1
  173. package/lib/module/specs/NativeApplePayButton.js +1 -1
  174. package/lib/module/specs/NativeAuBECSDebitForm.js +1 -1
  175. package/lib/module/specs/NativeCardField.js +1 -1
  176. package/lib/module/specs/NativeCardField.js.map +1 -1
  177. package/lib/module/specs/NativeCardForm.js +1 -1
  178. package/lib/module/specs/NativeCardForm.js.map +1 -1
  179. package/lib/module/specs/NativeConnectAccountOnboardingView.js +1 -1
  180. package/lib/module/specs/NativeCurrencySelectorElement.js +2 -0
  181. package/lib/module/specs/NativeCurrencySelectorElement.js.map +1 -0
  182. package/lib/module/specs/NativeEmbeddedPaymentElement.js +1 -1
  183. package/lib/module/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  184. package/lib/module/specs/NativeGooglePayButton.js +1 -1
  185. package/lib/module/specs/NativeNavigationBar.js +1 -1
  186. package/lib/module/specs/NativeOnrampSdkModule.js.map +1 -1
  187. package/lib/module/specs/NativePaymentMethodMessagingElement.js +1 -1
  188. package/lib/module/specs/NativeStripeContainer.js +1 -1
  189. package/lib/module/specs/NativeStripeSdkModule.js.map +1 -1
  190. package/lib/module/types/EmbeddedPaymentElement.js +1 -1
  191. package/lib/module/types/EmbeddedPaymentElement.js.map +1 -1
  192. package/lib/typescript/src/components/CurrencySelectorElement.d.ts +62 -0
  193. package/lib/typescript/src/components/CurrencySelectorElement.d.ts.map +1 -0
  194. package/lib/typescript/src/components/PaymentMethodMessagingElement.d.ts +1 -1
  195. package/lib/typescript/src/components/PaymentMethodMessagingElement.d.ts.map +1 -1
  196. package/lib/typescript/src/events.d.ts +11 -0
  197. package/lib/typescript/src/events.d.ts.map +1 -1
  198. package/lib/typescript/src/functions.d.ts.map +1 -1
  199. package/lib/typescript/src/hooks/useCheckout.d.ts.map +1 -1
  200. package/lib/typescript/src/hooks/useOnramp.d.ts +22 -0
  201. package/lib/typescript/src/hooks/useOnramp.d.ts.map +1 -1
  202. package/lib/typescript/src/specs/NativeCurrencySelectorElement.d.ts +25 -0
  203. package/lib/typescript/src/specs/NativeCurrencySelectorElement.d.ts.map +1 -0
  204. package/lib/typescript/src/specs/NativeEmbeddedPaymentElement.d.ts +5 -1
  205. package/lib/typescript/src/specs/NativeEmbeddedPaymentElement.d.ts.map +1 -1
  206. package/lib/typescript/src/specs/NativeOnrampSdkModule.d.ts +3 -0
  207. package/lib/typescript/src/specs/NativeOnrampSdkModule.d.ts.map +1 -1
  208. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts +5 -2
  209. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts.map +1 -1
  210. package/lib/typescript/src/types/Checkout.d.ts +268 -86
  211. package/lib/typescript/src/types/Checkout.d.ts.map +1 -1
  212. package/lib/typescript/src/types/EmbeddedPaymentElement.d.ts +36 -1
  213. package/lib/typescript/src/types/EmbeddedPaymentElement.d.ts.map +1 -1
  214. package/lib/typescript/src/types/Onramp.d.ts +94 -0
  215. package/lib/typescript/src/types/Onramp.d.ts.map +1 -1
  216. package/package.json +16 -4
  217. package/src/components/CurrencySelectorElement.tsx +95 -0
  218. package/src/components/PaymentMethodMessagingElement.tsx +54 -52
  219. package/src/events.ts +11 -0
  220. package/src/functions.ts +30 -1
  221. package/src/hooks/useCheckout.tsx +129 -74
  222. package/src/hooks/useOnramp.tsx +44 -0
  223. package/src/specs/NativeCurrencySelectorElement.ts +35 -0
  224. package/src/specs/NativeEmbeddedPaymentElement.ts +12 -2
  225. package/src/specs/NativeOnrampSdkModule.ts +5 -0
  226. package/src/specs/NativeStripeSdkModule.ts +16 -2
  227. package/src/types/Checkout.ts +291 -86
  228. package/src/types/EmbeddedPaymentElement.tsx +117 -26
  229. package/src/types/Onramp.ts +109 -0
  230. package/stripe-react-native.podspec +1 -1
  231. package/android/.idea/AndroidProjectSystem.xml +0 -6
  232. package/android/.idea/caches/deviceStreaming.xml +0 -835
  233. package/android/.idea/compiler.xml +0 -6
  234. package/android/.idea/gradle.xml +0 -17
  235. package/android/.idea/migrations.xml +0 -10
  236. package/android/.idea/misc.xml +0 -10
  237. package/android/.idea/runConfigurations.xml +0 -17
  238. package/android/.idea/vcs.xml +0 -6
  239. package/android/local.properties +0 -8
@@ -0,0 +1,360 @@
1
+ //
2
+ // StripeSdkImpl+Checkout.swift
3
+ // stripe-react-native
4
+ //
5
+ // Created by Nick Porter on 4/29/26.
6
+ //
7
+
8
+ import Combine
9
+ import Foundation
10
+ @_spi(ReactNativeSDK) import StripePaymentSheet
11
+
12
+ extension StripeSdkImpl {
13
+ internal func currentCheckoutStateResult(checkout: Checkout) -> NSDictionary {
14
+ Mappers.mapFromCheckoutState(checkout.state)
15
+ }
16
+
17
+ @objc(initCheckoutSession:configuration:resolver:rejecter:)
18
+ public func initCheckoutSession(
19
+ clientSecret: String,
20
+ configuration: NSDictionary,
21
+ resolver resolve: @escaping RCTPromiseResolveBlock,
22
+ rejecter reject: @escaping RCTPromiseRejectBlock
23
+ ) {
24
+ let checkoutConfiguration = buildCheckoutConfiguration(params: configuration)
25
+
26
+ Task { @MainActor [weak self] in
27
+ guard let self else {
28
+ reject(ErrorType.Failed, "Stripe SDK is unavailable", nil)
29
+ return
30
+ }
31
+
32
+ do {
33
+ let checkout = try await Checkout(
34
+ clientSecret: clientSecret,
35
+ configuration: checkoutConfiguration
36
+ )
37
+ let sessionKey = UUID().uuidString
38
+
39
+ let cancellable = checkout.$state
40
+ .dropFirst()
41
+ .sink { [weak self] state in
42
+ self?.emitter?.emitCheckoutSessionDidChangeState([
43
+ "sessionKey": sessionKey,
44
+ "state": Mappers.mapFromCheckoutState(state),
45
+ ])
46
+ }
47
+
48
+ self.checkoutInstances[sessionKey] = checkout
49
+ self.checkoutStateCancellables[sessionKey] = cancellable
50
+
51
+ resolve([
52
+ "sessionKey": sessionKey,
53
+ "state": self.currentCheckoutStateResult(checkout: checkout),
54
+ ])
55
+ } catch {
56
+ reject(self.checkoutErrorCode(for: error), error.localizedDescription, error)
57
+ }
58
+ }
59
+ }
60
+
61
+ @objc(checkoutUpdateShippingAddress:address:name:phone:resolver:rejecter:)
62
+ public func checkoutUpdateShippingAddress(
63
+ sessionKey: String,
64
+ address: NSDictionary,
65
+ name: String?,
66
+ phone: String?,
67
+ resolver resolve: @escaping RCTPromiseResolveBlock,
68
+ rejecter reject: @escaping RCTPromiseRejectBlock
69
+ ) {
70
+ performCheckoutAddressMutation(
71
+ sessionKey: sessionKey,
72
+ address: address,
73
+ name: name,
74
+ phone: phone,
75
+ missingCountryMessage: "A shipping address country is required.",
76
+ resolver: resolve,
77
+ rejecter: reject
78
+ ) { checkout, addressUpdate in
79
+ try await checkout.updateShippingAddress(
80
+ name: addressUpdate.name,
81
+ phone: addressUpdate.phone,
82
+ address: addressUpdate.address
83
+ )
84
+ }
85
+ }
86
+
87
+ @objc(checkoutUpdateBillingAddress:address:name:phone:resolver:rejecter:)
88
+ public func checkoutUpdateBillingAddress(
89
+ sessionKey: String,
90
+ address: NSDictionary,
91
+ name: String?,
92
+ phone: String?,
93
+ resolver resolve: @escaping RCTPromiseResolveBlock,
94
+ rejecter reject: @escaping RCTPromiseRejectBlock
95
+ ) {
96
+ performCheckoutAddressMutation(
97
+ sessionKey: sessionKey,
98
+ address: address,
99
+ name: name,
100
+ phone: phone,
101
+ missingCountryMessage: "A billing address country is required.",
102
+ resolver: resolve,
103
+ rejecter: reject
104
+ ) { checkout, addressUpdate in
105
+ try await checkout.updateBillingAddress(
106
+ name: addressUpdate.name,
107
+ phone: addressUpdate.phone,
108
+ address: addressUpdate.address
109
+ )
110
+ }
111
+ }
112
+
113
+ @objc(checkoutApplyPromotionCode:code:resolver:rejecter:)
114
+ public func checkoutApplyPromotionCode(
115
+ sessionKey: String,
116
+ code: String,
117
+ resolver resolve: @escaping RCTPromiseResolveBlock,
118
+ rejecter reject: @escaping RCTPromiseRejectBlock
119
+ ) {
120
+ performCheckoutMutation(
121
+ sessionKey: sessionKey,
122
+ resolver: resolve,
123
+ rejecter: reject
124
+ ) { checkout in
125
+ try await checkout.applyPromotionCode(code)
126
+ }
127
+ }
128
+
129
+ @objc(checkoutRemovePromotionCode:resolver:rejecter:)
130
+ public func checkoutRemovePromotionCode(
131
+ sessionKey: String,
132
+ resolver resolve: @escaping RCTPromiseResolveBlock,
133
+ rejecter reject: @escaping RCTPromiseRejectBlock
134
+ ) {
135
+ performCheckoutMutation(
136
+ sessionKey: sessionKey,
137
+ resolver: resolve,
138
+ rejecter: reject
139
+ ) { checkout in
140
+ try await checkout.removePromotionCode()
141
+ }
142
+ }
143
+
144
+ @objc(checkoutUpdateLineItemQuantity:lineItemId:quantity:resolver:rejecter:)
145
+ public func checkoutUpdateLineItemQuantity(
146
+ sessionKey: String,
147
+ lineItemId: String,
148
+ quantity: Double,
149
+ resolver resolve: @escaping RCTPromiseResolveBlock,
150
+ rejecter reject: @escaping RCTPromiseRejectBlock
151
+ ) {
152
+ guard quantity.isFinite, let integerQuantity = Int(exactly: quantity) else {
153
+ reject(ErrorType.Failed, "Line item quantity must be an integer.", nil)
154
+ return
155
+ }
156
+
157
+ performCheckoutMutation(
158
+ sessionKey: sessionKey,
159
+ resolver: resolve,
160
+ rejecter: reject
161
+ ) { checkout in
162
+ try await checkout.updateQuantity(lineItemId: lineItemId, quantity: integerQuantity)
163
+ }
164
+ }
165
+
166
+ @objc(checkoutSelectShippingOption:id:resolver:rejecter:)
167
+ public func checkoutSelectShippingOption(
168
+ sessionKey: String,
169
+ id: String,
170
+ resolver resolve: @escaping RCTPromiseResolveBlock,
171
+ rejecter reject: @escaping RCTPromiseRejectBlock
172
+ ) {
173
+ performCheckoutMutation(
174
+ sessionKey: sessionKey,
175
+ resolver: resolve,
176
+ rejecter: reject
177
+ ) { checkout in
178
+ try await checkout.selectShippingOption(id)
179
+ }
180
+ }
181
+
182
+ @objc(checkoutUpdateTaxId:type:value:resolver:rejecter:)
183
+ public func checkoutUpdateTaxId(
184
+ sessionKey: String,
185
+ type: String,
186
+ value: String,
187
+ resolver resolve: @escaping RCTPromiseResolveBlock,
188
+ rejecter reject: @escaping RCTPromiseRejectBlock
189
+ ) {
190
+ performCheckoutMutation(
191
+ sessionKey: sessionKey,
192
+ resolver: resolve,
193
+ rejecter: reject
194
+ ) { checkout in
195
+ try await checkout.updateTaxId(type: type, value: value)
196
+ }
197
+ }
198
+
199
+ @objc(checkoutRunServerUpdateStart:resolver:rejecter:)
200
+ public func checkoutRunServerUpdateStart(
201
+ sessionKey: String,
202
+ resolver resolve: @escaping RCTPromiseResolveBlock,
203
+ rejecter reject: @escaping RCTPromiseRejectBlock
204
+ ) {
205
+ Task { @MainActor [weak self] in
206
+ guard let self else {
207
+ reject(ErrorType.Failed, "Stripe SDK is unavailable", nil)
208
+ return
209
+ }
210
+
211
+ guard let checkout = self.checkoutInstances[sessionKey] else {
212
+ reject(ErrorType.Failed, "Checkout session not found", nil)
213
+ return
214
+ }
215
+
216
+ guard self.serverUpdateContinuations[sessionKey] == nil else {
217
+ reject(ErrorType.Failed, "A server update is already in progress for this session", nil)
218
+ return
219
+ }
220
+
221
+ do {
222
+ try await checkout.runServerUpdate {
223
+ try await withCheckedThrowingContinuation { continuation in
224
+ self.serverUpdateContinuations[sessionKey] = continuation
225
+ }
226
+ }
227
+ resolve(self.currentCheckoutStateResult(checkout: checkout))
228
+ } catch {
229
+ reject(self.checkoutErrorCode(for: error), error.localizedDescription, error)
230
+ }
231
+ }
232
+ }
233
+
234
+ @objc(checkoutRunServerUpdateComplete:error:resolver:rejecter:)
235
+ public func checkoutRunServerUpdateComplete(
236
+ sessionKey: String,
237
+ error: String?,
238
+ resolver resolve: @escaping RCTPromiseResolveBlock,
239
+ rejecter reject: @escaping RCTPromiseRejectBlock
240
+ ) {
241
+ guard let continuation = serverUpdateContinuations.removeValue(forKey: sessionKey) else {
242
+ reject(ErrorType.Failed, "No pending server update for this session", nil)
243
+ return
244
+ }
245
+
246
+ if let error {
247
+ continuation.resume(throwing: CheckoutError.apiError(message: error))
248
+ } else {
249
+ continuation.resume()
250
+ }
251
+ resolve(nil)
252
+ }
253
+
254
+ internal func buildCheckoutConfiguration(params: NSDictionary) -> Checkout.Configuration {
255
+ var configuration = Checkout.Configuration()
256
+
257
+ if let adaptivePricing = params["adaptivePricing"] as? NSDictionary,
258
+ let allowed = adaptivePricing["allowed"] as? Bool {
259
+ configuration.adaptivePricing.allowed = allowed
260
+ }
261
+
262
+ return configuration
263
+ }
264
+
265
+ private func performCheckoutMutation(
266
+ sessionKey: String,
267
+ resolver resolve: @escaping RCTPromiseResolveBlock,
268
+ rejecter reject: @escaping RCTPromiseRejectBlock,
269
+ operation: @escaping (Checkout) async throws -> Void
270
+ ) {
271
+ Task { @MainActor [weak self] in
272
+ guard let self else {
273
+ reject(ErrorType.Failed, "Stripe SDK is unavailable", nil)
274
+ return
275
+ }
276
+
277
+ guard let checkout = self.checkoutInstances[sessionKey] else {
278
+ reject(ErrorType.Failed, "Checkout session not found", nil)
279
+ return
280
+ }
281
+
282
+ do {
283
+ try await operation(checkout)
284
+ resolve(self.currentCheckoutStateResult(checkout: checkout))
285
+ } catch {
286
+ reject(self.checkoutErrorCode(for: error), error.localizedDescription, error)
287
+ }
288
+ }
289
+ }
290
+
291
+ private func performCheckoutAddressMutation(
292
+ sessionKey: String,
293
+ address: NSDictionary,
294
+ name: String?,
295
+ phone: String?,
296
+ missingCountryMessage: String,
297
+ resolver resolve: @escaping RCTPromiseResolveBlock,
298
+ rejecter reject: @escaping RCTPromiseRejectBlock,
299
+ operation: @escaping (Checkout, Checkout.ContactAddress) async throws -> Void
300
+ ) {
301
+ guard let addressUpdate = buildCheckoutAddressUpdate(
302
+ address: address,
303
+ name: name,
304
+ phone: phone
305
+ ) else {
306
+ reject(ErrorType.Failed, missingCountryMessage, nil)
307
+ return
308
+ }
309
+
310
+ performCheckoutMutation(
311
+ sessionKey: sessionKey,
312
+ resolver: resolve,
313
+ rejecter: reject
314
+ ) { checkout in
315
+ try await operation(checkout, addressUpdate)
316
+ }
317
+ }
318
+
319
+ private func buildCheckoutAddressUpdate(
320
+ address: NSDictionary,
321
+ name: String?,
322
+ phone: String?
323
+ ) -> Checkout.ContactAddress? {
324
+ guard let country = address["country"] as? String, !country.isEmpty else {
325
+ return nil
326
+ }
327
+
328
+ let checkoutAddress = Checkout.Address(
329
+ country: country,
330
+ line1: address["line1"] as? String,
331
+ line2: address["line2"] as? String,
332
+ city: address["city"] as? String,
333
+ state: address["state"] as? String,
334
+ postalCode: address["postalCode"] as? String
335
+ )
336
+
337
+ return Checkout.ContactAddress(
338
+ name: name,
339
+ phone: phone,
340
+ address: checkoutAddress
341
+ )
342
+ }
343
+
344
+ private func checkoutErrorCode(for error: Error) -> String {
345
+ if let checkoutError = error as? CheckoutError {
346
+ switch checkoutError {
347
+ case .invalidClientSecret:
348
+ return "InvalidClientSecret"
349
+ case .sessionNotOpen:
350
+ return "SessionNotOpen"
351
+ case .sheetCurrentlyPresented:
352
+ return "SheetCurrentlyPresented"
353
+ default:
354
+ return ErrorType.Failed
355
+ }
356
+ }
357
+
358
+ return ErrorType.Failed
359
+ }
360
+ }
@@ -6,7 +6,7 @@
6
6
  //
7
7
 
8
8
  import Foundation
9
- @_spi(PrivateBetaCustomerSheet) @_spi(CustomerSessionBetaAccess) @_spi(STP) import StripePaymentSheet
9
+ @_spi(PrivateBetaCustomerSheet) @_spi(STP) import StripePaymentSheet
10
10
  extension StripeSdkImpl {
11
11
  @objc(initCustomerSheet:customerAdapterOverrides:resolver:rejecter:)
12
12
  public func initCustomerSheet(params: NSDictionary,
@@ -6,7 +6,7 @@
6
6
  //
7
7
 
8
8
  import Foundation
9
- @_spi(EmbeddedPaymentElementPrivateBeta) @_spi(ExperimentalAllowsRemovalOfLastSavedPaymentMethodAPI) @_spi(CustomerSessionBetaAccess) @_spi(STP) @_spi(CustomPaymentMethodsBeta) @_spi(CardFundingFilteringPrivatePreview) import StripePaymentSheet
9
+ @_spi(ExperimentalAllowsRemovalOfLastSavedPaymentMethodAPI) @_spi(STP) @_spi(CustomPaymentMethodsBeta) @_spi(CardFundingFilteringPrivatePreview) import StripePaymentSheet
10
10
 
11
11
  @objc(StripeSdkImpl)
12
12
  extension StripeSdkImpl {
@@ -19,19 +19,22 @@ extension StripeSdkImpl {
19
19
  resolve: @escaping RCTPromiseResolveBlock,
20
20
  reject: @escaping RCTPromiseRejectBlock) {
21
21
  guard let modeParams = intentConfig["mode"] as? NSDictionary else {
22
- resolve(Errors.createError(ErrorType.Failed, "One of `paymentIntentClientSecret`, `setupIntentClientSecret`, or `intentConfiguration.mode` is required"))
22
+ emitLoadingFailed(message: "One of `paymentIntentClientSecret`, `setupIntentClientSecret`, or `intentConfiguration.mode` is required")
23
+ resolve(nil)
23
24
  return
24
25
  }
25
26
  let hasConfirmHandler = intentConfig.object(forKey: "confirmHandler") != nil
26
27
  let hasConfirmationTokenHandler = intentConfig.object(forKey: "confirmationTokenConfirmHandler") != nil
27
28
 
28
29
  if !hasConfirmHandler && !hasConfirmationTokenHandler {
29
- resolve(Errors.createError(ErrorType.Failed, "You must provide either `intentConfiguration.confirmHandler` or `intentConfiguration.confirmationTokenConfirmHandler` if you are not passing an intent client secret"))
30
+ emitLoadingFailed(message: "You must provide either `intentConfiguration.confirmHandler` or `intentConfiguration.confirmationTokenConfirmHandler` if you are not passing an intent client secret")
31
+ resolve(nil)
30
32
  return
31
33
  }
32
34
 
33
35
  if hasConfirmHandler && hasConfirmationTokenHandler {
34
- resolve(Errors.createError(ErrorType.Failed, "You must provide either `confirmHandler` or `confirmationTokenConfirmHandler`, but not both"))
36
+ emitLoadingFailed(message: "You must provide either `confirmHandler` or `confirmationTokenConfirmHandler`, but not both")
37
+ resolve(nil)
35
38
  return
36
39
  }
37
40
  let captureMethodString = intentConfig["captureMethod"] as? String
@@ -44,7 +47,8 @@ extension StripeSdkImpl {
44
47
  )
45
48
 
46
49
  guard let configuration = buildEmbeddedPaymentElementConfiguration(params: configuration).configuration else {
47
- resolve(Errors.createError(ErrorType.Failed, "Invalid configuration"))
50
+ emitLoadingFailed(message: "Invalid configuration")
51
+ resolve(nil)
48
52
  return
49
53
  }
50
54
 
@@ -54,26 +58,88 @@ extension StripeSdkImpl {
54
58
  intentConfiguration: intentConfig,
55
59
  configuration: configuration
56
60
  )
57
- embeddedPaymentElement.delegate = embeddedInstanceDelegate
58
- embeddedPaymentElement.presentingViewController = RCTPresentedViewController()
59
- self.embeddedInstance = embeddedPaymentElement
60
-
61
- // success: resolve promise
61
+ attachEmbedded(embeddedPaymentElement)
62
62
  resolve(nil)
63
-
64
- // publish initial state
65
- embeddedInstanceDelegate.embeddedPaymentElementDidUpdateHeight(embeddedPaymentElement: embeddedPaymentElement)
66
- embeddedInstanceDelegate.embeddedPaymentElementDidUpdatePaymentOption(embeddedPaymentElement: embeddedPaymentElement)
67
63
  } catch {
68
- // 1) still resolve the promise so JS hook can finish loading
64
+ emitLoadingFailed(error: error)
65
+ // Resolve so the JS hook can finish loading; loading errors are
66
+ // surfaced through the embeddedPaymentElementLoadingFailed event.
69
67
  resolve(nil)
68
+ }
69
+ }
70
+ }
71
+
72
+ @objc(createEmbeddedPaymentElementWithCheckout:configuration:resolve:reject:)
73
+ public func createEmbeddedPaymentElementWithCheckout(
74
+ sessionKey: String,
75
+ configuration: NSDictionary,
76
+ resolve: @escaping RCTPromiseResolveBlock,
77
+ reject: @escaping RCTPromiseRejectBlock
78
+ ) {
79
+ guard let checkout = checkoutInstances[sessionKey] else {
80
+ emitLoadingFailed(message: "Checkout session not found")
81
+ resolve(nil)
82
+ return
83
+ }
84
+
85
+ guard let configuration = buildEmbeddedPaymentElementConfiguration(params: configuration).configuration else {
86
+ emitLoadingFailed(message: "Invalid configuration")
87
+ resolve(nil)
88
+ return
89
+ }
70
90
 
71
- // 2) emit a loading‐failed event with the error message
72
- let msg = error.localizedDescription
73
- self.emitter?.emitEmbeddedPaymentElementLoadingFailed(["message": msg])
91
+ Task {
92
+ do {
93
+ let embeddedPaymentElement = try await EmbeddedPaymentElement.create(
94
+ checkout: checkout,
95
+ configuration: configuration
96
+ )
97
+ attachEmbedded(embeddedPaymentElement)
98
+ resolve(nil)
99
+ } catch {
100
+ emitLoadingFailed(error: error)
101
+ resolve(nil)
74
102
  }
75
103
  }
104
+ }
105
+
106
+ /// Wires up a freshly created element and emits its initial height /
107
+ /// payment-option state to JS.
108
+ @nonobjc
109
+ private func attachEmbedded(_ element: EmbeddedPaymentElement) {
110
+ element.delegate = embeddedInstanceDelegate
111
+ element.presentingViewController = RCTPresentedViewController()
112
+ self.embeddedInstance = element
76
113
 
114
+ embeddedInstanceDelegate.embeddedPaymentElementDidUpdateHeight(embeddedPaymentElement: element)
115
+ embeddedInstanceDelegate.embeddedPaymentElementDidUpdatePaymentOption(embeddedPaymentElement: element)
116
+ }
117
+
118
+ @nonobjc
119
+ private func emitLoadingFailed(message: String) {
120
+ self.emitter?.emitEmbeddedPaymentElementLoadingFailed(["message": message])
121
+ }
122
+
123
+ @nonobjc
124
+ private func emitLoadingFailed(error: Error) {
125
+ emitLoadingFailed(message: error.localizedDescription)
126
+ }
127
+
128
+ @nonobjc
129
+ private func resolveEmbeddedUpdateResult(
130
+ _ updateResult: EmbeddedPaymentElement.UpdateResult,
131
+ resolve: @escaping RCTPromiseResolveBlock
132
+ ) {
133
+ switch updateResult {
134
+ case .succeeded:
135
+ resolve(["status": "succeeded"])
136
+ case .canceled:
137
+ resolve(["status": "canceled"])
138
+ case .failed(let error):
139
+ self.emitter?.emitEmbeddedPaymentElementLoadingFailed(["message": error.localizedDescription])
140
+ // We don't resolve with an error b/c loading errors are handled via the embeddedPaymentElementLoadingFailed event
141
+ resolve(nil)
142
+ }
77
143
  }
78
144
 
79
145
  @objc(confirmEmbeddedPaymentElement:reject:)
@@ -143,16 +209,31 @@ extension StripeSdkImpl {
143
209
  return
144
210
  }
145
211
 
146
- switch updateResult {
147
- case .succeeded:
148
- resolve(["status": "succeeded"])
149
- case .canceled:
150
- resolve(["status": "canceled"])
151
- case .failed(let error):
152
- self.emitter?.emitEmbeddedPaymentElementLoadingFailed(["message": error.localizedDescription])
153
- // We don't resolve with an error b/c loading errors are handled via the embeddedPaymentElementLoadingFailed event
154
- resolve(nil)
212
+ self.resolveEmbeddedUpdateResult(updateResult, resolve: resolve)
213
+ }
214
+ }
215
+
216
+ @objc(updateEmbeddedPaymentElementWithCheckout:resolve:reject:)
217
+ public func updateEmbeddedPaymentElementWithCheckout(
218
+ sessionKey: String,
219
+ resolve: @escaping RCTPromiseResolveBlock,
220
+ reject: @escaping RCTPromiseRejectBlock
221
+ ) {
222
+ guard let checkout = checkoutInstances[sessionKey] else {
223
+ resolve(Errors.createError(ErrorType.Failed, "Checkout session not found"))
224
+ return
225
+ }
226
+
227
+ Task {
228
+ guard let updateResult = await self.embeddedInstance?.update(checkout: checkout) else {
229
+ resolve(Errors.createError(
230
+ ErrorType.Failed,
231
+ "No EmbeddedPaymentElement instance — did you call create first?"
232
+ ))
233
+ return
155
234
  }
235
+
236
+ self.resolveEmbeddedUpdateResult(updateResult, resolve: resolve)
156
237
  }
157
238
  }
158
239
 
@@ -6,7 +6,7 @@
6
6
  //
7
7
 
8
8
  import Foundation
9
- @_spi(ExperimentalAllowsRemovalOfLastSavedPaymentMethodAPI) @_spi(CustomerSessionBetaAccess) @_spi(EmbeddedPaymentElementPrivateBeta) @_spi(STP) @_spi(PaymentMethodOptionsSetupFutureUsagePreview) @_spi(CustomPaymentMethodsBeta) @_spi(ConfirmationTokensPublicPreview) @_spi(CardFundingFilteringPrivatePreview) import StripePaymentSheet
9
+ @_spi(ExperimentalAllowsRemovalOfLastSavedPaymentMethodAPI) @_spi(STP) @_spi(PaymentMethodOptionsSetupFutureUsagePreview) @_spi(CustomPaymentMethodsBeta) @_spi(ConfirmationTokensPublicPreview) @_spi(CardFundingFilteringPrivatePreview) import StripePaymentSheet
10
10
 
11
11
  extension StripeSdkImpl {
12
12
  internal func buildPaymentSheetConfiguration(
@@ -183,7 +183,23 @@ extension StripeSdkImpl {
183
183
  }
184
184
  }
185
185
 
186
- if let paymentIntentClientSecret = params["paymentIntentClientSecret"] as? String {
186
+ if let checkout = params["checkout"] as? NSDictionary,
187
+ let sessionKey = checkout["sessionKey"] as? String {
188
+ guard let checkout = checkoutInstances[sessionKey] else {
189
+ resolve(Errors.createError(ErrorType.Failed, "Checkout session not found"))
190
+ return
191
+ }
192
+
193
+ if params["customFlow"] as? Bool == true {
194
+ PaymentSheet.FlowController.create(checkout: checkout,
195
+ configuration: configuration) { [weak self] result in
196
+ handlePaymentSheetFlowControllerResult(result: result, stripeSdk: self)
197
+ }
198
+ } else {
199
+ self.paymentSheet = PaymentSheet(checkout: checkout, configuration: configuration)
200
+ resolve([])
201
+ }
202
+ } else if let paymentIntentClientSecret = params["paymentIntentClientSecret"] as? String {
187
203
  if !Errors.isPIClientSecretValid(clientSecret: paymentIntentClientSecret) {
188
204
  resolve(Errors.createError(ErrorType.Failed, "`secret` format does not match expected client secret formatting."))
189
205
  return