framepayments-react-native 1.0.0 → 1.0.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 (162) hide show
  1. package/README.md +28 -8
  2. package/android/build/.transforms/3db830673120be833016e77c88c53305/results.bin +1 -0
  3. package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$Companion.dex +0 -0
  4. package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$tryShowCheckout$1.dex +0 -0
  5. package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity.dex +0 -0
  6. package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameFlowActivity$CartItemDto.dex +0 -0
  7. package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameFlowActivity$Companion.dex +0 -0
  8. package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameFlowActivity$parseCartItems$type$1.dex +0 -0
  9. package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameFlowActivity.dex +0 -0
  10. package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameSDKModule.dex +0 -0
  11. package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameSDKPackage.dex +0 -0
  12. package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/desugar_graph.bin +0 -0
  13. package/android/build/.transforms/e32bd1e24a69eac3ebaf0c3a5e659207/results.bin +1 -0
  14. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/AndroidManifest.xml +18 -0
  15. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/output-metadata.json +18 -0
  16. package/android/build/intermediates/aar_metadata/debug/aar-metadata.properties +5 -0
  17. package/android/build/intermediates/annotation_processor_list/debug/annotationProcessors.json +1 -0
  18. package/android/build/intermediates/compile_library_classes_jar/debug/classes.jar +0 -0
  19. package/android/build/intermediates/compile_r_class_jar/debug/R.jar +0 -0
  20. package/android/build/intermediates/compile_symbol_list/debug/R.txt +0 -0
  21. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
  22. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
  23. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
  24. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
  25. package/android/build/intermediates/incremental/packageDebugAssets/merger.xml +2 -0
  26. package/android/build/intermediates/java_res/debug/out/META-INF/framepayments-react-native_debug.kotlin_module +0 -0
  27. package/android/build/intermediates/local_only_symbol_list/debug/R-def.txt +2 -0
  28. package/android/build/intermediates/manifest_merge_blame_file/debug/manifest-merger-blame-debug-report.txt +27 -0
  29. package/android/build/intermediates/merged_manifest/debug/AndroidManifest.xml +18 -0
  30. package/android/build/intermediates/navigation_json/debug/navigation.json +1 -0
  31. package/android/build/intermediates/runtime_library_classes_dir/debug/META-INF/framepayments-react-native_debug.kotlin_module +0 -0
  32. package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$Companion.class +0 -0
  33. package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$tryShowCheckout$1.class +0 -0
  34. package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity.class +0 -0
  35. package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameFlowActivity$CartItemDto.class +0 -0
  36. package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameFlowActivity$Companion.class +0 -0
  37. package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameFlowActivity$parseCartItems$type$1.class +0 -0
  38. package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameFlowActivity.class +0 -0
  39. package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameSDKModule.class +0 -0
  40. package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameSDKPackage.class +0 -0
  41. package/android/build/intermediates/runtime_library_classes_jar/debug/classes.jar +0 -0
  42. package/android/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt +1 -0
  43. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  44. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
  45. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
  46. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
  47. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  48. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
  49. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
  50. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  51. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  52. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  53. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  54. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  55. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  56. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
  57. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  58. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  59. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  60. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  61. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  62. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  63. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
  64. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
  65. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream +0 -0
  66. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len +0 -0
  67. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len +0 -0
  68. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
  69. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i +0 -0
  70. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len +0 -0
  71. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  72. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  73. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  74. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  75. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  76. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  77. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
  78. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  79. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  80. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  81. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  82. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  83. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  84. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
  85. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  86. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
  87. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
  88. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
  89. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  90. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
  91. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
  92. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
  93. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
  94. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
  95. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
  96. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  97. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
  98. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
  99. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
  100. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
  101. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
  102. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
  103. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
  104. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
  105. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
  106. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +2 -0
  107. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  108. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
  109. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
  110. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
  111. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
  112. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
  113. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
  114. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  115. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
  116. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
  117. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
  118. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  119. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
  120. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
  121. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  122. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  123. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  124. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  125. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  126. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  127. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
  128. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  129. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  130. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  131. package/android/build/outputs/logs/manifest-merger-debug-report.txt +35 -0
  132. package/android/build/tmp/kotlin-classes/debug/META-INF/framepayments-react-native_debug.kotlin_module +0 -0
  133. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$Companion.class +0 -0
  134. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$tryShowCheckout$1.class +0 -0
  135. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity.class +0 -0
  136. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity$CartItemDto.class +0 -0
  137. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity$Companion.class +0 -0
  138. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity$parseCartItems$type$1.class +0 -0
  139. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity.class +0 -0
  140. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameSDKModule.class +0 -0
  141. package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameSDKPackage.class +0 -0
  142. package/android/build.gradle +6 -2
  143. package/android/src/main/AndroidManifest.xml +2 -1
  144. package/android/src/main/java/com/framepayments/reactnativeframe/FrameCheckoutActivity.kt +44 -0
  145. package/android/src/main/java/com/framepayments/reactnativeframe/FrameSDKModule.kt +14 -10
  146. package/ios/FramePreloader.swift +28 -0
  147. package/ios/FrameSDKBridge.m +57 -1
  148. package/ios/FrameSDKBridge.swift +35 -54
  149. package/ios/FrameVCHelper.h +12 -0
  150. package/ios/FrameVCHelper.m +11 -0
  151. package/lib/__tests__/native.test.d.ts +32 -0
  152. package/lib/__tests__/native.test.d.ts.map +1 -0
  153. package/lib/__tests__/native.test.js +101 -0
  154. package/lib/index.d.ts +9 -1
  155. package/lib/index.d.ts.map +1 -1
  156. package/lib/index.js +4 -1
  157. package/lib/native.d.ts +1 -1
  158. package/lib/native.d.ts.map +1 -1
  159. package/lib/native.js +4 -3
  160. package/package.json +11 -8
  161. package/src/index.ts +6 -1
  162. package/src/native.ts +7 -4
