expo-iap 4.7.2 → 5.0.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 (58) hide show
  1. package/CLAUDE.md +5 -6
  2. package/android/src/main/java/expo/modules/iap/ExpoIapHelper.kt +12 -87
  3. package/android/src/main/java/expo/modules/iap/ExpoIapLog.kt +0 -14
  4. package/android/src/main/java/expo/modules/iap/ExpoIapModule.kt +5 -80
  5. package/build/index.d.ts +1 -19
  6. package/build/index.d.ts.map +1 -1
  7. package/build/index.js +14 -89
  8. package/build/index.js.map +1 -1
  9. package/build/index.kepler.d.ts +1 -42
  10. package/build/index.kepler.d.ts.map +1 -1
  11. package/build/index.kepler.js +10 -65
  12. package/build/index.kepler.js.map +1 -1
  13. package/build/modules/android.d.ts +1 -104
  14. package/build/modules/android.d.ts.map +1 -1
  15. package/build/modules/android.js +0 -124
  16. package/build/modules/android.js.map +1 -1
  17. package/build/modules/ios.d.ts +2 -57
  18. package/build/modules/ios.d.ts.map +1 -1
  19. package/build/modules/ios.js +3 -102
  20. package/build/modules/ios.js.map +1 -1
  21. package/build/types.d.ts +76 -284
  22. package/build/types.d.ts.map +1 -1
  23. package/build/types.js +0 -6
  24. package/build/types.js.map +1 -1
  25. package/build/useIAP.d.ts +1 -34
  26. package/build/useIAP.d.ts.map +1 -1
  27. package/build/useIAP.js +7 -50
  28. package/build/useIAP.js.map +1 -1
  29. package/build/utils/errorMapping.d.ts.map +1 -1
  30. package/build/utils/errorMapping.js +25 -7
  31. package/build/utils/errorMapping.js.map +1 -1
  32. package/build/vega-adapter.d.ts +1 -1
  33. package/build/vega-adapter.d.ts.map +1 -1
  34. package/build/vega-adapter.js +8 -28
  35. package/build/vega-adapter.js.map +1 -1
  36. package/ios/ExpoIapHelper.swift +19 -55
  37. package/ios/ExpoIapLog.swift +0 -11
  38. package/ios/ExpoIapModule.swift +12 -46
  39. package/ios/onside/OnsideIapModule.swift +1 -19
  40. package/openiap-versions.json +3 -3
  41. package/package.json +1 -1
  42. package/plugin/build/withIAP.d.ts +2 -14
  43. package/plugin/build/withIAP.js +6 -67
  44. package/plugin/src/expoConfig.augmentation.d.ts +6 -33
  45. package/plugin/src/withIAP.ts +8 -132
  46. package/src/index.kepler.ts +12 -93
  47. package/src/index.ts +13 -125
  48. package/src/modules/android.ts +0 -152
  49. package/src/modules/ios.ts +4 -122
  50. package/src/types.ts +77 -295
  51. package/src/useIAP.ts +9 -108
  52. package/src/utils/errorMapping.ts +31 -7
  53. package/src/vega-adapter.ts +13 -34
  54. package/build/utils/deprecation.d.ts +0 -3
  55. package/build/utils/deprecation.d.ts.map +0 -1
  56. package/build/utils/deprecation.js +0 -13
  57. package/build/utils/deprecation.js.map +0 -1
  58. package/src/utils/deprecation.ts +0 -16
package/CLAUDE.md CHANGED
@@ -51,18 +51,17 @@ Before committing any changes:
51
51
 
52
52
  #### Function Naming
53
53
 
54
- - Functions that only operate on one platform must carry the suffix: `nameIOS` or `nameAndroid` (e.g. `getStorefrontIOS`, `deepLinkToSubscriptionsAndroid`).
54
+ - Functions that only operate on one platform must carry the suffix: `nameIOS` or `nameAndroid` (e.g. `getReceiptDataIOS`, `deepLinkToSubscriptionsAndroid`).
55
55
  - Cross-platform helpers should expose a single name and branch internally via `Platform.select` or equivalent.
56
56
 
57
57
  #### Field Naming
58
58
 
59
- - **iOS-related fields**: Use `IOS` suffix (e.g., `displayNameIOS`, `discountsIOS`, `introductoryPriceIOS`)
59
+ - **iOS-related fields**: Use `IOS` suffix (e.g., `displayNameIOS`, `subscriptionGroupIdIOS`, `introductoryPriceIOS`)
60
60
  - **Exception**: When an acronym appears at the end of a field name, use uppercase (e.g., `quantityIOS`, `appBundleIdIOS`, not `quantityIos`)
