expo-iap 2.8.6 → 2.9.0-rc.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 (44) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/CLAUDE.md +7 -0
  3. package/CONTRIBUTING.md +3 -4
  4. package/android/src/main/java/expo/modules/iap/ExpoIapModule.kt +120 -7
  5. package/android/src/main/java/expo/modules/iap/Types.kt +1 -1
  6. package/build/helpers/subscription.d.ts.map +1 -1
  7. package/build/helpers/subscription.js +3 -6
  8. package/build/helpers/subscription.js.map +1 -1
  9. package/build/index.d.ts +31 -5
  10. package/build/index.d.ts.map +1 -1
  11. package/build/index.js +53 -25
  12. package/build/index.js.map +1 -1
  13. package/build/modules/android.d.ts.map +1 -1
  14. package/build/modules/android.js.map +1 -1
  15. package/build/modules/ios.d.ts.map +1 -1
  16. package/build/modules/ios.js.map +1 -1
  17. package/build/types/ExpoIapAndroid.types.d.ts +2 -2
  18. package/build/types/ExpoIapAndroid.types.d.ts.map +1 -1
  19. package/build/types/ExpoIapAndroid.types.js.map +1 -1
  20. package/build/types/ExpoIapIOS.types.d.ts +3 -3
  21. package/build/types/ExpoIapIOS.types.d.ts.map +1 -1
  22. package/build/types/ExpoIapIOS.types.js.map +1 -1
  23. package/build/useIAP.d.ts +12 -4
  24. package/build/useIAP.d.ts.map +1 -1
  25. package/build/useIAP.js +10 -5
  26. package/build/useIAP.js.map +1 -1
  27. package/ios/ExpoIap.podspec +1 -0
  28. package/ios/ExpoIapModule.swift +354 -1159
  29. package/jest.config.js +14 -17
  30. package/package.json +5 -3
  31. package/plugin/build/withIAP.d.ts +7 -1
  32. package/plugin/build/withIAP.js +16 -2
  33. package/plugin/build/withLocalOpenIAP.d.ts +9 -0
  34. package/plugin/build/withLocalOpenIAP.js +85 -0
  35. package/plugin/src/withIAP.ts +21 -2
  36. package/plugin/src/withLocalOpenIAP.ts +66 -0
  37. package/plugin/tsconfig.tsbuildinfo +1 -1
  38. package/src/helpers/subscription.ts +21 -28
  39. package/src/index.ts +70 -33
  40. package/src/modules/android.ts +7 -7
  41. package/src/modules/ios.ts +11 -5
  42. package/src/types/ExpoIapAndroid.types.ts +3 -4
  43. package/src/types/ExpoIapIOS.types.ts +4 -3
  44. package/src/useIAP.ts +40 -12
