react-native-iap 15.5.2 → 15.5.4

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.
@@ -402,43 +402,32 @@ class HybridRnIap : HybridRnIapSpec() {
402
402
  val skusList = skus.toList()
403
403
 
404
404
  val products: List<ProductCommon> = try {
405
- when (queryType) {
406
- ProductQueryType.All -> {
407
- collectAllQueryProducts(
408
- skusList = skusList,
409
- fetchKind = { kind ->
410
- RnIapLog.payload(
411
- "fetchProducts.native",
412
- mapOf("skus" to skusList, "type" to kind.rawValue)
413
- )
414
- val fetched = openIap.fetchProducts(ProductRequest(skusList, kind)).productsOrEmpty()
415
- RnIapLog.result(
416
- "fetchProducts.native",
417
- fetched.map { mapOf("id" to it.id, "type" to it.type.rawValue) }
418
- )
419
- fetched
420
- },
421
- onFailure = { kind, error ->
422
- RnIapLog.failure("fetchProducts.native[${kind.rawValue}]", error)
423
- },
424
- )
425
- }
426
- else -> {
427
- RnIapLog.payload(
428
- "fetchProducts.native",
429
- mapOf("skus" to skusList, "type" to queryType.rawValue)
430
- )
431
- val fetched = openIap.fetchProducts(ProductRequest(skusList, queryType)).productsOrEmpty()
432
- RnIapLog.result(
433
- "fetchProducts.native",
434
- fetched.map { mapOf("id" to it.id, "type" to it.type.rawValue) }
435
- )
405
+ RnIapLog.payload(
406
+ "fetchProducts.native",
407
+ mapOf("skus" to skusList, "type" to queryType.rawValue)
408
+ )
409
+ // Pass the query type through unchanged: the native module resolves
410
+ // ProductQueryType.All itself, so each sku keeps its real product type
411
+ // instead of being shadowed by a per-type not-found placeholder.
412
+ val fetched = openIap.fetchProducts(ProductRequest(skusList, queryType)).productsOrEmpty()
413
+ RnIapLog.result(
414
+ "fetchProducts.native",
415
+ fetched.map { mapOf("id" to it.id, "type" to it.type.rawValue) }
416
+ )
436
417
 
437
- // Preserve input order for non-All queries
438
- val byId = fetched.associateBy { it.id }
439
- skusList.mapNotNull { byId[it] }
440
- }
418
+ // Match the iOS bridge's result shape: preserve input order,
419
+ // drop duplicate skus, then append any fetched products that
420
+ // were not requested.
421
+ val byId = fetched.associateBy { it.id }
422
+ val seenIds = mutableSetOf<String>()
423
+ val orderedProducts = mutableListOf<ProductCommon>()
424
+ skusList.forEach { sku ->
425
+ byId[sku]?.takeIf { seenIds.add(it.id) }?.let(orderedProducts::add)
426
+ }
427
+ fetched.forEach { product ->
428
+ if (seenIds.add(product.id)) orderedProducts.add(product)
441
429
  }
430
+ orderedProducts
442
431
  } catch (e: OpenIapError) {
443
432
  throw OpenIapException(toErrorJson(e))
444
433
  }
@@ -1509,8 +1498,12 @@ class HybridRnIap : HybridRnIapSpec() {
1509
1498
  },
1510
1499
  isValid = item.isValid,
1511
1500
  productId = item.productId?.let { Variant_NullType_String.Second(it) },
1512
- state = mapIapkitPurchaseState(item.state.name),
1513
- store = mapIapkitStore(item.store.name)
1501
+ // Use rawValue ("pending-acknowledgment"), not the Kotlin
1502
+ // enum constant name ("PendingAcknowledgment") — the
1503
+ // mappers match separator-delimited spellings, so
1504
+ // multi-word states would otherwise degrade to UNKNOWN.
1505
+ state = mapIapkitPurchaseState(item.state.rawValue),
1506
+ store = mapIapkitStore(item.store.rawValue)
1514
1507
  )
1515
1508
  }
1516
1509
 
@@ -1525,7 +1518,7 @@ class HybridRnIap : HybridRnIapSpec() {
1525
1518
  NitroVerifyPurchaseWithProviderResult(
1526
1519
  iapkit = nitroIapkitResult?.let { Variant_NullType_NitroVerifyPurchaseWithIapkitResult.Second(it) },
1527
1520
  errors = nitroErrors?.let { Variant_NullType_Array_NitroVerifyPurchaseWithProviderError_.Second(it) },
1528
- provider = mapPurchaseVerificationProvider(result.provider.name)
1521
+ provider = mapPurchaseVerificationProvider(result.provider.rawValue)
1529
1522
  )
1530
1523
  } catch (e: Exception) {
1531
1524
  RnIapLog.failure("verifyPurchaseWithProvider", e)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-iap",
3
- "version": "15.5.2",
3
+ "version": "15.5.4",
4
4
  "description": "React Native In-App Purchases module for iOS and Android using Nitro",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -1,42 +0,0 @@
1
- package com.margelo.nitro.iap
2
-
3
- import dev.hyo.openiap.ProductCommon
4
- import dev.hyo.openiap.ProductQueryType
5
- import kotlin.coroutines.cancellation.CancellationException
6
- import kotlinx.coroutines.async
7
- import kotlinx.coroutines.coroutineScope
8
-
9
- internal suspend fun collectAllQueryProducts(
10
- skusList: List<String>,
11
- fetchKind: suspend (ProductQueryType) -> List<ProductCommon>,
12
- onFailure: (ProductQueryType, Throwable) -> Unit = { _, _ -> },
13
- ): List<ProductCommon> = coroutineScope {
14
- val byId = linkedMapOf<String, ProductCommon>()
15
- var firstFailure: Throwable? = null
16
-
17
- val queries = listOf(ProductQueryType.InApp, ProductQueryType.Subs).map { kind ->
18
- kind to async {
19
- runCatching {
20
- fetchKind(kind)
21
- }
22
- }
23
- }
24
-
25
- queries.forEach { (kind, query) ->
26
- query.await().onSuccess { fetched ->
27
- fetched.forEach { product ->
28
- byId.putIfAbsent(product.id, product)
29
- }
30
- }.onFailure { error ->
31
- if (error is CancellationException) throw error
32
- onFailure(kind, error)
33
- if (firstFailure == null) firstFailure = error
34
- }
35
- }
36
-
37
- if (byId.isEmpty()) {
38
- firstFailure?.let { throw it }
39
- }
40
-
41
- skusList.mapNotNull { byId[it] }
42
- }