expo-iap 2.7.14 → 2.8.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.
Files changed (46) hide show
  1. package/.copilot-instructions.md +5 -5
  2. package/.cursorrules +31 -13
  3. package/CHANGELOG.md +53 -1
  4. package/CLAUDE.md +45 -4
  5. package/android/src/main/java/expo/modules/iap/ExpoIapModule.kt +52 -35
  6. package/build/ExpoIap.types.d.ts +21 -14
  7. package/build/ExpoIap.types.d.ts.map +1 -1
  8. package/build/ExpoIap.types.js +0 -1
  9. package/build/ExpoIap.types.js.map +1 -1
  10. package/build/helpers/subscription.d.ts.map +1 -1
  11. package/build/helpers/subscription.js +24 -17
  12. package/build/helpers/subscription.js.map +1 -1
  13. package/build/index.d.ts +2 -2
  14. package/build/index.js +10 -10
  15. package/build/index.js.map +1 -1
  16. package/build/modules/ios.d.ts +10 -23
  17. package/build/modules/ios.d.ts.map +1 -1
  18. package/build/modules/ios.js +9 -23
  19. package/build/modules/ios.js.map +1 -1
  20. package/build/types/ExpoIapAndroid.types.d.ts +50 -15
  21. package/build/types/ExpoIapAndroid.types.d.ts.map +1 -1
  22. package/build/types/ExpoIapAndroid.types.js +11 -6
  23. package/build/types/ExpoIapAndroid.types.js.map +1 -1
  24. package/build/types/{ExpoIapIos.types.d.ts → ExpoIapIOS.types.d.ts} +68 -39
  25. package/build/types/ExpoIapIOS.types.d.ts.map +1 -0
  26. package/build/types/ExpoIapIOS.types.js +2 -0
  27. package/build/types/ExpoIapIOS.types.js.map +1 -0
  28. package/build/{useIap.d.ts → useIAP.d.ts} +2 -2
  29. package/build/{useIap.d.ts.map → useIAP.d.ts.map} +1 -1
  30. package/build/{useIap.js → useIAP.js} +7 -6
  31. package/build/useIAP.js.map +1 -0
  32. package/bun.lock +677 -61
  33. package/ios/ExpoIapModule.swift +133 -51
  34. package/jest.config.js +43 -0
  35. package/package.json +8 -3
  36. package/src/ExpoIap.types.ts +44 -29
  37. package/src/helpers/subscription.ts +27 -20
  38. package/src/index.ts +13 -13
  39. package/src/modules/ios.ts +13 -40
  40. package/src/types/ExpoIapAndroid.types.ts +62 -15
  41. package/src/types/{ExpoIapIos.types.ts → ExpoIapIOS.types.ts} +73 -39
  42. package/src/{useIap.ts → useIAP.ts} +7 -6
  43. package/build/types/ExpoIapIos.types.d.ts.map +0 -1
  44. package/build/types/ExpoIapIos.types.js +0 -2
  45. package/build/types/ExpoIapIos.types.js.map +0 -1
  46. package/build/useIap.js.map +0 -1
package/src/index.ts CHANGED
@@ -5,9 +5,9 @@ import {Platform} from 'react-native';
5
5
  // Internal modules
6
6
  import ExpoIapModule from './ExpoIapModule';
7
7
  import {
8
- isProductIos,
8
+ isProductIOS,
9
9
  validateReceiptIOS,
10
- deepLinkToSubscriptionsIos,
10
+ deepLinkToSubscriptionsIOS,
11
11
  } from './modules/ios';
