react-native-iap 15.3.5 → 15.4.0-rc.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.
- package/README.md +1 -1
- package/android/build.gradle +13 -5
- package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +16 -3
- package/ios/HybridRnIap.swift +12 -0
- package/lib/module/index.js +93 -75
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.kepler.js +170 -0
- package/lib/module/index.kepler.js.map +1 -0
- package/lib/module/types/amazon-devices-kepler/index.d.js +2 -0
- package/lib/module/types/amazon-devices-kepler/index.d.js.map +1 -0
- package/lib/module/types.js +5 -2
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/error.js +98 -15
- package/lib/module/utils/error.js.map +1 -1
- package/lib/module/utils/type-bridge.js +4 -1
- package/lib/module/utils/type-bridge.js.map +1 -1
- package/lib/module/vega-adapter.js +981 -0
- package/lib/module/vega-adapter.js.map +1 -0
- package/lib/module/vega.js +10 -0
- package/lib/module/vega.js.map +1 -0
- package/lib/module/vega.kepler.js +18 -0
- package/lib/module/vega.kepler.js.map +1 -0
- package/lib/typescript/plugin/src/withIAP.d.ts +33 -0
- package/lib/typescript/plugin/src/withIAP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +9 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/index.kepler.d.ts +55 -0
- package/lib/typescript/src/index.kepler.d.ts.map +1 -0
- package/lib/typescript/src/specs/RnIap.nitro.d.ts +10 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +16 -3
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/error.d.ts +1 -1
- package/lib/typescript/src/utils/error.d.ts.map +1 -1
- package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
- package/lib/typescript/src/vega-adapter.d.ts +76 -0
- package/lib/typescript/src/vega-adapter.d.ts.map +1 -0
- package/lib/typescript/src/vega.d.ts +4 -0
- package/lib/typescript/src/vega.d.ts.map +1 -0
- package/lib/typescript/src/vega.kepler.d.ts +4 -0
- package/lib/typescript/src/vega.kepler.d.ts.map +1 -0
- package/nitrogen/generated/android/NitroIap+autolinking.cmake +1 -0
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +5 -0
- package/nitrogen/generated/android/c++/JIapStore.hpp +3 -0
- package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithIapkitAmazonProps.hpp +71 -0
- package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithIapkitProps.hpp +9 -1
- package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithProviderProps.hpp +4 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.hpp +75 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_NitroVerifyPurchaseWithIapkitProps.hpp +4 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/IapStore.kt +2 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroVerifyPurchaseWithIapkitAmazonProps.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroVerifyPurchaseWithIapkitProps.kt +5 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.kt +53 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +47 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +3 -0
- package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +3 -0
- package/nitrogen/generated/ios/swift/IapStore.swift +4 -0
- package/nitrogen/generated/ios/swift/NitroVerifyPurchaseWithIapkitAmazonProps.swift +103 -0
- package/nitrogen/generated/ios/swift/NitroVerifyPurchaseWithIapkitProps.swift +38 -1
- package/nitrogen/generated/ios/swift/Variant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.swift +18 -0
- package/nitrogen/generated/shared/c++/IapStore.hpp +4 -0
- package/nitrogen/generated/shared/c++/NitroVerifyPurchaseWithIapkitAmazonProps.hpp +94 -0
- package/nitrogen/generated/shared/c++/NitroVerifyPurchaseWithIapkitProps.hpp +8 -1
- package/openiap-versions.json +2 -2
- package/package.json +17 -4
- package/plugin/build/withIAP.d.ts +33 -0
- package/plugin/build/withIAP.js +109 -42
- package/plugin/src/withIAP.ts +185 -55
- package/src/index.kepler.ts +311 -0
- package/src/index.ts +187 -78
- package/src/specs/RnIap.nitro.ts +13 -2
- package/src/types/amazon-devices-kepler/index.d.ts +14 -0
- package/src/types.ts +17 -3
- package/src/utils/error.ts +127 -14
- package/src/utils/type-bridge.ts +4 -1
- package/src/vega-adapter.ts +1503 -0
- package/src/vega.kepler.ts +21 -0
- package/src/vega.ts +10 -0
- package/android/src/test/java/com/margelo/nitro/iap/ListenerThreadSafetyTest.kt +0 -154
- package/android/src/test/java/com/margelo/nitro/iap/OpenIapExceptionTest.kt +0 -93
- package/android/src/test/java/com/margelo/nitro/iap/ProductQueryHelpersTest.kt +0 -140
- package/plugin/tsconfig.tsbuildinfo +0 -1
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,
|
|
@@ -64,6 +64,7 @@ import {
|
|
|
64
64
|
import {RnIapConsole} from './utils/debug';
|
|
65
65
|
import {getSuccessFromPurchaseVariant} from './utils/purchase';
|
|
66
66
|
import {parseAppTransactionPayload} from './utils';
|
|
67
|
+
import {getVegaIapModule, isVegaOS} from './vega';
|
|
67
68
|
|
|
68
69
|
// ------------------------------
|
|
69
70
|
// Billing Programs API (Android 8.2.0+)
|
|
@@ -72,9 +73,7 @@ import {parseAppTransactionPayload} from './utils';
|
|
|
72
73
|
// Note: BillingProgramAndroid, ExternalLinkLaunchModeAndroid, and ExternalLinkTypeAndroid
|
|
73
74
|
// are exported from './types' (auto-generated from openiap-gql).
|
|
74
75
|
// Import them here for use in this file's interfaces and functions.
|
|
75
|
-
import type {
|
|
76
|
-
BillingProgramAndroid,
|
|
77
|
-
} from './types';
|
|
76
|
+
import type {BillingProgramAndroid} from './types';
|
|
78
77
|
|
|
79
78
|
// Export all types
|
|
80
79
|
export type {
|
|
@@ -85,6 +84,7 @@ export type {
|
|
|
85
84
|
} from './specs/RnIap.nitro';
|
|
86
85
|
export * from './types';
|
|
87
86
|
export * from './utils/error';
|
|
87
|
+
export * from './vega';
|
|
88
88
|
|
|
89
89
|
export type ProductTypeInput = 'inapp' | 'in-app' | 'subs';
|
|
90
90
|
|
|
@@ -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
|
|
|
@@ -167,6 +178,10 @@ let iapRef: RnIap | null = null;
|
|
|
167
178
|
*/
|
|
168
179
|
export const isNitroReady = (): boolean => {
|
|
169
180
|
if (iapRef) return true;
|
|
181
|
+
if (isVegaOS()) {
|
|
182
|
+
iapRef = getVegaIapModule();
|
|
183
|
+
return Boolean(iapRef);
|
|
184
|
+
}
|
|
170
185
|
try {
|
|
171
186
|
iapRef = NitroModules.createHybridObject<RnIap>('RnIap');
|
|
172
187
|
return true;
|
|
@@ -201,10 +216,25 @@ export const isStandardIOS = (): boolean => {
|
|
|
201
216
|
return Platform.OS === 'ios' && !isTVOS() && !isMacOS();
|
|
202
217
|
};
|
|
203
218
|
|
|
219
|
+
const isAndroidStoreRuntime = (): boolean => {
|
|
220
|
+
return Platform.OS === 'android' || isVegaOS();
|
|
221
|
+
};
|
|
222
|
+
|
|
204
223
|
const IAP = {
|
|
205
224
|
get instance(): RnIap {
|
|
206
225
|
if (iapRef) return iapRef;
|
|
207
226
|
|
|
227
|
+
if (isVegaOS()) {
|
|
228
|
+
const vegaModule = getVegaIapModule();
|
|
229
|
+
if (!vegaModule) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
'Amazon Vega IAP module is unavailable. Install @amazon-devices/keplerscript-appstore-iap-lib in the Vega app target and build with the React Native for Vega kepler platform.',
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
iapRef = vegaModule;
|
|
235
|
+
return iapRef;
|
|
236
|
+
}
|
|
237
|
+
|
|
208
238
|
// Attempt to create the HybridObject and map common Nitro/JSI readiness errors
|
|
209
239
|
try {
|
|
210
240
|
iapRef = NitroModules.createHybridObject<RnIap>('RnIap');
|
|
@@ -743,7 +773,7 @@ function tryAttachSubscriptionBillingIssueNative(): void {
|
|
|
743
773
|
const msg = toErrorMessage(e);
|
|
744
774
|
if (msg.includes('Nitro runtime not installed')) {
|
|
745
775
|
RnIapConsole.warn(
|
|
746
|
-
'[subscriptionBillingIssueListener] Nitro not ready yet; will retry
|
|
776
|
+
'[subscriptionBillingIssueListener] Nitro not ready yet; will retry after initConnection()',
|
|
747
777
|
);
|
|
748
778
|
} else {
|
|
749
779
|
throw e;
|
|
@@ -852,7 +882,7 @@ export const fetchProducts: QueryField<'fetchProducts'> = async (request) => {
|
|
|
852
882
|
// item.type === 'subs' case
|
|
853
883
|
// For Android, check if subscription items have actual offers
|
|
854
884
|
if (
|
|
855
|
-
|
|
885
|
+
isAndroidStoreRuntime() &&
|
|
856
886
|
item.platform === 'android' &&
|
|
857
887
|
item.type === 'subs'
|
|
858
888
|
) {
|
|
@@ -905,8 +935,10 @@ export const fetchProducts: QueryField<'fetchProducts'> = async (request) => {
|
|
|
905
935
|
|
|
906
936
|
return convertedProducts as FetchProductsResult;
|
|
907
937
|
} catch (error) {
|
|
908
|
-
|
|
909
|
-
|
|
938
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
939
|
+
'[fetchProducts] Failed:',
|
|
940
|
+
error,
|
|
941
|
+
);
|
|
910
942
|
throw createPurchaseError({
|
|
911
943
|
code: parsedError.code,
|
|
912
944
|
message: parsedError.message,
|
|
@@ -971,11 +1003,26 @@ export const getAvailablePurchases: QueryField<
|
|
|
971
1003
|
}
|
|
972
1004
|
|
|
973
1005
|
return validPurchases.map(convertNitroPurchaseToPurchase);
|
|
974
|
-
} else if (
|
|
975
|
-
// For Android, we need to call twice for inapp and subs
|
|
1006
|
+
} else if (isAndroidStoreRuntime()) {
|
|
976
1007
|
const includeSuspended = Boolean(
|
|
977
1008
|
options?.includeSuspendedAndroid ?? false,
|
|
978
1009
|
);
|
|
1010
|
+
|
|
1011
|
+
if (isVegaOS()) {
|
|
1012
|
+
const nitroPurchases = await IAP.instance.getAvailablePurchases({
|
|
1013
|
+
android: {includeSuspended},
|
|
1014
|
+
});
|
|
1015
|
+
const validPurchases = nitroPurchases.filter(validateNitroPurchase);
|
|
1016
|
+
if (validPurchases.length !== nitroPurchases.length) {
|
|
1017
|
+
RnIapConsole.warn(
|
|
1018
|
+
`[getAvailablePurchases] Some Vega purchases failed validation: ${nitroPurchases.length - validPurchases.length} invalid`,
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
return validPurchases.map(convertNitroPurchaseToPurchase);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
// For Android Play/Horizon/Fire OS, query in-app items and subscriptions separately.
|
|
979
1026
|
const inappNitroPurchases = await IAP.instance.getAvailablePurchases({
|
|
980
1027
|
android: {type: 'inapp', includeSuspended},
|
|
981
1028
|
});
|
|
@@ -1027,8 +1074,10 @@ export const getPromotedProductIOS: QueryField<
|
|
|
1027
1074
|
const converted = convertNitroProductToProduct(nitroProduct);
|
|
1028
1075
|
return converted.platform === 'ios' ? (converted as ProductIOS) : null;
|
|
1029
1076
|
} catch (error) {
|
|
1030
|
-
|
|
1031
|
-
|
|
1077
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1078
|
+
'[getPromotedProductIOS] Failed:',
|
|
1079
|
+
error,
|
|
1080
|
+
);
|
|
1032
1081
|
throw createPurchaseError({
|
|
1033
1082
|
code: parsedError.code,
|
|
1034
1083
|
message: parsedError.message,
|
|
@@ -1073,9 +1122,9 @@ export const getStorefrontIOS: QueryField<'getStorefrontIOS'> = async () => {
|
|
|
1073
1122
|
* @see {@link https://openiap.dev/docs/apis/get-storefront}
|
|
1074
1123
|
*/
|
|
1075
1124
|
export const getStorefront: QueryField<'getStorefront'> = async () => {
|
|
1076
|
-
if (Platform.OS !== 'ios' &&
|
|
1125
|
+
if (Platform.OS !== 'ios' && !isAndroidStoreRuntime()) {
|
|
1077
1126
|
RnIapConsole.warn(
|
|
1078
|
-
'[getStorefront] Storefront lookup is only supported on iOS and
|
|
1127
|
+
'[getStorefront] Storefront lookup is only supported on iOS, Android, and Vega OS.',
|
|
1079
1128
|
);
|
|
1080
1129
|
return '';
|
|
1081
1130
|
}
|
|
@@ -1181,8 +1230,10 @@ export const subscriptionStatusIOS: QueryField<
|
|
|
1181
1230
|
.filter((status): status is NitroSubscriptionStatus => status != null)
|
|
1182
1231
|
.map(convertNitroSubscriptionStatusToSubscriptionStatusIOS);
|
|
1183
1232
|
} catch (error) {
|
|
1184
|
-
|
|
1185
|
-
|
|
1233
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1234
|
+
'[subscriptionStatusIOS] Failed:',
|
|
1235
|
+
error,
|
|
1236
|
+
);
|
|
1186
1237
|
throw createPurchaseError({
|
|
1187
1238
|
code: parsedError.code,
|
|
1188
1239
|
message: parsedError.message,
|
|
@@ -1215,8 +1266,10 @@ export const currentEntitlementIOS: QueryField<
|
|
|
1215
1266
|
}
|
|
1216
1267
|
return null;
|
|
1217
1268
|
} catch (error) {
|
|
1218
|
-
|
|
1219
|
-
|
|
1269
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1270
|
+
'[currentEntitlementIOS] Failed:',
|
|
1271
|
+
error,
|
|
1272
|
+
);
|
|
1220
1273
|
throw createPurchaseError({
|
|
1221
1274
|
code: parsedError.code,
|
|
1222
1275
|
message: parsedError.message,
|
|
@@ -1249,8 +1302,10 @@ export const latestTransactionIOS: QueryField<'latestTransactionIOS'> = async (
|
|
|
1249
1302
|
}
|
|
1250
1303
|
return null;
|
|
1251
1304
|
} catch (error) {
|
|
1252
|
-
|
|
1253
|
-
|
|
1305
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1306
|
+
'[latestTransactionIOS] Failed:',
|
|
1307
|
+
error,
|
|
1308
|
+
);
|
|
1254
1309
|
throw createPurchaseError({
|
|
1255
1310
|
code: parsedError.code,
|
|
1256
1311
|
message: parsedError.message,
|
|
@@ -1282,8 +1337,10 @@ export const getPendingTransactionsIOS: QueryField<
|
|
|
1282
1337
|
(purchase): purchase is PurchaseIOS => purchase.platform === 'ios',
|
|
1283
1338
|
);
|
|
1284
1339
|
} catch (error) {
|
|
1285
|
-
|
|
1286
|
-
|
|
1340
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1341
|
+
'[getPendingTransactionsIOS] Failed:',
|
|
1342
|
+
error,
|
|
1343
|
+
);
|
|
1287
1344
|
throw createPurchaseError({
|
|
1288
1345
|
code: parsedError.code,
|
|
1289
1346
|
message: parsedError.message,
|
|
@@ -1313,8 +1370,10 @@ export const getAllTransactionsIOS: QueryField<
|
|
|
1313
1370
|
(purchase): purchase is PurchaseIOS => purchase.platform === 'ios',
|
|
1314
1371
|
);
|
|
1315
1372
|
} catch (error) {
|
|
1316
|
-
|
|
1317
|
-
|
|
1373
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1374
|
+
'[getAllTransactionsIOS] Failed:',
|
|
1375
|
+
error,
|
|
1376
|
+
);
|
|
1318
1377
|
throw createPurchaseError({
|
|
1319
1378
|
code: parsedError.code,
|
|
1320
1379
|
message: parsedError.message,
|
|
@@ -1346,8 +1405,10 @@ export const showManageSubscriptionsIOS: MutationField<
|
|
|
1346
1405
|
(purchase): purchase is PurchaseIOS => purchase.platform === 'ios',
|
|
1347
1406
|
);
|
|
1348
1407
|
} catch (error) {
|
|
1349
|
-
|
|
1350
|
-
|
|
1408
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1409
|
+
'[showManageSubscriptionsIOS] Failed:',
|
|
1410
|
+
error,
|
|
1411
|
+
);
|
|
1351
1412
|
throw createPurchaseError({
|
|
1352
1413
|
code: parsedError.code,
|
|
1353
1414
|
message: parsedError.message,
|
|
@@ -1375,8 +1436,10 @@ export const isEligibleForIntroOfferIOS: QueryField<
|
|
|
1375
1436
|
try {
|
|
1376
1437
|
return await IAP.instance.isEligibleForIntroOfferIOS(groupID);
|
|
1377
1438
|
} catch (error) {
|
|
1378
|
-
|
|
1379
|
-
|
|
1439
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1440
|
+
'[isEligibleForIntroOfferIOS] Failed:',
|
|
1441
|
+
error,
|
|
1442
|
+
);
|
|
1380
1443
|
throw createPurchaseError({
|
|
1381
1444
|
code: parsedError.code,
|
|
1382
1445
|
message: parsedError.message,
|
|
@@ -1407,8 +1470,10 @@ export const getReceiptDataIOS: QueryField<'getReceiptDataIOS'> = async () => {
|
|
|
1407
1470
|
try {
|
|
1408
1471
|
return await IAP.instance.getReceiptDataIOS();
|
|
1409
1472
|
} catch (error) {
|
|
1410
|
-
|
|
1411
|
-
|
|
1473
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1474
|
+
'[getReceiptDataIOS] Failed:',
|
|
1475
|
+
error,
|
|
1476
|
+
);
|
|
1412
1477
|
throw createPurchaseError({
|
|
1413
1478
|
code: parsedError.code,
|
|
1414
1479
|
message: parsedError.message,
|
|
@@ -1435,8 +1500,10 @@ export const getReceiptIOS = async (): Promise<string> => {
|
|
|
1435
1500
|
}
|
|
1436
1501
|
return await IAP.instance.getReceiptDataIOS();
|
|
1437
1502
|
} catch (error) {
|
|
1438
|
-
|
|
1439
|
-
|
|
1503
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1504
|
+
'[getReceiptIOS] Failed:',
|
|
1505
|
+
error,
|
|
1506
|
+
);
|
|
1440
1507
|
throw createPurchaseError({
|
|
1441
1508
|
code: parsedError.code,
|
|
1442
1509
|
message: parsedError.message,
|
|
@@ -1463,8 +1530,10 @@ export const requestReceiptRefreshIOS = async (): Promise<string> => {
|
|
|
1463
1530
|
}
|
|
1464
1531
|
return await IAP.instance.getReceiptDataIOS();
|
|
1465
1532
|
} catch (error) {
|
|
1466
|
-
|
|
1467
|
-
|
|
1533
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1534
|
+
'[requestReceiptRefreshIOS] Failed:',
|
|
1535
|
+
error,
|
|
1536
|
+
);
|
|
1468
1537
|
throw createPurchaseError({
|
|
1469
1538
|
code: parsedError.code,
|
|
1470
1539
|
message: parsedError.message,
|
|
@@ -1492,8 +1561,10 @@ export const isTransactionVerifiedIOS: QueryField<
|
|
|
1492
1561
|
try {
|
|
1493
1562
|
return await IAP.instance.isTransactionVerifiedIOS(sku);
|
|
1494
1563
|
} catch (error) {
|
|
1495
|
-
|
|
1496
|
-
|
|
1564
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1565
|
+
'[isTransactionVerifiedIOS] Failed:',
|
|
1566
|
+
error,
|
|
1567
|
+
);
|
|
1497
1568
|
throw createPurchaseError({
|
|
1498
1569
|
code: parsedError.code,
|
|
1499
1570
|
message: parsedError.message,
|
|
@@ -1521,8 +1592,10 @@ export const getTransactionJwsIOS: QueryField<'getTransactionJwsIOS'> = async (
|
|
|
1521
1592
|
try {
|
|
1522
1593
|
return await IAP.instance.getTransactionJwsIOS(sku);
|
|
1523
1594
|
} catch (error) {
|
|
1524
|
-
|
|
1525
|
-
|
|
1595
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1596
|
+
'[getTransactionJwsIOS] Failed:',
|
|
1597
|
+
error,
|
|
1598
|
+
);
|
|
1526
1599
|
throw createPurchaseError({
|
|
1527
1600
|
code: parsedError.code,
|
|
1528
1601
|
message: parsedError.message,
|
|
@@ -1559,12 +1632,18 @@ export const initConnection: MutationField<'initConnection'> = async (
|
|
|
1559
1632
|
config,
|
|
1560
1633
|
) => {
|
|
1561
1634
|
try {
|
|
1562
|
-
|
|
1635
|
+
const result = await IAP.instance.initConnection(
|
|
1563
1636
|
config as Record<string, unknown> | undefined,
|
|
1564
1637
|
);
|
|
1638
|
+
if (subscriptionBillingIssueJsListeners.size > 0) {
|
|
1639
|
+
tryAttachSubscriptionBillingIssueNative();
|
|
1640
|
+
}
|
|
1641
|
+
return result;
|
|
1565
1642
|
} catch (error) {
|
|
1566
|
-
|
|
1567
|
-
|
|
1643
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1644
|
+
'Failed to initialize IAP connection:',
|
|
1645
|
+
error,
|
|
1646
|
+
);
|
|
1568
1647
|
throw createPurchaseError({
|
|
1569
1648
|
code: parsedError.code,
|
|
1570
1649
|
message: parsedError.message,
|
|
@@ -1586,8 +1665,10 @@ export const endConnection: MutationField<'endConnection'> = async () => {
|
|
|
1586
1665
|
resetListenerState();
|
|
1587
1666
|
return result;
|
|
1588
1667
|
} catch (error) {
|
|
1589
|
-
|
|
1590
|
-
|
|
1668
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1669
|
+
'Failed to end IAP connection:',
|
|
1670
|
+
error,
|
|
1671
|
+
);
|
|
1591
1672
|
throw createPurchaseError({
|
|
1592
1673
|
code: parsedError.code,
|
|
1593
1674
|
message: parsedError.message,
|
|
@@ -1613,8 +1694,10 @@ export const restorePurchases: MutationField<'restorePurchases'> = async () => {
|
|
|
1613
1694
|
onlyIncludeActiveItemsIOS: true,
|
|
1614
1695
|
});
|
|
1615
1696
|
} catch (error) {
|
|
1616
|
-
|
|
1617
|
-
|
|
1697
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1698
|
+
'Failed to restore purchases:',
|
|
1699
|
+
error,
|
|
1700
|
+
);
|
|
1618
1701
|
throw createPurchaseError({
|
|
1619
1702
|
code: parsedError.code,
|
|
1620
1703
|
message: parsedError.message,
|
|
@@ -1674,7 +1757,7 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
|
1674
1757
|
'Invalid request for iOS. The `sku` property is required.',
|
|
1675
1758
|
);
|
|
1676
1759
|
}
|
|
1677
|
-
} else if (
|
|
1760
|
+
} else if (isAndroidStoreRuntime()) {
|
|
1678
1761
|
// Support both 'google' (recommended) and 'android' (deprecated) fields
|
|
1679
1762
|
const androidRequest =
|
|
1680
1763
|
perPlatformRequest.google ?? perPlatformRequest.android;
|
|
@@ -1742,7 +1825,7 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
|
1742
1825
|
// Support both 'google' (recommended) and 'android' (deprecated) fields
|
|
1743
1826
|
const androidRequestSource =
|
|
1744
1827
|
perPlatformRequest.google ?? perPlatformRequest.android;
|
|
1745
|
-
if (
|
|
1828
|
+
if (isAndroidStoreRuntime() && androidRequestSource) {
|
|
1746
1829
|
const androidRequest = isSubs
|
|
1747
1830
|
? (androidRequestSource as RequestSubscriptionAndroidProps)
|
|
1748
1831
|
: (androidRequestSource as RequestPurchaseAndroidProps);
|
|
@@ -1798,8 +1881,10 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
|
1798
1881
|
|
|
1799
1882
|
return await IAP.instance.requestPurchase(unifiedRequest);
|
|
1800
1883
|
} catch (error) {
|
|
1801
|
-
|
|
1802
|
-
|
|
1884
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
1885
|
+
'Failed to request purchase:',
|
|
1886
|
+
error,
|
|
1887
|
+
);
|
|
1803
1888
|
throw createPurchaseError({
|
|
1804
1889
|
code: parsedError.code,
|
|
1805
1890
|
message: parsedError.message,
|
|
@@ -1849,7 +1934,7 @@ export const finishTransaction: MutationField<'finishTransaction'> = async (
|
|
|
1849
1934
|
transactionId: purchase.id,
|
|
1850
1935
|
},
|
|
1851
1936
|
};
|
|
1852
|
-
} else if (
|
|
1937
|
+
} else if (isAndroidStoreRuntime()) {
|
|
1853
1938
|
const token = purchase.purchaseToken ?? undefined;
|
|
1854
1939
|
|
|
1855
1940
|
if (!token) {
|
|
@@ -1907,9 +1992,9 @@ export const acknowledgePurchaseAndroid: MutationField<
|
|
|
1907
1992
|
'acknowledgePurchaseAndroid'
|
|
1908
1993
|
> = async (purchaseToken) => {
|
|
1909
1994
|
try {
|
|
1910
|
-
if (
|
|
1995
|
+
if (!isAndroidStoreRuntime()) {
|
|
1911
1996
|
throw new Error(
|
|
1912
|
-
'acknowledgePurchaseAndroid is only available on Android',
|
|
1997
|
+
'acknowledgePurchaseAndroid is only available on Android and Vega OS',
|
|
1913
1998
|
);
|
|
1914
1999
|
}
|
|
1915
2000
|
|
|
@@ -1921,8 +2006,10 @@ export const acknowledgePurchaseAndroid: MutationField<
|
|
|
1921
2006
|
});
|
|
1922
2007
|
return getSuccessFromPurchaseVariant(result, 'acknowledgePurchaseAndroid');
|
|
1923
2008
|
} catch (error) {
|
|
1924
|
-
|
|
1925
|
-
|
|
2009
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
2010
|
+
'Failed to acknowledge purchase Android:',
|
|
2011
|
+
error,
|
|
2012
|
+
);
|
|
1926
2013
|
throw createPurchaseError({
|
|
1927
2014
|
code: parsedError.code,
|
|
1928
2015
|
message: parsedError.message,
|
|
@@ -1948,8 +2035,10 @@ export const consumePurchaseAndroid: MutationField<
|
|
|
1948
2035
|
'consumePurchaseAndroid'
|
|
1949
2036
|
> = async (purchaseToken) => {
|
|
1950
2037
|
try {
|
|
1951
|
-
if (
|
|
1952
|
-
throw new Error(
|
|
2038
|
+
if (!isAndroidStoreRuntime()) {
|
|
2039
|
+
throw new Error(
|
|
2040
|
+
'consumePurchaseAndroid is only available on Android and Vega OS',
|
|
2041
|
+
);
|
|
1953
2042
|
}
|
|
1954
2043
|
|
|
1955
2044
|
const result = await IAP.instance.finishTransaction({
|
|
@@ -1960,8 +2049,10 @@ export const consumePurchaseAndroid: MutationField<
|
|
|
1960
2049
|
});
|
|
1961
2050
|
return getSuccessFromPurchaseVariant(result, 'consumePurchaseAndroid');
|
|
1962
2051
|
} catch (error) {
|
|
1963
|
-
|
|
1964
|
-
|
|
2052
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
2053
|
+
'Failed to consume purchase Android:',
|
|
2054
|
+
error,
|
|
2055
|
+
);
|
|
1965
2056
|
throw createPurchaseError({
|
|
1966
2057
|
code: parsedError.code,
|
|
1967
2058
|
message: parsedError.message,
|
|
@@ -2109,8 +2200,10 @@ export const validateReceipt: MutationField<'validateReceipt'> = async (
|
|
|
2109
2200
|
return result;
|
|
2110
2201
|
}
|
|
2111
2202
|
} catch (error) {
|
|
2112
|
-
|
|
2113
|
-
|
|
2203
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
2204
|
+
'[validateReceipt] Failed:',
|
|
2205
|
+
error,
|
|
2206
|
+
);
|
|
2114
2207
|
throw createPurchaseError({
|
|
2115
2208
|
code: parsedError.code,
|
|
2116
2209
|
message: parsedError.message,
|
|
@@ -2168,8 +2261,14 @@ export const validateReceiptIOS: QueryField<'validateReceiptIOS'> = async (
|
|
|
2168
2261
|
* provider: 'iapkit',
|
|
2169
2262
|
* iapkit: {
|
|
2170
2263
|
* apiKey: 'your-api-key',
|
|
2171
|
-
*
|
|
2172
|
-
*
|
|
2264
|
+
* // Choose exactly one store payload.
|
|
2265
|
+
* // apple: { jws: purchase.purchaseToken },
|
|
2266
|
+
* // google: { purchaseToken: purchase.purchaseToken },
|
|
2267
|
+
* amazon: {
|
|
2268
|
+
* userId: amazonUserId,
|
|
2269
|
+
* receiptId: purchase.purchaseToken,
|
|
2270
|
+
* sandbox: __DEV__,
|
|
2271
|
+
* },
|
|
2173
2272
|
* },
|
|
2174
2273
|
* });
|
|
2175
2274
|
* ```
|
|
@@ -2203,8 +2302,10 @@ export const verifyPurchaseWithProvider: MutationField<
|
|
|
2203
2302
|
errors: result.errors ?? null,
|
|
2204
2303
|
};
|
|
2205
2304
|
} catch (error) {
|
|
2206
|
-
|
|
2207
|
-
|
|
2305
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
2306
|
+
'[verifyPurchaseWithProvider] Failed:',
|
|
2307
|
+
error,
|
|
2308
|
+
);
|
|
2208
2309
|
throw createPurchaseError({
|
|
2209
2310
|
code: parsedError.code,
|
|
2210
2311
|
message: parsedError.message,
|
|
@@ -2230,8 +2331,7 @@ export const syncIOS: MutationField<'syncIOS'> = async () => {
|
|
|
2230
2331
|
const result = await IAP.instance.syncIOS();
|
|
2231
2332
|
return Boolean(result);
|
|
2232
2333
|
} catch (error) {
|
|
2233
|
-
|
|
2234
|
-
const parsedError = parseErrorStringToJsonObj(error);
|
|
2334
|
+
const parsedError = parseErrorAndLogIfNeeded('[syncIOS] Failed:', error);
|
|
2235
2335
|
throw createPurchaseError({
|
|
2236
2336
|
code: parsedError.code,
|
|
2237
2337
|
message: parsedError.message,
|
|
@@ -2259,8 +2359,10 @@ export const presentCodeRedemptionSheetIOS: MutationField<
|
|
|
2259
2359
|
const result = await IAP.instance.presentCodeRedemptionSheetIOS();
|
|
2260
2360
|
return Boolean(result);
|
|
2261
2361
|
} catch (error) {
|
|
2262
|
-
|
|
2263
|
-
|
|
2362
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
2363
|
+
'[presentCodeRedemptionSheetIOS] Failed:',
|
|
2364
|
+
error,
|
|
2365
|
+
);
|
|
2264
2366
|
throw createPurchaseError({
|
|
2265
2367
|
code: parsedError.code,
|
|
2266
2368
|
message: parsedError.message,
|
|
@@ -2315,11 +2417,10 @@ export const requestPurchaseOnPromotedProductIOS =
|
|
|
2315
2417
|
|
|
2316
2418
|
return true;
|
|
2317
2419
|
} catch (error) {
|
|
2318
|
-
|
|
2420
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
2319
2421
|
'[requestPurchaseOnPromotedProductIOS] Failed:',
|
|
2320
2422
|
error,
|
|
2321
2423
|
);
|
|
2322
|
-
const parsedError = parseErrorStringToJsonObj(error);
|
|
2323
2424
|
throw createPurchaseError({
|
|
2324
2425
|
code: parsedError.code,
|
|
2325
2426
|
message: parsedError.message,
|
|
@@ -2347,8 +2448,10 @@ export const clearTransactionIOS: MutationField<
|
|
|
2347
2448
|
await IAP.instance.clearTransactionIOS();
|
|
2348
2449
|
return true;
|
|
2349
2450
|
} catch (error) {
|
|
2350
|
-
|
|
2351
|
-
|
|
2451
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
2452
|
+
'[clearTransactionIOS] Failed:',
|
|
2453
|
+
error,
|
|
2454
|
+
);
|
|
2352
2455
|
throw createPurchaseError({
|
|
2353
2456
|
code: parsedError.code,
|
|
2354
2457
|
message: parsedError.message,
|
|
@@ -2377,8 +2480,10 @@ export const beginRefundRequestIOS: MutationField<
|
|
|
2377
2480
|
const status = await IAP.instance.beginRefundRequestIOS(sku);
|
|
2378
2481
|
return status ?? null;
|
|
2379
2482
|
} catch (error) {
|
|
2380
|
-
|
|
2381
|
-
|
|
2483
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
2484
|
+
'[beginRefundRequestIOS] Failed:',
|
|
2485
|
+
error,
|
|
2486
|
+
);
|
|
2382
2487
|
throw createPurchaseError({
|
|
2383
2488
|
code: parsedError.code,
|
|
2384
2489
|
message: parsedError.message,
|
|
@@ -2430,8 +2535,10 @@ export const deepLinkToSubscriptionsIOS = async (): Promise<boolean> => {
|
|
|
2430
2535
|
await IAP.instance.showManageSubscriptionsIOS();
|
|
2431
2536
|
return true;
|
|
2432
2537
|
} catch (error) {
|
|
2433
|
-
|
|
2434
|
-
|
|
2538
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
2539
|
+
'[deepLinkToSubscriptionsIOS] Failed:',
|
|
2540
|
+
error,
|
|
2541
|
+
);
|
|
2435
2542
|
throw createPurchaseError({
|
|
2436
2543
|
code: parsedError.code,
|
|
2437
2544
|
message: parsedError.message,
|
|
@@ -2512,8 +2619,10 @@ export const getActiveSubscriptions: QueryField<
|
|
|
2512
2619
|
RnIapConsole.error('IAP connection not initialized:', error);
|
|
2513
2620
|
throw error;
|
|
2514
2621
|
}
|
|
2515
|
-
|
|
2516
|
-
|
|
2622
|
+
const parsedError = parseErrorAndLogIfNeeded(
|
|
2623
|
+
'Failed to get active subscriptions:',
|
|
2624
|
+
error,
|
|
2625
|
+
);
|
|
2517
2626
|
throw createPurchaseError({
|
|
2518
2627
|
code: parsedError.code,
|
|
2519
2628
|
message: parsedError.message,
|
package/src/specs/RnIap.nitro.ts
CHANGED
|
@@ -88,7 +88,7 @@ export type IapkitPurchaseState =
|
|
|
88
88
|
|
|
89
89
|
// Store identifier for purchase origin
|
|
90
90
|
// Defined locally for Nitro codegen (not in GQL schema)
|
|
91
|
-
export type IapStore = 'unknown' | 'apple' | 'google' | 'horizon';
|
|
91
|
+
export type IapStore = 'unknown' | 'apple' | 'google' | 'horizon' | 'amazon';
|
|
92
92
|
|
|
93
93
|
// Purchase verification provider selection
|
|
94
94
|
// Defined locally for Nitro codegen (not in GQL schema)
|
|
@@ -149,7 +149,8 @@ export interface NitroReceiptValidationHorizonOptions {
|
|
|
149
149
|
userId: VerifyPurchaseHorizonOptions['userId'];
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
export type NitroPurchaseUpdatedListenerOptions =
|
|
152
|
+
export type NitroPurchaseUpdatedListenerOptions =
|
|
153
|
+
PurchaseUpdatedListenerOptions;
|
|
153
154
|
|
|
154
155
|
export interface NitroReceiptValidationParams {
|
|
155
156
|
apple?: NitroReceiptValidationAppleOptions | null;
|
|
@@ -383,8 +384,18 @@ export interface NitroVerifyPurchaseWithIapkitGoogleProps {
|
|
|
383
384
|
purchaseToken: string;
|
|
384
385
|
}
|
|
385
386
|
|
|
387
|
+
export interface NitroVerifyPurchaseWithIapkitAmazonProps {
|
|
388
|
+
/** Amazon Appstore receipt id returned by PurchaseResponse.getReceipt().getReceiptId(). */
|
|
389
|
+
receiptId: string;
|
|
390
|
+
/** Use Amazon RVS Cloud Sandbox for App Tester receipts. */
|
|
391
|
+
sandbox?: boolean | null;
|
|
392
|
+
/** Amazon Appstore user id returned by PurchaseResponse.getUserData().getUserId(). */
|
|
393
|
+
userId?: string | null;
|
|
394
|
+
}
|
|
395
|
+
|
|
386
396
|
export interface NitroVerifyPurchaseWithIapkitProps {
|
|
387
397
|
apiKey?: string | null;
|
|
398
|
+
amazon?: NitroVerifyPurchaseWithIapkitAmazonProps | null;
|
|
388
399
|
apple?: NitroVerifyPurchaseWithIapkitAppleProps | null;
|
|
389
400
|
google?: NitroVerifyPurchaseWithIapkitGoogleProps | null;
|
|
390
401
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare module '@amazon-devices/keplerscript-appstore-iap-lib' {
|
|
2
|
+
export const PurchasingService: {
|
|
3
|
+
getProductData(request: {skus: string[]}): Promise<unknown>;
|
|
4
|
+
getPurchaseUpdates(request: {reset: boolean}): Promise<unknown>;
|
|
5
|
+
getUserData(request: {
|
|
6
|
+
fetchUserProfileAccessConsentStatus: boolean;
|
|
7
|
+
}): Promise<unknown>;
|
|
8
|
+
notifyFulfillment(request: {
|
|
9
|
+
fulfillmentResult: number;
|
|
10
|
+
receiptId: string;
|
|
11
|
+
}): Promise<unknown>;
|
|
12
|
+
purchase(request: {sku: string}): Promise<unknown>;
|
|
13
|
+
};
|
|
14
|
+
}
|