react-native-iap 15.2.0 → 15.2.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 (95) hide show
  1. package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +117 -114
  2. package/android/src/main/java/com/margelo/nitro/iap/ProductQueryHelpers.kt +42 -0
  3. package/android/src/test/java/com/margelo/nitro/iap/ProductQueryHelpersTest.kt +140 -0
  4. package/ios/HybridRnIap.swift +33 -0
  5. package/lib/module/hooks/useIAP.js.map +1 -1
  6. package/lib/module/hooks/useWebhookEvents.js +113 -0
  7. package/lib/module/hooks/useWebhookEvents.js.map +1 -0
  8. package/lib/module/index.js +331 -131
  9. package/lib/module/index.js.map +1 -1
  10. package/lib/module/kit-api.js +161 -0
  11. package/lib/module/kit-api.js.map +1 -0
  12. package/lib/module/types.js +16 -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 +6 -0
  16. package/lib/module/utils/errorMapping.js.map +1 -1
  17. package/lib/module/webhook-client.js +164 -0
  18. package/lib/module/webhook-client.js.map +1 -0
  19. package/lib/typescript/plugin/src/withIAP.d.ts +1 -1
  20. package/lib/typescript/src/hooks/useIAP.d.ts +162 -2
  21. package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
  22. package/lib/typescript/src/hooks/useWebhookEvents.d.ts +55 -0
  23. package/lib/typescript/src/hooks/useWebhookEvents.d.ts.map +1 -0
  24. package/lib/typescript/src/index.d.ts +282 -129
  25. package/lib/typescript/src/index.d.ts.map +1 -1
  26. package/lib/typescript/src/kit-api.d.ts +54 -0
  27. package/lib/typescript/src/kit-api.d.ts.map +1 -0
  28. package/lib/typescript/src/specs/RnIap.nitro.d.ts +7 -0
  29. package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
  30. package/lib/typescript/src/types.d.ts +304 -74
  31. package/lib/typescript/src/types.d.ts.map +1 -1
  32. package/lib/typescript/src/utils/error.d.ts +3 -0
  33. package/lib/typescript/src/utils/error.d.ts.map +1 -1
  34. package/lib/typescript/src/utils/errorMapping.d.ts +6 -0
  35. package/lib/typescript/src/utils/errorMapping.d.ts.map +1 -1
  36. package/lib/typescript/src/webhook-client.d.ts +82 -0
  37. package/lib/typescript/src/webhook-client.d.ts.map +1 -0
  38. package/nitrogen/generated/android/NitroIap+autolinking.cmake +3 -0
  39. package/nitrogen/generated/android/c++/JAdvancedCommerceInfoIOS.hpp +118 -0
  40. package/nitrogen/generated/android/c++/JAdvancedCommerceItemDetailsIOS.hpp +62 -0
  41. package/nitrogen/generated/android/c++/JAdvancedCommerceItemIOS.hpp +78 -0
  42. package/nitrogen/generated/android/c++/JAdvancedCommerceRefundIOS.hpp +62 -0
  43. package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +44 -0
  44. package/nitrogen/generated/android/c++/JHybridRnIapSpec.hpp +1 -0
  45. package/nitrogen/generated/android/c++/JPurchase.hpp +11 -0
  46. package/nitrogen/generated/android/c++/JPurchaseIOS.hpp +16 -1
  47. package/nitrogen/generated/android/c++/JRequestPurchaseResult.hpp +11 -0
  48. package/nitrogen/generated/android/c++/JVariant_NullType_AdvancedCommerceInfoIOS.cpp +26 -0
  49. package/nitrogen/generated/android/c++/JVariant_NullType_AdvancedCommerceInfoIOS.hpp +84 -0
  50. package/nitrogen/generated/android/c++/JVariant_NullType_AdvancedCommerceItemDetailsIOS.cpp +26 -0
  51. package/nitrogen/generated/android/c++/JVariant_NullType_AdvancedCommerceItemDetailsIOS.hpp +74 -0
  52. package/nitrogen/generated/android/c++/JVariant_NullType_Array_AdvancedCommerceRefundIOS_.cpp +35 -0
  53. package/nitrogen/generated/android/c++/JVariant_NullType_Array_AdvancedCommerceRefundIOS_.hpp +84 -0
  54. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/AdvancedCommerceInfoIOS.kt +59 -0
  55. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/AdvancedCommerceItemDetailsIOS.kt +38 -0
  56. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/AdvancedCommerceItemIOS.kt +44 -0
  57. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/AdvancedCommerceRefundIOS.kt +38 -0
  58. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/HybridRnIapSpec.kt +4 -0
  59. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/PurchaseIOS.kt +5 -2
  60. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_NullType_AdvancedCommerceInfoIOS.kt +53 -0
  61. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_NullType_AdvancedCommerceItemDetailsIOS.kt +53 -0
  62. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_NullType_Array_AdvancedCommerceRefundIOS_.kt +53 -0
  63. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +166 -0
  64. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +12 -0
  65. package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +20 -0
  66. package/nitrogen/generated/ios/swift/AdvancedCommerceInfoIOS.swift +294 -0
  67. package/nitrogen/generated/ios/swift/AdvancedCommerceItemDetailsIOS.swift +61 -0
  68. package/nitrogen/generated/ios/swift/AdvancedCommerceItemIOS.swift +141 -0
  69. package/nitrogen/generated/ios/swift/AdvancedCommerceRefundIOS.swift +61 -0
  70. package/nitrogen/generated/ios/swift/HybridRnIapSpec.swift +1 -0
  71. package/nitrogen/generated/ios/swift/HybridRnIapSpec_cxx.swift +25 -0
  72. package/nitrogen/generated/ios/swift/PurchaseIOS.swift +39 -2
  73. package/nitrogen/generated/ios/swift/Variant_NullType_AdvancedCommerceInfoIOS.swift +18 -0
  74. package/nitrogen/generated/ios/swift/Variant_NullType_AdvancedCommerceItemDetailsIOS.swift +18 -0
  75. package/nitrogen/generated/ios/swift/Variant_NullType__AdvancedCommerceRefundIOS_.swift +18 -0
  76. package/nitrogen/generated/shared/c++/AdvancedCommerceInfoIOS.hpp +117 -0
  77. package/nitrogen/generated/shared/c++/AdvancedCommerceItemDetailsIOS.hpp +86 -0
  78. package/nitrogen/generated/shared/c++/AdvancedCommerceItemIOS.hpp +99 -0
  79. package/nitrogen/generated/shared/c++/AdvancedCommerceRefundIOS.hpp +86 -0
  80. package/nitrogen/generated/shared/c++/HybridRnIapSpec.cpp +1 -0
  81. package/nitrogen/generated/shared/c++/HybridRnIapSpec.hpp +1 -0
  82. package/nitrogen/generated/shared/c++/PurchaseIOS.hpp +9 -2
  83. package/openiap-versions.json +3 -3
  84. package/package.json +1 -1
  85. package/plugin/build/withIAP.d.ts +1 -1
  86. package/plugin/src/withIAP.ts +1 -1
  87. package/src/hooks/useIAP.ts +162 -2
  88. package/src/hooks/useWebhookEvents.ts +180 -0
  89. package/src/index.ts +348 -130
  90. package/src/kit-api.ts +225 -0
  91. package/src/specs/RnIap.nitro.ts +8 -0
  92. package/src/types.ts +314 -74
  93. package/src/utils/error.ts +3 -0
  94. package/src/utils/errorMapping.ts +12 -0
  95. package/src/webhook-client.ts +312 -0
