@umituz/react-native-subscription 2.17.4 → 2.17.6
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.17.
|
|
3
|
+
"version": "2.17.6",
|
|
4
4
|
"description": "Complete subscription management with RevenueCat, paywall UI, and credits system for React Native apps",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -92,33 +92,10 @@ export function useCompletePendingPurchase({
|
|
|
92
92
|
}
|
|
93
93
|
}, [userId, purchasePackage, clearPendingPurchase, closePaywall, onPurchaseSuccess, onPurchaseError]);
|
|
94
94
|
|
|
95
|
-
//
|
|
95
|
+
// Track auth state for reference (no auto-trigger - caller must explicitly call completePendingPurchase)
|
|
96
96
|
useEffect(() => {
|
|
97
|
-
const wasAnonymous = wasAnonymousRef.current;
|
|
98
|
-
const isNowAuthenticated = userId && !isAnonymous;
|
|
99
97
|
wasAnonymousRef.current = isAnonymous;
|
|
100
|
-
|
|
101
|
-
if (__DEV__) {
|
|
102
|
-
console.log("[CompletePendingPurchase] Auth state check:", {
|
|
103
|
-
wasAnonymous,
|
|
104
|
-
isNowAuthenticated,
|
|
105
|
-
hasPending: pendingPurchaseControl.hasPending(),
|
|
106
|
-
pendingId: pendingPurchaseControl.get().package?.product.identifier,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Only trigger if user just authenticated AND there's a pending purchase
|
|
111
|
-
if (wasAnonymous && isNowAuthenticated && pendingPurchaseControl.hasPending()) {
|
|
112
|
-
if (__DEV__) {
|
|
113
|
-
console.log("[CompletePendingPurchase] Auth completed, auto-completing purchase");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Execute in next microtask to ensure React state updates are flushed
|
|
117
|
-
queueMicrotask(() => {
|
|
118
|
-
completePendingPurchase();
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
}, [userId, isAnonymous, completePendingPurchase]);
|
|
98
|
+
}, [isAnonymous]);
|
|
122
99
|
|
|
123
100
|
return {
|
|
124
101
|
completePendingPurchase,
|
|
@@ -10,11 +10,39 @@ import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionM
|
|
|
10
10
|
import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
|
|
11
11
|
import { creditsQueryKeys } from "../../../presentation/hooks/useCredits";
|
|
12
12
|
|
|
13
|
+
declare const __DEV__: boolean;
|
|
14
|
+
|
|
13
15
|
export interface PurchaseResult {
|
|
14
16
|
success: boolean;
|
|
15
17
|
productId: string;
|
|
16
18
|
}
|
|
17
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Global purchase lock to prevent double purchases
|
|
22
|
+
*/
|
|
23
|
+
let purchaseInProgress = false;
|
|
24
|
+
let purchaseProductId: string | null = null;
|
|
25
|
+
|
|
26
|
+
export const purchaseLock = {
|
|
27
|
+
isLocked: () => purchaseInProgress,
|
|
28
|
+
getProductId: () => purchaseProductId,
|
|
29
|
+
acquire: (productId: string): boolean => {
|
|
30
|
+
if (purchaseInProgress) {
|
|
31
|
+
if (__DEV__) {
|
|
32
|
+
console.log('[PurchaseLock] Already in progress:', purchaseProductId);
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
purchaseInProgress = true;
|
|
37
|
+
purchaseProductId = productId;
|
|
38
|
+
return true;
|
|
39
|
+
},
|
|
40
|
+
release: () => {
|
|
41
|
+
purchaseInProgress = false;
|
|
42
|
+
purchaseProductId = null;
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
18
46
|
/**
|
|
19
47
|
* Purchase a subscription package
|
|
20
48
|
* Credits are initialized by CustomerInfoListener when entitlement becomes active
|
|
@@ -30,6 +58,14 @@ export const usePurchasePackage = (userId: string | undefined) => {
|
|
|
30
58
|
|
|
31
59
|
const productId = pkg.product.identifier;
|
|
32
60
|
|
|
61
|
+
// Check and acquire purchase lock
|
|
62
|
+
if (!purchaseLock.acquire(productId)) {
|
|
63
|
+
if (__DEV__) {
|
|
64
|
+
console.log('[DEBUG usePurchasePackage] Skipping - purchase already in progress');
|
|
65
|
+
}
|
|
66
|
+
return { success: false, productId };
|
|
67
|
+
}
|
|
68
|
+
|
|
33
69
|
if (__DEV__) {
|
|
34
70
|
console.log('[DEBUG usePurchasePackage] Starting purchase:', {
|
|
35
71
|
packageId: pkg.identifier,
|
|
@@ -38,27 +74,31 @@ export const usePurchasePackage = (userId: string | undefined) => {
|
|
|
38
74
|
});
|
|
39
75
|
}
|
|
40
76
|
|
|
41
|
-
|
|
77
|
+
try {
|
|
78
|
+
const success = await SubscriptionManager.purchasePackage(pkg);
|
|
42
79
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
80
|
+
if (success) {
|
|
81
|
+
if (__DEV__) {
|
|
82
|
+
console.log('[DEBUG usePurchasePackage] Purchase successful:', {
|
|
83
|
+
packageId: pkg.identifier,
|
|
84
|
+
productId,
|
|
85
|
+
userId,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// Credits will be initialized by CustomerInfoListener
|
|
89
|
+
} else {
|
|
90
|
+
if (__DEV__) {
|
|
91
|
+
console.log('[DEBUG usePurchasePackage] Purchase failed:', {
|
|
92
|
+
packageId: pkg.identifier,
|
|
93
|
+
userId,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
50
96
|
}
|
|
51
|
-
// Credits will be initialized by CustomerInfoListener
|
|
52
|
-
} else {
|
|
53
|
-
if (__DEV__) {
|
|
54
|
-
console.log('[DEBUG usePurchasePackage] Purchase failed:', {
|
|
55
|
-
packageId: pkg.identifier,
|
|
56
|
-
userId,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
97
|
|
|
61
|
-
|
|
98
|
+
return { success, productId };
|
|
99
|
+
} finally {
|
|
100
|
+
purchaseLock.release();
|
|
101
|
+
}
|
|
62
102
|
},
|
|
63
103
|
onSuccess: (result) => {
|
|
64
104
|
if (result.success) {
|