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.
Files changed (46) hide show
  1. package/NitroIap.podspec +2 -0
  2. package/README.md +9 -9
  3. package/android/build.gradle +2 -1
  4. package/android/consumer-rules.pro +7 -0
  5. package/app.plugin.js +1 -1
  6. package/ios/HybridRnIap.swift +380 -1192
  7. package/lib/module/helpers/subscription.js.map +1 -1
  8. package/lib/module/hooks/useIAP.js +74 -58
  9. package/lib/module/hooks/useIAP.js.map +1 -1
  10. package/lib/module/index.js +20 -3
  11. package/lib/module/index.js.map +1 -1
  12. package/lib/module/types.js +8 -0
  13. package/lib/module/types.js.map +1 -1
  14. package/lib/module/utils/error.js.map +1 -1
  15. package/lib/module/utils/errorMapping.js +33 -0
  16. package/lib/module/utils/errorMapping.js.map +1 -0
  17. package/lib/module/utils/type-bridge.js +19 -0
  18. package/lib/module/utils/type-bridge.js.map +1 -1
  19. package/lib/typescript/src/helpers/subscription.d.ts.map +1 -1
  20. package/lib/typescript/src/hooks/useIAP.d.ts +4 -4
  21. package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
  22. package/lib/typescript/src/index.d.ts +7 -3
  23. package/lib/typescript/src/index.d.ts.map +1 -1
  24. package/lib/typescript/src/types.d.ts +19 -0
  25. package/lib/typescript/src/types.d.ts.map +1 -1
  26. package/lib/typescript/src/utils/error.d.ts.map +1 -1
  27. package/lib/typescript/src/utils/errorMapping.d.ts +5 -0
  28. package/lib/typescript/src/utils/errorMapping.d.ts.map +1 -0
  29. package/lib/typescript/src/utils/type-bridge.d.ts +3 -2
  30. package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
  31. package/package.json +5 -2
  32. package/plugin/tsconfig.tsbuildinfo +1 -1
  33. package/src/helpers/subscription.ts +30 -30
  34. package/src/hooks/useIAP.ts +252 -230
  35. package/src/index.ts +366 -340
  36. package/src/types.ts +21 -0
  37. package/src/utils/error.ts +19 -19
  38. package/src/utils/errorMapping.ts +44 -0
  39. package/src/utils/type-bridge.ts +127 -93
  40. package/ios/ErrorUtils.swift +0 -153
  41. package/ios/ProductStore.swift +0 -43
  42. package/ios/reactnativeiap.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  43. package/ios/reactnativeiap.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  44. package/plugin/build/src/withIAP.d.ts +0 -3
  45. package/plugin/build/src/withIAP.js +0 -81
  46. 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
- } from './types';
27
- import type {ProductRequest} from './types';
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
- } from './utils/type-bridge';
34
- import {parseErrorStringToJsonObj} from './utils/error';
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' && iosReq.andDangerouslyFinishTransactionAutomatically == null;
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: (androidResult.productType === 'subs' ? 'subs' : 'inapp'),
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<any[]> - Array of subscription status objects
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 (sku: string): Promise<any[]> => {
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
- return statuses || [];
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