react-native-iap 15.2.4 → 15.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +29 -49
  2. package/android/build.gradle +92 -22
  3. package/android/gradle.properties +5 -1
  4. package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +1 -1
  5. package/android/src/main/java/com/margelo/nitro/iap/RnIapLog.kt +3 -1
  6. package/ios/HybridRnIap.swift +12 -6
  7. package/lib/module/index.js +73 -158
  8. package/lib/module/index.js.map +1 -1
  9. package/lib/typescript/src/hooks/useIAP.d.ts +15 -15
  10. package/lib/typescript/src/index.d.ts +59 -88
  11. package/lib/typescript/src/index.d.ts.map +1 -1
  12. package/lib/typescript/src/specs/RnIap.nitro.d.ts +2 -15
  13. package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
  14. package/lib/typescript/src/types.d.ts +47 -47
  15. package/nitro.json +0 -1
  16. package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +7 -7
  17. package/nitrogen/generated/android/c++/JHybridRnIapSpec.hpp +1 -1
  18. package/nitrogen/generated/android/c++/{JNitroPurchaseUpdatedListenerOptions.hpp → JPurchaseUpdatedListenerOptions.hpp} +10 -10
  19. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/HybridRnIapSpec.kt +2 -2
  20. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/{NitroPurchaseUpdatedListenerOptions.kt → PurchaseUpdatedListenerOptions.kt} +5 -5
  21. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +10 -10
  22. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +3 -3
  23. package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +4 -4
  24. package/nitrogen/generated/ios/swift/HybridRnIapSpec.swift +1 -1
  25. package/nitrogen/generated/ios/swift/HybridRnIapSpec_cxx.swift +1 -1
  26. package/nitrogen/generated/ios/swift/{NitroPurchaseUpdatedListenerOptions.swift → PurchaseUpdatedListenerOptions.swift} +5 -5
  27. package/nitrogen/generated/shared/c++/HybridRnIapSpec.hpp +4 -4
  28. package/nitrogen/generated/shared/c++/{NitroPurchaseUpdatedListenerOptions.hpp → PurchaseUpdatedListenerOptions.hpp} +11 -11
  29. package/openiap-versions.json +2 -2
  30. package/package.json +4 -6
  31. package/src/hooks/useIAP.ts +15 -15
  32. package/src/index.ts +93 -204
  33. package/src/specs/RnIap.nitro.ts +2 -15
  34. package/src/types.ts +47 -47
package/src/index.ts CHANGED
@@ -44,6 +44,8 @@ import type {
44
44
  RequestSubscriptionIosProps,
45
45
  RequestSubscriptionPropsByPlatforms,
46
46
  ActiveSubscription,
47
+ DeveloperProvidedBillingDetailsAndroid,
48
+ UserChoiceBillingDetails,
47
49
  } from './types';
