expo-iap 2.6.0 → 2.6.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.
@@ -1,5 +1,11 @@
1
+ // External dependencies
1
2
  import {Platform} from 'react-native';
3
+
4
+ // Internal modules
2
5
  import {purchaseUpdatedListener} from '..';
6
+ import ExpoIapModule from '../ExpoIapModule';
7
+
8
+ // Types
3
9
  import {
4
10
  ProductPurchase,
5
11
  PurchaseError,
@@ -10,7 +16,6 @@ import type {
10
16
  ProductStatusIos,
11
17
  AppTransactionIOS,
12
18
  } from '../types/ExpoIapIos.types';
13
- import ExpoIapModule from '../ExpoIapModule';
14
19
 
15
20
  export type TransactionEvent = {
16
21
  transaction?: ProductPurchase;
@@ -88,49 +93,136 @@ export function isProductIos<T extends {platform?: string}>(
88
93
  /**
89
94
  * Sync state with Appstore (iOS only)
90
95
  * https://developer.apple.com/documentation/storekit/appstore/3791906-sync
96
+ *
97
+ * @returns Promise resolving to null on success
98
+ * @throws Error if called on non-iOS platform
99
+ *
100
+ * @platform iOS
91
101
  */
92
- export const sync = (): Promise<null> => ExpoIapModule.sync();
102
+ export const syncIOS = (): Promise<null> => {
103
+ if (Platform.OS !== 'ios') {
104
+ throw new Error('syncIOS: This method is only available on iOS');
105
+ }
106
+ return ExpoIapModule.sync();
107
+ };
93
108
 
94
109
  /**
110
+ * Check if user is eligible for introductory offer
111
+ *
112
+ * @param groupID The subscription group ID
113
+ * @returns Promise resolving to true if eligible
114
+ * @throws Error if called on non-iOS platform
95
115
  *
116
+ * @platform iOS
96
117
  */
97
- export const isEligibleForIntroOffer = (groupID: string): Promise<boolean> =>
98
- ExpoIapModule.isEligibleForIntroOffer(groupID);
118
+ export const isEligibleForIntroOfferIOS = (
119
+ groupID: string,
120
+ ): Promise<boolean> => {
121
+ if (Platform.OS !== 'ios') {
122
+ throw new Error(
123
+ 'isEligibleForIntroOfferIOS: This method is only available on iOS',
124
+ );
125
+ }
126
+ return ExpoIapModule.isEligibleForIntroOffer(groupID);
127
+ };
99
128
 
100
129
  /**
130
+ * Get subscription status for a specific SKU
131
+ *
132
+ * @param sku The product SKU
133
+ * @returns Promise resolving to array of subscription status
134
+ * @throws Error if called on non-iOS platform
101
135
  *
136
+ * @platform iOS
102
137
  */
103
-
104
- export const subscriptionStatus = (sku: string): Promise<ProductStatusIos[]> =>
105
- ExpoIapModule.subscriptionStatus(sku);
138
+ export const subscriptionStatusIOS = (
139
+ sku: string,
140
+ ): Promise<ProductStatusIos[]> => {
141
+ if (Platform.OS !== 'ios') {
142
+ throw new Error(
143
+ 'subscriptionStatusIOS: This method is only available on iOS',
144
+ );
145
+ }
146
+ return ExpoIapModule.subscriptionStatus(sku);
147
+ };
106
148
 
107
149
  /**
150
+ * Get current entitlement for a specific SKU
151
+ *
152
+ * @param sku The product SKU
153
+ * @returns Promise resolving to current entitlement
154
+ * @throws Error if called on non-iOS platform
108
155
  *
156
+ * @platform iOS
109
157
  */
110
- export const currentEntitlement = (sku: string): Promise<ProductPurchase> =>
111
- ExpoIapModule.currentEntitlement(sku);
158
+ export const currentEntitlementIOS = (
159
+ sku: string,
160
+ ): Promise<ProductPurchase> => {
161
+ if (Platform.OS !== 'ios') {
162
+ throw new Error(
163
+ 'currentEntitlementIOS: This method is only available on iOS',
164
+ );
165
+ }
166
+ return ExpoIapModule.currentEntitlement(sku);
167
+ };
112
168
 
113
169
  /**
170
+ * Get latest transaction for a specific SKU
171
+ *
172
+ * @param sku The product SKU
173
+ * @returns Promise resolving to latest transaction
174
+ * @throws Error if called on non-iOS platform
114
175
  *
176
+ * @platform iOS
115
177
  */
116
- export const latestTransaction = (sku: string): Promise<ProductPurchase> =>
117
- ExpoIapModule.latestTransaction(sku);
178
+ export const latestTransactionIOS = (sku: string): Promise<ProductPurchase> => {
179
+ if (Platform.OS !== 'ios') {
180
+ throw new Error(
181
+ 'latestTransactionIOS: This method is only available on iOS',
182
+ );
183
+ }
184
+ return ExpoIapModule.latestTransaction(sku);
185
+ };
118
186
 
119
187
  /**
188
+ * Begin refund request for a specific SKU
189
+ *
190
+ * @param sku The product SKU
191
+ * @returns Promise resolving to refund request status
192
+ * @throws Error if called on non-iOS platform
120
193
  *
194
+ * @platform iOS
121
195
  */
122
196
  type RefundRequestStatus = 'success' | 'userCancelled';
123
- export const beginRefundRequest = (sku: string): Promise<RefundRequestStatus> =>
124
- ExpoIapModule.beginRefundRequest(sku);
197
+ export const beginRefundRequestIOS = (
198
+ sku: string,
199
+ ): Promise<RefundRequestStatus> => {
200
+ if (Platform.OS !== 'ios') {
201
+ throw new Error(
202
+ 'beginRefundRequestIOS: This method is only available on iOS',
203
+ );
204
+ }
205
+ return ExpoIapModule.beginRefundRequest(sku);
206
+ };
125
207
 
126
208
  /**
127
209
  * Shows the system UI for managing subscriptions.
128
210
  * When the user changes subscription renewal status, the system will emit events to
129
211
  * purchaseUpdatedListener and transactionUpdatedIos listeners.
130
- * @returns {Promise<null>}
212
+ *
213
+ * @returns Promise resolving to null on success
214
+ * @throws Error if called on non-iOS platform
215
+ *
216
+ * @platform iOS
131
217
  */
132
- export const showManageSubscriptions = (): Promise<null> =>
133
- ExpoIapModule.showManageSubscriptions();
218
+ export const showManageSubscriptionsIOS = (): Promise<null> => {
219
+ if (Platform.OS !== 'ios') {
220
+ throw new Error(
221
+ 'showManageSubscriptionsIOS: This method is only available on iOS',
222
+ );
223
+ }
224
+ return ExpoIapModule.showManageSubscriptions();
225
+ };
134
226
 
135
227
  /**
136
228
  * Get the receipt data from the iOS device.
@@ -142,7 +234,7 @@ export const showManageSubscriptions = (): Promise<null> =>
142
234
  *
143
235
  * @returns {Promise<string>} Base64 encoded receipt data
144
236
  */
145
- export const getReceiptIos = (): Promise<string> => {
237
+ export const getReceiptIOS = (): Promise<string> => {
146
238
  if (Platform.OS !== 'ios') {
147
239
  throw new Error('This method is only available on iOS');
148
240
  }
@@ -153,12 +245,17 @@ export const getReceiptIos = (): Promise<string> => {
153
245
  * Check if a transaction is verified through StoreKit 2.
154
246
  * StoreKit 2 performs local verification of transaction JWS signatures.
155
247
  *
156
- * @param {string} sku The product's SKU (on iOS)
157
- * @returns {Promise<boolean>} True if the transaction is verified
248
+ * @param sku The product's SKU (on iOS)
249
+ * @returns Promise resolving to true if the transaction is verified
250
+ * @throws Error if called on non-iOS platform
251
+ *
252
+ * @platform iOS
158
253
  */
159
- export const isTransactionVerified = (sku: string): Promise<boolean> => {
254
+ export const isTransactionVerifiedIOS = (sku: string): Promise<boolean> => {
160
255
  if (Platform.OS !== 'ios') {
161
- throw new Error('This method is only available on iOS');
256
+ throw new Error(
257
+ 'isTransactionVerifiedIOS: This method is only available on iOS',
258
+ );
162
259
  }
163
260
  return ExpoIapModule.isTransactionVerified(sku);
164
261
  };
@@ -167,12 +264,17 @@ export const isTransactionVerified = (sku: string): Promise<boolean> => {
167
264
  * Get the JWS representation of a purchase for server-side verification.
168
265
  * The JWS (JSON Web Signature) can be verified on your server using Apple's public keys.
169
266
  *
170
- * @param {string} sku The product's SKU (on iOS)
171
- * @returns {Promise<string>} JWS representation of the transaction
267
+ * @param sku The product's SKU (on iOS)
268
+ * @returns Promise resolving to JWS representation of the transaction
269
+ * @throws Error if called on non-iOS platform
270
+ *
271
+ * @platform iOS
172
272
  */
173
- export const getTransactionJws = (sku: string): Promise<string> => {
273
+ export const getTransactionJwsIOS = (sku: string): Promise<string> => {
174
274
  if (Platform.OS !== 'ios') {
175
- throw new Error('This method is only available on iOS');
275
+ throw new Error(
276
+ 'getTransactionJwsIOS: This method is only available on iOS',
277
+ );
176
278
  }
177
279
  return ExpoIapModule.getTransactionJws(sku);
178
280
  };
@@ -192,7 +294,7 @@ export const getTransactionJws = (sku: string): Promise<string> => {
192
294
  * latestTransaction?: ProductPurchase;
193
295
  * }>}
194
296
  */
195
- export const validateReceiptIos = async (
297
+ export const validateReceiptIOS = async (
196
298
  sku: string,
197
299
  ): Promise<{
198
300
  isValid: boolean;
@@ -204,7 +306,7 @@ export const validateReceiptIos = async (
204
306
  throw new Error('This method is only available on iOS');
205
307
  }
206
308
 
207
- const result = await ExpoIapModule.validateReceiptIos(sku);
309
+ const result = await ExpoIapModule.validateReceiptIOS(sku);
208
310
  return result;
209
311
  };
210
312
 
@@ -214,12 +316,16 @@ export const validateReceiptIos = async (
214
316
  *
215
317
  * Note: This only works on real devices, not simulators.
216
318
  *
217
- * @returns {Promise<boolean>} True if the sheet was presented successfully
218
- * @throws {Error} If called on non-iOS platform or tvOS
319
+ * @returns Promise resolving to true if the sheet was presented successfully
320
+ * @throws Error if called on non-iOS platform or tvOS
321
+ *
322
+ * @platform iOS
219
323
  */
220
- export const presentCodeRedemptionSheet = (): Promise<boolean> => {
324
+ export const presentCodeRedemptionSheetIOS = (): Promise<boolean> => {
221
325
  if (Platform.OS !== 'ios') {
222
- throw new Error('This method is only available on iOS');
326
+ throw new Error(
327
+ 'presentCodeRedemptionSheetIOS: This method is only available on iOS',
328
+ );
223
329
  }
224
330
  return ExpoIapModule.presentCodeRedemptionSheet();
225
331
  };
@@ -228,12 +334,160 @@ export const presentCodeRedemptionSheet = (): Promise<boolean> => {
228
334
  * Get app transaction information (iOS 16.0+).
229
335
  * AppTransaction represents the initial purchase that unlocked the app.
230
336
  *
231
- * @returns {Promise<AppTransactionIOS | null>} The app transaction information or null if not available
232
- * @throws {Error} If called on non-iOS platform or iOS version < 16.0
337
+ * @returns Promise resolving to the app transaction information or null if not available
338
+ * @throws Error if called on non-iOS platform or iOS version < 16.0
339
+ *
340
+ * @platform iOS
233
341
  */
234
- export const getAppTransaction = (): Promise<AppTransactionIOS | null> => {
342
+ export const getAppTransactionIOS = (): Promise<AppTransactionIOS | null> => {
235
343
  if (Platform.OS !== 'ios') {
236
- throw new Error('This method is only available on iOS');
344
+ throw new Error(
345
+ 'getAppTransactionIOS: This method is only available on iOS',
346
+ );
237
347
  }
238
348
  return ExpoIapModule.getAppTransaction();
239
349
  };
350
+
351
+ // ============= DEPRECATED FUNCTIONS =============
352
+ // These will be removed in version 3.0.0
353
+
354
+ /**
355
+ * @deprecated Use `syncIOS` instead. This function will be removed in version 3.0.0.
356
+ */
357
+ export const sync = (): Promise<null> => {
358
+ console.warn(
359
+ '`sync` is deprecated. Use `syncIOS` instead. This function will be removed in version 3.0.0.',
360
+ );
361
+ return syncIOS();
362
+ };
363
+
364
+ /**
365
+ * @deprecated Use `isEligibleForIntroOfferIOS` instead. This function will be removed in version 3.0.0.
366
+ */
367
+ export const isEligibleForIntroOffer = (groupID: string): Promise<boolean> => {
368
+ console.warn(
369
+ '`isEligibleForIntroOffer` is deprecated. Use `isEligibleForIntroOfferIOS` instead. This function will be removed in version 3.0.0.',
370
+ );
371
+ return isEligibleForIntroOfferIOS(groupID);
372
+ };
373
+
374
+ /**
375
+ * @deprecated Use `subscriptionStatusIOS` instead. This function will be removed in version 3.0.0.
376
+ */
377
+ export const subscriptionStatus = (
378
+ sku: string,
379
+ ): Promise<ProductStatusIos[]> => {
380
+ console.warn(
381
+ '`subscriptionStatus` is deprecated. Use `subscriptionStatusIOS` instead. This function will be removed in version 3.0.0.',
382
+ );
383
+ return subscriptionStatusIOS(sku);
384
+ };
385
+
386
+ /**
387
+ * @deprecated Use `currentEntitlementIOS` instead. This function will be removed in version 3.0.0.
388
+ */
389
+ export const currentEntitlement = (sku: string): Promise<ProductPurchase> => {
390
+ console.warn(
391
+ '`currentEntitlement` is deprecated. Use `currentEntitlementIOS` instead. This function will be removed in version 3.0.0.',
392
+ );
393
+ return currentEntitlementIOS(sku);
394
+ };
395
+
396
+ /**
397
+ * @deprecated Use `latestTransactionIOS` instead. This function will be removed in version 3.0.0.
398
+ */
399
+ export const latestTransaction = (sku: string): Promise<ProductPurchase> => {
400
+ console.warn(
401
+ '`latestTransaction` is deprecated. Use `latestTransactionIOS` instead. This function will be removed in version 3.0.0.',
402
+ );
403
+ return latestTransactionIOS(sku);
404
+ };
405
+
406
+ /**
407
+ * @deprecated Use `beginRefundRequestIOS` instead. This function will be removed in version 3.0.0.
408
+ */
409
+ export const beginRefundRequest = (
410
+ sku: string,
411
+ ): Promise<RefundRequestStatus> => {
412
+ console.warn(
413
+ '`beginRefundRequest` is deprecated. Use `beginRefundRequestIOS` instead. This function will be removed in version 3.0.0.',
414
+ );
415
+ return beginRefundRequestIOS(sku);
416
+ };
417
+
418
+ /**
419
+ * @deprecated Use `showManageSubscriptionsIOS` instead. This function will be removed in version 3.0.0.
420
+ */
421
+ export const showManageSubscriptions = (): Promise<null> => {
422
+ console.warn(
423
+ '`showManageSubscriptions` is deprecated. Use `showManageSubscriptionsIOS` instead. This function will be removed in version 3.0.0.',
424
+ );
425
+ return showManageSubscriptionsIOS();
426
+ };
427
+
428
+ /**
429
+ * @deprecated Use `getReceiptIOS` instead. This function will be removed in version 3.0.0.
430
+ */
431
+ export const getReceiptIos = (): Promise<string> => {
432
+ console.warn(
433
+ '`getReceiptIos` is deprecated. Use `getReceiptIOS` instead. This function will be removed in version 3.0.0.',
434
+ );
435
+ return getReceiptIOS();
436
+ };
437
+
438
+ /**
439
+ * @deprecated Use `isTransactionVerifiedIOS` instead. This function will be removed in version 3.0.0.
440
+ */
441
+ export const isTransactionVerified = (sku: string): Promise<boolean> => {
442
+ console.warn(
443
+ '`isTransactionVerified` is deprecated. Use `isTransactionVerifiedIOS` instead. This function will be removed in version 3.0.0.',
444
+ );
445
+ return isTransactionVerifiedIOS(sku);
446
+ };
447
+
448
+ /**
449
+ * @deprecated Use `getTransactionJwsIOS` instead. This function will be removed in version 3.0.0.
450
+ */
451
+ export const getTransactionJws = (sku: string): Promise<string> => {
452
+ console.warn(
453
+ '`getTransactionJws` is deprecated. Use `getTransactionJwsIOS` instead. This function will be removed in version 3.0.0.',
454
+ );
455
+ return getTransactionJwsIOS(sku);
456
+ };
457
+
458
+ /**
459
+ * @deprecated Use `validateReceiptIOS` instead. This function will be removed in version 3.0.0.
460
+ */
461
+ export const validateReceiptIos = async (
462
+ sku: string,
463
+ ): Promise<{
464
+ isValid: boolean;
465
+ receiptData: string;
466
+ jwsRepresentation: string;
467
+ latestTransaction?: ProductPurchase;
468
+ }> => {
469
+ console.warn(
470
+ '`validateReceiptIos` is deprecated. Use `validateReceiptIOS` instead. This function will be removed in version 3.0.0.',
471
+ );
472
+ return validateReceiptIOS(sku);
473
+ };
474
+
475
+ /**
476
+ * @deprecated Use `presentCodeRedemptionSheetIOS` instead. This function will be removed in version 3.0.0.
477
+ */
478
+ export const presentCodeRedemptionSheet = (): Promise<boolean> => {
479
+ console.warn(
480
+ '`presentCodeRedemptionSheet` is deprecated. Use `presentCodeRedemptionSheetIOS` instead. This function will be removed in version 3.0.0.',
481
+ );
482
+ return presentCodeRedemptionSheetIOS();
483
+ };
484
+
485
+ /**
486
+ * @deprecated Use `getAppTransactionIOS` instead. This function will be removed in version 3.0.0.
487
+ */
488
+ export const getAppTransaction = (): Promise<AppTransactionIOS | null> => {
489
+ console.warn(
490
+ '`getAppTransaction` is deprecated. Use `getAppTransactionIOS` instead. This function will be removed in version 3.0.0.',
491
+ );
492
+ return getAppTransactionIOS();
493
+ };
package/src/useIap.ts CHANGED
@@ -1,3 +1,9 @@
1
+ // External dependencies
2
+ import {useCallback, useEffect, useState, useRef} from 'react';
3
+ import {Platform} from 'react-native';
4
+ import {EventSubscription} from 'expo-modules-core';
5
+
6
+ // Internal modules
1
7
  import {
2
8
  endConnection,
3
9
  initConnection,
@@ -10,9 +16,10 @@ import {
10
16
  getSubscriptions,
11
17
  requestPurchase as requestPurchaseInternal,
12
18
  } from './';
13
- import {sync, validateReceiptIos} from './modules/ios';
19
+ import {syncIOS, validateReceiptIOS} from './modules/ios';
14
20
  import {validateReceiptAndroid} from './modules/android';
15
- import {useCallback, useEffect, useState, useRef} from 'react';
21
+
22
+ // Types
16
23
  import {
17
24
  Product,
18
25
  ProductPurchase,
@@ -22,8 +29,6 @@ import {
22
29
  SubscriptionProduct,
23
30
  SubscriptionPurchase,
24
31
  } from './ExpoIap.types';
25
- import {Platform} from 'react-native';
26
- import {EventSubscription} from 'expo-modules-core';
27
32
 
28
33
  type UseIap = {
29
34
  connected: boolean;
@@ -248,7 +253,7 @@ export function useIAP(options?: UseIAPOptions): UseIap {
248
253
  const restorePurchases = useCallback(async (): Promise<void> => {
249
254
  try {
250
255
  if (Platform.OS === 'ios') {
251
- await sync().catch((error) => {
256
+ await syncIOS().catch((error) => {
252
257
  if (optionsRef.current?.onSyncError) {
253
258
  optionsRef.current.onSyncError(error);
254
259
  } else {
@@ -273,7 +278,7 @@ export function useIAP(options?: UseIAPOptions): UseIap {
273
278
  },
274
279
  ) => {
275
280
  if (Platform.OS === 'ios') {
276
- return await validateReceiptIos(sku);
281
+ return await validateReceiptIOS(sku);
277
282
  } else if (Platform.OS === 'android') {
278
283
  if (
279
284
  !androidOptions ||