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