react-native-iap 13.0.4 → 14.0.0-rc.2
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.
- package/NitroIap.podspec +33 -0
- package/README.md +163 -51
- package/android/CMakeLists.txt +32 -0
- package/android/build.gradle +107 -138
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -13
- package/android/src/main/AndroidManifest.xml +1 -4
- package/android/src/main/cpp/cpp-adapter.cpp +6 -0
- package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +843 -0
- package/android/src/main/java/com/margelo/nitro/iap/NitroIapPackage.java +33 -0
- package/android/src/main/java/com/margelo/nitro/iap/Types.kt +173 -0
- package/ios/Bridge.h +8 -0
- package/ios/ErrorUtils.swift +153 -0
- package/ios/HybridRnIap.swift +1326 -0
- package/ios/ProductStore.swift +33 -0
- package/ios/reactnativeiap.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/ios/reactnativeiap.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/lib/module/helpers/subscription.js +56 -0
- package/lib/module/helpers/subscription.js.map +1 -0
- package/lib/module/hooks/useIAP.js +175 -123
- package/lib/module/hooks/useIAP.js.map +1 -1
- package/lib/module/index.js +1015 -9
- package/lib/module/index.js.map +1 -1
- package/lib/module/package.json +1 -0
- package/lib/module/specs/RnIap.nitro.js +4 -0
- package/lib/{commonjs/modules/common.js.map → module/specs/RnIap.nitro.js.map} +1 -1
- package/lib/module/types.js +187 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/utils/error.js +80 -0
- package/lib/module/utils/error.js.map +1 -0
- package/lib/module/utils/type-bridge.js +202 -0
- package/lib/module/utils/type-bridge.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/plugin/src/withIAP.d.ts +2 -7
- package/lib/typescript/plugin/src/withIAP.d.ts.map +1 -1
- package/lib/typescript/scripts/check-nitro-versions.d.ts +3 -0
- package/lib/typescript/scripts/check-nitro-versions.d.ts.map +1 -0
- package/lib/typescript/src/helpers/subscription.d.ts +14 -0
- package/lib/typescript/src/helpers/subscription.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useIAP.d.ts +42 -26
- package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +356 -8
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts +404 -0
- package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +544 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/utils/error.d.ts +30 -0
- package/lib/typescript/src/utils/error.d.ts.map +1 -0
- package/lib/typescript/src/utils/type-bridge.d.ts +40 -0
- package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -0
- package/nitro.json +17 -0
- package/nitrogen/generated/android/NitroIap+autolinking.cmake +80 -0
- package/nitrogen/generated/android/NitroIap+autolinking.gradle +27 -0
- package/nitrogen/generated/android/NitroIapOnLoad.cpp +50 -0
- package/nitrogen/generated/android/NitroIapOnLoad.hpp +25 -0
- package/nitrogen/generated/android/c++/JFunc_void_NitroProduct.hpp +78 -0
- package/nitrogen/generated/android/c++/JFunc_void_NitroPurchase.hpp +78 -0
- package/nitrogen/generated/android/c++/JFunc_void_NitroPurchaseResult.hpp +78 -0
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +577 -0
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.hpp +93 -0
- package/nitrogen/generated/android/c++/JNitroAndroidReceiptValidationOptions.hpp +66 -0
- package/nitrogen/generated/android/c++/JNitroAvailablePurchasesAndroidOptions.hpp +54 -0
- package/nitrogen/generated/android/c++/JNitroAvailablePurchasesIosOptions.hpp +65 -0
- package/nitrogen/generated/android/c++/JNitroAvailablePurchasesOptions.hpp +62 -0
- package/nitrogen/generated/android/c++/JNitroFinishTransactionAndroidParams.hpp +58 -0
- package/nitrogen/generated/android/c++/JNitroFinishTransactionIosParams.hpp +53 -0
- package/nitrogen/generated/android/c++/JNitroFinishTransactionParams.hpp +62 -0
- package/nitrogen/generated/android/c++/JNitroProduct.hpp +154 -0
- package/nitrogen/generated/android/c++/JNitroPurchase.hpp +122 -0
- package/nitrogen/generated/android/c++/JNitroPurchaseRequest.hpp +66 -0
- package/nitrogen/generated/android/c++/JNitroPurchaseResult.hpp +70 -0
- package/nitrogen/generated/android/c++/JNitroReceiptValidationParams.hpp +60 -0
- package/nitrogen/generated/android/c++/JNitroReceiptValidationResultAndroid.hpp +122 -0
- package/nitrogen/generated/android/c++/JNitroReceiptValidationResultIOS.hpp +68 -0
- package/nitrogen/generated/android/c++/JNitroRequestPurchaseAndroid.hpp +115 -0
- package/nitrogen/generated/android/c++/JNitroRequestPurchaseIos.hpp +84 -0
- package/nitrogen/generated/android/c++/JNitroSubscriptionOffer.hpp +57 -0
- package/nitrogen/generated/android/c++/JNitroSubscriptionRenewalInfo.hpp +74 -0
- package/nitrogen/generated/android/c++/JNitroSubscriptionStatus.hpp +64 -0
- package/nitrogen/generated/android/c++/JVariant_Boolean_NitroPurchaseResult.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_Boolean_NitroPurchaseResult.hpp +71 -0
- package/nitrogen/generated/android/c++/JVariant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid.hpp +75 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Func_void_NitroProduct.kt +81 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Func_void_NitroPurchase.kt +81 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Func_void_NitroPurchaseResult.kt +81 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/HybridRnIapSpec.kt +198 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroAndroidReceiptValidationOptions.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroAvailablePurchasesAndroidOptions.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroAvailablePurchasesIosOptions.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroAvailablePurchasesOptions.kt +32 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroFinishTransactionAndroidParams.kt +32 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroFinishTransactionIosParams.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroFinishTransactionParams.kt +32 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroIapOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroProduct.kt +104 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroPurchase.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroPurchaseRequest.kt +32 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroPurchaseResult.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroReceiptValidationParams.kt +32 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroReceiptValidationResultAndroid.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroReceiptValidationResultIOS.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroRequestPurchaseAndroid.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroRequestPurchaseIos.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroSubscriptionOffer.kt +32 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroSubscriptionRenewalInfo.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroSubscriptionStatus.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_Boolean_NitroPurchaseResult.kt +42 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid.kt +42 -0
- package/nitrogen/generated/ios/NitroIap+autolinking.rb +60 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.cpp +152 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +1061 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +107 -0
- package/nitrogen/generated/ios/NitroIapAutolinking.mm +33 -0
- package/nitrogen/generated/ios/NitroIapAutolinking.swift +25 -0
- package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +355 -0
- package/nitrogen/generated/ios/swift/Func_void.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_NitroProduct.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_NitroPurchase.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_NitroPurchaseResult.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_NitroProduct_.swift +54 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_NitroPurchase_.swift +54 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +54 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_std__vector_NitroSubscriptionStatus__.swift +54 -0
- package/nitrogen/generated/ios/swift/Func_void_std__string.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__variant_NitroReceiptValidationResultIOS__NitroReceiptValidationResultAndroid_.swift +59 -0
- package/nitrogen/generated/ios/swift/Func_void_std__variant_bool__NitroPurchaseResult_.swift +59 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_NitroProduct_.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_NitroPurchase_.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridRnIapSpec.swift +78 -0
- package/nitrogen/generated/ios/swift/HybridRnIapSpec_cxx.swift +750 -0
- package/nitrogen/generated/ios/swift/NitroAndroidReceiptValidationOptions.swift +80 -0
- package/nitrogen/generated/ios/swift/NitroAvailablePurchasesAndroidOptions.swift +54 -0
- package/nitrogen/generated/ios/swift/NitroAvailablePurchasesIosOptions.swift +116 -0
- package/nitrogen/generated/ios/swift/NitroAvailablePurchasesOptions.swift +84 -0
- package/nitrogen/generated/ios/swift/NitroFinishTransactionAndroidParams.swift +58 -0
- package/nitrogen/generated/ios/swift/NitroFinishTransactionIosParams.swift +35 -0
- package/nitrogen/generated/ios/swift/NitroFinishTransactionParams.swift +84 -0
- package/nitrogen/generated/ios/swift/NitroProduct.swift +653 -0
- package/nitrogen/generated/ios/swift/NitroPurchase.swift +453 -0
- package/nitrogen/generated/ios/swift/NitroPurchaseRequest.swift +84 -0
- package/nitrogen/generated/ios/swift/NitroPurchaseResult.swift +117 -0
- package/nitrogen/generated/ios/swift/NitroReceiptValidationParams.swift +65 -0
- package/nitrogen/generated/ios/swift/NitroReceiptValidationResultAndroid.swift +258 -0
- package/nitrogen/generated/ios/swift/NitroReceiptValidationResultIOS.swift +87 -0
- package/nitrogen/generated/ios/swift/NitroRequestPurchaseAndroid.swift +225 -0
- package/nitrogen/generated/ios/swift/NitroRequestPurchaseIos.swift +161 -0
- package/nitrogen/generated/ios/swift/NitroSubscriptionOffer.swift +46 -0
- package/nitrogen/generated/ios/swift/NitroSubscriptionRenewalInfo.swift +152 -0
- package/nitrogen/generated/ios/swift/NitroSubscriptionStatus.swift +76 -0
- package/nitrogen/generated/ios/swift/Variant_Bool_NitroPurchaseResult.swift +18 -0
- package/nitrogen/generated/ios/swift/Variant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid.swift +18 -0
- package/nitrogen/generated/shared/c++/HybridRnIapSpec.cpp +50 -0
- package/nitrogen/generated/shared/c++/HybridRnIapSpec.hpp +125 -0
- package/nitrogen/generated/shared/c++/NitroAndroidReceiptValidationOptions.hpp +80 -0
- package/nitrogen/generated/shared/c++/NitroAvailablePurchasesAndroidOptions.hpp +68 -0
- package/nitrogen/generated/shared/c++/NitroAvailablePurchasesIosOptions.hpp +79 -0
- package/nitrogen/generated/shared/c++/NitroAvailablePurchasesOptions.hpp +76 -0
- package/nitrogen/generated/shared/c++/NitroFinishTransactionAndroidParams.hpp +72 -0
- package/nitrogen/generated/shared/c++/NitroFinishTransactionIosParams.hpp +67 -0
- package/nitrogen/generated/shared/c++/NitroFinishTransactionParams.hpp +76 -0
- package/nitrogen/generated/shared/c++/NitroProduct.hpp +168 -0
- package/nitrogen/generated/shared/c++/NitroPurchase.hpp +136 -0
- package/nitrogen/generated/shared/c++/NitroPurchaseRequest.hpp +76 -0
- package/nitrogen/generated/shared/c++/NitroPurchaseResult.hpp +84 -0
- package/nitrogen/generated/shared/c++/NitroReceiptValidationParams.hpp +74 -0
- package/nitrogen/generated/shared/c++/NitroReceiptValidationResultAndroid.hpp +136 -0
- package/nitrogen/generated/shared/c++/NitroReceiptValidationResultIOS.hpp +82 -0
- package/nitrogen/generated/shared/c++/NitroRequestPurchaseAndroid.hpp +95 -0
- package/nitrogen/generated/shared/c++/NitroRequestPurchaseIos.hpp +85 -0
- package/nitrogen/generated/shared/c++/NitroSubscriptionOffer.hpp +71 -0
- package/nitrogen/generated/shared/c++/NitroSubscriptionRenewalInfo.hpp +88 -0
- package/nitrogen/generated/shared/c++/NitroSubscriptionStatus.hpp +78 -0
- package/package.json +144 -104
- package/plugin/build/src/withIAP.d.ts +3 -0
- package/plugin/build/src/withIAP.js +81 -0
- package/plugin/build/tsconfig.tsbuildinfo +1 -0
- package/plugin/build/withIAP.d.ts +2 -7
- package/plugin/build/withIAP.js +62 -51
- package/plugin/src/withIAP.ts +119 -0
- package/plugin/tsconfig.json +18 -0
- package/plugin/tsconfig.tsbuildinfo +1 -0
- package/src/helpers/subscription.ts +65 -0
- package/src/hooks/useIAP.ts +361 -222
- package/src/index.ts +1194 -9
- package/src/specs/RnIap.nitro.ts +501 -0
- package/src/types.ts +680 -0
- package/src/utils/error.ts +97 -0
- package/src/utils/type-bridge.ts +209 -0
- package/LICENSE +0 -21
- package/RNIap.podspec +0 -36
- package/android/src/amazon/AndroidManifest.xml +0 -14
- package/android/src/amazon/java/com/dooboolab/rniap/EventSender.kt +0 -10
- package/android/src/amazon/java/com/dooboolab/rniap/PurchasingServiceProxy.kt +0 -29
- package/android/src/amazon/java/com/dooboolab/rniap/PurchasingServiceProxyAmazonImpl.kt +0 -31
- package/android/src/amazon/java/com/dooboolab/rniap/RNIapActivityListener.kt +0 -55
- package/android/src/amazon/java/com/dooboolab/rniap/RNIapAmazonListener.kt +0 -325
- package/android/src/amazon/java/com/dooboolab/rniap/RNIapAmazonModule.kt +0 -244
- package/android/src/amazon/java/com/dooboolab/rniap/RNIapPackage.kt +0 -17
- package/android/src/amazon/java/com/dooboolab/rniap/modifysubscription/RNIapAmazonModifySubscriptionListener.kt +0 -88
- package/android/src/amazon/java/com/dooboolab/rniap/utils/Extensions.kt +0 -22
- package/android/src/main/java/com/dooboolab/rniap/PromiseUtils.kt +0 -62
- package/android/src/main/java/com/dooboolab/rniap/PromiseUtlis.kt +0 -43
- package/android/src/play/java/com/dooboolab/rniap/PlayUtils.kt +0 -114
- package/android/src/play/java/com/dooboolab/rniap/RNIapActivityListener.kt +0 -15
- package/android/src/play/java/com/dooboolab/rniap/RNIapModule.kt +0 -911
- package/android/src/play/java/com/dooboolab/rniap/RNIapPackage.kt +0 -17
- package/android/src/testAmazon/java/com/dooboolab/rniap/RNIapAmazonModuleTest.kt +0 -170
- package/app.plugin.js +0 -1
- package/ios/IapSerializationUtils.swift +0 -290
- package/ios/IapTypes.swift +0 -56
- package/ios/IapUtils.swift +0 -40
- package/ios/LatestPromiseKeeper.swift +0 -52
- package/ios/RNIapIos-Bridging-Header.h +0 -2
- package/ios/RNIapIos.m +0 -69
- package/ios/RNIapIos.swift +0 -868
- package/ios/RNIapIos.xcodeproj/project.pbxproj +0 -289
- package/ios/RNIapIosSk2.m +0 -126
- package/ios/RNIapIosSk2.swift +0 -1413
- package/ios/ThreadSafe.swift +0 -18
- package/lib/commonjs/eventEmitter.js +0 -195
- package/lib/commonjs/eventEmitter.js.map +0 -1
- package/lib/commonjs/hooks/index.js +0 -17
- package/lib/commonjs/hooks/index.js.map +0 -1
- package/lib/commonjs/hooks/useIAP.js +0 -203
- package/lib/commonjs/hooks/useIAP.js.map +0 -1
- package/lib/commonjs/hooks/withIAPContext.js +0 -95
- package/lib/commonjs/hooks/withIAPContext.js.map +0 -1
- package/lib/commonjs/iap.js +0 -836
- package/lib/commonjs/iap.js.map +0 -1
- package/lib/commonjs/index.js +0 -105
- package/lib/commonjs/index.js.map +0 -1
- package/lib/commonjs/internal/enhancedFetch.js +0 -26
- package/lib/commonjs/internal/enhancedFetch.js.map +0 -1
- package/lib/commonjs/internal/fillProductsWithAdditionalData.js +0 -50
- package/lib/commonjs/internal/fillProductsWithAdditionalData.js.map +0 -1
- package/lib/commonjs/internal/index.js +0 -39
- package/lib/commonjs/internal/index.js.map +0 -1
- package/lib/commonjs/internal/platform.js +0 -119
- package/lib/commonjs/internal/platform.js.map +0 -1
- package/lib/commonjs/modules/amazon.js +0 -50
- package/lib/commonjs/modules/amazon.js.map +0 -1
- package/lib/commonjs/modules/android.js +0 -92
- package/lib/commonjs/modules/android.js.map +0 -1
- package/lib/commonjs/modules/common.js +0 -2
- package/lib/commonjs/modules/index.js +0 -50
- package/lib/commonjs/modules/index.js.map +0 -1
- package/lib/commonjs/modules/ios.js +0 -160
- package/lib/commonjs/modules/ios.js.map +0 -1
- package/lib/commonjs/modules/iosSk2.js +0 -113
- package/lib/commonjs/modules/iosSk2.js.map +0 -1
- package/lib/commonjs/purchaseError.js +0 -170
- package/lib/commonjs/purchaseError.js.map +0 -1
- package/lib/commonjs/types/amazon.js +0 -2
- package/lib/commonjs/types/amazon.js.map +0 -1
- package/lib/commonjs/types/android.js +0 -67
- package/lib/commonjs/types/android.js.map +0 -1
- package/lib/commonjs/types/apple.js +0 -24
- package/lib/commonjs/types/apple.js.map +0 -1
- package/lib/commonjs/types/appleSk2.js +0 -137
- package/lib/commonjs/types/appleSk2.js.map +0 -1
- package/lib/commonjs/types/index.js +0 -67
- package/lib/commonjs/types/index.js.map +0 -1
- package/lib/commonjs/utils/errorMapping.js +0 -83
- package/lib/commonjs/utils/errorMapping.js.map +0 -1
- package/lib/commonjs/utils/typeGuards.js +0 -74
- package/lib/commonjs/utils/typeGuards.js.map +0 -1
- package/lib/module/eventEmitter.js +0 -185
- package/lib/module/eventEmitter.js.map +0 -1
- package/lib/module/hooks/index.js +0 -2
- package/lib/module/hooks/index.js.map +0 -1
- package/lib/module/hooks/withIAPContext.js +0 -86
- package/lib/module/hooks/withIAPContext.js.map +0 -1
- package/lib/module/iap.js +0 -805
- package/lib/module/iap.js.map +0 -1
- package/lib/module/internal/enhancedFetch.js +0 -19
- package/lib/module/internal/enhancedFetch.js.map +0 -1
- package/lib/module/internal/fillProductsWithAdditionalData.js +0 -43
- package/lib/module/internal/fillProductsWithAdditionalData.js.map +0 -1
- package/lib/module/internal/index.js +0 -4
- package/lib/module/internal/index.js.map +0 -1
- package/lib/module/internal/platform.js +0 -102
- package/lib/module/internal/platform.js.map +0 -1
- package/lib/module/modules/amazon.js +0 -42
- package/lib/module/modules/amazon.js.map +0 -1
- package/lib/module/modules/android.js +0 -81
- package/lib/module/modules/android.js.map +0 -1
- package/lib/module/modules/common.js +0 -2
- package/lib/module/modules/common.js.map +0 -1
- package/lib/module/modules/index.js +0 -5
- package/lib/module/modules/index.js.map +0 -1
- package/lib/module/modules/ios.js +0 -145
- package/lib/module/modules/ios.js.map +0 -1
- package/lib/module/modules/iosSk2.js +0 -96
- package/lib/module/modules/iosSk2.js.map +0 -1
- package/lib/module/purchaseError.js +0 -164
- package/lib/module/purchaseError.js.map +0 -1
- package/lib/module/types/amazon.js +0 -2
- package/lib/module/types/amazon.js.map +0 -1
- package/lib/module/types/android.js +0 -63
- package/lib/module/types/android.js.map +0 -1
- package/lib/module/types/apple.js +0 -17
- package/lib/module/types/apple.js.map +0 -1
- package/lib/module/types/appleSk2.js +0 -129
- package/lib/module/types/appleSk2.js.map +0 -1
- package/lib/module/types/index.js +0 -75
- package/lib/module/types/index.js.map +0 -1
- package/lib/module/utils/errorMapping.js +0 -75
- package/lib/module/utils/errorMapping.js.map +0 -1
- package/lib/module/utils/typeGuards.js +0 -61
- package/lib/module/utils/typeGuards.js.map +0 -1
- package/lib/typescript/src/eventEmitter.d.ts +0 -151
- package/lib/typescript/src/eventEmitter.d.ts.map +0 -1
- package/lib/typescript/src/hooks/index.d.ts +0 -2
- package/lib/typescript/src/hooks/index.d.ts.map +0 -1
- package/lib/typescript/src/hooks/withIAPContext.d.ts +0 -27
- package/lib/typescript/src/hooks/withIAPContext.d.ts.map +0 -1
- package/lib/typescript/src/iap.d.ts +0 -503
- package/lib/typescript/src/iap.d.ts.map +0 -1
- package/lib/typescript/src/internal/enhancedFetch.d.ts +0 -6
- package/lib/typescript/src/internal/enhancedFetch.d.ts.map +0 -1
- package/lib/typescript/src/internal/fillProductsWithAdditionalData.d.ts +0 -7
- package/lib/typescript/src/internal/fillProductsWithAdditionalData.d.ts.map +0 -1
- package/lib/typescript/src/internal/index.d.ts +0 -4
- package/lib/typescript/src/internal/index.d.ts.map +0 -1
- package/lib/typescript/src/internal/platform.d.ts +0 -27
- package/lib/typescript/src/internal/platform.d.ts.map +0 -1
- package/lib/typescript/src/modules/amazon.d.ts +0 -55
- package/lib/typescript/src/modules/amazon.d.ts.map +0 -1
- package/lib/typescript/src/modules/android.d.ts +0 -74
- package/lib/typescript/src/modules/android.d.ts.map +0 -1
- package/lib/typescript/src/modules/common.d.ts +0 -14
- package/lib/typescript/src/modules/common.d.ts.map +0 -1
- package/lib/typescript/src/modules/index.d.ts +0 -5
- package/lib/typescript/src/modules/index.d.ts.map +0 -1
- package/lib/typescript/src/modules/ios.d.ts +0 -117
- package/lib/typescript/src/modules/ios.d.ts.map +0 -1
- package/lib/typescript/src/modules/iosSk2.d.ts +0 -140
- package/lib/typescript/src/modules/iosSk2.d.ts.map +0 -1
- package/lib/typescript/src/purchaseError.d.ts +0 -133
- package/lib/typescript/src/purchaseError.d.ts.map +0 -1
- package/lib/typescript/src/types/amazon.d.ts +0 -33
- package/lib/typescript/src/types/amazon.d.ts.map +0 -1
- package/lib/typescript/src/types/android.d.ts +0 -66
- package/lib/typescript/src/types/android.d.ts.map +0 -1
- package/lib/typescript/src/types/apple.d.ts +0 -27
- package/lib/typescript/src/types/apple.d.ts.map +0 -1
- package/lib/typescript/src/types/appleSk2.d.ts +0 -129
- package/lib/typescript/src/types/appleSk2.d.ts.map +0 -1
- package/lib/typescript/src/types/index.d.ts +0 -302
- package/lib/typescript/src/types/index.d.ts.map +0 -1
- package/lib/typescript/src/utils/errorMapping.d.ts +0 -29
- package/lib/typescript/src/utils/errorMapping.d.ts.map +0 -1
- package/lib/typescript/src/utils/typeGuards.d.ts +0 -53
- package/lib/typescript/src/utils/typeGuards.d.ts.map +0 -1
- package/src/eventEmitter.ts +0 -212
- package/src/hooks/index.ts +0 -1
- package/src/hooks/withIAPContext.tsx +0 -179
- package/src/iap.ts +0 -1046
- package/src/internal/enhancedFetch.ts +0 -25
- package/src/internal/fillProductsWithAdditionalData.ts +0 -47
- package/src/internal/index.ts +0 -3
- package/src/internal/platform.ts +0 -135
- package/src/modules/amazon.ts +0 -94
- package/src/modules/android.ts +0 -179
- package/src/modules/common.ts +0 -16
- package/src/modules/index.ts +0 -4
- package/src/modules/ios.ts +0 -229
- package/src/modules/iosSk2.ts +0 -194
- package/src/purchaseError.ts +0 -196
- package/src/types/amazon.ts +0 -40
- package/src/types/android.ts +0 -89
- package/src/types/apple.ts +0 -44
- package/src/types/appleSk2.ts +0 -275
- package/src/types/index.ts +0 -379
- package/src/utils/errorMapping.ts +0 -88
- package/src/utils/typeGuards.ts +0 -90
package/src/index.ts
CHANGED
|
@@ -1,9 +1,1194 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
// External dependencies
|
|
2
|
+
import { Platform } from 'react-native'
|
|
3
|
+
import { NitroModules } from 'react-native-nitro-modules'
|
|
4
|
+
|
|
5
|
+
// Internal modules
|
|
6
|
+
import type {
|
|
7
|
+
NitroPurchaseResult,
|
|
8
|
+
RnIap,
|
|
9
|
+
NitroReceiptValidationParams,
|
|
10
|
+
NitroReceiptValidationResultIOS,
|
|
11
|
+
NitroReceiptValidationResultAndroid,
|
|
12
|
+
} from './specs/RnIap.nitro'
|
|
13
|
+
import type {
|
|
14
|
+
Product,
|
|
15
|
+
Purchase,
|
|
16
|
+
PurchaseAndroid,
|
|
17
|
+
RequestPurchaseProps,
|
|
18
|
+
RequestSubscriptionProps,
|
|
19
|
+
RequestSubscriptionAndroidProps,
|
|
20
|
+
PurchaseOptions,
|
|
21
|
+
FinishTransactionParams,
|
|
22
|
+
ReceiptValidationResultIOS,
|
|
23
|
+
ReceiptValidationResultAndroid,
|
|
24
|
+
RequestPurchaseIosProps,
|
|
25
|
+
RequestPurchaseAndroidProps,
|
|
26
|
+
} from './types'
|
|
27
|
+
import {
|
|
28
|
+
convertNitroProductToProduct,
|
|
29
|
+
convertNitroPurchaseToPurchase,
|
|
30
|
+
validateNitroProduct,
|
|
31
|
+
validateNitroPurchase,
|
|
32
|
+
} from './utils/type-bridge'
|
|
33
|
+
import { parseErrorStringToJsonObj } from './utils/error'
|
|
34
|
+
|
|
35
|
+
// Export all types
|
|
36
|
+
export type {
|
|
37
|
+
RnIap,
|
|
38
|
+
NitroProduct,
|
|
39
|
+
NitroPurchase,
|
|
40
|
+
NitroPurchaseResult,
|
|
41
|
+
} from './specs/RnIap.nitro'
|
|
42
|
+
export * from './types'
|
|
43
|
+
export * from './utils/error'
|
|
44
|
+
|
|
45
|
+
// Types for event listeners
|
|
46
|
+
export interface EventSubscription {
|
|
47
|
+
remove(): void
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ActiveSubscription and PurchaseError types are already exported via 'export * from ./types'
|
|
51
|
+
|
|
52
|
+
// Export hooks
|
|
53
|
+
export { useIAP } from './hooks/useIAP'
|
|
54
|
+
|
|
55
|
+
// Development utilities removed - use type bridge functions directly if needed
|
|
56
|
+
|
|
57
|
+
// Create the RnIap HybridObject instance (internal use only)
|
|
58
|
+
const iap = NitroModules.createHybridObject<RnIap>('RnIap')
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Initialize connection to the store
|
|
62
|
+
*/
|
|
63
|
+
export const initConnection = async (): Promise<boolean> => {
|
|
64
|
+
try {
|
|
65
|
+
return await iap.initConnection()
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('Failed to initialize IAP connection:', error)
|
|
68
|
+
throw error
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* End connection to the store
|
|
74
|
+
*/
|
|
75
|
+
export const endConnection = async (): Promise<boolean> => {
|
|
76
|
+
try {
|
|
77
|
+
return await iap.endConnection()
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error('Failed to end IAP connection:', error)
|
|
80
|
+
throw error
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Fetch products from the store
|
|
86
|
+
* @param params - Product request configuration
|
|
87
|
+
* @param params.skus - Array of product SKUs to fetch
|
|
88
|
+
* @param params.type - Type of products: 'inapp' for regular products (default) or 'subs' for subscriptions
|
|
89
|
+
* @returns Promise<Product[]> - Array of products from the store
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* // Regular products
|
|
94
|
+
* const products = await fetchProducts({
|
|
95
|
+
* skus: ['product1', 'product2'],
|
|
96
|
+
* type: 'inapp'
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* // Subscriptions
|
|
100
|
+
* const subscriptions = await fetchProducts({
|
|
101
|
+
* skus: ['sub1', 'sub2'],
|
|
102
|
+
* type: 'subs'
|
|
103
|
+
* });
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export const fetchProducts = async ({
|
|
107
|
+
skus,
|
|
108
|
+
type = 'inapp',
|
|
109
|
+
}: {
|
|
110
|
+
skus: string[]
|
|
111
|
+
type?: 'inapp' | 'subs'
|
|
112
|
+
}): Promise<Product[]> => {
|
|
113
|
+
try {
|
|
114
|
+
if (!skus || skus.length === 0) {
|
|
115
|
+
throw new Error('No SKUs provided')
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const nitroProducts = await iap.fetchProducts(skus, type)
|
|
119
|
+
|
|
120
|
+
// Validate and convert NitroProducts to TypeScript Products
|
|
121
|
+
const validProducts = nitroProducts.filter(validateNitroProduct)
|
|
122
|
+
if (validProducts.length !== nitroProducts.length) {
|
|
123
|
+
console.warn(
|
|
124
|
+
`[fetchProducts] Some products failed validation: ${nitroProducts.length - validProducts.length} invalid`
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const typedProducts = validProducts.map(convertNitroProductToProduct)
|
|
129
|
+
return typedProducts
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error('[fetchProducts] Failed:', error)
|
|
132
|
+
throw error
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Request a purchase for products or subscriptions
|
|
138
|
+
* @param params - Purchase request configuration
|
|
139
|
+
* @param params.request - Platform-specific purchase parameters
|
|
140
|
+
* @param params.type - Type of purchase: 'inapp' for products (default) or 'subs' for subscriptions
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* // Product purchase
|
|
145
|
+
* await requestPurchase({
|
|
146
|
+
* request: {
|
|
147
|
+
* ios: { sku: productId },
|
|
148
|
+
* android: { skus: [productId] }
|
|
149
|
+
* },
|
|
150
|
+
* type: 'inapp'
|
|
151
|
+
* });
|
|
152
|
+
*
|
|
153
|
+
* // Subscription purchase
|
|
154
|
+
* await requestPurchase({
|
|
155
|
+
* request: {
|
|
156
|
+
* ios: { sku: subscriptionId },
|
|
157
|
+
* android: {
|
|
158
|
+
* skus: [subscriptionId],
|
|
159
|
+
* subscriptionOffers: [{ sku: subscriptionId, offerToken: 'token' }]
|
|
160
|
+
* }
|
|
161
|
+
* },
|
|
162
|
+
* type: 'subs'
|
|
163
|
+
* });
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
/**
|
|
167
|
+
* Request a purchase for products or subscriptions
|
|
168
|
+
* ⚠️ Important: This is an event-based operation, not promise-based.
|
|
169
|
+
* Listen for events through purchaseUpdatedListener or purchaseErrorListener.
|
|
170
|
+
* @param params - Purchase request configuration
|
|
171
|
+
* @param params.request - Platform-specific purchase parameters
|
|
172
|
+
* @param params.type - Type of purchase: 'inapp' for products (default) or 'subs' for subscriptions
|
|
173
|
+
*/
|
|
174
|
+
export const requestPurchase = async ({
|
|
175
|
+
request,
|
|
176
|
+
type = 'inapp',
|
|
177
|
+
}: {
|
|
178
|
+
request: RequestPurchaseProps | RequestSubscriptionProps
|
|
179
|
+
type?: 'inapp' | 'subs'
|
|
180
|
+
}): Promise<void> => {
|
|
181
|
+
try {
|
|
182
|
+
// Validate platform-specific requests
|
|
183
|
+
if (Platform.OS === 'ios') {
|
|
184
|
+
const iosRequest = request.ios
|
|
185
|
+
if (!iosRequest?.sku) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
'Invalid request for iOS. The `sku` property is required.'
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
} else if (Platform.OS === 'android') {
|
|
191
|
+
const androidRequest = request.android
|
|
192
|
+
if (!androidRequest?.skus?.length) {
|
|
193
|
+
throw new Error(
|
|
194
|
+
'Invalid request for Android. The `skus` property is required and must be a non-empty array.'
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
throw new Error('Unsupported platform')
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Transform the request for the unified interface
|
|
202
|
+
const unifiedRequest: any = {}
|
|
203
|
+
|
|
204
|
+
if (Platform.OS === 'ios' && request.ios) {
|
|
205
|
+
unifiedRequest.ios = {
|
|
206
|
+
...request.ios,
|
|
207
|
+
} as RequestPurchaseIosProps
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (Platform.OS === 'android' && request.android) {
|
|
211
|
+
if (type === 'subs') {
|
|
212
|
+
const subsRequest = request.android as RequestSubscriptionAndroidProps
|
|
213
|
+
unifiedRequest.android = {
|
|
214
|
+
...subsRequest,
|
|
215
|
+
subscriptionOffers: subsRequest.subscriptionOffers || [],
|
|
216
|
+
} as RequestPurchaseAndroidProps
|
|
217
|
+
} else {
|
|
218
|
+
unifiedRequest.android = request.android
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Call unified method - returns void, listen for events instead
|
|
223
|
+
await iap.requestPurchase(unifiedRequest)
|
|
224
|
+
} catch (error) {
|
|
225
|
+
console.error('Failed to request purchase:', error)
|
|
226
|
+
throw error
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Get available purchases (purchased items not yet consumed/finished)
|
|
232
|
+
* @param params - Options for getting available purchases
|
|
233
|
+
* @param params.alsoPublishToEventListenerIOS - Whether to also publish to event listener (iOS only)
|
|
234
|
+
* @param params.onlyIncludeActiveItemsIOS - Whether to only include active items (iOS only)
|
|
235
|
+
* @param params.alsoPublishToEventListener - @deprecated Use alsoPublishToEventListenerIOS instead
|
|
236
|
+
* @param params.onlyIncludeActiveItems - @deprecated Use onlyIncludeActiveItemsIOS instead
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```typescript
|
|
240
|
+
* const purchases = await getAvailablePurchases({
|
|
241
|
+
* onlyIncludeActiveItemsIOS: true
|
|
242
|
+
* });
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
export const getAvailablePurchases = async ({
|
|
246
|
+
alsoPublishToEventListener = false,
|
|
247
|
+
onlyIncludeActiveItems = true,
|
|
248
|
+
alsoPublishToEventListenerIOS,
|
|
249
|
+
onlyIncludeActiveItemsIOS,
|
|
250
|
+
}: PurchaseOptions = {}): Promise<Purchase[]> => {
|
|
251
|
+
try {
|
|
252
|
+
// Create unified options
|
|
253
|
+
const options: any = {}
|
|
254
|
+
|
|
255
|
+
if (Platform.OS === 'ios') {
|
|
256
|
+
// Use new IOS suffixed parameters if provided, fallback to deprecated ones
|
|
257
|
+
options.ios = {
|
|
258
|
+
alsoPublishToEventListenerIOS:
|
|
259
|
+
alsoPublishToEventListenerIOS ?? alsoPublishToEventListener,
|
|
260
|
+
onlyIncludeActiveItemsIOS:
|
|
261
|
+
onlyIncludeActiveItemsIOS ?? onlyIncludeActiveItems,
|
|
262
|
+
// Keep deprecated parameters for backward compatibility
|
|
263
|
+
alsoPublishToEventListener:
|
|
264
|
+
alsoPublishToEventListenerIOS ?? alsoPublishToEventListener,
|
|
265
|
+
onlyIncludeActiveItems:
|
|
266
|
+
onlyIncludeActiveItemsIOS ?? onlyIncludeActiveItems,
|
|
267
|
+
}
|
|
268
|
+
} else if (Platform.OS === 'android') {
|
|
269
|
+
// For Android, we need to call twice for inapp and subs
|
|
270
|
+
const inappNitroPurchases = await iap.getAvailablePurchases({
|
|
271
|
+
android: { type: 'inapp' },
|
|
272
|
+
})
|
|
273
|
+
const subsNitroPurchases = await iap.getAvailablePurchases({
|
|
274
|
+
android: { type: 'subs' },
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
// Validate and convert both sets of purchases
|
|
278
|
+
const allNitroPurchases = [...inappNitroPurchases, ...subsNitroPurchases]
|
|
279
|
+
const validPurchases = allNitroPurchases.filter(validateNitroPurchase)
|
|
280
|
+
if (validPurchases.length !== allNitroPurchases.length) {
|
|
281
|
+
console.warn(
|
|
282
|
+
`[getAvailablePurchases] Some Android purchases failed validation: ${allNitroPurchases.length - validPurchases.length} invalid`
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return validPurchases.map(convertNitroPurchaseToPurchase)
|
|
287
|
+
} else {
|
|
288
|
+
throw new Error('Unsupported platform')
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const nitroPurchases = await iap.getAvailablePurchases(options)
|
|
292
|
+
|
|
293
|
+
// Validate and convert NitroPurchases to TypeScript Purchases
|
|
294
|
+
const validPurchases = nitroPurchases.filter(validateNitroPurchase)
|
|
295
|
+
if (validPurchases.length !== nitroPurchases.length) {
|
|
296
|
+
console.warn(
|
|
297
|
+
`[getAvailablePurchases] Some purchases failed validation: ${nitroPurchases.length - validPurchases.length} invalid`
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return validPurchases.map(convertNitroPurchaseToPurchase)
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.error('Failed to get available purchases:', error)
|
|
304
|
+
throw error
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Finish a transaction (consume or acknowledge)
|
|
310
|
+
* @param params - Transaction finish parameters
|
|
311
|
+
* @param params.purchase - The purchase to finish
|
|
312
|
+
* @param params.isConsumable - Whether this is a consumable product (Android only)
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```typescript
|
|
316
|
+
* await finishTransaction({
|
|
317
|
+
* purchase: myPurchase,
|
|
318
|
+
* isConsumable: true
|
|
319
|
+
* });
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
export const finishTransaction = async ({
|
|
323
|
+
purchase,
|
|
324
|
+
isConsumable = false,
|
|
325
|
+
}: FinishTransactionParams): Promise<NitroPurchaseResult | boolean> => {
|
|
326
|
+
try {
|
|
327
|
+
// Create unified params
|
|
328
|
+
const params: any = {}
|
|
329
|
+
|
|
330
|
+
if (Platform.OS === 'ios') {
|
|
331
|
+
if (!purchase.id) {
|
|
332
|
+
throw new Error('purchase.id required to finish iOS transaction')
|
|
333
|
+
}
|
|
334
|
+
params.ios = {
|
|
335
|
+
transactionId: purchase.id,
|
|
336
|
+
}
|
|
337
|
+
} else if (Platform.OS === 'android') {
|
|
338
|
+
const androidPurchase = purchase as PurchaseAndroid
|
|
339
|
+
const token =
|
|
340
|
+
androidPurchase.purchaseToken || androidPurchase.purchaseTokenAndroid
|
|
341
|
+
|
|
342
|
+
if (!token) {
|
|
343
|
+
throw new Error('purchaseToken required to finish Android transaction')
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
params.android = {
|
|
347
|
+
purchaseToken: token,
|
|
348
|
+
isConsumable,
|
|
349
|
+
}
|
|
350
|
+
} else {
|
|
351
|
+
throw new Error('Unsupported platform')
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const result = await iap.finishTransaction(params)
|
|
355
|
+
|
|
356
|
+
// Handle variant return type
|
|
357
|
+
if (typeof result === 'boolean') {
|
|
358
|
+
return result
|
|
359
|
+
}
|
|
360
|
+
// It's a PurchaseResult
|
|
361
|
+
return result as NitroPurchaseResult
|
|
362
|
+
} catch (error) {
|
|
363
|
+
console.error('Failed to finish transaction:', error)
|
|
364
|
+
throw error
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Acknowledge a purchase (Android only)
|
|
370
|
+
* @param purchaseToken - The purchase token to acknowledge
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```typescript
|
|
374
|
+
* await acknowledgePurchaseAndroid('purchase_token_here');
|
|
375
|
+
* ```
|
|
376
|
+
*/
|
|
377
|
+
export const acknowledgePurchaseAndroid = async (
|
|
378
|
+
purchaseToken: string
|
|
379
|
+
): Promise<NitroPurchaseResult> => {
|
|
380
|
+
try {
|
|
381
|
+
if (Platform.OS !== 'android') {
|
|
382
|
+
throw new Error('acknowledgePurchaseAndroid is only available on Android')
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const result = await iap.finishTransaction({
|
|
386
|
+
android: {
|
|
387
|
+
purchaseToken,
|
|
388
|
+
isConsumable: false,
|
|
389
|
+
},
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
// Result is a variant, extract PurchaseResult
|
|
393
|
+
if (typeof result === 'boolean') {
|
|
394
|
+
// This shouldn't happen for Android, but handle it
|
|
395
|
+
return {
|
|
396
|
+
responseCode: 0,
|
|
397
|
+
code: '0',
|
|
398
|
+
message: 'Success',
|
|
399
|
+
purchaseToken,
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return result as NitroPurchaseResult
|
|
403
|
+
} catch (error) {
|
|
404
|
+
console.error('Failed to acknowledge purchase Android:', error)
|
|
405
|
+
throw error
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Consume a purchase (Android only)
|
|
411
|
+
* @param purchaseToken - The purchase token to consume
|
|
412
|
+
*
|
|
413
|
+
* @example
|
|
414
|
+
* ```typescript
|
|
415
|
+
* await consumePurchaseAndroid('purchase_token_here');
|
|
416
|
+
* ```
|
|
417
|
+
*/
|
|
418
|
+
export const consumePurchaseAndroid = async (
|
|
419
|
+
purchaseToken: string
|
|
420
|
+
): Promise<NitroPurchaseResult> => {
|
|
421
|
+
try {
|
|
422
|
+
if (Platform.OS !== 'android') {
|
|
423
|
+
throw new Error('consumePurchaseAndroid is only available on Android')
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const result = await iap.finishTransaction({
|
|
427
|
+
android: {
|
|
428
|
+
purchaseToken,
|
|
429
|
+
isConsumable: true,
|
|
430
|
+
},
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
// Result is a variant, extract PurchaseResult
|
|
434
|
+
if (typeof result === 'boolean') {
|
|
435
|
+
// This shouldn't happen for Android, but handle it
|
|
436
|
+
return {
|
|
437
|
+
responseCode: 0,
|
|
438
|
+
code: '0',
|
|
439
|
+
message: 'Success',
|
|
440
|
+
purchaseToken,
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return result as NitroPurchaseResult
|
|
444
|
+
} catch (error) {
|
|
445
|
+
console.error('Failed to consume purchase Android:', error)
|
|
446
|
+
throw error
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// ============================================================================
|
|
451
|
+
// EVENT LISTENERS
|
|
452
|
+
// ============================================================================
|
|
453
|
+
|
|
454
|
+
// Store wrapped listeners for proper removal
|
|
455
|
+
const listenerMap = new WeakMap<Function, Function>()
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Purchase updated event listener
|
|
459
|
+
* Fired when a purchase is successful or when a pending purchase is completed.
|
|
460
|
+
*
|
|
461
|
+
* @param listener - Function to call when a purchase is updated
|
|
462
|
+
* @returns EventSubscription object with remove method
|
|
463
|
+
*
|
|
464
|
+
* @example
|
|
465
|
+
* ```typescript
|
|
466
|
+
* const subscription = purchaseUpdatedListener((purchase) => {
|
|
467
|
+
* console.log('Purchase successful:', purchase);
|
|
468
|
+
* // 1. Validate receipt with backend
|
|
469
|
+
* // 2. Deliver content to user
|
|
470
|
+
* // 3. Call finishTransaction to acknowledge
|
|
471
|
+
* });
|
|
472
|
+
*
|
|
473
|
+
* // Later, clean up
|
|
474
|
+
* subscription.remove();
|
|
475
|
+
* ```
|
|
476
|
+
*/
|
|
477
|
+
export const purchaseUpdatedListener = (
|
|
478
|
+
listener: (purchase: Purchase) => void
|
|
479
|
+
): EventSubscription => {
|
|
480
|
+
// Wrap the listener to convert NitroPurchase to Purchase
|
|
481
|
+
const wrappedListener = (nitroPurchase: any) => {
|
|
482
|
+
if (validateNitroPurchase(nitroPurchase)) {
|
|
483
|
+
const convertedPurchase = convertNitroPurchaseToPurchase(nitroPurchase)
|
|
484
|
+
listener(convertedPurchase)
|
|
485
|
+
} else {
|
|
486
|
+
console.error(
|
|
487
|
+
'Invalid purchase data received from native:',
|
|
488
|
+
nitroPurchase
|
|
489
|
+
)
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Store the wrapped listener for removal
|
|
494
|
+
listenerMap.set(listener, wrappedListener)
|
|
495
|
+
iap.addPurchaseUpdatedListener(wrappedListener)
|
|
496
|
+
|
|
497
|
+
return {
|
|
498
|
+
remove: () => {
|
|
499
|
+
const wrapped = listenerMap.get(listener)
|
|
500
|
+
if (wrapped) {
|
|
501
|
+
iap.removePurchaseUpdatedListener(wrapped as any)
|
|
502
|
+
listenerMap.delete(listener)
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Purchase error event listener
|
|
510
|
+
* Fired when a purchase fails or is cancelled by the user.
|
|
511
|
+
*
|
|
512
|
+
* @param listener - Function to call when a purchase error occurs
|
|
513
|
+
* @returns EventSubscription object with remove method
|
|
514
|
+
*
|
|
515
|
+
* @example
|
|
516
|
+
* ```typescript
|
|
517
|
+
* const subscription = purchaseErrorListener((error) => {
|
|
518
|
+
* switch (error.code) {
|
|
519
|
+
* case 'E_USER_CANCELLED':
|
|
520
|
+
* // User cancelled - no action needed
|
|
521
|
+
* break;
|
|
522
|
+
* case 'E_ITEM_UNAVAILABLE':
|
|
523
|
+
* // Product not available
|
|
524
|
+
* break;
|
|
525
|
+
* case 'E_NETWORK_ERROR':
|
|
526
|
+
* // Retry with backoff
|
|
527
|
+
* break;
|
|
528
|
+
* }
|
|
529
|
+
* });
|
|
530
|
+
*
|
|
531
|
+
* // Later, clean up
|
|
532
|
+
* subscription.remove();
|
|
533
|
+
* ```
|
|
534
|
+
*/
|
|
535
|
+
export const purchaseErrorListener = (
|
|
536
|
+
listener: (error: NitroPurchaseResult) => void
|
|
537
|
+
): EventSubscription => {
|
|
538
|
+
// Store the listener for removal
|
|
539
|
+
listenerMap.set(listener, listener)
|
|
540
|
+
iap.addPurchaseErrorListener(listener as any)
|
|
541
|
+
|
|
542
|
+
return {
|
|
543
|
+
remove: () => {
|
|
544
|
+
iap.removePurchaseErrorListener(listener as any)
|
|
545
|
+
listenerMap.delete(listener)
|
|
546
|
+
},
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* iOS-only listener for App Store promoted product events.
|
|
552
|
+
* Fired when a user clicks on a promoted in-app purchase in the App Store.
|
|
553
|
+
*
|
|
554
|
+
* @param listener - Callback function that receives the promoted product
|
|
555
|
+
* @returns EventSubscription object with remove method
|
|
556
|
+
*
|
|
557
|
+
* @example
|
|
558
|
+
* ```typescript
|
|
559
|
+
* const subscription = promotedProductListenerIOS((product) => {
|
|
560
|
+
* console.log('Promoted product:', product);
|
|
561
|
+
* // Trigger purchase flow for the promoted product
|
|
562
|
+
* });
|
|
563
|
+
*
|
|
564
|
+
* // Later, clean up
|
|
565
|
+
* subscription.remove();
|
|
566
|
+
* ```
|
|
567
|
+
*
|
|
568
|
+
* @platform iOS
|
|
569
|
+
*/
|
|
570
|
+
export const promotedProductListenerIOS = (
|
|
571
|
+
listener: (product: Product) => void
|
|
572
|
+
): EventSubscription => {
|
|
573
|
+
if (Platform.OS !== 'ios') {
|
|
574
|
+
console.warn(
|
|
575
|
+
'promotedProductListenerIOS: This listener is only available on iOS'
|
|
576
|
+
)
|
|
577
|
+
return { remove: () => {} }
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Wrap the listener to convert NitroProduct to Product
|
|
581
|
+
const wrappedListener = (nitroProduct: any) => {
|
|
582
|
+
if (validateNitroProduct(nitroProduct)) {
|
|
583
|
+
const convertedProduct = convertNitroProductToProduct(nitroProduct)
|
|
584
|
+
listener(convertedProduct)
|
|
585
|
+
} else {
|
|
586
|
+
console.error(
|
|
587
|
+
'Invalid promoted product data received from native:',
|
|
588
|
+
nitroProduct
|
|
589
|
+
)
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Store the wrapped listener for removal
|
|
594
|
+
listenerMap.set(listener, wrappedListener)
|
|
595
|
+
iap.addPromotedProductListenerIOS(wrappedListener)
|
|
596
|
+
|
|
597
|
+
return {
|
|
598
|
+
remove: () => {
|
|
599
|
+
const wrapped = listenerMap.get(listener)
|
|
600
|
+
if (wrapped) {
|
|
601
|
+
iap.removePromotedProductListenerIOS(wrapped as any)
|
|
602
|
+
listenerMap.delete(listener)
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// ============================================================================
|
|
609
|
+
// iOS-SPECIFIC FUNCTIONS
|
|
610
|
+
// ============================================================================
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Validate receipt on both iOS and Android platforms
|
|
614
|
+
* @param sku - Product SKU
|
|
615
|
+
* @param androidOptions - Android-specific validation options (required for Android)
|
|
616
|
+
* @returns Promise<ReceiptValidationResultIOS | ReceiptValidationResultAndroid> - Platform-specific receipt validation result
|
|
617
|
+
*/
|
|
618
|
+
export const validateReceipt = async (
|
|
619
|
+
sku: string,
|
|
620
|
+
androidOptions?: {
|
|
621
|
+
packageName: string
|
|
622
|
+
productToken: string
|
|
623
|
+
accessToken: string
|
|
624
|
+
isSub?: boolean
|
|
625
|
+
}
|
|
626
|
+
): Promise<ReceiptValidationResultIOS | ReceiptValidationResultAndroid> => {
|
|
627
|
+
if (!iap) {
|
|
628
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
629
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
630
|
+
)
|
|
631
|
+
throw new Error(errorJson.message)
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
try {
|
|
635
|
+
const params: NitroReceiptValidationParams = {
|
|
636
|
+
sku,
|
|
637
|
+
androidOptions,
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
const nitroResult = await iap.validateReceipt(params)
|
|
641
|
+
|
|
642
|
+
// Convert Nitro result to public API result
|
|
643
|
+
if (Platform.OS === 'ios') {
|
|
644
|
+
const iosResult = nitroResult as NitroReceiptValidationResultIOS
|
|
645
|
+
const result: ReceiptValidationResultIOS = {
|
|
646
|
+
isValid: iosResult.isValid,
|
|
647
|
+
receiptData: iosResult.receiptData,
|
|
648
|
+
jwsRepresentation: iosResult.jwsRepresentation,
|
|
649
|
+
latestTransaction: iosResult.latestTransaction
|
|
650
|
+
? convertNitroPurchaseToPurchase(iosResult.latestTransaction)
|
|
651
|
+
: undefined,
|
|
652
|
+
}
|
|
653
|
+
return result
|
|
654
|
+
} else {
|
|
655
|
+
// Android
|
|
656
|
+
const androidResult = nitroResult as NitroReceiptValidationResultAndroid
|
|
657
|
+
const result: ReceiptValidationResultAndroid = {
|
|
658
|
+
autoRenewing: androidResult.autoRenewing,
|
|
659
|
+
betaProduct: androidResult.betaProduct,
|
|
660
|
+
cancelDate: androidResult.cancelDate,
|
|
661
|
+
cancelReason: androidResult.cancelReason,
|
|
662
|
+
deferredDate: androidResult.deferredDate,
|
|
663
|
+
deferredSku: androidResult.deferredSku,
|
|
664
|
+
freeTrialEndDate: androidResult.freeTrialEndDate,
|
|
665
|
+
gracePeriodEndDate: androidResult.gracePeriodEndDate,
|
|
666
|
+
parentProductId: androidResult.parentProductId,
|
|
667
|
+
productId: androidResult.productId,
|
|
668
|
+
productType: androidResult.productType,
|
|
669
|
+
purchaseDate: androidResult.purchaseDate,
|
|
670
|
+
quantity: androidResult.quantity,
|
|
671
|
+
receiptId: androidResult.receiptId,
|
|
672
|
+
renewalDate: androidResult.renewalDate,
|
|
673
|
+
term: androidResult.term,
|
|
674
|
+
termSku: androidResult.termSku,
|
|
675
|
+
testTransaction: androidResult.testTransaction,
|
|
676
|
+
}
|
|
677
|
+
return result
|
|
678
|
+
}
|
|
679
|
+
} catch (error) {
|
|
680
|
+
console.error('[validateReceipt] Failed:', error)
|
|
681
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
682
|
+
throw new Error(errorJson.message)
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Sync iOS purchases with App Store (iOS only)
|
|
688
|
+
* @returns Promise<boolean>
|
|
689
|
+
* @platform iOS
|
|
690
|
+
*/
|
|
691
|
+
export const syncIOS = async (): Promise<boolean> => {
|
|
692
|
+
if (Platform.OS !== 'ios') {
|
|
693
|
+
throw new Error('syncIOS is only available on iOS')
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (!iap) {
|
|
697
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
698
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
699
|
+
)
|
|
700
|
+
throw new Error(errorJson.message)
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
try {
|
|
704
|
+
return await iap.syncIOS()
|
|
705
|
+
} catch (error) {
|
|
706
|
+
console.error('[syncIOS] Failed:', error)
|
|
707
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
708
|
+
throw new Error(errorJson.message)
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Request the promoted product from the App Store (iOS only)
|
|
714
|
+
* @returns Promise<Product | null> - The promoted product or null if none available
|
|
715
|
+
* @platform iOS
|
|
716
|
+
*/
|
|
717
|
+
export const requestPromotedProductIOS = async (): Promise<Product | null> => {
|
|
718
|
+
if (Platform.OS !== 'ios') {
|
|
719
|
+
return null
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
if (!iap) {
|
|
723
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
724
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
725
|
+
)
|
|
726
|
+
throw new Error(errorJson.message)
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
try {
|
|
730
|
+
const nitroProduct = await iap.requestPromotedProductIOS()
|
|
731
|
+
if (nitroProduct) {
|
|
732
|
+
return convertNitroProductToProduct(nitroProduct)
|
|
733
|
+
}
|
|
734
|
+
return null
|
|
735
|
+
} catch (error) {
|
|
736
|
+
console.error('[getPromotedProductIOS] Failed:', error)
|
|
737
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
738
|
+
throw new Error(errorJson.message)
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Present the code redemption sheet for offer codes (iOS only)
|
|
744
|
+
* @returns Promise<boolean> - True if the sheet was presented successfully
|
|
745
|
+
* @platform iOS
|
|
746
|
+
*/
|
|
747
|
+
export const presentCodeRedemptionSheetIOS = async (): Promise<boolean> => {
|
|
748
|
+
if (Platform.OS !== 'ios') {
|
|
749
|
+
return false
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
if (!iap) {
|
|
753
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
754
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
755
|
+
)
|
|
756
|
+
throw new Error(errorJson.message)
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
try {
|
|
760
|
+
return await iap.presentCodeRedemptionSheetIOS()
|
|
761
|
+
} catch (error) {
|
|
762
|
+
console.error('[presentCodeRedemptionSheetIOS] Failed:', error)
|
|
763
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
764
|
+
throw new Error(errorJson.message)
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Buy promoted product on iOS
|
|
770
|
+
* @returns Promise<void>
|
|
771
|
+
* @platform iOS
|
|
772
|
+
*/
|
|
773
|
+
export const buyPromotedProductIOS = async (): Promise<void> => {
|
|
774
|
+
if (Platform.OS !== 'ios') {
|
|
775
|
+
throw new Error('buyPromotedProductIOS is only available on iOS')
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
if (!iap) {
|
|
779
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
780
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
781
|
+
)
|
|
782
|
+
throw new Error(errorJson.message)
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
try {
|
|
786
|
+
await iap.buyPromotedProductIOS()
|
|
787
|
+
} catch (error) {
|
|
788
|
+
console.error('[buyPromotedProductIOS] Failed:', error)
|
|
789
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
790
|
+
throw new Error(errorJson.message)
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* Clear unfinished transactions on iOS
|
|
796
|
+
* @returns Promise<void>
|
|
797
|
+
* @platform iOS
|
|
798
|
+
*/
|
|
799
|
+
export const clearTransactionIOS = async (): Promise<void> => {
|
|
800
|
+
if (Platform.OS !== 'ios') {
|
|
801
|
+
return
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
if (!iap) {
|
|
805
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
806
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
807
|
+
)
|
|
808
|
+
throw new Error(errorJson.message)
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
try {
|
|
812
|
+
await iap.clearTransactionIOS()
|
|
813
|
+
} catch (error) {
|
|
814
|
+
console.error('[clearTransactionIOS] Failed:', error)
|
|
815
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
816
|
+
throw new Error(errorJson.message)
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Begin a refund request for a product on iOS 15+
|
|
822
|
+
* @param sku - The product SKU to refund
|
|
823
|
+
* @returns Promise<string | null> - The refund status or null if not available
|
|
824
|
+
* @platform iOS
|
|
825
|
+
*/
|
|
826
|
+
export const beginRefundRequestIOS = async (
|
|
827
|
+
sku: string
|
|
828
|
+
): Promise<string | null> => {
|
|
829
|
+
if (Platform.OS !== 'ios') {
|
|
830
|
+
return null
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
if (!iap) {
|
|
834
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
835
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
836
|
+
)
|
|
837
|
+
throw new Error(errorJson.message)
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
try {
|
|
841
|
+
return await iap.beginRefundRequestIOS(sku)
|
|
842
|
+
} catch (error) {
|
|
843
|
+
console.error('[beginRefundRequestIOS] Failed:', error)
|
|
844
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
845
|
+
throw new Error(errorJson.message)
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Get subscription status for a product (iOS only)
|
|
851
|
+
* @param sku - The product SKU
|
|
852
|
+
* @returns Promise<any[]> - Array of subscription status objects
|
|
853
|
+
* @platform iOS
|
|
854
|
+
*/
|
|
855
|
+
export const subscriptionStatusIOS = async (sku: string): Promise<any[]> => {
|
|
856
|
+
if (Platform.OS !== 'ios') {
|
|
857
|
+
throw new Error('subscriptionStatusIOS is only available on iOS')
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if (!iap) {
|
|
861
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
862
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
863
|
+
)
|
|
864
|
+
throw new Error(errorJson.message)
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
try {
|
|
868
|
+
const statuses = await iap.subscriptionStatusIOS(sku)
|
|
869
|
+
return statuses || []
|
|
870
|
+
} catch (error) {
|
|
871
|
+
console.error('[subscriptionStatusIOS] Failed:', error)
|
|
872
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
873
|
+
throw new Error(errorJson.message)
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* Get current entitlement for a product (iOS only)
|
|
879
|
+
* @param sku - The product SKU
|
|
880
|
+
* @returns Promise<Purchase | null> - Current entitlement or null
|
|
881
|
+
* @platform iOS
|
|
882
|
+
*/
|
|
883
|
+
export const currentEntitlementIOS = async (
|
|
884
|
+
sku: string
|
|
885
|
+
): Promise<Purchase | null> => {
|
|
886
|
+
if (Platform.OS !== 'ios') {
|
|
887
|
+
return null
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
if (!iap) {
|
|
891
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
892
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
893
|
+
)
|
|
894
|
+
throw new Error(errorJson.message)
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
try {
|
|
898
|
+
const nitroPurchase = await iap.currentEntitlementIOS(sku)
|
|
899
|
+
if (nitroPurchase) {
|
|
900
|
+
return convertNitroPurchaseToPurchase(nitroPurchase)
|
|
901
|
+
}
|
|
902
|
+
return null
|
|
903
|
+
} catch (error) {
|
|
904
|
+
console.error('[currentEntitlementIOS] Failed:', error)
|
|
905
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
906
|
+
throw new Error(errorJson.message)
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/**
|
|
911
|
+
* Get latest transaction for a product (iOS only)
|
|
912
|
+
* @param sku - The product SKU
|
|
913
|
+
* @returns Promise<Purchase | null> - Latest transaction or null
|
|
914
|
+
* @platform iOS
|
|
915
|
+
*/
|
|
916
|
+
export const latestTransactionIOS = async (
|
|
917
|
+
sku: string
|
|
918
|
+
): Promise<Purchase | null> => {
|
|
919
|
+
if (Platform.OS !== 'ios') {
|
|
920
|
+
return null
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
if (!iap) {
|
|
924
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
925
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
926
|
+
)
|
|
927
|
+
throw new Error(errorJson.message)
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
try {
|
|
931
|
+
const nitroPurchase = await iap.latestTransactionIOS(sku)
|
|
932
|
+
if (nitroPurchase) {
|
|
933
|
+
return convertNitroPurchaseToPurchase(nitroPurchase)
|
|
934
|
+
}
|
|
935
|
+
return null
|
|
936
|
+
} catch (error) {
|
|
937
|
+
console.error('[latestTransactionIOS] Failed:', error)
|
|
938
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
939
|
+
throw new Error(errorJson.message)
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Get pending transactions (iOS only)
|
|
945
|
+
* @returns Promise<Purchase[]> - Array of pending transactions
|
|
946
|
+
* @platform iOS
|
|
947
|
+
*/
|
|
948
|
+
export const getPendingTransactionsIOS = async (): Promise<Purchase[]> => {
|
|
949
|
+
if (Platform.OS !== 'ios') {
|
|
950
|
+
return []
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
if (!iap) {
|
|
954
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
955
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
956
|
+
)
|
|
957
|
+
throw new Error(errorJson.message)
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
try {
|
|
961
|
+
const nitroPurchases = await iap.getPendingTransactionsIOS()
|
|
962
|
+
return nitroPurchases.map(convertNitroPurchaseToPurchase)
|
|
963
|
+
} catch (error) {
|
|
964
|
+
console.error('[getPendingTransactionsIOS] Failed:', error)
|
|
965
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
966
|
+
throw new Error(errorJson.message)
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* Show manage subscriptions screen (iOS only)
|
|
972
|
+
* @returns Promise<boolean> - Success flag
|
|
973
|
+
* @platform iOS
|
|
974
|
+
*/
|
|
975
|
+
export const showManageSubscriptionsIOS = async (): Promise<boolean> => {
|
|
976
|
+
if (Platform.OS !== 'ios') {
|
|
977
|
+
return false
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
if (!iap) {
|
|
981
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
982
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
983
|
+
)
|
|
984
|
+
throw new Error(errorJson.message)
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
try {
|
|
988
|
+
return await iap.showManageSubscriptionsIOS()
|
|
989
|
+
} catch (error) {
|
|
990
|
+
console.error('[showManageSubscriptionsIOS] Failed:', error)
|
|
991
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
992
|
+
throw new Error(errorJson.message)
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/**
|
|
997
|
+
* Check if user is eligible for intro offer (iOS only)
|
|
998
|
+
* @param groupID - The subscription group ID
|
|
999
|
+
* @returns Promise<boolean> - Eligibility status
|
|
1000
|
+
* @platform iOS
|
|
1001
|
+
*/
|
|
1002
|
+
export const isEligibleForIntroOfferIOS = async (
|
|
1003
|
+
groupID: string
|
|
1004
|
+
): Promise<boolean> => {
|
|
1005
|
+
if (Platform.OS !== 'ios') {
|
|
1006
|
+
return false
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
if (!iap) {
|
|
1010
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
1011
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
1012
|
+
)
|
|
1013
|
+
throw new Error(errorJson.message)
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
try {
|
|
1017
|
+
return await iap.isEligibleForIntroOfferIOS(groupID)
|
|
1018
|
+
} catch (error) {
|
|
1019
|
+
console.error('[isEligibleForIntroOfferIOS] Failed:', error)
|
|
1020
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
1021
|
+
throw new Error(errorJson.message)
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Get receipt data (iOS only)
|
|
1027
|
+
* @returns Promise<string> - Base64 encoded receipt data
|
|
1028
|
+
* @platform iOS
|
|
1029
|
+
*/
|
|
1030
|
+
export const getReceiptDataIOS = async (): Promise<string> => {
|
|
1031
|
+
if (Platform.OS !== 'ios') {
|
|
1032
|
+
throw new Error('getReceiptDataIOS is only available on iOS')
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
if (!iap) {
|
|
1036
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
1037
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
1038
|
+
)
|
|
1039
|
+
throw new Error(errorJson.message)
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
try {
|
|
1043
|
+
return await iap.getReceiptDataIOS()
|
|
1044
|
+
} catch (error) {
|
|
1045
|
+
console.error('[getReceiptDataIOS] Failed:', error)
|
|
1046
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
1047
|
+
throw new Error(errorJson.message)
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
/**
|
|
1052
|
+
* Check if transaction is verified (iOS only)
|
|
1053
|
+
* @param sku - The product SKU
|
|
1054
|
+
* @returns Promise<boolean> - Verification status
|
|
1055
|
+
* @platform iOS
|
|
1056
|
+
*/
|
|
1057
|
+
export const isTransactionVerifiedIOS = async (
|
|
1058
|
+
sku: string
|
|
1059
|
+
): Promise<boolean> => {
|
|
1060
|
+
if (Platform.OS !== 'ios') {
|
|
1061
|
+
return false
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
if (!iap) {
|
|
1065
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
1066
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
1067
|
+
)
|
|
1068
|
+
throw new Error(errorJson.message)
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
try {
|
|
1072
|
+
return await iap.isTransactionVerifiedIOS(sku)
|
|
1073
|
+
} catch (error) {
|
|
1074
|
+
console.error('[isTransactionVerifiedIOS] Failed:', error)
|
|
1075
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
1076
|
+
throw new Error(errorJson.message)
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
/**
|
|
1081
|
+
* Get transaction JWS representation (iOS only)
|
|
1082
|
+
* @param sku - The product SKU
|
|
1083
|
+
* @returns Promise<string | null> - JWS representation or null
|
|
1084
|
+
* @platform iOS
|
|
1085
|
+
*/
|
|
1086
|
+
export const getTransactionJwsIOS = async (
|
|
1087
|
+
sku: string
|
|
1088
|
+
): Promise<string | null> => {
|
|
1089
|
+
if (Platform.OS !== 'ios') {
|
|
1090
|
+
return null
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
if (!iap) {
|
|
1094
|
+
const errorJson = parseErrorStringToJsonObj(
|
|
1095
|
+
'RnIap: Service not initialized. Call initConnection() first.'
|
|
1096
|
+
)
|
|
1097
|
+
throw new Error(errorJson.message)
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
try {
|
|
1101
|
+
return await iap.getTransactionJwsIOS(sku)
|
|
1102
|
+
} catch (error) {
|
|
1103
|
+
console.error('[getTransactionJwsIOS] Failed:', error)
|
|
1104
|
+
const errorJson = parseErrorStringToJsonObj(error)
|
|
1105
|
+
throw new Error(errorJson.message)
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* Get the storefront identifier for the user's App Store account (iOS only)
|
|
1111
|
+
* @returns Promise<string> - The storefront identifier (e.g., 'USA' for United States)
|
|
1112
|
+
* @platform iOS
|
|
1113
|
+
*
|
|
1114
|
+
* @example
|
|
1115
|
+
* ```typescript
|
|
1116
|
+
* const storefront = await getStorefrontIOS();
|
|
1117
|
+
* console.log('User storefront:', storefront); // e.g., 'USA', 'GBR', 'KOR'
|
|
1118
|
+
* ```
|
|
1119
|
+
*/
|
|
1120
|
+
export const getStorefrontIOS = async (): Promise<string> => {
|
|
1121
|
+
if (Platform.OS !== 'ios') {
|
|
1122
|
+
throw new Error('getStorefrontIOS is only available on iOS')
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
try {
|
|
1126
|
+
// Call the native method to get storefront
|
|
1127
|
+
const storefront = await iap.getStorefrontIOS()
|
|
1128
|
+
return storefront
|
|
1129
|
+
} catch (error) {
|
|
1130
|
+
console.error('Failed to get storefront:', error)
|
|
1131
|
+
throw error
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/**
|
|
1136
|
+
* iOS only - Gets the original app transaction ID if the app was purchased from the App Store
|
|
1137
|
+
* @platform iOS
|
|
1138
|
+
* @description
|
|
1139
|
+
* This function retrieves the original app transaction information if the app was purchased
|
|
1140
|
+
* from the App Store. Returns null if the app was not purchased (e.g., free app or TestFlight).
|
|
1141
|
+
*
|
|
1142
|
+
* @returns {Promise<string | null>} The original app transaction ID or null
|
|
1143
|
+
*
|
|
1144
|
+
* @example
|
|
1145
|
+
* ```typescript
|
|
1146
|
+
* const appTransaction = await getAppTransactionIOS();
|
|
1147
|
+
* if (appTransaction) {
|
|
1148
|
+
* console.log('App was purchased, transaction ID:', appTransaction);
|
|
1149
|
+
* } else {
|
|
1150
|
+
* console.log('App was not purchased from App Store');
|
|
1151
|
+
* }
|
|
1152
|
+
* ```
|
|
1153
|
+
*/
|
|
1154
|
+
export const getAppTransactionIOS = async (): Promise<string | null> => {
|
|
1155
|
+
if (Platform.OS !== 'ios') {
|
|
1156
|
+
throw new Error('getAppTransactionIOS is only available on iOS')
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
try {
|
|
1160
|
+
// Call the native method to get app transaction
|
|
1161
|
+
const appTransaction = await iap.getAppTransactionIOS()
|
|
1162
|
+
return appTransaction
|
|
1163
|
+
} catch (error) {
|
|
1164
|
+
console.error('Failed to get app transaction:', error)
|
|
1165
|
+
throw error
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// Export subscription helpers
|
|
1170
|
+
export {
|
|
1171
|
+
getActiveSubscriptions,
|
|
1172
|
+
hasActiveSubscriptions,
|
|
1173
|
+
} from './helpers/subscription'
|
|
1174
|
+
|
|
1175
|
+
// Type conversion utilities
|
|
1176
|
+
export {
|
|
1177
|
+
convertNitroProductToProduct,
|
|
1178
|
+
convertNitroPurchaseToPurchase,
|
|
1179
|
+
convertProductToSubscriptionProduct,
|
|
1180
|
+
validateNitroProduct,
|
|
1181
|
+
validateNitroPurchase,
|
|
1182
|
+
checkTypeSynchronization,
|
|
1183
|
+
} from './utils/type-bridge'
|
|
1184
|
+
|
|
1185
|
+
// Deprecated exports for backward compatibility
|
|
1186
|
+
/**
|
|
1187
|
+
* @deprecated Use acknowledgePurchaseAndroid instead
|
|
1188
|
+
*/
|
|
1189
|
+
export const acknowledgePurchase = acknowledgePurchaseAndroid
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* @deprecated Use consumePurchaseAndroid instead
|
|
1193
|
+
*/
|
|
1194
|
+
export const consumePurchase = consumePurchaseAndroid
|