61
61
  - Platform-specific fields: `currencyCodeIOS`, `currencySymbolIOS`, `countryCodeIOS`
62
- - Product fields: `isFamilyShareableIOS`, `jsonRepresentationIOS`, `subscriptionInfoIOS`
62
+ - Product fields: `isFamilyShareableIOS`, `jsonRepresentationIOS`, `subscriptionGroupIdIOS`
63
63
  - **Android-related fields**: Use `Android` suffix (e.g., `nameAndroid`)
64
- - Platform-specific fields: `oneTimePurchaseOfferDetailsAndroid`, `subscriptionOfferDetailsAndroid`
65
- - In **Android-specific types** (e.g., `ProductSubscriptionAndroidOfferDetails`), keep `pricingPhases` without suffix for consistency with Google Play Billing
64
+ - Platform-specific fields: `productStatusAndroid`, `basePlanIdAndroid`
66
65
  - In **cross-platform types** (e.g., `SubscriptionOffer`, `DiscountOffer`), use `pricingPhasesAndroid` suffix to distinguish from common fields
67
66
  - **Common fields**: Fields shared across platforms go in Common types (e.g., `ids`, `platform`, `debugDescription`)
68
67
  - Use these for data that exists on both platforms without platform-specific variations
@@ -71,7 +70,7 @@ Before committing any changes:
71
70
 
72
71
  - **iOS types**: Use `IOS` suffix (e.g., `PurchaseIOS`, `ProductIOS`)
73
72
  - **Android types**: Use descriptive prefixes to identify subtypes:
74
- - ✅ Good: `ProductAndroidOneTimePurchaseOfferDetail`, `ProductSubscriptionAndroidOfferDetails`, `PurchaseAndroidState`
73
+ - ✅ Good: `BillingProgramAvailabilityResultAndroid`, `SubscriptionPeriodIOS`, `PurchaseAndroidState`
75
74
  - ❌ Avoid: `OneTimePurchaseOfferDetails`, `SubscriptionOfferAndroid`, `PurchaseStateAndroid`
76
75
  - **General IAP types**: Use `Iap` prefix (e.g., `IapPurchase`, not `IAPPurchase`)
77
76
 
@@ -64,76 +64,35 @@ object ExpoIapHelper {
64
64
  }
65
65
 
66
66
  fun parseProductQueryType(rawType: String?): ProductQueryType {
67
- val normalized =
68
- rawType
69
- ?.trim()
70
- ?.lowercase(Locale.US)
71
- ?.replace("-", "")
72
- ?.replace("_", "")
73
-
67
+ val normalized = rawType?.trim()?.lowercase(Locale.US)
74
68
  return when (normalized) {
69
+ null, "", "in-app" -> ProductQueryType.InApp
75
70
  "subs" -> ProductQueryType.Subs
76
71
  "all" -> ProductQueryType.All
77
- else -> ProductQueryType.InApp
72
+ else -> throw IllegalArgumentException(
73
+ "Unsupported product type: $rawType. Use in-app, subs, or all.",
74
+ )
78
75
  }
79
76
  }
80
77
 
81
78
  internal fun parseDeepLinkSubscriptionParams(params: Map<String, Any?>): DeepLinkSubscriptionParams {
82
- val hasCanonicalSku = params.containsKey("skuAndroid")
83
- val hasCanonicalPackageName = params.containsKey("packageNameAndroid")
84
- val legacySku = params["sku"] as? String
85
- val legacyPackageName = params["packageName"] as? String
86
-
87
- if (!hasCanonicalSku && legacySku != null) {
88
- ExpoIapLog.deprecation(
89
- "deep-link.sku",
90
- "`sku` is deprecated and will be removed in expo-iap 5.0.0. Use `skuAndroid` instead.",
91
- )
92
- }
93
- if (!hasCanonicalPackageName && legacyPackageName != null) {
94
- ExpoIapLog.deprecation(
95
- "deep-link.packageName",
96
- "`packageName` is deprecated and will be removed in expo-iap 5.0.0. Use `packageNameAndroid` instead.",
97
- )
98
- }
99
-
100
79
  return DeepLinkSubscriptionParams(
101
- sku =
102
- if (hasCanonicalSku) {
103
- params["skuAndroid"] as? String
104
- } else {
105
- legacySku
106
- },
107
- packageName =
108
- if (hasCanonicalPackageName) {
109
- params["packageNameAndroid"] as? String
110
- } else {
111
- legacyPackageName
112
- },
80
+ sku = params["skuAndroid"] as? String,
81
+ packageName = params["packageNameAndroid"] as? String,
113
82
  )
114
83
  }
