@umituz/react-native-subscription 2.14.45 → 2.14.48
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 +2 -4
- package/src/domains/paywall/components/PaywallHeader.tsx +1 -0
- package/src/domains/paywall/components/PaywallModal.styles.ts +49 -0
- package/src/domains/paywall/components/PaywallModal.tsx +2 -37
- package/src/domains/wallet/domain/entities/CreditCost.ts +3 -3
- package/src/domains/wallet/infrastructure/repositories/TransactionRepository.ts +11 -20
- package/src/domains/wallet/presentation/components/BalanceCard.tsx +4 -3
- package/src/domains/wallet/presentation/components/TransactionItem.tsx +4 -3
- package/src/domains/wallet/presentation/components/TransactionList.tsx +7 -5
- package/src/domains/wallet/presentation/hooks/useWallet.ts +6 -4
- package/src/domains/wallet/presentation/screens/WalletScreen.tsx +11 -8
- package/src/infrastructure/repositories/CreditsRepository.ts +7 -42
- package/src/infrastructure/services/CreditsInitializer.ts +1 -52
- package/src/infrastructure/services/SubscriptionService.ts +2 -0
- package/src/presentation/components/feedback/PaywallFeedbackModal.tsx +1 -0
- package/src/presentation/components/sections/SubscriptionSection.tsx +4 -3
- package/src/presentation/hooks/useCreditChecker.ts +3 -2
- package/src/presentation/hooks/useCredits.ts +4 -3
- package/src/presentation/hooks/usePremium.ts +4 -3
- package/src/presentation/hooks/useSubscriptionDetails.ts +3 -2
- package/src/presentation/hooks/useSubscriptionSettingsConfig.ts +4 -3
- package/src/presentation/screens/SubscriptionDetailScreen.tsx +3 -2
- package/src/presentation/screens/components/UpgradePrompt.tsx +4 -3
- package/src/revenuecat/infrastructure/services/CustomerInfoListenerManager.ts +60 -158
- package/src/revenuecat/infrastructure/services/OfferingsFetcher.ts +13 -29
- package/src/revenuecat/infrastructure/services/PurchaseHandler.ts +64 -88
- package/src/revenuecat/infrastructure/services/RestoreHandler.ts +32 -48
- package/src/revenuecat/infrastructure/services/RevenueCatInitializer.ts +90 -219
- package/src/revenuecat/infrastructure/services/RevenueCatService.ts +121 -126
- package/src/revenuecat/infrastructure/utils/InitializationCache.ts +25 -29
- package/src/revenuecat/infrastructure/utils/PremiumStatusSyncer.ts +52 -100
- package/src/revenuecat/infrastructure/utils/UserIdProvider.ts +17 -25
- package/src/revenuecat/presentation/hooks/usePaywallFlow.ts +9 -8
|
@@ -4,177 +4,79 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import Purchases, {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
type CustomerInfo,
|
|
8
|
+
type CustomerInfoUpdateListener,
|
|
9
9
|
} from "react-native-purchases";
|
|
10
|
-
import type { RevenueCatConfig } from
|
|
11
|
-
import { syncPremiumStatus } from
|
|
10
|
+
import type { RevenueCatConfig } from "../../domain/value-objects/RevenueCatConfig";
|
|
11
|
+
import { syncPremiumStatus } from "../utils/PremiumStatusSyncer";
|
|
12
12
|
|
|
13
13
|
export class CustomerInfoListenerManager {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
setUserId(userId: string): void {
|
|
23
|
-
this.currentUserId = userId;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
clearUserId(): void {
|
|
27
|
-
this.currentUserId = null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
setupListener(config: RevenueCatConfig): void {
|
|
31
|
-
this.removeListener();
|
|
32
|
-
|
|
33
|
-
if (__DEV__) {
|
|
34
|
-
console.log("[CustomerInfoListener] Setting up listener", {
|
|
35
|
-
userId: this.currentUserId,
|
|
36
|
-
entitlementId: this.entitlementIdentifier,
|
|
37
|
-
});
|
|
14
|
+
private listener: CustomerInfoUpdateListener | null = null;
|
|
15
|
+
private currentUserId: string | null = null;
|
|
16
|
+
private entitlementIdentifier: string;
|
|
17
|
+
|
|
18
|
+
constructor(entitlementIdentifier: string) {
|
|
19
|
+
this.entitlementIdentifier = entitlementIdentifier;
|
|
38
20
|
}
|
|
39
21
|
|
|
40
|
-
|
|
41
|
-
|
|
22
|
+
setUserId(userId: string): void {
|
|
23
|
+
this.currentUserId = userId;
|
|
24
|
+
}
|
|
42
25
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
userId: this.currentUserId,
|
|
47
|
-
hasActiveEntitlements: Object.keys(customerInfo.entitlements.active).length > 0,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
26
|
+
clearUserId(): void {
|
|
27
|
+
this.currentUserId = null;
|
|
28
|
+
}
|
|
50
29
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
console.warn("[CustomerInfoListener] ❌ No userId, skipping");
|
|
54
|
-
}
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const hasPremium =
|
|
59
|
-
!!customerInfo.entitlements.active[this.entitlementIdentifier];
|
|
60
|
-
|
|
61
|
-
if (__DEV__) {
|
|
62
|
-
console.log("[CustomerInfoListener] Customer info updated", {
|
|
63
|
-
userId: this.currentUserId,
|
|
64
|
-
hasPremium,
|
|
65
|
-
entitlementIdentifier: this.entitlementIdentifier,
|
|
66
|
-
activeEntitlements: Object.keys(customerInfo.entitlements.active),
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
userId: this.currentUserId,
|
|
71
|
-
hasPremium,
|
|
72
|
-
entitlementIdentifier: this.entitlementIdentifier,
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// Handle credit renewal for subscription renewals
|
|
76
|
-
if (hasPremium && config.onCreditRenewal) {
|
|
77
|
-
const premiumEntitlement =
|
|
78
|
-
customerInfo.entitlements.active[this.entitlementIdentifier];
|
|
79
|
-
|
|
80
|
-
if (premiumEntitlement && premiumEntitlement.expirationDate) {
|
|
81
|
-
const productId = premiumEntitlement.productIdentifier;
|
|
82
|
-
const renewalId = `renewal_${productId}_${premiumEntitlement.expirationDate}`;
|
|
83
|
-
|
|
84
|
-
if (__DEV__) {
|
|
85
|
-
console.log("[CustomerInfoListener] 💰 Processing credit renewal", {
|
|
86
|
-
userId: this.currentUserId,
|
|
87
|
-
productId,
|
|
88
|
-
renewalId,
|
|
89
|
-
expirationDate: premiumEntitlement.expirationDate,
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
"subscription",
|
|
94
|
-
"Processing credit renewal",
|
|
95
|
-
{
|
|
96
|
-
userId: this.currentUserId,
|
|
97
|
-
productId,
|
|
98
|
-
renewalId,
|
|
99
|
-
}
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
await config.onCreditRenewal(
|
|
104
|
-
this.currentUserId,
|
|
105
|
-
productId,
|
|
106
|
-
renewalId
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
if (__DEV__) {
|
|
110
|
-
console.log("[CustomerInfoListener] ✅ Credit renewal completed", {
|
|
111
|
-
userId: this.currentUserId,
|
|
112
|
-
productId,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
30
|
+
setupListener(config: RevenueCatConfig): void {
|
|
31
|
+
this.removeListener();
|
|
115
32
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
userId: this.currentUserId,
|
|
120
|
-
productId,
|
|
121
|
-
}
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
// Notify app to invalidate credits cache
|
|
125
|
-
if (config.onCreditsUpdated && this.currentUserId) {
|
|
126
|
-
config.onCreditsUpdated(this.currentUserId);
|
|
127
|
-
}
|
|
128
|
-
} catch (error) {
|
|
129
|
-
if (__DEV__) {
|
|
130
|
-
console.error("[CustomerInfoListener] ❌ Credit renewal failed", {
|
|
131
|
-
userId: this.currentUserId,
|
|
132
|
-
productId,
|
|
133
|
-
error: error instanceof Error ? error.message : String(error),
|
|
134
|
-
});
|
|
33
|
+
this.listener = async (customerInfo: CustomerInfo) => {
|
|
34
|
+
if (!this.currentUserId) {
|
|
35
|
+
return;
|
|
135
36
|
}
|
|
136
37
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
38
|
+
const hasPremium =
|
|
39
|
+
!!customerInfo.entitlements.active[this.entitlementIdentifier];
|
|
40
|
+
|
|
41
|
+
if (hasPremium && config.onCreditRenewal) {
|
|
42
|
+
const premiumEntitlement =
|
|
43
|
+
customerInfo.entitlements.active[this.entitlementIdentifier];
|
|
44
|
+
|
|
45
|
+
if (premiumEntitlement && premiumEntitlement.expirationDate) {
|
|
46
|
+
const productId = premiumEntitlement.productIdentifier;
|
|
47
|
+
const renewalId = `renewal_${productId}_${premiumEntitlement.expirationDate}`;
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
await config.onCreditRenewal(
|
|
51
|
+
this.currentUserId,
|
|
52
|
+
productId,
|
|
53
|
+
renewalId
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (config.onCreditsUpdated && this.currentUserId) {
|
|
57
|
+
config.onCreditsUpdated(this.currentUserId);
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
// Silent error handling
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
162
64
|
|
|
163
|
-
|
|
164
|
-
|
|
65
|
+
syncPremiumStatus(config, this.currentUserId, customerInfo);
|
|
66
|
+
};
|
|
165
67
|
|
|
166
|
-
|
|
167
|
-
|
|
68
|
+
Purchases.addCustomerInfoUpdateListener(this.listener);
|
|
69
|
+
}
|
|
168
70
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
71
|
+
removeListener(): void {
|
|
72
|
+
if (this.listener) {
|
|
73
|
+
Purchases.removeCustomerInfoUpdateListener(this.listener);
|
|
74
|
+
this.listener = null;
|
|
75
|
+
}
|
|
173
76
|
}
|
|
174
|
-
}
|
|
175
77
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
78
|
+
destroy(): void {
|
|
79
|
+
this.removeListener();
|
|
80
|
+
this.clearUserId();
|
|
81
|
+
}
|
|
180
82
|
}
|
|
@@ -6,37 +6,21 @@
|
|
|
6
6
|
import Purchases, { type PurchasesOffering } from "react-native-purchases";
|
|
7
7
|
|
|
8
8
|
export interface OfferingsFetcherDeps {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
isInitialized: () => boolean;
|
|
10
|
+
isUsingTestStore: () => boolean;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export async function fetchOfferings(
|
|
14
|
-
|
|
14
|
+
deps: OfferingsFetcherDeps
|
|
15
15
|
): Promise<PurchasesOffering | null> {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const packagesCount = offerings.current?.availablePackages?.length ?? 0;
|
|
27
|
-
|
|
28
|
-
hasCurrent: !!offerings.current,
|
|
29
|
-
packagesCount,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
return offerings.current;
|
|
33
|
-
} catch (error) {
|
|
34
|
-
error instanceof Error ? error : new Error(String(error)),
|
|
35
|
-
{
|
|
36
|
-
packageName: "subscription",
|
|
37
|
-
operation: "fetch_offerings",
|
|
38
|
-
}
|
|
39
|
-
);
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
16
|
+
if (!deps.isInitialized()) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const offerings = await Purchases.getOfferings();
|
|
22
|
+
return offerings.current;
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
42
26
|
}
|
|
@@ -4,112 +4,88 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import Purchases, { type PurchasesPackage } from "react-native-purchases";
|
|
7
|
-
import type { PurchaseResult } from
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
import type { PurchaseResult } from "../../application/ports/IRevenueCatService";
|
|
8
|
+
import {
|
|
9
|
+
RevenueCatPurchaseError,
|
|
10
|
+
RevenueCatInitializationError,
|
|
11
|
+
} from "../../domain/errors/RevenueCatError";
|
|
12
|
+
import type { RevenueCatConfig } from "../../domain/value-objects/RevenueCatConfig";
|
|
13
|
+
import {
|
|
14
|
+
isUserCancelledError,
|
|
15
|
+
getErrorMessage,
|
|
16
|
+
} from "../../domain/types/RevenueCatTypes";
|
|
17
|
+
import {
|
|
18
|
+
syncPremiumStatus,
|
|
19
|
+
notifyPurchaseCompleted,
|
|
20
|
+
} from "../utils/PremiumStatusSyncer";
|
|
18
21
|
|
|
19
22
|
export interface PurchaseHandlerDeps {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
config: RevenueCatConfig;
|
|
24
|
+
isInitialized: () => boolean;
|
|
25
|
+
isUsingTestStore: () => boolean;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
function isConsumableProduct(
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
pkg: PurchasesPackage,
|
|
30
|
+
consumableIds: string[]
|
|
28
31
|
): boolean {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
if (consumableIds.length === 0) return false;
|
|
33
|
+
const identifier = pkg.product.identifier.toLowerCase();
|
|
34
|
+
return consumableIds.some((id) => identifier.includes(id.toLowerCase()));
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
/**
|
|
35
38
|
* Handle package purchase - supports both subscriptions and consumables
|
|
36
39
|
*/
|
|
37
40
|
export async function handlePurchase(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
deps: PurchaseHandlerDeps,
|
|
42
|
+
pkg: PurchasesPackage,
|
|
43
|
+
userId: string
|
|
41
44
|
): Promise<PurchaseResult> {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (!deps.isInitialized()) {
|
|
47
|
-
const error = new RevenueCatInitializationError();
|
|
48
|
-
packageName: "subscription",
|
|
49
|
-
operation: "purchase",
|
|
50
|
-
userId,
|
|
51
|
-
productId: pkg.product.identifier,
|
|
52
|
-
});
|
|
53
|
-
throw error;
|
|
54
|
-
}
|
|
45
|
+
if (!deps.isInitialized()) {
|
|
46
|
+
throw new RevenueCatInitializationError();
|
|
47
|
+
}
|
|
55
48
|
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
const consumableIds = deps.config.consumableProductIdentifiers || [];
|
|
50
|
+
const isConsumable = isConsumableProduct(pkg, consumableIds);
|
|
58
51
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
try {
|
|
53
|
+
const purchaseResult = await Purchases.purchasePackage(pkg);
|
|
54
|
+
const customerInfo = purchaseResult.customerInfo;
|
|
62
55
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
56
|
+
if (isConsumable) {
|
|
57
|
+
return {
|
|
58
|
+
success: true,
|
|
59
|
+
isPremium: false,
|
|
60
|
+
customerInfo,
|
|
61
|
+
isConsumable: true,
|
|
62
|
+
productId: pkg.product.identifier,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
72
65
|
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
const entitlementIdentifier = deps.config.entitlementIdentifier;
|
|
67
|
+
const isPremium = !!customerInfo.entitlements.active[entitlementIdentifier];
|
|
75
68
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
69
|
+
if (isPremium) {
|
|
70
|
+
await syncPremiumStatus(deps.config, userId, customerInfo);
|
|
71
|
+
await notifyPurchaseCompleted(
|
|
72
|
+
deps.config,
|
|
73
|
+
userId,
|
|
74
|
+
pkg.product.identifier,
|
|
75
|
+
customerInfo
|
|
76
|
+
);
|
|
77
|
+
return { success: true, isPremium: true, customerInfo };
|
|
78
|
+
}
|
|
86
79
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
throw entitlementError;
|
|
98
|
-
} catch (error) {
|
|
99
|
-
if (isUserCancelledError(error)) {
|
|
100
|
-
productId: pkg.product.identifier,
|
|
101
|
-
userId,
|
|
102
|
-
});
|
|
103
|
-
return { success: false, isPremium: false };
|
|
80
|
+
throw new RevenueCatPurchaseError(
|
|
81
|
+
"Purchase completed but premium entitlement not active",
|
|
82
|
+
pkg.product.identifier
|
|
83
|
+
);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (isUserCancelledError(error)) {
|
|
86
|
+
return { success: false, isPremium: false };
|
|
87
|
+
}
|
|
88
|
+
const errorMessage = getErrorMessage(error, "Purchase failed");
|
|
89
|
+
throw new RevenueCatPurchaseError(errorMessage, pkg.product.identifier);
|
|
104
90
|
}
|
|
105
|
-
const errorMessage = getErrorMessage(error, "Purchase failed");
|
|
106
|
-
const purchaseError = new RevenueCatPurchaseError(errorMessage, pkg.product.identifier);
|
|
107
|
-
packageName: "subscription",
|
|
108
|
-
operation: "purchase",
|
|
109
|
-
userId,
|
|
110
|
-
productId: pkg.product.identifier,
|
|
111
|
-
originalError: error instanceof Error ? error.message : String(error),
|
|
112
|
-
});
|
|
113
|
-
throw purchaseError;
|
|
114
|
-
}
|
|
115
91
|
}
|
|
@@ -4,65 +4,49 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import Purchases from "react-native-purchases";
|
|
7
|
-
import type { RestoreResult } from
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
import type { RestoreResult } from "../../application/ports/IRevenueCatService";
|
|
8
|
+
import {
|
|
9
|
+
RevenueCatRestoreError,
|
|
10
|
+
RevenueCatInitializationError,
|
|
11
|
+
} from "../../domain/errors/RevenueCatError";
|
|
12
|
+
import type { RevenueCatConfig } from "../../domain/value-objects/RevenueCatConfig";
|
|
13
|
+
import { getErrorMessage } from "../../domain/types/RevenueCatTypes";
|
|
14
|
+
import {
|
|
15
|
+
syncPremiumStatus,
|
|
16
|
+
notifyRestoreCompleted,
|
|
17
|
+
} from "../utils/PremiumStatusSyncer";
|
|
16
18
|
|
|
17
19
|
export interface RestoreHandlerDeps {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
config: RevenueCatConfig;
|
|
21
|
+
isInitialized: () => boolean;
|
|
22
|
+
isUsingTestStore: () => boolean;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* Handle restore purchases
|
|
25
27
|
*/
|
|
26
28
|
export async function handleRestore(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
deps: RestoreHandlerDeps,
|
|
30
|
+
userId: string
|
|
29
31
|
): Promise<RestoreResult> {
|
|
32
|
+
if (!deps.isInitialized()) {
|
|
33
|
+
throw new RevenueCatInitializationError();
|
|
34
|
+
}
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
userId,
|
|
36
|
-
});
|
|
37
|
-
throw error;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const customerInfo = await Purchases.restorePurchases();
|
|
42
|
-
const entitlementIdentifier = deps.config.entitlementIdentifier;
|
|
43
|
-
const isPremium = !!customerInfo.entitlements.active[entitlementIdentifier];
|
|
36
|
+
try {
|
|
37
|
+
const customerInfo = await Purchases.restorePurchases();
|
|
38
|
+
const entitlementIdentifier = deps.config.entitlementIdentifier;
|
|
39
|
+
const isPremium = !!customerInfo.entitlements.active[entitlementIdentifier];
|
|
44
40
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
entitlementId: entitlementIdentifier,
|
|
49
|
-
});
|
|
50
|
-
} else {
|
|
51
|
-
userId,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
41
|
+
if (isPremium) {
|
|
42
|
+
await syncPremiumStatus(deps.config, userId, customerInfo);
|
|
43
|
+
}
|
|
54
44
|
|
|
55
|
-
|
|
45
|
+
await notifyRestoreCompleted(deps.config, userId, isPremium, customerInfo);
|
|
56
46
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
operation: "restore",
|
|
63
|
-
userId,
|
|
64
|
-
originalError: error instanceof Error ? error.message : String(error),
|
|
65
|
-
});
|
|
66
|
-
throw restoreError;
|
|
67
|
-
}
|
|
47
|
+
return { success: isPremium, isPremium, customerInfo };
|
|
48
|
+
} catch (error) {
|
|
49
|
+
const errorMessage = getErrorMessage(error, "Restore failed");
|
|
50
|
+
throw new RevenueCatRestoreError(errorMessage);
|
|
51
|
+
}
|
|
68
52
|
}
|