package/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## [2.9.0] - 2025-09-05
4
+
5
+ ### Added
6
+
7
+ - **iOS**: Integrated [OpenIAP Apple](https://github.com/hyodotdev/openiap-apple) v1.1.5
8
+ - Updated types to match [OpenIAP v1.1.0 specification](https://www.openiap.dev/docs/versions#v1-1-0)
9
+ - Enhanced error handling with `PurchaseError` type and native error code mapping
10
+ - New type system: `ProductRequest`, `RequestPurchaseProps`, `ReceiptValidationProps`
11
+ - Improved receipt validation with `ReceiptValidationResult`
12
+
13
+ ### Changed
14
+
15
+ - Updated `serializePurchase` and `serializeProduct` for new OpenIAP structure
16
+ - Updated listener setup to use new OpenIAP methods (`purchaseUpdatedListener`, `purchaseErrorListener`)
17
+ - Added unified `removeAllListeners()` for cleanup
18
+
19
+ ### Fixed
20
+
21
+ - Fixed duplicate purchase success alerts
22
+ - Fixed restore purchase alerts on screen entry
23
+ - Improved purchase validation logic
24
+
25
+ ### Note
26
+
27
+ - Android native module integration with OpenIAP Android planned for v3.0.0
28
+
29
+ ## [2.8.7] - 2025-09-03
30
+
31
+ ### Added
32
+
33
+ - `fetchProducts` function following OpenIAP terminology (replaces `requestProducts`)
34
+
35
+ ### Deprecated
36
+
37
+ - `requestProducts` - Use `fetchProducts` instead (will be removed in v3.0.0)
38
+
39
+ ### Changed
40
+
41
+ - Internal useIAP hook now uses `fetchProducts`
42
+ - Updated documentation and deprecation messages
43
+
3
44
  ## [2.8.6]
4
45
 
5
46
  ### Changed
package/CLAUDE.md CHANGED
@@ -93,3 +93,10 @@ For new feature proposals:
93
93
  2. Get community feedback and consensus
94
94
  3. Ensure alignment with OpenIAP standards
95
95
  4. Implement following the agreed specification
96
+
97
+ ## Documentation Guidelines
98
+
99
+ ### Blog Post Conventions
100
+
101
+ - **Title format**: Use version number only (e.g., `v2.8.7 - Feature Description`, not `Expo IAP v2.8.7 - Feature Description`)
102
+ - **Heading format**: Use version number only in headings (e.g., `# v2.8.7 Release Notes`, not `# Expo IAP v2.8.7 Release Notes`)
package/CONTRIBUTING.md CHANGED
@@ -47,7 +47,6 @@ This project includes VSCode configurations for easier development:
47
47
  1. **Install recommended extensions**: When you open the project in VSCode, you'll be prompted to install recommended extensions. Accept to install them.
48
48
 
49
49
  1. **Use Debug Configurations**: Press `F5` or go to Run → Start Debugging and select:
50
-
51
50
  - `Debug iOS (Expo)` - Runs the example app on iOS simulator
52
51
  - `Debug Android (Expo)` - Runs the example app on Android emulator
53
52
  - `iOS + Metro` - Starts Metro bundler and iOS app together
@@ -183,7 +182,7 @@ bun start
183
182
  # Run on iOS simulator
184
183
  bun run ios
185
184
 
186
- # Run on Android emulator
185
+ # Run on Android emulator
187
186
  bun run android
188
187
 
189
188
  # Run tests
@@ -287,12 +286,12 @@ bun run test:coverage
287
286
  Example test structure:
288
287
 
289
288
  ```typescript
290
- import {render, fireEvent} from '@testing-library/react-native';
289
+ import { render, fireEvent } from '@testing-library/react-native';
291
290
  import MyComponent from '../MyComponent';
292
291
 
293
292
  describe('MyComponent', () => {
294
293
  it('should render correctly', () => {
295
- const {getByText} = render(<MyComponent />);
294
+ const { getByText } = render(<MyComponent />);
296
295
  expect(getByText('Expected Text')).toBeTruthy();
297
296
  });
298
297
  });
@@ -73,7 +73,7 @@ class ExpoIapModule :
73
73
  error["code"] = errorData.code
74
74
  error["message"] = errorData.message
75
75
  try {
76
- sendEvent(IapEvent.PURCHASE_ERROR, error.toMap())
76
+ sendEvent(OpenIapEvent.PURCHASE_ERROR, error.toMap())
77
77
  } catch (e: Exception) {
78
78
  Log.e(TAG, "Failed to send PURCHASE_ERROR event: ${e.message}")
79
79
  }
@@ -109,7 +109,7 @@ class ExpoIapModule :
109
109
  }
110
110
  promiseItems.add(item.toMap())
111
111
  try {
112
- sendEvent(IapEvent.PURCHASE_UPDATED, item.toMap())
112
+ sendEvent(OpenIapEvent.PURCHASE_UPDATED, item.toMap())
113
113
  } catch (e: Exception) {
114
114
  Log.e(TAG, "Failed to send PURCHASE_UPDATED event: ${e.message}")
115
115
  }
@@ -125,7 +125,7 @@ class ExpoIapModule :
125
125
  "The purchases are null. This is a normal behavior if you have requested DEFERRED proration. If not please report an issue.",
126
126
  )
127
127
  try {
128
- sendEvent(IapEvent.PURCHASE_UPDATED, result.toMap())
128
+ sendEvent(OpenIapEvent.PURCHASE_UPDATED, result.toMap())
129
129
  } catch (e: Exception) {
130
130
  Log.e(TAG, "Failed to send PURCHASE_UPDATED event: ${e.message}")
131
131
  }
@@ -141,7 +141,7 @@ class ExpoIapModule :
141
141
  "ERROR_CODES" to IapErrorCode.toMap()
142
142
  )
143
143
 
144
- Events(IapEvent.PURCHASE_UPDATED, IapEvent.PURCHASE_ERROR)
144
+ Events(OpenIapEvent.PURCHASE_UPDATED, OpenIapEvent.PURCHASE_ERROR)
145
145
 
146
146
  AsyncFunction("initConnection") { promise: Promise ->
147
147
  initBillingClient(promise) { promise.resolve(true) }
@@ -154,7 +154,120 @@ class ExpoIapModule :
154
154
  promise.resolve(true)
155
155
  }
156
156
 
157
+ AsyncFunction("fetchProducts") { type: String, skuArr: Array<String>, promise: Promise ->
158
+ ensureConnection(promise) { billingClient ->
159
+ val skuList =
160
+ skuArr.map { sku ->
161
+ QueryProductDetailsParams.Product
162
+ .newBuilder()
163
+ .setProductId(sku)
164
+ .setProductType(type)
165
+ .build()
166
+ }
167
+
168
+ if (skuList.isEmpty()) {
169
+ promise.reject(IapErrorCode.E_EMPTY_SKU_LIST, "The SKU list is empty.", null)
170
+ return@ensureConnection
171
+ }
172
+
173
+ val params =
174
+ QueryProductDetailsParams
175
+ .newBuilder()
176
+ .setProductList(skuList)
177
+ .build()
178
+
179
+ billingClient.queryProductDetailsAsync(params) { billingResult: BillingResult, productDetailsResult: QueryProductDetailsResult ->
180
+ if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
181
+ promise.reject(
182
+ IapErrorCode.E_QUERY_PRODUCT,
183
+ "Error querying product details: ${billingResult.debugMessage}",
184
+ null,
185
+ )
186
+ return@queryProductDetailsAsync
187
+ }
188
+
189
+ val productDetailsList = productDetailsResult.productDetailsList ?: emptyList()
190
+
191
+ val items =
192
+ productDetailsList.map { productDetails ->
193
+ skus[productDetails.productId] = productDetails
194
+
195
+ val currency = productDetails.oneTimePurchaseOfferDetails?.priceCurrencyCode
196
+ ?: productDetails.subscriptionOfferDetails?.firstOrNull()?.pricingPhases?.pricingPhaseList?.firstOrNull()?.priceCurrencyCode
197
+ ?: "Unknown"
198
+ val displayPrice = productDetails.oneTimePurchaseOfferDetails?.formattedPrice
199
+ ?: productDetails.subscriptionOfferDetails?.firstOrNull()?.pricingPhases?.pricingPhaseList?.firstOrNull()?.formattedPrice
200
+ ?: "N/A"
201
+
202
+ // Prepare reusable data
203
+ val oneTimePurchaseData = productDetails.oneTimePurchaseOfferDetails?.let {
204
+ mapOf(
205
+ "priceCurrencyCode" to it.priceCurrencyCode,
206
+ "formattedPrice" to it.formattedPrice,
207
+ "priceAmountMicros" to it.priceAmountMicros.toString(),
208
+ )
209
+ }
210
+
211
+ val subscriptionOfferData = productDetails.subscriptionOfferDetails?.map { subscriptionOfferDetailsItem ->
212
+ mapOf(
213
+ "basePlanId" to subscriptionOfferDetailsItem.basePlanId,
214
+ "offerId" to subscriptionOfferDetailsItem.offerId,
215
+ "offerToken" to subscriptionOfferDetailsItem.offerToken,
216
+ "offerTags" to subscriptionOfferDetailsItem.offerTags,
217
+ "pricingPhases" to
218
+ mapOf(
219
+ "pricingPhaseList" to
220
+ subscriptionOfferDetailsItem.pricingPhases.pricingPhaseList.map
221
+ { pricingPhaseItem ->
222
+ mapOf(
223
+ "formattedPrice" to pricingPhaseItem.formattedPrice,
224
+ "priceCurrencyCode" to pricingPhaseItem.priceCurrencyCode,
225
+ "billingPeriod" to pricingPhaseItem.billingPeriod,
226
+ "billingCycleCount" to pricingPhaseItem.billingCycleCount,
227
+ "priceAmountMicros" to
228
+ pricingPhaseItem.priceAmountMicros.toString(),
229
+ "recurrenceMode" to pricingPhaseItem.recurrenceMode,
230
+ )
231
+ },
232
+ ),
233
+ )
234
+ }
235
+
236
+ // Convert Android productType to our expected 'inapp' or 'subs'
237
+ val productType = if (productDetails.productType == BillingClient.ProductType.SUBS) "subs" else "inapp"
238
+
239
+ mapOf(
240
+ "id" to productDetails.productId,
241
+ "title" to productDetails.title,
242
+ "description" to productDetails.description,
243
+ "type" to productType,
244
+ // New field names with Android suffix
245
+ "nameAndroid" to productDetails.name,
246
+ "oneTimePurchaseOfferDetailsAndroid" to oneTimePurchaseData,
247
+ "subscriptionOfferDetailsAndroid" to subscriptionOfferData,
248
+ "platform" to "android",
249
+ "currency" to currency,
250
+ "displayPrice" to displayPrice,
251
+ // START: Deprecated - will be removed in v2.9.0
252
+ // Use nameAndroid instead of displayName
253
+ "displayName" to productDetails.name,
254
+ // Use nameAndroid instead of name
255
+ "name" to productDetails.name,
256
+ // Use oneTimePurchaseOfferDetailsAndroid instead of oneTimePurchaseOfferDetails
257
+ "oneTimePurchaseOfferDetails" to oneTimePurchaseData,
258
+ // Use subscriptionOfferDetailsAndroid instead of subscriptionOfferDetails
259
+ "subscriptionOfferDetails" to subscriptionOfferData,
260
+ // END: Deprecated - will be removed in v2.9.0
261
+ )
262
+ }
263
+ promise.resolve(items)
264
+ }
265
+ }
266
+ }
267
+
157
268
  AsyncFunction("requestProducts") { type: String, skuArr: Array<String>, promise: Promise ->
269
+ Log.w("ExpoIap", "WARNING: requestProducts is deprecated. Use fetchProducts instead. The 'request' prefix should only be used for event-based operations. This method will be removed in version 3.0.0.")
270
+
158
271
  ensureConnection(promise) { billingClient ->
159
272
  val skuList =
160
273
  skuArr.map { sku ->
@@ -337,7 +450,7 @@ class ExpoIapModule :
337
450
  val debugMessage = "The number of skus (${skuArr.size}) must match: the number of offerTokens (${offerTokenArr.size}) for Subscriptions"
338
451
  try {
339
452
  sendEvent(
340
- IapEvent.PURCHASE_ERROR,
453
+ OpenIapEvent.PURCHASE_ERROR,
341
454
  mapOf(
342
455
  "debugMessage" to debugMessage,
343
456
  "code" to IapErrorCode.E_SKU_OFFER_MISMATCH,
@@ -359,7 +472,7 @@ class ExpoIapModule :
359
472
  "The sku was not found. Please fetch products first by calling getItems"
360
473
  try {
361
474
  sendEvent(
362
- IapEvent.PURCHASE_ERROR,
475
+ OpenIapEvent.PURCHASE_ERROR,
363
476
  mapOf(
364
477
  "debugMessage" to debugMessage,
365
478
  "code" to IapErrorCode.E_SKU_NOT_FOUND,
@@ -464,7 +577,7 @@ class ExpoIapModule :
464
577
  }
465
578
 
466
579
  try {
467
- sendEvent(IapEvent.PURCHASE_ERROR, errorMap.toMap())
580
+ sendEvent(OpenIapEvent.PURCHASE_ERROR, errorMap.toMap())
468
581
  } catch (e: Exception) {
469
582
  Log.e(TAG, "Failed to send PURCHASE_ERROR event: ${e.message}")
470
583
  }
@@ -85,7 +85,7 @@ object IapErrorCode {
85
85
  /**
86
86
  * IAP Event constants
87
87
  */
88
- object IapEvent {
88
+ object OpenIapEvent {
89
89
  const val PURCHASE_UPDATED = "purchase-updated"
90
90
  const val PURCHASE_ERROR = "purchase-error"
91
91
  }
@@ -1 +1 @@
1
- {"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../src/helpers/subscription.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,IAAI,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GACjC,kBAAkB,MAAM,EAAE,KACzB,OAAO,CAAC,kBAAkB,EAAE,CAgG9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GACjC,kBAAkB,MAAM,EAAE,KACzB,OAAO,CAAC,OAAO,CAGjB,CAAC"}
1
+ {"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../src/helpers/subscription.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,IAAI,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GACjC,kBAAkB,MAAM,EAAE,KACzB,OAAO,CAAC,kBAAkB,EAAE,CAyF9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GACjC,kBAAkB,MAAM,EAAE,KACzB,OAAO,CAAC,OAAO,CAGjB,CAAC"}
@@ -20,7 +20,7 @@ export const getActiveSubscriptions = async (subscriptionIds) => {
20
20
  }
21
21
  // Check if this purchase has subscription-specific fields
22
22
  const hasSubscriptionFields = ('expirationDateIOS' in purchase && purchase.expirationDateIOS) ||
23
- 'autoRenewingAndroid' in purchase ||
23
+ ('autoRenewingAndroid' in purchase) ||
24
24
  ('environmentIOS' in purchase && purchase.environmentIOS === 'Sandbox');
25
25
  if (!hasSubscriptionFields) {
26
26
  return false;
@@ -35,11 +35,8 @@ export const getActiveSubscriptions = async (subscriptionIds) => {
35
35
  if ('environmentIOS' in purchase && purchase.environmentIOS) {
36
36
  const dayInMs = 24 * 60 * 60 * 1000;
37
37
  // If no expiration date, consider active if transaction is recent (within 24 hours for Sandbox)
38
- if (!('expirationDateIOS' in purchase) ||
39
- !purchase.expirationDateIOS) {
40
- if (purchase.environmentIOS === 'Sandbox' &&
41
- purchase.transactionDate &&
42
- currentTime - purchase.transactionDate < dayInMs) {
38
+ if (!('expirationDateIOS' in purchase) || !purchase.expirationDateIOS) {
39
+ if (purchase.environmentIOS === 'Sandbox' && purchase.transactionDate && (currentTime - purchase.transactionDate) < dayInMs) {
43
40
  return true;
44
41
  }
45
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../src/helpers/subscription.ts"],"names":[],"mappings":"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","sourcesContent":["import {Platform} from 'react-native';\nimport {getAvailablePurchases} from '../index';\n\nexport interface ActiveSubscription {\n productId: string;\n isActive: boolean;\n expirationDateIOS?: Date;\n autoRenewingAndroid?: boolean;\n environmentIOS?: string;\n willExpireSoon?: boolean;\n daysUntilExpirationIOS?: number;\n}\n\n/**\n * Get all active subscriptions with detailed information\n * @param subscriptionIds - Optional array of subscription product IDs to filter. If not provided, returns all active subscriptions.\n * @returns Promise<ActiveSubscription[]> array of active subscriptions with details\n */\nexport const getActiveSubscriptions = async (\n subscriptionIds?: string[],\n): Promise<ActiveSubscription[]> => {\n try {\n const purchases = await getAvailablePurchases();\n const currentTime = Date.now();\n const activeSubscriptions: ActiveSubscription[] = [];\n\n // Filter purchases to find active subscriptions\n const filteredPurchases = purchases.filter((purchase) => {\n // If specific IDs provided, filter by them\n if (subscriptionIds && subscriptionIds.length > 0) {\n if (!subscriptionIds.includes(purchase.productId)) {\n return false;\n }\n }\n\n // Check if this purchase has subscription-specific fields\n const hasSubscriptionFields =\n ('expirationDateIOS' in purchase && purchase.expirationDateIOS) ||\n 'autoRenewingAndroid' in purchase ||\n ('environmentIOS' in purchase && purchase.environmentIOS === 'Sandbox');\n\n if (!hasSubscriptionFields) {\n return false;\n }\n\n // Check if it's actually active\n if (Platform.OS === 'ios') {\n if ('expirationDateIOS' in purchase && purchase.expirationDateIOS) {\n return purchase.expirationDateIOS > currentTime;\n }\n // For iOS purchases without expiration date (like Sandbox), we consider them active\n // if they have the environmentIOS field and were created recently\n if ('environmentIOS' in purchase && purchase.environmentIOS) {\n const dayInMs = 24 * 60 * 60 * 1000;\n // If no expiration date, consider active if transaction is recent (within 24 hours for Sandbox)\n if (\n !('expirationDateIOS' in purchase) ||\n !purchase.expirationDateIOS\n ) {\n if (\n purchase.environmentIOS === 'Sandbox' &&\n purchase.transactionDate &&\n currentTime - purchase.transactionDate < dayInMs\n ) {\n return true;\n }\n }\n }\n } else if (Platform.OS === 'android') {\n // For Android, if it's in the purchases list, it's active\n return true;\n }\n\n return false;\n });\n\n // Convert to ActiveSubscription format\n for (const purchase of filteredPurchases) {\n const subscription: ActiveSubscription = {\n productId: purchase.productId,\n isActive: true,\n };\n\n // Add platform-specific details\n if (Platform.OS === 'ios') {\n if ('expirationDateIOS' in purchase && purchase.expirationDateIOS) {\n const expirationDate = new Date(purchase.expirationDateIOS);\n subscription.expirationDateIOS = expirationDate;\n\n // Calculate days until expiration (round to nearest day)\n const daysUntilExpiration = Math.round(\n (purchase.expirationDateIOS - currentTime) / (1000 * 60 * 60 * 24),\n );\n subscription.daysUntilExpirationIOS = daysUntilExpiration;\n subscription.willExpireSoon = daysUntilExpiration <= 7;\n }\n\n if ('environmentIOS' in purchase) {\n subscription.environmentIOS = purchase.environmentIOS;\n }\n } else if (Platform.OS === 'android') {\n if ('autoRenewingAndroid' in purchase) {\n subscription.autoRenewingAndroid = purchase.autoRenewingAndroid;\n // If auto-renewing is false, subscription will expire soon\n subscription.willExpireSoon = !purchase.autoRenewingAndroid;\n }\n }\n\n activeSubscriptions.push(subscription);\n }\n\n return activeSubscriptions;\n } catch (error) {\n console.error('Error getting active subscriptions:', error);\n return [];\n }\n};\n\n/**\n * Check if user has any active subscriptions\n * @param subscriptionIds - Optional array of subscription product IDs to check. If not provided, checks all subscriptions.\n * @returns Promise<boolean> true if user has at least one active subscription\n */\nexport const hasActiveSubscriptions = async (\n subscriptionIds?: string[],\n): Promise<boolean> => {\n const subscriptions = await getActiveSubscriptions(subscriptionIds);\n return subscriptions.length > 0;\n};\n"]}
1
+ {"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../src/helpers/subscription.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'react-native';\nimport { getAvailablePurchases } from '../index';\n\nexport interface ActiveSubscription {\n productId: string;\n isActive: boolean;\n expirationDateIOS?: Date;\n autoRenewingAndroid?: boolean;\n environmentIOS?: string;\n willExpireSoon?: boolean;\n daysUntilExpirationIOS?: number;\n}\n\n/**\n * Get all active subscriptions with detailed information\n * @param subscriptionIds - Optional array of subscription product IDs to filter. If not provided, returns all active subscriptions.\n * @returns Promise<ActiveSubscription[]> array of active subscriptions with details\n */\nexport const getActiveSubscriptions = async (\n subscriptionIds?: string[]\n): Promise<ActiveSubscription[]> => {\n try {\n const purchases = await getAvailablePurchases();\n const currentTime = Date.now();\n const activeSubscriptions: ActiveSubscription[] = [];\n \n // Filter purchases to find active subscriptions\n const filteredPurchases = purchases.filter((purchase) => {\n // If specific IDs provided, filter by them\n if (subscriptionIds && subscriptionIds.length > 0) {\n if (!subscriptionIds.includes(purchase.productId)) {\n return false;\n }\n }\n \n // Check if this purchase has subscription-specific fields\n const hasSubscriptionFields = \n ('expirationDateIOS' in purchase && purchase.expirationDateIOS) ||\n ('autoRenewingAndroid' in purchase) ||\n ('environmentIOS' in purchase && purchase.environmentIOS === 'Sandbox');\n \n if (!hasSubscriptionFields) {\n return false;\n }\n \n // Check if it's actually active\n if (Platform.OS === 'ios') {\n if ('expirationDateIOS' in purchase && purchase.expirationDateIOS) {\n return purchase.expirationDateIOS > currentTime;\n }\n // For iOS purchases without expiration date (like Sandbox), we consider them active\n // if they have the environmentIOS field and were created recently\n if ('environmentIOS' in purchase && purchase.environmentIOS) {\n const dayInMs = 24 * 60 * 60 * 1000;\n // If no expiration date, consider active if transaction is recent (within 24 hours for Sandbox)\n if (!('expirationDateIOS' in purchase) || !purchase.expirationDateIOS) {\n if (purchase.environmentIOS === 'Sandbox' && purchase.transactionDate && (currentTime - purchase.transactionDate) < dayInMs) {\n return true;\n }\n }\n }\n } else if (Platform.OS === 'android') {\n // For Android, if it's in the purchases list, it's active\n return true;\n }\n \n return false;\n });\n \n // Convert to ActiveSubscription format\n for (const purchase of filteredPurchases) {\n const subscription: ActiveSubscription = {\n productId: purchase.productId,\n isActive: true,\n };\n \n // Add platform-specific details\n if (Platform.OS === 'ios') {\n if ('expirationDateIOS' in purchase && purchase.expirationDateIOS) {\n const expirationDate = new Date(purchase.expirationDateIOS);\n subscription.expirationDateIOS = expirationDate;\n \n // Calculate days until expiration (round to nearest day)\n const daysUntilExpiration = Math.round(\n (purchase.expirationDateIOS - currentTime) / (1000 * 60 * 60 * 24)\n );\n subscription.daysUntilExpirationIOS = daysUntilExpiration;\n subscription.willExpireSoon = daysUntilExpiration <= 7;\n }\n \n if ('environmentIOS' in purchase) {\n subscription.environmentIOS = purchase.environmentIOS;\n }\n } else if (Platform.OS === 'android') {\n if ('autoRenewingAndroid' in purchase) {\n subscription.autoRenewingAndroid = purchase.autoRenewingAndroid;\n // If auto-renewing is false, subscription will expire soon\n subscription.willExpireSoon = !purchase.autoRenewingAndroid;\n }\n }\n \n activeSubscriptions.push(subscription);\n }\n \n return activeSubscriptions;\n } catch (error) {\n console.error('Error getting active subscriptions:', error);\n return [];\n }\n};\n\n/**\n * Check if user has any active subscriptions\n * @param subscriptionIds - Optional array of subscription product IDs to check. If not provided, checks all subscriptions.\n * @returns Promise<boolean> true if user has at least one active subscription\n */\nexport const hasActiveSubscriptions = async (\n subscriptionIds?: string[]\n): Promise<boolean> => {\n const subscriptions = await getActiveSubscriptions(subscriptionIds);\n return subscriptions.length > 0;\n};"]}
package/build/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export * from './modules/ios';
5
5
  export type { AppTransactionIOS } from './types/ExpoIapIOS.types';
6
6
  export { getActiveSubscriptions, hasActiveSubscriptions, type ActiveSubscription, } from './helpers/subscription';
7
7
  export declare const PI: any;
8
- export declare enum IapEvent {
8
+ export declare enum OpenIapEvent {
9
9
  PurchaseUpdated = "purchase-updated",
10
10
  PurchaseError = "purchase-error",
11
11
  /** @deprecated Use PurchaseUpdated instead. This will be removed in a future version. */
@@ -53,27 +53,53 @@ export declare const getProducts: (skus: string[]) => Promise<Product[]>;
53
53
  export declare const getSubscriptions: (skus: string[]) => Promise<SubscriptionProduct[]>;
54
54
  export declare function endConnection(): Promise<boolean>;
55
55
  /**
56
- * Request products with unified API (v2.7.0+)
56
+ * Fetch products with unified API (v2.7.0+)
57
57
  *
58
- * @param params - Product request configuration
58
+ * @param params - Product fetch configuration
59
59
  * @param params.skus - Array of product SKUs to fetch
60
60
  * @param params.type - Type of products: 'inapp' for regular products (default) or 'subs' for subscriptions
61
61
  *
62
62
  * @example
63
63
  * ```typescript
64
64
  * // Regular products
65
- * const products = await requestProducts({
65
+ * const products = await fetchProducts({
66
66
  * skus: ['product1', 'product2'],
67
67
  * type: 'inapp'
68
68
  * });
69
69
  *
70
70
  * // Subscriptions
71
- * const subscriptions = await requestProducts({
71
+ * const subscriptions = await fetchProducts({
72
72
  * skus: ['sub1', 'sub2'],
73
73
  * type: 'subs'
74
74
  * });
75
75
  * ```
76
76
  */
77
+ export declare const fetchProducts: ({ skus, type, }: {
78
+ skus: string[];
79
+ type?: "inapp" | "subs";
80
+ }) => Promise<Product[] | SubscriptionProduct[]>;
81
+ /**
82
+ * @deprecated Use `fetchProducts` instead. This method will be removed in version 3.0.0.
83
+ *
84
+ * The 'request' prefix should only be used for event-based operations that trigger
85
+ * purchase flows. Since this function simply fetches product information, it has been
86
+ * renamed to `fetchProducts` to follow OpenIAP terminology guidelines.
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * // Old way (deprecated)
91
+ * const products = await requestProducts({
92
+ * skus: ['com.example.product1'],
93
+ * type: 'inapp'
94
+ * });
95
+ *
96
+ * // New way (recommended)
97
+ * const products = await fetchProducts({
98
+ * skus: ['com.example.product1'],
99
+ * type: 'inapp'
100
+ * });
101
+ * ```
102
+ */
77
103
  export declare const requestProducts: ({ skus, type, }: {
78
104
  skus: string[];
79
105
  type?: "inapp" | "subs";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkBA,OAAO,EACL,OAAO,EACP,QAAQ,EACR,aAAa,EAEb,cAAc,EACd,wBAAwB,EACxB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AAKzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAC,iBAAiB,EAAC,MAAM,0BAA0B,CAAC;AAGhE,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,kBAAkB,GACxB,MAAM,wBAAwB,CAAC;AAGhC,eAAO,MAAM,EAAE,KAAmB,CAAC;AAEnC,oBAAY,YAAY;IACtB,eAAe,qBAAqB;IACpC,aAAa,mBAAmB;IAChC,yFAAyF;IACzF,qBAAqB,4BAA4B;IACjD,kBAAkB,yBAAyB;CAC5C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,OAE1C;AAGD,eAAO,MAAM,OAAO,EAAoD;IACtE,WAAW,EAAE,CACX,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,KAC/B;QAAC,MAAM,EAAE,MAAM,IAAI,CAAA;KAAC,CAAC;IAC1B,cAAc,EAAE,CACd,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,KAC/B,IAAI,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,UAAU,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI;YARrB,MAAM,IAAI;CAezB,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,UAAU,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI;YAlB1B,MAAM,IAAI;CAqBzB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,0BAA0B,GACrC,UAAU,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI;YA5CtB,MAAM,IAAI;CAqDzB,CAAC;AAEF,wBAAgB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAGjD;AAED,eAAO,MAAM,WAAW,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,OAAO,EAAE,CA8BnE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,MAAM,MAAM,EAAE,KACb,OAAO,CAAC,mBAAmB,EAAE,CAqC/B,CAAC;AAEF,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAEtD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,aAAa,GAAU,iBAGjC;IACD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACzB,KAAG,OAAO,CAAC,OAAO,EAAE,GAAG,mBAAmB,EAAE,CA0C5C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,eAAe,GAAU,iBAGnC;IACD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACzB,KAAG,OAAO,CAAC,OAAO,EAAE,GAAG,mBAAmB,EAAE,CAK5C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,oHAKhC;IACD,4DAA4D;IAC5D,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,wDAAwD;IACxD,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CAChC,KAAG,OAAO,CAAC,QAAQ,EAAE,CAQ1B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,oHAKlC;IACD,4DAA4D;IAC5D,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,wDAAwD;IACxD,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CAChC,KAAG,OAAO,CAAC,QAAQ,EAAE,CAkBtB,CAAC;AAEN,eAAO,MAAM,qBAAqB,GAAI,oHAKnC;IACD,4DAA4D;IAC5D,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,wDAAwD;IACxD,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CAChC,KAAG,OAAO,CAAC,QAAQ,EAAE,CAetB,CAAC;AAgBN,KAAK,eAAe,GAChB;IACE,OAAO,EAAE,oBAAoB,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,GACD;IACE,OAAO,EAAE,wBAAwB,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAaN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,eAAe,GAC1B,YAAY,eAAe,KAC1B,OAAO,CACN,QAAQ,GACR,QAAQ,EAAE,GACV,IAAI,CAoGP,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,mBAAmB,GAC9B,SAAS,wBAAwB,KAChC,OAAO,CAAC,QAAQ,GAAG,QAAQ,EAAE,GAAG,IAAI,GAAG,IAAI,CAS7C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,6BAG/B;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,KAAG,OAAO,CAAC,cAAc,GAAG,OAAO,CAyCnC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,QAAO,OAAO,CAAC,MAAM,CAMjD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,QAAO,OAAO,CAAC,MAAM,CAK9C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAC1B,KAAK,MAAM,EACX,iBAAiB;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,KACA,OAAO,CAAC,GAAG,CAwBb,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,uBAAuB,GAAI,SAAS;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,KAAG,OAAO,CAAC,IAAI,CA2Bf,CAAC;AAEF,cAAc,UAAU,CAAC;AACzB,cAAc,sBAAsB,CAAC"}
package/build/index.js CHANGED
@@ -15,25 +15,25 @@ export * from './modules/ios';
15
15
  export { getActiveSubscriptions, hasActiveSubscriptions, } from './helpers/subscription';
16
16
  // Get the native constant value
17
17
  export const PI = ExpoIapModule.PI;
18
- export var IapEvent;
19
- (function (IapEvent) {
20
- IapEvent["PurchaseUpdated"] = "purchase-updated";
21
- IapEvent["PurchaseError"] = "purchase-error";
18
+ export var OpenIapEvent;
19
+ (function (OpenIapEvent) {
20
+ OpenIapEvent["PurchaseUpdated"] = "purchase-updated";
21
+ OpenIapEvent["PurchaseError"] = "purchase-error";
22
22
  /** @deprecated Use PurchaseUpdated instead. This will be removed in a future version. */
23
- IapEvent["TransactionIapUpdated"] = "iap-transaction-updated";
24
- IapEvent["PromotedProductIOS"] = "promoted-product-ios";
25
- })(IapEvent || (IapEvent = {}));
23
+ OpenIapEvent["TransactionIapUpdated"] = "iap-transaction-updated";
24
+ OpenIapEvent["PromotedProductIOS"] = "promoted-product-ios";
25
+ })(OpenIapEvent || (OpenIapEvent = {}));
26
26
  export function setValueAsync(value) {
27
27
  return ExpoIapModule.setValueAsync(value);
28
28
  }
29
29
  // Ensure the emitter has proper EventEmitter interface
30
30
  export const emitter = (ExpoIapModule || NativeModulesProxy.ExpoIap);
31
31
  export const purchaseUpdatedListener = (listener) => {
32
- const emitterSubscription = emitter.addListener(IapEvent.PurchaseUpdated, listener);
32
+ const emitterSubscription = emitter.addListener(OpenIapEvent.PurchaseUpdated, listener);
33
33
  return emitterSubscription;
34
34
  };
35
35
  export const purchaseErrorListener = (listener) => {
36
- return emitter.addListener(IapEvent.PurchaseError, listener);
36
+ return emitter.addListener(OpenIapEvent.PurchaseError, listener);
37
37
  };
38
38
  /**
39
39
  * iOS-only listener for App Store promoted product events.
@@ -60,20 +60,20 @@ export const promotedProductListenerIOS = (listener) => {
60
60
  console.warn('promotedProductListenerIOS: This listener is only available on iOS');
61
61
  return { remove: () => { } };
62
62
  }
63
- return emitter.addListener(IapEvent.PromotedProductIOS, listener);
63
+ return emitter.addListener(OpenIapEvent.PromotedProductIOS, listener);
64
64
  };
65
65
  export function initConnection() {
66
66
  const result = ExpoIapModule.initConnection();
67
67
  return Promise.resolve(result);
68
68
  }
69
69
  export const getProducts = async (skus) => {
70
- console.warn("`getProducts` is deprecated. Use `requestProducts({ skus, type: 'inapp' })` instead. This function will be removed in version 3.0.0.");
70
+ console.warn("`getProducts` is deprecated. Use `fetchProducts({ skus, type: 'inapp' })` instead. This function will be removed in version 3.0.0.");
71
71
  if (!skus?.length) {
72
72
  return Promise.reject(new Error('"skus" is required'));
73
73
  }
74
74
  return Platform.select({
75
75
  ios: async () => {
76
- const rawItems = await ExpoIapModule.requestProducts(skus);
76
+ const rawItems = await ExpoIapModule.fetchProducts(skus);
77
77
  return rawItems.filter((item) => {
78
78
  if (!isProductIOS(item))
79
79
  return false;
@@ -85,20 +85,20 @@ export const getProducts = async (skus) => {
85
85
  });
86
86
  },
87
87
  android: async () => {
88
- const products = await ExpoIapModule.requestProducts('inapp', skus);
88
+ const products = await ExpoIapModule.fetchProducts('inapp', skus);
89
89
  return products.filter((product) => isProductAndroid(product));
90
90
  },
91
91
  default: () => Promise.reject(new Error('Unsupported Platform')),
92
92
  })();
93
93
  };
94
94
  export const getSubscriptions = async (skus) => {
95
- console.warn("`getSubscriptions` is deprecated. Use `requestProducts({ skus, type: 'subs' })` instead. This function will be removed in version 3.0.0.");
95
+ console.warn("`getSubscriptions` is deprecated. Use `fetchProducts({ skus, type: 'subs' })` instead. This function will be removed in version 3.0.0.");
96
96
  if (!skus?.length) {
97
97
  return Promise.reject(new Error('"skus" is required'));
98
98
  }
99
99
  return Platform.select({
100
100
  ios: async () => {
101
- const rawItems = await ExpoIapModule.requestProducts(skus);
101
+ const rawItems = await ExpoIapModule.fetchProducts(skus);
102
102
  return rawItems.filter((item) => {
103
103
  if (!isProductIOS(item))
104
104
  return false;
@@ -110,7 +110,7 @@ export const getSubscriptions = async (skus) => {
110
110
  });
111
111
  },
112
112
  android: async () => {
113
- const rawItems = await ExpoIapModule.requestProducts('subs', skus);
113
+ const rawItems = await ExpoIapModule.fetchProducts('subs', skus);
114
114
  return rawItems.filter((item) => {
115
115
  if (!isProductAndroid(item))
116
116
  return false;
@@ -128,33 +128,33 @@ export async function endConnection() {
128
128
  return ExpoIapModule.endConnection();
129
129
  }
130
130
  /**
131
- * Request products with unified API (v2.7.0+)
131
+ * Fetch products with unified API (v2.7.0+)
132
132
  *
133
- * @param params - Product request configuration
133
+ * @param params - Product fetch configuration
134
134
  * @param params.skus - Array of product SKUs to fetch
135
135
  * @param params.type - Type of products: 'inapp' for regular products (default) or 'subs' for subscriptions
136
136
  *
137
137
  * @example
138
138
  * ```typescript
139
139
  * // Regular products
140
- * const products = await requestProducts({
140
+ * const products = await fetchProducts({
141
141
  * skus: ['product1', 'product2'],
142
142
  * type: 'inapp'
143
143
  * });
144
144
  *
145
145
  * // Subscriptions
146
- * const subscriptions = await requestProducts({
146
+ * const subscriptions = await fetchProducts({
147
147
  * skus: ['sub1', 'sub2'],
148
148
  * type: 'subs'
149
149
  * });
150
150
  * ```
151
151
  */
152
- export const requestProducts = async ({ skus, type = 'inapp', }) => {
152
+ export const fetchProducts = async ({ skus, type = 'inapp', }) => {
153
153
  if (!skus?.length) {
154
154
  throw new Error('No SKUs provided');
155
155
  }
156
156
  if (Platform.OS === 'ios') {
157
- const rawItems = await ExpoIapModule.requestProducts(skus);
157
+ const rawItems = await ExpoIapModule.fetchProducts(skus);
158
158
  const filteredItems = rawItems.filter((item) => {
159
159
  if (!isProductIOS(item))
160
160
  return false;
@@ -169,7 +169,7 @@ export const requestProducts = async ({ skus, type = 'inapp', }) => {
169
169
  : filteredItems;
170
170
  }
171
171
  if (Platform.OS === 'android') {
172
- const items = await ExpoIapModule.requestProducts(type, skus);
172
+ const items = await ExpoIapModule.fetchProducts(type, skus);
173
173
  const filteredItems = items.filter((item) => {
174
174
  if (!isProductAndroid(item))
175
175
  return false;
@@ -185,6 +185,32 @@ export const requestProducts = async ({ skus, type = 'inapp', }) => {
185
185
  }
186
186
  throw new Error('Unsupported platform');
187
187
  };
188
+ /**
189
+ * @deprecated Use `fetchProducts` instead. This method will be removed in version 3.0.0.
190
+ *
191
+ * The 'request' prefix should only be used for event-based operations that trigger
192
+ * purchase flows. Since this function simply fetches product information, it has been
193
+ * renamed to `fetchProducts` to follow OpenIAP terminology guidelines.
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * // Old way (deprecated)
198
+ * const products = await requestProducts({
199
+ * skus: ['com.example.product1'],
200
+ * type: 'inapp'
201
+ * });
202
+ *
203
+ * // New way (recommended)
204
+ * const products = await fetchProducts({
205
+ * skus: ['com.example.product1'],
206
+ * type: 'inapp'
207
+ * });
208
+ * ```
209
+ */
210
+ export const requestProducts = async ({ skus, type = 'inapp', }) => {
211
+ console.warn("`requestProducts` is deprecated. Use `fetchProducts` instead. The 'request' prefix should only be used for event-based operations. This method will be removed in version 3.0.0.");
212
+ return fetchProducts({ skus, type });
213
+ };
188
214
  /**
189
215
  * @deprecated Use `getPurchaseHistories` instead. This function will be removed in version 3.0.0.
190
216
  */
@@ -279,7 +305,9 @@ export const requestPurchase = (requestObj) => {
279
305
  return (async () => {
280
306
  const offer = offerToRecordIOS(withOffer);
281
307
  const purchase = await ExpoIapModule.requestPurchase(sku, andDangerouslyFinishTransactionAutomatically, appAccountToken, quantity ?? -1, offer);
282
- return type === 'inapp' ? purchase : purchase;
308
+ return type === 'inapp'
309
+ ? purchase
310
+ : purchase;
283
311
  })();
284
312
  }
285
313
  if (Platform.OS === 'android') {
@@ -393,7 +421,7 @@ export const getStorefrontIOS = () => {
393
421
  console.warn('getStorefrontIOS: This method is only available on iOS');
394
422
  return Promise.resolve('');
395
423
  }
396
- return ExpoIapModule.getStorefront();
424
+ return ExpoIapModule.getStorefrontIOS();
397
425
  };
398
426
  /**
399
427
  * @deprecated Use `getStorefrontIOS` instead. This function will be removed in version 3.0.0.