react-native-iap 14.0.1 → 14.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.
- package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +81 -22
- package/ios/HybridRnIap.swift +151 -11
- package/ios/ProductStore.swift +10 -0
- package/lib/module/helpers/subscription.js +9 -1
- package/lib/module/helpers/subscription.js.map +1 -1
- package/lib/module/hooks/useIAP.js +9 -13
- package/lib/module/hooks/useIAP.js.map +1 -1
- package/lib/module/index.js +43 -28
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +24 -16
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/type-bridge.js +64 -13
- package/lib/module/utils/type-bridge.js.map +1 -1
- package/lib/typescript/src/helpers/subscription.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +12 -22
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts +15 -11
- package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +58 -58
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
- package/nitro.json +5 -1
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +13 -4
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroProduct.hpp +40 -36
- package/nitrogen/generated/android/c++/JNitroPurchase.hpp +12 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/HybridRnIapSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroProduct.kt +12 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroPurchase.kt +9 -0
- package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +1 -1
- package/nitrogen/generated/ios/swift/HybridRnIapSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridRnIapSpec_cxx.swift +13 -7
- package/nitrogen/generated/ios/swift/NitroProduct.swift +73 -43
- package/nitrogen/generated/ios/swift/NitroPurchase.swift +35 -2
- package/nitrogen/generated/shared/c++/HybridRnIapSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/NitroProduct.hpp +41 -37
- package/nitrogen/generated/shared/c++/NitroPurchase.hpp +13 -1
- package/package.json +9 -2
- package/src/helpers/subscription.ts +13 -2
- package/src/hooks/useIAP.ts +8 -21
- package/src/index.ts +58 -38
- package/src/specs/RnIap.nitro.ts +15 -11
- package/src/types.ts +66 -62
- package/src/utils/type-bridge.ts +80 -16
package/src/types.ts
CHANGED
|
@@ -16,7 +16,13 @@ export type ChangeEventPayload = {
|
|
|
16
16
|
value: string
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// iOS detailed product types (4 types)
|
|
20
|
+
export enum ProductTypeIOS {
|
|
21
|
+
consumable = 'consumable',
|
|
22
|
+
nonConsumable = 'nonConsumable',
|
|
23
|
+
autoRenewableSubscription = 'autoRenewableSubscription',
|
|
24
|
+
nonRenewingSubscription = 'nonRenewingSubscription',
|
|
25
|
+
}
|
|
20
26
|
|
|
21
27
|
// ============================================================================
|
|
22
28
|
// COMMON TYPES (Base types shared across all platforms)
|
|
@@ -32,8 +38,8 @@ export type ProductCommon = {
|
|
|
32
38
|
title: string
|
|
33
39
|
/** Product description */
|
|
34
40
|
description: string
|
|
35
|
-
/** Product type: 'inapp'
|
|
36
|
-
type:
|
|
41
|
+
/** Product type: 'inapp' or 'subs' for Android compatibility */
|
|
42
|
+
type: 'inapp' | 'subs' // Note: this is the actual product type, not for filtering
|
|
37
43
|
/** Display name for the product */
|
|
38
44
|
displayName?: string
|
|
39
45
|
/** Formatted price string for display (e.g., "$9.99") */
|
|
@@ -69,6 +75,21 @@ export type PurchaseCommon = {
|
|
|
69
75
|
purchaseToken?: string
|
|
70
76
|
/** Platform identifier ('ios' or 'android') */
|
|
71
77
|
platform?: string
|
|
78
|
+
/** Purchase quantity (defaults to 1) */
|
|
79
|
+
quantity: number
|
|
80
|
+
/** Purchase state (common field) */
|
|
81
|
+
purchaseState: PurchaseState
|
|
82
|
+
/** Auto-renewable subscription flag (common field) */
|
|
83
|
+
isAutoRenewing: boolean
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export enum PurchaseState {
|
|
87
|
+
pending = 'pending',
|
|
88
|
+
purchased = 'purchased',
|
|
89
|
+
failed = 'failed',
|
|
90
|
+
restored = 'restored', // iOS only
|
|
91
|
+
deferred = 'deferred', // iOS only
|
|
92
|
+
unknown = 'unknown',
|
|
72
93
|
}
|
|
73
94
|
|
|
74
95
|
export type ProductSubscriptionCommon = ProductCommon & {
|
|
@@ -128,6 +149,7 @@ export type ProductIOS = ProductCommon & {
|
|
|
128
149
|
jsonRepresentationIOS: string
|
|
129
150
|
platform: 'ios'
|
|
130
151
|
subscriptionInfoIOS?: SubscriptionInfo
|
|
152
|
+
typeIOS: ProductTypeIOS // Detailed iOS product type
|
|
131
153
|
// deprecated fields
|
|
132
154
|
displayName?: string
|
|
133
155
|
isFamilyShareable?: boolean
|
|
@@ -245,12 +267,6 @@ export type ProductSubscriptionAndroid = ProductAndroid & {
|
|
|
245
267
|
subscriptionOfferDetails?: ProductSubscriptionAndroidOfferDetails[]
|
|
246
268
|
}
|
|
247
269
|
|
|
248
|
-
export enum PurchaseAndroidState {
|
|
249
|
-
UNSPECIFIED_STATE = 0,
|
|
250
|
-
PURCHASED = 1,
|
|
251
|
-
PENDING = 2,
|
|
252
|
-
}
|
|
253
|
-
|
|
254
270
|
export type PurchaseAndroid = PurchaseCommon & {
|
|
255
271
|
platform: 'android'
|
|
256
272
|
/**
|
|
@@ -259,8 +275,8 @@ export type PurchaseAndroid = PurchaseCommon & {
|
|
|
259
275
|
purchaseTokenAndroid?: string
|
|
260
276
|
dataAndroid?: string
|
|
261
277
|
signatureAndroid?: string
|
|
278
|
+
/** @deprecated Use the common `isAutoRenewing` field instead */
|
|
262
279
|
autoRenewingAndroid?: boolean
|
|
263
|
-
purchaseStateAndroid?: PurchaseAndroidState
|
|
264
280
|
isAcknowledgedAndroid?: boolean
|
|
265
281
|
packageNameAndroid?: string
|
|
266
282
|
developerPayloadAndroid?: string
|
|
@@ -322,13 +338,21 @@ export type Purchase =
|
|
|
322
338
|
// REQUEST TYPES
|
|
323
339
|
// ============================================================================
|
|
324
340
|
|
|
341
|
+
// Product request parameters for fetching products from the store
|
|
342
|
+
export interface ProductRequest {
|
|
343
|
+
/** Product SKUs to fetch */
|
|
344
|
+
skus: string[]
|
|
345
|
+
/** Filter type: "inapp" (default), "subs", or "all" */
|
|
346
|
+
type?: 'inapp' | 'subs' | 'all'
|
|
347
|
+
}
|
|
348
|
+
|
|
325
349
|
// iOS-specific purchase request parameters
|
|
326
350
|
export interface RequestPurchaseIosProps {
|
|
327
351
|
readonly sku: string
|
|
328
352
|
readonly andDangerouslyFinishTransactionAutomatically?: boolean
|
|
329
353
|
readonly appAccountToken?: string
|
|
330
354
|
readonly quantity?: number
|
|
331
|
-
readonly withOffer?:
|
|
355
|
+
readonly withOffer?: DiscountOffer
|
|
332
356
|
}
|
|
333
357
|
|
|
334
358
|
// Android-specific purchase request parameters
|
|
@@ -418,7 +442,7 @@ export type PurchaseResult = {
|
|
|
418
442
|
}
|
|
419
443
|
|
|
420
444
|
// Additional iOS types
|
|
421
|
-
export type
|
|
445
|
+
export type DiscountOffer = {
|
|
422
446
|
identifier: string
|
|
423
447
|
keyIdentifier: string
|
|
424
448
|
nonce: string
|
|
@@ -447,22 +471,12 @@ export type AppTransactionIOS = {
|
|
|
447
471
|
// ============================================================================
|
|
448
472
|
|
|
449
473
|
/**
|
|
450
|
-
* Options for getAvailablePurchases methods
|
|
474
|
+
* Options for getAvailablePurchases and getPurchaseHistories methods
|
|
451
475
|
*/
|
|
452
476
|
export interface PurchaseOptions {
|
|
453
|
-
/**
|
|
454
|
-
* @deprecated Use alsoPublishToEventListenerIOS instead
|
|
455
|
-
* Whether to also publish purchases to event listener (iOS only)
|
|
456
|
-
*/
|
|
457
|
-
alsoPublishToEventListener?: boolean
|
|
458
|
-
/**
|
|
459
|
-
* @deprecated Use onlyIncludeActiveItemsIOS instead
|
|
460
|
-
* Whether to only include active items (iOS only)
|
|
461
|
-
*/
|
|
462
|
-
onlyIncludeActiveItems?: boolean
|
|
463
|
-
/** Whether to also publish purchases to event listener (iOS only) */
|
|
477
|
+
/** Whether to also publish purchases to event listener */
|
|
464
478
|
alsoPublishToEventListenerIOS?: boolean
|
|
465
|
-
/** Whether to only include active items (subscriptions that are still active)
|
|
479
|
+
/** Whether to only include active items (subscriptions that are still active) */
|
|
466
480
|
onlyIncludeActiveItemsIOS?: boolean
|
|
467
481
|
}
|
|
468
482
|
|
|
@@ -513,7 +527,7 @@ export interface IapContext {
|
|
|
513
527
|
/** Initialize connection to the store */
|
|
514
528
|
initConnection(): Promise<boolean>
|
|
515
529
|
/** End connection to the store */
|
|
516
|
-
endConnection(): Promise<
|
|
530
|
+
endConnection(): Promise<boolean>
|
|
517
531
|
/** Sync purchases (iOS only) */
|
|
518
532
|
sync(): Promise<void>
|
|
519
533
|
|
|
@@ -521,11 +535,11 @@ export interface IapContext {
|
|
|
521
535
|
/**
|
|
522
536
|
* Fetch products from the store
|
|
523
537
|
* @param params.skus - Array of product SKUs to fetch
|
|
524
|
-
* @param params.type - Type of products: 'inapp' for regular products
|
|
538
|
+
* @param params.type - Type of products: 'inapp' for regular products, 'subs' for subscriptions, 'all' to fetch both. Defaults to 'inapp'
|
|
525
539
|
*/
|
|
526
540
|
fetchProducts(params: {
|
|
527
541
|
skus: string[]
|
|
528
|
-
type?:
|
|
542
|
+
type?: 'inapp' | 'subs' | 'all' // Defaults to 'inapp'
|
|
529
543
|
}): Promise<Product[] | SubscriptionProduct[]>
|
|
530
544
|
|
|
531
545
|
// Purchase methods
|
|
@@ -561,7 +575,13 @@ export interface IapContext {
|
|
|
561
575
|
// Receipt validation
|
|
562
576
|
/** Validate a receipt (server-side validation recommended) */
|
|
563
577
|
validateReceipt(
|
|
564
|
-
|
|
578
|
+
sku: string,
|
|
579
|
+
androidOptions?: {
|
|
580
|
+
packageName: string
|
|
581
|
+
productToken: string
|
|
582
|
+
accessToken: string
|
|
583
|
+
isSub?: boolean
|
|
584
|
+
}
|
|
565
585
|
): Promise<ReceiptValidationResult>
|
|
566
586
|
}
|
|
567
587
|
|
|
@@ -580,7 +600,7 @@ export interface PurchaseError {
|
|
|
580
600
|
/**
|
|
581
601
|
* Validation options for receipt validation
|
|
582
602
|
*/
|
|
583
|
-
export interface
|
|
603
|
+
export interface ReceiptValidationProps {
|
|
584
604
|
/** Product SKU to validate */
|
|
585
605
|
sku: string
|
|
586
606
|
/** Android-specific validation options */
|
|
@@ -595,7 +615,7 @@ export interface ValidateReceiptProps {
|
|
|
595
615
|
/**
|
|
596
616
|
* iOS receipt validation result
|
|
597
617
|
*/
|
|
598
|
-
export interface
|
|
618
|
+
export interface ReceiptValidationResultIOS {
|
|
599
619
|
/** Whether the receipt is valid */
|
|
600
620
|
isValid: boolean
|
|
601
621
|
/** Receipt data string */
|
|
@@ -609,35 +629,6 @@ export interface ReceiptIOS {
|
|
|
609
629
|
/**
|
|
610
630
|
* Android receipt validation result
|
|
611
631
|
*/
|
|
612
|
-
export interface ReceiptAndroid {
|
|
613
|
-
/** Whether the receipt is valid */
|
|
614
|
-
isValid: boolean
|
|
615
|
-
/** Receipt data string */
|
|
616
|
-
receiptData: string
|
|
617
|
-
/** JWS representation */
|
|
618
|
-
jwsRepresentation: string
|
|
619
|
-
/** Latest transaction if available */
|
|
620
|
-
latestTransaction?: Purchase
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
/**
|
|
624
|
-
* Receipt validation result from receipt validation
|
|
625
|
-
*/
|
|
626
|
-
export type ReceiptValidationResult = ReceiptAndroid | ReceiptIOS
|
|
627
|
-
|
|
628
|
-
/**
|
|
629
|
-
* New iOS receipt validation result (matches user specification)
|
|
630
|
-
*/
|
|
631
|
-
export interface ReceiptValidationResultIOS {
|
|
632
|
-
isValid: boolean
|
|
633
|
-
receiptData: string
|
|
634
|
-
jwsRepresentation: string
|
|
635
|
-
latestTransaction?: Purchase
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
/**
|
|
639
|
-
* New Android receipt validation result (matches user specification)
|
|
640
|
-
*/
|
|
641
632
|
export interface ReceiptValidationResultAndroid {
|
|
642
633
|
autoRenewing: boolean
|
|
643
634
|
betaProduct: boolean
|
|
@@ -649,7 +640,7 @@ export interface ReceiptValidationResultAndroid {
|
|
|
649
640
|
gracePeriodEndDate: number
|
|
650
641
|
parentProductId: string
|
|
651
642
|
productId: string
|
|
652
|
-
productType:
|
|
643
|
+
productType: 'inapp' | 'subs'
|
|
653
644
|
purchaseDate: number
|
|
654
645
|
quantity: number
|
|
655
646
|
receiptId: string
|
|
@@ -659,6 +650,13 @@ export interface ReceiptValidationResultAndroid {
|
|
|
659
650
|
testTransaction: boolean
|
|
660
651
|
}
|
|
661
652
|
|
|
653
|
+
/**
|
|
654
|
+
* Receipt validation result from receipt validation
|
|
655
|
+
*/
|
|
656
|
+
export type ReceiptValidationResult =
|
|
657
|
+
| ReceiptValidationResultAndroid
|
|
658
|
+
| ReceiptValidationResultIOS
|
|
659
|
+
|
|
662
660
|
/**
|
|
663
661
|
* Represents an active subscription with platform-specific details
|
|
664
662
|
*/
|
|
@@ -667,9 +665,15 @@ export interface ActiveSubscription {
|
|
|
667
665
|
productId: string
|
|
668
666
|
/** Whether the subscription is currently active */
|
|
669
667
|
isActive: boolean
|
|
668
|
+
/** Transaction identifier for backend validation */
|
|
669
|
+
transactionId: string
|
|
670
|
+
/** JWT token (iOS) or purchase token (Android) for backend validation */
|
|
671
|
+
purchaseToken?: string
|
|
672
|
+
/** Transaction timestamp */
|
|
673
|
+
transactionDate: number
|
|
670
674
|
/** iOS: Subscription expiration date */
|
|
671
675
|
expirationDateIOS?: Date
|
|
672
|
-
/**
|
|
676
|
+
/** @deprecated Use the common `isAutoRenewing` field instead */
|
|
673
677
|
autoRenewingAndroid?: boolean
|
|
674
678
|
/** iOS: Environment where the subscription was purchased (Production/Sandbox) */
|
|
675
679
|
environmentIOS?: string
|
package/src/utils/type-bridge.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import type { NitroProduct, NitroPurchase } from '../specs/RnIap.nitro'
|
|
11
11
|
import type { Product, Purchase, SubscriptionProduct } from '../types'
|
|
12
|
+
import { PurchaseState, ProductTypeIOS } from '../types'
|
|
12
13
|
import { Platform } from 'react-native'
|
|
13
14
|
|
|
14
15
|
// ============================================================================
|
|
@@ -39,8 +40,27 @@ export function convertNitroProductToProduct(
|
|
|
39
40
|
if (Platform.OS === 'ios') {
|
|
40
41
|
// Map iOS fields from Nitro to TypeScript types
|
|
41
42
|
const iosProduct = product as any // Temporarily cast to access iOS fields
|
|
42
|
-
iosProduct.isFamilyShareable = nitroProduct.
|
|
43
|
-
iosProduct.jsonRepresentation = nitroProduct.
|
|
43
|
+
iosProduct.isFamilyShareable = (nitroProduct as any).isFamilyShareableIOS
|
|
44
|
+
iosProduct.jsonRepresentation = (nitroProduct as any).jsonRepresentationIOS
|
|
45
|
+
// Detailed iOS product type - directly from the native field
|
|
46
|
+
const typeIOSValue: string | undefined = (nitroProduct as any).typeIOS
|
|
47
|
+
|
|
48
|
+
switch (typeIOSValue) {
|
|
49
|
+
case 'consumable':
|
|
50
|
+
iosProduct.typeIOS = ProductTypeIOS.consumable
|
|
51
|
+
break
|
|
52
|
+
case 'nonConsumable':
|
|
53
|
+
iosProduct.typeIOS = ProductTypeIOS.nonConsumable
|
|
54
|
+
break
|
|
55
|
+
case 'autoRenewableSubscription':
|
|
56
|
+
iosProduct.typeIOS = ProductTypeIOS.autoRenewableSubscription
|
|
57
|
+
break
|
|
58
|
+
case 'nonRenewingSubscription':
|
|
59
|
+
iosProduct.typeIOS = ProductTypeIOS.nonRenewingSubscription
|
|
60
|
+
break
|
|
61
|
+
default:
|
|
62
|
+
iosProduct.typeIOS = undefined
|
|
63
|
+
}
|
|
44
64
|
iosProduct.subscriptionPeriodUnitIOS =
|
|
45
65
|
nitroProduct.subscriptionPeriodUnitIOS
|
|
46
66
|
iosProduct.subscriptionPeriodNumberIOS =
|
|
@@ -57,16 +77,25 @@ export function convertNitroProductToProduct(
|
|
|
57
77
|
} else if (Platform.OS === 'android') {
|
|
58
78
|
// Map Android fields from Nitro to TypeScript types
|
|
59
79
|
const androidProduct = product as any // Temporarily cast to access Android fields
|
|
60
|
-
androidProduct.originalPrice = nitroProduct.
|
|
61
|
-
androidProduct.originalPriceAmountMicros =
|
|
62
|
-
nitroProduct
|
|
63
|
-
|
|
64
|
-
androidProduct.
|
|
65
|
-
nitroProduct
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
androidProduct.originalPrice = (nitroProduct as any).originalPriceAndroid
|
|
81
|
+
androidProduct.originalPriceAmountMicros = (
|
|
82
|
+
nitroProduct as any
|
|
83
|
+
).originalPriceAmountMicrosAndroid
|
|
84
|
+
androidProduct.introductoryPriceValue = (
|
|
85
|
+
nitroProduct as any
|
|
86
|
+
).introductoryPriceValueAndroid
|
|
87
|
+
androidProduct.introductoryPriceCycles = (
|
|
88
|
+
nitroProduct as any
|
|
89
|
+
).introductoryPriceCyclesAndroid
|
|
90
|
+
androidProduct.introductoryPricePeriod = (
|
|
91
|
+
nitroProduct as any
|
|
92
|
+
).introductoryPricePeriodAndroid
|
|
93
|
+
androidProduct.subscriptionPeriod = (
|
|
94
|
+
nitroProduct as any
|
|
95
|
+
).subscriptionPeriodAndroid
|
|
96
|
+
androidProduct.freeTrialPeriod = (
|
|
97
|
+
nitroProduct as any
|
|
98
|
+
).freeTrialPeriodAndroid
|
|
70
99
|
|
|
71
100
|
// Map subscription offer details (parse from JSON string)
|
|
72
101
|
if (nitroProduct.subscriptionOfferDetailsAndroid) {
|
|
@@ -83,8 +112,9 @@ export function convertNitroProductToProduct(
|
|
|
83
112
|
// Create flattened offer fields for easier access in example code
|
|
84
113
|
androidProduct.oneTimePurchaseOfferFormattedPrice =
|
|
85
114
|
nitroProduct.displayPrice
|
|
86
|
-
androidProduct.oneTimePurchaseOfferPriceAmountMicros =
|
|
87
|
-
nitroProduct
|
|
115
|
+
androidProduct.oneTimePurchaseOfferPriceAmountMicros = (
|
|
116
|
+
nitroProduct as any
|
|
117
|
+
).originalPriceAmountMicrosAndroid
|
|
88
118
|
androidProduct.oneTimePurchaseOfferPriceCurrencyCode = nitroProduct.currency
|
|
89
119
|
}
|
|
90
120
|
|
|
@@ -130,6 +160,11 @@ export function convertNitroPurchaseToPurchase(
|
|
|
130
160
|
transactionReceipt: '', // Will be set by native layer
|
|
131
161
|
purchaseToken: nitroPurchase.purchaseToken,
|
|
132
162
|
platform: nitroPurchase.platform as 'ios' | 'android',
|
|
163
|
+
// Common fields from NitroPurchase
|
|
164
|
+
quantity: nitroPurchase.quantity || 1,
|
|
165
|
+
purchaseState:
|
|
166
|
+
(nitroPurchase.purchaseState as PurchaseState) || PurchaseState.unknown,
|
|
167
|
+
isAutoRenewing: nitroPurchase.isAutoRenewing || false,
|
|
133
168
|
}
|
|
134
169
|
|
|
135
170
|
// Add platform-specific fields
|
|
@@ -141,19 +176,42 @@ export function convertNitroPurchaseToPurchase(
|
|
|
141
176
|
iosPurchase.originalTransactionIdentifierIOS =
|
|
142
177
|
nitroPurchase.originalTransactionIdentifierIOS
|
|
143
178
|
iosPurchase.appAccountToken = nitroPurchase.appAccountToken
|
|
179
|
+
// Fill common quantity from iOS-specific quantity when available
|
|
180
|
+
if (typeof nitroPurchase.quantityIOS === 'number') {
|
|
181
|
+
purchase.quantity = nitroPurchase.quantityIOS
|
|
182
|
+
}
|
|
144
183
|
} else if (Platform.OS === 'android') {
|
|
145
184
|
const androidPurchase = purchase as any
|
|
146
185
|
androidPurchase.purchaseTokenAndroid = nitroPurchase.purchaseTokenAndroid
|
|
147
186
|
androidPurchase.dataAndroid = nitroPurchase.dataAndroid
|
|
148
187
|
androidPurchase.signatureAndroid = nitroPurchase.signatureAndroid
|
|
149
|
-
|
|
150
|
-
androidPurchase.
|
|
188
|
+
// Support both old and new field names for backward compatibility
|
|
189
|
+
androidPurchase.autoRenewingAndroid =
|
|
190
|
+
nitroPurchase.autoRenewingAndroid ?? nitroPurchase.isAutoRenewing
|
|
191
|
+
// no longer surface purchaseStateAndroid on TS side
|
|
151
192
|
androidPurchase.isAcknowledgedAndroid = nitroPurchase.isAcknowledgedAndroid
|
|
152
193
|
androidPurchase.packageNameAndroid = nitroPurchase.packageNameAndroid
|
|
153
194
|
androidPurchase.obfuscatedAccountIdAndroid =
|
|
154
195
|
nitroPurchase.obfuscatedAccountIdAndroid
|
|
155
196
|
androidPurchase.obfuscatedProfileIdAndroid =
|
|
156
197
|
nitroPurchase.obfuscatedProfileIdAndroid
|
|
198
|
+
|
|
199
|
+
// Use the common isAutoRenewing field from NitroPurchase
|
|
200
|
+
purchase.isAutoRenewing = nitroPurchase.isAutoRenewing
|
|
201
|
+
|
|
202
|
+
// Map numeric Android purchase state to common PurchaseState
|
|
203
|
+
switch (nitroPurchase.purchaseStateAndroid) {
|
|
204
|
+
case 1:
|
|
205
|
+
purchase.purchaseState = PurchaseState.purchased
|
|
206
|
+
break
|
|
207
|
+
case 2:
|
|
208
|
+
purchase.purchaseState = PurchaseState.pending
|
|
209
|
+
break
|
|
210
|
+
case 0:
|
|
211
|
+
default:
|
|
212
|
+
purchase.purchaseState = PurchaseState.unknown
|
|
213
|
+
break
|
|
214
|
+
}
|
|
157
215
|
}
|
|
158
216
|
|
|
159
217
|
return purchase as Purchase
|
|
@@ -169,6 +227,9 @@ export function convertNitroPurchaseToPurchase(
|
|
|
169
227
|
* Validate that a NitroProduct has all required fields for conversion
|
|
170
228
|
*/
|
|
171
229
|
export function validateNitroProduct(nitroProduct: NitroProduct): boolean {
|
|
230
|
+
if (!nitroProduct || typeof nitroProduct !== 'object') {
|
|
231
|
+
return false
|
|
232
|
+
}
|
|
172
233
|
const required = ['id', 'title', 'description', 'type', 'platform']
|
|
173
234
|
for (const field of required) {
|
|
174
235
|
if (
|
|
@@ -189,6 +250,9 @@ export function validateNitroProduct(nitroProduct: NitroProduct): boolean {
|
|
|
189
250
|
* Validate that a NitroPurchase has all required fields for conversion
|
|
190
251
|
*/
|
|
191
252
|
export function validateNitroPurchase(nitroPurchase: NitroPurchase): boolean {
|
|
253
|
+
if (!nitroPurchase || typeof nitroPurchase !== 'object') {
|
|
254
|
+
return false
|
|
255
|
+
}
|
|
192
256
|
const required = ['id', 'productId', 'transactionDate', 'platform']
|
|
193
257
|
for (const field of required) {
|
|
194
258
|
if (
|