expo-iap 3.3.0-rc.1 → 3.3.0-rc.3
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 -22
- package/android/src/main/java/expo/modules/iap/ExpoIapModule.kt +17 -13
- package/build/index.d.ts.map +1 -1
- package/build/index.js +16 -12
- package/build/index.js.map +1 -1
- package/build/modules/ios.d.ts.map +1 -1
- package/build/modules/ios.js +4 -2
- package/build/modules/ios.js.map +1 -1
- package/build/types.d.ts +94 -9
- package/build/types.d.ts.map +1 -1
- package/build/types.js.map +1 -1
- package/coverage/clover.xml +57 -55
- package/coverage/coverage-final.json +2 -2
- package/coverage/lcov-report/index.html +14 -14
- package/coverage/lcov-report/src/index.html +14 -14
- package/coverage/lcov-report/src/index.ts.html +34 -22
- package/coverage/lcov-report/src/modules/android.ts.html +1 -1
- package/coverage/lcov-report/src/modules/index.html +1 -1
- package/coverage/lcov-report/src/modules/ios.ts.html +13 -7
- package/coverage/lcov-report/src/utils/debug.ts.html +1 -1
- package/coverage/lcov-report/src/utils/errorMapping.ts.html +1 -1
- package/coverage/lcov-report/src/utils/index.html +1 -1
- package/coverage/lcov.info +100 -96
- package/ios/ExpoIapModule.swift +1 -1
- package/openiap-versions.json +3 -3
- package/package.json +1 -1
- package/plugin/build/withIAP.d.ts +8 -5
- package/plugin/build/withIAP.js +12 -3
- package/plugin/src/withIAP.ts +18 -9
- package/src/index.ts +16 -12
- package/src/modules/ios.ts +4 -2
- package/src/types.ts +97 -9
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { ConfigPlugin } from 'expo/config-plugins';
|
|
2
2
|
import { withIosAlternativeBilling, type IOSAlternativeBillingConfig } from './withIosAlternativeBilling';
|
|
3
3
|
export interface ExpoIapPluginOptions {
|
|
4
|
+
/**
|
|
5
|
+
* IAPKit API key for server-side receipt verification.
|
|
6
|
+
* Get your API key from https://iapkit.com
|
|
7
|
+
* This will be available via `Constants.expoConfig?.extra?.iapkitApiKey`
|
|
8
|
+
*/
|
|
9
|
+
iapkitApiKey?: string;
|
|
4
10
|
/** Local development path for OpenIAP library */
|
|
5
11
|
localPath?: string | {
|
|
6
12
|
ios?: string;
|
|
@@ -46,11 +52,8 @@ export interface ExpoIapPluginOptions {
|
|
|
46
52
|
*/
|
|
47
53
|
horizonAppId?: string;
|
|
48
54
|
};
|
|
49
|
-
/** @deprecated Use ios.alternativeBilling instead */
|
|
50
|
-
iosAlternativeBilling?: IOSAlternativeBillingConfig;
|
|
51
|
-
/** @deprecated Use android.horizonAppId instead */
|
|
52
|
-
horizonAppId?: string;
|
|
53
55
|
}
|
|
54
|
-
|
|
56
|
+
declare const withIap: ConfigPlugin<ExpoIapPluginOptions | void>;
|
|
57
|
+
export { withIosAlternativeBilling, withIap };
|
|
55
58
|
declare const _default: ConfigPlugin<void | ExpoIapPluginOptions>;
|
|
56
59
|
export default _default;
|
package/plugin/build/withIAP.js
CHANGED
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.withIosAlternativeBilling = void 0;
|
|
39
|
+
exports.withIap = exports.withIosAlternativeBilling = void 0;
|
|
40
40
|
const config_plugins_1 = require("expo/config-plugins");
|
|
41
41
|
const fs = __importStar(require("fs"));
|
|
42
42
|
const path = __importStar(require("path"));
|
|
@@ -219,10 +219,18 @@ const withIapIOS = (config, options) => {
|
|
|
219
219
|
};
|
|
220
220
|
const withIap = (config, options) => {
|
|
221
221
|
try {
|
|
222
|
+
// Add iapkitApiKey to extra if provided
|
|
223
|
+
if (options?.iapkitApiKey) {
|
|
224
|
+
config.extra = {
|
|
225
|
+
...config.extra,
|
|
226
|
+
iapkitApiKey: options.iapkitApiKey,
|
|
227
|
+
};
|
|
228
|
+
logOnce('🔑 [expo-iap] Added iapkitApiKey to config.extra');
|
|
229
|
+
}
|
|
222
230
|
// Read Horizon configuration from modules
|
|
223
231
|
const isHorizonEnabled = options?.modules?.horizon ?? false;
|
|
224
|
-
const horizonAppId = options?.android?.horizonAppId
|
|
225
|
-
const iosAlternativeBilling = options?.ios?.alternativeBilling
|
|
232
|
+
const horizonAppId = options?.android?.horizonAppId;
|
|
233
|
+
const iosAlternativeBilling = options?.ios?.alternativeBilling;
|
|
226
234
|
logOnce(`🔍 [expo-iap] Config values: horizonAppId=${horizonAppId}, isHorizonEnabled=${isHorizonEnabled}`);
|
|
227
235
|
// Respect explicit flag; fall back to presence of localPath only when flag is unset
|
|
228
236
|
const isLocalDev = options?.enableLocalDev ?? !!options?.localPath;
|
|
@@ -270,4 +278,5 @@ const withIap = (config, options) => {
|
|
|
270
278
|
return config;
|
|
271
279
|
}
|
|
272
280
|
};
|
|
281
|
+
exports.withIap = withIap;
|
|
273
282
|
exports.default = (0, config_plugins_1.createRunOncePlugin)(withIap, pkg.name, pkg.version);
|
package/plugin/src/withIAP.ts
CHANGED
|
@@ -289,6 +289,12 @@ const withIapIOS: ConfigPlugin<IOSAlternativeBillingConfig | undefined> = (
|
|
|
289
289
|
};
|
|
290
290
|
|
|
291
291
|
export interface ExpoIapPluginOptions {
|
|
292
|
+
/**
|
|
293
|
+
* IAPKit API key for server-side receipt verification.
|
|
294
|
+
* Get your API key from https://iapkit.com
|
|
295
|
+
* This will be available via `Constants.expoConfig?.extra?.iapkitApiKey`
|
|
296
|
+
*/
|
|
297
|
+
iapkitApiKey?: string;
|
|
292
298
|
/** Local development path for OpenIAP library */
|
|
293
299
|
localPath?:
|
|
294
300
|
| string
|
|
@@ -336,10 +342,6 @@ export interface ExpoIapPluginOptions {
|
|
|
336
342
|
*/
|
|
337
343
|
horizonAppId?: string;
|
|
338
344
|
};
|
|
339
|
-
/** @deprecated Use ios.alternativeBilling instead */
|
|
340
|
-
iosAlternativeBilling?: IOSAlternativeBillingConfig;
|
|
341
|
-
/** @deprecated Use android.horizonAppId instead */
|
|
342
|
-
horizonAppId?: string;
|
|
343
345
|
}
|
|
344
346
|
|
|
345
347
|
const withIap: ConfigPlugin<ExpoIapPluginOptions | void> = (
|
|
@@ -347,13 +349,20 @@ const withIap: ConfigPlugin<ExpoIapPluginOptions | void> = (
|
|
|
347
349
|
options,
|
|
348
350
|
) => {
|
|
349
351
|
try {
|
|
352
|
+
// Add iapkitApiKey to extra if provided
|
|
353
|
+
if (options?.iapkitApiKey) {
|
|
354
|
+
config.extra = {
|
|
355
|
+
...config.extra,
|
|
356
|
+
iapkitApiKey: options.iapkitApiKey,
|
|
357
|
+
};
|
|
358
|
+
logOnce('🔑 [expo-iap] Added iapkitApiKey to config.extra');
|
|
359
|
+
}
|
|
360
|
+
|
|
350
361
|
// Read Horizon configuration from modules
|
|
351
362
|
const isHorizonEnabled = options?.modules?.horizon ?? false;
|
|
352
363
|
|
|
353
|
-
const horizonAppId =
|
|
354
|
-
|
|
355
|
-
const iosAlternativeBilling =
|
|
356
|
-
options?.ios?.alternativeBilling ?? options?.iosAlternativeBilling;
|
|
364
|
+
const horizonAppId = options?.android?.horizonAppId;
|
|
365
|
+
const iosAlternativeBilling = options?.ios?.alternativeBilling;
|
|
357
366
|
|
|
358
367
|
logOnce(
|
|
359
368
|
`🔍 [expo-iap] Config values: horizonAppId=${horizonAppId}, isHorizonEnabled=${isHorizonEnabled}`,
|
|
@@ -416,5 +425,5 @@ const withIap: ConfigPlugin<ExpoIapPluginOptions | void> = (
|
|
|
416
425
|
}
|
|
417
426
|
};
|
|
418
427
|
|
|
419
|
-
export {withIosAlternativeBilling};
|
|
428
|
+
export {withIosAlternativeBilling, withIap};
|
|
420
429
|
export default createRunOncePlugin(withIap, pkg.name, pkg.version);
|
package/src/index.ts
CHANGED
|
@@ -727,29 +727,33 @@ export const deepLinkToSubscriptions: MutationField<
|
|
|
727
727
|
export const validateReceipt: MutationField<'validateReceipt'> = async (
|
|
728
728
|
options,
|
|
729
729
|
) => {
|
|
730
|
-
const {
|
|
730
|
+
const {apple, google} = options as MutationValidateReceiptArgs;
|
|
731
731
|
|
|
732
732
|
if (Platform.OS === 'ios') {
|
|
733
|
-
|
|
733
|
+
if (!apple?.sku) {
|
|
734
|
+
throw new Error('iOS validation requires apple.sku');
|
|
735
|
+
}
|
|
736
|
+
return validateReceiptIOS({apple: {sku: apple.sku}});
|
|
734
737
|
}
|
|
735
738
|
|
|
736
739
|
if (Platform.OS === 'android') {
|
|
737
740
|
if (
|
|
738
|
-
!
|
|
739
|
-
!
|
|
740
|
-
!
|
|
741
|
-
!
|
|
741
|
+
!google ||
|
|
742
|
+
!google.sku ||
|
|
743
|
+
!google.packageName ||
|
|
744
|
+
!google.purchaseToken ||
|
|
745
|
+
!google.accessToken
|
|
742
746
|
) {
|
|
743
747
|
throw new Error(
|
|
744
|
-
'Android validation requires packageName,
|
|
748
|
+
'Android validation requires google.sku, google.packageName, google.purchaseToken, and google.accessToken',
|
|
745
749
|
);
|
|
746
750
|
}
|
|
747
751
|
return validateReceiptAndroid({
|
|
748
|
-
packageName:
|
|
749
|
-
productId: sku,
|
|
750
|
-
productToken:
|
|
751
|
-
accessToken:
|
|
752
|
-
isSub:
|
|
752
|
+
packageName: google.packageName,
|
|
753
|
+
productId: google.sku,
|
|
754
|
+
productToken: google.purchaseToken,
|
|
755
|
+
accessToken: google.accessToken,
|
|
756
|
+
isSub: google.isSub ?? undefined,
|
|
753
757
|
});
|
|
754
758
|
}
|
|
755
759
|
|
package/src/modules/ios.ts
CHANGED
|
@@ -237,10 +237,12 @@ export const getTransactionJwsIOS: QueryField<'getTransactionJwsIOS'> = async (
|
|
|
237
237
|
*/
|
|
238
238
|
const validateReceiptIOSImpl = async (props: VerifyPurchaseProps | string) => {
|
|
239
239
|
const sku =
|
|
240
|
-
typeof props === 'string'
|
|
240
|
+
typeof props === 'string'
|
|
241
|
+
? props
|
|
242
|
+
: (props as VerifyPurchaseProps)?.apple?.sku;
|
|
241
243
|
|
|
242
244
|
if (!sku) {
|
|
243
|
-
throw new Error('validateReceiptIOS requires a SKU');
|
|
245
|
+
throw new Error('validateReceiptIOS requires a SKU (via apple.sku)');
|
|
244
246
|
}
|
|
245
247
|
|
|
246
248
|
return (await ExpoIapModule.validateReceiptIOS(
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
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
|
-
|
|
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;
|