48
50
  import {
49
51
  convertNitroProductToProduct,
@@ -72,8 +74,6 @@ import {parseAppTransactionPayload} from './utils';
72
74
  // Import them here for use in this file's interfaces and functions.
73
75
  import type {
74
76
  BillingProgramAndroid,
75
- ExternalLinkLaunchModeAndroid,
76
- ExternalLinkTypeAndroid,
77
77
  } from './types';
78
78
 
79
79
  // Export all types
@@ -89,7 +89,7 @@ export * from './utils/error';
89
89
  export type ProductTypeInput = 'inapp' | 'in-app' | 'subs';
90
90
 
91
91
  const LEGACY_INAPP_WARNING =
92
- "[react-native-iap] `type: 'inapp'` is deprecated and will be removed in v14.4.0. Use 'in-app' instead.";
92
+ "[react-native-iap] `type: 'inapp'` is deprecated and will be removed in a future major version. Use 'in-app' instead.";
93
93
 
94
94
  type NitroPurchaseRequest = Parameters<RnIap['requestPurchase']>[0];
95
95
  type NitroAvailablePurchasesOptions = NonNullable<
@@ -121,6 +121,9 @@ const toErrorMessage = (error: unknown): string => {
121
121
  return String(error ?? '');
122
122
  };
123
123
 
124
+ const unsupportedPlatformError = (): Error =>
125
+ new Error(`Unsupported platform: ${Platform.OS}`);
126
+
124
127
  export interface EventSubscription {
125
128
  remove(): void;
126
129
  }
@@ -517,7 +520,7 @@ export const promotedProductListenerIOS = (
517
520
  * const subscription = userChoiceBillingListenerAndroid((details) => {
518
521
  * console.log('User chose alternative billing');
519
522
  * console.log('Products:', details.products);
520
- * console.log('Token:', details.externalTransactionToken);
523
+ * console.log('External transaction token received; send it to your backend without logging it.');
521
524
  *
522
525
  * // Send token to backend for Google Play reporting
523
526
  * await reportToGooglePlay(details.externalTransactionToken);
@@ -531,7 +534,9 @@ type NitroUserChoiceBillingListener = Parameters<
531
534
  RnIap['addUserChoiceBillingListenerAndroid']
532
535
  >[0];
533
536
 
534
- const userChoiceBillingJsListeners = new Set<(details: any) => void>();
537
+ const userChoiceBillingJsListeners = new Set<
538
+ (details: UserChoiceBillingDetails) => void
539
+ >();
535
540
  let userChoiceBillingNativeAttached = false;
536
541
  const userChoiceBillingNativeHandler: NitroUserChoiceBillingListener = (
537
542
  details,
@@ -549,7 +554,7 @@ const userChoiceBillingNativeHandler: NitroUserChoiceBillingListener = (
549
554
  };
550
555
 
551
556
  export const userChoiceBillingListenerAndroid = (
552
- listener: (details: any) => void,
557
+ listener: (details: UserChoiceBillingDetails) => void,
553
558
  ): EventSubscription => {
554
559
  if (Platform.OS !== 'android') {
555
560
  RnIapConsole.warn(
@@ -602,7 +607,7 @@ export const userChoiceBillingListenerAndroid = (
602
607
  * ```typescript
603
608
  * const subscription = developerProvidedBillingListenerAndroid((details) => {
604
609
  * console.log('User chose developer billing');
605
- * console.log('Token:', details.externalTransactionToken);
610
+ * console.log('External transaction token received; send it to your backend without logging it.');
606
611
  *
607
612
  * // Process payment through your external payment system
608
613
  * await processExternalPayment();
@@ -637,15 +642,6 @@ const developerProvidedBillingNativeHandler: NitroDeveloperProvidedBillingListen
637
642
  }
638
643
  };
639
644
 
640
- export interface DeveloperProvidedBillingDetailsAndroid {
641
- /**
642
- * External transaction token used to report transactions made through developer billing.
643
- * This token must be used when reporting the external transaction to Google Play.
644
- * Must be reported within 24 hours of the transaction.
645
- */
646
- externalTransactionToken: string;
647
- }
648
-
649
645
  export const developerProvidedBillingListenerAndroid = (
650
646
  listener: (details: DeveloperProvidedBillingDetailsAndroid) => void,
651
647
  ): EventSubscription => {
@@ -801,7 +797,7 @@ export const subscriptionBillingIssueListener = (
801
797
  * @remarks This is a regular promise-based call. Don't confuse with `request*` APIs
802
798
  * (`requestPurchase`), which are event-based.
803
799
  *
804
- * @see {@link https://www.openiap.dev/docs/apis/fetch-products}
800
+ * @see {@link https://openiap.dev/docs/apis/fetch-products}
805
801
  */
806
802
  export const fetchProducts: QueryField<'fetchProducts'> = async (request) => {
807
803
  const {skus, type} = request;
@@ -943,7 +939,7 @@ export const fetchProducts: QueryField<'fetchProducts'> = async (request) => {
943
939
  * }
944
940
  * ```
945
941
  *
946
- * @see {@link https://www.openiap.dev/docs/apis/get-available-purchases}
942
+ * @see {@link https://openiap.dev/docs/apis/get-available-purchases}
947
943
  */
948
944
  export const getAvailablePurchases: QueryField<
949
945
  'getAvailablePurchases'
@@ -998,7 +994,7 @@ export const getAvailablePurchases: QueryField<
998
994
 
999
995
  return validPurchases.map(convertNitroPurchaseToPurchase);
1000
996
  } else {
1001
- throw new Error('Unsupported platform');
997
+ throw unsupportedPlatformError();
1002
998
  }
1003
999
  } catch (error) {
1004
1000
  RnIapConsole.error('Failed to get available purchases:', error);
@@ -1011,7 +1007,7 @@ export const getAvailablePurchases: QueryField<
1011
1007
  * @returns Promise<Product | null> - The promoted product or null if none available
1012
1008
  * @platform iOS
1013
1009
  *
1014
- * @see {@link https://www.openiap.dev/docs/apis/ios/get-promoted-product-ios}
1010
+ * @see {@link https://openiap.dev/docs/apis/ios/get-promoted-product-ios}
1015
1011
  */
1016
1012
  export const getPromotedProductIOS: QueryField<
1017
1013
  'getPromotedProductIOS'
@@ -1055,7 +1051,7 @@ export const requestPromotedProductIOS = getPromotedProductIOS;
1055
1051
  * console.log('User storefront:', storefront); // e.g., 'USA', 'GBR', 'KOR'
1056
1052
  * ```
1057
1053
  *
1058
- * @see {@link https://www.openiap.dev/docs/apis/ios/get-storefront-ios}
1054
+ * @see {@link https://openiap.dev/docs/apis/ios/get-storefront-ios}
1059
1055
  */
1060
1056
  export const getStorefrontIOS: QueryField<'getStorefrontIOS'> = async () => {
1061
1057
  if (Platform.OS !== 'ios') {
@@ -1074,7 +1070,7 @@ export const getStorefrontIOS: QueryField<'getStorefrontIOS'> = async () => {
1074
1070
  /**
1075
1071
  * Return the user's storefront country code.
1076
1072
  *
1077
- * @see {@link https://www.openiap.dev/docs/apis/get-storefront}
1073
+ * @see {@link https://openiap.dev/docs/apis/get-storefront}
1078
1074
  */
1079
1075
  export const getStorefront: QueryField<'getStorefront'> = async () => {
1080
1076
  if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
@@ -1128,7 +1124,7 @@ export const getStorefront: QueryField<'getStorefront'> = async () => {
1128
1124
  * }
1129
1125
  * ```
1130
1126
  *
1131
- * @see {@link https://www.openiap.dev/docs/apis/ios/get-app-transaction-ios}
1127
+ * @see {@link https://openiap.dev/docs/apis/ios/get-app-transaction-ios}
1132
1128
  */
1133
1129
  export const getAppTransactionIOS: QueryField<
1134
1130
  'getAppTransactionIOS'
@@ -1169,7 +1165,7 @@ export const getAppTransactionIOS: QueryField<
1169
1165
  * @throws Error when called on non-iOS platforms or when IAP is not initialized
1170
1166
  * @platform iOS
1171
1167
  *
1172
- * @see {@link https://www.openiap.dev/docs/apis/ios/subscription-status-ios}
1168
+ * @see {@link https://openiap.dev/docs/apis/ios/subscription-status-ios}
1173
1169
  */
1174
1170
  export const subscriptionStatusIOS: QueryField<
1175
1171
  'subscriptionStatusIOS'
@@ -1202,7 +1198,7 @@ export const subscriptionStatusIOS: QueryField<
1202
1198
  * @returns Promise<Purchase | null> - Current entitlement or null
1203
1199
  * @platform iOS
1204
1200
  *
1205
- * @see {@link https://www.openiap.dev/docs/apis/ios/current-entitlement-ios}
1201
+ * @see {@link https://openiap.dev/docs/apis/ios/current-entitlement-ios}
1206
1202
  */
1207
1203
  export const currentEntitlementIOS: QueryField<
1208
1204
  'currentEntitlementIOS'
@@ -1236,7 +1232,7 @@ export const currentEntitlementIOS: QueryField<
1236
1232
  * @returns Promise<Purchase | null> - Latest transaction or null
1237
1233
  * @platform iOS
1238
1234
  *
1239
- * @see {@link https://www.openiap.dev/docs/apis/ios/latest-transaction-ios}
1235
+ * @see {@link https://openiap.dev/docs/apis/ios/latest-transaction-ios}
1240
1236
  */
1241
1237
  export const latestTransactionIOS: QueryField<'latestTransactionIOS'> = async (
1242
1238
  sku,
@@ -1269,7 +1265,7 @@ export const latestTransactionIOS: QueryField<'latestTransactionIOS'> = async (
1269
1265
  * @returns Promise<Purchase[]> - Array of pending transactions
1270
1266
  * @platform iOS
1271
1267
  *
1272
- * @see {@link https://www.openiap.dev/docs/apis/ios/get-pending-transactions-ios}
1268
+ * @see {@link https://openiap.dev/docs/apis/ios/get-pending-transactions-ios}
1273
1269
  */
1274
1270
  export const getPendingTransactionsIOS: QueryField<
1275
1271
  'getPendingTransactionsIOS'
@@ -1300,7 +1296,7 @@ export const getPendingTransactionsIOS: QueryField<
1300
1296
  /**
1301
1297
  * List every StoreKit transaction (finished + unfinished) for the current user.
1302
1298
  *
1303
- * @see {@link https://www.openiap.dev/docs/apis/ios/get-all-transactions-ios}
1299
+ * @see {@link https://openiap.dev/docs/apis/ios/get-all-transactions-ios}
1304
1300
  */
1305
1301
  export const getAllTransactionsIOS: QueryField<
1306
1302
  'getAllTransactionsIOS'
@@ -1333,7 +1329,7 @@ export const getAllTransactionsIOS: QueryField<
1333
1329
  * @returns Promise<Purchase[]> - Subscriptions where auto-renewal status changed
1334
1330
  * @platform iOS
1335
1331
  *
1336
- * @see {@link https://www.openiap.dev/docs/apis/ios/show-manage-subscriptions-ios}
1332
+ * @see {@link https://openiap.dev/docs/apis/ios/show-manage-subscriptions-ios}
1337
1333
  */
1338
1334
  export const showManageSubscriptionsIOS: MutationField<
1339
1335
  'showManageSubscriptionsIOS'
@@ -1367,7 +1363,7 @@ export const showManageSubscriptionsIOS: MutationField<
1367
1363
  * @returns Promise<boolean> - Eligibility status
1368
1364
  * @platform iOS
1369
1365
  *
1370
- * @see {@link https://www.openiap.dev/docs/apis/ios/is-eligible-for-intro-offer-ios}
1366
+ * @see {@link https://openiap.dev/docs/apis/ios/is-eligible-for-intro-offer-ios}
1371
1367
  */
1372
1368
  export const isEligibleForIntroOfferIOS: QueryField<
1373
1369
  'isEligibleForIntroOfferIOS'
@@ -1395,7 +1391,7 @@ export const isEligibleForIntroOfferIOS: QueryField<
1395
1391
  * @returns Promise<string> - Base64 encoded receipt data
1396
1392
  * @platform iOS
1397
1393
  *
1398
- * @see {@link https://www.openiap.dev/docs/apis/ios/get-receipt-data-ios}
1394
+ * @see {@link https://openiap.dev/docs/apis/ios/get-receipt-data-ios}
1399
1395
  */
1400
1396
  export const getReceiptDataIOS: QueryField<'getReceiptDataIOS'> = async () => {
1401
1397
  if (Platform.OS !== 'ios') {
@@ -1484,7 +1480,7 @@ export const requestReceiptRefreshIOS = async (): Promise<string> => {
1484
1480
  * @returns Promise<boolean> - Verification status
1485
1481
  * @platform iOS
1486
1482
  *
1487
- * @see {@link https://www.openiap.dev/docs/apis/ios/is-transaction-verified-ios}
1483
+ * @see {@link https://openiap.dev/docs/apis/ios/is-transaction-verified-ios}
1488
1484
  */
1489
1485
  export const isTransactionVerifiedIOS: QueryField<
1490
1486
  'isTransactionVerifiedIOS'
@@ -1513,7 +1509,7 @@ export const isTransactionVerifiedIOS: QueryField<
1513
1509
  * @returns Promise<string | null> - JWS representation or null
1514
1510
  * @platform iOS
1515
1511
  *
1516
- * @see {@link https://www.openiap.dev/docs/apis/ios/get-transaction-jws-ios}
1512
+ * @see {@link https://openiap.dev/docs/apis/ios/get-transaction-jws-ios}
1517
1513
  */
1518
1514
  export const getTransactionJwsIOS: QueryField<'getTransactionJwsIOS'> = async (
1519
1515
  sku,
@@ -1557,7 +1553,7 @@ export const getTransactionJwsIOS: QueryField<'getTransactionJwsIOS'> = async (
1557
1553
  * @remarks When using `useIAP()`, connection is auto-managed on mount/unmount —
1558
1554
  * pass options to the hook instead of calling this directly.
1559
1555
  *
1560
- * @see {@link https://www.openiap.dev/docs/apis/init-connection}
1556
+ * @see {@link https://openiap.dev/docs/apis/init-connection}
1561
1557
  */
1562
1558
  export const initConnection: MutationField<'initConnection'> = async (
1563
1559
  config,
@@ -1581,7 +1577,7 @@ export const initConnection: MutationField<'initConnection'> = async (
1581
1577
  /**
1582
1578
  * Close the store connection and release resources.
1583
1579
  *
1584
- * @see {@link https://www.openiap.dev/docs/apis/end-connection}
1580
+ * @see {@link https://openiap.dev/docs/apis/end-connection}
1585
1581
  */
1586
1582
  export const endConnection: MutationField<'endConnection'> = async () => {
1587
1583
  try {
@@ -1604,7 +1600,7 @@ export const endConnection: MutationField<'endConnection'> = async () => {
1604
1600
  /**
1605
1601
  * Restore non-consumable and active subscription purchases.
1606
1602
  *
1607
- * @see {@link https://www.openiap.dev/docs/apis/restore-purchases}
1603
+ * @see {@link https://openiap.dev/docs/apis/restore-purchases}
1608
1604
  */
1609
1605
  export const restorePurchases: MutationField<'restorePurchases'> = async () => {
1610
1606
  try {
@@ -1652,7 +1648,7 @@ export const restorePurchases: MutationField<'restorePurchases'> = async () => {
1652
1648
  * @remarks Event-based. Listen for the result via {@link purchaseUpdatedListener} /
1653
1649
  * {@link purchaseErrorListener}, or use `useIAP({ onPurchaseSuccess, onPurchaseError })`.
1654
1650
  *
1655
- * @see {@link https://www.openiap.dev/docs/apis/request-purchase}
1651
+ * @see {@link https://openiap.dev/docs/apis/request-purchase}
1656
1652
  */
1657
1653
  export const requestPurchase: MutationField<'requestPurchase'> = async (
1658
1654
  request,
@@ -1688,7 +1684,7 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
1688
1684
  );
1689
1685
  }
1690
1686
  } else {
1691
- throw new Error('Unsupported platform');
1687
+ throw unsupportedPlatformError();
1692
1688
  }
1693
1689
 
1694
1690
  const unifiedRequest: NitroPurchaseRequest = {};
@@ -1723,6 +1719,22 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
1723
1719
  if (iosRequest.advancedCommerceData) {
1724
1720
  iosPayload.advancedCommerceData = iosRequest.advancedCommerceData;
1725
1721
  }
1722
+ if (isSubs) {
1723
+ const subscriptionRequest = iosRequest as RequestSubscriptionIosProps;
1724
+ if (
1725
+ subscriptionRequest.introductoryOfferEligibility !== undefined
1726
+ ) {
1727
+ iosPayload.introductoryOfferEligibility =
1728
+ subscriptionRequest.introductoryOfferEligibility;
1729
+ }
1730
+ if (subscriptionRequest.promotionalOfferJWS) {
1731
+ iosPayload.promotionalOfferJWS =
1732
+ subscriptionRequest.promotionalOfferJWS;
1733
+ }
1734
+ if (subscriptionRequest.winBackOffer) {
1735
+ iosPayload.winBackOffer = subscriptionRequest.winBackOffer;
1736
+ }
1737
+ }
1726
1738
 
1727
1739
  unifiedRequest.ios = iosPayload;
1728
1740
  }
@@ -1820,7 +1832,7 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
1820
1832
  * @remarks **Critical:** Android purchases must be finalized within 3 days or Google
1821
1833
  * auto-refunds. iOS unfinished transactions replay on every app launch.
1822
1834
  *
1823
- * @see {@link https://www.openiap.dev/docs/apis/finish-transaction}
1835
+ * @see {@link https://openiap.dev/docs/apis/finish-transaction}
1824
1836
  */
1825
1837
  export const finishTransaction: MutationField<'finishTransaction'> = async (
1826
1838
  args,
@@ -1851,7 +1863,7 @@ export const finishTransaction: MutationField<'finishTransaction'> = async (
1851
1863
  },
1852
1864
  };
1853
1865
  } else {
1854
- throw new Error('Unsupported platform');
1866
+ throw unsupportedPlatformError();
1855
1867
  }
1856
1868
 
1857
1869
  const result = await IAP.instance.finishTransaction(params);
@@ -1889,7 +1901,7 @@ export const finishTransaction: MutationField<'finishTransaction'> = async (
1889
1901
  * await acknowledgePurchaseAndroid('purchase_token_here');
1890
1902
  * ```
1891
1903
  *
1892
- * @see {@link https://www.openiap.dev/docs/apis/android/acknowledge-purchase-android}
1904
+ * @see {@link https://openiap.dev/docs/apis/android/acknowledge-purchase-android}
1893
1905
  */
1894
1906
  export const acknowledgePurchaseAndroid: MutationField<
1895
1907
  'acknowledgePurchaseAndroid'
@@ -1930,7 +1942,7 @@ export const acknowledgePurchaseAndroid: MutationField<
1930
1942
  * await consumePurchaseAndroid('purchase_token_here');
1931
1943
  * ```
1932
1944
  *
1933
- * @see {@link https://www.openiap.dev/docs/apis/android/consume-purchase-android}
1945
+ * @see {@link https://openiap.dev/docs/apis/android/consume-purchase-android}
1934
1946
  */
1935
1947
  export const consumePurchaseAndroid: MutationField<
1936
1948
  'consumePurchaseAndroid'
@@ -1987,7 +1999,7 @@ export const consumePurchaseAndroid: MutationField<
1987
1999
  * });
1988
2000
  * ```
1989
2001
  *
1990
- * @see {@link https://www.openiap.dev/docs/apis/validate-receipt}
2002
+ * @see {@link https://openiap.dev/docs/apis/validate-receipt}
1991
2003
  */
1992
2004
  export const validateReceipt: MutationField<'validateReceipt'> = async (
1993
2005
  options,
@@ -2118,7 +2130,7 @@ export const validateReceipt: MutationField<'validateReceipt'> = async (
2118
2130
  * @param options - Receipt validation options containing the SKU
2119
2131
  * @returns Promise resolving to receipt validation result
2120
2132
  *
2121
- * @see {@link https://www.openiap.dev/docs/features/validation#verify-purchase}
2133
+ * @see {@link https://openiap.dev/docs/features/validation#verify-purchase}
2122
2134
  */
2123
2135
  export const verifyPurchase: MutationField<'verifyPurchase'> = validateReceipt;
2124
2136
 
@@ -2129,7 +2141,7 @@ export const verifyPurchase: MutationField<'verifyPurchase'> = validateReceipt;
2129
2141
  * consumers who imported `validateReceiptIOS` — which is still declared on the
2130
2142
  * OpenIAP Query interface — keep working. Throws on non-iOS platforms.
2131
2143
  *
2132
- * @see {@link https://www.openiap.dev/docs/apis/ios/validate-receipt-ios}
2144
+ * @see {@link https://openiap.dev/docs/apis/ios/validate-receipt-ios}
2133
2145
  */
2134
2146
  export const validateReceiptIOS: QueryField<'validateReceiptIOS'> = async (
2135
2147
  options,
@@ -2162,7 +2174,7 @@ export const validateReceiptIOS: QueryField<'validateReceiptIOS'> = async (
2162
2174
  * });
2163
2175
  * ```
2164
2176
  *
2165
- * @see {@link https://www.openiap.dev/docs/features/validation#verify-purchase-with-provider}
2177
+ * @see {@link https://openiap.dev/docs/features/validation#verify-purchase-with-provider}
2166
2178
  */
2167
2179
  export const verifyPurchaseWithProvider: MutationField<
2168
2180
  'verifyPurchaseWithProvider'
@@ -2207,7 +2219,7 @@ export const verifyPurchaseWithProvider: MutationField<
2207
2219
  * @returns Promise<boolean>
2208
2220
  * @platform iOS
2209
2221
  *
2210
- * @see {@link https://www.openiap.dev/docs/apis/ios/sync-ios}
2222
+ * @see {@link https://openiap.dev/docs/apis/ios/sync-ios}
2211
2223
  */
2212
2224
  export const syncIOS: MutationField<'syncIOS'> = async () => {
2213
2225
  if (Platform.OS !== 'ios') {
@@ -2234,7 +2246,7 @@ export const syncIOS: MutationField<'syncIOS'> = async () => {
2234
2246
  * @returns Promise<boolean> - Indicates whether the redemption sheet was presented
2235
2247
  * @platform iOS
2236
2248
  *
2237
- * @see {@link https://www.openiap.dev/docs/apis/ios/present-code-redemption-sheet-ios}
2249
+ * @see {@link https://openiap.dev/docs/apis/ios/present-code-redemption-sheet-ios}
2238
2250
  */
2239
2251
  export const presentCodeRedemptionSheetIOS: MutationField<
2240
2252
  'presentCodeRedemptionSheetIOS'
@@ -2278,7 +2290,7 @@ export const presentCodeRedemptionSheetIOS: MutationField<
2278
2290
  * @returns Promise<boolean> - true when the request triggers successfully
2279
2291
  * @platform iOS
2280
2292
  *
2281
- * @see {@link https://www.openiap.dev/docs/apis/ios/request-purchase-on-promoted-product-ios}
2293
+ * @see {@link https://openiap.dev/docs/apis/ios/request-purchase-on-promoted-product-ios}
2282
2294
  */
2283
2295
  export const requestPurchaseOnPromotedProductIOS =
2284
2296
  async (): Promise<boolean> => {
@@ -2322,7 +2334,7 @@ export const requestPurchaseOnPromotedProductIOS =
2322
2334
  * @returns Promise<boolean>
2323
2335
  * @platform iOS
2324
2336
  *
2325
- * @see {@link https://www.openiap.dev/docs/apis/ios/clear-transaction-ios}
2337
+ * @see {@link https://openiap.dev/docs/apis/ios/clear-transaction-ios}
2326
2338
  */
2327
2339
  export const clearTransactionIOS: MutationField<
2328
2340
  'clearTransactionIOS'
@@ -2352,7 +2364,7 @@ export const clearTransactionIOS: MutationField<
2352
2364
  * @returns Promise<string | null> - The refund status or null if not available
2353
2365
  * @platform iOS
2354
2366
  *
2355
- * @see {@link https://www.openiap.dev/docs/apis/ios/begin-refund-request-ios}
2367
+ * @see {@link https://openiap.dev/docs/apis/ios/begin-refund-request-ios}
2356
2368
  */
2357
2369
  export const beginRefundRequestIOS: MutationField<
2358
2370
  'beginRefundRequestIOS'
@@ -2380,7 +2392,7 @@ export const beginRefundRequestIOS: MutationField<
2380
2392
  * Deeplinks to native interface that allows users to manage their subscriptions
2381
2393
  * Cross-platform alias aligning with expo-iap
2382
2394
  *
2383
- * @see {@link https://www.openiap.dev/docs/apis/deep-link-to-subscriptions}
2395
+ * @see {@link https://openiap.dev/docs/apis/deep-link-to-subscriptions}
2384
2396
  */
2385
2397
  export const deepLinkToSubscriptions: MutationField<
2386
2398
  'deepLinkToSubscriptions'
@@ -2395,16 +2407,15 @@ export const deepLinkToSubscriptions: MutationField<
2395
2407
  return;
2396
2408
  }
2397
2409
  if (Platform.OS === 'ios') {
2398
- try {
2399
- if (typeof IAP.instance.deepLinkToSubscriptionsIOS === 'function') {
2400
- await IAP.instance.deepLinkToSubscriptionsIOS();
2401
- } else {
2402
- await IAP.instance.showManageSubscriptionsIOS();
2403
- }
2404
- } catch (error) {
2405
- RnIapConsole.warn('[deepLinkToSubscriptions] Failed on iOS:', error);
2410
+ if (typeof IAP.instance.deepLinkToSubscriptionsIOS === 'function') {
2411
+ await IAP.instance.deepLinkToSubscriptionsIOS();
2412
+ } else {
2413
+ await IAP.instance.showManageSubscriptionsIOS();
2406
2414
  }
2415
+ return;
2407
2416
  }
2417
+
2418
+ throw unsupportedPlatformError();
2408
2419
  };
2409
2420
 
2410
2421
  export const deepLinkToSubscriptionsIOS = async (): Promise<boolean> => {
@@ -2443,7 +2454,7 @@ export const deepLinkToSubscriptionsIOS = async (): Promise<boolean> => {
2443
2454
  * @param subscriptionIds - Optional array of subscription IDs to filter by
2444
2455
  * @returns Promise<ActiveSubscription[]> - Array of active subscriptions
2445
2456
  *
2446
- * @see {@link https://www.openiap.dev/docs/apis/get-active-subscriptions}
2457
+ * @see {@link https://openiap.dev/docs/apis/get-active-subscriptions}
2447
2458
  */
2448
2459
  export const getActiveSubscriptions: QueryField<
2449
2460
  'getActiveSubscriptions'
@@ -2469,7 +2480,7 @@ export const getActiveSubscriptions: QueryField<
2469
2480
  environmentIOS: sub.environmentIOS ?? null,
2470
2481
  willExpireSoon: sub.willExpireSoon ?? null,
2471
2482
  daysUntilExpirationIOS: sub.daysUntilExpirationIOS ?? null,
2472
- // 🆕 renewalInfoIOS - subscription lifecycle information (iOS only)
2483
+ // renewalInfoIOS contains subscription lifecycle information on iOS.
2473
2484
  renewalInfoIOS: sub.renewalInfoIOS
2474
2485
  ? {
2475
2486
  willAutoRenew: sub.renewalInfoIOS.willAutoRenew ?? false,
@@ -2512,90 +2523,6 @@ export const getActiveSubscriptions: QueryField<
2512
2523
  }
2513
2524
  };
2514
2525
 
2515
- // OLD IMPLEMENTATION - REPLACED WITH NATIVE CALL
2516
- /*
2517
- export const getActiveSubscriptions_OLD: QueryField<
2518
- 'getActiveSubscriptions'
2519
- > = async (subscriptionIds) => {
2520
- try {
2521
- // Get all available purchases first
2522
- const allPurchases = await getAvailablePurchases();
2523
-
2524
- // For the critical bug fix: this function was previously returning ALL purchases
2525
- // Now we properly filter for subscriptions only
2526
-
2527
- // In production with real data, Android subscription filtering is done via platform-specific calls
2528
- // But for backward compatibility and test support, we also check platform-specific fields
2529
-
2530
- // Since expirationDateIOS and subscriptionGroupIdIOS are not available in NitroPurchase,
2531
- // we need to rely on other indicators or assume all purchases are subscriptions
2532
- // when called from getActiveSubscriptions
2533
- const purchases = allPurchases;
2534
-
2535
- // Filter for subscriptions and map to ActiveSubscription format
2536
- const subscriptions = purchases
2537
- .filter((purchase) => {
2538
- // Filter by subscription IDs if provided
2539
- if (subscriptionIds && subscriptionIds.length > 0) {
2540
- return subscriptionIds.includes(purchase.productId);
2541
- }
2542
- return true;
2543
- })
2544
- .map((purchase): ActiveSubscription => {
2545
- // Safe access to platform-specific fields with type guards
2546
- const expirationDateIOS =
2547
- 'expirationDateIOS' in purchase
2548
- ? ((purchase as PurchaseIOS).expirationDateIOS ?? null)
2549
- : null;
2550
-
2551
- const environmentIOS =
2552
- 'environmentIOS' in purchase
2553
- ? ((purchase as PurchaseIOS).environmentIOS ?? null)
2554
- : null;
2555
-
2556
- const autoRenewingAndroid =
2557
- 'autoRenewingAndroid' in purchase || 'isAutoRenewing' in purchase
2558
- ? ((purchase as PurchaseAndroid).autoRenewingAndroid ??
2559
- (purchase as PurchaseAndroid).isAutoRenewing) // deprecated - use isAutoRenewing instead
2560
- : null;
2561
-
2562
- // 🆕 Extract renewalInfoIOS if available
2563
- const renewalInfoIOS =
2564
- 'renewalInfoIOS' in purchase
2565
- ? ((purchase as PurchaseIOS).renewalInfoIOS ?? null)
2566
- : null;
2567
-
2568
- return {
2569
- productId: purchase.productId,
2570
- isActive: true, // If it's in availablePurchases, it's active
2571
- // Backend validation fields - use transactionId ?? id for proper field mapping
2572
- transactionId: purchase.transactionId ?? purchase.id,
2573
- purchaseToken: purchase.purchaseToken,
2574
- transactionDate: purchase.transactionDate,
2575
- // Platform-specific fields
2576
- expirationDateIOS,
2577
- autoRenewingAndroid,
2578
- environmentIOS,
2579
- renewalInfoIOS,
2580
- // Convenience fields
2581
- willExpireSoon: false, // Would need to calculate based on expiration date
2582
- daysUntilExpirationIOS:
2583
- expirationDateIOS != null
2584
- ? Math.ceil(
2585
- (expirationDateIOS - Date.now()) / (1000 * 60 * 60 * 24),
2586
- )
2587
- : null,
2588
- };
2589
- });
2590
-
2591
- return subscriptions;
2592
- } catch (error) {
2593
- RnIapConsole.error('Failed to get active subscriptions:', error);
2594
- const errorJson = parseErrorStringToJsonObj(error);
2595
- throw new Error(errorJson.message);
2596
- }
2597
- };
2598
-
2599
2526
  /**
2600
2527
  * Check if the user has any active subscriptions (OpenIAP compliant)
2601
2528
  * Returns true if the user has at least one active subscription, false otherwise.
@@ -2604,7 +2531,7 @@ export const getActiveSubscriptions_OLD: QueryField<
2604
2531
  * @param subscriptionIds - Optional array of subscription IDs to check
2605
2532
  * @returns Promise<boolean> - True if there are active subscriptions
2606
2533
  *
2607
- * @see {@link https://www.openiap.dev/docs/apis/has-active-subscriptions}
2534
+ * @see {@link https://openiap.dev/docs/apis/has-active-subscriptions}
2608
2535
  */
2609
2536
  export const hasActiveSubscriptions: QueryField<
2610
2537
  'hasActiveSubscriptions'
@@ -2733,7 +2660,7 @@ const normalizeProductQueryType = (
2733
2660
  * }
2734
2661
  * ```
2735
2662
  *
2736
- * @see {@link https://www.openiap.dev/docs/apis/android/check-alternative-billing-availability-android}
2663
+ * @see {@link https://openiap.dev/docs/apis/android/check-alternative-billing-availability-android}
2737
2664
  */
2738
2665
  export const checkAlternativeBillingAvailabilityAndroid: MutationField<
2739
2666
  'checkAlternativeBillingAvailabilityAndroid'
@@ -2775,7 +2702,7 @@ export const checkAlternativeBillingAvailabilityAndroid: MutationField<
2775
2702
  * }
2776
2703
  * ```
2777
2704
  *
2778
- * @see {@link https://www.openiap.dev/docs/apis/android/show-alternative-billing-dialog-android}
2705
+ * @see {@link https://openiap.dev/docs/apis/android/show-alternative-billing-dialog-android}
2779
2706
  */
2780
2707
  export const showAlternativeBillingDialogAndroid: MutationField<
2781
2708
  'showAlternativeBillingDialogAndroid'
@@ -2814,7 +2741,7 @@ export const showAlternativeBillingDialogAndroid: MutationField<
2814
2741
  * }
2815
2742
  * ```
2816
2743
  *
2817
- * @see {@link https://www.openiap.dev/docs/apis/android/create-alternative-billing-token-android}
2744
+ * @see {@link https://openiap.dev/docs/apis/android/create-alternative-billing-token-android}
2818
2745
  */
2819
2746
  export const createAlternativeBillingTokenAndroid: MutationField<
2820
2747
  'createAlternativeBillingTokenAndroid'
@@ -2830,40 +2757,6 @@ export const createAlternativeBillingTokenAndroid: MutationField<
2830
2757
  }
2831
2758
  };
2832
2759
 
2833
- /**
2834
- * Parameters for launching an external link (Android 8.2.0+).
2835
- */
2836
- export interface LaunchExternalLinkParamsAndroid {
2837
- /** The billing program (external-content-link or external-offer) */
2838
- billingProgram: BillingProgramAndroid;
2839
- /** The external link launch mode */
2840
- launchMode: ExternalLinkLaunchModeAndroid;
2841
- /** The type of the external link */
2842
- linkType: ExternalLinkTypeAndroid;
2843
- /** The URI where the content will be accessed from */
2844
- linkUri: string;
2845
- }
2846
-
2847
- /**
2848
- * Result of checking billing program availability (Android 8.2.0+).
2849
- */
2850
- export interface BillingProgramAvailabilityResultAndroid {
2851
- /** The billing program that was checked */
2852
- billingProgram: BillingProgramAndroid;
2853
- /** Whether the billing program is available for the user */
2854
- isAvailable: boolean;
2855
- }
2856
-
2857
- /**
2858
- * Reporting details for external transactions (Android 8.2.0+).
2859
- */
2860
- export interface BillingProgramReportingDetailsAndroid {
2861
- /** The billing program that the reporting details are associated with */
2862
- billingProgram: BillingProgramAndroid;
2863
- /** External transaction token used to report transactions to Google */
2864
- externalTransactionToken: string;
2865
- }
2866
-
2867
2760
  /**
2868
2761
  * Enable a billing program before initConnection (Android only).
2869
2762
  * Must be called BEFORE initConnection() to configure the BillingClient.
@@ -2889,7 +2782,7 @@ export const enableBillingProgramAndroid = (
2889
2782
  return;
2890
2783
  }
2891
2784
  try {
2892
- IAP.instance.enableBillingProgramAndroid(program as any);
2785
+ IAP.instance.enableBillingProgramAndroid(program);
2893
2786
  } catch (error) {
2894
2787
  RnIapConsole.error('Failed to enable billing program:', error);
2895
2788
  }
@@ -2911,7 +2804,7 @@ export const enableBillingProgramAndroid = (
2911
2804
  * }
2912
2805
  * ```
2913
2806
  *
2914
- * @see {@link https://www.openiap.dev/docs/apis/android/is-billing-program-available-android}
2807
+ * @see {@link https://openiap.dev/docs/apis/android/is-billing-program-available-android}
2915
2808
  */
2916
2809
  export const isBillingProgramAvailableAndroid: MutationField<
2917
2810
  'isBillingProgramAvailableAndroid'
@@ -2920,9 +2813,7 @@ export const isBillingProgramAvailableAndroid: MutationField<
2920
2813
  throw new Error('Billing Programs API is only supported on Android');
2921
2814
  }
2922
2815
  try {
2923
- const result = await IAP.instance.isBillingProgramAvailableAndroid(
2924
- program as any,
2925
- );
2816
+ const result = await IAP.instance.isBillingProgramAvailableAndroid(program);
2926
2817
  return {
2927
2818
  billingProgram: result.billingProgram as unknown as BillingProgramAndroid,
2928
2819
  isAvailable: result.isAvailable,
@@ -2952,7 +2843,7 @@ export const isBillingProgramAvailableAndroid: MutationField<
2952
2843
  * });
2953
2844
  * ```
2954
2845
  *
2955
- * @see {@link https://www.openiap.dev/docs/apis/android/create-billing-program-reporting-details-android}
2846
+ * @see {@link https://openiap.dev/docs/apis/android/create-billing-program-reporting-details-android}
2956
2847
  */
2957
2848
  export const createBillingProgramReportingDetailsAndroid: MutationField<
2958
2849
  'createBillingProgramReportingDetailsAndroid'
@@ -2962,9 +2853,7 @@ export const createBillingProgramReportingDetailsAndroid: MutationField<
2962
2853
  }
2963
2854
  try {
2964
2855
  const result =
2965
- await IAP.instance.createBillingProgramReportingDetailsAndroid(
2966
- program as any,
2967
- );
2856
+ await IAP.instance.createBillingProgramReportingDetailsAndroid(program);
2968
2857
  return {
2969
2858
  billingProgram: result.billingProgram as unknown as BillingProgramAndroid,
2970
2859
  externalTransactionToken: result.externalTransactionToken,
@@ -2999,7 +2888,7 @@ export const createBillingProgramReportingDetailsAndroid: MutationField<
2999
2888
  * }
3000
2889
  * ```
3001
2890
  *
3002
- * @see {@link https://www.openiap.dev/docs/apis/android/launch-external-link-android}
2891
+ * @see {@link https://openiap.dev/docs/apis/android/launch-external-link-android}
3003
2892
  */
3004
2893
  export const launchExternalLinkAndroid: MutationField<
3005
2894
  'launchExternalLinkAndroid'
@@ -3009,9 +2898,9 @@ export const launchExternalLinkAndroid: MutationField<
3009
2898
  }
3010
2899
  try {
3011
2900
  return await IAP.instance.launchExternalLinkAndroid({
3012
- billingProgram: params.billingProgram as any,
3013
- launchMode: params.launchMode as any,
3014
- linkType: params.linkType as any,
2901
+ billingProgram: params.billingProgram,
2902
+ launchMode: params.launchMode,
2903
+ linkType: params.linkType,
3015
2904
  linkUri: params.linkUri,
3016
2905
  });
3017
2906
  } catch (error) {
@@ -3043,7 +2932,7 @@ export const launchExternalLinkAndroid: MutationField<
3043
2932
  * }
3044
2933
  * ```
3045
2934
  *
3046
- * @see {@link https://www.openiap.dev/docs/apis/ios/can-present-external-purchase-notice-ios}
2935
+ * @see {@link https://openiap.dev/docs/apis/ios/can-present-external-purchase-notice-ios}
3047
2936
  */
3048
2937
  export const canPresentExternalPurchaseNoticeIOS: QueryField<
3049
2938
  'canPresentExternalPurchaseNoticeIOS'
@@ -3078,7 +2967,7 @@ export const canPresentExternalPurchaseNoticeIOS: QueryField<
3078
2967
  * }
3079
2968
  * ```
3080
2969
  *
3081
- * @see {@link https://www.openiap.dev/docs/apis/ios/present-external-purchase-notice-sheet-ios}
2970
+ * @see {@link https://openiap.dev/docs/apis/ios/present-external-purchase-notice-sheet-ios}
3082
2971
  */
3083
2972
  export const presentExternalPurchaseNoticeSheetIOS =
3084
2973
  async (): Promise<ExternalPurchaseNoticeResultIOS> => {
@@ -3111,7 +3000,7 @@ export const presentExternalPurchaseNoticeSheetIOS =
3111
3000
  * }
3112
3001
  * ```
3113
3002
  *
3114
- * @see {@link https://www.openiap.dev/docs/apis/ios/present-external-purchase-link-ios}
3003
+ * @see {@link https://openiap.dev/docs/apis/ios/present-external-purchase-link-ios}
3115
3004
  */
3116
3005
  export const presentExternalPurchaseLinkIOS: MutationField<
3117
3006
  'presentExternalPurchaseLinkIOS'
@@ -3120,7 +3009,7 @@ export const presentExternalPurchaseLinkIOS: MutationField<
3120
3009
  throw new Error('External purchase is only supported on iOS');
3121
3010
  }
3122
3011
  try {
3123
- return (await IAP.instance.presentExternalPurchaseLinkIOS(url)) as any;
3012
+ return await IAP.instance.presentExternalPurchaseLinkIOS(url);
3124
3013
  } catch (error) {
3125
3014
  RnIapConsole.error('Failed to present external purchase link:', error);
3126
3015
  throw error;
@@ -3147,7 +3036,7 @@ export const presentExternalPurchaseLinkIOS: MutationField<
3147
3036
  * }
3148
3037
  * ```
3149
3038
  *
3150
- * @see {@link https://www.openiap.dev/docs/apis/ios/is-eligible-for-external-purchase-custom-link-ios}
3039
+ * @see {@link https://openiap.dev/docs/apis/ios/is-eligible-for-external-purchase-custom-link-ios}
3151
3040
  */
3152
3041
  export const isEligibleForExternalPurchaseCustomLinkIOS =
3153
3042
  async (): Promise<boolean> => {
@@ -3184,7 +3073,7 @@ export const isEligibleForExternalPurchaseCustomLinkIOS =
3184
3073
  * }
3185
3074
  * ```
3186
3075
  *
3187
- * @see {@link https://www.openiap.dev/docs/apis/ios/get-external-purchase-custom-link-token-ios}
3076
+ * @see {@link https://openiap.dev/docs/apis/ios/get-external-purchase-custom-link-token-ios}
3188
3077
  */
3189
3078
  export const getExternalPurchaseCustomLinkTokenIOS = async (
3190
3079
  tokenType: ExternalPurchaseCustomLinkTokenTypeIOS,
@@ -3224,7 +3113,7 @@ export const getExternalPurchaseCustomLinkTokenIOS = async (
3224
3113
  * }
3225
3114
  * ```
3226
3115
  *
3227
- * @see {@link https://www.openiap.dev/docs/apis/ios/show-external-purchase-custom-link-notice-ios}
3116
+ * @see {@link https://openiap.dev/docs/apis/ios/show-external-purchase-custom-link-notice-ios}
3228
3117
  */
3229
3118
  export const showExternalPurchaseCustomLinkNoticeIOS = async (
3230
3119
  noticeType: ExternalPurchaseCustomLinkNoticeTypeIOS,