react-native-iap 9.0.0-beta → 9.0.0-beta12

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 (94) hide show
  1. package/README.md +11 -22
  2. package/RNIap.podspec +33 -18
  3. package/android/build.gradle +137 -38
  4. package/android/gradle.properties +8 -0
  5. package/android/src/play/java/com/dooboolab/RNIap/RNIapModule.kt +99 -89
  6. package/android/src/play/java/com/dooboolab/RNIap/RNIapPackage.kt +0 -1
  7. package/android/src/testPlay/java/com/dooboolab/RNIap/{RNIapModuleTestV4.kt → RNIapModuleTest.kt} +47 -35
  8. package/ios/RNIapIos-Bridging-Header.h +2 -0
  9. package/ios/RNIapIos.m +14 -1
  10. package/ios/RNIapIos.swift +903 -883
  11. package/ios/{RNIap.xcodeproj → RNIapIos.xcodeproj}/project.pbxproj +29 -116
  12. package/lib/commonjs/__test__/iap.test.js +21 -0
  13. package/lib/commonjs/__test__/iap.test.js.map +1 -0
  14. package/lib/commonjs/hooks/useIAP.js +78 -0
  15. package/lib/commonjs/hooks/useIAP.js.map +1 -0
  16. package/lib/commonjs/hooks/withIAPContext.js +92 -0
  17. package/lib/commonjs/hooks/withIAPContext.js.map +1 -0
  18. package/lib/commonjs/iap.js +586 -0
  19. package/lib/commonjs/iap.js.map +1 -0
  20. package/lib/commonjs/index.js +59 -0
  21. package/lib/commonjs/index.js.map +1 -0
  22. package/lib/commonjs/types/amazon.js +2 -0
  23. package/lib/commonjs/types/amazon.js.map +1 -0
  24. package/lib/commonjs/types/android.js +55 -0
  25. package/lib/commonjs/types/android.js.map +1 -0
  26. package/lib/commonjs/types/apple.js +165 -0
  27. package/lib/commonjs/types/apple.js.map +1 -0
  28. package/lib/commonjs/types/index.js +59 -0
  29. package/lib/commonjs/types/index.js.map +1 -0
  30. package/lib/module/__test__/iap.test.js +17 -0
  31. package/lib/module/__test__/iap.test.js.map +1 -0
  32. package/lib/module/hooks/useIAP.js +68 -0
  33. package/lib/module/hooks/useIAP.js.map +1 -0
  34. package/lib/module/hooks/withIAPContext.js +76 -0
  35. package/lib/module/hooks/withIAPContext.js.map +1 -0
  36. package/lib/module/iap.js +494 -0
  37. package/lib/module/iap.js.map +1 -0
  38. package/lib/module/index.js +6 -0
  39. package/lib/module/index.js.map +1 -0
  40. package/lib/module/types/amazon.js +2 -0
  41. package/lib/module/types/amazon.js.map +1 -0
  42. package/lib/module/types/android.js +44 -0
  43. package/lib/module/types/android.js.map +1 -0
  44. package/lib/module/types/apple.js +153 -0
  45. package/lib/module/types/apple.js.map +1 -0
  46. package/lib/module/types/index.js +48 -0
  47. package/lib/module/types/index.js.map +1 -0
  48. package/{src → lib/typescript}/__test__/iap.test.d.ts +0 -0
  49. package/{src → lib/typescript}/hooks/useIAP.d.ts +1 -1
  50. package/{src → lib/typescript}/hooks/withIAPContext.d.ts +1 -1
  51. package/{src → lib/typescript}/iap.d.ts +17 -12
  52. package/{src → lib/typescript}/index.d.ts +2 -1
  53. package/{src → lib/typescript}/types/amazon.d.ts +0 -0
  54. package/{src → lib/typescript}/types/android.d.ts +0 -0
  55. package/{src → lib/typescript}/types/apple.d.ts +0 -0
  56. package/{src → lib/typescript}/types/index.d.ts +35 -22
  57. package/package.json +87 -57
  58. package/src/__test__/iap.test.ts +20 -0
  59. package/src/hooks/useIAP.ts +130 -0
  60. package/src/hooks/withIAPContext.tsx +160 -0
  61. package/src/iap.ts +700 -0
  62. package/src/{index.js → index.ts} +4 -1
  63. package/src/types/amazon.ts +23 -0
  64. package/src/types/android.ts +51 -0
  65. package/src/types/apple.ts +467 -0
  66. package/src/types/index.ts +185 -0
  67. package/.editorconfig +0 -10
  68. package/.flowconfig +0 -11
  69. package/.monolinterrc +0 -3
  70. package/.yarn/install-state.gz +0 -0
  71. package/.yarn/releases/yarn-3.2.0.cjs +0 -785
  72. package/.yarnrc.yml +0 -3
  73. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  74. package/android/gradle/wrapper/gradle-wrapper.properties +0 -6
  75. package/android/gradlew +0 -160
  76. package/android/gradlew.bat +0 -90
  77. package/android/src/play/java/com/dooboolab/RNIap/RNIapModuleInterface.kt +0 -44
  78. package/android/src/play/java/com/dooboolab/RNIap/RNIapModuleV4.kt +0 -656
  79. package/babel.config.js +0 -10
  80. package/index.d.ts +0 -3
  81. package/index.js +0 -3
  82. package/index.js.flow +0 -9
  83. package/ios/RNIap.xcodeproj/xcshareddata/xcschemes/RNIap.xcscheme +0 -80
  84. package/ios/RNIapQueue.swift +0 -36
  85. package/jest.config.js +0 -194
  86. package/src/__test__/iap.test.js +0 -59
  87. package/src/hooks/useIAP.js +0 -141
  88. package/src/hooks/withIAPContext.js +0 -150
  89. package/src/iap.js +0 -640
  90. package/src/types/amazon.js +0 -1
  91. package/src/types/android.js +0 -22
  92. package/src/types/apple.js +0 -165
  93. package/src/types/index.js +0 -40
  94. package/test/mocks/react-native-modules.js +0 -14
