react-native-hyperswitch-dev-sdk 0.4.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 (262) hide show
  1. package/HyperswitchSdkReactNative.podspec +42 -0
  2. package/LICENSE +201 -0
  3. package/android/build.gradle +161 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/hyperswitch_autolinking.gradle +378 -0
  6. package/android/proguard-rules.pro +72 -0
  7. package/android/src/legacy/java/com/facebook/react/viewmanagers/GooglePayButtonManagerDelegate.java +41 -0
  8. package/android/src/legacy/java/com/facebook/react/viewmanagers/GooglePayButtonManagerInterface.java +20 -0
  9. package/android/src/legacy/java/com/facebook/react/viewmanagers/NativePaymentWidgetManagerDelegate.java +38 -0
  10. package/android/src/legacy/java/com/facebook/react/viewmanagers/NativePaymentWidgetManagerInterface.java +21 -0
  11. package/android/src/legacy/java/com/hyperswitchsdkreactnative/NativeHyperswitchSdkNativeSpec.java +106 -0
  12. package/android/src/legacy/java/com/hyperswitchsdkreactnative/NativeHyperswitchSdkReactNativeSpec.java +77 -0
  13. package/android/src/legacy/java/com/hyperswitchsdkreactnative/NativePaymentWidgetNativeSpec.java +36 -0
  14. package/android/src/main/AndroidManifest.xml +15 -0
  15. package/android/src/main/assets/hyperswitch.bundle +1535 -0
  16. package/android/src/main/java/com/hyperswitchsdkreactnative/HyperswitchSdkReactNativePackage.kt +47 -0
  17. package/android/src/main/java/com/hyperswitchsdkreactnative/modules/NativePaymentWidgetModule.kt +173 -0
  18. package/android/src/main/java/com/hyperswitchsdkreactnative/modules/ReactNativeHyperswitchModule.kt +396 -0
  19. package/android/src/main/java/com/hyperswitchsdkreactnative/views/PaymentElementViewManager.kt +99 -0
  20. package/android/src/main/java/io/hyperswitch/HyperswitchReactPackageProvider.kt +19 -0
  21. package/android/src/main/java/io/hyperswitch/PaymentEventType.kt +18 -0
  22. package/android/src/main/java/io/hyperswitch/model/ElementConfiguration.kt +58 -0
  23. package/android/src/main/java/io/hyperswitch/paymentsession/ExitHeadlessCallBackManager.kt +47 -0
  24. package/android/src/main/java/io/hyperswitch/paymentsession/GetPaymentSessionCallBackManager.kt +23 -0
  25. package/android/src/main/java/io/hyperswitch/paymentsession/PaymentMethod.kt +167 -0
  26. package/android/src/main/java/io/hyperswitch/paymentsession/PaymentSessionHandler.kt +68 -0
  27. package/android/src/main/java/io/hyperswitch/paymentsession/PaymentSessionHandlerImpl.kt +179 -0
  28. package/android/src/main/java/io/hyperswitch/paymentsession/PaymentSessionReactLauncher.kt +226 -0
  29. package/android/src/main/java/io/hyperswitch/paymentsession/PaymentSheetCallbackManager.kt +40 -0
  30. package/android/src/main/java/io/hyperswitch/paymentsheet/PaymentResult.kt +63 -0
  31. package/android/src/main/java/io/hyperswitch/react/GooglePayButtonManager.kt +54 -0
  32. package/android/src/main/java/io/hyperswitch/react/HyperActivity.kt +73 -0
  33. package/android/src/main/java/io/hyperswitch/react/HyperEventEmitter.kt +144 -0
  34. package/android/src/main/java/io/hyperswitch/react/HyperFragment.kt +429 -0
  35. package/android/src/main/java/io/hyperswitch/react/HyperFragmentManager.kt +155 -0
  36. package/android/src/main/java/io/hyperswitch/react/HyperHeadlessModule.kt +43 -0
  37. package/android/src/main/java/io/hyperswitch/react/HyperModule.kt +405 -0
  38. package/android/src/main/java/io/hyperswitch/react/HyperPackage.kt +16 -0
  39. package/android/src/main/java/io/hyperswitch/react/ReactNativeController.kt +251 -0
  40. package/android/src/main/java/io/hyperswitch/utils/ConversionUtils.kt +256 -0
  41. package/android/src/main/java/io/hyperswitch/utils/StandardResult.kt +45 -0
  42. package/android/src/main/java/io/hyperswitch/view/GooglePayButtonView.kt +59 -0
  43. package/android/src/main/java/io/hyperswitch/view/PaymentWidgetView.kt +405 -0
  44. package/android/src/main/res/values/attrs.xml +6 -0
  45. package/android/src/main/res/values/strings.xml +5 -0
  46. package/android/src/main/res/values/theme.xml +16 -0
  47. package/ios/Modules/ReactNative/HyperswitchModule.swift +470 -0
  48. package/ios/Modules/ReactNative/HyperswitchSdkReactNative.h +5 -0
  49. package/ios/Modules/ReactNative/HyperswitchSdkReactNative.mm +121 -0
  50. package/ios/Modules/ReactNative/NativeHyperswitchModule.h +18 -0
  51. package/ios/Modules/ReactNative/NativeHyperswitchModule.mm +165 -0
  52. package/ios/Modules/ReactNative/NativeHyperswitchModuleImpl.swift +290 -0
  53. package/ios/Modules/ReactNative/NativePaymentElementModule.mm +129 -0
  54. package/ios/Views/Fabric/ApplePayView.h +14 -0
  55. package/ios/Views/Fabric/ApplePayView.mm +89 -0
  56. package/ios/Views/Fabric/NativePaymentElementView.h +21 -0
  57. package/ios/Views/Fabric/NativePaymentElementView.mm +200 -0
  58. package/ios/Views/Fabric/NativePaymentWidgetViewRegistry.h +37 -0
  59. package/ios/Views/Fabric/NativePaymentWidgetViewRegistry.m +45 -0
  60. package/ios/Views/Native/NativePaymentWidget.m +26 -0
  61. package/ios/Views/Native/NativePaymentWidget.swift +420 -0
  62. package/ios/hyperswitchSDK/Core/ApplePay/ApplePayHandler.swift +261 -0
  63. package/ios/hyperswitchSDK/Core/ApplePay/ApplePayViewManager.m +18 -0
  64. package/ios/hyperswitchSDK/Core/ApplePay/ApplePayViewManager.swift +126 -0
  65. package/ios/hyperswitchSDK/Core/DeviceDataCollection/HeadlessWebView.swift +144 -0
  66. package/ios/hyperswitchSDK/Core/HyperCVCWidget/CVCWidget.swift +136 -0
  67. package/ios/hyperswitchSDK/Core/HyperExpressCheckout/ExpressCheckoutLauncher.swift +116 -0
  68. package/ios/hyperswitchSDK/Core/HyperExpressCheckout/ExpressCheckoutWidget.swift +42 -0
  69. package/ios/hyperswitchSDK/Core/HyperPaymentCardTextField/PaymentCardTextField+SwiftUI.swift +67 -0
  70. package/ios/hyperswitchSDK/Core/HyperPaymentCardTextField/PaymentCardTextField.swift +44 -0
  71. package/ios/hyperswitchSDK/Core/HyperPaymentCardTextField/PaymentHandler.swift +59 -0
  72. package/ios/hyperswitchSDK/Core/HyperPaymentCardTextField/PaymentIntentParams.swift +31 -0
  73. package/ios/hyperswitchSDK/Core/HyperPaymentCardTextField/PaymentMethodParams.swift +25 -0
  74. package/ios/hyperswitchSDK/Core/HyperPaymentMethodManagement/PaymentManagementConfiguration.swift +213 -0
  75. package/ios/hyperswitchSDK/Core/HyperPaymentMethodManagement/PaymentMethodManagementWidget.swift +92 -0
  76. package/ios/hyperswitchSDK/Core/HyperPaymentSheet/PaymentSheet+Events.swift +36 -0
  77. package/ios/hyperswitchSDK/Core/HyperPaymentSheet/PaymentSheetView+SwiftUI.swift +49 -0
  78. package/ios/hyperswitchSDK/Core/HyperPaymentSheet/PaymentSheetView+UIKit.swift +49 -0
  79. package/ios/hyperswitchSDK/Core/HyperPaymentSheet/PaymentSheetView.swift +68 -0
  80. package/ios/hyperswitchSDK/Core/HyperPaymentWidget/PaymentWidget.swift +212 -0
  81. package/ios/hyperswitchSDK/Core/HyperSession/PaymentSession+UIKit.swift +228 -0
  82. package/ios/hyperswitchSDK/Core/HyperSession/PaymentSessionTypes.swift +174 -0
  83. package/ios/hyperswitchSDK/Core/NativeModule/HyperHeadless.m +15 -0
  84. package/ios/hyperswitchSDK/Core/NativeModule/HyperHeadless.swift +108 -0
  85. package/ios/hyperswitchSDK/Core/NativeModule/HyperModule.m +31 -0
  86. package/ios/hyperswitchSDK/Core/NativeModule/HyperModule.swift +343 -0
  87. package/ios/hyperswitchSDK/Core/NativeModule/OTAServices.swift +117 -0
  88. package/ios/hyperswitchSDK/Core/NativeModule/RNHeadlessManager.swift +47 -0
  89. package/ios/hyperswitchSDK/Core/NativeModule/RNResponseHandler.swift +12 -0
  90. package/ios/hyperswitchSDK/Core/NativeModule/RNViewManager.swift +55 -0
  91. package/ios/hyperswitchSDK/Core/NativeModule/WidgetAction.swift +30 -0
  92. package/ios/hyperswitchSDK/Core/NativeModule/WidgetResponseRegistry.swift +92 -0
  93. package/ios/hyperswitchSDK/Core/NativeModule/hyper-Bridging-Header.h +12 -0
  94. package/ios/hyperswitchSDK/Core/Resources/HyperOTA.plist +20 -0
  95. package/ios/hyperswitchSDK/Core/Resources/hyperswitch.bundle +1531 -0
  96. package/ios/hyperswitchSDK/CoreLite/ApplePayHandlerLite.swift +251 -0
  97. package/ios/hyperswitchSDK/CoreLite/PaymentSession+Lite.swift +25 -0
  98. package/ios/hyperswitchSDK/CoreLite/PaymentSheetView+Lite.swift +45 -0
  99. package/ios/hyperswitchSDK/CoreLite/SwiftUI+Lite.swift +48 -0
  100. package/ios/hyperswitchSDK/CoreLite/WebViewController.swift +278 -0
  101. package/ios/hyperswitchSDK/Shared/APIClient.swift +22 -0
  102. package/ios/hyperswitchSDK/Shared/Codable+UIKit.swift +75 -0
  103. package/ios/hyperswitchSDK/Shared/CustomEndpointConfiguration.swift +67 -0
  104. package/ios/hyperswitchSDK/Shared/DictionaryConverter.swift +104 -0
  105. package/ios/hyperswitchSDK/Shared/Environment.swift +24 -0
  106. package/ios/hyperswitchSDK/Shared/Extensions.swift +101 -0
  107. package/ios/hyperswitchSDK/Shared/Helper.swift +40 -0
  108. package/ios/hyperswitchSDK/Shared/HyperEvents/PaymentEventData.swift +125 -0
  109. package/ios/hyperswitchSDK/Shared/HyperEvents/PaymentEventSubscriptionBuilder.swift +45 -0
  110. package/ios/hyperswitchSDK/Shared/HyperEvents/PaymentEventType.swift +30 -0
  111. package/ios/hyperswitchSDK/Shared/HyperNetworking.swift +151 -0
  112. package/ios/hyperswitchSDK/Shared/HyperParams.swift +44 -0
  113. package/ios/hyperswitchSDK/Shared/HyperUIViewController.swift +27 -0
  114. package/ios/hyperswitchSDK/Shared/Hyperswitch.swift +20 -0
  115. package/ios/hyperswitchSDK/Shared/HyperswitchConfigurationSchema.swift +54 -0
  116. package/ios/hyperswitchSDK/Shared/HyperswitchEnvironment.swift +11 -0
  117. package/ios/hyperswitchSDK/Shared/NativeLogger/Debouncer.swift +37 -0
  118. package/ios/hyperswitchSDK/Shared/NativeLogger/LogBuilder.swift +113 -0
  119. package/ios/hyperswitchSDK/Shared/NativeLogger/LogFileManager.swift +76 -0
  120. package/ios/hyperswitchSDK/Shared/NativeLogger/LogManager.swift +113 -0
  121. package/ios/hyperswitchSDK/Shared/NativeLogger/LogPayload.swift +91 -0
  122. package/ios/hyperswitchSDK/Shared/PaymentMethodType.swift +15 -0
  123. package/ios/hyperswitchSDK/Shared/PaymentSession.swift +98 -0
  124. package/ios/hyperswitchSDK/Shared/PaymentSessionConfiguration.swift +14 -0
  125. package/ios/hyperswitchSDK/Shared/PaymentSheet.swift +33 -0
  126. package/ios/hyperswitchSDK/Shared/PaymentSheetAppearance+Codable.swift +182 -0
  127. package/ios/hyperswitchSDK/Shared/PaymentSheetAppearance.swift +238 -0
  128. package/ios/hyperswitchSDK/Shared/PaymentSheetConfiguration.swift +161 -0
  129. package/ios/hyperswitchSDK/Shared/SDKParams.swift +43 -0
  130. package/ios/hyperswitchSDK/Shared/SavedPaymentMethodsConfiguration.swift +20 -0
  131. package/ios/hyperswitchSDK/Shared/SwiftUIManager.swift +28 -0
  132. package/ios/hyperswitchSDK/Shared/Version.swift +12 -0
  133. package/lib/bs/JuspayTechReactNativeHyperswitch.cmi +0 -0
  134. package/lib/bs/JuspayTechReactNativeHyperswitch.cmj +0 -0
  135. package/lib/bs/JuspayTechReactNativeHyperswitch.cmt +0 -0
  136. package/lib/bs/JuspayTechReactNativeHyperswitch.mlmap +0 -0
  137. package/lib/bs/build.ninja +8 -0
  138. package/lib/bs/install.ninja +9 -0
  139. package/lib/bs/src/context/HyperProvider-JuspayTechReactNativeHyperswitch.cmt +0 -0
  140. package/lib/bs/src/context/WidgetRegistry-JuspayTechReactNativeHyperswitch.cmt +0 -0
  141. package/lib/bs/src/core/Hyper-JuspayTechReactNativeHyperswitch.cmt +0 -0
  142. package/lib/bs/src/core/HyperElements-JuspayTechReactNativeHyperswitch.cmt +0 -0
  143. package/lib/bs/src/hooks/usePaymentSession-JuspayTechReactNativeHyperswitch.cmt +0 -0
  144. package/lib/bs/src/hooks/useWidget-JuspayTechReactNativeHyperswitch.cmt +0 -0
  145. package/lib/bs/src/modules/NativeHyperswitchSdk-JuspayTechReactNativeHyperswitch.cmt +0 -0
  146. package/lib/bs/src/types/HyperTypes-JuspayTechReactNativeHyperswitch.cmt +0 -0
  147. package/lib/bs/src/types/NativeModuleTypes-JuspayTechReactNativeHyperswitch.cmt +0 -0
  148. package/lib/bs/src/types/PaymentSheetConfiguration-JuspayTechReactNativeHyperswitch.cmt +0 -0
  149. package/lib/bs/src/utils/AppearanceTransformer-JuspayTechReactNativeHyperswitch.cmt +0 -0
  150. package/lib/bs/src/utils/EventValidator-JuspayTechReactNativeHyperswitch.cmt +0 -0
  151. package/lib/bs/src/utils/NewArchUtils-JuspayTechReactNativeHyperswitch.cmt +0 -0
  152. package/lib/bs/src/utils/PaymentSheetEventManager-JuspayTechReactNativeHyperswitch.cmt +0 -0
  153. package/lib/bs/src/utils/ReactNativeUtils-JuspayTechReactNativeHyperswitch.cmt +0 -0
  154. package/lib/bs/src/utils/ResponseHandler-JuspayTechReactNativeHyperswitch.cmt +0 -0
  155. package/lib/bs/src/views/CVCElement-JuspayTechReactNativeHyperswitch.cmt +0 -0
  156. package/lib/bs/src/views/NativePaymentWidget-JuspayTechReactNativeHyperswitch.cmt +0 -0
  157. package/lib/bs/src/views/NativePaymentWidgetImpl-JuspayTechReactNativeHyperswitch.cmt +0 -0
  158. package/lib/bs/src/views/PaymentElement-JuspayTechReactNativeHyperswitch.cmt +0 -0
  159. package/lib/commonjs/index.bundle.js +2 -0
  160. package/lib/commonjs/index.bundle.js.map +1 -0
  161. package/lib/module/index.bundle.js +2 -0
  162. package/lib/module/index.bundle.js.map +1 -0
  163. package/lib/typescript/babel.config.d.ts +10 -0
  164. package/lib/typescript/babel.config.d.ts.map +1 -0
  165. package/lib/typescript/eslint.config.d.mts +3 -0
  166. package/lib/typescript/eslint.config.d.mts.map +1 -0
  167. package/lib/typescript/rollup.config.d.ts +23 -0
  168. package/lib/typescript/rollup.config.d.ts.map +1 -0
  169. package/lib/typescript/scripts/bootstrap.d.ts +2 -0
  170. package/lib/typescript/scripts/bootstrap.d.ts.map +1 -0
  171. package/lib/typescript/src/context/Elements.d.ts +7 -0
  172. package/lib/typescript/src/context/Elements.d.ts.map +1 -0
  173. package/lib/typescript/src/context/HyperElements.d.ts +23 -0
  174. package/lib/typescript/src/context/HyperElements.d.ts.map +1 -0
  175. package/lib/typescript/src/context/PaymentSession.d.ts +15 -0
  176. package/lib/typescript/src/context/PaymentSession.d.ts.map +1 -0
  177. package/lib/typescript/src/context/SavedPaymentMethods.d.ts +5 -0
  178. package/lib/typescript/src/context/SavedPaymentMethods.d.ts.map +1 -0
  179. package/lib/typescript/src/context/WidgetRegistry.d.ts +8 -0
  180. package/lib/typescript/src/context/WidgetRegistry.d.ts.map +1 -0
  181. package/lib/typescript/src/context/hooks.d.ts +5 -0
  182. package/lib/typescript/src/context/hooks.d.ts.map +1 -0
  183. package/lib/typescript/src/index.d.ts +10 -0
  184. package/lib/typescript/src/index.d.ts.map +1 -0
  185. package/lib/typescript/src/modules/NativeHyperswitchSdk.d.ts +61 -0
  186. package/lib/typescript/src/modules/NativeHyperswitchSdk.d.ts.map +1 -0
  187. package/lib/typescript/src/specs/ApplePayViewNativeComponent.d.ts +10 -0
  188. package/lib/typescript/src/specs/ApplePayViewNativeComponent.d.ts.map +1 -0
  189. package/lib/typescript/src/specs/NativeHyperHeadless.d.ts +14 -0
  190. package/lib/typescript/src/specs/NativeHyperHeadless.d.ts.map +1 -0
  191. package/lib/typescript/src/specs/NativeHyperswitchModule.d.ts +32 -0
  192. package/lib/typescript/src/specs/NativeHyperswitchModule.d.ts.map +1 -0
  193. package/lib/typescript/src/specs/NativeHyperswitchSdkNative.d.ts +33 -0
  194. package/lib/typescript/src/specs/NativeHyperswitchSdkNative.d.ts.map +1 -0
  195. package/lib/typescript/src/specs/NativePaymentElementModule.d.ts +9 -0
  196. package/lib/typescript/src/specs/NativePaymentElementModule.d.ts.map +1 -0
  197. package/lib/typescript/src/specs/PaymentElementNativeComponent.d.ts +19 -0
  198. package/lib/typescript/src/specs/PaymentElementNativeComponent.d.ts.map +1 -0
  199. package/lib/typescript/src/specs/utils.d.ts +15 -0
  200. package/lib/typescript/src/specs/utils.d.ts.map +1 -0
  201. package/lib/typescript/src/types/NativeModuleTypes.d.ts +67 -0
  202. package/lib/typescript/src/types/NativeModuleTypes.d.ts.map +1 -0
  203. package/lib/typescript/src/types/PaymentSheetConfiguration.d.ts +255 -0
  204. package/lib/typescript/src/types/PaymentSheetConfiguration.d.ts.map +1 -0
  205. package/lib/typescript/src/types/definitions.d.ts +85 -0
  206. package/lib/typescript/src/types/definitions.d.ts.map +1 -0
  207. package/lib/typescript/src/types/elements/index.d.ts +23 -0
  208. package/lib/typescript/src/types/elements/index.d.ts.map +1 -0
  209. package/lib/typescript/src/types/paymentresult/index.d.ts +5 -0
  210. package/lib/typescript/src/types/paymentresult/index.d.ts.map +1 -0
  211. package/lib/typescript/src/types/savedPaymentMethods/index.d.ts +69 -0
  212. package/lib/typescript/src/types/savedPaymentMethods/index.d.ts.map +1 -0
  213. package/lib/typescript/src/utils/EventValidator.d.ts +9 -0
  214. package/lib/typescript/src/utils/EventValidator.d.ts.map +1 -0
  215. package/lib/typescript/src/utils/InitializationState.d.ts +13 -0
  216. package/lib/typescript/src/utils/InitializationState.d.ts.map +1 -0
  217. package/lib/typescript/src/utils/LaunchOptions.d.ts +7 -0
  218. package/lib/typescript/src/utils/LaunchOptions.d.ts.map +1 -0
  219. package/lib/typescript/src/utils/NewArchUtils.d.ts +7 -0
  220. package/lib/typescript/src/utils/NewArchUtils.d.ts.map +1 -0
  221. package/lib/typescript/src/utils/ReactNativeUtils.d.ts +3 -0
  222. package/lib/typescript/src/utils/ReactNativeUtils.d.ts.map +1 -0
  223. package/lib/typescript/src/views/CVCElement.d.ts +15 -0
  224. package/lib/typescript/src/views/CVCElement.d.ts.map +1 -0
  225. package/lib/typescript/src/views/NativePaymentWidget.d.ts +3 -0
  226. package/lib/typescript/src/views/NativePaymentWidget.d.ts.map +1 -0
  227. package/lib/typescript/src/views/NativePaymentWidgetImpl.d.ts +5 -0
  228. package/lib/typescript/src/views/NativePaymentWidgetImpl.d.ts.map +1 -0
  229. package/lib/typescript/src/views/PaymentElement.d.ts +18 -0
  230. package/lib/typescript/src/views/PaymentElement.d.ts.map +1 -0
  231. package/package.json +184 -0
  232. package/src/context/Elements.ts +80 -0
  233. package/src/context/HyperElements.tsx +81 -0
  234. package/src/context/PaymentSession.ts +121 -0
  235. package/src/context/SavedPaymentMethods.ts +80 -0
  236. package/src/context/WidgetRegistry.ts +74 -0
  237. package/src/context/hooks.ts +79 -0
  238. package/src/index.ts +53 -0
  239. package/src/modules/NativeHyperswitchSdk.ts +155 -0
  240. package/src/specs/ApplePayViewNativeComponent.ts +11 -0
  241. package/src/specs/NativeHyperHeadless.ts +22 -0
  242. package/src/specs/NativeHyperswitchModule.ts +51 -0
  243. package/src/specs/NativeHyperswitchSdkNative.ts +62 -0
  244. package/src/specs/NativePaymentElementModule.ts +25 -0
  245. package/src/specs/PaymentElementNativeComponent.ts +21 -0
  246. package/src/specs/utils.ts +15 -0
  247. package/src/types/NativeModuleTypes.ts +73 -0
  248. package/src/types/PaymentSheetConfiguration.ts +360 -0
  249. package/src/types/definitions.ts +109 -0
  250. package/src/types/elements/index.ts +33 -0
  251. package/src/types/paymentresult/index.ts +4 -0
  252. package/src/types/savedPaymentMethods/index.ts +74 -0
  253. package/src/utils/EventValidator.ts +39 -0
  254. package/src/utils/InitializationState.ts +28 -0
  255. package/src/utils/LaunchOptions.ts +41 -0
  256. package/src/utils/NewArchUtils.ts +18 -0
  257. package/src/utils/ReactNativeUtils.ts +13 -0
  258. package/src/views/CVCElement.tsx +122 -0
  259. package/src/views/NativePaymentWidget.ts +2 -0
  260. package/src/views/NativePaymentWidgetImpl.ts +16 -0
  261. package/src/views/PaymentElement.tsx +189 -0
  262. package/tsconfig.build.json +21 -0
