react-native-iap 15.3.4 → 15.3.6

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 (61) hide show
  1. package/ios/HybridRnIap.swift +5 -2
  2. package/lib/module/index.js +42 -61
  3. package/lib/module/index.js.map +1 -1
  4. package/lib/module/types.js.map +1 -1
  5. package/lib/module/utils/error.js +98 -15
  6. package/lib/module/utils/error.js.map +1 -1
  7. package/lib/typescript/src/index.d.ts.map +1 -1
  8. package/lib/typescript/src/specs/RnIap.nitro.d.ts +10 -6
  9. package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
  10. package/lib/typescript/src/types.d.ts +59 -5
  11. package/lib/typescript/src/types.d.ts.map +1 -1
  12. package/lib/typescript/src/utils/error.d.ts +1 -1
  13. package/lib/typescript/src/utils/error.d.ts.map +1 -1
  14. package/nitrogen/generated/android/NitroIap+autolinking.cmake +2 -0
  15. package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +14 -0
  16. package/nitrogen/generated/android/c++/JNitroPurchaseRequest.hpp +2 -0
  17. package/nitrogen/generated/android/c++/JNitroRequestPurchaseIos.hpp +11 -5
  18. package/nitrogen/generated/android/c++/JPurchase.hpp +8 -0
  19. package/nitrogen/generated/android/c++/JPurchaseIOS.hpp +17 -1
  20. package/nitrogen/generated/android/c++/JRenewalCommitmentInfoIOS.hpp +75 -0
  21. package/nitrogen/generated/android/c++/JRenewalInfoIOS.hpp +14 -1
  22. package/nitrogen/generated/android/c++/JRequestPurchaseResult.hpp +8 -0
  23. package/nitrogen/generated/android/c++/JSubscriptionBillingPlanTypeIOS.hpp +61 -0
  24. package/nitrogen/generated/android/c++/JTransactionCommitmentInfoIOS.hpp +69 -0
  25. package/nitrogen/generated/android/c++/JVariant_NullType_NitroRequestPurchaseIos.hpp +2 -0
  26. package/nitrogen/generated/android/c++/JVariant_NullType_RenewalCommitmentInfoIOS.cpp +26 -0
  27. package/nitrogen/generated/android/c++/JVariant_NullType_RenewalCommitmentInfoIOS.hpp +74 -0
  28. package/nitrogen/generated/android/c++/JVariant_NullType_RenewalInfoIOS.hpp +5 -0
  29. package/nitrogen/generated/android/c++/JVariant_NullType_TransactionCommitmentInfoIOS.cpp +26 -0
  30. package/nitrogen/generated/android/c++/JVariant_NullType_TransactionCommitmentInfoIOS.hpp +71 -0
  31. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroRequestPurchaseIos.kt +6 -3
  32. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/PurchaseIOS.kt +8 -2
  33. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/RenewalCommitmentInfoIOS.kt +50 -0
  34. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/RenewalInfoIOS.kt +8 -2
  35. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/SubscriptionBillingPlanTypeIOS.kt +24 -0
  36. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/TransactionCommitmentInfoIOS.kt +47 -0
  37. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_NullType_RenewalCommitmentInfoIOS.kt +53 -0
  38. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_NullType_TransactionCommitmentInfoIOS.kt +53 -0
  39. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +112 -0
  40. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +9 -0
  41. package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +9 -0
  42. package/nitrogen/generated/ios/swift/NitroRequestPurchaseIos.swift +24 -13
  43. package/nitrogen/generated/ios/swift/PurchaseIOS.swift +49 -1
  44. package/nitrogen/generated/ios/swift/RenewalCommitmentInfoIOS.swift +49 -0
  45. package/nitrogen/generated/ios/swift/RenewalInfoIOS.swift +49 -1
  46. package/nitrogen/generated/ios/swift/SubscriptionBillingPlanTypeIOS.swift +44 -0
  47. package/nitrogen/generated/ios/swift/TransactionCommitmentInfoIOS.swift +44 -0
  48. package/nitrogen/generated/ios/swift/Variant_NullType_RenewalCommitmentInfoIOS.swift +18 -0
  49. package/nitrogen/generated/ios/swift/Variant_NullType_TransactionCommitmentInfoIOS.swift +18 -0
  50. package/nitrogen/generated/shared/c++/NitroRequestPurchaseIos.hpp +12 -5
  51. package/nitrogen/generated/shared/c++/PurchaseIOS.hpp +15 -1
  52. package/nitrogen/generated/shared/c++/RenewalCommitmentInfoIOS.hpp +101 -0
  53. package/nitrogen/generated/shared/c++/RenewalInfoIOS.hpp +15 -2
  54. package/nitrogen/generated/shared/c++/SubscriptionBillingPlanTypeIOS.hpp +80 -0
  55. package/nitrogen/generated/shared/c++/TransactionCommitmentInfoIOS.hpp +95 -0
  56. package/openiap-versions.json +3 -3
  57. package/package.json +1 -1
  58. package/src/index.ts +127 -64
  59. package/src/specs/RnIap.nitro.ts +10 -5
  60. package/src/types.ts +64 -5
  61. package/src/utils/error.ts +127 -14