@@ -0,0 +1,76 @@
1
+ import React, { useContext, useEffect, useMemo, useState } from 'react';
2
+ import { getPromotedProductIOS, initConnection, promotedProductListener, purchaseErrorListener, purchaseUpdatedListener } from '../iap';
3
+ // @ts-ignore
4
+ const IAPContext = /*#__PURE__*/React.createContext(null);
5
+ export function useIAPContext() {
6
+ const ctx = useContext(IAPContext);
7
+
8
+ if (!ctx) {
9
+ throw new Error('You need wrap your app with withIAPContext HOC');
10
+ }
11
+
12
+ return ctx;
13
+ }
14
+ export function withIAPContext(Component) {
15
+ return function WrapperComponent(props) {
16
+ const [connected, setConnected] = useState(false);
17
+ const [products, setProducts] = useState([]);
18
+ const [promotedProductsIOS, setPromotedProductsIOS] = useState([]);
19
+ const [subscriptions, setSubscriptions] = useState([]);
20
+ const [purchaseHistories, setPurchaseHistories] = useState([]);
21
+ const [availablePurchases, setAvailablePurchases] = useState([]);
22
+ const [currentPurchase, setCurrentPurchase] = useState();
23
+ const [currentPurchaseError, setCurrentPurchaseError] = useState();
24
+ const [initConnectionError, setInitConnectionError] = useState();
25
+ const context = useMemo(() => ({
26
+ connected,
27
+ products,
28
+ subscriptions,
29
+ promotedProductsIOS,
30
+ purchaseHistories,
31
+ availablePurchases,
32
+ currentPurchase,
33
+ currentPurchaseError,
34
+ initConnectionError,
35
+ setProducts,
36
+ setSubscriptions,
37
+ setPurchaseHistories,
38
+ setAvailablePurchases,
39
+ setCurrentPurchase,
40
+ setCurrentPurchaseError
41
+ }), [connected, products, subscriptions, promotedProductsIOS, purchaseHistories, availablePurchases, currentPurchase, currentPurchaseError, initConnectionError, setProducts, setSubscriptions, setPurchaseHistories, setAvailablePurchases, setCurrentPurchase, setCurrentPurchaseError]);
42
+ useEffect(() => {
43
+ initConnection().then(value => {
44
+ setInitConnectionError(undefined);
45
+ setConnected(value);
46
+ }).catch(setInitConnectionError);
47
+ }, []);
48
+ useEffect(() => {
49
+ if (!connected) {
50
+ return;
51
+ }
52
+
53
+ const purchaseUpdateSubscription = purchaseUpdatedListener(async purchase => {
54
+ setCurrentPurchaseError(undefined);
55
+ setCurrentPurchase(purchase);
56
+ });
57
+ const purchaseErrorSubscription = purchaseErrorListener(error => {
58
+ setCurrentPurchase(undefined);
59
+ setCurrentPurchaseError(error);
60
+ });
61
+ const promotedProductSubscription = promotedProductListener(async () => {
62
+ const product = await getPromotedProductIOS();
63
+ setPromotedProductsIOS(prevProducts => [...prevProducts, ...(product ? [product] : [])]);
64
+ });
65
+ return () => {
66
+ purchaseUpdateSubscription.remove();
67
+ purchaseErrorSubscription.remove();
68
+ promotedProductSubscription.remove();
69
+ };
70
+ }, [connected]);
71
+ return /*#__PURE__*/React.createElement(IAPContext.Provider, {
72
+ value: context
73
+ }, /*#__PURE__*/React.createElement(Component, props));
74
+ };
75
+ }
76
+ //# sourceMappingURL=withIAPContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["React","useContext","useEffect","useMemo","useState","getPromotedProductIOS","initConnection","promotedProductListener","purchaseErrorListener","purchaseUpdatedListener","IAPContext","createContext","useIAPContext","ctx","Error","withIAPContext","Component","WrapperComponent","props","connected","setConnected","products","setProducts","promotedProductsIOS","setPromotedProductsIOS","subscriptions","setSubscriptions","purchaseHistories","setPurchaseHistories","availablePurchases","setAvailablePurchases","currentPurchase","setCurrentPurchase","currentPurchaseError","setCurrentPurchaseError","initConnectionError","setInitConnectionError","context","then","value","undefined","catch","purchaseUpdateSubscription","purchase","purchaseErrorSubscription","error","promotedProductSubscription","product","prevProducts","remove"],"sources":["withIAPContext.tsx"],"sourcesContent":["import React, {useContext, useEffect, useMemo, useState} from 'react';\n\nimport {\n getPromotedProductIOS,\n initConnection,\n promotedProductListener,\n purchaseErrorListener,\n purchaseUpdatedListener,\n} from '../iap';\nimport type {\n InAppPurchase,\n Product,\n Purchase,\n PurchaseError,\n Subscription,\n SubscriptionPurchase,\n} from '../types';\n\ntype IAPContextType = {\n connected: boolean;\n products: Product[];\n promotedProductsIOS: Product[];\n subscriptions: Subscription[];\n purchaseHistories: Purchase[];\n availablePurchases: Purchase[];\n currentPurchase?: Purchase;\n currentPurchaseError?: PurchaseError;\n initConnectionError?: Error;\n setProducts: (products: Product[]) => void;\n setSubscriptions: (subscriptions: Subscription[]) => void;\n setPurchaseHistories: (purchaseHistories: Purchase[]) => void;\n setAvailablePurchases: (availablePurchases: Purchase[]) => void;\n setCurrentPurchase: (currentPurchase: Purchase | undefined) => void;\n setCurrentPurchaseError: (\n currentPurchaseError: PurchaseError | undefined,\n ) => void;\n};\n\n// @ts-ignore\nconst IAPContext = React.createContext<IAPContextType>(null);\n\nexport function useIAPContext(): IAPContextType {\n const ctx = useContext(IAPContext);\n\n if (!ctx) {\n throw new Error('You need wrap your app with withIAPContext HOC');\n }\n\n return ctx;\n}\n\nexport function withIAPContext<T>(Component: React.ComponentType<T>) {\n return function WrapperComponent(props: T) {\n const [connected, setConnected] = useState(false);\n const [products, setProducts] = useState<Product[]>([]);\n\n const [promotedProductsIOS, setPromotedProductsIOS] = useState<Product[]>(\n [],\n );\n const [subscriptions, setSubscriptions] = useState<Subscription[]>([]);\n const [purchaseHistories, setPurchaseHistories] = useState<Purchase[]>([]);\n\n const [availablePurchases, setAvailablePurchases] = useState<Purchase[]>(\n [],\n );\n const [currentPurchase, setCurrentPurchase] = useState<Purchase>();\n\n const [currentPurchaseError, setCurrentPurchaseError] =\n useState<PurchaseError>();\n\n const [initConnectionError, setInitConnectionError] = useState<Error>();\n\n const context = useMemo(\n () => ({\n connected,\n products,\n subscriptions,\n promotedProductsIOS,\n purchaseHistories,\n availablePurchases,\n currentPurchase,\n currentPurchaseError,\n initConnectionError,\n setProducts,\n setSubscriptions,\n setPurchaseHistories,\n setAvailablePurchases,\n setCurrentPurchase,\n setCurrentPurchaseError,\n }),\n [\n connected,\n products,\n subscriptions,\n promotedProductsIOS,\n purchaseHistories,\n availablePurchases,\n currentPurchase,\n currentPurchaseError,\n initConnectionError,\n setProducts,\n setSubscriptions,\n setPurchaseHistories,\n setAvailablePurchases,\n setCurrentPurchase,\n setCurrentPurchaseError,\n ],\n );\n\n useEffect(() => {\n initConnection()\n .then((value) => {\n setInitConnectionError(undefined);\n setConnected(value);\n })\n .catch(setInitConnectionError);\n }, []);\n\n useEffect(() => {\n if (!connected) {\n return;\n }\n\n const purchaseUpdateSubscription = purchaseUpdatedListener(\n async (purchase: InAppPurchase | SubscriptionPurchase) => {\n setCurrentPurchaseError(undefined);\n setCurrentPurchase(purchase);\n },\n );\n\n const purchaseErrorSubscription = purchaseErrorListener(\n (error: PurchaseError) => {\n setCurrentPurchase(undefined);\n setCurrentPurchaseError(error);\n },\n );\n\n const promotedProductSubscription = promotedProductListener(async () => {\n const product = await getPromotedProductIOS();\n\n setPromotedProductsIOS((prevProducts) => [\n ...prevProducts,\n ...(product ? [product] : []),\n ]);\n });\n\n return () => {\n purchaseUpdateSubscription.remove();\n purchaseErrorSubscription.remove();\n promotedProductSubscription.remove();\n };\n }, [connected]);\n\n return (\n <IAPContext.Provider value={context}>\n <Component {...props} />\n </IAPContext.Provider>\n );\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,494 @@
1
+ import { Linking, NativeEventEmitter, NativeModules, Platform } from 'react-native';
2
+ import { ReceiptValidationStatus } from './types/apple';
3
+ import { IAPErrorCode, InstallSourceAndroid, PurchaseStateAndroid } from './types';
4
+ const {
5
+ RNIapIos,
6
+ RNIapModule,
7
+ RNIapAmazonModule
8
+ } = NativeModules;
9
+ const isAndroid = Platform.OS === 'android';
10
+ const ANDROID_ITEM_TYPE_SUBSCRIPTION = 'subs';
11
+ const ANDROID_ITEM_TYPE_IAP = 'inapp';
12
+ export const getInstallSourceAndroid = () => {
13
+ return RNIapModule ? InstallSourceAndroid.GOOGLE_PLAY : InstallSourceAndroid.AMAZON;
14
+ };
15
+ let androidNativeModule = RNIapModule;
16
+ export const setAndroidNativeModule = nativeModule => {
17
+ androidNativeModule = nativeModule;
18
+ };
19
+
20
+ const checkNativeAndroidAvailable = () => {
21
+ if (!RNIapModule && !RNIapAmazonModule) {
22
+ throw new Error(IAPErrorCode.E_IAP_NOT_AVAILABLE);
23
+ }
24
+ };
25
+
26
+ const getAndroidModule = () => {
27
+ checkNativeAndroidAvailable();
28
+ return androidNativeModule ? androidNativeModule : RNIapModule ? RNIapModule : RNIapAmazonModule;
29
+ };
30
+
31
+ const checkNativeIOSAvailable = () => {
32
+ if (!RNIapIos) {
33
+ throw new Error(IAPErrorCode.E_IAP_NOT_AVAILABLE);
34
+ }
35
+ };
36
+
37
+ const getIosModule = () => {
38
+ checkNativeIOSAvailable();
39
+ return RNIapIos;
40
+ };
41
+
42
+ const getNativeModule = () => {
43
+ return isAndroid ? getAndroidModule() : getIosModule();
44
+ };
45
+ /**
46
+ * Init module for purchase flow. Required on Android. In ios it will check whether user canMakePayment.
47
+ * @returns {Promise<boolean>}
48
+ */
49
+
50
+
51
+ export const initConnection = () => getNativeModule().initConnection();
52
+ /**
53
+ * End module for purchase flow.
54
+ * @returns {Promise<void>}
55
+ */
56
+
57
+ export const endConnection = () => getNativeModule().endConnection();
58
+ /**
59
+ * Consume all 'ghost' purchases (that is, pending payment that already failed but is still marked as pending in Play Store cache). Android only.
60
+ * @returns {Promise<boolean>}
61
+ */
62
+
63
+ export const flushFailedPurchasesCachedAsPendingAndroid = () => getAndroidModule().flushFailedPurchasesCachedAsPending();
64
+ /**
65
+ * Fill products with additional data
66
+ * @param {Array<ProductCommon>} products Products
67
+ */
68
+
69
+ const fillProductsAdditionalData = async products => {
70
+ // Amazon
71
+ if (RNIapAmazonModule) {
72
+ // On amazon we must get the user marketplace to detect the currency
73
+ const user = await RNIapAmazonModule.getUser();
74
+ const currencies = {
75
+ CA: 'CAD',
76
+ ES: 'EUR',
77
+ AU: 'AUD',
78
+ DE: 'EUR',
79
+ IN: 'INR',
80
+ US: 'USD',
81
+ JP: 'JPY',
82
+ GB: 'GBP',
83
+ IT: 'EUR',
84
+ BR: 'BRL',
85
+ FR: 'EUR'
86
+ };
87
+ const currency = currencies[user.userMarketplaceAmazon]; // Add currency to products
88
+
89
+ products.forEach(product => {
90
+ if (currency) {
91
+ product.currency = currency;
92
+ }
93
+ });
94
+ }
95
+
96
+ return products;
97
+ };
98
+ /**
99
+ * Get a list of products (consumable and non-consumable items, but not subscriptions)
100
+ * @param {string[]} skus The item skus
101
+ * @returns {Promise<Product[]>}
102
+ */
103
+
104
+
105
+ export const getProducts = skus => (Platform.select({
106
+ ios: async () => {
107
+ const items = await getIosModule().getItems(skus);
108
+ return items.filter(item => skus.includes(item.productId) && item.type === 'iap');
109
+ },
110
+ android: async () => {
111
+ const products = await getAndroidModule().getItemsByType(ANDROID_ITEM_TYPE_IAP, skus);
112
+ return fillProductsAdditionalData(products);
113
+ }
114
+ }) || Promise.resolve)();
115
+ /**
116
+ * Get a list of subscriptions
117
+ * @param {string[]} skus The item skus
118
+ * @returns {Promise<Subscription[]>}
119
+ */
120
+
121
+ export const getSubscriptions = skus => (Platform.select({
122
+ ios: async () => {
123
+ const items = await getIosModule().getItems(skus);
124
+ return items.filter(item => skus.includes(item.productId) && item.type === 'subs');
125
+ },
126
+ android: async () => {
127
+ const subscriptions = await getAndroidModule().getItemsByType(ANDROID_ITEM_TYPE_SUBSCRIPTION, skus);
128
+ return fillProductsAdditionalData(subscriptions);
129
+ }
130
+ }) || Promise.resolve)();
131
+ /**
132
+ * Gets an inventory of purchases made by the user regardless of consumption status
133
+ * @returns {Promise<(InAppPurchase | SubscriptionPurchase)[]>}
134
+ */
135
+
136
+ export const getPurchaseHistory = () => (Platform.select({
137
+ ios: async () => {
138
+ return getIosModule().getAvailableItems();
139
+ },
140
+ android: async () => {
141
+ if (RNIapAmazonModule) {
142
+ return await RNIapAmazonModule.getAvailableItems();
143
+ }
144
+
145
+ const products = await getAndroidModule().getPurchaseHistoryByType(ANDROID_ITEM_TYPE_IAP);
146
+ const subscriptions = await getAndroidModule().getPurchaseHistoryByType(ANDROID_ITEM_TYPE_SUBSCRIPTION);
147
+ return products.concat(subscriptions);
148
+ }
149
+ }) || Promise.resolve)();
150
+ /**
151
+ * Get all purchases made by the user (either non-consumable, or haven't been consumed yet)
152
+ * @returns {Promise<(InAppPurchase | SubscriptionPurchase)[]>}
153
+ */
154
+
155
+ export const getAvailablePurchases = () => (Platform.select({
156
+ ios: async () => {
157
+ return getIosModule().getAvailableItems();
158
+ },
159
+ android: async () => {
160
+ if (RNIapAmazonModule) {
161
+ return await RNIapAmazonModule.getAvailableItems();
162
+ }
163
+
164
+ const products = await getAndroidModule().getAvailableItemsByType(ANDROID_ITEM_TYPE_IAP);
165
+ const subscriptions = await getAndroidModule().getAvailableItemsByType(ANDROID_ITEM_TYPE_SUBSCRIPTION);
166
+ return products.concat(subscriptions);
167
+ }
168
+ }) || Promise.resolve)();
169
+ /**
170
+ * Request a purchase for product. This will be received in `PurchaseUpdatedListener`.
171
+ * @param {string} sku The product's sku/ID
172
+ * @param {string} [applicationUsername] The purchaser's user ID
173
+ * @param {boolean} [andDangerouslyFinishTransactionAutomaticallyIOS] You should set this to false and call finishTransaction manually when you have delivered the purchased goods to the user. It defaults to true to provide backwards compatibility. Will default to false in version 4.0.0.
174
+ * @param {string} [obfuscatedAccountIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
175
+ * @param {string} [obfuscatedProfileIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
176
+ * @returns {Promise<InAppPurchase>}
177
+ */
178
+
179
+ export const requestPurchase = _ref => {
180
+ let {
181
+ sku,
182
+ andDangerouslyFinishTransactionAutomaticallyIOS = false,
183
+ obfuscatedAccountIdAndroid,
184
+ obfuscatedProfileIdAndroid,
185
+ applicationUsername
186
+ } = _ref;
187
+ return (Platform.select({
188
+ ios: async () => {
189
+ if (andDangerouslyFinishTransactionAutomaticallyIOS) {
190
+ console.warn('You are dangerously allowing react-native-iap to finish your transaction automatically. You should set andDangerouslyFinishTransactionAutomatically to false when calling requestPurchase and call finishTransaction manually when you have delivered the purchased goods to the user. It defaults to true to provide backwards compatibility. Will default to false in version 4.0.0.');
191
+ }
192
+
193
+ return getIosModule().buyProduct(sku, andDangerouslyFinishTransactionAutomaticallyIOS, applicationUsername);
194
+ },
195
+ android: async () => {
196
+ return getAndroidModule().buyItemByType(ANDROID_ITEM_TYPE_IAP, [sku], null, -1, obfuscatedAccountIdAndroid, obfuscatedProfileIdAndroid, undefined);
197
+ }
198
+ }) || Promise.resolve)();
199
+ };
200
+ /**
201
+ * Request a purchase for product. This will be received in `PurchaseUpdatedListener`.
202
+ * @param {string} [sku] The product's sku/ID
203
+ * @param {string} [applicationUsername] The purchaser's user ID
204
+ * @param {boolean} [andDangerouslyFinishTransactionAutomaticallyIOS] You should set this to false and call finishTransaction manually when you have delivered the purchased goods to the user. It defaults to true to provide backwards compatibility. Will default to false in version 4.0.0.
205
+ * @param {string} [purchaseTokenAndroid] purchaseToken that the user is upgrading or downgrading from (Android).
206
+ * @param {ProrationModesAndroid} [prorationModeAndroid] UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY, IMMEDIATE_WITH_TIME_PRORATION, IMMEDIATE_AND_CHARGE_PRORATED_PRICE, IMMEDIATE_WITHOUT_PRORATION, DEFERRED
207
+ * @param {string} [obfuscatedAccountIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
208
+ * @param {string} [obfuscatedProfileIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
209
+ * @param {string[]} [selectedOfferIndices] Array of Selected Offer indices from the list returned by get products
210
+ * @param {string[]} [skus] Skus to purchase, if more than one, otherwise it'll default to sku
211
+ * @returns {Promise<SubscriptionPurchase | null>} Promise resolves to null when using proratioModesAndroid=DEFERRED, and to a SubscriptionPurchase otherwise
212
+ */
213
+
214
+ export const requestSubscription = _ref2 => {
215
+ let {
216
+ sku,
217
+ andDangerouslyFinishTransactionAutomaticallyIOS = false,
218
+ purchaseTokenAndroid,
219
+ prorationModeAndroid = -1,
220
+ obfuscatedAccountIdAndroid,
221
+ obfuscatedProfileIdAndroid,
222
+ selectedOfferIndices = undefined,
223
+ // Android Billing V5
224
+ skus = undefined,
225
+ // Android Billing V5
226
+ applicationUsername
227
+ } = _ref2;
228
+ return (Platform.select({
229
+ ios: async () => {
230
+ if (andDangerouslyFinishTransactionAutomaticallyIOS) {
231
+ console.warn('You are dangerously allowing react-native-iap to finish your transaction automatically. You should set andDangerouslyFinishTransactionAutomatically to false when calling requestPurchase and call finishTransaction manually when you have delivered the purchased goods to the user. It defaults to true to provide backwards compatibility. Will default to false in version 4.0.0.');
232
+ }
233
+
234
+ return getIosModule().buyProduct(sku, andDangerouslyFinishTransactionAutomaticallyIOS, applicationUsername);
235
+ },
236
+ android: async () => {
237
+ return getAndroidModule().buyItemByType(ANDROID_ITEM_TYPE_SUBSCRIPTION, skus ? skus : [sku], purchaseTokenAndroid, prorationModeAndroid, obfuscatedAccountIdAndroid, obfuscatedProfileIdAndroid, selectedOfferIndices);
238
+ }
239
+ }) || Promise.resolve)();
240
+ };
241
+ /**
242
+ * Request a purchase for product. This will be received in `PurchaseUpdatedListener`.
243
+ * @param {string} sku The product's sku/ID
244
+ * @returns {Promise<void>}
245
+ */
246
+
247
+ export const requestPurchaseWithQuantityIOS = (sku, quantity) => getIosModule().buyProductWithQuantityIOS(sku, quantity);
248
+ /**
249
+ * Finish Transaction (both platforms)
250
+ * Abstracts Finish Transaction
251
+ * iOS: Tells StoreKit that you have delivered the purchase to the user and StoreKit can now let go of the transaction.
252
+ * Call this after you have persisted the purchased state to your server or local data in your app.
253
+ * `react-native-iap` will continue to deliver the purchase updated events with the successful purchase until you finish the transaction. **Even after the app has relaunched.**
254
+ * Android: it will consume purchase for consumables and acknowledge purchase for non-consumables.
255
+ * @param {object} purchase The purchase that you would like to finish.
256
+ * @param {boolean} isConsumable Checks if purchase is consumable. Has effect on `android`.
257
+ * @param {string} developerPayloadAndroid Android developerPayload.
258
+ * @returns {Promise<string | void> }
259
+ */
260
+
261
+ export const finishTransaction = (purchase, isConsumable, developerPayloadAndroid) => {
262
+ return (Platform.select({
263
+ ios: async () => {
264
+ return getIosModule().finishTransaction(purchase.transactionId);
265
+ },
266
+ android: async () => {
267
+ if (purchase) {
268
+ if (isConsumable) {
269
+ return getAndroidModule().consumeProduct(purchase.purchaseToken, developerPayloadAndroid);
270
+ } else if (purchase.userIdAmazon || !purchase.isAcknowledgedAndroid && purchase.purchaseStateAndroid === PurchaseStateAndroid.PURCHASED) {
271
+ return getAndroidModule().acknowledgePurchase(purchase.purchaseToken, developerPayloadAndroid);
272
+ } else {
273
+ throw new Error('purchase is not suitable to be purchased');
274
+ }
275
+ } else {
276
+ throw new Error('purchase is not assigned');
277
+ }
278
+ }
279
+ }) || Promise.resolve)();
280
+ };
281
+ /**
282
+ * Clear Transaction (iOS only)
283
+ * Finish remaining transactions. Related to issue #257 and #801
284
+ * link : https://github.com/dooboolab/react-native-iap/issues/257
285
+ * https://github.com/dooboolab/react-native-iap/issues/801
286
+ * @returns {Promise<void>}
287
+ */
288
+
289
+ export const clearTransactionIOS = () => getIosModule().clearTransaction();
290
+ /**
291
+ * Clear valid Products (iOS only)
292
+ * Remove all products which are validated by Apple server.
293
+ * @returns {void}
294
+ */
295
+
296
+ export const clearProductsIOS = () => getIosModule().clearProducts();
297
+ /**
298
+ * Acknowledge a product (on Android.) No-op on iOS.
299
+ * @param {string} token The product's token (on Android)
300
+ * @returns {Promise<PurchaseResult | void>}
301
+ */
302
+
303
+ export const acknowledgePurchaseAndroid = (token, developerPayload) => {
304
+ return getAndroidModule().acknowledgePurchase(token, developerPayload);
305
+ };
306
+ /**
307
+ * Deep link to subscriptions screen on Android. No-op on iOS.
308
+ * @param {string} sku The product's SKU (on Android)
309
+ * @returns {Promise<void>}
310
+ */
311
+
312
+ export const deepLinkToSubscriptionsAndroid = async sku => {
313
+ checkNativeAndroidAvailable();
314
+ return Linking.openURL(`https://play.google.com/store/account/subscriptions?package=${await RNIapModule.getPackageName()}&sku=${sku}`);
315
+ };
316
+ /**
317
+ * Should Add Store Payment (iOS only)
318
+ * Indicates the the App Store purchase should continue from the app instead of the App Store.
319
+ * @returns {Promise<Product | null>} promoted product
320
+ */
321
+
322
+ export const getPromotedProductIOS = () => getIosModule().promotedProduct();
323
+ /**
324
+ * Buy the currently selected promoted product (iOS only)
325
+ * Initiates the payment process for a promoted product. Should only be called in response to the `iap-promoted-product` event.
326
+ * @returns {Promise<void>}
327
+ */
328
+
329
+ export const buyPromotedProductIOS = () => getIosModule().buyPromotedProduct();
330
+
331
+ const fetchJsonOrThrow = async (url, receiptBody) => {
332
+ const response = await fetch(url, {
333
+ method: 'POST',
334
+ headers: {
335
+ Accept: 'application/json',
336
+ 'Content-Type': 'application/json'
337
+ },
338
+ body: JSON.stringify(receiptBody)
339
+ });
340
+
341
+ if (!response.ok) {
342
+ throw Object.assign(new Error(response.statusText), {
343
+ statusCode: response.status
344
+ });
345
+ }
346
+
347
+ return response.json();
348
+ };
349
+
350
+ const requestAgnosticReceiptValidationIos = async receiptBody => {
351
+ const response = await fetchJsonOrThrow('https://buy.itunes.apple.com/verifyReceipt', receiptBody); // Best practice is to check for test receipt and check sandbox instead
352
+ // https://developer.apple.com/documentation/appstorereceipts/verifyreceipt
353
+
354
+ if (response && response.status === ReceiptValidationStatus.TEST_RECEIPT) {
355
+ const testResponse = await fetchJsonOrThrow('https://sandbox.itunes.apple.com/verifyReceipt', receiptBody);
356
+ return testResponse;
357
+ }
358
+
359
+ return response;
360
+ };
361
+ /**
362
+ * Buy products or subscriptions with offers (iOS only)
363
+ *
364
+ * Runs the payment process with some info you must fetch
365
+ * from your server.
366
+ * @param {string} sku The product identifier
367
+ * @param {string} forUser An user identifier on you system
368
+ * @param {Apple.PaymentDiscount} withOffer The offer information
369
+ * @param {string} withOffer.identifier The offer identifier
370
+ * @param {string} withOffer.keyIdentifier Key identifier that it uses to generate the signature
371
+ * @param {string} withOffer.nonce An UUID returned from the server
372
+ * @param {string} withOffer.signature The actual signature returned from the server
373
+ * @param {number} withOffer.timestamp The timestamp of the signature
374
+ * @returns {Promise<void>}
375
+ */
376
+
377
+
378
+ export const requestPurchaseWithOfferIOS = (sku, forUser, withOffer) => getIosModule().buyProductWithOffer(sku, forUser, withOffer);
379
+ /**
380
+ * Validate receipt for iOS.
381
+ * @param {object} receiptBody the receipt body to send to apple server.
382
+ * @param {boolean} isTest whether this is in test environment which is sandbox.
383
+ * @returns {Promise<Apple.ReceiptValidationResponse | false>}
384
+ */
385
+
386
+ export const validateReceiptIos = async (receiptBody, isTest) => {
387
+ if (isTest == null) {
388
+ return await requestAgnosticReceiptValidationIos(receiptBody);
389
+ }
390
+
391
+ const url = isTest ? 'https://sandbox.itunes.apple.com/verifyReceipt' : 'https://buy.itunes.apple.com/verifyReceipt';
392
+ const response = await fetchJsonOrThrow(url, receiptBody);
393
+ return response;
394
+ };
395
+ /**
396
+ * Validate receipt for Android. NOTE: This method is here for debugging purposes only. Including
397
+ * your access token in the binary you ship to users is potentially dangerous.
398
+ * Use server side validation instead for your production builds
399
+ * @param {string} packageName package name of your app.
400
+ * @param {string} productId product id for your in app product.
401
+ * @param {string} productToken token for your purchase.
402
+ * @param {string} accessToken accessToken from googleApis.
403
+ * @param {boolean} isSub whether this is subscription or inapp. `true` for subscription.
404
+ * @returns {Promise<object>}
405
+ */
406
+
407
+ export const validateReceiptAndroid = async (packageName, productId, productToken, accessToken, isSub) => {
408
+ const type = isSub ? 'subscriptions' : 'products';
409
+ const url = 'https://androidpublisher.googleapis.com/androidpublisher/v3/applications' + `/${packageName}/purchases/${type}/${productId}` + `/tokens/${productToken}?access_token=${accessToken}`;
410
+ const response = await fetch(url, {
411
+ method: 'GET',
412
+ headers: {
413
+ 'Content-Type': 'application/json'
414
+ }
415
+ });
416
+
417
+ if (!response.ok) {
418
+ throw Object.assign(new Error(response.statusText), {
419
+ statusCode: response.status
420
+ });
421
+ }
422
+
423
+ return response.json();
424
+ };
425
+ /**
426
+ * Validate receipt for Amazon. NOTE: This method is here for debugging purposes only. Including
427
+ * your developer secret in the binary you ship to users is potentially dangerous.
428
+ * Use server side validation instead for your production builds
429
+ * @param {string} developerSecret: from the Amazon developer console.
430
+ * @param {string} userId who purchased the item.
431
+ * @param {string} receiptId long obfuscated string returned when purchasing the item
432
+ * @param {boolean} useSandbox Defaults to true, use sandbox environment or production.
433
+ * @returns {Promise<object>}
434
+ */
435
+
436
+ export const validateReceiptAmazon = async function (developerSecret, userId, receiptId) {
437
+ let useSandbox = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
438
+ const sandBoxUrl = useSandbox ? 'sandbox/' : '';
439
+ const url = `https://appstore-sdk.amazon.com/${sandBoxUrl}version/1.0/verifyReceiptId/developer/${developerSecret}/user/${userId}/receiptId/${receiptId}`;
440
+ const response = await fetch(url, {
441
+ method: 'GET',
442
+ headers: {
443
+ 'Content-Type': 'application/json'
444
+ }
445
+ });
446
+
447
+ if (!response.ok) {
448
+ throw Object.assign(new Error(response.statusText), {
449
+ statusCode: response.status
450
+ });
451
+ }
452
+
453
+ return response.json();
454
+ };
455
+ /**
456
+ * Add IAP purchase event
457
+ * @returns {callback(e: InAppPurchase | ProductPurchase)}
458
+ */
459
+
460
+ export const purchaseUpdatedListener = listener => {
461
+ const emitterSubscription = new NativeEventEmitter(getNativeModule()).addListener('purchase-updated', listener);
462
+
463
+ if (isAndroid) {
464
+ getAndroidModule().startListening();
465
+ }
466
+
467
+ return emitterSubscription;
468
+ };
469
+ /**
470
+ * Add IAP purchase error event
471
+ * @returns {callback(e: PurchaseError)}
472
+ */
473
+
474
+ export const purchaseErrorListener = listener => new NativeEventEmitter(getNativeModule()).addListener('purchase-error', listener);
475
+ /**
476
+ * Add IAP promoted subscription event
477
+ * Only available on iOS
478
+ */
479
+
480
+ export const promotedProductListener = listener => new NativeEventEmitter(getIosModule()).addListener('iap-promoted-product', listener);
481
+ /**
482
+ * Get the current receipt base64 encoded in IOS.
483
+ * @param {forceRefresh?:boolean}
484
+ * @returns {Promise<ProductPurchase[]>}
485
+ */
486
+
487
+ export const getPendingPurchasesIOS = async () => getIosModule().getPendingTransactions();
488
+ /**
489
+ * Launches a modal to register the redeem offer code in IOS.
490
+ * @returns {Promise<null>}
491
+ */
492
+
493
+ export const presentCodeRedemptionSheetIOS = async () => getIosModule().presentCodeRedemptionSheet();
494
+ //# sourceMappingURL=iap.js.map