115
84
 
116
85
  fun parseRequestPurchaseParams(params: Map<String, Any?>): RequestPurchaseParams {
117
- // Support nested request.google / request.android structure
118
- // If the params contain a "request" key with nested platform-specific data,
119
- // extract and flatten it before parsing.
86
+ // If the params contain a canonical request.google envelope, flatten it
87
+ // before parsing the native request.
120
88
  val effective: Map<String, Any?> =
121
89
  run {
122
90
  val request = params["request"] as? Map<*, *>
123
91
  if (request != null) {
124
- val hasCanonicalGoogle = request.containsKey("google")
125
- val canonicalGoogle = request["google"] as? Map<*, *>
126
- val legacyAndroid = request["android"] as? Map<*, *>
127
- if (!hasCanonicalGoogle && legacyAndroid != null) {
128
- ExpoIapLog.deprecation(
129
- "request-purchase.android",
130
- "`request.android` is deprecated and will be removed in expo-iap 5.0.0. Use `request.google` instead.",
131
- )
132
- }
133
- val nested = if (hasCanonicalGoogle) canonicalGoogle else legacyAndroid
92
+ val nested = request["google"] as? Map<*, *>
134
93
  if (nested != null) {
135
94
  val flat = mutableMapOf<String, Any?>()
136
- // Carry over top-level fields like type, useAlternativeBilling
95
+ // Carry over top-level fields such as the purchase type.
137
96
  for ((k, v) in params) {
138
97
  if (k != "request") flat[k] = v
139
98
  }
@@ -151,33 +110,10 @@ object ExpoIapHelper {
151
110
  }
152
111
 
153
112
  val type = effective["type"] as? String
154
- val hasCanonicalSkus = effective.containsKey("skus")
155
- val canonicalSkus = (effective["skus"] as? List<*>)?.filterIsInstance<String>()
156
- val legacySkuArr = (effective["skuArr"] as? List<*>)?.filterIsInstance<String>()
157
- if (!hasCanonicalSkus && legacySkuArr != null) {
158
- ExpoIapLog.deprecation(
159
- "request-purchase.skuArr",
160
- "`skuArr` is deprecated and will be removed in expo-iap 5.0.0. Use `skus` instead.",
161
- )
162
- }
163
- val skus: List<String> =
164
- if (hasCanonicalSkus) {
165
- canonicalSkus ?: emptyList()
166
- } else {
167
- legacySkuArr ?: emptyList()
168
- }
113
+ val skus = (effective["skus"] as? List<*>)?.filterIsInstance<String>() ?: emptyList()
169
114
  val obfuscatedAccountId = effective["obfuscatedAccountId"] as? String
170
115
  val obfuscatedProfileId = effective["obfuscatedProfileId"] as? String
171
116
  val isOfferPersonalized = effective["isOfferPersonalized"] as? Boolean ?: false
172
- val hasCanonicalSubscriptionOffers = effective.containsKey("subscriptionOffers")
173
- val legacyOfferTokenArr =
174
- (effective["offerTokenArr"] as? List<*>)?.filterIsInstance<String>() ?: emptyList()
175
- val offerTokenArr =
176
- if (hasCanonicalSubscriptionOffers) {
177
- emptyList()
178
- } else {
179
- legacyOfferTokenArr
180
- }
181
117
  val explicitSubscriptionOffers =
182
118
  (effective["subscriptionOffers"] as? List<*>)?.mapNotNull { rawOffer ->
183
119
  val offerMap = rawOffer as? Map<*, *> ?: return@mapNotNull null
@@ -189,15 +125,8 @@ object ExpoIapHelper {
189
125
  AndroidSubscriptionOfferInput(offerToken = offerToken, sku = sku)
190
126
  }
191
127
  } ?: emptyList()
192
- if (!hasCanonicalSubscriptionOffers && offerTokenArr.isNotEmpty()) {
193
- ExpoIapLog.deprecation(
194
- "request-purchase.offerTokenArr",
195
- "`offerTokenArr` is deprecated and will be removed in expo-iap 5.0.0. Use `subscriptionOffers` instead.",
196
- )
197
- }
198
128
  val purchaseToken = effective["purchaseToken"] as? String
199
129
  val originalExternalTransactionId = effective["originalExternalTransactionId"] as? String
200
- val replacementMode = effective["replacementMode"] as? Number
201
130
  val developerBillingOption =
202
131
  (effective["developerBillingOption"] as? Map<*, *>)?.let { optionMap ->
203
132
  val json =
@@ -230,12 +159,10 @@ object ExpoIapHelper {
230
159
  obfuscatedProfileId = obfuscatedProfileId,
231
160
  isOfferPersonalized = isOfferPersonalized,
232
161
  offerToken = offerToken,
233
- offerTokenArr = offerTokenArr,
234
162
  explicitSubscriptionOffers = explicitSubscriptionOffers,
235
163
  developerBillingOption = developerBillingOption,
236
164
  originalExternalTransactionId = originalExternalTransactionId,
237
165
  purchaseToken = purchaseToken,
238
- replacementMode = replacementMode,
239
166
  subscriptionProductReplacementParams = subscriptionProductReplacementParams,
240
167
  )
241
168
  }
@@ -259,12 +186,10 @@ object ExpoIapHelper {
259
186
  val isOfferPersonalized: Boolean,
260
187
  /** Offer token for one-time purchase discounts (Android 8.0+) */
261
188
  val offerToken: String?,
262
- val offerTokenArr: List<String>,
263
189
  val explicitSubscriptionOffers: List<AndroidSubscriptionOfferInput>,
264
190
  val developerBillingOption: DeveloperBillingOptionParamsAndroid?,
265
191
  val originalExternalTransactionId: String?,
266
192
  val purchaseToken: String?,
267
- val replacementMode: Number?,
268
193
  val subscriptionProductReplacementParams: SubscriptionProductReplacementParamsAndroid?,
269
194
  )
270
195
 
@@ -3,14 +3,10 @@ package expo.modules.iap
3
3
  import android.util.Log
4
4
  import org.json.JSONArray
5
5
  import org.json.JSONObject
6
- import java.util.Collections
7
6
  import java.util.Locale
8
- import java.util.concurrent.ConcurrentHashMap
9
7
 
10
8
  internal object ExpoIapLog {
11
9
  private const val TAG = "ExpoIap"
12
- private val emittedDeprecations: MutableSet<String> =
13
- Collections.newSetFromMap(ConcurrentHashMap())
14
10
  private val SENSITIVE_KEY_FRAGMENTS =
15
11
  setOf(
16
12
  "token",
@@ -57,16 +53,6 @@ internal object ExpoIapLog {
57
53
  Log.w(TAG, message)
58
54
  }
59
55
 
60
- fun deprecation(
61
- key: String,
62
- message: String,
63
- ) {
64
- if (!emittedDeprecations.add(key)) {
65
- return
66
- }
67
- Log.w(TAG, message)
68
- }
69
-
70
56
  fun debug(message: String) {
71
57
  if (BuildConfig.DEBUG || Log.isLoggable(TAG, Log.DEBUG)) {
72
58
  Log.d(TAG, message)
@@ -1,7 +1,6 @@
1
1
  package expo.modules.iap
2
2
 
3
3
  import android.content.Context
4
- import dev.hyo.openiap.AndroidSubscriptionOfferInput
5
4
  import dev.hyo.openiap.DeepLinkOptions
6
5
  import dev.hyo.openiap.FetchProductsResultAll
7
6
  import dev.hyo.openiap.FetchProductsResultProducts
@@ -203,15 +202,15 @@ class ExpoIapModule : Module() {
203
202
  }
204
203
  }
205
204
 
206
- AsyncFunction("fetchProducts") { type: String, skuArr: Array<String>, promise: Promise ->
205
+ AsyncFunction("fetchProducts") { type: String, skus: Array<String>, promise: Promise ->
207
206
  ExpoIapLog.payload(
208
207
  "fetchProducts",
209
- mapOf("type" to type, "skus" to skuArr.toList()),
208
+ mapOf("type" to type, "skus" to skus.toList()),
210
209
  )
211
210
  scope.launch {
212
211
  try {
213
212
  val queryType = ExpoIapHelper.parseProductQueryType(type)
214
- val request = ProductRequest(skuArr.toList(), queryType)
213
+ val request = ProductRequest(skus.toList(), queryType)
215
214
  val result = openIap.fetchProducts(request)
216
215
  val payload =
217
216
  when (result) {
@@ -232,7 +231,7 @@ class ExpoIapModule : Module() {
232
231
  "message" to "Failed to query products",
233
232
  "debugMessage" to e.message,
234
233
  "platform" to "android",
235
- "productIds" to skuArr.toList(),
234
+ "productIds" to skus.toList(),
236
235
  "productType" to type,
237
236
  )
238
237
  }
@@ -339,22 +338,8 @@ class ExpoIapModule : Module() {
339
338
  else -> ProductQueryType.InApp
340
339
  }
341
340
 
342
- val fallbackOffers =
343
- if (parsedParams.explicitSubscriptionOffers.isEmpty() && parsedParams.offerTokenArr.isNotEmpty()) {
344
- parsedParams.skus.zip(parsedParams.offerTokenArr).mapNotNull { (sku, token) ->
345
- if (token.isNotEmpty()) {
346
- AndroidSubscriptionOfferInput(offerToken = token, sku = sku)
347
- } else {
348
- null
349
- }
350
- }
351
- } else {
352
- emptyList()
353
- }
354
-
355
341
  val subscriptionOffers =
356
- (parsedParams.explicitSubscriptionOffers.ifEmpty { fallbackOffers })
357
- .takeIf { it.isNotEmpty() }
342
+ parsedParams.explicitSubscriptionOffers.takeIf { it.isNotEmpty() }
358
343
 
359
344
  val requestProps =
360
345
  when (productType) {
@@ -367,7 +352,6 @@ class ExpoIapModule : Module() {
367
352
  developerBillingOption = parsedParams.developerBillingOption,
368
353
  originalExternalTransactionId = parsedParams.originalExternalTransactionId,
369
354
  purchaseToken = parsedParams.purchaseToken,
370
- replacementMode = parsedParams.replacementMode?.toInt(),
371
355
  skus = parsedParams.skus,
372
356
  subscriptionOffers = subscriptionOffers,
373
357
  subscriptionProductReplacementParams = parsedParams.subscriptionProductReplacementParams,
@@ -486,65 +470,6 @@ class ExpoIapModule : Module() {
486
470
  }
487
471
  }
488
472
 
489
- @Suppress("DEPRECATION")
490
- AsyncFunction("checkAlternativeBillingAvailabilityAndroid") { promise: Promise ->
491
- ExpoIapLog.payload("checkAlternativeBillingAvailabilityAndroid", null)
492
- scope.launch {
493
- try {
494
- val isAvailable = openIap.checkAlternativeBillingAvailability()
495
- ExpoIapLog.result("checkAlternativeBillingAvailabilityAndroid", isAvailable)
496
- promise.resolve(isAvailable)
497
- } catch (e: Exception) {
498
- ExpoIapLog.failure("checkAlternativeBillingAvailabilityAndroid", e)
499
- promise.reject(OpenIapError.ServiceUnavailable.CODE, e.message, null)
500
- }
501
- }
502
- }
503
-
504
- @Suppress("DEPRECATION")
505
- AsyncFunction("showAlternativeBillingDialogAndroid") { promise: Promise ->
506
- ExpoIapLog.payload("showAlternativeBillingDialogAndroid", null)
507
- scope.launch {
508
- try {
509
- val activity =
510
- runCatching { currentActivity }
511
- .onFailure {
512
- ExpoIapLog.failure("showAlternativeBillingDialogAndroid activity", it)
513
- }.getOrNull() ?: run {
514
- promise.reject(OpenIapError.ServiceUnavailable.CODE, "Activity not available", null)
515
- return@launch
516
- }
517
- openIap.setActivity(activity)
518
- val userAccepted = openIap.showAlternativeBillingInformationDialog(activity)
519
- ExpoIapLog.result("showAlternativeBillingDialogAndroid", userAccepted)
520
- promise.resolve(userAccepted)
521
- } catch (e: Exception) {
522
- ExpoIapLog.failure("showAlternativeBillingDialogAndroid", e)
523
- promise.reject(OpenIapError.ServiceUnavailable.CODE, e.message, null)
524
- }
525
- }
526
- }
527
-
528
- @Suppress("DEPRECATION")
529
- AsyncFunction("createAlternativeBillingTokenAndroid") { sku: String?, promise: Promise ->
530
- ExpoIapLog.payload("createAlternativeBillingTokenAndroid", mapOf("sku" to sku))
531
- scope.launch {
532
- try {
533
- // Note: OpenIapModule.createAlternativeBillingReportingToken() doesn't accept sku parameter
534
- // The sku parameter is ignored for now - may be used in future versions
535
- val token = openIap.createAlternativeBillingReportingToken()
536
- ExpoIapLog.result(
537
- "createAlternativeBillingTokenAndroid",
538
- if (token.isNullOrBlank()) "<empty>" else "<token>",
539
- )
540
- promise.resolve(token)
541
- } catch (e: Exception) {
542
- ExpoIapLog.failure("createAlternativeBillingTokenAndroid", e)
543
- promise.reject(OpenIapError.ServiceUnavailable.CODE, e.message, null)
544
- }
545
- }
546
- }
547
-
548
473
  @Suppress("UNCHECKED_CAST")
549
474
  AsyncFunction("verifyPurchase") { params: Map<String, Any?>, promise: Promise ->
550
475
  ExpoIapLog.payload("verifyPurchase", params)
package/build/index.d.ts CHANGED
@@ -41,11 +41,7 @@ type ExpoIapEmitter = {
41
41
  removeListener<E extends OpenIapEvent>(eventName: E, listener: ExpoIapEventListener<E>): void;
42
42
  };
43
43
  export declare const emitter: ExpoIapEmitter;
44
- /**
45
- * Accepts the legacy 'inapp' alias for backward compatibility. The alias is
46
- * deprecated and scheduled for removal in expo-iap 5.0.0 — use 'in-app'.
47
- */
48
- export type ProductTypeInput = ProductQueryType | 'inapp';
44
+ export type ProductTypeInput = ProductQueryType;
49
45
  export declare const purchaseUpdatedListener: (listener: (event: Purchase) => void, options?: PurchaseUpdatedListenerOptions | null) => {
50
46
  remove: () => void;
51
47
  };
@@ -373,20 +369,6 @@ export declare const restorePurchases: MutationField<'restorePurchases'>;
373
369
  * @see {@link https://openiap.dev/docs/apis/deep-link-to-subscriptions}
374
370
  */
375
371
  export declare const deepLinkToSubscriptions: MutationField<'deepLinkToSubscriptions'>;
376
- /**
377
- * Internal receipt validation function (NOT RECOMMENDED for production use)
378
- *
379
- * WARNING: This function performs client-side validation which is NOT secure.
380
- * For production apps, always validate receipts on your secure server:
381
- * - iOS: Send receipt data to Apple's verification endpoint from your server
382
- * - Android: Use Google Play Developer API with service account credentials
383
- *
384
- * @deprecated Use verifyPurchase instead. This function will be removed in
385
- * expo-iap 5.0.0.
386
- *
387
- * @see {@link https://openiap.dev/docs/apis/validate-receipt}
388
- */
389
- export declare const validateReceipt: MutationField<'validateReceipt'>;
390
372
  /**
391
373
  * Verify purchase with the configured providers
392
374
  *
@@ -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":"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"}
package/build/index.js CHANGED
@@ -3,10 +3,9 @@ import { Platform } from 'react-native';
3
3
  // Internal modules
4
4
  import ExpoIapModule, { getNativeModule } from './ExpoIapModule';
5
5
  import { isVegaOS } from './vega';
6
- import { isProductIOS, validateReceiptIOS, deepLinkToSubscriptionsIOS, syncIOS, } from './modules/ios';
7
- import { isProductAndroid, validateReceiptAndroid, deepLinkToSubscriptionsAndroid, } from './modules/android';
6
+ import { isProductIOS, deepLinkToSubscriptionsIOS, syncIOS } from './modules/ios';
7
+ import { isProductAndroid, deepLinkToSubscriptionsAndroid, } from './modules/android';
8
8
  import { ExpoIapConsole } from './utils/debug';
9
- import { warnLegacyOnce } from './utils/deprecation';
10
9
  import { ErrorCode } from './types';
11
10
  import { createPurchaseError, createPurchaseErrorFromNativeException, OPENIAP_ERROR_ENVELOPE_PREFIX, } from './utils/errorMapping';
12
11
  // Export all types
@@ -118,10 +117,7 @@ const configurePurchaseUpdatedListenerOptionsIOS = (dedupeTransactionIOS) => {
118
117
  });
119
118
  };
120
119
  const normalizeProductType = (type) => {
121
- if (type === 'inapp') {
122
- warnLegacyOnce('product-type.inapp', "'inapp' product type is deprecated and will be removed in expo-iap 5.0.0. Use 'in-app' instead.");
123
- }
124
- if (!type || type === 'inapp' || type === 'in-app') {
120
+ if (!type || type === 'in-app') {
125
121
  return {
126
122
  canonical: 'in-app',
127
123
  native: 'in-app',
@@ -141,18 +137,6 @@ const normalizeProductType = (type) => {
141
137
  }
142
138
  throw new Error(`Unsupported product type: ${type}`);
143
139
  };
144
- const normalizePurchasePlatform = (purchase) => {
145
- const platform = purchase.platform;
146
- if (typeof platform !== 'string') {
147
- return purchase;
148
- }
149
- const lowered = platform.toLowerCase();
150
- if (lowered === platform || (lowered !== 'ios' && lowered !== 'android')) {
151
- return purchase;
152
- }
153
- return { ...purchase, platform: lowered };
154
- };
155
- const normalizePurchaseArray = (purchases) => purchases.map((purchase) => normalizePurchasePlatform(purchase));
156
140
  const isAndroidStoreRuntime = () => {
157
141
  return Platform.OS === 'android' || isVegaOS();
158
142
  };
@@ -165,7 +149,7 @@ export const purchaseUpdatedListener = (listener, options) => {
165
149
  };
166
150
  let listenerDedupeGenerationIOS = purchaseUpdatedDedupeGenerationIOS;
167
151
  const wrappedListener = (event) => {
168
- const normalized = normalizePurchasePlatform(event);
152
+ const normalized = event;
169
153
  if (Platform.OS === 'ios') {
170
154
  if (listenerDedupeGenerationIOS !== purchaseUpdatedDedupeGenerationIOS) {
171
155
  clearPurchaseUpdatedDedupeHistoryIOS(listenerDedupeHistoryIOS);
@@ -364,10 +348,8 @@ export const developerProvidedBillingListenerAndroid = (listener) => {
364
348
  * ```
365
349
  */
366
350
  export const subscriptionBillingIssueListener = (listener) => {
367
- // Mirror purchaseUpdatedListener's platform normalization so consumers get
368
- // a consistent payload regardless of native casing.
369
351
  const wrappedListener = (event) => {
370
- listener(normalizePurchasePlatform(event));
352
+ listener(event);
371
353
  };
372
354
  return emitter.addListener(OpenIapEvent.SubscriptionBillingIssue, wrappedListener);
373
355
  };
@@ -549,7 +531,7 @@ export const getAvailablePurchases = async (options) => {
549
531
  };
550
532
  if (isVegaOS()) {
551
533
  const purchases = await ExpoIapModule.getAvailableItems(normalizedOptions);
552
- return normalizePurchaseArray(purchases);
534
+ return purchases;
553
535
  }
554
536
  let purchases;
555
537
  if (Platform.OS === 'ios') {
@@ -561,7 +543,7 @@ export const getAvailablePurchases = async (options) => {
561
543
  else {
562
544
  throw unsupportedPlatformError();
563
545
  }
564
- return normalizePurchaseArray(purchases);
546
+ return purchases;
565
547
  };
566
548
  /**
567
549
  * Get all active subscriptions with detailed information.
@@ -665,23 +647,9 @@ export const getStorefront = async () => {
665
647
  };
666
648
  function normalizeRequestProps(request, platform) {
667
649
  if (platform === 'ios') {
668
- if (Object.prototype.hasOwnProperty.call(request, 'apple')) {
669
- return request.apple;
670
- }
671
- if (Object.prototype.hasOwnProperty.call(request, 'ios')) {
672
- warnLegacyOnce('request-purchase.ios', '`request.ios` is deprecated and will be removed in expo-iap 5.0.0. Use `request.apple` instead.');
673
- return request.ios;
674
- }
675
- return undefined;
650
+ return request.apple;
676
651
  }
677
- if (Object.prototype.hasOwnProperty.call(request, 'google')) {
678
- return request.google;
679
- }
680
- if (Object.prototype.hasOwnProperty.call(request, 'android')) {
681
- warnLegacyOnce('request-purchase.android', '`request.android` is deprecated and will be removed in expo-iap 5.0.0. Use `request.google` instead.');
682
- return request.android;
683
- }
684
- return undefined;
652
+ return request.google;
685
653
  }
686
654
  /**
687
655
  * Initiate a purchase or subscription flow. The result is delivered through
@@ -733,7 +701,6 @@ export const requestPurchase = async (args) => {
733
701
  const payload = {
734
702
  type: canonical === 'in-app' ? 'in-app' : 'subs',
735
703
  request: { apple: normalizedRequest },
736
- useAlternativeBilling: args.useAlternativeBilling,
737
704
  };
738
705
  const purchase = (await invokeNativeWithPurchaseError(() => ExpoIapModule.requestPurchase(payload), 'ios', {
739
706
  code: ErrorCode.PurchaseError,
@@ -743,10 +710,10 @@ export const requestPurchase = async (args) => {
743
710
  productType: canonical,
744
711
  }));
745
712
  if (Array.isArray(purchase)) {
746
- return normalizePurchaseArray(purchase);
713
+ return purchase;
747
714
  }
748
715
  if (purchase) {
749
- return normalizePurchasePlatform(purchase);
716
+ return purchase;
750
717
  }
751
718
  return canonical === 'subs' ? [] : null;
752
719
  }
@@ -770,7 +737,6 @@ export const requestPurchase = async (args) => {
770
737
  type: native,
771
738
  skus,
772
739
  purchaseToken: undefined,
773
- replacementMode: -1,
774
740
  obfuscatedAccountId: obfuscatedAccountId,
775
741
  obfuscatedProfileId: obfuscatedProfileId,
776
742
  offerToken: offerToken,
@@ -783,7 +749,7 @@ export const requestPurchase = async (args) => {
783
749
  productIds: skus,
784
750
  productType: canonical,
785
751
  }));
786
- return normalizePurchaseArray(result);
752
+ return result;
787
753
  }
788
754
  if (canonical === 'subs') {
789
755
  const normalizedRequest = normalizeRequestProps(request, 'android');
@@ -799,16 +765,14 @@ export const requestPurchase = async (args) => {
799
765
  ' })\n\n' +
800
766
  'See: https://openiap.dev/docs/apis/request-purchase');
801
767
  }
802
- const { skus, obfuscatedAccountId, obfuscatedProfileId, isOfferPersonalized, subscriptionOffers, replacementMode: replacementModeInput, purchaseToken: purchaseTokenInput, originalExternalTransactionId, developerBillingOption, subscriptionProductReplacementParams, } = normalizedRequest;
768
+ const { skus, obfuscatedAccountId, obfuscatedProfileId, isOfferPersonalized, subscriptionOffers, purchaseToken: purchaseTokenInput, originalExternalTransactionId, developerBillingOption, subscriptionProductReplacementParams, } = normalizedRequest;
803
769
  const normalizedOffers = subscriptionOffers ?? [];
804
- const replacementMode = replacementModeInput ?? -1;
805
770
  const purchaseToken = purchaseTokenInput ?? undefined;
806
771
  const result = (await invokeNativeWithPurchaseError(() => ExpoIapModule.requestPurchase({
807
772
  type: native,
808
773
  skus,
809
774
  purchaseToken,
810
775
  originalExternalTransactionId: originalExternalTransactionId ?? undefined,
811
- replacementMode,
812
776
  obfuscatedAccountId: obfuscatedAccountId,
813
777
  obfuscatedProfileId: obfuscatedProfileId,
814
778
  subscriptionOffers: normalizedOffers,
@@ -822,7 +786,7 @@ export const requestPurchase = async (args) => {
822
786
  productIds: skus,
823
787
  productType: canonical,
824
788
  }));
825
- return normalizePurchaseArray(result);
789
+ return result;
826
790
  }
827
791
  throw new Error("Invalid request for Android: Expected a valid request object with 'skus' array.");
828
792
  }
@@ -934,45 +898,6 @@ export const deepLinkToSubscriptions = async (options) => {
934
898
  }
935
899
  throw unsupportedPlatformError();
936
900
  };
937
- /**
938
- * Internal receipt validation function (NOT RECOMMENDED for production use)
939
- *
940
- * WARNING: This function performs client-side validation which is NOT secure.
941
- * For production apps, always validate receipts on your secure server:
942
- * - iOS: Send receipt data to Apple's verification endpoint from your server
943
- * - Android: Use Google Play Developer API with service account credentials
944
- *
945
- * @deprecated Use verifyPurchase instead. This function will be removed in
946
- * expo-iap 5.0.0.
947
- *
948
- * @see {@link https://openiap.dev/docs/apis/validate-receipt}
949
- */
950
- export const validateReceipt = async (options) => {
951
- const { apple, google } = options;
952
- if (Platform.OS === 'ios') {
953
- if (!apple?.sku) {
954
- throw new Error('iOS validation requires apple.sku');
955
- }
956
- return validateReceiptIOS({ apple: { sku: apple.sku } });
957
- }
958
- if (Platform.OS === 'android') {
959
- if (!google ||
960
- !google.sku ||
961
- !google.packageName ||
962
- !google.purchaseToken ||
963
- !google.accessToken) {
964
- throw new Error('Android validation requires google.sku, google.packageName, google.purchaseToken, and google.accessToken');
965
- }
966
- return validateReceiptAndroid({
967
- packageName: google.packageName,
968
- productId: google.sku,
969
- productToken: google.purchaseToken,
970
- accessToken: google.accessToken,
971
- isSub: google.isSub ?? undefined,
972
- });
973
- }
974
- throw unsupportedPlatformError();
975
- };
976
901
  /**
977
902
  * Verify purchase with the configured providers
978
903
  *