react-native-iap 14.6.0-rc.1 → 14.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +72 -36
  2. package/ios/HybridRnIap.swift +8 -2
  3. package/lib/module/hooks/useIAP.js +1 -6
  4. package/lib/module/hooks/useIAP.js.map +1 -1
  5. package/lib/module/index.js +62 -10
  6. package/lib/module/index.js.map +1 -1
  7. package/lib/module/types.js +58 -0
  8. package/lib/module/types.js.map +1 -1
  9. package/lib/typescript/plugin/src/withIAP.d.ts +6 -0
  10. package/lib/typescript/plugin/src/withIAP.d.ts.map +1 -1
  11. package/lib/typescript/src/hooks/useIAP.d.ts +5 -7
  12. package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
  13. package/lib/typescript/src/index.d.ts +20 -2
  14. package/lib/typescript/src/index.d.ts.map +1 -1
  15. package/lib/typescript/src/specs/RnIap.nitro.d.ts +19 -8
  16. package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
  17. package/lib/typescript/src/types.d.ts +94 -9
  18. package/lib/typescript/src/types.d.ts.map +1 -1
  19. package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +12 -4
  20. package/nitrogen/generated/android/c++/JNitroReceiptValidationAppleOptions.hpp +57 -0
  21. package/nitrogen/generated/android/c++/{JNitroReceiptValidationAndroidOptions.hpp → JNitroReceiptValidationGoogleOptions.hpp} +18 -14
  22. package/nitrogen/generated/android/c++/JNitroReceiptValidationHorizonOptions.hpp +65 -0
  23. package/nitrogen/generated/android/c++/JNitroReceiptValidationParams.hpp +19 -11
  24. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroReceiptValidationAppleOptions.kt +36 -0
  25. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/{NitroReceiptValidationAndroidOptions.kt → NitroReceiptValidationGoogleOptions.kt} +9 -6
  26. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroReceiptValidationHorizonOptions.kt +42 -0
  27. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroReceiptValidationParams.kt +7 -4
  28. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +46 -10
  29. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +9 -3
  30. package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +9 -3
  31. package/nitrogen/generated/ios/swift/NitroReceiptValidationAppleOptions.swift +35 -0
  32. package/nitrogen/generated/ios/swift/{NitroReceiptValidationAndroidOptions.swift → NitroReceiptValidationGoogleOptions.swift} +21 -10
  33. package/nitrogen/generated/ios/swift/NitroReceiptValidationHorizonOptions.swift +57 -0
  34. package/nitrogen/generated/ios/swift/NitroReceiptValidationParams.swift +46 -11
  35. package/nitrogen/generated/shared/c++/NitroReceiptValidationAppleOptions.hpp +75 -0
  36. package/nitrogen/generated/shared/c++/{NitroReceiptValidationAndroidOptions.hpp → NitroReceiptValidationGoogleOptions.hpp} +18 -14
  37. package/nitrogen/generated/shared/c++/NitroReceiptValidationHorizonOptions.hpp +83 -0
  38. package/nitrogen/generated/shared/c++/NitroReceiptValidationParams.hpp +22 -13
  39. package/openiap-versions.json +3 -3
  40. package/package.json +1 -1
  41. package/plugin/build/withIAP.d.ts +6 -0
  42. package/plugin/build/withIAP.js +46 -2
  43. package/plugin/src/withIAP.ts +67 -2
  44. package/plugin/tsconfig.tsbuildinfo +1 -1
  45. package/src/hooks/useIAP.ts +8 -23
  46. package/src/index.ts +79 -14
  47. package/src/specs/RnIap.nitro.ts +24 -10
  48. package/src/types.ts +97 -9
  49. package/ios/reactnativeiap.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  50. package/ios/reactnativeiap.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  51. package/plugin/build/src/withIAP.d.ts +0 -3
  52. package/plugin/build/src/withIAP.js +0 -81
  53. package/plugin/build/tsconfig.tsbuildinfo +0 -1
