react-native-iap 14.3.1 → 14.3.2-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _exportNames = {};
7
+ exports.default = void 0;
8
+ var _reactNativeNitroModules = require("react-native-nitro-modules");
9
+ var _RnIap = require("./specs/RnIap.nitro");
10
+ Object.keys(_RnIap).forEach(function (key) {
11
+ if (key === "default" || key === "__esModule") return;
12
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
13
+ if (key in exports && exports[key] === _RnIap[key]) return;
14
+ Object.defineProperty(exports, key, {
15
+ enumerable: true,
16
+ get: function () {
17
+ return _RnIap[key];
18
+ }
19
+ });
20
+ });
21
+ var _types = require("./types");
22
+ Object.keys(_types).forEach(function (key) {
23
+ if (key === "default" || key === "__esModule") return;
24
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
25
+ if (key in exports && exports[key] === _types[key]) return;
26
+ Object.defineProperty(exports, key, {
27
+ enumerable: true,
28
+ get: function () {
29
+ return _types[key];
30
+ }
31
+ });
32
+ });
33
+ // Create and export the RnIap HybridObject directly
34
+ const RnIap = _reactNativeNitroModules.NitroModules.createHybridObject('RnIap');
35
+ var _default = exports.default = RnIap;
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNativeNitroModules","require","_RnIap","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_types","RnIap","NitroModules","createHybridObject","_default","default"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;AAAA,IAAAA,wBAAA,GAAAC,OAAA;AAGA,IAAAC,MAAA,GAAAD,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAF,MAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,MAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,MAAA,CAAAI,GAAA;IAAA;EAAA;AAAA;AACA,IAAAS,MAAA,GAAAd,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAW,MAAA,EAAAV,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAS,MAAA,CAAAT,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,MAAA,CAAAT,GAAA;IAAA;EAAA;AAAA;AAEA;AACA,MAAMU,KAAK,GAAGC,qCAAY,CAACC,kBAAkB,CAAY,OAAO,CAAC;AAAA,IAAAC,QAAA,GAAAR,OAAA,CAAAS,OAAA,GAElDJ,KAAK","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ //# sourceMappingURL=RnIap.nitro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["specs/RnIap.nitro.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PurchaseAndroidState = exports.ErrorCode = void 0;
7
+ // ============================================================================
8
+ // CORE TYPES
9
+ // ============================================================================
10
+ // ============================================================================
11
+ // COMMON TYPES (Base types shared across all platforms)
12
+ // ============================================================================
13
+ /**
14
+ * Base product information shared across all platforms
15
+ */
16
+ /**
17
+ * Base purchase information shared across all platforms
18
+ * Represents both consumables, non-consumables, and subscriptions
19
+ */
20
+ // ============================================================================
21
+ // PLATFORM TYPES
22
+ // ============================================================================
23
+ // ============================================================================
24
+ // IOS TYPES
25
+ // ============================================================================
26
+ // ============================================================================
27
+ // ANDROID TYPES
28
+ // ============================================================================
29
+ let PurchaseAndroidState = exports.PurchaseAndroidState = /*#__PURE__*/function (PurchaseAndroidState) {
30
+ PurchaseAndroidState[PurchaseAndroidState["UNSPECIFIED_STATE"] = 0] = "UNSPECIFIED_STATE";
31
+ PurchaseAndroidState[PurchaseAndroidState["PURCHASED"] = 1] = "PURCHASED";
32
+ PurchaseAndroidState[PurchaseAndroidState["PENDING"] = 2] = "PENDING";
33
+ return PurchaseAndroidState;
34
+ }({}); // ============================================================================
35
+ // TYPE ALIASES
36
+ // ============================================================================
37
+ // Legacy naming for backward compatibility
38
+ // Legacy naming for backward compatibility
39
+ // ============================================================================
40
+ // UNION TYPES
41
+ // ============================================================================
42
+ // Product Union Types
43
+ // Purchase Union Types
44
+ /**
45
+ * Regular product purchase (consumable or non-consumable)
46
+ * Both types appear in getAvailablePurchases until finishTransaction is called
47
+ */
48
+ /**
49
+ * Active subscription purchase
50
+ * Appears in getAvailablePurchases while subscription is active
51
+ */
52
+ /**
53
+ * Combined purchase type that includes all purchase types
54
+ * Used as return type for getAvailablePurchases
55
+ */
56
+ // ============================================================================
57
+ // REQUEST TYPES
58
+ // ============================================================================
59
+ // iOS-specific purchase request parameters
60
+ // Android-specific purchase request parameters
61
+ // Android-specific subscription request parameters
62
+ // Platform-specific request structures
63
+ // Modern request types (v2.7.0+)
64
+ // ============================================================================
65
+ // ERROR TYPES
66
+ // ============================================================================
67
+ let ErrorCode = exports.ErrorCode = /*#__PURE__*/function (ErrorCode) {
68
+ ErrorCode["E_UNKNOWN"] = "E_UNKNOWN";
69
+ ErrorCode["E_USER_CANCELLED"] = "E_USER_CANCELLED";
70
+ ErrorCode["E_USER_ERROR"] = "E_USER_ERROR";
71
+ ErrorCode["E_ITEM_UNAVAILABLE"] = "E_ITEM_UNAVAILABLE";
72
+ ErrorCode["E_REMOTE_ERROR"] = "E_REMOTE_ERROR";
73
+ ErrorCode["E_NETWORK_ERROR"] = "E_NETWORK_ERROR";
74
+ ErrorCode["E_SERVICE_ERROR"] = "E_SERVICE_ERROR";
75
+ ErrorCode["E_RECEIPT_FAILED"] = "E_RECEIPT_FAILED";
76
+ ErrorCode["E_RECEIPT_FINISHED_FAILED"] = "E_RECEIPT_FINISHED_FAILED";
77
+ ErrorCode["E_NOT_PREPARED"] = "E_NOT_PREPARED";
78
+ ErrorCode["E_NOT_ENDED"] = "E_NOT_ENDED";
79
+ ErrorCode["E_ALREADY_OWNED"] = "E_ALREADY_OWNED";
80
+ ErrorCode["E_DEVELOPER_ERROR"] = "E_DEVELOPER_ERROR";
81
+ ErrorCode["E_BILLING_RESPONSE_JSON_PARSE_ERROR"] = "E_BILLING_RESPONSE_JSON_PARSE_ERROR";
82
+ ErrorCode["E_DEFERRED_PAYMENT"] = "E_DEFERRED_PAYMENT";
83
+ ErrorCode["E_INTERRUPTED"] = "E_INTERRUPTED";
84
+ ErrorCode["E_IAP_NOT_AVAILABLE"] = "E_IAP_NOT_AVAILABLE";
85
+ ErrorCode["E_PURCHASE_ERROR"] = "E_PURCHASE_ERROR";
86
+ ErrorCode["E_SYNC_ERROR"] = "E_SYNC_ERROR";
87
+ ErrorCode["E_TRANSACTION_VALIDATION_FAILED"] = "E_TRANSACTION_VALIDATION_FAILED";
88
+ ErrorCode["E_ACTIVITY_UNAVAILABLE"] = "E_ACTIVITY_UNAVAILABLE";
89
+ ErrorCode["E_ALREADY_PREPARED"] = "E_ALREADY_PREPARED";
90
+ ErrorCode["E_PENDING"] = "E_PENDING";
91
+ ErrorCode["E_CONNECTION_CLOSED"] = "E_CONNECTION_CLOSED";
92
+ return ErrorCode;
93
+ }({}); // Additional iOS types
94
+ // ============================================================================
95
+ // METHOD OPTIONS TYPES
96
+ // ============================================================================
97
+ /**
98
+ * Options for getAvailablePurchases and getPurchaseHistories methods
99
+ */
100
+ /**
101
+ * Parameters for finishTransaction method
102
+ */
103
+ // ============================================================================
104
+ // IAP CONTEXT INTERFACE
105
+ // ============================================================================
106
+ /**
107
+ * Main IAP context interface providing all in-app purchase functionality
108
+ */
109
+ /**
110
+ * Purchase error type
111
+ */
112
+ /**
113
+ * Validation options for receipt validation
114
+ */
115
+ /**
116
+ * Validation result from receipt validation
117
+ */
118
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["PurchaseAndroidState","exports","ErrorCode"],"sourceRoot":"../../src","sources":["types.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AAQA;AACA;AACA;AAEA;AACA;AACA;AAwBA;AACA;AACA;AACA;AAwBA;AACA;AACA;AAKA;AACA;AACA;AAyGA;AACA;AACA;AAAA,IAsDYA,oBAAoB,GAAAC,OAAA,CAAAD,oBAAA,0BAApBA,oBAAoB;EAApBA,oBAAoB,CAApBA,oBAAoB;EAApBA,oBAAoB,CAApBA,oBAAoB;EAApBA,oBAAoB,CAApBA,oBAAoB;EAAA,OAApBA,oBAAoB;AAAA,OAuBhC;AACA;AACA;AAEA;AAIA;AAIA;AACA;AACA;AAEA;AASA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAKA;AACA;AACA;AAEA;AASA;AAQA;AAWA;AAWA;AAIA;AACA;AACA;AAAA,IAEYE,SAAS,GAAAD,OAAA,CAAAC,SAAA,0BAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAAA,OAATA,SAAS;AAAA,OAuCrB;AAyBA;AACA;AACA;AAEA;AACA;AACA;AAQA;AACA;AACA;AAeA;AACA;AACA;AAEA;AACA;AACA;AAkFA;AACA;AACA;AAUA;AACA;AACA;AAmBA;AACA;AACA","ignoreList":[]}
@@ -38,15 +38,29 @@ export const restorePurchases = async (options = {
38
38
 
39
39
  // Development utilities removed - use type bridge functions directly if needed
40
40
 
41
- // Create the RnIap HybridObject instance (internal use only)
42
- const iap = NitroModules.createHybridObject('RnIap');
41
+ // Create the RnIap HybridObject instance lazily to avoid early JSI crashes
42
+ let iapRef = null;
43
+ const IAP = {
44
+ get instance() {
45
+ if (iapRef) return iapRef;
46
+
47
+ // Guard against accessing Nitro before it's installed into the JS runtime
48
+ const hasNitroDispatcher = typeof globalThis !== 'undefined' && globalThis?.__nitro?.dispatcher != null;
49
+ const isJestEnvironment = typeof globalThis.jest !== 'undefined' || typeof process !== 'undefined' && !!process.env && process.env.JEST_WORKER_ID != null;
50
+ if (!hasNitroDispatcher && !isJestEnvironment) {
51
+ throw new Error('Nitro runtime not installed yet. Ensure react-native-nitro-modules is initialized before calling IAP.');
52
+ }
53
+ iapRef = NitroModules.createHybridObject('RnIap');
54
+ return iapRef;
55
+ }
56
+ };
43
57
 
44
58
  /**
45
59
  * Initialize connection to the store
46
60
  */
47
61
  export const initConnection = async () => {
48
62
  try {
49
- return await iap.initConnection();
63
+ return await IAP.instance.initConnection();
50
64
  } catch (error) {
51
65
  console.error('Failed to initialize IAP connection:', error);
52
66
  throw error;
@@ -58,7 +72,9 @@ export const initConnection = async () => {
58
72
  */
59
73
  export const endConnection = async () => {
60
74
  try {
61
- return await iap.endConnection();
75
+ // If never initialized, treat as ended
76
+ if (!iapRef) return true;
77
+ return await IAP.instance.endConnection();
62
78
  } catch (error) {
63
79
  console.error('Failed to end IAP connection:', error);
64
80
  throw error;
@@ -90,7 +106,7 @@ export const fetchProducts = async ({
90
106
  throw new Error('No SKUs provided');
91
107
  }
92
108
  if (type === 'all') {
93
- const [inappNitro, subsNitro] = await Promise.all([iap.fetchProducts(skus, 'inapp'), iap.fetchProducts(skus, 'subs')]);
109
+ const [inappNitro, subsNitro] = await Promise.all([IAP.instance.fetchProducts(skus, 'inapp'), IAP.instance.fetchProducts(skus, 'subs')]);
94
110
  const allNitro = [...inappNitro, ...subsNitro];
95
111
  const validAll = allNitro.filter(validateNitroProduct);
96
112
  if (validAll.length !== allNitro.length) {
@@ -98,7 +114,7 @@ export const fetchProducts = async ({
98
114
  }
99
115
  return validAll.map(convertNitroProductToProduct);
100
116
  }
101
- const nitroProducts = await iap.fetchProducts(skus, type);
117
+ const nitroProducts = await IAP.instance.fetchProducts(skus, type);
102
118
 
103
119
  // Validate and convert NitroProducts to TypeScript Products
104
120
  const validProducts = nitroProducts.filter(validateNitroProduct);
@@ -197,7 +213,7 @@ export const requestPurchase = async ({
197
213
  }
198
214
 
199
215
  // Call unified method - returns void, listen for events instead
200
- await iap.requestPurchase(unifiedRequest);
216
+ await IAP.instance.requestPurchase(unifiedRequest);
201
217
  } catch (error) {
202
218
  console.error('Failed to request purchase:', error);
203
219
  throw error;
@@ -234,12 +250,12 @@ export const getAvailablePurchases = async ({
234
250
  };
235
251
  } else if (Platform.OS === 'android') {
236
252
  // For Android, we need to call twice for inapp and subs
237
- const inappNitroPurchases = await iap.getAvailablePurchases({
253
+ const inappNitroPurchases = await IAP.instance.getAvailablePurchases({
238
254
  android: {
239
255
  type: 'inapp'
240
256
  }
241
257
  });
242
- const subsNitroPurchases = await iap.getAvailablePurchases({
258
+ const subsNitroPurchases = await IAP.instance.getAvailablePurchases({
243
259
  android: {
244
260
  type: 'subs'
245
261
  }
@@ -255,7 +271,7 @@ export const getAvailablePurchases = async ({
255
271
  } else {
256
272
  throw new Error('Unsupported platform');
257
273
  }
258
- const nitroPurchases = await iap.getAvailablePurchases(options);
274
+ const nitroPurchases = await IAP.instance.getAvailablePurchases(options);
259
275
 
260
276
  // Validate and convert NitroPurchases to TypeScript Purchases
261
277
  const validPurchases = nitroPurchases.filter(validateNitroPurchase);
@@ -310,7 +326,7 @@ export const finishTransaction = async ({
310
326
  } else {
311
327
  throw new Error('Unsupported platform');
312
328
  }
313
- const result = await iap.finishTransaction(params);
329
+ const result = await IAP.instance.finishTransaction(params);
314
330
 
315
331
  // Handle variant return type
316
332
  if (typeof result === 'boolean') {
@@ -348,7 +364,7 @@ export const acknowledgePurchaseAndroid = async purchaseToken => {
348
364
  if (Platform.OS !== 'android') {
349
365
  throw new Error('acknowledgePurchaseAndroid is only available on Android');
350
366
  }
351
- const result = await iap.finishTransaction({
367
+ const result = await IAP.instance.finishTransaction({
352
368
  android: {
353
369
  purchaseToken,
354
370
  isConsumable: false
@@ -386,7 +402,7 @@ export const consumePurchaseAndroid = async purchaseToken => {
386
402
  if (Platform.OS !== 'android') {
387
403
  throw new Error('consumePurchaseAndroid is only available on Android');
388
404
  }
389
- const result = await iap.finishTransaction({
405
+ const result = await IAP.instance.finishTransaction({
390
406
  android: {
391
407
  purchaseToken,
392
408
  isConsumable: true
@@ -450,12 +466,27 @@ export const purchaseUpdatedListener = listener => {
450
466
 
451
467
  // Store the wrapped listener for removal
452
468
  listenerMap.set(listener, wrappedListener);
453
- iap.addPurchaseUpdatedListener(wrappedListener);
469
+ let attached = false;
470
+ try {
471
+ IAP.instance.addPurchaseUpdatedListener(wrappedListener);
472
+ attached = true;
473
+ } catch (e) {
474
+ const msg = String(e ?? '');
475
+ if (msg.includes('Nitro runtime not installed')) {
476
+ console.warn('[purchaseUpdatedListener] Nitro not ready yet; listener inert until initConnection()');
477
+ } else {
478
+ throw e;
479
+ }
480
+ }
454
481
  return {
455
482
  remove: () => {
456
483
  const wrapped = listenerMap.get(listener);
457
484
  if (wrapped) {
458
- iap.removePurchaseUpdatedListener(wrapped);
485
+ if (attached) {
486
+ try {
487
+ IAP.instance.removePurchaseUpdatedListener(wrapped);
488
+ } catch {}
489
+ }
459
490
  listenerMap.delete(listener);
460
491
  }
461
492
  }
@@ -492,10 +523,25 @@ export const purchaseUpdatedListener = listener => {
492
523
  export const purchaseErrorListener = listener => {
493
524
  // Store the listener for removal
494
525
  listenerMap.set(listener, listener);
495
- iap.addPurchaseErrorListener(listener);
526
+ let attached = false;
527
+ try {
528
+ IAP.instance.addPurchaseErrorListener(listener);
529
+ attached = true;
530
+ } catch (e) {
531
+ const msg = String(e ?? '');
532
+ if (msg.includes('Nitro runtime not installed')) {
533
+ console.warn('[purchaseErrorListener] Nitro not ready yet; listener inert until initConnection()');
534
+ } else {
535
+ throw e;
536
+ }
537
+ }
496
538
  return {
497
539
  remove: () => {
498
- iap.removePurchaseErrorListener(listener);
540
+ if (attached) {
541
+ try {
542
+ IAP.instance.removePurchaseErrorListener(listener);
543
+ } catch {}
544
+ }
499
545
  listenerMap.delete(listener);
500
546
  }
501
547
  };
@@ -541,12 +587,27 @@ export const promotedProductListenerIOS = listener => {
541
587
 
542
588
  // Store the wrapped listener for removal
543
589
  listenerMap.set(listener, wrappedListener);
544
- iap.addPromotedProductListenerIOS(wrappedListener);
590
+ let attached = false;
591
+ try {
592
+ IAP.instance.addPromotedProductListenerIOS(wrappedListener);
593
+ attached = true;
594
+ } catch (e) {
595
+ const msg = String(e ?? '');
596
+ if (msg.includes('Nitro runtime not installed')) {
597
+ console.warn('[promotedProductListenerIOS] Nitro not ready yet; listener inert until initConnection()');
598
+ } else {
599
+ throw e;
600
+ }
601
+ }
545
602
  return {
546
603
  remove: () => {
547
604
  const wrapped = listenerMap.get(listener);
548
605
  if (wrapped) {
549
- iap.removePromotedProductListenerIOS(wrapped);
606
+ if (attached) {
607
+ try {
608
+ IAP.instance.removePromotedProductListenerIOS(wrapped);
609
+ } catch {}
610
+ }
550
611
  listenerMap.delete(listener);
551
612
  }
552
613
  }
@@ -564,16 +625,12 @@ export const promotedProductListenerIOS = listener => {
564
625
  * @returns Promise<ReceiptValidationResultIOS | ReceiptValidationResultAndroid> - Platform-specific receipt validation result
565
626
  */
566
627
  export const validateReceipt = async (sku, androidOptions) => {
567
- if (!iap) {
568
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
569
- throw new Error(errorJson.message);
570
- }
571
628
  try {
572
629
  const params = {
573
630
  sku,
574
631
  androidOptions
575
632
  };
576
- const nitroResult = await iap.validateReceipt(params);
633
+ const nitroResult = await IAP.instance.validateReceipt(params);
577
634
 
578
635
  // Convert Nitro result to public API result
579
636
  if (Platform.OS === 'ios') {
@@ -626,12 +683,8 @@ export const syncIOS = async () => {
626
683
  if (Platform.OS !== 'ios') {
627
684
  throw new Error('syncIOS is only available on iOS');
628
685
  }
629
- if (!iap) {
630
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
631
- throw new Error(errorJson.message);
632
- }
633
686
  try {
634
- return await iap.syncIOS();
687
+ return await IAP.instance.syncIOS();
635
688
  } catch (error) {
636
689
  console.error('[syncIOS] Failed:', error);
637
690
  const errorJson = parseErrorStringToJsonObj(error);
@@ -648,12 +701,8 @@ export const requestPromotedProductIOS = async () => {
648
701
  if (Platform.OS !== 'ios') {
649
702
  return null;
650
703
  }
651
- if (!iap) {
652
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
653
- throw new Error(errorJson.message);
654
- }
655
704
  try {
656
- const nitroProduct = await iap.requestPromotedProductIOS();
705
+ const nitroProduct = await IAP.instance.requestPromotedProductIOS();
657
706
  if (nitroProduct) {
658
707
  return convertNitroProductToProduct(nitroProduct);
659
708
  }
@@ -674,12 +723,8 @@ export const presentCodeRedemptionSheetIOS = async () => {
674
723
  if (Platform.OS !== 'ios') {
675
724
  return false;
676
725
  }
677
- if (!iap) {
678
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
679
- throw new Error(errorJson.message);
680
- }
681
726
  try {
682
- return await iap.presentCodeRedemptionSheetIOS();
727
+ return await IAP.instance.presentCodeRedemptionSheetIOS();
683
728
  } catch (error) {
684
729
  console.error('[presentCodeRedemptionSheetIOS] Failed:', error);
685
730
  const errorJson = parseErrorStringToJsonObj(error);
@@ -696,12 +741,8 @@ export const buyPromotedProductIOS = async () => {
696
741
  if (Platform.OS !== 'ios') {
697
742
  throw new Error('buyPromotedProductIOS is only available on iOS');
698
743
  }
699
- if (!iap) {
700
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
701
- throw new Error(errorJson.message);
702
- }
703
744
  try {
704
- await iap.buyPromotedProductIOS();
745
+ await IAP.instance.buyPromotedProductIOS();
705
746
  } catch (error) {
706
747
  console.error('[buyPromotedProductIOS] Failed:', error);
707
748
  const errorJson = parseErrorStringToJsonObj(error);
@@ -718,12 +759,8 @@ export const clearTransactionIOS = async () => {
718
759
  if (Platform.OS !== 'ios') {
719
760
  return;
720
761
  }
721
- if (!iap) {
722
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
723
- throw new Error(errorJson.message);
724
- }
725
762
  try {
726
- await iap.clearTransactionIOS();
763
+ await IAP.instance.clearTransactionIOS();
727
764
  } catch (error) {
728
765
  console.error('[clearTransactionIOS] Failed:', error);
729
766
  const errorJson = parseErrorStringToJsonObj(error);
@@ -741,12 +778,8 @@ export const beginRefundRequestIOS = async sku => {
741
778
  if (Platform.OS !== 'ios') {
742
779
  return null;
743
780
  }
744
- if (!iap) {
745
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
746
- throw new Error(errorJson.message);
747
- }
748
781
  try {
749
- return await iap.beginRefundRequestIOS(sku);
782
+ return await IAP.instance.beginRefundRequestIOS(sku);
750
783
  } catch (error) {
751
784
  console.error('[beginRefundRequestIOS] Failed:', error);
752
785
  const errorJson = parseErrorStringToJsonObj(error);
@@ -765,12 +798,8 @@ export const subscriptionStatusIOS = async sku => {
765
798
  if (Platform.OS !== 'ios') {
766
799
  throw new Error('subscriptionStatusIOS is only available on iOS');
767
800
  }
768
- if (!iap) {
769
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
770
- throw new Error(errorJson.message);
771
- }
772
801
  try {
773
- const statuses = await iap.subscriptionStatusIOS(sku);
802
+ const statuses = await IAP.instance.subscriptionStatusIOS(sku);
774
803
  if (!statuses || !Array.isArray(statuses)) return [];
775
804
  return statuses.map(s => convertNitroSubscriptionStatusToSubscriptionStatusIOS(s));
776
805
  } catch (error) {
@@ -790,12 +819,8 @@ export const currentEntitlementIOS = async sku => {
790
819
  if (Platform.OS !== 'ios') {
791
820
  return null;
792
821
  }
793
- if (!iap) {
794
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
795
- throw new Error(errorJson.message);
796
- }
797
822
  try {
798
- const nitroPurchase = await iap.currentEntitlementIOS(sku);
823
+ const nitroPurchase = await IAP.instance.currentEntitlementIOS(sku);
799
824
  if (nitroPurchase) {
800
825
  return convertNitroPurchaseToPurchase(nitroPurchase);
801
826
  }
@@ -817,12 +842,8 @@ export const latestTransactionIOS = async sku => {
817
842
  if (Platform.OS !== 'ios') {
818
843
  return null;
819
844
  }
820
- if (!iap) {
821
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
822
- throw new Error(errorJson.message);
823
- }
824
845
  try {
825
- const nitroPurchase = await iap.latestTransactionIOS(sku);
846
+ const nitroPurchase = await IAP.instance.latestTransactionIOS(sku);
826
847
  if (nitroPurchase) {
827
848
  return convertNitroPurchaseToPurchase(nitroPurchase);
828
849
  }
@@ -843,12 +864,8 @@ export const getPendingTransactionsIOS = async () => {
843
864
  if (Platform.OS !== 'ios') {
844
865
  return [];
845
866
  }
846
- if (!iap) {
847
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
848
- throw new Error(errorJson.message);
849
- }
850
867
  try {
851
- const nitroPurchases = await iap.getPendingTransactionsIOS();
868
+ const nitroPurchases = await IAP.instance.getPendingTransactionsIOS();
852
869
  return nitroPurchases.map(convertNitroPurchaseToPurchase);
853
870
  } catch (error) {
854
871
  console.error('[getPendingTransactionsIOS] Failed:', error);
@@ -866,12 +883,8 @@ export const showManageSubscriptionsIOS = async () => {
866
883
  if (Platform.OS !== 'ios') {
867
884
  return [];
868
885
  }
869
- if (!iap) {
870
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
871
- throw new Error(errorJson.message);
872
- }
873
886
  try {
874
- const nitroPurchases = await iap.showManageSubscriptionsIOS();
887
+ const nitroPurchases = await IAP.instance.showManageSubscriptionsIOS();
875
888
  return nitroPurchases.map(convertNitroPurchaseToPurchase);
876
889
  } catch (error) {
877
890
  console.error('[showManageSubscriptionsIOS] Failed:', error);
@@ -890,12 +903,8 @@ export const isEligibleForIntroOfferIOS = async groupID => {
890
903
  if (Platform.OS !== 'ios') {
891
904
  return false;
892
905
  }
893
- if (!iap) {
894
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
895
- throw new Error(errorJson.message);
896
- }
897
906
  try {
898
- return await iap.isEligibleForIntroOfferIOS(groupID);
907
+ return await IAP.instance.isEligibleForIntroOfferIOS(groupID);
899
908
  } catch (error) {
900
909
  console.error('[isEligibleForIntroOfferIOS] Failed:', error);
901
910
  const errorJson = parseErrorStringToJsonObj(error);
@@ -912,12 +921,8 @@ export const getReceiptDataIOS = async () => {
912
921
  if (Platform.OS !== 'ios') {
913
922
  throw new Error('getReceiptDataIOS is only available on iOS');
914
923
  }
915
- if (!iap) {
916
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
917
- throw new Error(errorJson.message);
918
- }
919
924
  try {
920
- return await iap.getReceiptDataIOS();
925
+ return await IAP.instance.getReceiptDataIOS();
921
926
  } catch (error) {
922
927
  console.error('[getReceiptDataIOS] Failed:', error);
923
928
  const errorJson = parseErrorStringToJsonObj(error);
@@ -935,12 +940,8 @@ export const isTransactionVerifiedIOS = async sku => {
935
940
  if (Platform.OS !== 'ios') {
936
941
  return false;
937
942
  }
938
- if (!iap) {
939
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
940
- throw new Error(errorJson.message);
941
- }
942
943
  try {
943
- return await iap.isTransactionVerifiedIOS(sku);
944
+ return await IAP.instance.isTransactionVerifiedIOS(sku);
944
945
  } catch (error) {
945
946
  console.error('[isTransactionVerifiedIOS] Failed:', error);
946
947
  const errorJson = parseErrorStringToJsonObj(error);
@@ -958,12 +959,8 @@ export const getTransactionJwsIOS = async sku => {
958
959
  if (Platform.OS !== 'ios') {
959
960
  return null;
960
961
  }
961
- if (!iap) {
962
- const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
963
- throw new Error(errorJson.message);
964
- }
965
962
  try {
966
- return await iap.getTransactionJwsIOS(sku);
963
+ return await IAP.instance.getTransactionJwsIOS(sku);
967
964
  } catch (error) {
968
965
  console.error('[getTransactionJwsIOS] Failed:', error);
969
966
  const errorJson = parseErrorStringToJsonObj(error);
@@ -988,7 +985,7 @@ export const getStorefrontIOS = async () => {
988
985
  }
989
986
  try {
990
987
  // Call the native method to get storefront
991
- const storefront = await iap.getStorefrontIOS();
988
+ const storefront = await IAP.instance.getStorefrontIOS();
992
989
  return storefront;
993
990
  } catch (error) {
994
991
  console.error('Failed to get storefront:', error);
@@ -1006,7 +1003,7 @@ export const getStorefront = async () => {
1006
1003
  if (Platform.OS === 'android') {
1007
1004
  try {
1008
1005
  // Optional since older builds may not have the method
1009
- const result = await iap.getStorefrontAndroid?.();
1006
+ const result = await IAP.instance.getStorefrontAndroid?.();
1010
1007
  return result ?? '';
1011
1008
  } catch {
1012
1009
  return '';
@@ -1021,7 +1018,7 @@ export const getStorefront = async () => {
1021
1018
  */
1022
1019
  export const deepLinkToSubscriptions = async (options = {}) => {
1023
1020
  if (Platform.OS === 'android') {
1024
- await iap.deepLinkToSubscriptionsAndroid?.({
1021
+ await IAP.instance.deepLinkToSubscriptionsAndroid?.({
1025
1022
  skuAndroid: options.skuAndroid,
1026
1023
  packageNameAndroid: options.packageNameAndroid
1027
1024
  });
@@ -1030,7 +1027,7 @@ export const deepLinkToSubscriptions = async (options = {}) => {
1030
1027
  // iOS: Use manage subscriptions sheet (ignore returned purchases for deeplink parity)
1031
1028
  if (Platform.OS === 'ios') {
1032
1029
  try {
1033
- await iap.showManageSubscriptionsIOS();
1030
+ await IAP.instance.showManageSubscriptionsIOS();
1034
1031
  } catch {
1035
1032
  // no-op
1036
1033
  }
@@ -1064,7 +1061,7 @@ export const getAppTransactionIOS = async () => {
1064
1061
  }
1065
1062
  try {
1066
1063
  // Call the native method to get app transaction
1067
- const appTransaction = await iap.getAppTransactionIOS();
1064
+ const appTransaction = await IAP.instance.getAppTransactionIOS();
1068
1065
  return appTransaction;
1069
1066
  } catch (error) {
1070
1067
  console.error('Failed to get app transaction:', error);