react-native-iap 12.0.3 → 12.1.0

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 (38) hide show
  1. package/lib/commonjs/iap.js +143 -110
  2. package/lib/commonjs/iap.js.map +1 -1
  3. package/lib/commonjs/internal/fillProductsWithAdditionalData.js +2 -1
  4. package/lib/commonjs/internal/fillProductsWithAdditionalData.js.map +1 -1
  5. package/lib/commonjs/internal/platform.js +28 -1
  6. package/lib/commonjs/internal/platform.js.map +1 -1
  7. package/lib/commonjs/modules/android.js.map +1 -1
  8. package/lib/commonjs/modules/ios.js.map +1 -1
  9. package/lib/commonjs/types/appleSk2.js +3 -0
  10. package/lib/commonjs/types/appleSk2.js.map +1 -1
  11. package/lib/commonjs/types/index.js +15 -1
  12. package/lib/commonjs/types/index.js.map +1 -1
  13. package/lib/module/iap.js +143 -111
  14. package/lib/module/iap.js.map +1 -1
  15. package/lib/module/internal/fillProductsWithAdditionalData.js +2 -1
  16. package/lib/module/internal/fillProductsWithAdditionalData.js.map +1 -1
  17. package/lib/module/internal/platform.js +24 -0
  18. package/lib/module/internal/platform.js.map +1 -1
  19. package/lib/module/modules/android.js.map +1 -1
  20. package/lib/module/modules/ios.js.map +1 -1
  21. package/lib/module/types/appleSk2.js +2 -0
  22. package/lib/module/types/appleSk2.js.map +1 -1
  23. package/lib/module/types/index.js +12 -0
  24. package/lib/module/types/index.js.map +1 -1
  25. package/lib/typescript/iap.d.ts +4 -4
  26. package/lib/typescript/internal/fillProductsWithAdditionalData.d.ts +2 -1
  27. package/lib/typescript/internal/platform.d.ts +9 -0
  28. package/lib/typescript/modules/android.d.ts +1 -1
  29. package/lib/typescript/modules/ios.d.ts +4 -4
  30. package/lib/typescript/types/index.d.ts +54 -28
  31. package/package.json +1 -1
  32. package/src/iap.ts +130 -74
  33. package/src/internal/fillProductsWithAdditionalData.ts +3 -2
  34. package/src/internal/platform.ts +20 -0
  35. package/src/modules/android.ts +1 -1
  36. package/src/modules/ios.ts +5 -5
  37. package/src/types/appleSk2.ts +2 -0
  38. package/src/types/index.ts +70 -30
@@ -39,10 +39,7 @@ export interface ProductCommon {
39
39
  description: string;
40
40
  price: string;
41
41
  currency: string;
42
- /**
43
- * For Android use subscription.subscriptionOfferDetails[*].pricingPhases.pricingPhaseList[*].formattedPrice
44
- */
45
- localizedPrice?: string;
42
+ localizedPrice: string;
46
43
  countryCode?: string;
47
44
  }