@@ -5,7 +5,7 @@ buildscript {
5
5
  }
6
6
  dependencies {
7
7
  classpath 'com.android.tools.build:gradle:8.1.0'
8
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0"
8
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0"
9
9
  }
10
10
  }
11
11
 
@@ -40,7 +40,11 @@ repositories {
40
40
 
41
41
  dependencies {
42
42
  implementation 'com.facebook.react:react-native:+'
43
- implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.0"
43
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:2.1.0"
44
44
  implementation 'com.framepayments:framesdk:1.2.0'
45
45
  implementation 'com.framepayments:framesdk_ui:1.2.0'
46
+ implementation 'com.google.code.gson:gson:2.10.1'
47
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
48
+ // Frame SDK UI uses Compose; LocalLifecycleOwner requires lifecycle-runtime-compose 2.8+
49
+ implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.8.2'
46
50
  }
@@ -1,4 +1,5 @@
1
- <manifest xmlns:android="http://schemas.android.com/apk/res/android">
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.framepayments.reactnativeframe">
2
3
  <application>
3
4
  <activity
4
5
  android:name="com.framepayments.reactnativeframe.FrameCheckoutActivity"
@@ -2,6 +2,8 @@ package com.framepayments.reactnativeframe
2
2
 
3
3
  import android.content.Intent
4
4
  import android.os.Bundle
5
+ import android.os.Handler
6
+ import android.os.Looper
5
7
  import android.widget.FrameLayout
6
8
  import androidx.appcompat.app.AppCompatActivity
7
9
  import com.framepayments.framesdk.FrameNetworking
@@ -11,6 +13,9 @@ import com.google.gson.Gson
11
13
 
12
14
  class FrameCheckoutActivity : AppCompatActivity() {
13
15
 
16
+ private val handler = Handler(Looper.getMainLooper())
17
+ private var pollRunnable: Runnable? = null
18
+
14
19
  override fun onCreate(savedInstanceState: Bundle?) {
15
20
  super.onCreate(savedInstanceState)
16
21
  val container = FrameLayout(this).apply {
@@ -22,6 +27,40 @@ class FrameCheckoutActivity : AppCompatActivity() {
22
27
  setContentView(container)
23
28
  val customerId = intent.getStringExtra(EXTRA_CUSTOMER_ID)
24
29
  val amount = intent.getIntExtra(EXTRA_AMOUNT, 0)
30
+
31
+ // Evervault must be configured before FrameCheckoutView (EncryptedPaymentCardInput) can inflate.
32
+ // configureEvervault() is async on first launch; direct checkout opens before it completes.
33
+ tryShowCheckout(container, customerId, amount)
34
+ }
35
+
36
+ private fun tryShowCheckout(container: FrameLayout, customerId: String?, amount: Int) {
37
+ if (FrameNetworking.isEvervaultConfigured) {
38
+ addCheckoutView(container, customerId, amount)
39
+ return
40
+ }
41
+ var attempts = 0
42
+ val maxAttempts = 50 // 5 seconds
43
+ pollRunnable = object : Runnable {
44
+ override fun run() {
45
+ if (isFinishing) return
46
+ if (FrameNetworking.isEvervaultConfigured) {
47
+ addCheckoutView(container, customerId, amount)
48
+ pollRunnable = null
49
+ return
50
+ }
51
+ attempts++
52
+ if (attempts >= maxAttempts) {
53
+ setResult(RESULT_CANCELED)
54
+ finish()
55
+ return
56
+ }
57
+ handler.postDelayed(this, 100)
58
+ }
59
+ }
60
+ handler.postDelayed(pollRunnable!!, 100)
61
+ }
62
+
63
+ private fun addCheckoutView(container: FrameLayout, customerId: String?, amount: Int) {
25
64
  val checkoutView = FrameCheckoutView(this)
26
65
  checkoutView.configure(customerId, amount) { chargeIntent ->
27
66
  val json = Gson().toJson(chargeIntent)
@@ -31,6 +70,11 @@ class FrameCheckoutActivity : AppCompatActivity() {
31
70
  container.addView(checkoutView)
32
71
  }
33
72
 
73
+ override fun onDestroy() {
74
+ pollRunnable?.let { handler.removeCallbacks(it) }
75
+ super.onDestroy()
76
+ }
77
+
34
78
  companion object {
35
79
  const val EXTRA_CUSTOMER_ID = "customer_id"
36
80
  const val EXTRA_AMOUNT = "amount"
@@ -43,11 +43,13 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
43
43
  return
44
44
  }
45
45
  checkoutPromise = promise
46
- val intent = Intent(activity, FrameCheckoutActivity::class.java).apply {
47
- putExtra(FrameCheckoutActivity.EXTRA_CUSTOMER_ID, customerId)
48
- putExtra(FrameCheckoutActivity.EXTRA_AMOUNT, amount.toInt())
46
+ activity.runOnUiThread {
47
+ val intent = Intent(activity, FrameCheckoutActivity::class.java).apply {
48
+ putExtra(FrameCheckoutActivity.EXTRA_CUSTOMER_ID, customerId)
49
+ putExtra(FrameCheckoutActivity.EXTRA_AMOUNT, amount.toInt())
50
+ }
51
+ activity.startActivityForResult(intent, FrameCheckoutActivity.REQUEST_CODE)
49
52
  }
50
- activity.startActivityForResult(intent, FrameCheckoutActivity.REQUEST_CODE)
51
53
  }
52
54
 
53
55
  @ReactMethod
@@ -66,12 +68,14 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
66
68
  return
67
69
  }
68
70
  cartPromise = promise
69
- val intent = Intent(activity, FrameFlowActivity::class.java).apply {
70
- putExtra(FrameFlowActivity.EXTRA_CUSTOMER_ID, customerId)
71
- putExtra(FrameFlowActivity.EXTRA_ITEMS_JSON, itemsJson)
72
- putExtra(FrameFlowActivity.EXTRA_SHIPPING_CENTS, shippingAmountInCents.toInt())
71
+ activity.runOnUiThread {
72
+ val intent = Intent(activity, FrameFlowActivity::class.java).apply {
73
+ putExtra(FrameFlowActivity.EXTRA_CUSTOMER_ID, customerId)
74
+ putExtra(FrameFlowActivity.EXTRA_ITEMS_JSON, itemsJson)
75
+ putExtra(FrameFlowActivity.EXTRA_SHIPPING_CENTS, shippingAmountInCents.toInt())
76
+ }
77
+ activity.startActivityForResult(intent, FrameFlowActivity.REQUEST_CODE)
73
78
  }
74
- activity.startActivityForResult(intent, FrameFlowActivity.REQUEST_CODE)
75
79
  }
76
80
 
77
81
  private fun readableArrayToJson(items: com.facebook.react.bridge.ReadableArray): String? {
@@ -82,7 +86,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
82
86
  obj.put("id", item.getString("id"))
83
87
  obj.put("title", item.getString("title"))
84
88
  obj.put("amountInCents", item.getDouble("amountInCents").toInt())
85
- obj.put("imageUrl", item.getString("imageUrl"))
89
+ obj.put("imageUrl", item.getString("imageUrl") ?: "")
86
90
  arr.put(obj)
87
91
  }
88
92
  return arr.toString()
@@ -0,0 +1,28 @@
1
+ //
2
+ // FramePreloader.swift
3
+ // FrameReactNative
4
+ //
5
+ // Preloads the Frame module on the main thread BEFORE the React Native bridge
6
+ // initializes. This avoids "Helpers are not supported by the default hub" crash
7
+ // that occurs when Frame/Evervault/Sift load on a background thread during
8
+ // bridge module discovery.
9
+ //
10
+
11
+ import Foundation
12
+ import Frame
13
+
14
+ @objc(FramePreloader)
15
+ public final class FramePreloader: NSObject {
16
+
17
+ /// Call from AppDelegate before [super application:didFinishLaunchingWithOptions].
18
+ /// Forces Frame (and its deps: Evervault, Sift) to load on main thread.
19
+ @objc public static func preloadOnMainThread() {
20
+ guard Thread.isMainThread else {
21
+ DispatchQueue.main.sync { preloadOnMainThread() }
22
+ return
23
+ }
24
+ // Touch FrameNetworking to trigger Frame module load on main thread.
25
+ // Evervault/Sift config is deferred to initializeWithAPIKey.
26
+ _ = FrameNetworking.shared
27
+ }
28
+ }
@@ -2,10 +2,28 @@
2
2
  // FrameSDKBridge.m
3
3
  // FrameReactNative
4
4
  //
5
+ // ObjC adapter that forwards to Swift FrameSDKBridge.
6
+ //
5
7
 
6
8
  #import <React/RCTBridgeModule.h>
9
+ #import "FrameVCHelper.h"
10
+
11
+ // Import app's Swift header (ObjCFrameSDKBridge, FramePreloader). The example uses FrameExampleTemp.
12
+ // If your app has a different module name, add Preprocessor Macro: FRAME_SWIFT_HEADER="YourApp-Swift.h"
13
+ #if defined(FRAME_SWIFT_HEADER)
14
+ #import FRAME_SWIFT_HEADER
15
+ #elif __has_include("FrameExampleTemp-Swift.h")
16
+ #import "FrameExampleTemp-Swift.h"
17
+ #elif __has_include(<FrameExampleTemp/FrameExampleTemp-Swift.h>)
18
+ #import <FrameExampleTemp/FrameExampleTemp-Swift.h>
19
+ #else
20
+ #error "Swift header not found. Add FRAME_SWIFT_HEADER=\"YourApp-Swift.h\" to your app target's Preprocessor Macros, or ensure Swift files compile before this file."
21
+ #endif
22
+
23
+ @interface FrameSDKModule : NSObject <RCTBridgeModule>
24
+ @end
7
25
 
8
- @interface RCT_EXTERN_MODULE(FrameSDK, FrameSDKBridge)
26
+ @interface RCT_EXTERN_MODULE(FrameSDK, FrameSDKModule)
9
27
 
10
28
  RCT_EXTERN_METHOD(initialize:(NSString *)apiKey
11
29
  debugMode:(BOOL)debugMode
@@ -24,3 +42,41 @@ RCT_EXTERN_METHOD(presentCart:(id)customerId
24
42
  rejecter:(RCTPromiseRejectBlock)reject)
25
43
 
26
44
  @end
45
+
46
+ @implementation FrameSDK
47
+ @end
48
+
49
+ @implementation FrameSDKModule
50
+
51
+ + (BOOL)requiresMainQueueSetup {
52
+ return YES;
53
+ }
54
+
55
+ - (void)initialize:(NSString *)apiKey debugMode:(BOOL)debugMode resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
56
+ [[[ObjCFrameSDKBridge alloc] init] initialize:apiKey debugMode:debugMode resolver:resolve rejecter:reject];
57
+ }
58
+
59
+ - (void)presentCheckout:(id)customerId amount:(NSNumber *)amount resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
60
+ dispatch_async(dispatch_get_main_queue(), ^{
61
+ UIViewController *topVC = FrameGetTopViewController();
62
+ if (!topVC) {
63
+ reject(@"NO_ROOT_VC", @"Could not find root view controller to present checkout", nil);
64
+ return;
65
+ }
66
+ NSString *cId = [customerId isKindOfClass:[NSString class]] ? (NSString *)customerId : nil;
67
+ [[[ObjCFrameSDKBridge alloc] init] presentCheckoutFrom:topVC customerId:cId amount:amount.intValue resolver:resolve rejecter:reject];
68
+ });
69
+ }
70
+
71
+ - (void)presentCart:(id)customerId items:(NSArray *)items shippingAmountInCents:(NSNumber *)shippingAmountInCents resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
72
+ dispatch_async(dispatch_get_main_queue(), ^{
73
+ UIViewController *topVC = FrameGetTopViewController();
74
+ if (!topVC) {
75
+ reject(@"NO_ROOT_VC", @"Could not find root view controller to present cart", nil);
76
+ return;
77
+ }
78
+ [[[ObjCFrameSDKBridge alloc] init] presentCartFrom:topVC customerId:customerId items:items shippingAmountInCents:shippingAmountInCents resolver:resolve rejecter:reject];
79
+ });
80
+ }
81
+
82
+ @end
@@ -11,14 +11,14 @@ import UIKit
11
11
  import SwiftUI
12
12
  import Frame
13
13
 
14
- @objc(FrameSDK)
15
- class FrameSDKBridge: NSObject {
14
+ @objc(ObjCFrameSDKBridge)
15
+ public class FrameSDKBridge: NSObject {
16
16
 
17
- @objc static func requiresMainQueueSetup() -> Bool {
17
+ @objc public static func requiresMainQueueSetup() -> Bool {
18
18
  return true
19
19
  }
20
20
 
21
- @objc
21
+ @objc public
22
22
  func initialize(_ apiKey: String, debugMode: Bool, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
23
23
  DispatchQueue.main.async {
24
24
  FrameNetworking.shared.initializeWithAPIKey(apiKey, debugMode: debugMode)
@@ -26,43 +26,41 @@ class FrameSDKBridge: NSObject {
26
26
  }
27
27
  }
28
28
 
29
- @objc
30
- func presentCheckout(_ customerId: NSObject, amount: NSNumber, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
31
- let cId = customerId as? String
32
- let amountInt = amount.intValue
33
- DispatchQueue.main.async { [weak self] in
34
- self?.presentCheckoutOnMain(customerId: cId, amount: amountInt, resolve: resolve, reject: reject)
35
- }
29
+ @objc public
30
+ func presentCheckout(from viewController: UIViewController, customerId: String?, amount: Int, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
31
+ presentCheckoutOnMain(from: viewController, customerId: customerId, amount: amount, resolve: resolve, reject: reject)
36
32
  }
37
33
 
38
- private func presentCheckoutOnMain(customerId: String?, amount: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
39
- guard let windowScene = UIApplication.shared.connectedScenes
40
- .compactMap({ $0 as? UIWindowScene })
41
- .first(where: { $0.activationState == .foregroundActive }),
42
- let rootVC = windowScene.windows.first(where: { $0.isKeyWindow })?.rootViewController else {
43
- reject("NO_ROOT_VC", "Could not find root view controller to present checkout", nil)
34
+ @objc public
35
+ func presentCart(from viewController: UIViewController, customerId: NSObject?, items: NSArray, shippingAmountInCents: Int, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
36
+ guard let cartItems = parseCartItems(items) else {
37
+ reject("INVALID_ITEMS", "Invalid cart items array", nil)
44
38
  return
45
39
  }
46
- var top = rootVC
47
- while let presented = top.presentedViewController { top = presented }
40
+ presentCartOnMain(from: viewController, customerId: customerId as? String, cartItems: cartItems, shippingAmountInCents: shippingAmountInCents, resolve: resolve, reject: reject)
41
+ }
42
+
43
+ private func presentCheckoutOnMain(from top: UIViewController, customerId: String?, amount: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
48
44
  let delegate = CheckoutDismissDelegate(resolve: resolve, reject: reject)
49
45
  let checkoutView = FrameCheckoutView(
50
46
  customerId: customerId,
51
47
  paymentAmount: amount,
52
- checkoutCallback: { [weak top, weak delegate] chargeIntent in
48
+ checkoutCallback: { [weak delegate] chargeIntent in
53
49
  delegate?.didComplete = true
54
- top?.dismiss(animated: true)
55
- if let dict = Self.encodeChargeIntent(chargeIntent) {
56
- resolve(dict)
57
- } else {
58
- reject("ENCODE_ERROR", "Failed to encode charge intent", nil)
50
+ top.dismiss(animated: true)
51
+ DispatchQueue.main.async {
52
+ if let dict = Self.encodeChargeIntent(chargeIntent) {
53
+ resolve(dict)
54
+ } else {
55
+ reject("ENCODE_ERROR", "Failed to encode charge intent", nil)
56
+ }
59
57
  }
60
58
  }
61
59
  )
62
60
  let hosting = UIHostingController(rootView: checkoutView)
63
- hosting.modalPresentationStyle = .pageSheet
61
+ hosting.modalPresentationStyle = UIModalPresentationStyle.pageSheet
64
62
  if let sheet = hosting.sheetPresentationController {
65
- sheet.detents = [.large()]
63
+ sheet.detents = [UISheetPresentationController.Detent.large()]
66
64
  }
67
65
  objc_setAssociatedObject(hosting, &checkoutDismissKey, delegate, .OBJC_ASSOCIATION_RETAIN)
68
66
  hosting.presentationController?.delegate = delegate
@@ -74,19 +72,6 @@ class FrameSDKBridge: NSObject {
74
72
  return try? JSONSerialization.jsonObject(with: data) as? [String: Any]
75
73
  }
76
74
 
77
- @objc
78
- func presentCart(_ customerId: NSObject, items: NSArray, shippingAmountInCents: NSNumber, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
79
- let cId = customerId as? String
80
- let shipping = shippingAmountInCents.intValue
81
- guard let cartItems = parseCartItems(items) else {
82
- reject("INVALID_ITEMS", "Invalid cart items array", nil)
83
- return
84
- }
85
- DispatchQueue.main.async { [weak self] in
86
- self?.presentCartOnMain(customerId: cId, cartItems: cartItems, shippingAmountInCents: shipping, resolve: resolve, reject: reject)
87
- }
88
- }
89
-
90
75
  private struct RNFrameCartItem: FrameCartItem {
91
76
  var id: String
92
77
  var imageURL: String
@@ -107,25 +92,16 @@ class FrameSDKBridge: NSObject {
107
92
  return result
108
93
  }
109
94
 
110
- private func presentCartOnMain(customerId: String?, cartItems: [RNFrameCartItem], shippingAmountInCents: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
111
- guard let windowScene = UIApplication.shared.connectedScenes
112
- .compactMap({ $0 as? UIWindowScene })
113
- .first(where: { $0.activationState == .foregroundActive }),
114
- let rootVC = windowScene.windows.first(where: { $0.isKeyWindow })?.rootViewController else {
115
- reject("NO_ROOT_VC", "Could not find root view controller to present cart", nil)
116
- return
117
- }
118
- var top = rootVC
119
- while let presented = top.presentedViewController { top = presented }
95
+ private func presentCartOnMain(from top: UIViewController, customerId: String?, cartItems: [RNFrameCartItem], shippingAmountInCents: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
120
96
  let cartView = FrameCartView(
121
97
  customer: nil,
122
98
  cartItems: cartItems,
123
99
  shippingAmountInCents: shippingAmountInCents
124
100
  )
125
101
  let hosting = UIHostingController(rootView: cartView)
126
- hosting.modalPresentationStyle = .pageSheet
102
+ hosting.modalPresentationStyle = UIModalPresentationStyle.pageSheet
127
103
  if let sheet = hosting.sheetPresentationController {
128
- sheet.detents = [.large()]
104
+ sheet.detents = [UISheetPresentationController.Detent.large()]
129
105
  }
130
106
  // When the sheet is dismissed (swipe or close), resolve. Note: FrameCartView does not expose ChargeIntent from nested checkout.
131
107
  let delegate = CartDismissDelegate(resolve: resolve)
@@ -145,7 +121,9 @@ private final class CheckoutDismissDelegate: NSObject, UIAdaptivePresentationCon
145
121
  }
146
122
  func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
147
123
  guard !didComplete else { return }
148
- reject("USER_CANCELED", "User dismissed checkout without completing payment", nil)
124
+ DispatchQueue.main.async { [reject] in
125
+ reject("USER_CANCELED", "User dismissed checkout without completing payment", nil)
126
+ }
149
127
  }
150
128
  }
151
129
 
@@ -153,9 +131,12 @@ private final class CartDismissDelegate: NSObject, UIAdaptivePresentationControl
153
131
  let resolve: RCTPromiseResolveBlock
154
132
  init(resolve: @escaping RCTPromiseResolveBlock) { self.resolve = resolve }
155
133
  func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
156
- resolve([String: Any]())
134
+ DispatchQueue.main.async { [resolve] in
135
+ resolve([String: Any]())
136
+ }
157
137
  }
158
138
  }
159
139
 
160
140
  private var cartDismissKey: UInt8 = 0
161
141
  private var checkoutDismissKey: UInt8 = 0
142
+
@@ -0,0 +1,12 @@
1
+ //
2
+ // FrameVCHelper.h
3
+ // FrameReactNative
4
+ //
5
+
6
+ #import <UIKit/UIKit.h>
7
+
8
+ NS_ASSUME_NONNULL_BEGIN
9
+
10
+ UIViewController * _Nullable FrameGetTopViewController(void);
11
+
12
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,11 @@
1
+ //
2
+ // FrameVCHelper.m
3
+ // FrameReactNative
4
+ //
5
+
6
+ #import "FrameVCHelper.h"
7
+ #import <React/RCTUtils.h>
8
+
9
+ UIViewController * _Nullable FrameGetTopViewController(void) {
10
+ return RCTPresentedViewController();
11
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Unit tests for the native module bridge (initialize, presentCheckout, presentCart).
3
+ * NativeModules.FrameSDK is mocked.
4
+ */
5
+ declare const mockInitialize: jest.Mock<Promise<void>, [_apiKey: string, _debugMode: boolean], any>;
6
+ declare const mockPresentCheckout: jest.Mock<Promise<{
7
+ id: string;
8
+ amount: number;
9
+ }>, [_customerId: unknown, _amount: number], any>;
10
+ declare const mockPresentCart: jest.Mock<Promise<{
11
+ id: string;
12
+ amount: number;
13
+ }>, [_customerId: unknown, _items: unknown[], _shipping: number], any>;
14
+ declare let initialize: (opts: {
15
+ apiKey: string;
16
+ debugMode?: boolean;
17
+ }) => void;
18
+ declare let presentCheckout: (opts: {
19
+ customerId?: string | null;
20
+ amount: number;
21
+ }) => Promise<unknown>;
22
+ declare let presentCart: (opts: {
23
+ customerId?: string | null;
24
+ items: Array<{
25
+ id: string;
26
+ title: string;
27
+ amountInCents: number;
28
+ imageUrl: string;
29
+ }>;
30
+ shippingAmountInCents: number;
31
+ }) => Promise<unknown>;
32
+ //# sourceMappingURL=native.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/native.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,QAAA,MAAM,cAAc,uEAAuE,CAAC;AAC5F,QAAA,MAAM,mBAAmB;;;iDAAqG,CAAC;AAC/H,QAAA,MAAM,eAAe;;;sEAA0H,CAAC;AAahJ,QAAA,IAAI,UAAU,EAAE,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,KAAK,IAAI,CAAC;AACxE,QAAA,IAAI,eAAe,EAAE,CAAC,IAAI,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAChG,QAAA,IAAI,WAAW,EAAE,CAAC,IAAI,EAAE;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrF,qBAAqB,EAAE,MAAM,CAAC;CAC/B,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC"}
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ /**
3
+ * Unit tests for the native module bridge (initialize, presentCheckout, presentCart).
4
+ * NativeModules.FrameSDK is mocked.
5
+ */
6
+ const mockInitialize = jest.fn((_apiKey, _debugMode) => Promise.resolve());
7
+ const mockPresentCheckout = jest.fn((_customerId, _amount) => Promise.resolve({ id: 'ci_1', amount: 10000 }));
8
+ const mockPresentCart = jest.fn((_customerId, _items, _shipping) => Promise.resolve({ id: 'ci_2', amount: 15000 }));
9
+ jest.mock('react-native', () => ({
10
+ NativeModules: {
11
+ FrameSDK: {
12
+ initialize: mockInitialize,
13
+ presentCheckout: mockPresentCheckout,
14
+ presentCart: mockPresentCart,
15
+ },
16
+ },
17
+ }));
18
+ // Re-import after mock so we get the mocked NativeModules
19
+ let initialize;
20
+ let presentCheckout;
21
+ let presentCart;
22
+ beforeEach(() => {
23
+ jest.resetModules();
24
+ mockInitialize.mockClear();
25
+ mockPresentCheckout.mockClear();
26
+ mockPresentCart.mockClear();
27
+ const native = require('../native');
28
+ initialize = native.initialize;
29
+ presentCheckout = native.presentCheckout;
30
+ presentCart = native.presentCart;
31
+ });
32
+ describe('initialize', () => {
33
+ it('calls native FrameSDK.initialize with apiKey and debugMode', () => {
34
+ initialize({ apiKey: 'sk_test_xxx', debugMode: true });
35
+ expect(mockInitialize).toHaveBeenCalledTimes(1);
36
+ expect(mockInitialize).toHaveBeenCalledWith('sk_test_xxx', true);
37
+ });
38
+ it('defaults debugMode to false', () => {
39
+ initialize({ apiKey: 'sk_test_yyy' });
40
+ expect(mockInitialize).toHaveBeenCalledWith('sk_test_yyy', false);
41
+ });
42
+ it('throws if apiKey is missing', () => {
43
+ expect(() => initialize({ apiKey: '' })).toThrow();
44
+ expect(() => initialize({})).toThrow();
45
+ expect(mockInitialize).not.toHaveBeenCalled();
46
+ });
47
+ });
48
+ describe('presentCheckout', () => {
49
+ it('throws NOT_INITIALIZED if initialize was not called', async () => {
50
+ try {
51
+ await presentCheckout({ amount: 10000 });
52
+ expect(true).toBe(false);
53
+ }
54
+ catch (e) {
55
+ expect(e.code).toBe('NOT_INITIALIZED');
56
+ expect(e.message).toContain('initialized');
57
+ }
58
+ expect(mockPresentCheckout).not.toHaveBeenCalled();
59
+ });
60
+ it('calls native presentCheckout with customerId and amount after initialize', async () => {
61
+ initialize({ apiKey: 'sk_xxx' });
62
+ const result = await presentCheckout({ customerId: 'cus_1', amount: 10000 });
63
+ expect(mockPresentCheckout).toHaveBeenCalledWith('cus_1', 10000);
64
+ expect(result).toEqual({ id: 'ci_1', amount: 10000 });
65
+ });
66
+ it('passes null for customerId when not provided', async () => {
67
+ initialize({ apiKey: 'sk_xxx' });
68
+ await presentCheckout({ amount: 5000 });
69
+ expect(mockPresentCheckout).toHaveBeenCalledWith(null, 5000);
70
+ });
71
+ });
72
+ describe('presentCart', () => {
73
+ const items = [
74
+ { id: '1', title: 'Item A', amountInCents: 1000, imageUrl: 'https://example.com/a.jpg' },
75
+ ];
76
+ it('throws NOT_INITIALIZED if initialize was not called', async () => {
77
+ try {
78
+ await presentCart({ items, shippingAmountInCents: 500 });
79
+ expect(true).toBe(false);
80
+ }
81
+ catch (e) {
82
+ expect(e.code).toBe('NOT_INITIALIZED');
83
+ }
84
+ expect(mockPresentCart).not.toHaveBeenCalled();
85
+ });
86
+ it('calls native presentCart with customerId, items, shipping after initialize', async () => {
87
+ initialize({ apiKey: 'sk_xxx' });
88
+ const result = await presentCart({
89
+ customerId: 'cus_2',
90
+ items,
91
+ shippingAmountInCents: 500,
92
+ });
93
+ expect(mockPresentCart).toHaveBeenCalledWith('cus_2', items, 500);
94
+ expect(result).toEqual({ id: 'ci_2', amount: 15000 });
95
+ });
96
+ it('passes null for customerId when not provided', async () => {
97
+ initialize({ apiKey: 'sk_xxx' });
98
+ await presentCart({ items, shippingAmountInCents: 0 });
99
+ expect(mockPresentCart).toHaveBeenCalledWith(null, items, 0);
100
+ });
101
+ });
package/lib/index.d.ts CHANGED
@@ -1,12 +1,20 @@
1
1
  /**
2
- * @framepayments/react-native-frame
2
+ * framepayments-react-native
3
3
  *
4
4
  * React Native SDK for Frame Payments.
5
5
  * - Initialize the SDK, then use presentCheckout / presentCart for payment UI.
6
6
  * - For API calls (customers, charge intents, refunds), use the framepayments (frame-node) package from JS.
7
7
  */
8
+ import { initialize, presentCheckout, presentCart } from './native';
8
9
  export { initialize, presentCheckout, presentCart } from './native';
9
10
  export type { FrameCartItem, ChargeIntent, FrameError } from './types';
10
11
  export { ErrorCodes } from './errors';
11
12
  export type { FrameErrorShape, FrameErrorCode } from './errors';
13
+ /** Default export for Frame.initialize(), Frame.presentCheckout(), etc. */
14
+ declare const _default: {
15
+ initialize: typeof initialize;
16
+ presentCheckout: typeof presentCheckout;
17
+ presentCart: typeof presentCart;
18
+ };
19
+ export default _default;
12
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACpE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACpE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAEhE,2EAA2E;;;;;;AAC3E,wBAA4D"}
package/lib/index.js CHANGED
@@ -1,9 +1,12 @@
1
1
  /**
2
- * @framepayments/react-native-frame
2
+ * framepayments-react-native
3
3
  *
4
4
  * React Native SDK for Frame Payments.
5
5
  * - Initialize the SDK, then use presentCheckout / presentCart for payment UI.
6
6
  * - For API calls (customers, charge intents, refunds), use the framepayments (frame-node) package from JS.
7
7
  */
8
+ import { initialize, presentCheckout, presentCart } from './native';
8
9
  export { initialize, presentCheckout, presentCart } from './native';
9
10
  export { ErrorCodes } from './errors';
11
+ /** Default export for Frame.initialize(), Frame.presentCheckout(), etc. */
12
+ export default { initialize, presentCheckout, presentCart };
package/lib/native.d.ts CHANGED
@@ -5,7 +5,7 @@ import type { ChargeIntent, FrameCartItem } from './types';
5
5
  export declare function initialize(options: {
6
6
  apiKey: string;
7
7
  debugMode?: boolean;
8
- }): void;
8
+ }): Promise<void>;
9
9
  export declare function presentCheckout(options: {
10
10
  customerId?: string | null;
11
11
  amount: number;
@@ -1 +1 @@
1
- {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAmB3D,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAMjF;AAwBD,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,YAAY,CAAC,CAKxB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GAAG,OAAO,CAAC,YAAY,CAAC,CASxB"}
1
+ {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAmB3D,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAS1F;AAwBD,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,YAAY,CAAC,CAKxB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GAAG,OAAO,CAAC,YAAY,CAAC,CASxB"}
package/lib/native.js CHANGED
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { NativeModules } from 'react-native';
5
5
  import { ErrorCodes } from './errors';
6
- const LINKING_ERROR = `The package '@framepayments/react-native-frame' doesn't seem to be linked. Make sure you have run 'pod install' (iOS) or rebuilt the app (Android).`;
6
+ const LINKING_ERROR = `The package 'framepayments-react-native' doesn't seem to be linked. Make sure you have run 'pod install' (iOS) or rebuilt the app (Android).`;
7
7
  const FrameSDK = NativeModules.FrameSDK
8
8
  ? NativeModules.FrameSDK
9
9
  : new Proxy({}, {
@@ -16,8 +16,9 @@ export function initialize(options) {
16
16
  if (!options?.apiKey) {
17
17
  throw new Error('Frame.initialize requires apiKey');
18
18
  }
19
- FrameSDK.initialize(options.apiKey, options.debugMode ?? false);
20
- isInitialized = true;
19
+ return wrapPromise(FrameSDK.initialize(options.apiKey, options.debugMode ?? false)).then(() => {
20
+ isInitialized = true;
21
+ });
21
22
  }
22
23
  function guardInitialized() {
23
24
  if (!isInitialized) {