12
12
  import {
13
13
  isProductAndroid,
@@ -28,13 +28,13 @@ import {
28
28
  SubscriptionPurchase,
29
29
  } from './ExpoIap.types';
30
30
  import {ProductPurchaseAndroid} from './types/ExpoIapAndroid.types';
31
- import {PaymentDiscount} from './types/ExpoIapIos.types';
31
+ import {PaymentDiscount} from './types/ExpoIapIOS.types';
32
32
 
33
33
  // Export all types
34
34
  export * from './ExpoIap.types';
35
35
  export * from './modules/android';
36
36
  export * from './modules/ios';
37
- export type {AppTransactionIOS} from './types/ExpoIapIos.types';
37
+ export type {AppTransactionIOS} from './types/ExpoIapIOS.types';
38
38
 
39
39
  // Export subscription helpers
40
40
  export {
@@ -135,7 +135,7 @@ export const getProducts = async (skus: string[]): Promise<Product[]> => {
135
135
  ios: async () => {
136
136
  const rawItems = await ExpoIapModule.getItems(skus);
137
137
  return rawItems.filter((item: unknown) => {
138
- if (!isProductIos(item)) return false;
138
+ if (!isProductIOS(item)) return false;
139
139
  return (
140
140
  typeof item === 'object' &&
141
141
  item !== null &&
@@ -169,7 +169,7 @@ export const getSubscriptions = async (
169
169
  ios: async () => {
170
170
  const rawItems = await ExpoIapModule.getItems(skus);
171
171
  return rawItems.filter((item: unknown) => {
172
- if (!isProductIos(item)) return false;
172
+ if (!isProductIOS(item)) return false;
173
173
  return (
174
174
  typeof item === 'object' &&
175
175
  item !== null &&
@@ -236,7 +236,7 @@ export const requestProducts = async ({
236
236
  if (Platform.OS === 'ios') {
237
237
  const rawItems = await ExpoIapModule.getItems(skus);
238
238
  const filteredItems = rawItems.filter((item: unknown) => {
239
- if (!isProductIos(item)) return false;
239
+ if (!isProductIOS(item)) return false;
240
240
  return (
241
241
  typeof item === 'object' &&
242
242
  item !== null &&
@@ -341,7 +341,7 @@ export const getAvailablePurchases = ({
341
341
  }) || (() => Promise.resolve([]))
342
342
  )();
343
343
 
344
- const offerToRecordIos = (
344
+ const offerToRecordIOS = (
345
345
  offer: PaymentDiscount | undefined,
346
346
  ): Record<keyof PaymentDiscount, string> | undefined => {
347
347
  if (!offer) return undefined;
@@ -429,17 +429,17 @@ export const requestPurchase = (
429
429
 
430
430
  const {
431
431
  sku,
432
- andDangerouslyFinishTransactionAutomaticallyIOS = false,
432
+ andDangerouslyFinishTransactionAutomatically = false,
433
433
  appAccountToken,
434
434
  quantity,
435
435
  withOffer,
436
436
  } = normalizedRequest;
437
437
 
438
438
  return (async () => {
439
- const offer = offerToRecordIos(withOffer);
439
+ const offer = offerToRecordIOS(withOffer);
440
440
  const purchase = await ExpoIapModule.buyProduct(
441
441
  sku,
442
- andDangerouslyFinishTransactionAutomaticallyIOS,
442
+ andDangerouslyFinishTransactionAutomatically,
443
443
  appAccountToken,
444
444
  quantity ?? -1,
445
445
  offer,
@@ -683,7 +683,7 @@ export const deepLinkToSubscriptions = (options: {
683
683
  packageNameAndroid?: string;
684
684
  }): Promise<void> => {
685
685
  if (Platform.OS === 'ios') {
686
- return deepLinkToSubscriptionsIos();
686
+ return deepLinkToSubscriptionsIOS();
687
687
  }
688
688
 
689
689
  if (Platform.OS === 'android') {
@@ -710,5 +710,5 @@ export const deepLinkToSubscriptions = (options: {
710
710
  return Promise.reject(new Error(`Unsupported platform: ${Platform.OS}`));
711
711
  };
712
712
 
713
- export * from './useIap';
713
+ export * from './useIAP';
714
714
  export * from './utils/errorMapping';
@@ -12,9 +12,9 @@ import {
12
12
  SubscriptionPurchase,
13
13
  } from '../ExpoIap.types';
14
14
  import type {
15
- ProductStatusIos,
15
+ ProductStatusIOS,
16
16
  AppTransactionIOS,
17
- } from '../types/ExpoIapIos.types';
17
+ } from '../types/ExpoIapIOS.types';
18
18
  import {Linking} from 'react-native';
19
19
 
20
20
  export type TransactionEvent = {
@@ -36,7 +36,7 @@ export type TransactionEvent = {
36
36
  * // Use:
37
37
  * // purchaseUpdatedListener((purchase) => { ... });
38
38
  */
39
- export const transactionUpdatedIos = (
39
+ export const transactionUpdatedIOS = (
40
40
  listener: (event: TransactionEvent) => void,
41
41
  ) => {
42
42
  const isProductPurchase = (item: unknown): item is ProductPurchase => {
@@ -74,7 +74,7 @@ export const transactionUpdatedIos = (
74
74
  };
75
75
 
76
76
  // Type guards
77
- export function isProductIos<T extends {platform?: string}>(
77
+ export function isProductIOS<T extends {platform?: string}>(
78
78
  item: unknown,
79
79
  ): item is T & {platform: 'ios'} {
80
80
  return (
@@ -102,16 +102,16 @@ export const syncIOS = (): Promise<null> => {
102
102
  /**
103
103
  * Check if user is eligible for introductory offer
104
104
  *
105
- * @param groupID The subscription group ID
105
+ * @param groupId The subscription group ID
106
106
  * @returns Promise resolving to true if eligible
107
107
  * @throws Error if called on non-iOS platform
108
108
  *
109
109
  * @platform iOS
110
110
  */
111
111
  export const isEligibleForIntroOfferIOS = (
112
- groupID: string,
112
+ groupId: string,
113
113
  ): Promise<boolean> => {
114
- return ExpoIapModule.isEligibleForIntroOffer(groupID);
114
+ return ExpoIapModule.isEligibleForIntroOffer(groupId);
115
115
  };
116
116
 
117
117
  /**
@@ -125,7 +125,7 @@ export const isEligibleForIntroOfferIOS = (
125
125
  */
126
126
  export const subscriptionStatusIOS = (
127
127
  sku: string,
128
- ): Promise<ProductStatusIos[]> => {
128
+ ): Promise<ProductStatusIOS[]> => {
129
129
  return ExpoIapModule.subscriptionStatus(sku);
130
130
  };
131
131
 
@@ -176,7 +176,7 @@ export const beginRefundRequestIOS = (
176
176
  /**
177
177
  * Shows the system UI for managing subscriptions.
178
178
  * When the user changes subscription renewal status, the system will emit events to
179
- * purchaseUpdatedListener and transactionUpdatedIos listeners.
179
+ * purchaseUpdatedListener and transactionUpdatedIOS listeners.
180
180
  *
181
181
  * @returns Promise resolving to null on success
182
182
  * @throws Error if called on non-iOS platform
@@ -321,7 +321,7 @@ export const buyPromotedProductIOS = (): Promise<void> => {
321
321
  *
322
322
  * @platform iOS
323
323
  */
324
- export const deepLinkToSubscriptionsIos = (): Promise<void> =>
324
+ export const deepLinkToSubscriptionsIOS = (): Promise<void> =>
325
325
  Linking.openURL('https://apps.apple.com/account/subscriptions');
326
326
 
327
327
  // ============= DEPRECATED FUNCTIONS =============
@@ -340,11 +340,11 @@ export const sync = (): Promise<null> => {
340
340
  /**
341
341
  * @deprecated Use `isEligibleForIntroOfferIOS` instead. This function will be removed in version 3.0.0.
342
342
  */
343
- export const isEligibleForIntroOffer = (groupID: string): Promise<boolean> => {
343
+ export const isEligibleForIntroOffer = (groupId: string): Promise<boolean> => {
344
344
  console.warn(
345
345
  '`isEligibleForIntroOffer` is deprecated. Use `isEligibleForIntroOfferIOS` instead. This function will be removed in version 3.0.0.',
346
346
  );
347
- return isEligibleForIntroOfferIOS(groupID);
347
+ return isEligibleForIntroOfferIOS(groupId);
348
348
  };
349
349
 
350
350
  /**
@@ -352,7 +352,7 @@ export const isEligibleForIntroOffer = (groupID: string): Promise<boolean> => {
352
352
  */
353
353
  export const subscriptionStatus = (
354
354
  sku: string,
355
- ): Promise<ProductStatusIos[]> => {
355
+ ): Promise<ProductStatusIOS[]> => {
356
356
  console.warn(
357
357
  '`subscriptionStatus` is deprecated. Use `subscriptionStatusIOS` instead. This function will be removed in version 3.0.0.',
358
358
  );
@@ -401,16 +401,6 @@ export const showManageSubscriptions = (): Promise<null> => {
401
401
  return showManageSubscriptionsIOS();
402
402
  };
403
403
 
404
- /**
405
- * @deprecated Use `getReceiptIOS` instead. This function will be removed in version 3.0.0.
406
- */
407
- export const getReceiptIos = (): Promise<string> => {
408
- console.warn(
409
- '`getReceiptIos` is deprecated. Use `getReceiptIOS` instead. This function will be removed in version 3.0.0.',
410
- );
411
- return getReceiptIOS();
412
- };
413
-
414
404
  /**
415
405
  * @deprecated Use `isTransactionVerifiedIOS` instead. This function will be removed in version 3.0.0.
416
406
  */
@@ -431,23 +421,6 @@ export const getTransactionJws = (sku: string): Promise<string> => {
431
421
  return getTransactionJwsIOS(sku);
432
422
  };
433
423
 
434
- /**
435
- * @deprecated Use `validateReceiptIOS` instead. This function will be removed in version 3.0.0.
436
- */
437
- export const validateReceiptIos = async (
438
- sku: string,
439
- ): Promise<{
440
- isValid: boolean;
441
- receiptData: string;
442
- jwsRepresentation: string;
443
- latestTransaction?: ProductPurchase;
444
- }> => {
445
- console.warn(
446
- '`validateReceiptIos` is deprecated. Use `validateReceiptIOS` instead. This function will be removed in version 3.0.0.',
447
- );
448
- return validateReceiptIOS(sku);
449
- };
450
-
451
424
  /**
452
425
  * @deprecated Use `presentCodeRedemptionSheetIOS` instead. This function will be removed in version 3.0.0.
453
426
  */
@@ -1,6 +1,6 @@
1
- import {PurchaseBase, ProductBase} from '../ExpoIap.types';
1
+ import {PurchaseCommon, ProductCommon} from '../ExpoIap.types';
2
2
 
3
- type OneTimePurchaseOfferDetails = {
3
+ type ProductAndroidOneTimePurchaseOfferDetail = {
4
4
  priceCurrencyCode: string;
5
5
  formattedPrice: string;
6
6
  priceAmountMicros: string;
@@ -20,21 +20,34 @@ type PricingPhasesAndroid = {
20
20
  pricingPhaseList: PricingPhaseAndroid[];
21
21
  };
22
22
 
23
- type SubscriptionOfferDetail = {
23
+ type ProductSubscriptionAndroidOfferDetail = {
24
24
  basePlanId: string;
25
- offerId: string;
25
+ offerId: string | null;
26
26
  offerToken: string;
27
27
  offerTags: string[];
28
28
  pricingPhases: PricingPhasesAndroid;
29
29
  };
30
30
 
31
- export type ProductAndroid = ProductBase & {
32
- name: string;
33
- oneTimePurchaseOfferDetails?: OneTimePurchaseOfferDetails;
34
- subscriptionOfferDetails?: SubscriptionOfferDetail[];
31
+ export type ProductAndroid = ProductCommon & {
32
+ nameAndroid: string;
33
+ oneTimePurchaseOfferDetailsAndroid?: ProductAndroidOneTimePurchaseOfferDetail;
34
+ platform: 'android';
35
+ subscriptionOfferDetailsAndroid?: ProductSubscriptionAndroidOfferDetail[];
36
+ /**
37
+ * @deprecated Use `nameAndroid` instead. This field will be removed in v2.9.0.
38
+ */
39
+ name?: string;
40
+ /**
41
+ * @deprecated Use `oneTimePurchaseOfferDetailsAndroid` instead. This field will be removed in v2.9.0.
42
+ */
43
+ oneTimePurchaseOfferDetails?: ProductAndroidOneTimePurchaseOfferDetail;
44
+ /**
45
+ * @deprecated Use `subscriptionOfferDetailsAndroid` instead. This field will be removed in v2.9.0.
46
+ */
47
+ subscriptionOfferDetails?: ProductSubscriptionAndroidOfferDetail[];
35
48
  };
36
49
 
37
- type SubscriptionOfferAndroid = {
50
+ type ProductSubscriptionAndroidOfferDetails = {
38
51
  basePlanId: string;
39
52
  offerId: string | null;
40
53
  offerToken: string;
@@ -42,10 +55,17 @@ type SubscriptionOfferAndroid = {
42
55
  offerTags: string[];
43
56
  };
44
57
 
45
- export type SubscriptionProductAndroid = ProductAndroid & {
46
- subscriptionOfferDetails: SubscriptionOfferAndroid[];
58
+ export type ProductSubscriptionAndroid = ProductAndroid & {
59
+ subscriptionOfferDetailsAndroid: ProductSubscriptionAndroidOfferDetails[];
60
+ /**
61
+ * @deprecated Use `subscriptionOfferDetailsAndroid` instead. This field will be removed in v2.9.0.
62
+ */
63
+ subscriptionOfferDetails?: ProductSubscriptionAndroidOfferDetails[];
47
64
  };
48
65
 
66
+ // Legacy naming for backward compatibility
67
+ export type SubscriptionProductAndroid = ProductSubscriptionAndroid;
68
+
49
69
  export type RequestPurchaseAndroidProps = {
50
70
  skus: string[];
51
71
  obfuscatedAccountIdAndroid?: string;
@@ -110,14 +130,21 @@ export enum FeatureTypeAndroid {
110
130
  SUBSCRIPTIONS_UPDATE = 'SUBSCRIPTIONS_UPDATE',
111
131
  }
112
132
 
113
- export enum PurchaseStateAndroid {
133
+ export enum PurchaseAndroidState {
114
134
  UNSPECIFIED_STATE = 0,
115
135
  PURCHASED = 1,
116
136
  PENDING = 2,
117
137
  }
118
138
 
119
- export type ProductPurchaseAndroid = PurchaseBase & {
120
- ids?: string[];
139
+ // Legacy naming for backward compatibility
140
+ /**
141
+ * @deprecated Use `PurchaseAndroidState` instead. This enum will be removed in v2.9.0.
142
+ */
143
+ export const PurchaseStateAndroid = PurchaseAndroidState;
144
+
145
+ // Legacy naming for backward compatibility
146
+ export type ProductPurchaseAndroid = PurchaseCommon & {
147
+ platform: 'android';
121
148
  /**
122
149
  * @deprecated Use `purchaseToken` instead. This field will be removed in a future version.
123
150
  */
@@ -125,10 +152,30 @@ export type ProductPurchaseAndroid = PurchaseBase & {
125
152
  dataAndroid?: string;
126
153
  signatureAndroid?: string;
127
154
  autoRenewingAndroid?: boolean;
128
- purchaseStateAndroid?: PurchaseStateAndroid;
155
+ purchaseStateAndroid?: PurchaseAndroidState;
129
156
  isAcknowledgedAndroid?: boolean;
130
157
  packageNameAndroid?: string;
131
158
  developerPayloadAndroid?: string;
132
159
  obfuscatedAccountIdAndroid?: string;
133
160
  obfuscatedProfileIdAndroid?: string;
134
161
  };
162
+
163
+ // Preferred naming
164
+ export type PurchaseAndroid = ProductPurchaseAndroid;
165
+
166
+ // Legacy type aliases for backward compatibility
167
+ /**
168
+ * @deprecated Use `ProductAndroidOneTimePurchaseOfferDetail` instead. This type will be removed in v2.9.0.
169
+ */
170
+ export type OneTimePurchaseOfferDetails =
171
+ ProductAndroidOneTimePurchaseOfferDetail;
172
+
173
+ /**
174
+ * @deprecated Use `ProductSubscriptionAndroidOfferDetail` instead. This type will be removed in v2.9.0.
175
+ */
176
+ export type SubscriptionOfferDetail = ProductSubscriptionAndroidOfferDetail;
177
+
178
+ /**
179
+ * @deprecated Use `ProductSubscriptionAndroidOfferDetails` instead. This type will be removed in v2.9.0.
180
+ */
181
+ export type SubscriptionOfferAndroid = ProductSubscriptionAndroidOfferDetails;
@@ -1,4 +1,4 @@
1
- import {PurchaseBase, ProductBase} from '../ExpoIap.types';
1
+ import {PurchaseCommon, ProductCommon} from '../ExpoIap.types';
2
2
 
3
3
  type SubscriptionIosPeriod = 'DAY' | 'WEEK' | 'MONTH' | 'YEAR' | '';
4
4
  type PaymentMode = '' | 'FREETRIAL' | 'PAYASYOUGO' | 'PAYUPFRONT';
@@ -19,17 +19,34 @@ type SubscriptionOffer = {
19
19
  type SubscriptionInfo = {
20
20
  introductoryOffer?: SubscriptionOffer;
21
21
  promotionalOffers?: SubscriptionOffer[];
22
- subscriptionGroupID: string;
22
+ subscriptionGroupId: string;
23
23
  subscriptionPeriod: {
24
24
  unit: SubscriptionIosPeriod;
25
25
  value: number;
26
26
  };
27
27
  };
28
28
 
29
- export type ProductIos = ProductBase & {
30
- displayName: string;
31
- isFamilyShareable: boolean;
32
- jsonRepresentation: string;
29
+ export type ProductIOS = ProductCommon & {
30
+ displayNameIOS: string;
31
+ isFamilyShareableIOS: boolean;
32
+ jsonRepresentationIOS: string;
33
+ platform: 'ios';
34
+ subscriptionInfoIOS?: SubscriptionInfo;
35
+ /**
36
+ * @deprecated Use `displayNameIOS` instead. This field will be removed in v2.9.0.
37
+ */
38
+ displayName?: string;
39
+ /**
40
+ * @deprecated Use `isFamilyShareableIOS` instead. This field will be removed in v2.9.0.
41
+ */
42
+ isFamilyShareable?: boolean;
43
+ /**
44
+ * @deprecated Use `jsonRepresentationIOS` instead. This field will be removed in v2.9.0.
45
+ */
46
+ jsonRepresentation?: string;
47
+ /**
48
+ * @deprecated Use `subscriptionInfoIOS` instead. This field will be removed in v2.9.0.
49
+ */
33
50
  subscription?: SubscriptionInfo;
34
51
  introductoryPriceNumberOfPeriodsIOS?: string;
35
52
  introductoryPriceSubscriptionPeriodIOS?: SubscriptionIosPeriod;
@@ -45,17 +62,29 @@ export type Discount = {
45
62
  subscriptionPeriod: string;
46
63
  };
47
64
 
48
- export type SubscriptionProductIos = ProductIos & {
49
- discounts?: Discount[];
50
- introductoryPrice?: string;
65
+ export type ProductSubscriptionIOS = ProductIOS & {
66
+ discountsIOS?: Discount[];
67
+ introductoryPriceIOS?: string;
51
68
  introductoryPriceAsAmountIOS?: string;
52
69
  introductoryPricePaymentModeIOS?: PaymentMode;
53
70
  introductoryPriceNumberOfPeriodsIOS?: string;
54
71
  introductoryPriceSubscriptionPeriodIOS?: SubscriptionIosPeriod;
72
+ platform: 'ios';
55
73
  subscriptionPeriodNumberIOS?: string;
56
74
  subscriptionPeriodUnitIOS?: SubscriptionIosPeriod;
75
+ /**
76
+ * @deprecated Use `discountsIOS` instead. This field will be removed in v2.9.0.
77
+ */
78
+ discounts?: Discount[];
79
+ /**
80
+ * @deprecated Use `introductoryPriceIOS` instead. This field will be removed in v2.9.0.
81
+ */
82
+ introductoryPrice?: string;
57
83
  };
58
84
 
85
+ // Legacy naming for backward compatibility
86
+ export type SubscriptionProductIOS = ProductSubscriptionIOS;
87
+
59
88
  export type PaymentDiscount = {
60
89
  /**
61
90
  * A string used to uniquely identify a discount offer for a product.
@@ -81,7 +110,7 @@ export type PaymentDiscount = {
81
110
 
82
111
  export type RequestPurchaseIosProps = {
83
112
  sku: string;
84
- andDangerouslyFinishTransactionAutomaticallyIOS?: boolean;
113
+ andDangerouslyFinishTransactionAutomatically?: boolean;
85
114
  /**
86
115
  * UUID representing user account
87
116
  */
@@ -90,8 +119,6 @@ export type RequestPurchaseIosProps = {
90
119
  withOffer?: PaymentDiscount;
91
120
  };
92
121
 
93
- export type RequestSubscriptionIosProps = RequestPurchaseIosProps;
94
-
95
122
  type SubscriptionStatus =
96
123
  | 'expired'
97
124
  | 'inBillingRetryPeriod'
@@ -105,50 +132,57 @@ type RenewalInfo = {
105
132
  autoRenewPreference?: string;
106
133
  };
107
134
 
108
- export type ProductStatusIos = {
135
+ export type ProductStatusIOS = {
109
136
  state: SubscriptionStatus;
110
137
  renewalInfo?: RenewalInfo;
111
138
  };
112
139
 
113
- export type ProductPurchaseIos = PurchaseBase & {
140
+ // Legacy naming for backward compatibility
141
+ export type ProductPurchaseIOS = PurchaseCommon & {
114
142
  // iOS basic fields
115
- quantityIos?: number;
116
- originalTransactionDateIos?: number;
117
- originalTransactionIdentifierIos?: string;
143
+ platform: 'ios';
144
+ quantityIOS?: number;
145
+ originalTransactionDateIOS?: number;
146
+ originalTransactionIdentifierIOS?: string;
118
147
  appAccountToken?: string;
119
148
  // iOS additional fields from StoreKit 2
120
- expirationDateIos?: number;
121
- webOrderLineItemIdIos?: number;
122
- environmentIos?: string;
123
- storefrontCountryCodeIos?: string;
124
- appBundleIdIos?: string;
125
- productTypeIos?: string;
126
- subscriptionGroupIdIos?: string;
127
- isUpgradedIos?: boolean;
128
- ownershipTypeIos?: string;
129
- reasonIos?: string;
130
- reasonStringRepresentationIos?: string;
131
- transactionReasonIos?: 'PURCHASE' | 'RENEWAL' | string;
132
- revocationDateIos?: number;
133
- revocationReasonIos?: string;
134
- offerIos?: {
149
+ expirationDateIOS?: number;
150
+ webOrderLineItemIdIOS?: number;
151
+ environmentIOS?: string;
152
+ storefrontCountryCodeIOS?: string;
153
+ appBundleIdIOS?: string;
154
+ productTypeIOS?: string;
155
+ subscriptionGroupIdIOS?: string;
156
+ isUpgradedIOS?: boolean;
157
+ ownershipTypeIOS?: string;
158
+ reasonIOS?: string;
159
+ reasonStringRepresentationIOS?: string;
160
+ transactionReasonIOS?: 'PURCHASE' | 'RENEWAL' | string;
161
+ revocationDateIOS?: number;
162
+ revocationReasonIOS?: string;
163
+ offerIOS?: {
135
164
  id: string;
136
165
  type: string;
137
166
  paymentMode: string;
138
167
  };
139
- priceIos?: number;
140
- currencyIos?: string;
168
+ // Price locale fields
169
+ currencyCodeIOS?: string;
170
+ currencySymbolIOS?: string;
171
+ countryCodeIOS?: string;
141
172
  /**
142
173
  * @deprecated Use `purchaseToken` instead. This field will be removed in a future version.
143
174
  * iOS 15+ JWS representation is now available through the `purchaseToken` field.
144
175
  */
145
- jwsRepresentationIos?: string;
176
+ jwsRepresentationIOS?: string;
146
177
  };
147
178
 
179
+ // Preferred naming
180
+ export type PurchaseIOS = ProductPurchaseIOS;
181
+
148
182
  export type AppTransactionIOS = {
149
- appTransactionID?: string; // Only available in iOS 18.4+
183
+ appTransactionId?: string; // Only available in iOS 18.4+
150
184
  originalPlatform?: string; // Only available in iOS 18.4+
151
- bundleID: string;
185
+ bundleId: string;
152
186
  appVersion: string;
153
187
  originalAppVersion: string;
154
188
  originalPurchaseDate: number;
@@ -156,7 +190,7 @@ export type AppTransactionIOS = {
156
190
  deviceVerificationNonce: string;
157
191
  environment: string;
158
192
  signedDate: number;
159
- appID?: number;
160
- appVersionID?: number;
193
+ appId?: number;
194
+ appVersionId?: number;
161
195
  preorderDate?: number;
162
196
  };
@@ -19,7 +19,7 @@ import {
19
19
  getActiveSubscriptions,
20
20
  hasActiveSubscriptions,
21
21
  type ActiveSubscription,
22
- } from './';
22
+ } from '.';
23
23
  import {
24
24
  syncIOS,
25
25
  getPromotedProductIOS,
@@ -158,7 +158,7 @@ export function useIAP(options?: UseIAPOptions): UseIap {
158
158
  const subscriptionsRef = useRef<{
159
159
  purchaseUpdate?: EventSubscription;
160
160
  purchaseError?: EventSubscription;
161
- promotedProductsIos?: EventSubscription;
161
+ promotedProductsIOS?: EventSubscription;
162
162
  promotedProductIOS?: EventSubscription;
163
163
  }>({});
164
164
 
@@ -260,7 +260,8 @@ export function useIAP(options?: UseIAPOptions): UseIap {
260
260
  return result;
261
261
  } catch (error) {
262
262
  console.error('Error getting active subscriptions:', error);
263
- setActiveSubscriptions([]);
263
+ // Don't clear existing activeSubscriptions on error - preserve current state
264
+ // This prevents the UI from showing empty state when there are temporary network issues
264
265
  return [];
265
266
  }
266
267
  },
@@ -385,7 +386,7 @@ export function useIAP(options?: UseIAPOptions): UseIap {
385
386
  setCurrentPurchaseError(undefined);
386
387
  setCurrentPurchase(purchase);
387
388
 
388
- if ('expirationDateIos' in purchase) {
389
+ if ('expirationDateIOS' in purchase) {
389
390
  await refreshSubscriptionStatus(purchase.id);
390
391
  }
391
392
 
@@ -408,7 +409,7 @@ export function useIAP(options?: UseIAPOptions): UseIap {
408
409
 
409
410
  if (Platform.OS === 'ios') {
410
411
  // iOS promoted products listener
411
- subscriptionsRef.current.promotedProductsIos =
412
+ subscriptionsRef.current.promotedProductsIOS =
412
413
  promotedProductListenerIOS((product: Product) => {
413
414
  setPromotedProductIOS(product);
414
415
 
@@ -427,7 +428,7 @@ export function useIAP(options?: UseIAPOptions): UseIap {
427
428
  return () => {
428
429
  currentSubscriptions.purchaseUpdate?.remove();
429
430
  currentSubscriptions.purchaseError?.remove();
430
- currentSubscriptions.promotedProductsIos?.remove();
431
+ currentSubscriptions.promotedProductsIOS?.remove();
431
432
  currentSubscriptions.promotedProductIOS?.remove();
432
433
  endConnection();
433
434
  setConnected(false);
@@ -1 +0,0 @@
1
- {"version":3,"file":"ExpoIapIos.types.d.ts","sourceRoot":"","sources":["../../src/types/ExpoIapIos.types.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=ExpoIapIos.types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ExpoIapIos.types.js","sourceRoot":"","sources":["../../src/types/ExpoIapIos.types.ts"],"names":[],"mappings":"","sourcesContent":["import {PurchaseBase, ProductBase} from '../ExpoIap.types';\n\ntype SubscriptionIosPeriod = 'DAY' | 'WEEK' | 'MONTH' | 'YEAR' | '';\ntype PaymentMode = '' | 'FREETRIAL' | 'PAYASYOUGO' | 'PAYUPFRONT';\n\ntype SubscriptionOffer = {\n displayPrice: string;\n id: string;\n paymentMode: PaymentMode;\n period: {\n unit: SubscriptionIosPeriod;\n value: number;\n };\n periodCount: number;\n price: number;\n type: 'introductory' | 'promotional';\n};\n\ntype SubscriptionInfo = {\n introductoryOffer?: SubscriptionOffer;\n promotionalOffers?: SubscriptionOffer[];\n subscriptionGroupID: string;\n subscriptionPeriod: {\n unit: SubscriptionIosPeriod;\n value: number;\n };\n};\n\nexport type ProductIos = ProductBase & {\n displayName: string;\n isFamilyShareable: boolean;\n jsonRepresentation: string;\n subscription?: SubscriptionInfo;\n introductoryPriceNumberOfPeriodsIOS?: string;\n introductoryPriceSubscriptionPeriodIOS?: SubscriptionIosPeriod;\n};\n\nexport type Discount = {\n identifier: string;\n type: string;\n numberOfPeriods: string;\n price: string;\n localizedPrice: string;\n paymentMode: PaymentMode;\n subscriptionPeriod: string;\n};\n\nexport type SubscriptionProductIos = ProductIos & {\n discounts?: Discount[];\n introductoryPrice?: string;\n introductoryPriceAsAmountIOS?: string;\n introductoryPricePaymentModeIOS?: PaymentMode;\n introductoryPriceNumberOfPeriodsIOS?: string;\n introductoryPriceSubscriptionPeriodIOS?: SubscriptionIosPeriod;\n subscriptionPeriodNumberIOS?: string;\n subscriptionPeriodUnitIOS?: SubscriptionIosPeriod;\n};\n\nexport type PaymentDiscount = {\n /**\n * A string used to uniquely identify a discount offer for a product.\n */\n identifier: string;\n /**\n * A string that identifies the key used to generate the signature.\n */\n keyIdentifier: string;\n /**\n * A universally unique ID (UUID) value that you define.\n */\n nonce: string;\n /**\n * A UTF-8 string representing the properties of a specific discount offer, cryptographically signed.\n */\n signature: string;\n /**\n * The date and time of the signature's creation in milliseconds, formatted in Unix epoch time.\n */\n timestamp: number;\n};\n\nexport type RequestPurchaseIosProps = {\n sku: string;\n andDangerouslyFinishTransactionAutomaticallyIOS?: boolean;\n /**\n * UUID representing user account\n */\n appAccountToken?: string;\n quantity?: number;\n withOffer?: PaymentDiscount;\n};\n\nexport type RequestSubscriptionIosProps = RequestPurchaseIosProps;\n\ntype SubscriptionStatus =\n | 'expired'\n | 'inBillingRetryPeriod'\n | 'inGracePeriod'\n | 'revoked'\n | 'subscribed';\n\ntype RenewalInfo = {\n jsonRepresentation?: string;\n willAutoRenew: boolean;\n autoRenewPreference?: string;\n};\n\nexport type ProductStatusIos = {\n state: SubscriptionStatus;\n renewalInfo?: RenewalInfo;\n};\n\nexport type ProductPurchaseIos = PurchaseBase & {\n // iOS basic fields\n quantityIos?: number;\n originalTransactionDateIos?: number;\n originalTransactionIdentifierIos?: string;\n appAccountToken?: string;\n // iOS additional fields from StoreKit 2\n expirationDateIos?: number;\n webOrderLineItemIdIos?: number;\n environmentIos?: string;\n storefrontCountryCodeIos?: string;\n appBundleIdIos?: string;\n productTypeIos?: string;\n subscriptionGroupIdIos?: string;\n isUpgradedIos?: boolean;\n ownershipTypeIos?: string;\n reasonIos?: string;\n reasonStringRepresentationIos?: string;\n transactionReasonIos?: 'PURCHASE' | 'RENEWAL' | string;\n revocationDateIos?: number;\n revocationReasonIos?: string;\n offerIos?: {\n id: string;\n type: string;\n paymentMode: string;\n };\n priceIos?: number;\n currencyIos?: string;\n /**\n * @deprecated Use `purchaseToken` instead. This field will be removed in a future version.\n * iOS 15+ JWS representation is now available through the `purchaseToken` field.\n */\n jwsRepresentationIos?: string;\n};\n\nexport type AppTransactionIOS = {\n appTransactionID?: string; // Only available in iOS 18.4+\n originalPlatform?: string; // Only available in iOS 18.4+\n bundleID: string;\n appVersion: string;\n originalAppVersion: string;\n originalPurchaseDate: number;\n deviceVerification: string;\n deviceVerificationNonce: string;\n environment: string;\n signedDate: number;\n appID?: number;\n appVersionID?: number;\n preorderDate?: number;\n};\n"]}