48
45
  export interface ProductPurchase {
@@ -103,30 +100,55 @@ export interface ProductIOS extends ProductCommon {
103
100
  type: 'inapp' | 'iap';
104
101
  }
105
102
  export declare type Product = ProductAndroid & ProductIOS;
106
- export interface SubscriptionAndroid extends ProductCommon {
103
+ /**
104
+ * Can be used to distinguish the different platforms' subscription information
105
+ */
106
+ export declare enum SubscriptionPlatform {
107
+ android = "android",
108
+ amazon = "amazon",
109
+ ios = "ios"
110
+ }
111
+ /** Android Billing v5 type */
112
+ export interface SubscriptionAndroid {
113
+ platform: SubscriptionPlatform.android;
114
+ productType: 'subs';
115
+ name: string;
116
+ title: string;
117
+ description: string;
118
+ productId: string;
119
+ subscriptionOfferDetails: SubscriptionOfferAndroid[];
120
+ }
121
+ export interface SubscriptionOfferAndroid {
122
+ offerToken: string;
123
+ pricingPhases: {
124
+ pricingPhaseList: PricingPhaseAndroid[];
125
+ };
126
+ offerTags: string[];
127
+ }
128
+ export interface PricingPhaseAndroid {
129
+ formattedPrice: string;
130
+ priceCurrencyCode: string;
131
+ /**
132
+ * P1W, P1M, P1Y
133
+ */
134
+ billingPeriod: string;
135
+ billingCycleCount: number;
136
+ priceAmountMicros: string;
137
+ recurrenceMode: number;
138
+ }
139
+ /**
140
+ * TODO: As of 2022-10-10, this typing is not verified against the real
141
+ * Amazon API. Please update this if you have a more accurate type.
142
+ */
143
+ export interface SubscriptionAmazon extends ProductCommon {
144
+ platform: SubscriptionPlatform.amazon;
107
145
  type: 'subs';
108
146
  productType?: string;
109
147
  name?: string;
110
- subscriptionOfferDetails?: {
111
- offerToken: string;
112
- pricingPhases: {
113
- pricingPhaseList: {
114
- formattedPrice: string;
115
- priceCurrencyCode: string;
116
- /**
117
- * P1W, P1M, P1Y
118
- */
119
- billingPeriod: string;
120
- billingCycleCount: number;
121
- priceAmountMicros: string;
122
- recurrenceMode: number;
123
- }[];
124
- };
125
- offerTags: string[];
126
- }[];
127
148
  }
128
149
  export declare type SubscriptionIosPeriod = 'DAY' | 'WEEK' | 'MONTH' | 'YEAR' | '';
129
150
  export interface SubscriptionIOS extends ProductCommon {
151
+ platform: SubscriptionPlatform.ios;
130
152
  type: 'subs';
131
153
  discounts?: Discount[];
132
154
  introductoryPrice?: string;
@@ -137,17 +159,17 @@ export interface SubscriptionIOS extends ProductCommon {
137
159
  subscriptionPeriodNumberIOS?: string;
138
160
  subscriptionPeriodUnitIOS?: SubscriptionIosPeriod;
139
161
  }
140
- export declare type Subscription = SubscriptionAndroid & SubscriptionIOS;
162
+ export declare type Subscription = SubscriptionAndroid | SubscriptionAmazon | SubscriptionIOS;
141
163
  export interface RequestPurchaseBaseAndroid {
142
164
  obfuscatedAccountIdAndroid?: string;
143
165
  obfuscatedProfileIdAndroid?: string;
144
166
  isOfferPersonalized?: boolean;
145
167
  }
146
168
  export interface RequestPurchaseAndroid extends RequestPurchaseBaseAndroid {
147
- skus?: Sku[];
169
+ skus: Sku[];
148
170
  }
149
171
  export interface RequestPurchaseIOS {
150
- sku?: Sku;
172
+ sku: Sku;
151
173
  andDangerouslyFinishTransactionAutomaticallyIOS?: boolean;
152
174
  /**
153
175
  * UUID representing user account
@@ -156,7 +178,9 @@ export interface RequestPurchaseIOS {
156
178
  quantity?: number;
157
179
  withOffer?: Apple.PaymentDiscount;
158
180
  }
159
- export declare type RequestPurchase = RequestPurchaseAndroid & RequestPurchaseIOS;
181
+ /** As of 2022-10-12, we only use the `sku` field for Amazon purchases */
182
+ export declare type RequestPurchaseAmazon = RequestPurchaseIOS;
183
+ export declare type RequestPurchase = RequestPurchaseAndroid | RequestPurchaseAmazon | RequestPurchaseIOS;
160
184
  /**
161
185
  * In order to purchase a new subscription, every sku must have a selected offerToken
162
186
  * @see SubscriptionAndroid.subscriptionOfferDetails.offerToken
@@ -168,10 +192,12 @@ export interface SubscriptionOffer {
168
192
  export interface RequestSubscriptionAndroid extends RequestPurchaseBaseAndroid {
169
193
  purchaseTokenAndroid?: string;
170
194
  prorationModeAndroid?: ProrationModesAndroid;
171
- subscriptionOffers?: SubscriptionOffer[];
195
+ subscriptionOffers: SubscriptionOffer[];
172
196
  }
173
197
  export declare type RequestSubscriptionIOS = RequestPurchaseIOS;
174
- export declare type RequestSubscription = RequestSubscriptionAndroid & RequestSubscriptionIOS;
198
+ /** As of 2022-10-12, we only use the `sku` field for Amazon subscriptions */
199
+ export declare type RequestSubscriptionAmazon = RequestSubscriptionIOS;
200
+ export declare type RequestSubscription = RequestSubscriptionAndroid | RequestSubscriptionAmazon | RequestSubscriptionIOS;
175
201
  declare module 'react-native' {
176
202
  interface NativeModulesStatic {
177
203
  RNIapIos: IosModuleProps;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-iap",
3
- "version": "12.0.3",
3
+ "version": "12.1.0",
4
4
  "description": "React Native In App Purchase Module.",
5
5
  "repository": "https://github.com/dooboolab/react-native-iap",
6
6
  "author": "dooboolab <support@dooboolab.com> (https://github.com/dooboolab)",
package/src/iap.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  import {
16
16
  fillProductsWithAdditionalData,
17
17
  getAndroidModule,
18
+ getAndroidModuleType,
18
19
  getIosModule,
19
20
  getNativeModule,
20
21
  isAmazon,
@@ -28,12 +29,16 @@ import {
28
29
  ProductPurchase,
29
30
  ProductType,
30
31
  PurchaseResult,
32
+ PurchaseStateAndroid,
31
33
  RequestPurchase,
32
34
  RequestSubscription,
33
35
  Subscription,
36
+ SubscriptionAmazon,
37
+ SubscriptionAndroid,
38
+ SubscriptionIOS,
39
+ SubscriptionPlatform,
34
40
  SubscriptionPurchase,
35
41
  } from './types';
36
- import {PurchaseStateAndroid} from './types';
37
42
 
38
43
  export {IapAndroid, IapAmazon, IapIos, IapIosSk2, isIosStorekit2};
39
44
 
@@ -231,32 +236,69 @@ export const getSubscriptions = ({
231
236
  }): Promise<Subscription[]> =>
232
237
  (
233
238
  Platform.select({
234
- ios: async () => {
235
- let items: Subscription[];
239
+ ios: async (): Promise<SubscriptionIOS[]> => {
240
+ let items: SubscriptionIOS[];
236
241
  if (isIosStorekit2()) {
237
242
  items = ((await RNIapIosSk2.getItems(skus)) as ProductSk2[]).map(
238
243
  subscriptionSk2Map,
239
244
  );
240
245
  } else {
241
- items = (await RNIapIos.getItems(skus)) as Subscription[];
246
+ items = (await RNIapIos.getItems(skus)) as SubscriptionIOS[];
242
247
  }
243
248
 
244
- return items.filter(
245
- (item: Subscription) =>
249
+ items = items.filter(
250
+ (item: SubscriptionIOS) =>
246
251
  skus.includes(item.productId) && item.type === 'subs',
247
252
  );
253
+
254
+ return addSubscriptionPlatform(items, SubscriptionPlatform.ios);
248
255
  },
249
- android: async () => {
250
- const subscriptions = (await getAndroidModule().getItemsByType(
256
+ android: async (): Promise<Subscription[]> => {
257
+ const androidPlatform = getAndroidModuleType();
258
+
259
+ let subscriptions = (await getAndroidModule().getItemsByType(
251
260
  ANDROID_ITEM_TYPE_SUBSCRIPTION,
252
261
  skus,
253
- )) as Subscription[];
254
-
255
- return fillProductsWithAdditionalData(subscriptions);
262
+ )) as SubscriptionAndroid[] | SubscriptionAmazon[];
263
+
264
+ switch (androidPlatform) {
265
+ case 'android': {
266
+ const castSubscriptions = subscriptions as SubscriptionAndroid[];
267
+ return addSubscriptionPlatform(
268
+ castSubscriptions,
269
+ SubscriptionPlatform.android,
270
+ );
271
+ }
272
+ case 'amazon':
273
+ let castSubscriptions = subscriptions as SubscriptionAmazon[];
274
+ castSubscriptions = await fillProductsWithAdditionalData(
275
+ castSubscriptions,
276
+ );
277
+ return addSubscriptionPlatform(
278
+ castSubscriptions,
279
+ SubscriptionPlatform.amazon,
280
+ );
281
+ case null:
282
+ default:
283
+ throw new Error(
284
+ `getSubscriptions received unknown platform ${androidPlatform}. Verify the logic in getAndroidModuleType`,
285
+ );
286
+ }
256
287
  },
257
288
  }) || (() => Promise.reject(new Error('Unsupported Platform')))
258
289
  )();
259
290
 
291
+ /**
292
+ * Adds an extra property to subscriptions so we can distinguish the platform
293
+ * we retrieved them on.
294
+ */
295
+ const addSubscriptionPlatform = <T>(
296
+ subscriptions: T[],
297
+ platform: SubscriptionPlatform,
298
+ ): T[] => {
299
+ return subscriptions.map((subscription) => ({...subscription, platform}));
300
+ };
301
+
260
302
  /**
261
303
  * Gets an inventory of purchases made by the user regardless of consumption status
262
304
  * ## Usage
@@ -281,8 +323,8 @@ const App = () => {
281
323
  ```
282
324
  @param {alsoPublishToEventListener}:boolean. (IOS Sk2 only) When `true`, every element will also be pushed to the purchaseUpdated listener.
283
325
  Note that this is only for backaward compatiblity. It won't publish to transactionUpdated (Storekit2) Defaults to `false`
284
- @param {automaticallyFinishRestoredTransactions}:boolean. (IOS Sk1 only) When `true`, all the transactions that are returned are automatically
285
- finished. This means that if you call this method again you won't get the same result on the same device. On the other hand, if `false` you'd
326
+ @param {automaticallyFinishRestoredTransactions}:boolean. (IOS Sk1 only) When `true`, all the transactions that are returned are automatically
327
+ finished. This means that if you call this method again you won't get the same result on the same device. On the other hand, if `false` you'd
286
328
  have to manually finish the returned transaction once you have delivered the content to your user.
287
329
  */
288
330
  export const getPurchaseHistory = ({
@@ -403,7 +445,7 @@ const App = () => {
403
445
  ```
404
446
  @param {alsoPublishToEventListener}:boolean When `true`, every element will also be pushed to the purchaseUpdated listener.
405
447
  Note that this is only for backaward compatiblity. It won't publish to transactionUpdated (Storekit2) Defaults to `false`
406
- *
448
+ *
407
449
  */
408
450
  export const getAvailablePurchases = ({
409
451
  alsoPublishToEventListener = false,
@@ -460,22 +502,22 @@ always keeping at false, and verifying the transaction receipts on the server-si
460
502
 
461
503
  ```ts
462
504
  requestPurchase(
463
- The product's sku/ID
505
+ The product's sku/ID
464
506
  sku,
465
507
 
466
-
508
+
467
509
  * You should set this to false and call finishTransaction manually when you have delivered the purchased goods to the user.
468
510
  * @default false
469
-
511
+
470
512
  andDangerouslyFinishTransactionAutomaticallyIOS = false,
471
513
 
472
- /** Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
514
+ /** Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
473
515
  obfuscatedAccountIdAndroid,
474
516
 
475
- Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
517
+ Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
476
518
  obfuscatedProfileIdAndroid,
477
519
 
478
- The purchaser's user ID
520
+ The purchaser's user ID
479
521
  applicationUsername,
480
522
  ): Promise<ProductPurchase>;
481
523
  ```
@@ -513,23 +555,24 @@ const App = () => {
513
555
 
514
556
  */
515
557
 
516
- export const requestPurchase = ({
517
- sku,
518
- andDangerouslyFinishTransactionAutomaticallyIOS = false,
519
- obfuscatedAccountIdAndroid,
520
- obfuscatedProfileIdAndroid,
521
- appAccountToken,
522
- skus, // Android Billing V5
523
- isOfferPersonalized = undefined, // Android Billing V5
524
- quantity,
525
- withOffer,
526
- }: RequestPurchase): Promise<ProductPurchase | void> =>
558
+ export const requestPurchase = (
559
+ request: RequestPurchase,
560
+ ): Promise<ProductPurchase | void> =>
527
561
  (
528
562
  Platform.select({
529
563
  ios: async () => {
530
- if (!sku) {
531
- return Promise.reject(new Error('sku is required for iOS purchase'));
564
+ if (!('sku' in request)) {
565
+ throw new Error('sku is required for iOS purchase');
532
566
  }
567
+
568
+ const {
569
+ sku,
570
+ andDangerouslyFinishTransactionAutomaticallyIOS = false,
571
+ appAccountToken,
572
+ quantity,
573
+ withOffer,
574
+ } = request;
575
+
533
576
  if (andDangerouslyFinishTransactionAutomaticallyIOS) {
534
577
  console.warn(
535
578
  'You are dangerously allowing react-native-iap to finish your transaction automatically. You should set andDangerouslyFinishTransactionAutomatically to false when calling requestPurchase and call finishTransaction manually when you have delivered the purchased goods to the user. It defaults to true to provide backwards compatibility. Will default to false in version 4.0.0.',
@@ -557,21 +600,25 @@ export const requestPurchase = ({
557
600
  },
558
601
  android: async () => {
559
602
  if (isAmazon) {
560
- if (!sku) {
561
- return Promise.reject(
562
- new Error('sku is required for Amazon purchase'),
563
- );
603
+ if (!('sku' in request)) {
604
+ throw new Error('sku is required for Amazon purchase');
564
605
  }
606
+ const {sku} = request;
565
607
  return RNIapAmazonModule.buyItemByType(sku);
566
608
  } else {
567
- if (!sku?.length && !sku) {
568
- return Promise.reject(
569
- new Error('skus is required for Android purchase'),
570
- );
609
+ if (!('skus' in request) || !request.skus.length) {
610
+ throw new Error('skus is required for Android purchase');
571
611
  }
612
+
613
+ const {
614
+ skus,
615
+ obfuscatedAccountIdAndroid,
616
+ obfuscatedProfileIdAndroid,
617
+ isOfferPersonalized,
618
+ } = request;
572
619
  return getAndroidModule().buyItemByType(
573
620
  ANDROID_ITEM_TYPE_IAP,
574
- skus?.length ? skus : [sku],
621
+ skus,
575
622
  undefined,
576
623
  -1,
577
624
  obfuscatedAccountIdAndroid,
@@ -599,7 +646,7 @@ always keeping at false, and verifying the transaction receipts on the server-si
599
646
 
600
647
  ```ts
601
648
  requestSubscription(
602
- The product's sku/ID
649
+ The product's sku/ID
603
650
  sku,
604
651
 
605
652
 
@@ -608,19 +655,19 @@ requestSubscription(
608
655
 
609
656
  andDangerouslyFinishTransactionAutomaticallyIOS = false,
610
657
 
611
- purchaseToken that the user is upgrading or downgrading from (Android).
658
+ purchaseToken that the user is upgrading or downgrading from (Android).
612
659
  purchaseTokenAndroid,
613
660
 
614
- UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY, IMMEDIATE_WITH_TIME_PRORATION, IMMEDIATE_AND_CHARGE_PRORATED_PRICE, IMMEDIATE_WITHOUT_PRORATION, DEFERRED
661
+ UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY, IMMEDIATE_WITH_TIME_PRORATION, IMMEDIATE_AND_CHARGE_PRORATED_PRICE, IMMEDIATE_WITHOUT_PRORATION, DEFERRED
615
662
  prorationModeAndroid = -1,
616
663
 
617
- /** Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
664
+ /** Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
618
665
  obfuscatedAccountIdAndroid,
619
666
 
620
- Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
667
+ Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
621
668
  obfuscatedProfileIdAndroid,
622
669
 
623
- The purchaser's user ID
670
+ The purchaser's user ID
624
671
  applicationUsername,
625
672
  ): Promise<SubscriptionPurchase>
626
673
  ```
@@ -661,27 +708,24 @@ const App = () => {
661
708
  };
662
709
  ```
663
710
  */
664
- export const requestSubscription = ({
665
- sku,
666
- andDangerouslyFinishTransactionAutomaticallyIOS = false,
667
- purchaseTokenAndroid,
668
- prorationModeAndroid = -1,
669
- obfuscatedAccountIdAndroid,
670
- obfuscatedProfileIdAndroid,
671
- subscriptionOffers = undefined, // Android Billing V5
672
- isOfferPersonalized = undefined, // Android Billing V5
673
- appAccountToken,
674
- quantity,
675
- withOffer,
676
- }: RequestSubscription): Promise<SubscriptionPurchase | null | void> =>
711
+ export const requestSubscription = (
712
+ request: RequestSubscription,
713
+ ): Promise<SubscriptionPurchase | null | void> =>
677
714
  (
678
715
  Platform.select({
679
716
  ios: async () => {
680
- if (!sku) {
681
- return Promise.reject(
682
- new Error('sku is required for iOS subscription'),
683
- );
717
+ if (!('sku' in request)) {
718
+ throw new Error('sku is required for iOS subscriptions');
684
719
  }
720
+
721
+ const {
722
+ sku,
723
+ andDangerouslyFinishTransactionAutomaticallyIOS = false,
724
+ appAccountToken,
725
+ quantity,
726
+ withOffer,
727
+ } = request;
728
+
685
729
  if (andDangerouslyFinishTransactionAutomaticallyIOS) {
686
730
  console.warn(
687
731
  'You are dangerously allowing react-native-iap to finish your transaction automatically. You should set andDangerouslyFinishTransactionAutomatically to false when calling requestPurchase and call finishTransaction manually when you have delivered the purchased goods to the user. It defaults to true to provide backwards compatibility. Will default to false in version 4.0.0.',
@@ -710,18 +754,30 @@ export const requestSubscription = ({
710
754
  },
711
755
  android: async () => {
712
756
  if (isAmazon) {
713
- if (!sku) {
714
- return Promise.reject(
715
- new Error('sku is required for Amazon purchase'),
716
- );
757
+ if (!('sku' in request)) {
758
+ throw new Error('sku is required for Amazon subscriptions');
717
759
  }
760
+ const {sku} = request;
718
761
  return RNIapAmazonModule.buyItemByType(sku);
719
762
  } else {
720
- if (!subscriptionOffers?.length) {
721
- return Promise.reject(
722
- 'subscriptionOffers are required for Google Play Subscriptions',
763
+ if (
764
+ !('subscriptionOffers' in request) ||
765
+ request.subscriptionOffers.length === 0
766
+ ) {
767
+ throw new Error(
768
+ 'subscriptionOffers are required for Google Play subscriptions',
723
769
  );
724
770
  }
771
+
772
+ const {
773
+ subscriptionOffers,
774
+ purchaseTokenAndroid,
775
+ prorationModeAndroid,
776
+ obfuscatedAccountIdAndroid,
777
+ obfuscatedProfileIdAndroid,
778
+ isOfferPersonalized,
779
+ } = request;
780
+
725
781
  return RNIapModule.buyItemByType(
726
782
  ANDROID_ITEM_TYPE_SUBSCRIPTION,
727
783
  subscriptionOffers?.map((so) => so.sku),
@@ -744,7 +800,7 @@ export const requestSubscription = ({
744
800
  * Call this after you have persisted the purchased state to your server or local data in your app.
745
801
  * `react-native-iap` will continue to deliver the purchase updated events with the successful purchase until you finish the transaction. **Even after the app has relaunched.**
746
802
  * Android: it will consume purchase for consumables and acknowledge purchase for non-consumables.
747
- *
803
+ *
748
804
  ```tsx
749
805
  import React from 'react';
750
806
  import {Button} from 'react-native';
@@ -759,7 +815,7 @@ const App = () => {
759
815
 
760
816
  return <Button title="Buy product" onPress={handlePurchase} />;
761
817
  };
762
- ```
818
+ ```
763
819
  */
764
820
  export const finishTransaction = ({
765
821
  purchase,
@@ -5,11 +5,12 @@ import type {ProductCommon} from '../types';
5
5
  const {RNIapAmazonModule} = NativeModules;
6
6
 
7
7
  /**
8
- * Fill products with additional data
8
+ * For Amazon products, we add the currency code from the user's information
9
+ * since it isn't included in the product information.
9
10
  */
10
11
  export const fillProductsWithAdditionalData = async <T extends ProductCommon>(
11
12
  items: T[],
12
- ) => {
13
+ ): Promise<T[]> => {
13
14
  if (RNIapAmazonModule) {
14
15
  // On amazon we must get the user marketplace to detect the currency
15
16
  const user = await RNIapAmazonModule.getUser();
@@ -25,6 +25,10 @@ export const checkNativeAndroidAvailable = (): void => {
25
25
  }
26
26
  };
27
27
 
28
+ /**
29
+ * If changing the typings of `getAndroidModule` to accommodate extra modules,
30
+ * make sure to update `getAndroidModuleType`.
31
+ */
28
32
  export const getAndroidModule = ():
29
33
  | typeof RNIapModule
30
34
  | typeof RNIapAmazonModule => {
@@ -37,6 +41,22 @@ export const getAndroidModule = ():
37
41
  : RNIapAmazonModule;
38
42
  };
39
43
 
44
+ /**
45
+ * Returns whether the Android in-app-purchase code is using the Android,
46
+ * Amazon, or another store.
47
+ */
48
+ export const getAndroidModuleType = (): 'android' | 'amazon' | null => {
49
+ const module = getAndroidModule();
50
+ switch (module) {
51
+ case RNIapModule:
52
+ return 'android';
53
+ case RNIapAmazonModule:
54
+ return 'amazon';
55
+ default:
56
+ return null;
57
+ }
58
+ };
59
+
40
60
  export const getNativeModule = ():
41
61
  | typeof RNIapModule
42
62
  | typeof RNIapAmazonModule
@@ -35,7 +35,7 @@ export type BuyItemByType = (
35
35
  type: string,
36
36
  skus: Sku[],
37
37
  purchaseToken: string | undefined,
38
- prorationMode: ProrationModesAndroid,
38
+ prorationMode: ProrationModesAndroid | undefined,
39
39
  obfuscatedAccountId: string | undefined,
40
40
  obfuscatedProfileId: string | undefined,
41
41
  subscriptionOffers: string[],
@@ -2,17 +2,17 @@ import type {ResponseBody as ReceiptValidationResponse} from '@jeremybarbet/appl
2
2
 
3
3
  import {getIosModule, isIosStorekit2} from '../internal';
4
4
  import type {
5
- Product,
5
+ ProductIOS,
6
6
  ProductPurchase,
7
7
  Purchase,
8
8
  Sku,
9
- Subscription,
9
+ SubscriptionIOS,
10
10
  } from '../types';
11
11
  import type {PaymentDiscount} from '../types/apple';
12
12
 
13
13
  import type {NativeModuleProps} from './common';
14
14
 
15
- type getItems = (skus: Sku[]) => Promise<Product[] | Subscription[]>;
15
+ type getItems = (skus: Sku[]) => Promise<ProductIOS[] | SubscriptionIOS[]>;
16
16
 
17
17
  type getAvailableItems = (
18
18
  automaticallyFinishRestoredTransactions: boolean,
@@ -28,7 +28,7 @@ export type BuyProduct = (
28
28
 
29
29
  type clearTransaction = () => Promise<void>;
30
30
  type clearProducts = () => Promise<void>;
31
- type promotedProduct = () => Promise<Product | null>;
31
+ type promotedProduct = () => Promise<ProductIOS | null>;
32
32
  type buyPromotedProduct = () => Promise<void>;
33
33
  type requestReceipt = (refresh: boolean) => Promise<string>;
34
34
 
@@ -83,7 +83,7 @@ export const presentCodeRedemptionSheetIOS = async (): Promise<null> =>
83
83
  * Indicates the the App Store purchase should continue from the app instead of the App Store.
84
84
  * @returns {Promise<Product | null>} promoted product
85
85
  */
86
- export const getPromotedProductIOS = (): Promise<Product | null> => {
86
+ export const getPromotedProductIOS = (): Promise<ProductIOS | null> => {
87
87
  if (!isIosStorekit2()) {
88
88
  return getIosModule().promotedProduct();
89
89
  } else {
@@ -7,6 +7,7 @@ import type {
7
7
  SubscriptionIosPeriod,
8
8
  } from '.';
9
9
  import type * as Apple from './apple';
10
+ import {SubscriptionPlatform} from '.';
10
11
 
11
12
  export type SubscriptionPeriod = {
12
13
  unit: 'day' | 'week' | 'month' | 'year';
@@ -71,6 +72,7 @@ export const subscriptionSk2Map = ({
71
72
  subscription,
72
73
  }: ProductSk2): SubscriptionIOS => {
73
74
  const prod: SubscriptionIOS = {
75
+ platform: SubscriptionPlatform.ios,
74
76
  title: displayName,
75
77
  productId: String(id),
76
78
  description,