@umituz/react-native-subscription 2.14.47 → 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 -2
- 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/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,251 +4,122 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import Purchases, { LOG_LEVEL } from "react-native-purchases";
|
|
7
|
-
import type { InitializeResult } from
|
|
8
|
-
import type { RevenueCatConfig } from
|
|
9
|
-
import { getErrorMessage } from
|
|
10
|
-
import { resolveApiKey } from
|
|
7
|
+
import type { InitializeResult } from "../../application/ports/IRevenueCatService";
|
|
8
|
+
import type { RevenueCatConfig } from "../../domain/value-objects/RevenueCatConfig";
|
|
9
|
+
import { getErrorMessage } from "../../domain/types/RevenueCatTypes";
|
|
10
|
+
import { resolveApiKey } from "../utils/ApiKeyResolver";
|
|
11
11
|
|
|
12
12
|
export interface InitializerDeps {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
config: RevenueCatConfig;
|
|
14
|
+
isUsingTestStore: () => boolean;
|
|
15
|
+
isInitialized: () => boolean;
|
|
16
|
+
getCurrentUserId: () => string | null;
|
|
17
|
+
setInitialized: (value: boolean) => void;
|
|
18
|
+
setCurrentUserId: (userId: string) => void;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
// Track if Purchases.configure has been called globally
|
|
22
21
|
let isPurchasesConfigured = false;
|
|
23
22
|
let isLogHandlerConfigured = false;
|
|
24
23
|
|
|
25
|
-
/**
|
|
26
|
-
* Configures custom log handler to filter StoreKit 2 internal errors
|
|
27
|
-
* These errors occur on simulator when no prior purchases exist
|
|
28
|
-
*/
|
|
29
24
|
function configureLogHandler(): void {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
Purchases.setLogHandler((logLevel, message) => {
|
|
33
|
-
// Filter out StoreKit 2 AppTransaction errors (normal on simulator)
|
|
34
|
-
const isAppTransactionError =
|
|
35
|
-
message.includes("Purchase was cancelled") ||
|
|
36
|
-
message.includes("AppTransaction") ||
|
|
37
|
-
message.includes("Couldn't find previous transactions");
|
|
38
|
-
|
|
39
|
-
if (isAppTransactionError) {
|
|
40
|
-
// Downgrade to debug level - only show in __DEV__
|
|
41
|
-
if (__DEV__) {
|
|
42
|
-
console.debug("[RevenueCat] (filtered)", message);
|
|
43
|
-
}
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
25
|
+
if (isLogHandlerConfigured) return;
|
|
46
26
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
break;
|
|
53
|
-
case LOG_LEVEL.INFO:
|
|
54
|
-
if (__DEV__) console.info("[RevenueCat]", message);
|
|
55
|
-
break;
|
|
56
|
-
case LOG_LEVEL.WARN:
|
|
57
|
-
if (__DEV__) console.warn("[RevenueCat]", message);
|
|
58
|
-
break;
|
|
59
|
-
case LOG_LEVEL.ERROR:
|
|
60
|
-
console.error("[RevenueCat]", message);
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
});
|
|
27
|
+
Purchases.setLogHandler((logLevel, message) => {
|
|
28
|
+
const isAppTransactionError =
|
|
29
|
+
message.includes("Purchase was cancelled") ||
|
|
30
|
+
message.includes("AppTransaction") ||
|
|
31
|
+
message.includes("Couldn't find previous transactions");
|
|
64
32
|
|
|
65
|
-
|
|
66
|
-
|
|
33
|
+
if (isAppTransactionError) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
67
36
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
console.log('[DEBUG RevenueCatInitializer] initializeSDK called', {
|
|
75
|
-
userId,
|
|
76
|
-
hasApiKey: !!apiKey,
|
|
77
|
-
isAlreadyConfigured: isPurchasesConfigured,
|
|
78
|
-
isInitialized: deps.isInitialized(),
|
|
79
|
-
currentUserId: deps.getCurrentUserId(),
|
|
37
|
+
switch (logLevel) {
|
|
38
|
+
case LOG_LEVEL.ERROR:
|
|
39
|
+
break;
|
|
40
|
+
default:
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
80
43
|
});
|
|
81
|
-
}
|
|
82
44
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
isAlreadyConfigured: isPurchasesConfigured,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Case 1: Already initialized with the same user ID
|
|
89
|
-
if (deps.isInitialized() && deps.getCurrentUserId() === userId) {
|
|
45
|
+
isLogHandlerConfigured = true;
|
|
46
|
+
}
|
|
90
47
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
48
|
+
export async function initializeSDK(
|
|
49
|
+
deps: InitializerDeps,
|
|
50
|
+
userId: string,
|
|
51
|
+
apiKey?: string
|
|
52
|
+
): Promise<InitializeResult> {
|
|
53
|
+
// Case 1: Already initialized with the same user ID
|
|
54
|
+
if (deps.isInitialized() && deps.getCurrentUserId() === userId) {
|
|
55
|
+
try {
|
|
56
|
+
const [customerInfo, offerings] = await Promise.all([
|
|
57
|
+
Purchases.getCustomerInfo(),
|
|
58
|
+
Purchases.getOfferings(),
|
|
59
|
+
]);
|
|
60
|
+
const entitlementId = deps.config.entitlementIdentifier;
|
|
61
|
+
const hasPremium = !!customerInfo.entitlements.active[entitlementId];
|
|
62
|
+
return { success: true, offering: offerings.current, hasPremium };
|
|
63
|
+
} catch {
|
|
64
|
+
return { success: false, offering: null, hasPremium: false };
|
|
105
65
|
}
|
|
106
|
-
);
|
|
107
|
-
return { success: false, offering: null, hasPremium: false };
|
|
108
66
|
}
|
|
109
|
-
}
|
|
110
67
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (__DEV__) {
|
|
135
|
-
console.log('[DEBUG RevenueCatInitializer] Already logged in with same user ID, skipping logIn');
|
|
68
|
+
// Case 2: Already configured but different user or re-initializing
|
|
69
|
+
if (isPurchasesConfigured) {
|
|
70
|
+
try {
|
|
71
|
+
const currentAppUserId = await Purchases.getAppUserID();
|
|
72
|
+
|
|
73
|
+
let customerInfo;
|
|
74
|
+
if (currentAppUserId !== userId) {
|
|
75
|
+
const result = await Purchases.logIn(userId);
|
|
76
|
+
customerInfo = result.customerInfo;
|
|
77
|
+
} else {
|
|
78
|
+
customerInfo = await Purchases.getCustomerInfo();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
deps.setInitialized(true);
|
|
82
|
+
deps.setCurrentUserId(userId);
|
|
83
|
+
|
|
84
|
+
const offerings = await Purchases.getOfferings();
|
|
85
|
+
const entitlementId = deps.config.entitlementIdentifier;
|
|
86
|
+
const hasPremium = !!customerInfo.entitlements.active[entitlementId];
|
|
87
|
+
|
|
88
|
+
return { success: true, offering: offerings.current, hasPremium };
|
|
89
|
+
} catch {
|
|
90
|
+
return { success: false, offering: null, hasPremium: false };
|
|
136
91
|
}
|
|
137
|
-
customerInfo = await Purchases.getCustomerInfo();
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
deps.setInitialized(true);
|
|
141
|
-
deps.setCurrentUserId(userId);
|
|
142
|
-
|
|
143
|
-
const offerings = await Purchases.getOfferings();
|
|
144
|
-
const entitlementId = deps.config.entitlementIdentifier;
|
|
145
|
-
const hasPremium = !!customerInfo.entitlements.active[entitlementId];
|
|
146
|
-
|
|
147
|
-
return { success: true, offering: offerings.current, hasPremium };
|
|
148
|
-
} catch {
|
|
149
|
-
// If logIn fails, we don't necessarily want to re-configure if it's already configured
|
|
150
|
-
// But we can return failure
|
|
151
|
-
return { success: false, offering: null, hasPremium: false };
|
|
152
92
|
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Case 3: First time configuration
|
|
156
|
-
const key = apiKey || resolveApiKey(deps.config);
|
|
157
|
-
if (__DEV__) {
|
|
158
|
-
console.log('[DEBUG RevenueCatInitializer] Resolved API key', {
|
|
159
|
-
hasKey: !!key,
|
|
160
|
-
keyPrefix: key ? key.substring(0, 10) + '...' : 'null',
|
|
161
|
-
isTestStore: deps.isUsingTestStore(),
|
|
162
|
-
configApiKey: deps.config.apiKey ? deps.config.apiKey.substring(0, 10) + '...' : 'null',
|
|
163
|
-
configTestStoreKey: deps.config.testStoreKey ? deps.config.testStoreKey.substring(0, 10) + '...' : 'null',
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
93
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
console.log('[DEBUG RevenueCatInitializer] ERROR: No API key available!');
|
|
170
|
-
}
|
|
171
|
-
const error = new Error("No RevenueCat API key available");
|
|
172
|
-
packageName: "subscription",
|
|
173
|
-
operation: "sdk_init_no_key",
|
|
174
|
-
userId,
|
|
175
|
-
});
|
|
176
|
-
return { success: false, offering: null, hasPremium: false };
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
try {
|
|
180
|
-
// Configure log handler before SDK initialization
|
|
181
|
-
configureLogHandler();
|
|
182
|
-
|
|
183
|
-
if (__DEV__) {
|
|
184
|
-
console.log('[DEBUG RevenueCatInitializer] Calling Purchases.configure', {
|
|
185
|
-
apiKey: key.substring(0, 10) + '...',
|
|
186
|
-
appUserID: userId,
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
await Purchases.configure({
|
|
190
|
-
apiKey: key,
|
|
191
|
-
appUserID: userId,
|
|
192
|
-
});
|
|
193
|
-
isPurchasesConfigured = true;
|
|
194
|
-
deps.setInitialized(true);
|
|
195
|
-
deps.setCurrentUserId(userId);
|
|
94
|
+
// Case 3: First time configuration
|
|
95
|
+
const key = apiKey || resolveApiKey(deps.config);
|
|
196
96
|
|
|
197
|
-
if (
|
|
198
|
-
|
|
97
|
+
if (!key) {
|
|
98
|
+
return { success: false, offering: null, hasPremium: false };
|
|
199
99
|
}
|
|
200
100
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
Purchases.getOfferings(),
|
|
204
|
-
]);
|
|
205
|
-
|
|
206
|
-
const packagesCount = offerings.current?.availablePackages?.length ?? 0;
|
|
207
|
-
|
|
208
|
-
if (__DEV__) {
|
|
209
|
-
console.log('[DEBUG RevenueCatInitializer] Data fetched', {
|
|
210
|
-
hasCurrent: !!offerings.current,
|
|
211
|
-
currentIdentifier: offerings.current?.identifier,
|
|
212
|
-
packagesCount,
|
|
213
|
-
allOfferingsCount: Object.keys(offerings.all).length,
|
|
214
|
-
allOfferingIds: Object.keys(offerings.all),
|
|
215
|
-
packages: offerings.current?.availablePackages?.map(p => ({
|
|
216
|
-
identifier: p.identifier,
|
|
217
|
-
packageType: p.packageType,
|
|
218
|
-
})),
|
|
219
|
-
});
|
|
220
|
-
}
|
|
101
|
+
try {
|
|
102
|
+
configureLogHandler();
|
|
221
103
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
104
|
+
await Purchases.configure({
|
|
105
|
+
apiKey: key,
|
|
106
|
+
appUserID: userId,
|
|
107
|
+
});
|
|
108
|
+
isPurchasesConfigured = true;
|
|
109
|
+
deps.setInitialized(true);
|
|
110
|
+
deps.setCurrentUserId(userId);
|
|
227
111
|
|
|
228
|
-
|
|
229
|
-
|
|
112
|
+
const [customerInfo, offerings] = await Promise.all([
|
|
113
|
+
Purchases.getCustomerInfo(),
|
|
114
|
+
Purchases.getOfferings(),
|
|
115
|
+
]);
|
|
230
116
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const errorMessage = getErrorMessage(error, "RevenueCat init failed");
|
|
117
|
+
const entitlementId = deps.config.entitlementIdentifier;
|
|
118
|
+
const hasPremium = !!customerInfo.entitlements.active[entitlementId];
|
|
234
119
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
error,
|
|
238
|
-
|
|
239
|
-
errorType: error instanceof Error ? error.constructor.name : typeof error,
|
|
240
|
-
});
|
|
120
|
+
return { success: true, offering: offerings.current, hasPremium };
|
|
121
|
+
} catch (error) {
|
|
122
|
+
getErrorMessage(error, "RevenueCat init failed");
|
|
123
|
+
return { success: false, offering: null, hasPremium: false };
|
|
241
124
|
}
|
|
242
|
-
|
|
243
|
-
error instanceof Error ? error : new Error(errorMessage),
|
|
244
|
-
{
|
|
245
|
-
packageName: "subscription",
|
|
246
|
-
operation: "sdk_init",
|
|
247
|
-
userId,
|
|
248
|
-
errorMessage,
|
|
249
|
-
}
|
|
250
|
-
);
|
|
251
|
-
|
|
252
|
-
return { success: false, offering: null, hasPremium: false };
|
|
253
|
-
}
|
|
254
125
|
}
|
|
@@ -4,15 +4,19 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import Purchases from "react-native-purchases";
|
|
7
|
-
import type { PurchasesOffering, PurchasesPackage, CustomerInfo } from "react-native-purchases";
|
|
8
7
|
import type {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
PurchasesOffering,
|
|
9
|
+
PurchasesPackage,
|
|
10
|
+
CustomerInfo,
|
|
11
|
+
} from "react-native-purchases";
|
|
12
|
+
import type {
|
|
13
|
+
IRevenueCatService,
|
|
14
|
+
InitializeResult,
|
|
15
|
+
PurchaseResult,
|
|
16
|
+
RestoreResult,
|
|
17
|
+
} from "../../application/ports/IRevenueCatService";
|
|
18
|
+
import type { RevenueCatConfig } from "../../domain/value-objects/RevenueCatConfig";
|
|
19
|
+
import { resolveApiKey } from "../utils/ApiKeyResolver";
|
|
16
20
|
import { initializeSDK } from "./RevenueCatInitializer";
|
|
17
21
|
import { fetchOfferings } from "./OfferingsFetcher";
|
|
18
22
|
import { handlePurchase } from "./PurchaseHandler";
|
|
@@ -21,146 +25,137 @@ import { CustomerInfoListenerManager } from "./CustomerInfoListenerManager";
|
|
|
21
25
|
import { ServiceStateManager } from "./ServiceStateManager";
|
|
22
26
|
|
|
23
27
|
export class RevenueCatService implements IRevenueCatService {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
getCurrentUserId(): string | null {
|
|
47
|
-
return this.stateManager.getCurrentUserId();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async initialize(userId: string, apiKey?: string): Promise<InitializeResult> {
|
|
51
|
-
if (this.isInitialized() && this.getCurrentUserId() === userId) {
|
|
52
|
-
return { success: true, offering: (await this.fetchOfferings()), hasPremium: false };
|
|
28
|
+
private stateManager: ServiceStateManager;
|
|
29
|
+
private listenerManager: CustomerInfoListenerManager;
|
|
30
|
+
|
|
31
|
+
constructor(config: RevenueCatConfig) {
|
|
32
|
+
this.stateManager = new ServiceStateManager(config);
|
|
33
|
+
this.listenerManager = new CustomerInfoListenerManager(
|
|
34
|
+
config.entitlementIdentifier
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
getRevenueCatKey(): string | null {
|
|
39
|
+
return resolveApiKey(this.stateManager.getConfig());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
isInitialized(): boolean {
|
|
43
|
+
return this.stateManager.isInitialized();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
isUsingTestStore(): boolean {
|
|
47
|
+
return this.stateManager.isUsingTestStore();
|
|
53
48
|
}
|
|
54
49
|
|
|
50
|
+
getCurrentUserId(): string | null {
|
|
51
|
+
return this.stateManager.getCurrentUserId();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async initialize(userId: string, apiKey?: string): Promise<InitializeResult> {
|
|
55
|
+
if (this.isInitialized() && this.getCurrentUserId() === userId) {
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
offering: await this.fetchOfferings(),
|
|
59
|
+
hasPremium: false,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const result = await initializeSDK(
|
|
65
|
+
{
|
|
66
|
+
config: this.stateManager.getConfig(),
|
|
67
|
+
isUsingTestStore: () => this.isUsingTestStore(),
|
|
68
|
+
isInitialized: () => this.isInitialized(),
|
|
69
|
+
getCurrentUserId: () => this.stateManager.getCurrentUserId(),
|
|
70
|
+
setInitialized: (value) => this.stateManager.setInitialized(value),
|
|
71
|
+
setCurrentUserId: (id) => this.stateManager.setCurrentUserId(id),
|
|
72
|
+
},
|
|
73
|
+
userId,
|
|
74
|
+
apiKey
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
if (result.success) {
|
|
78
|
+
this.listenerManager.setUserId(userId);
|
|
79
|
+
this.listenerManager.setupListener(this.stateManager.getConfig());
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return result;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
55
87
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
isUsingTestStore: () => this.isUsingTestStore(),
|
|
61
|
-
isInitialized: () => this.isInitialized(),
|
|
62
|
-
getCurrentUserId: () => this.stateManager.getCurrentUserId(),
|
|
63
|
-
setInitialized: (value) => this.stateManager.setInitialized(value),
|
|
64
|
-
setCurrentUserId: (id) => this.stateManager.setCurrentUserId(id),
|
|
65
|
-
},
|
|
66
|
-
userId,
|
|
67
|
-
apiKey
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
if (result.success) {
|
|
71
|
-
this.listenerManager.setUserId(userId);
|
|
72
|
-
this.listenerManager.setupListener(this.stateManager.getConfig());
|
|
73
|
-
} else {
|
|
74
|
-
userId,
|
|
75
|
-
hasOffering: !!result.offering,
|
|
88
|
+
async fetchOfferings(): Promise<PurchasesOffering | null> {
|
|
89
|
+
return fetchOfferings({
|
|
90
|
+
isInitialized: () => this.isInitialized(),
|
|
91
|
+
isUsingTestStore: () => this.isUsingTestStore(),
|
|
76
92
|
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return result;
|
|
80
|
-
} catch (error) {
|
|
81
|
-
packageName: "subscription",
|
|
82
|
-
operation: "initialize",
|
|
83
|
-
userId,
|
|
84
|
-
});
|
|
85
|
-
throw error;
|
|
86
93
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
{
|
|
102
|
-
config: this.stateManager.getConfig(),
|
|
103
|
-
isInitialized: () => this.isInitialized(),
|
|
104
|
-
isUsingTestStore: () => this.isUsingTestStore(),
|
|
105
|
-
},
|
|
106
|
-
pkg,
|
|
107
|
-
userId
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async restorePurchases(userId: string): Promise<RestoreResult> {
|
|
112
|
-
return handleRestore(
|
|
113
|
-
{
|
|
114
|
-
config: this.stateManager.getConfig(),
|
|
115
|
-
isInitialized: () => this.isInitialized(),
|
|
116
|
-
isUsingTestStore: () => this.isUsingTestStore(),
|
|
117
|
-
},
|
|
118
|
-
userId
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async getCustomerInfo(): Promise<CustomerInfo | null> {
|
|
123
|
-
if (!this.isInitialized()) {
|
|
124
|
-
return null;
|
|
94
|
+
|
|
95
|
+
async purchasePackage(
|
|
96
|
+
pkg: PurchasesPackage,
|
|
97
|
+
userId: string
|
|
98
|
+
): Promise<PurchaseResult> {
|
|
99
|
+
return handlePurchase(
|
|
100
|
+
{
|
|
101
|
+
config: this.stateManager.getConfig(),
|
|
102
|
+
isInitialized: () => this.isInitialized(),
|
|
103
|
+
isUsingTestStore: () => this.isUsingTestStore(),
|
|
104
|
+
},
|
|
105
|
+
pkg,
|
|
106
|
+
userId
|
|
107
|
+
);
|
|
125
108
|
}
|
|
126
|
-
return Purchases.getCustomerInfo();
|
|
127
|
-
}
|
|
128
109
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
110
|
+
async restorePurchases(userId: string): Promise<RestoreResult> {
|
|
111
|
+
return handleRestore(
|
|
112
|
+
{
|
|
113
|
+
config: this.stateManager.getConfig(),
|
|
114
|
+
isInitialized: () => this.isInitialized(),
|
|
115
|
+
isUsingTestStore: () => this.isUsingTestStore(),
|
|
116
|
+
},
|
|
117
|
+
userId
|
|
118
|
+
);
|
|
132
119
|
}
|
|
133
120
|
|
|
134
|
-
|
|
135
|
-
|
|
121
|
+
async getCustomerInfo(): Promise<CustomerInfo | null> {
|
|
122
|
+
if (!this.isInitialized()) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
return Purchases.getCustomerInfo();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async reset(): Promise<void> {
|
|
129
|
+
if (!this.isInitialized()) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
136
132
|
|
|
137
|
-
|
|
133
|
+
this.listenerManager.destroy();
|
|
138
134
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
135
|
+
try {
|
|
136
|
+
await Purchases.logOut();
|
|
137
|
+
this.stateManager.setInitialized(false);
|
|
138
|
+
} catch {
|
|
139
|
+
// Silent error handling
|
|
140
|
+
}
|
|
145
141
|
}
|
|
146
|
-
}
|
|
147
142
|
}
|
|
148
143
|
|
|
149
144
|
let revenueCatServiceInstance: RevenueCatService | null = null;
|
|
150
145
|
|
|
151
146
|
export function initializeRevenueCatService(
|
|
152
|
-
|
|
147
|
+
config: RevenueCatConfig
|
|
153
148
|
): RevenueCatService {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
149
|
+
if (!revenueCatServiceInstance) {
|
|
150
|
+
revenueCatServiceInstance = new RevenueCatService(config);
|
|
151
|
+
}
|
|
152
|
+
return revenueCatServiceInstance;
|
|
158
153
|
}
|
|
159
154
|
|
|
160
155
|
export function getRevenueCatService(): RevenueCatService | null {
|
|
161
|
-
|
|
156
|
+
return revenueCatServiceInstance;
|
|
162
157
|
}
|
|
163
158
|
|
|
164
159
|
export function resetRevenueCatService(): void {
|
|
165
|
-
|
|
160
|
+
revenueCatServiceInstance = null;
|
|
166
161
|
}
|