expo-iap 3.0.7 → 3.0.8
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/CLAUDE.md +12 -0
- package/android/build.gradle +1 -1
- package/build/index.d.ts +14 -66
- package/build/index.d.ts.map +1 -1
- package/build/index.js +149 -151
- package/build/index.js.map +1 -1
- package/build/modules/android.d.ts +7 -12
- package/build/modules/android.d.ts.map +1 -1
- package/build/modules/android.js +13 -11
- package/build/modules/android.js.map +1 -1
- package/build/modules/ios.d.ts +19 -35
- package/build/modules/ios.d.ts.map +1 -1
- package/build/modules/ios.js +86 -33
- package/build/modules/ios.js.map +1 -1
- package/build/types.d.ts +99 -76
- package/build/types.d.ts.map +1 -1
- package/build/types.js +1 -0
- package/build/types.js.map +1 -1
- package/build/useIAP.d.ts +6 -11
- package/build/useIAP.d.ts.map +1 -1
- package/build/useIAP.js +44 -15
- package/build/useIAP.js.map +1 -1
- package/build/utils/purchase.d.ts +9 -0
- package/build/utils/purchase.d.ts.map +1 -0
- package/build/utils/purchase.js +34 -0
- package/build/utils/purchase.js.map +1 -0
- package/package.json +2 -2
- package/plugin/build/withIAP.js +3 -3
- package/plugin/src/withIAP.ts +3 -3
- package/src/index.ts +217 -250
- package/src/modules/android.ts +23 -22
- package/src/modules/ios.ts +123 -45
- package/src/types.ts +131 -85
- package/src/useIAP.ts +83 -42
- package/src/utils/purchase.ts +52 -0
- package/.copilot-instructions.md +0 -321
- package/.cursorrules +0 -321
package/src/modules/android.ts
CHANGED
|
@@ -5,7 +5,11 @@ import {Linking} from 'react-native';
|
|
|
5
5
|
import ExpoIapModule from '../ExpoIapModule';
|
|
6
6
|
|
|
7
7
|
// Types
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
DeepLinkOptions,
|
|
10
|
+
MutationField,
|
|
11
|
+
ReceiptValidationResultAndroid,
|
|
12
|
+
} from '../types';
|
|
9
13
|
|
|
10
14
|
// Type guards
|
|
11
15
|
export function isProductAndroid<T extends {platform?: string}>(
|
|
@@ -22,25 +26,24 @@ export function isProductAndroid<T extends {platform?: string}>(
|
|
|
22
26
|
/**
|
|
23
27
|
* Deep link to subscriptions screen on Android.
|
|
24
28
|
* @param {Object} params - The parameters object
|
|
25
|
-
* @param {string} params.
|
|
26
|
-
* @param {string} params.
|
|
29
|
+
* @param {string} params.skuAndroid - The product's SKU (on Android)
|
|
30
|
+
* @param {string} params.packageNameAndroid - The package name of your Android app (e.g., 'com.example.app')
|
|
27
31
|
* @returns {Promise<void>}
|
|
28
32
|
*
|
|
29
33
|
* @example
|
|
30
34
|
* ```typescript
|
|
31
35
|
* await deepLinkToSubscriptionsAndroid({
|
|
32
|
-
*
|
|
33
|
-
*
|
|
36
|
+
* skuAndroid: 'subscription_id',
|
|
37
|
+
* packageNameAndroid: 'com.example.app'
|
|
34
38
|
* });
|
|
35
39
|
* ```
|
|
36
40
|
*/
|
|
37
|
-
export const deepLinkToSubscriptionsAndroid = async (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}): Promise<void> => {
|
|
41
|
+
export const deepLinkToSubscriptionsAndroid = async (
|
|
42
|
+
options?: DeepLinkOptions | null,
|
|
43
|
+
): Promise<void> => {
|
|
44
|
+
const sku = options?.skuAndroid ?? undefined;
|
|
45
|
+
const packageName = options?.packageNameAndroid ?? undefined;
|
|
46
|
+
|
|
44
47
|
// Prefer native deep link implementation via OpenIAP module
|
|
45
48
|
if (ExpoIapModule?.deepLinkToSubscriptionsAndroid) {
|
|
46
49
|
return (ExpoIapModule as any).deepLinkToSubscriptionsAndroid({
|
|
@@ -117,28 +120,26 @@ export const validateReceiptAndroid = async ({
|
|
|
117
120
|
* @param {string} params.token - The product's token (on Android)
|
|
118
121
|
* @returns {Promise<VoidResult | void>}
|
|
119
122
|
*/
|
|
120
|
-
export const acknowledgePurchaseAndroid
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}): Promise<VoidResult | boolean | void> => {
|
|
125
|
-
const result = await ExpoIapModule.acknowledgePurchaseAndroid(token);
|
|
123
|
+
export const acknowledgePurchaseAndroid: MutationField<
|
|
124
|
+
'acknowledgePurchaseAndroid'
|
|
125
|
+
> = async (purchaseToken) => {
|
|
126
|
+
const result = await ExpoIapModule.acknowledgePurchaseAndroid(purchaseToken);
|
|
126
127
|
|
|
127
|
-
if (typeof result === 'boolean'
|
|
128
|
+
if (typeof result === 'boolean') {
|
|
128
129
|
return result;
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
if (result && typeof result === 'object') {
|
|
132
133
|
const record = result as Record<string, unknown>;
|
|
133
134
|
if (typeof record.success === 'boolean') {
|
|
134
|
-
return
|
|
135
|
+
return record.success;
|
|
135
136
|
}
|
|
136
137
|
if (typeof record.responseCode === 'number') {
|
|
137
|
-
return
|
|
138
|
+
return record.responseCode === 0;
|
|
138
139
|
}
|
|
139
140
|
}
|
|
140
141
|
|
|
141
|
-
return
|
|
142
|
+
return true;
|
|
142
143
|
};
|
|
143
144
|
|
|
144
145
|
/**
|
package/src/modules/ios.ts
CHANGED
|
@@ -6,14 +6,18 @@ import ExpoIapModule from '../ExpoIapModule';
|
|
|
6
6
|
|
|
7
7
|
// Types
|
|
8
8
|
import type {
|
|
9
|
-
|
|
9
|
+
MutationField,
|
|
10
|
+
ProductIOS,
|
|
10
11
|
Purchase,
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
PurchaseIOS,
|
|
13
|
+
QueryField,
|
|
14
|
+
ReceiptValidationProps,
|
|
13
15
|
ReceiptValidationResultIOS,
|
|
16
|
+
SubscriptionStatusIOS,
|
|
14
17
|
} from '../types';
|
|
15
18
|
import type {PurchaseError} from '../purchase-error';
|
|
16
19
|
import {Linking} from 'react-native';
|
|
20
|
+
import {normalizePurchaseId, normalizePurchaseList} from '../utils/purchase';
|
|
17
21
|
|
|
18
22
|
export type TransactionEvent = {
|
|
19
23
|
transaction?: Purchase;
|
|
@@ -44,8 +48,8 @@ export function isProductIOS<T extends {platform?: string}>(
|
|
|
44
48
|
*
|
|
45
49
|
* @platform iOS
|
|
46
50
|
*/
|
|
47
|
-
export const syncIOS = ()
|
|
48
|
-
return ExpoIapModule.syncIOS();
|
|
51
|
+
export const syncIOS: MutationField<'syncIOS'> = async () => {
|
|
52
|
+
return Boolean(await ExpoIapModule.syncIOS());
|
|
49
53
|
};
|
|
50
54
|
|
|
51
55
|
/**
|
|
@@ -57,10 +61,13 @@ export const syncIOS = (): Promise<null> => {
|
|
|
57
61
|
*
|
|
58
62
|
* @platform iOS
|
|
59
63
|
*/
|
|
60
|
-
export const isEligibleForIntroOfferIOS
|
|
61
|
-
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
+
export const isEligibleForIntroOfferIOS: QueryField<
|
|
65
|
+
'isEligibleForIntroOfferIOS'
|
|
66
|
+
> = async (groupID) => {
|
|
67
|
+
if (!groupID) {
|
|
68
|
+
throw new Error('isEligibleForIntroOfferIOS requires a groupID');
|
|
69
|
+
}
|
|
70
|
+
return ExpoIapModule.isEligibleForIntroOfferIOS(groupID);
|
|
64
71
|
};
|
|
65
72
|
|
|
66
73
|
/**
|
|
@@ -72,10 +79,14 @@ export const isEligibleForIntroOfferIOS = (
|
|
|
72
79
|
*
|
|
73
80
|
* @platform iOS
|
|
74
81
|
*/
|
|
75
|
-
export const subscriptionStatusIOS
|
|
76
|
-
|
|
77
|
-
)
|
|
78
|
-
|
|
82
|
+
export const subscriptionStatusIOS: QueryField<
|
|
83
|
+
'subscriptionStatusIOS'
|
|
84
|
+
> = async (sku) => {
|
|
85
|
+
if (!sku) {
|
|
86
|
+
throw new Error('subscriptionStatusIOS requires a SKU');
|
|
87
|
+
}
|
|
88
|
+
const status = await ExpoIapModule.subscriptionStatusIOS(sku);
|
|
89
|
+
return (status ?? []) as SubscriptionStatusIOS[];
|
|
79
90
|
};
|
|
80
91
|
|
|
81
92
|
/**
|
|
@@ -87,8 +98,14 @@ export const subscriptionStatusIOS = (
|
|
|
87
98
|
*
|
|
88
99
|
* @platform iOS
|
|
89
100
|
*/
|
|
90
|
-
export const currentEntitlementIOS
|
|
91
|
-
|
|
101
|
+
export const currentEntitlementIOS: QueryField<
|
|
102
|
+
'currentEntitlementIOS'
|
|
103
|
+
> = async (sku) => {
|
|
104
|
+
if (!sku) {
|
|
105
|
+
throw new Error('currentEntitlementIOS requires a SKU');
|
|
106
|
+
}
|
|
107
|
+
const purchase = await ExpoIapModule.currentEntitlementIOS(sku);
|
|
108
|
+
return normalizePurchaseId((purchase ?? null) as PurchaseIOS | null);
|
|
92
109
|
};
|
|
93
110
|
|
|
94
111
|
/**
|
|
@@ -100,8 +117,14 @@ export const currentEntitlementIOS = (sku: string): Promise<Purchase> => {
|
|
|
100
117
|
*
|
|
101
118
|
* @platform iOS
|
|
102
119
|
*/
|
|
103
|
-
export const latestTransactionIOS
|
|
104
|
-
|
|
120
|
+
export const latestTransactionIOS: QueryField<'latestTransactionIOS'> = async (
|
|
121
|
+
sku,
|
|
122
|
+
) => {
|
|
123
|
+
if (!sku) {
|
|
124
|
+
throw new Error('latestTransactionIOS requires a SKU');
|
|
125
|
+
}
|
|
126
|
+
const transaction = await ExpoIapModule.latestTransactionIOS(sku);
|
|
127
|
+
return normalizePurchaseId((transaction ?? null) as PurchaseIOS | null);
|
|
105
128
|
};
|
|
106
129
|
|
|
107
130
|
/**
|
|
@@ -113,11 +136,14 @@ export const latestTransactionIOS = (sku: string): Promise<Purchase> => {
|
|
|
113
136
|
*
|
|
114
137
|
* @platform iOS
|
|
115
138
|
*/
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
)
|
|
120
|
-
|
|
139
|
+
export const beginRefundRequestIOS: MutationField<
|
|
140
|
+
'beginRefundRequestIOS'
|
|
141
|
+
> = async (sku) => {
|
|
142
|
+
if (!sku) {
|
|
143
|
+
throw new Error('beginRefundRequestIOS requires a SKU');
|
|
144
|
+
}
|
|
145
|
+
const status = await ExpoIapModule.beginRefundRequestIOS(sku);
|
|
146
|
+
return status ?? null;
|
|
121
147
|
};
|
|
122
148
|
|
|
123
149
|
/**
|
|
@@ -129,8 +155,11 @@ export const beginRefundRequestIOS = (
|
|
|
129
155
|
*
|
|
130
156
|
* @platform iOS
|
|
131
157
|
*/
|
|
132
|
-
export const showManageSubscriptionsIOS
|
|
133
|
-
|
|
158
|
+
export const showManageSubscriptionsIOS: MutationField<
|
|
159
|
+
'showManageSubscriptionsIOS'
|
|
160
|
+
> = async () => {
|
|
161
|
+
const purchases = await ExpoIapModule.showManageSubscriptionsIOS();
|
|
162
|
+
return normalizePurchaseList((purchases ?? []) as PurchaseIOS[]);
|
|
134
163
|
};
|
|
135
164
|
|
|
136
165
|
/**
|
|
@@ -143,10 +172,12 @@ export const showManageSubscriptionsIOS = (): Promise<Purchase[]> => {
|
|
|
143
172
|
*
|
|
144
173
|
* @returns {Promise<string>} Base64 encoded receipt data
|
|
145
174
|
*/
|
|
146
|
-
export const
|
|
175
|
+
export const getReceiptDataIOS: QueryField<'getReceiptDataIOS'> = async () => {
|
|
147
176
|
return ExpoIapModule.getReceiptDataIOS();
|
|
148
177
|
};
|
|
149
178
|
|
|
179
|
+
export const getReceiptIOS = getReceiptDataIOS;
|
|
180
|
+
|
|
150
181
|
/**
|
|
151
182
|
* Check if a transaction is verified through StoreKit 2.
|
|
152
183
|
* StoreKit 2 performs local verification of transaction JWS signatures.
|
|
@@ -157,7 +188,12 @@ export const getReceiptIOS = (): Promise<string> => {
|
|
|
157
188
|
*
|
|
158
189
|
* @platform iOS
|
|
159
190
|
*/
|
|
160
|
-
export const isTransactionVerifiedIOS
|
|
191
|
+
export const isTransactionVerifiedIOS: QueryField<
|
|
192
|
+
'isTransactionVerifiedIOS'
|
|
193
|
+
> = async (sku) => {
|
|
194
|
+
if (!sku) {
|
|
195
|
+
throw new Error('isTransactionVerifiedIOS requires a SKU');
|
|
196
|
+
}
|
|
161
197
|
return ExpoIapModule.isTransactionVerifiedIOS(sku);
|
|
162
198
|
};
|
|
163
199
|
|
|
@@ -171,8 +207,14 @@ export const isTransactionVerifiedIOS = (sku: string): Promise<boolean> => {
|
|
|
171
207
|
*
|
|
172
208
|
* @platform iOS
|
|
173
209
|
*/
|
|
174
|
-
export const getTransactionJwsIOS
|
|
175
|
-
|
|
210
|
+
export const getTransactionJwsIOS: QueryField<'getTransactionJwsIOS'> = async (
|
|
211
|
+
sku,
|
|
212
|
+
) => {
|
|
213
|
+
if (!sku) {
|
|
214
|
+
throw new Error('getTransactionJwsIOS requires a SKU');
|
|
215
|
+
}
|
|
216
|
+
const jws = await ExpoIapModule.getTransactionJwsIOS(sku);
|
|
217
|
+
return jws ?? '';
|
|
176
218
|
};
|
|
177
219
|
|
|
178
220
|
/**
|
|
@@ -190,13 +232,34 @@ export const getTransactionJwsIOS = (sku: string): Promise<string> => {
|
|
|
190
232
|
* latestTransaction?: Purchase;
|
|
191
233
|
* }>}
|
|
192
234
|
*/
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
)
|
|
196
|
-
const
|
|
197
|
-
|
|
235
|
+
const validateReceiptIOSImpl = async (
|
|
236
|
+
props: ReceiptValidationProps | string,
|
|
237
|
+
) => {
|
|
238
|
+
const sku =
|
|
239
|
+
typeof props === 'string' ? props : (props as ReceiptValidationProps)?.sku;
|
|
240
|
+
|
|
241
|
+
if (!sku) {
|
|
242
|
+
throw new Error('validateReceiptIOS requires a SKU');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const result = (await ExpoIapModule.validateReceiptIOS(
|
|
246
|
+
sku,
|
|
247
|
+
)) as ReceiptValidationResultIOS;
|
|
248
|
+
const normalizedLatest = normalizePurchaseId(
|
|
249
|
+
result.latestTransaction ?? undefined,
|
|
250
|
+
);
|
|
251
|
+
if (normalizedLatest === result.latestTransaction) {
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
...result,
|
|
256
|
+
latestTransaction: normalizedLatest ?? null,
|
|
257
|
+
};
|
|
198
258
|
};
|
|
199
259
|
|
|
260
|
+
export const validateReceiptIOS =
|
|
261
|
+
validateReceiptIOSImpl as QueryField<'validateReceiptIOS'>;
|
|
262
|
+
|
|
200
263
|
/**
|
|
201
264
|
* Present the code redemption sheet for offer codes (iOS only).
|
|
202
265
|
* This allows users to redeem promotional codes for in-app purchases and subscriptions.
|
|
@@ -208,8 +271,10 @@ export const validateReceiptIOS = async (
|
|
|
208
271
|
*
|
|
209
272
|
* @platform iOS
|
|
210
273
|
*/
|
|
211
|
-
export const presentCodeRedemptionSheetIOS
|
|
212
|
-
|
|
274
|
+
export const presentCodeRedemptionSheetIOS: MutationField<
|
|
275
|
+
'presentCodeRedemptionSheetIOS'
|
|
276
|
+
> = async () => {
|
|
277
|
+
return Boolean(await ExpoIapModule.presentCodeRedemptionSheetIOS());
|
|
213
278
|
};
|
|
214
279
|
|
|
215
280
|
/**
|
|
@@ -226,8 +291,10 @@ export const presentCodeRedemptionSheetIOS = (): Promise<boolean> => {
|
|
|
226
291
|
* @platform iOS
|
|
227
292
|
* @since iOS 16.0
|
|
228
293
|
*/
|
|
229
|
-
export const getAppTransactionIOS
|
|
230
|
-
|
|
294
|
+
export const getAppTransactionIOS: QueryField<
|
|
295
|
+
'getAppTransactionIOS'
|
|
296
|
+
> = async () => {
|
|
297
|
+
return (await ExpoIapModule.getAppTransactionIOS()) ?? null;
|
|
231
298
|
};
|
|
232
299
|
|
|
233
300
|
/**
|
|
@@ -240,8 +307,11 @@ export const getAppTransactionIOS = (): Promise<AppTransaction | null> => {
|
|
|
240
307
|
*
|
|
241
308
|
* @platform iOS
|
|
242
309
|
*/
|
|
243
|
-
export const getPromotedProductIOS
|
|
244
|
-
|
|
310
|
+
export const getPromotedProductIOS: QueryField<
|
|
311
|
+
'getPromotedProductIOS'
|
|
312
|
+
> = async () => {
|
|
313
|
+
const product = await ExpoIapModule.getPromotedProductIOS();
|
|
314
|
+
return (product ?? null) as ProductIOS | null;
|
|
245
315
|
};
|
|
246
316
|
|
|
247
317
|
/**
|
|
@@ -253,8 +323,11 @@ export const getPromotedProductIOS = (): Promise<Product | null> => {
|
|
|
253
323
|
*
|
|
254
324
|
* @platform iOS
|
|
255
325
|
*/
|
|
256
|
-
export const requestPurchaseOnPromotedProductIOS
|
|
257
|
-
|
|
326
|
+
export const requestPurchaseOnPromotedProductIOS: MutationField<
|
|
327
|
+
'requestPurchaseOnPromotedProductIOS'
|
|
328
|
+
> = async () => {
|
|
329
|
+
await ExpoIapModule.requestPurchaseOnPromotedProductIOS();
|
|
330
|
+
return true;
|
|
258
331
|
};
|
|
259
332
|
|
|
260
333
|
/**
|
|
@@ -263,8 +336,11 @@ export const requestPurchaseOnPromotedProductIOS = (): Promise<void> => {
|
|
|
263
336
|
* @returns Promise resolving to array of pending transactions
|
|
264
337
|
* @platform iOS
|
|
265
338
|
*/
|
|
266
|
-
export const getPendingTransactionsIOS
|
|
267
|
-
|
|
339
|
+
export const getPendingTransactionsIOS: QueryField<
|
|
340
|
+
'getPendingTransactionsIOS'
|
|
341
|
+
> = async () => {
|
|
342
|
+
const transactions = await ExpoIapModule.getPendingTransactionsIOS();
|
|
343
|
+
return normalizePurchaseList((transactions ?? []) as PurchaseIOS[]);
|
|
268
344
|
};
|
|
269
345
|
|
|
270
346
|
/**
|
|
@@ -273,8 +349,10 @@ export const getPendingTransactionsIOS = (): Promise<any[]> => {
|
|
|
273
349
|
* @returns Promise resolving when transaction is cleared
|
|
274
350
|
* @platform iOS
|
|
275
351
|
*/
|
|
276
|
-
export const clearTransactionIOS
|
|
277
|
-
|
|
352
|
+
export const clearTransactionIOS: MutationField<
|
|
353
|
+
'clearTransactionIOS'
|
|
354
|
+
> = async () => {
|
|
355
|
+
return Boolean(await ExpoIapModule.clearTransactionIOS());
|
|
278
356
|
};
|
|
279
357
|
|
|
280
358
|
/**
|