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