package/src/index.ts CHANGED
@@ -1335,29 +1335,94 @@ export const consumePurchaseAndroid: MutationField<
1335
1335
 
1336
1336
  /**
1337
1337
  * Validate receipt on both iOS and Android platforms
1338
- * @param sku - Product SKU
1339
- * @param androidOptions - Android-specific validation options (required for Android)
1338
+ * @deprecated Use `verifyPurchase` instead. This function will be removed in a future version.
1339
+ * @param options - Platform-specific verification options
1340
+ * @param options.apple - Apple App Store verification options (iOS)
1341
+ * @param options.google - Google Play verification options (Android)
1342
+ * @param options.horizon - Meta Horizon (Quest) verification options
1340
1343
  * @returns Promise<VerifyPurchaseResultIOS | VerifyPurchaseResultAndroid> - Platform-specific receipt validation result
1344
+ *
1345
+ * @example
1346
+ * ```typescript
1347
+ * // Use verifyPurchase instead:
1348
+ * const result = await verifyPurchase({
1349
+ * apple: { sku: 'premium_monthly' },
1350
+ * google: {
1351
+ * sku: 'premium_monthly',
1352
+ * packageName: 'com.example.app',
1353
+ * purchaseToken: 'token...',
1354
+ * accessToken: 'oauth_token...',
1355
+ * isSub: true
1356
+ * }
1357
+ * });
1358
+ * ```
1341
1359
  */