@@ -39,7 +39,9 @@ const toErrorMessage = error => {
39
39
 
40
40
  // Export hooks
41
41
  export { useIAP } from "./hooks/useIAP.js";
42
-
42
+ export { useWebhookEvents } from "./hooks/useWebhookEvents.js";
43
+ export { connectWebhookStream, parseWebhookEventData } from "./webhook-client.js";
44
+ export { kitApi, KitApiError } from "./kit-api.js";
43
45
  // Restore completed transactions (cross-platform)
44
46
  // Development utilities removed - use type bridge functions directly if needed
45
47
 
@@ -467,20 +469,28 @@ export const subscriptionBillingIssueListener = listener => {
467
469
  // ------------------------------
468
470
 
469
471
  /**
470
- * Fetch products from the store
471
- * @param params - Product request configuration
472
- * @param params.skus - Array of product SKUs to fetch
473
- * @param params.type - Optional filter: 'in-app' (default) for products, 'subs' for subscriptions, or 'all' for both.
474
- * @returns Promise<Product[]> - Array of products from the store
472
+ * Retrieve products or subscriptions from the store by SKU.
475
473
  *
476
- * @example
477
- * ```typescript
478
- * // Regular products
479
- * const products = await fetchProducts({ skus: ['product1', 'product2'] });
474
+ * @param request `ProductRequest` — `skus` (string[]) and optional `type`
475
+ * (`'in-app' | 'subs' | 'all'`, defaults to `'in-app'`).
476
+ * @returns Promise resolving to a `FetchProductsResult` union — `Product[]` for `'in-app'`,
477
+ * `ProductSubscription[]` for `'subs'`, a mixed array for `'all'`, or `null`
478
+ * (the schema retains the nullable branch for backwards compatibility).
479
+ * @throws When the store rejects the request (empty `skus`, not connected,
480
+ * network/store error). Unknown SKUs are simply omitted from the result, not thrown.
480
481
  *
481
- * // Subscriptions
482
- * const subscriptions = await fetchProducts({ skus: ['sub1', 'sub2'], type: 'subs' });
482
+ * @example
483
+ * ```ts
484
+ * const products = await fetchProducts({
485
+ * skus: ['com.app.coins_100', 'com.app.premium'],
486
+ * type: 'in-app',
487
+ * });
483
488
  * ```
489
+ *
490
+ * @remarks This is a regular promise-based call. Don't confuse with `request*` APIs
491
+ * (`requestPurchase`), which are event-based.
492
+ *
493
+ * @see {@link https://www.openiap.dev/docs/apis/fetch-products}
484
494
  */
485
495
  export const fetchProducts = async request => {
486
496
  const {
@@ -554,22 +564,40 @@ export const fetchProducts = async request => {
554
564
  return convertedProducts;
555
565
  } catch (error) {
556
566
  RnIapConsole.error('[fetchProducts] Failed:', error);
557
- throw error;
567
+ const parsedError = parseErrorStringToJsonObj(error);
568
+ throw createPurchaseError({
569
+ code: parsedError.code,
570
+ message: parsedError.message,
571
+ responseCode: parsedError.responseCode,
572
+ debugMessage: parsedError.debugMessage,
573
+ productId: parsedError.productId,
574
+ productIds: parsedError.productIds,
575
+ productType: parsedError.productType,
576
+ isEmptyProductList: parsedError.isEmptyProductList,
577
+ platform: Platform.OS === 'ios' ? 'ios' : 'android'
578
+ });
558
579
  }
559
580
  };
560
581
 
561
582
  /**
562
- * Get available purchases (purchased items not yet consumed/finished)
563
- * @param params - Options for getting available purchases
564
- * @param params.alsoPublishToEventListener - Whether to also publish to event listener
565
- * @param params.onlyIncludeActiveItems - Whether to only include active items
583
+ * List the user's unfinished purchases non-consumables, active subscriptions, and any
584
+ * pending transactions not yet finished.
585
+ *
586
+ * @param options Optional `PurchaseOptions`.
587
+ * - iOS: `alsoPublishToEventListenerIOS`, `onlyIncludeActiveItemsIOS`.
588
+ * - Android: `includeSuspendedAndroid` (include subscriptions in a paused/grace state).
589
+ * @returns Promise resolving to an array of `Purchase` currently held by the store.
590
+ * @throws When the platform query fails.
566
591
  *
567
592
  * @example
568
- * ```typescript
569
- * const purchases = await getAvailablePurchases({
570
- * onlyIncludeActiveItemsIOS: true
571
- * });
593
+ * ```ts
594
+ * const purchases = await getAvailablePurchases();
595
+ * for (const p of purchases) {
596
+ * if (await verifyOnServer(p)) await finishTransaction({ purchase: p, isConsumable: false });
597
+ * }
572
598
  * ```
599
+ *
600
+ * @see {@link https://www.openiap.dev/docs/apis/get-available-purchases}
573
601
  */
574
602
  export const getAvailablePurchases = async options => {
575
603
  const alsoPublishToEventListenerIOS = Boolean(options?.alsoPublishToEventListenerIOS ?? false);
@@ -626,6 +654,8 @@ export const getAvailablePurchases = async options => {
626
654
  * Request the promoted product from the App Store (iOS only)
627
655
  * @returns Promise<Product | null> - The promoted product or null if none available
628
656
  * @platform iOS
657
+ *
658
+ * @see {@link https://www.openiap.dev/docs/apis/ios/get-promoted-product-ios}
629
659
  */
630
660
  export const getPromotedProductIOS = async () => {
631
661
  if (Platform.OS !== 'ios') {
@@ -650,6 +680,20 @@ export const getPromotedProductIOS = async () => {
650
680
  }
651
681
  };
652
682
  export const requestPromotedProductIOS = getPromotedProductIOS;
683
+
684
+ /**
685
+ * Get the storefront identifier for the user's App Store account (iOS only)
686
+ * @returns Promise<string> - The storefront identifier (e.g., 'USA' for United States)
687
+ * @platform iOS
688
+ *
689
+ * @example
690
+ * ```typescript
691
+ * const storefront = await getStorefrontIOS();
692
+ * console.log('User storefront:', storefront); // e.g., 'USA', 'GBR', 'KOR'
693
+ * ```
694
+ *
695
+ * @see {@link https://www.openiap.dev/docs/apis/ios/get-storefront-ios}
696
+ */
653
697
  export const getStorefrontIOS = async () => {
654
698
  if (Platform.OS !== 'ios') {
655
699
  throw new Error('getStorefrontIOS is only available on iOS');
@@ -662,6 +706,12 @@ export const getStorefrontIOS = async () => {
662
706
  throw error;
663
707
  }
664
708
  };
709
+
710
+ /**
711
+ * Return the user's storefront country code.
712
+ *
713
+ * @see {@link https://www.openiap.dev/docs/apis/get-storefront}
714
+ */
665
715
  export const getStorefront = async () => {
666
716
  if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
667
717
  RnIapConsole.warn('[getStorefront] Storefront lookup is only supported on iOS and Android.');
@@ -683,6 +733,28 @@ export const getStorefront = async () => {
683
733
  throw error;
684
734
  }
685
735
  };
736
+
737
+ /**
738
+ * iOS only - Gets the original app transaction ID if the app was purchased from the App Store
739
+ * @platform iOS
740
+ * @description
741
+ * This function retrieves the original app transaction information if the app was purchased
742
+ * from the App Store. Returns null if the app was not purchased (e.g., free app or TestFlight).
743
+ *
744
+ * @returns {Promise<string | null>} The original app transaction ID or null
745
+ *
746
+ * @example
747
+ * ```typescript
748
+ * const appTransaction = await getAppTransactionIOS();
749
+ * if (appTransaction) {
750
+ * console.log('App was purchased, transaction ID:', appTransaction);
751
+ * } else {
752
+ * console.log('App was not purchased from App Store');
753
+ * }
754
+ * ```
755
+ *
756
+ * @see {@link https://www.openiap.dev/docs/apis/ios/get-app-transaction-ios}
757
+ */
686
758
  export const getAppTransactionIOS = async () => {
687
759
  if (Platform.OS !== 'ios') {
688
760
  throw new Error('getAppTransactionIOS is only available on iOS');
@@ -708,6 +780,16 @@ export const getAppTransactionIOS = async () => {
708
780
  throw error;
709
781
  }
710
782
  };
783
+
784
+ /**
785
+ * Get subscription status for a product (iOS only)
786
+ * @param sku - The product SKU
787
+ * @returns Promise<SubscriptionStatusIOS[]> - Array of subscription status objects
788
+ * @throws Error when called on non-iOS platforms or when IAP is not initialized
789
+ * @platform iOS
790
+ *
791
+ * @see {@link https://www.openiap.dev/docs/apis/ios/subscription-status-ios}
792
+ */
711
793
  export const subscriptionStatusIOS = async sku => {
712
794
  if (Platform.OS !== 'ios') {
713
795
  throw new Error('subscriptionStatusIOS is only available on iOS');
@@ -727,6 +809,15 @@ export const subscriptionStatusIOS = async sku => {
727
809
  });
728
810
  }
729
811
  };
812
+
813
+ /**
814
+ * Get current entitlement for a product (iOS only)
815
+ * @param sku - The product SKU
816
+ * @returns Promise<Purchase | null> - Current entitlement or null
817
+ * @platform iOS
818
+ *
819
+ * @see {@link https://www.openiap.dev/docs/apis/ios/current-entitlement-ios}
820
+ */
730
821
  export const currentEntitlementIOS = async sku => {
731
822
  if (Platform.OS !== 'ios') {
732
823
  return null;
@@ -749,6 +840,15 @@ export const currentEntitlementIOS = async sku => {
749
840
  });
750
841
  }
751
842
  };
843
+
844
+ /**
845
+ * Get latest transaction for a product (iOS only)
846
+ * @param sku - The product SKU
847
+ * @returns Promise<Purchase | null> - Latest transaction or null
848
+ * @platform iOS
849
+ *
850
+ * @see {@link https://www.openiap.dev/docs/apis/ios/latest-transaction-ios}
851
+ */
752
852
  export const latestTransactionIOS = async sku => {
753
853
  if (Platform.OS !== 'ios') {
754
854
  return null;
@@ -771,6 +871,14 @@ export const latestTransactionIOS = async sku => {
771
871
  });
772
872
  }
773
873
  };
874
+
875
+ /**
876
+ * Get pending transactions (iOS only)
877
+ * @returns Promise<Purchase[]> - Array of pending transactions
878
+ * @platform iOS
879
+ *
880
+ * @see {@link https://www.openiap.dev/docs/apis/ios/get-pending-transactions-ios}
881
+ */
774
882
  export const getPendingTransactionsIOS = async () => {
775
883
  if (Platform.OS !== 'ios') {
776
884
  return [];
@@ -789,6 +897,38 @@ export const getPendingTransactionsIOS = async () => {
789
897
  });
790
898
  }
791
899
  };
900
+
901
+ /**
902
+ * List every StoreKit transaction (finished + unfinished) for the current user.
903
+ *
904
+ * @see {@link https://www.openiap.dev/docs/apis/ios/get-all-transactions-ios}
905
+ */
906
+ export const getAllTransactionsIOS = async () => {
907
+ if (Platform.OS !== 'ios') {
908
+ return [];
909
+ }
910
+ try {
911
+ const nitroPurchases = await IAP.instance.getAllTransactionsIOS();
912
+ return nitroPurchases.map(convertNitroPurchaseToPurchase).filter(purchase => purchase.platform === 'ios');
913
+ } catch (error) {
914
+ RnIapConsole.error('[getAllTransactionsIOS] Failed:', error);
915
+ const parsedError = parseErrorStringToJsonObj(error);
916
+ throw createPurchaseError({
917
+ code: parsedError.code,
918
+ message: parsedError.message,
919
+ responseCode: parsedError.responseCode,
920
+ debugMessage: parsedError.debugMessage
921
+ });
922
+ }
923
+ };
924
+
925
+ /**
926
+ * Show manage subscriptions screen (iOS only)
927
+ * @returns Promise<Purchase[]> - Subscriptions where auto-renewal status changed
928
+ * @platform iOS
929
+ *
930
+ * @see {@link https://www.openiap.dev/docs/apis/ios/show-manage-subscriptions-ios}
931
+ */
792
932
  export const showManageSubscriptionsIOS = async () => {
793
933
  if (Platform.OS !== 'ios') {
794
934
  return [];
@@ -807,6 +947,15 @@ export const showManageSubscriptionsIOS = async () => {
807
947
  });
808
948
  }
809
949
  };
950
+
951
+ /**
952
+ * Check if user is eligible for intro offer (iOS only)
953
+ * @param groupID - The subscription group ID
954
+ * @returns Promise<boolean> - Eligibility status
955
+ * @platform iOS
956
+ *
957
+ * @see {@link https://www.openiap.dev/docs/apis/ios/is-eligible-for-intro-offer-ios}
958
+ */
810
959
  export const isEligibleForIntroOfferIOS = async groupID => {
811
960
  if (Platform.OS !== 'ios') {
812
961
  return false;
@@ -824,6 +973,14 @@ export const isEligibleForIntroOfferIOS = async groupID => {
824
973
  });
825
974
  }
826
975
  };
976
+
977
+ /**
978
+ * Get receipt data (iOS only)
979
+ * @returns Promise<string> - Base64 encoded receipt data
980
+ * @platform iOS
981
+ *
982
+ * @see {@link https://www.openiap.dev/docs/apis/ios/get-receipt-data-ios}
983
+ */
827
984
  export const getReceiptDataIOS = async () => {
828
985
  if (Platform.OS !== 'ios') {
829
986
  throw new Error('getReceiptDataIOS is only available on iOS');
@@ -884,6 +1041,15 @@ export const requestReceiptRefreshIOS = async () => {
884
1041
  });
885
1042
  }
886
1043
  };
1044
+
1045
+ /**
1046
+ * Check if transaction is verified (iOS only)
1047
+ * @param sku - The product SKU
1048
+ * @returns Promise<boolean> - Verification status
1049
+ * @platform iOS
1050
+ *
1051
+ * @see {@link https://www.openiap.dev/docs/apis/ios/is-transaction-verified-ios}
1052
+ */
887
1053
  export const isTransactionVerifiedIOS = async sku => {
888
1054
  if (Platform.OS !== 'ios') {
889
1055
  return false;
@@ -901,6 +1067,15 @@ export const isTransactionVerifiedIOS = async sku => {
901
1067
  });
902
1068
  }
903
1069
  };
1070
+
1071
+ /**
1072
+ * Get transaction JWS representation (iOS only)
1073
+ * @param sku - The product SKU
1074
+ * @returns Promise<string | null> - JWS representation or null
1075
+ * @platform iOS
1076
+ *
1077
+ * @see {@link https://www.openiap.dev/docs/apis/ios/get-transaction-jws-ios}
1078
+ */
904
1079
  export const getTransactionJwsIOS = async sku => {
905
1080
  if (Platform.OS !== 'ios') {
906
1081
  return null;
@@ -924,25 +1099,23 @@ export const getTransactionJwsIOS = async sku => {
924
1099
  // ------------------------------
925
1100
 
926
1101
  /**
927
- * Initialize connection to the store
928
- * @param config - Optional configuration including alternative billing mode for Android
929
- * @param config.alternativeBillingModeAndroid - Alternative billing mode: 'none', 'user-choice', or 'alternative-only'
1102
+ * Initialize the store connection. Must be called before any other IAP API.
1103
+ *
1104
+ * @param config Optional connection config. Use `enableBillingProgramAndroid` (Android,
1105
+ * Play Billing 8.2.0+) to opt into External Payments etc. iOS ignores Android-specific fields.
1106
+ * @returns Promise resolving to `true` when the platform billing client is connected.
1107
+ * @throws When the platform billing client fails to initialize.
930
1108
  *
931
1109
  * @example
932
- * ```typescript
933
- * // Standard billing (default)
1110
+ * ```ts
934
1111
  * await initConnection();
1112
+ * await initConnection({ enableBillingProgramAndroid: 'external-offer' });
1113
+ * ```
935
1114
  *
936
- * // User choice billing (Android)
937
- * await initConnection({
938
- * alternativeBillingModeAndroid: 'user-choice'
939
- * });
1115
+ * @remarks When using `useIAP()`, connection is auto-managed on mount/unmount —
1116
+ * pass options to the hook instead of calling this directly.
940
1117
  *
941
- * // Alternative billing only (Android)
942
- * await initConnection({
943
- * alternativeBillingModeAndroid: 'alternative-only'
944
- * });
945
- * ```
1118
+ * @see {@link https://www.openiap.dev/docs/apis/init-connection}
946
1119
  */
947
1120
  export const initConnection = async config => {
948
1121
  try {
@@ -960,7 +1133,9 @@ export const initConnection = async config => {
960
1133
  };
961
1134
 
962
1135
  /**
963
- * End connection to the store
1136
+ * Close the store connection and release resources.
1137
+ *
1138
+ * @see {@link https://www.openiap.dev/docs/apis/end-connection}
964
1139
  */
965
1140
  export const endConnection = async () => {
966
1141
  try {
@@ -979,6 +1154,12 @@ export const endConnection = async () => {
979
1154
  });
980
1155
  }
981
1156
  };
1157
+
1158
+ /**
1159
+ * Restore non-consumable and active subscription purchases.
1160
+ *
1161
+ * @see {@link https://www.openiap.dev/docs/apis/restore-purchases}
1162
+ */
982
1163
  export const restorePurchases = async () => {
983
1164
  try {
984
1165
  if (Platform.OS === 'ios') {
@@ -1001,9 +1182,30 @@ export const restorePurchases = async () => {
1001
1182
  };
1002
1183
 
1003
1184
  /**
1004
- * Request a purchase for products or subscriptions
1005
- * ⚠️ Important: This is an event-based operation, not promise-based.
1006
- * Listen for events through purchaseUpdatedListener or purchaseErrorListener.
1185
+ * Initiate a purchase or subscription flow. The result is delivered through
1186
+ * `purchaseUpdatedListener` NOT the return value.
1187
+ *
1188
+ * @param request `RequestPurchaseProps`, discriminated by `type`:
1189
+ * - `type: 'in-app'` — pass `request.apple.sku` (iOS) and/or `request.google.skus` (Android).
1190
+ * - `type: 'subs'` — same shape, plus `request.google.subscriptionOffers: [{ sku, offerToken }]`.
1191
+ * @returns The dispatched purchase payload. **Do not rely on it** for the actual outcome.
1192
+ * @throws Synchronous rejection from the store (e.g. `E_NOT_PREPARED`, validation failure).
1193
+ *
1194
+ * @example
1195
+ * ```ts
1196
+ * await requestPurchase({
1197
+ * request: {
1198
+ * apple: { sku: 'com.app.premium' },
1199
+ * google: { skus: ['com.app.premium'] },
1200
+ * },
1201
+ * type: 'in-app',
1202
+ * });
1203
+ * ```
1204
+ *
1205
+ * @remarks Event-based. Listen for the result via {@link purchaseUpdatedListener} /
1206
+ * {@link purchaseErrorListener}, or use `useIAP({ onPurchaseSuccess, onPurchaseError })`.
1207
+ *
1208
+ * @see {@link https://www.openiap.dev/docs/apis/request-purchase}
1007
1209
  */
1008
1210
  export const requestPurchase = async request => {
1009
1211
  try {
@@ -1117,19 +1319,28 @@ export const requestPurchase = async request => {
1117
1319
  };
1118
1320
 
1119
1321
  /**
1120
- * Finish a transaction (consume or acknowledge)
1121
- * @param params - Transaction finish parameters
1122
- * @param params.purchase - The purchase to finish
1123
- * @param params.isConsumable - Whether this is a consumable product (Android only)
1124
- * @returns Promise<void> - Resolves when the transaction is successfully finished
1322
+ * Complete a purchase transaction. Call after server-side verification to remove it
1323
+ * from the queue.
1324
+ *
1325
+ * @param args.purchase The `Purchase` to finalize.
1326
+ * @param args.isConsumable `true` for consumables (consumes the token so the SKU can be
1327
+ * re-bought, e.g. coins); `false` (default) for non-consumables and subscriptions.
1328
+ * @returns Promise that resolves once the platform finalizes the transaction.
1329
+ * @throws When the platform finalize call fails.
1125
1330
  *
1126
1331
  * @example
1127
- * ```typescript
1128
- * await finishTransaction({
1129
- * purchase: myPurchase,
1130
- * isConsumable: true
1332
+ * ```ts
1333
+ * purchaseUpdatedListener(async (purchase) => {
1334
+ * if (await verifyOnServer(purchase)) {
1335
+ * await finishTransaction({ purchase, isConsumable: false });
1336
+ * }
1131
1337
  * });
1132
1338
  * ```
1339
+ *
1340
+ * @remarks **Critical:** Android purchases must be finalized within 3 days or Google
1341
+ * auto-refunds. iOS unfinished transactions replay on every app launch.
1342
+ *
1343
+ * @see {@link https://www.openiap.dev/docs/apis/finish-transaction}
1133
1344
  */
1134
1345
  export const finishTransaction = async args => {
1135
1346
  const {
@@ -1192,6 +1403,8 @@ export const finishTransaction = async args => {
1192
1403
  * ```typescript
1193
1404
  * await acknowledgePurchaseAndroid('purchase_token_here');
1194
1405
  * ```
1406
+ *
1407
+ * @see {@link https://www.openiap.dev/docs/apis/android/acknowledge-purchase-android}
1195
1408
  */
1196
1409
  export const acknowledgePurchaseAndroid = async purchaseToken => {
1197
1410
  try {
@@ -1226,6 +1439,8 @@ export const acknowledgePurchaseAndroid = async purchaseToken => {
1226
1439
  * ```typescript
1227
1440
  * await consumePurchaseAndroid('purchase_token_here');
1228
1441
  * ```
1442
+ *
1443
+ * @see {@link https://www.openiap.dev/docs/apis/android/consume-purchase-android}
1229
1444
  */
1230
1445
  export const consumePurchaseAndroid = async purchaseToken => {
1231
1446
  try {
@@ -1278,6 +1493,8 @@ export const consumePurchaseAndroid = async purchaseToken => {
1278
1493
  * }
1279
1494
  * });
1280
1495
  * ```
1496
+ *
1497
+ * @see {@link https://www.openiap.dev/docs/apis/validate-receipt}
1281
1498
  */
1282
1499
  export const validateReceipt = async options => {
1283
1500
  const {
@@ -1385,9 +1602,28 @@ export const validateReceipt = async options => {
1385
1602
  *
1386
1603
  * @param options - Receipt validation options containing the SKU
1387
1604
  * @returns Promise resolving to receipt validation result
1605
+ *
1606
+ * @see {@link https://www.openiap.dev/docs/features/validation#verify-purchase}
1388
1607
  */
1389
1608
  export const verifyPurchase = validateReceipt;
1390
1609
 
1610
+ /**
1611
+ * iOS-only receipt validation alias.
1612
+ *
1613
+ * @deprecated Use `verifyPurchase` (or `validateReceipt`) instead. Kept so
1614
+ * consumers who imported `validateReceiptIOS` — which is still declared on the
1615
+ * OpenIAP Query interface — keep working. Throws on non-iOS platforms.
1616
+ *
1617
+ * @see {@link https://www.openiap.dev/docs/apis/ios/validate-receipt-ios}
1618
+ */
1619
+ export const validateReceiptIOS = async options => {
1620
+ if (Platform.OS !== 'ios') {
1621
+ throw new Error('validateReceiptIOS is only available on iOS');
1622
+ }
1623
+ const result = await validateReceipt(options);
1624
+ return result;
1625
+ };
1626
+
1391
1627
  /**
1392
1628
  * Verify purchase with a specific provider (e.g., IAPKit)
1393
1629
  *
@@ -1408,6 +1644,8 @@ export const verifyPurchase = validateReceipt;
1408
1644
  * },
1409
1645
  * });
1410
1646
  * ```
1647
+ *
1648
+ * @see {@link https://www.openiap.dev/docs/features/validation#verify-purchase-with-provider}
1411
1649
  */
1412
1650
  export const verifyPurchaseWithProvider = async options => {
1413
1651
  try {
@@ -1447,6 +1685,8 @@ export const verifyPurchaseWithProvider = async options => {
1447
1685
  * Sync iOS purchases with App Store (iOS only)
1448
1686
  * @returns Promise<boolean>
1449
1687
  * @platform iOS
1688
+ *
1689
+ * @see {@link https://www.openiap.dev/docs/apis/ios/sync-ios}
1450
1690
  */
1451
1691
  export const syncIOS = async () => {
1452
1692
  if (Platform.OS !== 'ios') {
@@ -1471,6 +1711,8 @@ export const syncIOS = async () => {
1471
1711
  * Present the code redemption sheet for offer codes (iOS only)
1472
1712
  * @returns Promise<boolean> - Indicates whether the redemption sheet was presented
1473
1713
  * @platform iOS
1714
+ *
1715
+ * @see {@link https://www.openiap.dev/docs/apis/ios/present-code-redemption-sheet-ios}
1474
1716
  */
1475
1717
  export const presentCodeRedemptionSheetIOS = async () => {
1476
1718
  if (Platform.OS !== 'ios') {
@@ -1510,6 +1752,8 @@ export const presentCodeRedemptionSheetIOS = async () => {
1510
1752
  *
1511
1753
  * @returns Promise<boolean> - true when the request triggers successfully
1512
1754
  * @platform iOS
1755
+ *
1756
+ * @see {@link https://www.openiap.dev/docs/apis/ios/request-purchase-on-promoted-product-ios}
1513
1757
  */
1514
1758
  export const requestPurchaseOnPromotedProductIOS = async () => {
1515
1759
  if (Platform.OS !== 'ios') {
@@ -1543,6 +1787,8 @@ export const requestPurchaseOnPromotedProductIOS = async () => {
1543
1787
  * Clear unfinished transactions on iOS
1544
1788
  * @returns Promise<boolean>
1545
1789
  * @platform iOS
1790
+ *
1791
+ * @see {@link https://www.openiap.dev/docs/apis/ios/clear-transaction-ios}
1546
1792
  */
1547
1793
  export const clearTransactionIOS = async () => {
1548
1794
  if (Platform.OS !== 'ios') {
@@ -1568,6 +1814,8 @@ export const clearTransactionIOS = async () => {
1568
1814
  * @param sku - The product SKU to refund
1569
1815
  * @returns Promise<string | null> - The refund status or null if not available
1570
1816
  * @platform iOS
1817
+ *
1818
+ * @see {@link https://www.openiap.dev/docs/apis/ios/begin-refund-request-ios}
1571
1819
  */
1572
1820
  export const beginRefundRequestIOS = async sku => {
1573
1821
  if (Platform.OS !== 'ios') {
@@ -1588,72 +1836,11 @@ export const beginRefundRequestIOS = async sku => {
1588
1836
  }
1589
1837
  };
1590
1838
 
1591
- /**
1592
- * Get subscription status for a product (iOS only)
1593
- * @param sku - The product SKU
1594
- * @returns Promise<SubscriptionStatusIOS[]> - Array of subscription status objects
1595
- * @throws Error when called on non-iOS platforms or when IAP is not initialized
1596
- * @platform iOS
1597
- */
1598
- /**
1599
- * Get current entitlement for a product (iOS only)
1600
- * @param sku - The product SKU
1601
- * @returns Promise<Purchase | null> - Current entitlement or null
1602
- * @platform iOS
1603
- */
1604
- /**
1605
- * Get latest transaction for a product (iOS only)
1606
- * @param sku - The product SKU
1607
- * @returns Promise<Purchase | null> - Latest transaction or null
1608
- * @platform iOS
1609
- */
1610
- /**
1611
- * Get pending transactions (iOS only)
1612
- * @returns Promise<Purchase[]> - Array of pending transactions
1613
- * @platform iOS
1614
- */
1615
- /**
1616
- * Show manage subscriptions screen (iOS only)
1617
- * @returns Promise<Purchase[]> - Subscriptions where auto-renewal status changed
1618
- * @platform iOS
1619
- */
1620
- /**
1621
- * Check if user is eligible for intro offer (iOS only)
1622
- * @param groupID - The subscription group ID
1623
- * @returns Promise<boolean> - Eligibility status
1624
- * @platform iOS
1625
- */
1626
- /**
1627
- * Get receipt data (iOS only)
1628
- * @returns Promise<string> - Base64 encoded receipt data
1629
- * @platform iOS
1630
- */
1631
- /**
1632
- * Check if transaction is verified (iOS only)
1633
- * @param sku - The product SKU
1634
- * @returns Promise<boolean> - Verification status
1635
- * @platform iOS
1636
- */
1637
- /**
1638
- * Get transaction JWS representation (iOS only)
1639
- * @param sku - The product SKU
1640
- * @returns Promise<string | null> - JWS representation or null
1641
- * @platform iOS
1642
- */
1643
- /**
1644
- * Get the storefront identifier for the user's App Store account (iOS only)
1645
- * @returns Promise<string> - The storefront identifier (e.g., 'USA' for United States)
1646
- * @platform iOS
1647
- *
1648
- * @example
1649
- * ```typescript
1650
- * const storefront = await getStorefrontIOS();
1651
- * console.log('User storefront:', storefront); // e.g., 'USA', 'GBR', 'KOR'
1652
- * ```
1653
- */
1654
1839
  /**
1655
1840
  * Deeplinks to native interface that allows users to manage their subscriptions
1656
1841
  * Cross-platform alias aligning with expo-iap
1842
+ *
1843
+ * @see {@link https://www.openiap.dev/docs/apis/deep-link-to-subscriptions}
1657
1844
  */
1658
1845
  export const deepLinkToSubscriptions = async options => {
1659
1846
  const resolvedOptions = options ?? undefined;
@@ -1698,25 +1885,6 @@ export const deepLinkToSubscriptionsIOS = async () => {
1698
1885
  }
1699
1886
  };
1700
1887
 
1701
- /**
1702
- * iOS only - Gets the original app transaction ID if the app was purchased from the App Store
1703
- * @platform iOS
1704
- * @description
1705
- * This function retrieves the original app transaction information if the app was purchased
1706
- * from the App Store. Returns null if the app was not purchased (e.g., free app or TestFlight).
1707
- *
1708
- * @returns {Promise<string | null>} The original app transaction ID or null
1709
- *
1710
- * @example
1711
- * ```typescript
1712
- * const appTransaction = await getAppTransactionIOS();
1713
- * if (appTransaction) {
1714
- * console.log('App was purchased, transaction ID:', appTransaction);
1715
- * } else {
1716
- * console.log('App was not purchased from App Store');
1717
- * }
1718
- * ```
1719
- */
1720
1888
  /**
1721
1889
  * Get all active subscriptions with detailed information (OpenIAP compliant)
1722
1890
  * Returns an array of active subscriptions. If subscriptionIds is not provided,
@@ -1729,6 +1897,8 @@ export const deepLinkToSubscriptionsIOS = async () => {
1729
1897
  *
1730
1898
  * @param subscriptionIds - Optional array of subscription IDs to filter by
1731
1899
  * @returns Promise<ActiveSubscription[]> - Array of active subscriptions
1900
+ *
1901
+ * @see {@link https://www.openiap.dev/docs/apis/get-active-subscriptions}
1732
1902
  */
1733
1903
  export const getActiveSubscriptions = async subscriptionIds => {
1734
1904
  try {
@@ -1875,6 +2045,8 @@ export const getActiveSubscriptions_OLD: QueryField<
1875
2045
  *
1876
2046
  * @param subscriptionIds - Optional array of subscription IDs to check
1877
2047
  * @returns Promise<boolean> - True if there are active subscriptions
2048
+ *
2049
+ * @see {@link https://www.openiap.dev/docs/apis/has-active-subscriptions}
1878
2050
  */
1879
2051
  export const hasActiveSubscriptions = async subscriptionIds => {
1880
2052
  try {
@@ -1977,6 +2149,8 @@ const normalizeProductQueryType = type => {
1977
2149
  * // Proceed with alternative billing flow
1978
2150
  * }
1979
2151
  * ```
2152
+ *
2153
+ * @see {@link https://www.openiap.dev/docs/apis/android/check-alternative-billing-availability-android}
1980
2154
  */
1981
2155
  export const checkAlternativeBillingAvailabilityAndroid = async () => {
1982
2156
  if (Platform.OS !== 'android') {
@@ -2012,6 +2186,8 @@ export const checkAlternativeBillingAvailabilityAndroid = async () => {
2012
2186
  * }
2013
2187
  * }
2014
2188
  * ```
2189
+ *
2190
+ * @see {@link https://www.openiap.dev/docs/apis/android/show-alternative-billing-dialog-android}
2015
2191
  */
2016
2192
  export const showAlternativeBillingDialogAndroid = async () => {
2017
2193
  if (Platform.OS !== 'android') {
@@ -2047,6 +2223,8 @@ export const showAlternativeBillingDialogAndroid = async () => {
2047
2223
  * });
2048
2224
  * }
2049
2225
  * ```
2226
+ *
2227
+ * @see {@link https://www.openiap.dev/docs/apis/android/create-alternative-billing-token-android}
2050
2228
  */
2051
2229
  export const createAlternativeBillingTokenAndroid = async sku => {
2052
2230
  if (Platform.OS !== 'android') {
@@ -2114,6 +2292,8 @@ export const enableBillingProgramAndroid = program => {
2114
2292
  * // External offers are available for this user
2115
2293
  * }
2116
2294
  * ```
2295
+ *
2296
+ * @see {@link https://www.openiap.dev/docs/apis/android/is-billing-program-available-android}
2117
2297
  */
2118
2298
  export const isBillingProgramAvailableAndroid = async program => {
2119
2299
  if (Platform.OS !== 'android') {
@@ -2149,6 +2329,8 @@ export const isBillingProgramAvailableAndroid = async program => {
2149
2329
  * body: JSON.stringify({ token: details.externalTransactionToken })
2150
2330
  * });
2151
2331
  * ```
2332
+ *
2333
+ * @see {@link https://www.openiap.dev/docs/apis/android/create-billing-program-reporting-details-android}
2152
2334
  */
2153
2335
  export const createBillingProgramReportingDetailsAndroid = async program => {
2154
2336
  if (Platform.OS !== 'android') {
@@ -2186,6 +2368,8 @@ export const createBillingProgramReportingDetailsAndroid = async program => {
2186
2368
  * console.log('User accepted external link');
2187
2369
  * }
2188
2370
  * ```
2371
+ *
2372
+ * @see {@link https://www.openiap.dev/docs/apis/android/launch-external-link-android}
2189
2373
  */
2190
2374
  export const launchExternalLinkAndroid = async params => {
2191
2375
  if (Platform.OS !== 'android') {
@@ -2209,7 +2393,11 @@ export const launchExternalLinkAndroid = async params => {
2209
2393
  // ------------------------------
2210
2394
 
2211
2395
  /**
2212
- * Check if the device can present an external purchase notice sheet (iOS 18.2+).
2396
+ * Check if the device can present an external purchase notice sheet (iOS 17.4+).
2397
+ *
2398
+ * Wraps `ExternalPurchase.canPresent`, which Apple introduced in iOS 17.4.
2399
+ * Note: the notice sheet itself (`presentExternalPurchaseNoticeSheetIOS`)
2400
+ * still requires iOS 18.2+; only the eligibility check is available earlier.
2213
2401
  *
2214
2402
  * @returns Promise<boolean> - true if notice sheet can be presented
2215
2403
  * @platform iOS
@@ -2222,6 +2410,8 @@ export const launchExternalLinkAndroid = async params => {
2222
2410
  * const result = await presentExternalPurchaseNoticeSheetIOS();
2223
2411
  * }
2224
2412
  * ```
2413
+ *
2414
+ * @see {@link https://www.openiap.dev/docs/apis/ios/can-present-external-purchase-notice-ios}
2225
2415
  */
2226
2416
  export const canPresentExternalPurchaseNoticeIOS = async () => {
2227
2417
  if (Platform.OS !== 'ios') {
@@ -2250,6 +2440,8 @@ export const canPresentExternalPurchaseNoticeIOS = async () => {
2250
2440
  * await presentExternalPurchaseLinkIOS('https://your-website.com/purchase');
2251
2441
  * }
2252
2442
  * ```
2443
+ *
2444
+ * @see {@link https://www.openiap.dev/docs/apis/ios/present-external-purchase-notice-sheet-ios}
2253
2445
  */
2254
2446
  export const presentExternalPurchaseNoticeSheetIOS = async () => {
2255
2447
  if (Platform.OS !== 'ios') {
@@ -2277,6 +2469,8 @@ export const presentExternalPurchaseNoticeSheetIOS = async () => {
2277
2469
  * console.log('User completed external purchase');
2278
2470
  * }
2279
2471
  * ```
2472
+ *
2473
+ * @see {@link https://www.openiap.dev/docs/apis/ios/present-external-purchase-link-ios}
2280
2474
  */
2281
2475
  export const presentExternalPurchaseLinkIOS = async url => {
2282
2476
  if (Platform.OS !== 'ios') {
@@ -2309,6 +2503,8 @@ export const presentExternalPurchaseLinkIOS = async url => {
2309
2503
  * // App can use custom external purchase links
2310
2504
  * }
2311
2505
  * ```
2506
+ *
2507
+ * @see {@link https://www.openiap.dev/docs/apis/ios/is-eligible-for-external-purchase-custom-link-ios}
2312
2508
  */
2313
2509
  export const isEligibleForExternalPurchaseCustomLinkIOS = async () => {
2314
2510
  if (Platform.OS !== 'ios') {
@@ -2340,6 +2536,8 @@ export const isEligibleForExternalPurchaseCustomLinkIOS = async () => {
2340
2536
  * await reportToApple(result.token);
2341
2537
  * }
2342
2538
  * ```
2539
+ *
2540
+ * @see {@link https://www.openiap.dev/docs/apis/ios/get-external-purchase-custom-link-token-ios}
2343
2541
  */
2344
2542
  export const getExternalPurchaseCustomLinkTokenIOS = async tokenType => {
2345
2543
  if (Platform.OS !== 'ios') {
@@ -2371,6 +2569,8 @@ export const getExternalPurchaseCustomLinkTokenIOS = async tokenType => {
2371
2569
  * await Linking.openURL('https://your-store.com/checkout');
2372
2570
  * }
2373
2571
  * ```
2572
+ *
2573
+ * @see {@link https://www.openiap.dev/docs/apis/ios/show-external-purchase-custom-link-notice-ios}
2374
2574
  */
2375
2575
  export const showExternalPurchaseCustomLinkNoticeIOS = async noticeType => {
2376
2576
  if (Platform.OS !== 'ios') {