package/src/index.ts CHANGED
@@ -55,7 +55,7 @@ import {
55
55
  validateNitroPurchase,
56
56
  convertNitroSubscriptionStatusToSubscriptionStatusIOS,
57
57
  } from './utils/type-bridge';
58
- import {parseErrorStringToJsonObj} from './utils/error';
58
+ import {isUserCancelledError, parseErrorStringToJsonObj} from './utils/error';
59
59
  import {
60
60
  normalizeErrorCodeFromNative,
61
61
  createPurchaseError,
@@ -121,6 +121,17 @@ const toErrorMessage = (error: unknown): string => {
121
121
  return String(error ?? '');
122
122
  };
123
123
 
124
+ const parseErrorAndLogIfNeeded = (
125
+ message: string,
126
+ error: unknown,
127
+ ): ReturnType<typeof parseErrorStringToJsonObj> => {
128
+ const parsedError = parseErrorStringToJsonObj(error);
129
+ if (!isUserCancelledError(parsedError)) {
130
+ RnIapConsole.error(message, error);
131
+ }
132
+ return parsedError;
133
+ };
134
+
124
135
  const unsupportedPlatformError = (): Error =>
125
136
  new Error(`Unsupported platform: ${Platform.OS}`);
126
137
 
@@ -905,8 +916,10 @@ export const fetchProducts: QueryField<'fetchProducts'> = async (request) => {
905
916
 
906
917
  return convertedProducts as FetchProductsResult;
907
918
  } catch (error) {
908
- RnIapConsole.error('[fetchProducts] Failed:', error);
909
- const parsedError = parseErrorStringToJsonObj(error);
919
+ const parsedError = parseErrorAndLogIfNeeded(
920
+ '[fetchProducts] Failed:',
921
+ error,
922
+ );
910
923
  throw createPurchaseError({
911
924
  code: parsedError.code,
912
925
  message: parsedError.message,
@@ -1027,8 +1040,10 @@ export const getPromotedProductIOS: QueryField<
1027
1040
  const converted = convertNitroProductToProduct(nitroProduct);
1028
1041
  return converted.platform === 'ios' ? (converted as ProductIOS) : null;
1029
1042
  } catch (error) {
1030
- RnIapConsole.error('[getPromotedProductIOS] Failed:', error);
1031
- const parsedError = parseErrorStringToJsonObj(error);
1043
+ const parsedError = parseErrorAndLogIfNeeded(
1044
+ '[getPromotedProductIOS] Failed:',
1045
+ error,
1046
+ );
1032
1047
  throw createPurchaseError({
1033
1048
  code: parsedError.code,
1034
1049
  message: parsedError.message,
@@ -1181,8 +1196,10 @@ export const subscriptionStatusIOS: QueryField<
1181
1196
  .filter((status): status is NitroSubscriptionStatus => status != null)
1182
1197
  .map(convertNitroSubscriptionStatusToSubscriptionStatusIOS);
1183
1198
  } catch (error) {
1184
- RnIapConsole.error('[subscriptionStatusIOS] Failed:', error);
1185
- const parsedError = parseErrorStringToJsonObj(error);
1199
+ const parsedError = parseErrorAndLogIfNeeded(
1200
+ '[subscriptionStatusIOS] Failed:',
1201
+ error,
1202
+ );
1186
1203
  throw createPurchaseError({
1187
1204
  code: parsedError.code,
1188
1205
  message: parsedError.message,
@@ -1215,8 +1232,10 @@ export const currentEntitlementIOS: QueryField<
1215
1232
  }
1216
1233
  return null;
1217
1234
  } catch (error) {
1218
- RnIapConsole.error('[currentEntitlementIOS] Failed:', error);
1219
- const parsedError = parseErrorStringToJsonObj(error);
1235
+ const parsedError = parseErrorAndLogIfNeeded(
1236
+ '[currentEntitlementIOS] Failed:',
1237
+ error,
1238
+ );
1220
1239
  throw createPurchaseError({
1221
1240
  code: parsedError.code,
1222
1241
  message: parsedError.message,
@@ -1249,8 +1268,10 @@ export const latestTransactionIOS: QueryField<'latestTransactionIOS'> = async (
1249
1268
  }
1250
1269
  return null;
1251
1270
  } catch (error) {
1252
- RnIapConsole.error('[latestTransactionIOS] Failed:', error);
1253
- const parsedError = parseErrorStringToJsonObj(error);
1271
+ const parsedError = parseErrorAndLogIfNeeded(
1272
+ '[latestTransactionIOS] Failed:',
1273
+ error,
1274
+ );
1254
1275
  throw createPurchaseError({
1255
1276
  code: parsedError.code,
1256
1277
  message: parsedError.message,
@@ -1282,8 +1303,10 @@ export const getPendingTransactionsIOS: QueryField<
1282
1303
  (purchase): purchase is PurchaseIOS => purchase.platform === 'ios',
1283
1304
  );
1284
1305
  } catch (error) {
1285
- RnIapConsole.error('[getPendingTransactionsIOS] Failed:', error);
1286
- const parsedError = parseErrorStringToJsonObj(error);
1306
+ const parsedError = parseErrorAndLogIfNeeded(
1307
+ '[getPendingTransactionsIOS] Failed:',
1308
+ error,
1309
+ );
1287
1310
  throw createPurchaseError({
1288
1311
  code: parsedError.code,
1289
1312
  message: parsedError.message,
@@ -1313,8 +1336,10 @@ export const getAllTransactionsIOS: QueryField<
1313
1336
  (purchase): purchase is PurchaseIOS => purchase.platform === 'ios',
1314
1337
  );
1315
1338
  } catch (error) {
1316
- RnIapConsole.error('[getAllTransactionsIOS] Failed:', error);
1317
- const parsedError = parseErrorStringToJsonObj(error);
1339
+ const parsedError = parseErrorAndLogIfNeeded(
1340
+ '[getAllTransactionsIOS] Failed:',
1341
+ error,
1342
+ );
1318
1343
  throw createPurchaseError({
1319
1344
  code: parsedError.code,
1320
1345
  message: parsedError.message,
@@ -1346,8 +1371,10 @@ export const showManageSubscriptionsIOS: MutationField<
1346
1371
  (purchase): purchase is PurchaseIOS => purchase.platform === 'ios',
1347
1372
  );
1348
1373
  } catch (error) {
1349
- RnIapConsole.error('[showManageSubscriptionsIOS] Failed:', error);
1350
- const parsedError = parseErrorStringToJsonObj(error);
1374
+ const parsedError = parseErrorAndLogIfNeeded(
1375
+ '[showManageSubscriptionsIOS] Failed:',
1376
+ error,
1377
+ );
1351
1378
  throw createPurchaseError({
1352
1379
  code: parsedError.code,
1353
1380
  message: parsedError.message,
@@ -1375,8 +1402,10 @@ export const isEligibleForIntroOfferIOS: QueryField<
1375
1402
  try {
1376
1403
  return await IAP.instance.isEligibleForIntroOfferIOS(groupID);
1377
1404
  } catch (error) {
1378
- RnIapConsole.error('[isEligibleForIntroOfferIOS] Failed:', error);
1379
- const parsedError = parseErrorStringToJsonObj(error);
1405
+ const parsedError = parseErrorAndLogIfNeeded(
1406
+ '[isEligibleForIntroOfferIOS] Failed:',
1407
+ error,
1408
+ );
1380
1409
  throw createPurchaseError({
1381
1410
  code: parsedError.code,
1382
1411
  message: parsedError.message,
@@ -1407,8 +1436,10 @@ export const getReceiptDataIOS: QueryField<'getReceiptDataIOS'> = async () => {
1407
1436
  try {
1408
1437
  return await IAP.instance.getReceiptDataIOS();
1409
1438
  } catch (error) {
1410
- RnIapConsole.error('[getReceiptDataIOS] Failed:', error);
1411
- const parsedError = parseErrorStringToJsonObj(error);
1439
+ const parsedError = parseErrorAndLogIfNeeded(
1440
+ '[getReceiptDataIOS] Failed:',
1441
+ error,
1442
+ );
1412
1443
  throw createPurchaseError({
1413
1444
  code: parsedError.code,
1414
1445
  message: parsedError.message,
@@ -1435,8 +1466,10 @@ export const getReceiptIOS = async (): Promise<string> => {
1435
1466
  }
1436
1467
  return await IAP.instance.getReceiptDataIOS();
1437
1468
  } catch (error) {
1438
- RnIapConsole.error('[getReceiptIOS] Failed:', error);
1439
- const parsedError = parseErrorStringToJsonObj(error);
1469
+ const parsedError = parseErrorAndLogIfNeeded(
1470
+ '[getReceiptIOS] Failed:',
1471
+ error,
1472
+ );
1440
1473
  throw createPurchaseError({
1441
1474
  code: parsedError.code,
1442
1475
  message: parsedError.message,
@@ -1463,8 +1496,10 @@ export const requestReceiptRefreshIOS = async (): Promise<string> => {
1463
1496
  }
1464
1497
  return await IAP.instance.getReceiptDataIOS();
1465
1498
  } catch (error) {
1466
- RnIapConsole.error('[requestReceiptRefreshIOS] Failed:', error);
1467
- const parsedError = parseErrorStringToJsonObj(error);
1499
+ const parsedError = parseErrorAndLogIfNeeded(
1500
+ '[requestReceiptRefreshIOS] Failed:',
1501
+ error,
1502
+ );
1468
1503
  throw createPurchaseError({
1469
1504
  code: parsedError.code,
1470
1505
  message: parsedError.message,
@@ -1492,8 +1527,10 @@ export const isTransactionVerifiedIOS: QueryField<
1492
1527
  try {
1493
1528
  return await IAP.instance.isTransactionVerifiedIOS(sku);
1494
1529
  } catch (error) {
1495
- RnIapConsole.error('[isTransactionVerifiedIOS] Failed:', error);
1496
- const parsedError = parseErrorStringToJsonObj(error);
1530
+ const parsedError = parseErrorAndLogIfNeeded(
1531
+ '[isTransactionVerifiedIOS] Failed:',
1532
+ error,
1533
+ );
1497
1534
  throw createPurchaseError({
1498
1535
  code: parsedError.code,
1499
1536
  message: parsedError.message,
@@ -1521,8 +1558,10 @@ export const getTransactionJwsIOS: QueryField<'getTransactionJwsIOS'> = async (
1521
1558
  try {
1522
1559
  return await IAP.instance.getTransactionJwsIOS(sku);
1523
1560
  } catch (error) {
1524
- RnIapConsole.error('[getTransactionJwsIOS] Failed:', error);
1525
- const parsedError = parseErrorStringToJsonObj(error);
1561
+ const parsedError = parseErrorAndLogIfNeeded(
1562
+ '[getTransactionJwsIOS] Failed:',
1563
+ error,
1564
+ );
1526
1565
  throw createPurchaseError({
1527
1566
  code: parsedError.code,
1528
1567
  message: parsedError.message,
@@ -1563,8 +1602,10 @@ export const initConnection: MutationField<'initConnection'> = async (
1563
1602
  config as Record<string, unknown> | undefined,
1564
1603
  );
1565
1604
  } catch (error) {
1566
- RnIapConsole.error('Failed to initialize IAP connection:', error);
1567
- const parsedError = parseErrorStringToJsonObj(error);
1605
+ const parsedError = parseErrorAndLogIfNeeded(
1606
+ 'Failed to initialize IAP connection:',
1607
+ error,
1608
+ );
1568
1609
  throw createPurchaseError({
1569
1610
  code: parsedError.code,
1570
1611
  message: parsedError.message,
@@ -1586,8 +1627,10 @@ export const endConnection: MutationField<'endConnection'> = async () => {
1586
1627
  resetListenerState();
1587
1628
  return result;
1588
1629
  } catch (error) {
1589
- RnIapConsole.error('Failed to end IAP connection:', error);
1590
- const parsedError = parseErrorStringToJsonObj(error);
1630
+ const parsedError = parseErrorAndLogIfNeeded(
1631
+ 'Failed to end IAP connection:',
1632
+ error,
1633
+ );
1591
1634
  throw createPurchaseError({
1592
1635
  code: parsedError.code,
1593
1636
  message: parsedError.message,
@@ -1613,8 +1656,10 @@ export const restorePurchases: MutationField<'restorePurchases'> = async () => {
1613
1656
  onlyIncludeActiveItemsIOS: true,
1614
1657
  });
1615
1658
  } catch (error) {
1616
- RnIapConsole.error('Failed to restore purchases:', error);
1617
- const parsedError = parseErrorStringToJsonObj(error);
1659
+ const parsedError = parseErrorAndLogIfNeeded(
1660
+ 'Failed to restore purchases:',
1661
+ error,
1662
+ );
1618
1663
  throw createPurchaseError({
1619
1664
  code: parsedError.code,
1620
1665
  message: parsedError.message,
@@ -1721,11 +1766,11 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
1721
1766
  }
1722
1767
  if (isSubs) {
1723
1768
  const subscriptionRequest = iosRequest as RequestSubscriptionIosProps;
1724
- if (
1725
- subscriptionRequest.introductoryOfferEligibility !== undefined
1726
- ) {
1727
- iosPayload.introductoryOfferEligibility =
1728
- subscriptionRequest.introductoryOfferEligibility;
1769
+ if (subscriptionRequest.billingPlanType) {
1770
+ iosPayload.billingPlanType = subscriptionRequest.billingPlanType;
1771
+ }
1772
+ if (subscriptionRequest.compactJWS !== undefined) {
1773
+ iosPayload.compactJWS = subscriptionRequest.compactJWS;
1729
1774
  }
1730
1775
  if (subscriptionRequest.promotionalOfferJWS) {
1731
1776
  iosPayload.promotionalOfferJWS =
@@ -1798,8 +1843,10 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
1798
1843
 
1799
1844
  return await IAP.instance.requestPurchase(unifiedRequest);
1800
1845
  } catch (error) {
1801
- RnIapConsole.error('Failed to request purchase:', error);
1802
- const parsedError = parseErrorStringToJsonObj(error);
1846
+ const parsedError = parseErrorAndLogIfNeeded(
1847
+ 'Failed to request purchase:',
1848
+ error,
1849
+ );
1803
1850
  throw createPurchaseError({
1804
1851
  code: parsedError.code,
1805
1852
  message: parsedError.message,
@@ -1921,8 +1968,10 @@ export const acknowledgePurchaseAndroid: MutationField<
1921
1968
  });
1922
1969
  return getSuccessFromPurchaseVariant(result, 'acknowledgePurchaseAndroid');
1923
1970
  } catch (error) {
1924
- RnIapConsole.error('Failed to acknowledge purchase Android:', error);
1925
- const parsedError = parseErrorStringToJsonObj(error);
1971
+ const parsedError = parseErrorAndLogIfNeeded(
1972
+ 'Failed to acknowledge purchase Android:',
1973
+ error,
1974
+ );
1926
1975
  throw createPurchaseError({
1927
1976
  code: parsedError.code,
1928
1977
  message: parsedError.message,
@@ -1960,8 +2009,10 @@ export const consumePurchaseAndroid: MutationField<
1960
2009
  });
1961
2010
  return getSuccessFromPurchaseVariant(result, 'consumePurchaseAndroid');
1962
2011
  } catch (error) {
1963
- RnIapConsole.error('Failed to consume purchase Android:', error);
1964
- const parsedError = parseErrorStringToJsonObj(error);
2012
+ const parsedError = parseErrorAndLogIfNeeded(
2013
+ 'Failed to consume purchase Android:',
2014
+ error,
2015
+ );
1965
2016
  throw createPurchaseError({
1966
2017
  code: parsedError.code,
1967
2018
  message: parsedError.message,
@@ -2109,8 +2160,10 @@ export const validateReceipt: MutationField<'validateReceipt'> = async (
2109
2160
  return result;
2110
2161
  }
2111
2162
  } catch (error) {
2112
- RnIapConsole.error('[validateReceipt] Failed:', error);
2113
- const parsedError = parseErrorStringToJsonObj(error);
2163
+ const parsedError = parseErrorAndLogIfNeeded(
2164
+ '[validateReceipt] Failed:',
2165
+ error,
2166
+ );
2114
2167
  throw createPurchaseError({
2115
2168
  code: parsedError.code,
2116
2169
  message: parsedError.message,
@@ -2203,8 +2256,10 @@ export const verifyPurchaseWithProvider: MutationField<
2203
2256
  errors: result.errors ?? null,
2204
2257
  };
2205
2258
  } catch (error) {
2206
- RnIapConsole.error('[verifyPurchaseWithProvider] Failed:', error);
2207
- const parsedError = parseErrorStringToJsonObj(error);
2259
+ const parsedError = parseErrorAndLogIfNeeded(
2260
+ '[verifyPurchaseWithProvider] Failed:',
2261
+ error,
2262
+ );
2208
2263
  throw createPurchaseError({
2209
2264
  code: parsedError.code,
2210
2265
  message: parsedError.message,
@@ -2230,8 +2285,7 @@ export const syncIOS: MutationField<'syncIOS'> = async () => {
2230
2285
  const result = await IAP.instance.syncIOS();
2231
2286
  return Boolean(result);
2232
2287
  } catch (error) {
2233
- RnIapConsole.error('[syncIOS] Failed:', error);
2234
- const parsedError = parseErrorStringToJsonObj(error);
2288
+ const parsedError = parseErrorAndLogIfNeeded('[syncIOS] Failed:', error);
2235
2289
  throw createPurchaseError({
2236
2290
  code: parsedError.code,
2237
2291
  message: parsedError.message,
@@ -2259,8 +2313,10 @@ export const presentCodeRedemptionSheetIOS: MutationField<
2259
2313
  const result = await IAP.instance.presentCodeRedemptionSheetIOS();
2260
2314
  return Boolean(result);
2261
2315
  } catch (error) {
2262
- RnIapConsole.error('[presentCodeRedemptionSheetIOS] Failed:', error);
2263
- const parsedError = parseErrorStringToJsonObj(error);
2316
+ const parsedError = parseErrorAndLogIfNeeded(
2317
+ '[presentCodeRedemptionSheetIOS] Failed:',
2318
+ error,
2319
+ );
2264
2320
  throw createPurchaseError({
2265
2321
  code: parsedError.code,
2266
2322
  message: parsedError.message,
@@ -2315,11 +2371,10 @@ export const requestPurchaseOnPromotedProductIOS =
2315
2371
 
2316
2372
  return true;
2317
2373
  } catch (error) {
2318
- RnIapConsole.error(
2374
+ const parsedError = parseErrorAndLogIfNeeded(
2319
2375
  '[requestPurchaseOnPromotedProductIOS] Failed:',
2320
2376
  error,
2321
2377
  );
2322
- const parsedError = parseErrorStringToJsonObj(error);
2323
2378
  throw createPurchaseError({
2324
2379
  code: parsedError.code,
2325
2380
  message: parsedError.message,
@@ -2347,8 +2402,10 @@ export const clearTransactionIOS: MutationField<
2347
2402
  await IAP.instance.clearTransactionIOS();
2348
2403
  return true;
2349
2404
  } catch (error) {
2350
- RnIapConsole.error('[clearTransactionIOS] Failed:', error);
2351
- const parsedError = parseErrorStringToJsonObj(error);
2405
+ const parsedError = parseErrorAndLogIfNeeded(
2406
+ '[clearTransactionIOS] Failed:',
2407
+ error,
2408
+ );
2352
2409
  throw createPurchaseError({
2353
2410
  code: parsedError.code,
2354
2411
  message: parsedError.message,
@@ -2377,8 +2434,10 @@ export const beginRefundRequestIOS: MutationField<
2377
2434
  const status = await IAP.instance.beginRefundRequestIOS(sku);
2378
2435
  return status ?? null;
2379
2436
  } catch (error) {
2380
- RnIapConsole.error('[beginRefundRequestIOS] Failed:', error);
2381
- const parsedError = parseErrorStringToJsonObj(error);
2437
+ const parsedError = parseErrorAndLogIfNeeded(
2438
+ '[beginRefundRequestIOS] Failed:',
2439
+ error,
2440
+ );
2382
2441
  throw createPurchaseError({
2383
2442
  code: parsedError.code,
2384
2443
  message: parsedError.message,
@@ -2430,8 +2489,10 @@ export const deepLinkToSubscriptionsIOS = async (): Promise<boolean> => {
2430
2489
  await IAP.instance.showManageSubscriptionsIOS();
2431
2490
  return true;
2432
2491
  } catch (error) {
2433
- RnIapConsole.error('[deepLinkToSubscriptionsIOS] Failed:', error);
2434
- const parsedError = parseErrorStringToJsonObj(error);
2492
+ const parsedError = parseErrorAndLogIfNeeded(
2493
+ '[deepLinkToSubscriptionsIOS] Failed:',
2494
+ error,
2495
+ );
2435
2496
  throw createPurchaseError({
2436
2497
  code: parsedError.code,
2437
2498
  message: parsedError.message,
@@ -2512,8 +2573,10 @@ export const getActiveSubscriptions: QueryField<
2512
2573
  RnIapConsole.error('IAP connection not initialized:', error);
2513
2574
  throw error;
2514
2575
  }
2515
- RnIapConsole.error('Failed to get active subscriptions:', error);
2516
- const parsedError = parseErrorStringToJsonObj(error);
2576
+ const parsedError = parseErrorAndLogIfNeeded(
2577
+ 'Failed to get active subscriptions:',
2578
+ error,
2579
+ );
2517
2580
  throw createPurchaseError({
2518
2581
  code: parsedError.code,
2519
2582
  message: parsedError.message,
@@ -49,6 +49,7 @@ import type {
49
49
  RequestPurchaseIosProps,
50
50
  RequestPurchaseResult,
51
51
  RequestSubscriptionAndroidProps,
52
+ RequestSubscriptionIosProps,
52
53
  UserChoiceBillingDetails,
53
54
  PaymentModeIOS,
54
55
  SubscriptionProductReplacementParamsAndroid,
@@ -175,13 +176,17 @@ export interface NitroRequestPurchaseIos {
175
176
  */
176
177
  advancedCommerceData?: RequestPurchaseIosProps['advancedCommerceData'];
177
178
  /**
178
- * Override introductory offer eligibility (iOS 15+, WWDC 2025).
179
- * Set to true to indicate the user is eligible for introductory offer,
180
- * or false to indicate they are not. When nil, the system determines eligibility.
181
- * Back-deployed to iOS 15.
179
+ * Billing plan to use for annual subscriptions that offer monthly billing with
180
+ * a 12-month commitment (iOS 26.4+).
181
+ * @platform iOS
182
+ */
183
+ billingPlanType?: RequestSubscriptionIosProps['billingPlanType'];
184
+ /**
185
+ * Compact JWS string for overriding introductory offer eligibility
186
+ * (iOS 15+, WWDC 2025). When nil, the system determines eligibility.
182
187
  * @platform iOS
183
188
  */
184
- introductoryOfferEligibility?: boolean | null;
189
+ compactJWS?: RequestSubscriptionIosProps['compactJWS'];
185
190
  /**
186
191
  * JWS promotional offer (iOS 15+, WWDC 2025).
187
192
  * New signature format using compact JWS string for promotional offers.
package/src/types.ts CHANGED
@@ -985,6 +985,11 @@ export interface ProductIOS extends ProductCommon {
985
985
  jsonRepresentationIOS: string;
986
986
  platform: 'ios';
987
987
  price?: (number | null);
988
+ /**
989
+ * iOS 26.4+ subscription pricing terms, including billing plan metadata for
990
+ * monthly subscriptions with a 12-month commitment.
991
+ */
992
+ pricingTermsIOS?: (SubscriptionPricingTermsIOS[] | null);
988
993
  /**
989
994
  * @deprecated Use subscriptionOffers instead for cross-platform compatibility.
990
995
  * @deprecated Use subscriptionOffers instead
@@ -1108,6 +1113,11 @@ export interface ProductSubscriptionIOS extends ProductCommon {
1108
1113
  jsonRepresentationIOS: string;
1109
1114
  platform: 'ios';
1110
1115
  price?: (number | null);
1116
+ /**
1117
+ * iOS 26.4+ subscription pricing terms, including billing plan metadata for
1118
+ * monthly subscriptions with a 12-month commitment.
1119
+ */
1120
+ pricingTermsIOS?: (SubscriptionPricingTermsIOS[] | null);
1111
1121
  /** App Store subscription group identifier for intro-offer eligibility checks. */
1112
1122
  subscriptionGroupIdIOS?: (string | null);
1113
1123
  /**
@@ -1234,6 +1244,10 @@ export interface PurchaseIOS extends PurchaseCommon {
1234
1244
  advancedCommerceInfoIOS?: (AdvancedCommerceInfoIOS | null);
1235
1245
  appAccountToken?: (string | null);
1236
1246
  appBundleIdIOS?: (string | null);
1247
+ /** iOS 26.4+ billing plan selected for this transaction. */
1248
+ billingPlanTypeIOS?: (SubscriptionBillingPlanTypeIOS | null);
1249
+ /** iOS 26.4+ progress information for monthly subscriptions with a 12-month commitment. */
1250
+ commitmentInfoIOS?: (TransactionCommitmentInfoIOS | null);
1237
1251
  countryCodeIOS?: (string | null);
1238
1252
  currencyCodeIOS?: (string | null);
1239
1253
  currencySymbolIOS?: (string | null);
@@ -1454,12 +1468,25 @@ export interface RefundResultIOS {
1454
1468
  status: string;
1455
1469
  }
1456
1470
 
1471
+ export interface RenewalCommitmentInfoIOS {
1472
+ commitmentAutoRenewProductId: string;
1473
+ commitmentAutoRenewStatus: boolean;
1474
+ commitmentRenewalBillingPlanType: SubscriptionBillingPlanTypeIOS;
1475
+ commitmentRenewalDate: number;
1476
+ commitmentRenewalPrice: number;
1477
+ }
1478
+
1457
1479
  /**
1458
1480
  * Subscription renewal information from Product.SubscriptionInfo.RenewalInfo
1459
1481
  * https://developer.apple.com/documentation/storekit/product/subscriptioninfo/renewalinfo
1460
1482
  */
1461
1483
  export interface RenewalInfoIOS {
1462
1484
  autoRenewPreference?: (string | null);
1485
+ /**
1486
+ * iOS 26.4+ renewal commitment metadata for monthly subscriptions with a
1487
+ * 12-month commitment.
1488
+ */
1489
+ commitmentInfo?: (RenewalCommitmentInfoIOS | null);
1463
1490
  /**
1464
1491
  * When subscription expires due to cancellation/billing issue
1465
1492
  * Possible values: "VOLUNTARY", "BILLING_ERROR", "DID_NOT_AGREE_TO_PRICE_INCREASE", "PRODUCT_NOT_AVAILABLE", "UNKNOWN"
@@ -1486,6 +1513,8 @@ export interface RenewalInfoIOS {
1486
1513
  * Possible values: "AGREED", "PENDING", null (no price increase)
1487
1514
  */
1488
1515
  priceIncreaseStatus?: (string | null);
1516
+ /** iOS 26.4+ billing plan that will renew after the current period. */
1517
+ renewalBillingPlanType?: (SubscriptionBillingPlanTypeIOS | null);
1489
1518
  /**
1490
1519
  * Expected renewal date (milliseconds since epoch)
1491
1520
  * For active subscriptions, when the next renewal/charge will occur
@@ -1646,12 +1675,17 @@ export interface RequestSubscriptionIosProps {
1646
1675
  andDangerouslyFinishTransactionAutomatically?: (boolean | null);
1647
1676
  appAccountToken?: (string | null);
1648
1677
  /**
1649
- * Override introductory offer eligibility (iOS 15+, WWDC 2025).
1650
- * Set to true to indicate the user is eligible for introductory offer,
1651
- * or false to indicate they are not. When nil, the system determines eligibility.
1652
- * Back-deployed to iOS 15.
1678
+ * Billing plan to use when purchasing an annual subscription that offers
1679
+ * monthly billing with a 12-month commitment (iOS 26.4+).
1680
+ */
1681
+ billingPlanType?: (SubscriptionBillingPlanTypeIOS | null);
1682
+ /**
1683
+ * Compact JWS string for overriding introductory offer eligibility
1684
+ * (iOS 15+, WWDC 2025). When nil, the system determines eligibility.
1685
+ * Generate the JWS on your server and pass it to StoreKit's
1686
+ * introductoryOfferEligibility(compactJWS:) purchase option.
1653
1687
  */
1654
- introductoryOfferEligibility?: (boolean | null);
1688
+ compactJWS?: (string | null);
1655
1689
  /**
1656
1690
  * JWS promotional offer (iOS 15+, WWDC 2025).
1657
1691
  * New signature format using compact JWS string for promotional offers.
@@ -1777,8 +1811,17 @@ export interface Subscription {
1777
1811
 
1778
1812
  export type SubscriptionPurchaseUpdatedArgs = (PurchaseUpdatedListenerOptions | null) | undefined;
1779
1813
 
1814
+ export type SubscriptionBillingPlanTypeIOS = 'unknown' | 'monthly' | 'up-front';
1815
+
1816
+ export interface SubscriptionCommitmentInfoIOS {
1817
+ displayPrice: string;
1818
+ period: SubscriptionPeriodValueIOS;
1819
+ price: number;
1820
+ }
1821
+
1780
1822
  export interface SubscriptionInfoIOS {
1781
1823
  introductoryOffer?: (SubscriptionOfferIOS | null);
1824
+ pricingTerms?: (SubscriptionPricingTermsIOS[] | null);
1782
1825
  promotionalOffers?: (SubscriptionOfferIOS[] | null);
1783
1826
  subscriptionGroupId: string;
1784
1827
  subscriptionPeriod: SubscriptionPeriodValueIOS;
@@ -1900,6 +1943,15 @@ export interface SubscriptionPeriodValueIOS {
1900
1943
  value: number;
1901
1944
  }
1902
1945
 
1946
+ export interface SubscriptionPricingTermsIOS {
1947
+ billingDisplayPrice: string;
1948
+ billingPeriod: SubscriptionPeriodValueIOS;
1949
+ billingPlanType: SubscriptionBillingPlanTypeIOS;
1950
+ billingPrice: number;
1951
+ commitmentInfo: SubscriptionCommitmentInfoIOS;
1952
+ subscriptionOffers?: (SubscriptionOffer[] | null);
1953
+ }
1954
+
1903
1955
  /**
1904
1956
  * Product-level subscription replacement parameters (Android)
1905
1957
  * Used with setSubscriptionProductReplacementParams in BillingFlowParams.ProductDetailsParams
@@ -1926,6 +1978,13 @@ export interface SubscriptionStatusIOS {
1926
1978
  state: string;
1927
1979
  }
1928
1980
 
1981
+ export interface TransactionCommitmentInfoIOS {
1982
+ billingPeriodNumber: number;
1983
+ commitmentExpiresDate: number;
1984
+ commitmentPrice: number;
1985
+ totalBillingPeriods: number;
1986
+ }
1987
+
1929
1988
  /**
1930
1989
  * User Choice Billing event details (Android)
1931
1990
  * Fired when a user selects alternative billing in the User Choice Billing dialog