1342
1360
  export const validateReceipt: MutationField<'validateReceipt'> = async (
1343
1361
  options,
1344
1362
  ) => {
1345
- const {sku, androidOptions} = options;
1363
+ const {apple, google, horizon} = options;
1346
1364
  try {
1347
- const normalizedAndroidOptions =
1348
- androidOptions != null
1349
- ? {
1350
- ...androidOptions,
1351
- isSub:
1352
- androidOptions.isSub == null
1353
- ? undefined
1354
- : Boolean(androidOptions.isSub),
1365
+ // Validate required fields based on platform
1366
+ if (Platform.OS === 'ios') {
1367
+ if (!apple?.sku) {
1368
+ throw new Error('Missing required parameter: apple.sku');
1369
+ }
1370
+ } else if (Platform.OS === 'android') {
1371
+ // Horizon verification path (e.g., Meta Quest) - skip Google validation
1372
+ if (horizon?.sku) {
1373
+ // Validate all required Horizon fields
1374
+ if (!horizon.userId || !horizon.accessToken) {
1375
+ throw new Error(
1376
+ 'Missing required Horizon parameters: userId and accessToken are required when horizon.sku is provided',
1377
+ );
1378
+ }
1379
+ // Horizon verification will be handled by native layer
1380
+ } else if (!google) {
1381
+ throw new Error('Missing required parameter: google options');
1382
+ } else {
1383
+ const requiredFields: (keyof typeof google)[] = [
1384
+ 'sku',
1385
+ 'accessToken',
1386
+ 'packageName',
1387
+ 'purchaseToken',
1388
+ ];
1389
+ for (const field of requiredFields) {
1390
+ if (!google[field]) {
1391
+ throw new Error(
1392
+ `Missing or empty required parameter: google.${field}`,
1393
+ );
1355
1394
  }
1356
- : undefined;
1395
+ }
1396
+ }
1397
+ }
1357
1398
 
1358
1399
  const params: NitroReceiptValidationParams = {
1359
- sku,
1360
- androidOptions: normalizedAndroidOptions,
1400
+ apple: apple?.sku
1401
+ ? {
1402
+ sku: apple.sku,
1403
+ }
1404
+ : null,
1405
+ google:
1406
+ google?.sku &&
1407
+ google.accessToken &&
1408
+ google.packageName &&
1409
+ google.purchaseToken
1410
+ ? {
1411
+ sku: google.sku,
1412
+ accessToken: google.accessToken,
1413
+ packageName: google.packageName,
1414
+ purchaseToken: google.purchaseToken,
1415
+ isSub: google.isSub == null ? undefined : Boolean(google.isSub),
1416
+ }
1417
+ : null,
1418
+ horizon:
1419
+ horizon?.sku && horizon.userId && horizon.accessToken
1420
+ ? {
1421
+ sku: horizon.sku,
1422
+ userId: horizon.userId,
1423
+ accessToken: horizon.accessToken,
1424
+ }
1425
+ : null,
1361
1426
  };
1362
1427
 
1363
1428
  const nitroResult = await IAP.instance.validateReceipt(params);
@@ -14,8 +14,9 @@ import type {
14
14
  ProductCommon,
15
15
  PurchaseCommon,
16
16
  PurchaseOptions,
17
- VerifyPurchaseAndroidOptions,
18
- VerifyPurchaseProps,
17
+ VerifyPurchaseAppleOptions,
18
+ VerifyPurchaseGoogleOptions,
19
+ VerifyPurchaseHorizonOptions,
19
20
  VerifyPurchaseResultAndroid,
20
21
  RequestPurchaseIosProps,
21
22
  RequestPurchaseResult,
@@ -64,18 +65,30 @@ export type ExternalLinkTypeAndroid =
64
65
  // ║ PARAMS ║
65
66
  // ╚══════════════════════════════════════════════════════════════════════════╝
66
67
 
67
- // Receipt validation parameters
68
+ // Receipt validation parameters (platform-specific)
68
69
 
69
- export interface NitroReceiptValidationAndroidOptions {
70
- accessToken: VerifyPurchaseAndroidOptions['accessToken'];
71
- isSub?: VerifyPurchaseAndroidOptions['isSub'];
72
- packageName: VerifyPurchaseAndroidOptions['packageName'];
73
- productToken: VerifyPurchaseAndroidOptions['productToken'];
70
+ export interface NitroReceiptValidationAppleOptions {
71
+ sku: VerifyPurchaseAppleOptions['sku'];
72
+ }
73
+
74
+ export interface NitroReceiptValidationGoogleOptions {
75
+ accessToken: VerifyPurchaseGoogleOptions['accessToken'];
76
+ isSub?: VerifyPurchaseGoogleOptions['isSub'];
77
+ packageName: VerifyPurchaseGoogleOptions['packageName'];
78
+ purchaseToken: VerifyPurchaseGoogleOptions['purchaseToken'];
79
+ sku: VerifyPurchaseGoogleOptions['sku'];
80
+ }
81
+
82
+ export interface NitroReceiptValidationHorizonOptions {
83
+ accessToken: VerifyPurchaseHorizonOptions['accessToken'];
84
+ sku: VerifyPurchaseHorizonOptions['sku'];
85
+ userId: VerifyPurchaseHorizonOptions['userId'];
74
86
  }
75
87
 
76
88
  export interface NitroReceiptValidationParams {
77
- sku: VerifyPurchaseProps['sku'];
78
- androidOptions?: NitroReceiptValidationAndroidOptions | null;
89
+ apple?: NitroReceiptValidationAppleOptions | null;
90
+ google?: NitroReceiptValidationGoogleOptions | null;
91
+ horizon?: NitroReceiptValidationHorizonOptions | null;
79
92
  }
80
93
 
81
94
  // Purchase request parameters
@@ -822,6 +835,7 @@ export interface RnIap extends HybridObject<{ios: 'swift'; android: 'kotlin'}> {
822
835
 
823
836
  /**
824
837
  * Validate a receipt on the appropriate platform
838
+ * @deprecated Use `verifyPurchase` instead. This function will be removed in a future version.
825
839
  * @param params - Receipt validation parameters including SKU and platform-specific options
826
840
  * @returns Promise<NitroReceiptValidationResultIOS | NitroReceiptValidationResultAndroid> - Platform-specific validation result
827
841
  */
package/src/types.ts CHANGED
@@ -917,6 +917,14 @@ export type RequestPurchaseProps =
917
917
  useAlternativeBilling?: boolean | null;
918
918
  };
919
919
 
920
+ /**
921
+ * Platform-specific purchase request parameters.
922
+ *
923
+ * Note: "Platforms" refers to the SDK/OS level (apple, google), not the store.
924
+ * - apple: Always targets App Store
925
+ * - google: Targets Play Store by default, or Horizon when built with horizon flavor
926
+ * (determined at build time, not runtime)
927
+ */
920
928
  export interface RequestPurchasePropsByPlatforms {
921
929
  /** @deprecated Use google instead */
922
930
  android?: (RequestPurchaseAndroidProps | null);
@@ -963,6 +971,14 @@ export interface RequestSubscriptionIosProps {
963
971
  withOffer?: (DiscountOfferInputIOS | null);
964
972
  }
965
973
 
974
+ /**
975
+ * Platform-specific subscription request parameters.
976
+ *
977
+ * Note: "Platforms" refers to the SDK/OS level (apple, google), not the store.
978
+ * - apple: Always targets App Store
979
+ * - google: Targets Play Store by default, or Horizon when built with horizon flavor
980
+ * (determined at build time, not runtime)
981
+ */
966
982
  export interface RequestSubscriptionPropsByPlatforms {
967
983
  /** @deprecated Use google instead */
968
984
  android?: (RequestSubscriptionAndroidProps | null);
@@ -984,12 +1000,18 @@ export interface RequestVerifyPurchaseWithIapkitGoogleProps {
984
1000
  purchaseToken: string;
985
1001
  }
986
1002
 
1003
+ /**
1004
+ * Platform-specific verification parameters for IAPKit.
1005
+ *
1006
+ * - apple: Verifies via App Store (JWS token)
1007
+ * - google: Verifies via Play Store (purchase token)
1008
+ */
987
1009
  export interface RequestVerifyPurchaseWithIapkitProps {
988
1010
  /** API key used for the Authorization header (Bearer {apiKey}). */
989
1011
  apiKey?: (string | null);
990
- /** Apple verification parameters. */
1012
+ /** Apple App Store verification parameters. */
991
1013
  apple?: (RequestVerifyPurchaseWithIapkitAppleProps | null);
992
- /** Google verification parameters. */
1014
+ /** Google Play Store verification parameters. */
993
1015
  google?: (RequestVerifyPurchaseWithIapkitGoogleProps | null);
994
1016
  }
995
1017
 
@@ -1088,21 +1110,76 @@ export interface ValidTimeWindowAndroid {
1088
1110
  startTimeMillis: string;
1089
1111
  }
1090
1112
 
1091
- export interface VerifyPurchaseAndroidOptions {
1113
+ /**
1114
+ * Apple App Store verification parameters.
1115
+ * Used for server-side receipt validation via App Store Server API.
1116
+ */
1117
+ export interface VerifyPurchaseAppleOptions {
1118
+ /** Product SKU to validate */
1119
+ sku: string;
1120
+ }
1121
+
1122
+ /**
1123
+ * Google Play Store verification parameters.
1124
+ * Used for server-side receipt validation via Google Play Developer API.
1125
+ *
1126
+ * ⚠️ SECURITY: Contains sensitive tokens (accessToken, purchaseToken). Do not log or persist this data.
1127
+ */
1128
+ export interface VerifyPurchaseGoogleOptions {
1129
+ /**
1130
+ * Google OAuth2 access token for API authentication.
1131
+ * ⚠️ Sensitive: Do not log this value.
1132
+ */
1092
1133
  accessToken: string;
1134
+ /** Whether this is a subscription purchase (affects API endpoint used) */
1093
1135
  isSub?: (boolean | null);
1136
+ /** Android package name (e.g., com.example.app) */
1094
1137
  packageName: string;
1095
- productToken: string;
1138
+ /**
1139
+ * Purchase token from the purchase response.
1140
+ * ⚠️ Sensitive: Do not log this value.
1141
+ */
1142
+ purchaseToken: string;
1143
+ /** Product SKU to validate */
1144
+ sku: string;
1096
1145
  }
1097
1146
 
1098
- export interface VerifyPurchaseProps {
1099
- /** Android-specific validation options */
1100
- androidOptions?: (VerifyPurchaseAndroidOptions | null);
1101
- /** Product SKU to validate */
1147
+ /**
1148
+ * Meta Horizon (Quest) verification parameters.
1149
+ * Used for server-side entitlement verification via Meta's S2S API.
1150
+ * POST https://graph.oculus.com/$APP_ID/verify_entitlement
1151
+ *
1152
+ * ⚠️ SECURITY: Contains sensitive token (accessToken). Do not log or persist this data.
1153
+ */
1154
+ export interface VerifyPurchaseHorizonOptions {
1155
+ /**
1156
+ * Access token for Meta API authentication (OC|$APP_ID|$APP_SECRET or User Access Token).
1157
+ * ⚠️ Sensitive: Do not log this value.
1158
+ */
1159
+ accessToken: string;
1160
+ /** The SKU for the add-on item, defined in Meta Developer Dashboard */
1102
1161
  sku: string;
1162
+ /** The user ID of the user whose purchase you want to verify */
1163
+ userId: string;
1103
1164
  }
1104
1165
 
1105
- export type VerifyPurchaseResult = VerifyPurchaseResultAndroid | VerifyPurchaseResultIOS;
1166
+ /**
1167
+ * Platform-specific purchase verification parameters.
1168
+ *
1169
+ * - apple: Verifies via App Store Server API
1170
+ * - google: Verifies via Google Play Developer API
1171
+ * - horizon: Verifies via Meta's S2S API (verify_entitlement endpoint)
1172
+ */
1173
+ export interface VerifyPurchaseProps {
1174
+ /** Apple App Store verification parameters. */
1175
+ apple?: (VerifyPurchaseAppleOptions | null);
1176
+ /** Google Play Store verification parameters. */
1177
+ google?: (VerifyPurchaseGoogleOptions | null);
1178
+ /** Meta Horizon (Quest) verification parameters. */
1179
+ horizon?: (VerifyPurchaseHorizonOptions | null);
1180
+ }
1181
+
1182
+ export type VerifyPurchaseResult = VerifyPurchaseResultAndroid | VerifyPurchaseResultHorizon | VerifyPurchaseResultIOS;
1106
1183
 
1107
1184
  export interface VerifyPurchaseResultAndroid {
1108
1185
  autoRenewing: boolean;
@@ -1125,6 +1202,17 @@ export interface VerifyPurchaseResultAndroid {
1125
1202
  testTransaction: boolean;
1126
1203
  }
1127
1204
 
1205
+ /**
1206
+ * Result from Meta Horizon verify_entitlement API.
1207
+ * Returns verification status and grant time for the entitlement.
1208
+ */
1209
+ export interface VerifyPurchaseResultHorizon {
1210
+ /** Unix timestamp (seconds) when the entitlement was granted. */
1211
+ grantTime?: (number | null);
1212
+ /** Whether the entitlement verification succeeded. */
1213
+ success: boolean;
1214
+ }
1215
+
1128
1216
  export interface VerifyPurchaseResultIOS {
1129
1217
  /** Whether the receipt is valid */
1130
1218
  isValid: boolean;
@@ -1,7 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <Workspace
3
- version = "1.0">
4
- <FileRef
5
- location = "self:">
6
- </FileRef>
7
- </Workspace>
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0">
4
- <dict>
5
- <key>IDEDidComputeMac32BitWarning</key>
6
- <true/>
7
- </dict>
8
- </plist>
@@ -1,3 +0,0 @@
1
- import type { ConfigPlugin } from 'expo/config-plugins';
2
- declare const _default: ConfigPlugin<void>;
3
- export default _default;
@@ -1,81 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const config_plugins_1 = require("expo/config-plugins");
4
- const pkg = require('../../package.json');
5
- // Global flag to prevent duplicate logs
6
- let hasLoggedPluginExecution = false;
7
- const addLineToGradle = (content, anchor, lineToAdd, offset = 1) => {
8
- const lines = content.split('\n');
9
- const index = lines.findIndex((line) => line.match(anchor));
10
- if (index === -1) {
11
- console.warn(`Anchor "${anchor}" not found in build.gradle. Appending to end.`);
12
- lines.push(lineToAdd);
13
- }
14
- else {
15
- lines.splice(index + offset, 0, lineToAdd);
16
- }
17
- return lines.join('\n');
18
- };
19
- const modifyAppBuildGradle = (gradle) => {
20
- let modified = gradle;
21
- // Add billing library dependencies to app-level build.gradle
22
- const billingDep = ` implementation "com.android.billingclient:billing-ktx:8.0.0"`;
23
- const gmsDep = ` implementation "com.google.android.gms:play-services-base:18.1.0"`;
24
- let hasAddedDependency = false;
25
- if (!modified.includes(billingDep)) {
26
- modified = addLineToGradle(modified, /dependencies\s*{/, billingDep);
27
- hasAddedDependency = true;
28
- }
29
- if (!modified.includes(gmsDep)) {
30
- modified = addLineToGradle(modified, /dependencies\s*{/, gmsDep, 1);
31
- hasAddedDependency = true;
32
- }
33
- // Log only once and only if we actually added dependencies
34
- if (hasAddedDependency && !hasLoggedPluginExecution) {
35
- console.log('🛠️ react-native-iap: Added billing dependencies to build.gradle');
36
- }
37
- return modified;
38
- };
39
- const withIapAndroid = (config) => {
40
- // Add IAP dependencies to app build.gradle
41
- config = (0, config_plugins_1.withAppBuildGradle)(config, (config) => {
42
- config.modResults.contents = modifyAppBuildGradle(config.modResults.contents);
43
- return config;
44
- });
45
- config = (0, config_plugins_1.withAndroidManifest)(config, (config) => {
46
- const manifest = config.modResults;
47
- if (!manifest.manifest['uses-permission']) {
48
- manifest.manifest['uses-permission'] = [];
49
- }
50
- const permissions = manifest.manifest['uses-permission'];
51
- const billingPerm = { $: { 'android:name': 'com.android.vending.BILLING' } };
52
- const alreadyExists = permissions.some((p) => p.$['android:name'] === 'com.android.vending.BILLING');
53
- if (!alreadyExists) {
54
- permissions.push(billingPerm);
55
- if (!hasLoggedPluginExecution) {
56
- console.log('✅ Added com.android.vending.BILLING to AndroidManifest.xml');
57
- }
58
- }
59
- else {
60
- if (!hasLoggedPluginExecution) {
61
- console.log('ℹ️ com.android.vending.BILLING already exists in AndroidManifest.xml');
62
- }
63
- }
64
- return config;
65
- });
66
- return config;
67
- };
68
- const withIAP = (config, _props) => {
69
- try {
70
- const result = withIapAndroid(config);
71
- // Set flag after first execution to prevent duplicate logs
72
- hasLoggedPluginExecution = true;
73
- return result;
74
- }
75
- catch (error) {
76
- config_plugins_1.WarningAggregator.addWarningAndroid('react-native-iap', `react-native-iap plugin encountered an error: ${error}`);
77
- console.error('react-native-iap plugin error:', error);
78
- return config;
79
- }
80
- };
81
- exports.default = (0, config_plugins_1.createRunOncePlugin)(withIAP, pkg.name, pkg.version);
@@ -1 +0,0 @@
1
- {"root":["../src/withiap.ts"],"version":"5.9.2"}