@@ -0,0 +1,47 @@
1
+ package com.hyperswitchsdkreactnative
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+ import com.facebook.react.uimanager.ViewManager
9
+ import com.hyperswitchsdkreactnative.modules.NativePaymentWidgetModule
10
+ import com.hyperswitchsdkreactnative.modules.ReactNativeHyperswitchModule
11
+ import com.hyperswitchsdkreactnative.views.PaymentElementViewManager
12
+ import io.hyperswitch.react.GooglePayButtonManager
13
+ import io.hyperswitch.react.HyperHeadlessModule
14
+ import io.hyperswitch.react.HyperModule
15
+ import java.util.ArrayList
16
+
17
+ class HyperswitchSdkReactNativePackage : BaseReactPackage() {
18
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
19
+ return when (name) {
20
+ HyperModule.NAME -> HyperModule(reactContext)
21
+ HyperHeadlessModule.NAME -> HyperHeadlessModule(reactContext)
22
+ ReactNativeHyperswitchModule.NAME -> ReactNativeHyperswitchModule(reactContext)
23
+ // NativePaymentWidgetNativeModule.NAME -> NativePaymentWidgetNativeModule(reactContext)
24
+ else -> null
25
+ }
26
+ }
27
+
28
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
29
+ val viewManagers: MutableList<ViewManager<*, *>> = ArrayList()
30
+ viewManagers.add(GooglePayButtonManager())
31
+ viewManagers.add(PaymentElementViewManager())
32
+ return viewManagers
33
+ }
34
+
35
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
36
+ return ReactModuleInfoProvider {
37
+ arrayOf(
38
+ HyperModule.NAME,
39
+ HyperHeadlessModule.NAME,
40
+ ReactNativeHyperswitchModule.NAME,
41
+ NativePaymentWidgetModule.NAME,
42
+ ).associateWith {
43
+ ReactModuleInfo(it, it, false, false, false, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED)
44
+ }.toMutableMap()
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,173 @@
1
+ package com.hyperswitchsdkreactnative.modules
2
+
3
+ import android.util.Log
4
+ import android.view.View
5
+ import android.view.ViewGroup
6
+ import com.facebook.react.bridge.Callback
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.facebook.react.uimanager.IllegalViewOperationException
9
+ import com.facebook.react.uimanager.UIManagerModule
10
+ import com.hyperswitchsdkreactnative.NativePaymentElementModuleSpec
11
+ import io.hyperswitch.view.PaymentWidgetView
12
+ import kotlinx.coroutines.CoroutineScope
13
+ import kotlinx.coroutines.Dispatchers
14
+ import kotlinx.coroutines.SupervisorJob
15
+ import kotlinx.coroutines.cancel
16
+
17
+ class NativePaymentWidgetModule(reactContext: ReactApplicationContext) :
18
+ NativePaymentElementModuleSpec(reactContext) {
19
+
20
+ private val moduleScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
21
+
22
+ override fun invalidate() {
23
+ moduleScope.cancel()
24
+ super.invalidate()
25
+ }
26
+
27
+ override fun getName(): String {
28
+ return NAME
29
+ }
30
+
31
+ override fun confirmPayment(
32
+ reactTag: Double,
33
+ callback: Callback
34
+ ) {
35
+ val uiManagerModule =
36
+ reactApplicationContext.getNativeModule(UIManagerModule::class.java)
37
+ uiManagerModule?.addUIBlock { nvhm ->
38
+ try {
39
+ val view = nvhm.resolveView(reactTag.toInt())
40
+ val element = resolveHyperswitchElement(view)
41
+ if (element != null) {
42
+ element.confirmPayment { result ->
43
+ callback.invoke(result)
44
+ }
45
+ } else {
46
+ callback.invoke("ERROR", "Invalid view type")
47
+ }
48
+ } catch (e: Exception) {
49
+ callback.invoke("ERROR", "View not found: ${e.message}")
50
+ }
51
+ }
52
+ }
53
+
54
+ override fun updateIntentInitForWidget(
55
+ reactTag: Double,
56
+ callback: Callback
57
+ ) {
58
+ val uiManagerModule =
59
+ reactApplicationContext.getNativeModule(UIManagerModule::class.java)
60
+ uiManagerModule?.addUIBlock { nvhm ->
61
+ try {
62
+ val view = nvhm.resolveView(reactTag.toInt())
63
+ // val element = resolveHyperswitchElement(view)
64
+ // if (element != null) {
65
+ //// element.updateIntentInit {
66
+ //// callback.invoke(Arguments.createMap().apply { putString("status", "success") })
67
+ //// }
68
+ // } else {
69
+ // callback.invoke("ERROR", "Invalid view type")
70
+ // }
71
+ } catch (e: IllegalViewOperationException) {
72
+ callback.invoke("ERROR", "View not found: ${e.message}")
73
+ }
74
+ }
75
+ }
76
+
77
+ override fun updateIntentCompleteForWidget(
78
+ reactTag: Double,
79
+ sdkAuthorization: String?,
80
+ callback: Callback
81
+ ) {
82
+ val uiManagerModule =
83
+ reactApplicationContext.getNativeModule<UIManagerModule?>(UIManagerModule::class.java)
84
+ uiManagerModule?.addUIBlock { nvhm ->
85
+ try {
86
+ val view = nvhm.resolveView(reactTag.toInt())
87
+ // val element = resolveHyperswitchElement(view)
88
+ // if (element != null) {
89
+ // moduleScope.launch {
90
+ // try {
91
+ //// val result = element.updateIntentComplete(sdkAuthorization)
92
+ //// callback.invoke(updateIntentResultToMap(result))
93
+ // } catch (e: Exception) {
94
+ // callback.invoke("ERROR", "updateIntentComplete failed: ${e.message}")
95
+ // }
96
+ // }
97
+ // } else {
98
+ // callback.invoke("ERROR", "Invalid view type")
99
+ // }
100
+ } catch (e: IllegalViewOperationException) {
101
+ callback.invoke("ERROR", "View not found: ${e.message}")
102
+ }
103
+ }
104
+ }
105
+
106
+ // private fun paymentResultToMap(result: PaymentResult): ReadableMap {
107
+ // val map = Arguments.createMap()
108
+ // when (result) {
109
+ // is PaymentResult.Completed -> {
110
+ // map.putString("status", "success")
111
+ // map.putString("message", "Payment confirmed successfully")
112
+ // result.data?.let { map.putString("data", it) }
113
+ // }
114
+ //
115
+ // is PaymentResult.Failed -> {
116
+ // map.putString("status", "failed")
117
+ // map.putString("code", result.throwable.cause?.message ?: "UNKNOWN_ERROR")
118
+ // map.putString("message", result.throwable.message ?: "An error has occurred.")
119
+ // }
120
+ //
121
+ // is PaymentResult.Canceled -> {
122
+ // map.putString("status", "cancelled")
123
+ // map.putString("message", "Payment confirmation cancelled")
124
+ // result.data?.let { map.putString("data", it) }
125
+ // }
126
+ // }
127
+ // return map
128
+ // }
129
+
130
+ private fun resolveHyperswitchElement(view: View?): PaymentWidgetView? {
131
+ if (view == null) return null
132
+ if (view is PaymentWidgetView) return view
133
+ if (view is ViewGroup) {
134
+ try {
135
+ return view.getChildAt(0) as PaymentWidgetView?
136
+ } catch (_: Exception) {
137
+ for (i in 0 until view.childCount) {
138
+ val child = view.getChildAt(i)
139
+ resolveHyperswitchElement(child)?.let {
140
+ return it
141
+ }
142
+ }
143
+ }
144
+ }
145
+ return null
146
+ }
147
+
148
+ // private fun updateIntentResultToMap(result: ElementUpdateIntentResult): ReadableMap {
149
+ // val map = Arguments.createMap()
150
+ // when (result) {
151
+ // is ElementUpdateIntentResult.Success -> {
152
+ // map.putString("status", "success")
153
+ // map.putString("message", "Update intent completed")
154
+ // }
155
+ //
156
+ // is ElementUpdateIntentResult.Cancelled -> {
157
+ // map.putString("status", "cancelled")
158
+ // map.putString("message", "Update intent cancelled")
159
+ // }
160
+ //
161
+ // is ElementUpdateIntentResult.Failure -> {
162
+ // map.putString("status", "failed")
163
+ // map.putString("code", result.cause.message ?: "UNKNOWN_ERROR")
164
+ // map.putString("message", result.cause.localizedMessage ?: "Update intent failed")
165
+ // }
166
+ // }
167
+ // return map
168
+ // }
169
+
170
+ companion object {
171
+ const val NAME = "NativePaymentElementModule"
172
+ }
173
+ }
@@ -0,0 +1,396 @@
1
+ package com.hyperswitchsdkreactnative.modules
2
+
3
+ import android.annotation.SuppressLint
4
+ import com.facebook.react.bridge.Promise
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.bridge.ReadableMap
7
+ import com.facebook.react.uimanager.UIManagerModule
8
+ import com.hyperswitchsdkreactnative.BuildConfig
9
+ import com.hyperswitchsdkreactnative.NativeHyperswitchModuleSpec
10
+ import io.hyperswitch.model.CustomEndpointConfiguration
11
+ import io.hyperswitch.model.HyperswitchConfiguration
12
+ import io.hyperswitch.model.HyperswitchEnvironment
13
+ import io.hyperswitch.model.OverrideEndpoints
14
+ import io.hyperswitch.paymentsession.GetPaymentSessionCallBackManager
15
+ import io.hyperswitch.paymentsession.LaunchOptions
16
+ import io.hyperswitch.paymentsession.PMError
17
+ import io.hyperswitch.paymentsession.PaymentMethodType
18
+ import io.hyperswitch.paymentsession.PaymentSessionHandler
19
+ import io.hyperswitch.paymentsession.PaymentSessionReactLauncher
20
+ import io.hyperswitch.paymentsession.PaymentSheetCallbackManager
21
+ import io.hyperswitch.utils.ConversionUtils
22
+ import io.hyperswitch.utils.StandardResult
23
+ import io.hyperswitch.view.PaymentWidgetView
24
+ import org.json.JSONArray
25
+ import org.json.JSONObject
26
+ import java.util.UUID
27
+ import java.util.concurrent.atomic.AtomicBoolean
28
+ import kotlin.String
29
+ import kotlin.collections.orEmpty
30
+
31
+
32
+ class ReactNativeHyperswitchModule(reactContext: ReactApplicationContext) :
33
+ NativeHyperswitchModuleSpec(reactContext) {
34
+
35
+ private var paymentSessionReactLauncher: PaymentSessionReactLauncher? = null
36
+ private var launchOptions: LaunchOptions? = null
37
+ private var handler: PaymentSessionHandler? = null
38
+
39
+ private var isPresented: AtomicBoolean = AtomicBoolean(false)
40
+
41
+ override fun getName(): String {
42
+ return NAME
43
+ }
44
+
45
+ override fun initialise(
46
+ publishableKey: String?,
47
+ platformPublishableKey: String?,
48
+ profileId: String?,
49
+ environment: String?,
50
+ customEndpoints: ReadableMap?,
51
+ promise: Promise?
52
+ ) {
53
+ val activity = currentActivity
54
+ if (publishableKey.isNullOrBlank()) {
55
+ promise?.reject("INITIALIZATION_ERROR", "publishableKey is required")
56
+ return
57
+ }
58
+ if (activity == null) {
59
+ promise?.reject("INITIALIZATION_ERROR", "Current activity is null")
60
+ return
61
+ }
62
+
63
+ activity.let {
64
+ paymentSessionReactLauncher = PaymentSessionReactLauncher(activity)
65
+ paymentSessionReactLauncher?.initializeReactNativeInstance()
66
+ }
67
+
68
+ val overrideEndpoints: OverrideEndpoints? = customEndpoints?.getMap("overrideEndpoints")?.let {
69
+ val overrideEndpointsMap = customEndpoints.getMap("overrideEndpoints")
70
+ OverrideEndpoints(
71
+ customBackendEndpoint = overrideEndpointsMap?.getString("customBackendEndpoint"),
72
+ customLoggingEndpoint = overrideEndpointsMap?.getString("customLoggingEndpoint"),
73
+ customAssetEndpoint = overrideEndpointsMap?.getString("customAssetEndpoint"),
74
+ customSDKConfigEndpoint = overrideEndpointsMap?.getString("customSDKConfigEndpoint"),
75
+ customConfirmEndpoint = overrideEndpointsMap?.getString("customConfirmEndpoint"),
76
+ customAirborneEndpoint = overrideEndpointsMap?.getString("customAirborneEndpoint"),
77
+ )
78
+ }
79
+ val customConfig = CustomEndpointConfiguration(
80
+ overrideEndpoints = overrideEndpoints,
81
+ commonEndpoint = customEndpoints?.getString("commonEndpoint")
82
+
83
+ )
84
+
85
+ hyperswitchConfig = HyperswitchConfiguration(
86
+ publishableKey = publishableKey,
87
+ profileId = profileId,
88
+ environment = environment?.let { HyperswitchEnvironment.valueOf(it) },
89
+ customConfig = customConfig
90
+ )
91
+ activity.let {
92
+ launchOptions = LaunchOptions(activity, BuildConfig.VERSION_NAME, hyperswitchConfig)
93
+ }
94
+ val handle = UUID.randomUUID().toString()
95
+ promise?.resolve(handle)
96
+ }
97
+
98
+ override fun presentPaymentSheet(
99
+ params: ReadableMap?,
100
+ promise: Promise?
101
+ ) {
102
+ try {
103
+ // val map = mutableMapOf<String, Any>().apply {
104
+ // put("code", "failed")
105
+ // put("message", "opened alreday")
106
+ // }
107
+ // promise?.resolve(map)
108
+ // return
109
+ // }
110
+ val props = mutableMapOf<String, Any?>().apply {
111
+ putAll(params?.toHashMap().orEmpty())
112
+ put("type", "payment")
113
+ }
114
+
115
+ val map: Map<String, Any?> = mapOf(
116
+ "props" to props
117
+ )
118
+ val bundle = launchOptions?.toBundle(map)
119
+ bundle?.let {
120
+ val isFragment = paymentSessionReactLauncher?.presentSheet(bundle)
121
+ // isPresented.set(true)
122
+ val resultCallback: (String) -> Unit = { it ->
123
+ // isPresented.set(false)
124
+ promise?.resolve(it)
125
+ }
126
+ PaymentSheetCallbackManager.setCallback(resultCallback, isFragment == true)
127
+ }
128
+ } catch (e: Exception) {
129
+ val map = mutableMapOf<String, Any>().apply {
130
+ put("code", "failed")
131
+ put("message", "failed to open")
132
+ put("reason", e.message.toString())
133
+ }
134
+ promise?.resolve(map)
135
+ }finally {
136
+ // isPresented.set(false)
137
+ }
138
+ }
139
+
140
+ override fun getCustomerSavedPaymentMethods(
141
+ params: ReadableMap?,
142
+ promise: Promise
143
+ ) {
144
+ val props = mutableMapOf<String, Any?>().apply {
145
+ putAll(params?.toHashMap().orEmpty())
146
+ put("type", "payment")
147
+ }
148
+
149
+ val map: Map<String, Any?> = mapOf(
150
+ "props" to props
151
+ )
152
+ val bundle = launchOptions?.toBundle(map)
153
+ bundle?.let {
154
+ val savedPaymentMethodCallback: (PaymentSessionHandler) -> Unit = { it ->
155
+ handler = it
156
+ promise.resolve(
157
+ JSONObject().apply {
158
+ put("code", "success")
159
+ put("message", "Saved payment methods is initialized")
160
+ }.toString()
161
+ )
162
+ }
163
+ GetPaymentSessionCallBackManager.setCallback(
164
+ params?.getMap("sessionConfig")?.getString("sdkAuthorization"),
165
+ savedPaymentMethodCallback
166
+ )
167
+ paymentSessionReactLauncher?.recreateReactContext(it)
168
+ }
169
+
170
+ }
171
+
172
+ override fun getCustomerLastUsedPaymentMethodData(promise: Promise) {
173
+ handler?.let {
174
+ it.getCustomerLastUsedPaymentMethodData().fold(
175
+ onSuccess = { data ->
176
+ promise.resolve(ConversionUtils.convertMapToJson(data.toMap()).toString())
177
+ },
178
+ onFailure = { error ->
179
+ promise.resolve(error.toString())
180
+ }
181
+ )
182
+ }
183
+ }
184
+
185
+ override fun getCustomerDefaultSavedPaymentMethodData(promise: Promise) {
186
+ handler?.let {
187
+ it.getCustomerDefaultSavedPaymentMethodData().fold(
188
+ onSuccess = { data ->
189
+ promise.resolve(ConversionUtils.convertMapToJson(data.toMap()).toString())
190
+ },
191
+ onFailure = { error ->
192
+ promise.reject(error.toString())
193
+ }
194
+ )
195
+ }
196
+ }
197
+
198
+ override fun getCustomerSavedPaymentMethodData(promise: Promise) {
199
+ handler?.let {
200
+ it.getCustomerSavedPaymentMethodData().fold(
201
+ onSuccess = { data ->
202
+ val jsonArray = JSONArray()
203
+ data.forEach { item ->
204
+ jsonArray.put(
205
+ ConversionUtils.convertMapToJson(item.toMap())
206
+ )
207
+ }
208
+ promise.resolve(jsonArray.toString())
209
+ },
210
+ onFailure = { error ->
211
+ promise.reject(error.toString())
212
+ }
213
+ )
214
+ }
215
+ }
216
+
217
+ override fun confirmWithCustomerLastUsedPaymentMethod(reactTag: Double, promise: Promise?) {
218
+ if (handler == null) {
219
+ promise?.resolve(
220
+ StandardResult.Failed(error = Throwable("Payment session handler not initialized."))
221
+ .toJSONString()
222
+ )
223
+ return
224
+ }
225
+
226
+ val reactTag = reactTag.toInt()
227
+
228
+ if (reactTag > 0) {
229
+ val defaultData = handler?.getCustomerLastUsedPaymentMethodData()
230
+ defaultData?.fold(
231
+ onSuccess = { pm ->
232
+ if (pm.requiresCvv && pm.paymentMethod == PaymentMethodType.CARD) {
233
+ confirmViaWidgetView(reactTag, pm.paymentToken, pm.paymentMethodId, promise)
234
+ } else {
235
+ handler?.confirmWithCustomerLastUsedPaymentMethod(null) { result ->
236
+ promise?.resolve(result)
237
+ }
238
+ }
239
+ },
240
+ onFailure = { error ->
241
+ val pmError = error as? PMError
242
+ promise?.resolve(
243
+ StandardResult.Failed(
244
+ code = pmError?.code ?: "UNKNOWN",
245
+ message = pmError?.message ?: error.message ?: "Unknown error",
246
+ error = Throwable(pmError?.message ?: error.message ?: "Unknown error")
247
+ )
248
+ )
249
+ }
250
+ )
251
+ } else {
252
+ handler?.confirmWithCustomerLastUsedPaymentMethod(null) { result ->
253
+ promise?.resolve(result)
254
+ }
255
+ }
256
+ }
257
+
258
+ override fun confirmWithCustomerDefaultPaymentMethod(reactTag: Double, promise: Promise?) {
259
+ if (handler == null) {
260
+ promise?.resolve(
261
+ StandardResult.Failed(error = Throwable("Payment session handler not initialized."))
262
+ .toJSONString()
263
+ )
264
+ return
265
+ }
266
+
267
+ val reactTag = reactTag.toInt()
268
+
269
+ if (reactTag > 0) {
270
+ val defaultData = handler?.getCustomerDefaultSavedPaymentMethodData()
271
+ defaultData?.fold(
272
+ onSuccess = { pm ->
273
+ if (pm.requiresCvv && pm.paymentMethod == PaymentMethodType.CARD) {
274
+ confirmViaWidgetView(reactTag, pm.paymentToken, pm.paymentMethodId, promise)
275
+ } else {
276
+ handler?.confirmWithCustomerDefaultPaymentMethod(null) { result ->
277
+ promise?.resolve(result)
278
+ }
279
+ }
280
+ },
281
+ onFailure = { error ->
282
+ val pmError = error as? PMError
283
+ promise?.resolve(
284
+ StandardResult.Failed(
285
+ code = pmError?.code ?: "UNKNOWN",
286
+ message = pmError?.message ?: error.message ?: "Unknown error",
287
+ error = Throwable(pmError?.message ?: error.message ?: "Unknown error")
288
+ )
289
+ )
290
+ }
291
+ )
292
+ } else {
293
+ handler?.confirmWithCustomerDefaultPaymentMethod(null) { result ->
294
+ promise?.resolve(result)
295
+ }
296
+ }
297
+ }
298
+
299
+ override fun confirmWithCustomerPaymentToken(
300
+ reactTag: Double,
301
+ token: String?,
302
+ promise: Promise?
303
+ ) {
304
+ if (handler == null) {
305
+ promise?.resolve(
306
+ StandardResult.Failed(
307
+ code = "error",
308
+ message = "UNKNOWN",
309
+ error = Throwable("Payment session handler not initialized.")
310
+ ).toJSONString()
311
+ )
312
+ return
313
+ }
314
+ if (token == null) {
315
+ promise?.resolve(
316
+ StandardResult.Failed(
317
+ code = "error",
318
+ message = "UNKNOWN",
319
+ error = Throwable("Token cannot be null")
320
+ ).toJSONString()
321
+ )
322
+ return
323
+ } else {
324
+ handler?.confirmWithCustomerPaymentToken(token, null) { result ->
325
+ promise?.resolve(result)
326
+ }
327
+ }
328
+ }
329
+
330
+ // override fun updateIntent(sdkAuthorization: String?, promise: Promise?) {
331
+ // val sdkAuthorizationNonNull = sdkAuthorization ?: run {
332
+ // promise?.reject("UPDATE_INTENT_ERROR", "sdkAuthorization is required")
333
+ // return
334
+ // }
335
+ //
336
+ //
337
+ // if (session == null) {
338
+ // promise?.reject(
339
+ // "UPDATE_INTENT_ERROR",
340
+ // "Payment session not initialized. Call initPaymentSession first."
341
+ // )
342
+ // return
343
+ // }
344
+ //
345
+ // session.updateSdkAuthorization(sdkAuthorizationNonNull)
346
+ // activeSdkAuthorization = sdkAuthorizationNonNull
347
+ //
348
+ // promise?.resolve(serializeResult("success", null, "Payment intent updated"))
349
+ //
350
+ // }
351
+
352
+
353
+ private fun confirmViaWidgetView(
354
+ reactTag: Int,
355
+ paymentToken: String,
356
+ paymentMethodId: String,
357
+ promise: Promise?
358
+ ) {
359
+
360
+ val uiManagerModule =
361
+ reactApplicationContext.getNativeModule<UIManagerModule?>(UIManagerModule::class.java)
362
+ uiManagerModule?.addUIBlock { nvhm ->
363
+ try {
364
+ val view = nvhm.resolveView(reactTag)
365
+ if (view is PaymentWidgetView) {
366
+ view.confirmCvcPayment(paymentToken, paymentMethodId) { result: String ->
367
+ promise?.resolve(result)
368
+ }
369
+ } else {
370
+ promise?.resolve(
371
+ StandardResult.Failed(
372
+ code = "INVALID_VIEW",
373
+ error = Throwable("View at reactTag $reactTag is not a CvcWidget")
374
+ )
375
+ )
376
+ }
377
+ } catch (e: Exception) {
378
+ promise?.resolve(
379
+ StandardResult.Failed(
380
+ code = "NO_WIDGET",
381
+ error = Throwable("CvcWidget not found at reactTag $reactTag: ${e.message}")
382
+ )
383
+ )
384
+ }
385
+ }
386
+ }
387
+
388
+ fun resetView() {
389
+ // PaymentSession manages its own sheet UI; no global provider reset is needed.
390
+ }
391
+
392
+ companion object {
393
+ const val NAME = "NativeHyperswitchModule"
394
+ private var hyperswitchConfig: HyperswitchConfiguration? = null
395
+ }
396
+ }