@umituz/react-native-subscription 2.27.65 → 2.27.67
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 +3 -1
- package/src/domains/credits/application/CreditLimitCalculator.ts +17 -0
- package/src/domains/credits/application/CreditsInitializer.ts +85 -0
- package/src/domains/credits/application/DeductCreditsCommand.ts +52 -0
- package/src/domains/credits/application/PurchaseMetadataGenerator.ts +59 -0
- package/src/domains/credits/application/credit-strategies/CreditAllocationContext.ts +35 -0
- package/src/domains/credits/application/credit-strategies/ICreditStrategy.ts +18 -0
- package/src/domains/credits/application/credit-strategies/StandardPurchaseCreditStrategy.ts +16 -0
- package/src/domains/credits/application/credit-strategies/SyncCreditStrategy.ts +15 -0
- package/src/domains/credits/application/credit-strategies/TrialCreditStrategy.ts +18 -0
- package/src/{infrastructure/mappers → domains/credits/core}/CreditsMapper.ts +4 -4
- package/src/domains/credits/infrastructure/CreditsRepository.ts +102 -0
- package/src/{presentation/hooks → domains/credits/presentation}/useCredits.ts +21 -4
- package/src/domains/subscription/application/SubscriptionAuthListener.ts +26 -0
- package/src/domains/subscription/application/SubscriptionInitializer.ts +77 -0
- package/src/{infrastructure/services → domains/subscription/application}/SubscriptionInitializerTypes.ts +21 -1
- package/src/domains/subscription/application/SubscriptionSyncService.ts +71 -0
- package/src/domains/subscription/application/SubscriptionSyncUtils.ts +16 -0
- package/src/{revenuecat/domain/value-objects → domains/subscription/core}/RevenueCatConfig.ts +1 -1
- package/src/{domain/types → domains/subscription/core}/RevenueCatData.ts +1 -1
- package/src/{domain/entities → domains/subscription/core}/SubscriptionStatus.ts +13 -21
- package/src/domains/subscription/core/SubscriptionStatusHandlers.ts +51 -0
- package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +67 -0
- package/src/domains/subscription/infrastructure/handlers/PurchaseStatusResolver.ts +27 -0
- package/src/domains/subscription/infrastructure/managers/SubscriptionInternalState.ts +12 -0
- package/src/domains/subscription/infrastructure/managers/SubscriptionManager.ts +110 -0
- package/src/{presentation/hooks → domains/subscription/presentation}/usePremium.ts +7 -4
- package/src/domains/trial/application/TrialEligibilityService.ts +25 -0
- package/src/domains/trial/application/TrialService.ts +68 -0
- package/src/{infrastructure/services → domains/trial/core}/TrialTypes.ts +1 -1
- package/src/domains/trial/infrastructure/DeviceTrialRepository.ts +30 -0
- package/src/presentation/components/details/PremiumStatusBadge.tsx +2 -2
- package/src/presentation/hooks/index.ts +11 -11
- package/src/shared/infrastructure/SubscriptionEventBus.ts +51 -0
- package/src/utils/packageTypeDetector.ts +13 -18
- package/src/application/README.md +0 -50
- package/src/domain/entities/README.md +0 -50
- package/src/domain/entities/SubscriptionStatus.test.ts +0 -105
- package/src/domain/errors/README.md +0 -53
- package/src/domain/value-objects/README.md +0 -50
- package/src/infrastructure/README.md +0 -55
- package/src/infrastructure/mappers/README.md +0 -21
- package/src/infrastructure/models/README.md +0 -26
- package/src/infrastructure/repositories/CreditsRepository.ts +0 -132
- package/src/infrastructure/repositories/README.md +0 -99
- package/src/infrastructure/services/CreditsInitializer.ts +0 -170
- package/src/infrastructure/services/README.md +0 -99
- package/src/infrastructure/services/SubscriptionInitializer.ts +0 -176
- package/src/infrastructure/services/SubscriptionService.ts +0 -133
- package/src/infrastructure/services/TrialService.ts +0 -197
- package/src/infrastructure/services/app-service-helpers.ts +0 -111
- package/src/revenuecat/README.md +0 -104
- package/src/revenuecat/application/README.md +0 -43
- package/src/revenuecat/application/ports/IRevenueCatService.ts +0 -76
- package/src/revenuecat/application/ports/README.md +0 -41
- package/src/revenuecat/domain/README.md +0 -48
- package/src/revenuecat/domain/constants/README.md +0 -41
- package/src/revenuecat/domain/entities/README.md +0 -42
- package/src/revenuecat/domain/errors/README.md +0 -53
- package/src/revenuecat/domain/types/README.md +0 -41
- package/src/revenuecat/domain/value-objects/README.md +0 -41
- package/src/revenuecat/index.ts +0 -13
- package/src/revenuecat/infrastructure/handlers/PackageHandler.ts +0 -161
- package/src/revenuecat/infrastructure/managers/SubscriptionManager.ts +0 -165
- package/src/revenuecat/presentation/README.md +0 -42
- /package/src/{domain/entities → domains/credits/core}/Credits.ts +0 -0
- /package/src/{infrastructure/models → domains/credits/core}/UserCreditsDocument.ts +0 -0
- /package/src/{infrastructure/repositories → domains/credits/infrastructure}/CreditsRepositoryProvider.ts +0 -0
- /package/src/{presentation/hooks → domains/credits/presentation}/useDeductCredit.ts +0 -0
- /package/src/{revenuecat/domain/constants → domains/subscription/core}/RevenueCatConstants.ts +0 -0
- /package/src/{revenuecat/domain/errors → domains/subscription/core}/RevenueCatError.ts +0 -0
- /package/src/{revenuecat/domain/types → domains/subscription/core}/RevenueCatTypes.ts +0 -0
- /package/src/{domain/entities → domains/subscription/core}/SubscriptionConstants.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/README.md +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/config/README.md +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/handlers/README.md +0 -0
- /package/src/{revenuecat/presentation → domains/subscription/infrastructure}/hooks/README.md +0 -0
- /package/src/{revenuecat/presentation → domains/subscription/infrastructure}/hooks/subscriptionQueryKeys.ts +0 -0
- /package/src/{revenuecat/presentation → domains/subscription/infrastructure}/hooks/useCustomerInfo.ts +0 -0
- /package/src/{revenuecat/presentation → domains/subscription/infrastructure}/hooks/useInitializeSubscription.ts +0 -0
- /package/src/{revenuecat/presentation → domains/subscription/infrastructure}/hooks/usePaywallFlow.ts +0 -0
- /package/src/{revenuecat/presentation → domains/subscription/infrastructure}/hooks/usePurchasePackage.ts +0 -0
- /package/src/{revenuecat/presentation → domains/subscription/infrastructure}/hooks/useRestorePurchase.ts +0 -0
- /package/src/{revenuecat/presentation → domains/subscription/infrastructure}/hooks/useRevenueCat.ts +0 -0
- /package/src/{revenuecat/presentation → domains/subscription/infrastructure}/hooks/useRevenueCatTrialEligibility.ts +0 -0
- /package/src/{revenuecat/presentation → domains/subscription/infrastructure}/hooks/useSubscriptionPackages.ts +0 -0
- /package/src/{revenuecat/presentation → domains/subscription/infrastructure}/hooks/useSubscriptionQueries.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/managers/README.md +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/services/CustomerInfoListenerManager.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/services/OfferingsFetcher.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/services/PurchaseHandler.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/services/README.md +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/services/RestoreHandler.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/services/RevenueCatInitializer.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/services/RevenueCatService.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/services/ServiceStateManager.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/utils/ApiKeyResolver.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/utils/InitializationCache.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/utils/PremiumStatusSyncer.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/utils/README.md +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/utils/RenewalDetector.ts +0 -0
- /package/src/{revenuecat → domains/subscription}/infrastructure/utils/UserIdProvider.ts +0 -0
- /package/src/{presentation/hooks → domains/subscription/presentation}/useAuthAwarePurchase.ts +0 -0
- /package/src/{presentation/hooks → domains/subscription/presentation}/useAuthSubscriptionSync.ts +0 -0
- /package/src/{presentation/hooks → domains/subscription/presentation}/useFeatureGate.ts +0 -0
- /package/src/{presentation/hooks → domains/subscription/presentation}/usePaywallVisibility.ts +0 -0
- /package/src/{presentation/hooks → domains/subscription/presentation}/usePremiumGate.ts +0 -0
- /package/src/{presentation/hooks → domains/subscription/presentation}/useSavedPurchaseAutoExecution.ts +0 -0
- /package/src/{presentation/hooks → domains/subscription/presentation}/useSubscriptionSettingsConfig.ts +0 -0
- /package/src/{presentation/hooks → domains/subscription/presentation}/useSubscriptionSettingsConfig.utils.ts +0 -0
- /package/src/{presentation/hooks → domains/subscription/presentation}/useSubscriptionStatus.ts +0 -0
- /package/src/{infrastructure/services → shared/application}/ActivationHandler.ts +0 -0
- /package/src/{infrastructure/services → shared/application}/FeedbackService.ts +0 -0
- /package/src/{application → shared/application}/ports/ISubscriptionRepository.ts +0 -0
- /package/src/{application → shared/application}/ports/ISubscriptionService.ts +0 -0
- /package/src/{application → shared/application}/ports/README.md +0 -0
- /package/src/{domain/errors → shared/utils}/InsufficientCreditsError.ts +0 -0
- /package/src/{infrastructure → shared}/utils/Logger.ts +0 -0
- /package/src/{domain/value-objects → shared/utils}/Result.ts +0 -0
- /package/src/{domain/value-objects → shared/utils}/SubscriptionConfig.ts +0 -0
- /package/src/{domain/errors → shared/utils}/SubscriptionError.ts +0 -0
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Trial Service - Device-based trial tracking to prevent abuse
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { doc, getDoc, setDoc, serverTimestamp, arrayUnion } from "firebase/firestore";
|
|
6
|
-
import { getFirestore } from "@umituz/react-native-firebase";
|
|
7
|
-
import { PersistentDeviceIdService } from "@umituz/react-native-design-system";
|
|
8
|
-
import type { TrialEligibilityResult } from "./TrialTypes";
|
|
9
|
-
|
|
10
|
-
export { TRIAL_CONFIG, type DeviceTrialRecord, type TrialEligibilityResult } from "./TrialTypes";
|
|
11
|
-
|
|
12
|
-
const DEVICE_TRIALS_COLLECTION = "device_trials";
|
|
13
|
-
|
|
14
|
-
/** Get persistent device ID */
|
|
15
|
-
export async function getDeviceId(): Promise<string> {
|
|
16
|
-
return PersistentDeviceIdService.getDeviceId();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** Check if device is eligible for trial */
|
|
20
|
-
export async function checkTrialEligibility(deviceId?: string): Promise<TrialEligibilityResult> {
|
|
21
|
-
try {
|
|
22
|
-
const effectiveDeviceId = deviceId || await getDeviceId();
|
|
23
|
-
const db = getFirestore();
|
|
24
|
-
|
|
25
|
-
if (!db) {
|
|
26
|
-
if (__DEV__) {
|
|
27
|
-
console.log("[TrialService] No Firestore instance");
|
|
28
|
-
}
|
|
29
|
-
return { eligible: true, deviceId: effectiveDeviceId };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const trialRef = doc(db, DEVICE_TRIALS_COLLECTION, effectiveDeviceId);
|
|
33
|
-
const trialDoc = await getDoc(trialRef);
|
|
34
|
-
|
|
35
|
-
if (!trialDoc.exists()) {
|
|
36
|
-
if (__DEV__) {
|
|
37
|
-
console.log("[TrialService] No trial record found, eligible");
|
|
38
|
-
}
|
|
39
|
-
return { eligible: true, deviceId: effectiveDeviceId };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const data = trialDoc.data();
|
|
43
|
-
const hasUsedTrial = data?.hasUsedTrial === true;
|
|
44
|
-
const trialInProgress = data?.trialInProgress === true;
|
|
45
|
-
|
|
46
|
-
if (__DEV__) {
|
|
47
|
-
console.log("[TrialService] Trial record found:", {
|
|
48
|
-
deviceId: effectiveDeviceId.slice(0, 8),
|
|
49
|
-
hasUsedTrial,
|
|
50
|
-
trialInProgress,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Not eligible if trial was already used (converted or ended)
|
|
55
|
-
// OR if trial is currently in progress
|
|
56
|
-
if (hasUsedTrial || trialInProgress) {
|
|
57
|
-
return {
|
|
58
|
-
eligible: false,
|
|
59
|
-
reason: "already_used",
|
|
60
|
-
deviceId: effectiveDeviceId,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return { eligible: true, deviceId: effectiveDeviceId };
|
|
65
|
-
} catch (error) {
|
|
66
|
-
if (__DEV__) {
|
|
67
|
-
console.error("[TrialService] Eligibility check error:", error);
|
|
68
|
-
}
|
|
69
|
-
return { eligible: false, reason: "error" };
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** Record trial start for a device */
|
|
74
|
-
export async function recordTrialStart(userId: string, deviceId?: string): Promise<boolean> {
|
|
75
|
-
try {
|
|
76
|
-
const effectiveDeviceId = deviceId || await getDeviceId();
|
|
77
|
-
const db = getFirestore();
|
|
78
|
-
|
|
79
|
-
if (!db) {
|
|
80
|
-
if (__DEV__) {
|
|
81
|
-
console.log("[TrialService] No Firestore instance");
|
|
82
|
-
}
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const trialRef = doc(db, DEVICE_TRIALS_COLLECTION, effectiveDeviceId);
|
|
87
|
-
|
|
88
|
-
await setDoc(
|
|
89
|
-
trialRef,
|
|
90
|
-
{
|
|
91
|
-
deviceId: effectiveDeviceId,
|
|
92
|
-
trialInProgress: true,
|
|
93
|
-
trialStartedAt: serverTimestamp(),
|
|
94
|
-
lastUserId: userId,
|
|
95
|
-
userIds: arrayUnion(userId),
|
|
96
|
-
updatedAt: serverTimestamp(),
|
|
97
|
-
},
|
|
98
|
-
{ merge: true }
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
// Also set createdAt if it's a new record
|
|
102
|
-
const existingDoc = await getDoc(trialRef);
|
|
103
|
-
if (!existingDoc.data()?.createdAt) {
|
|
104
|
-
await setDoc(
|
|
105
|
-
trialRef,
|
|
106
|
-
{ createdAt: serverTimestamp() },
|
|
107
|
-
{ merge: true }
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (__DEV__) {
|
|
112
|
-
console.log("[TrialService] Trial recorded:", {
|
|
113
|
-
deviceId: effectiveDeviceId.slice(0, 8),
|
|
114
|
-
userId: userId.slice(0, 8),
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return true;
|
|
119
|
-
} catch (error) {
|
|
120
|
-
if (__DEV__) {
|
|
121
|
-
console.error("[TrialService] Record trial error:", error);
|
|
122
|
-
}
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Record trial end (cancelled or expired)
|
|
129
|
-
*/
|
|
130
|
-
export async function recordTrialEnd(deviceId?: string): Promise<boolean> {
|
|
131
|
-
try {
|
|
132
|
-
const effectiveDeviceId = deviceId || await getDeviceId();
|
|
133
|
-
const db = getFirestore();
|
|
134
|
-
|
|
135
|
-
if (!db) return false;
|
|
136
|
-
|
|
137
|
-
const trialRef = doc(db, DEVICE_TRIALS_COLLECTION, effectiveDeviceId);
|
|
138
|
-
|
|
139
|
-
await setDoc(
|
|
140
|
-
trialRef,
|
|
141
|
-
{
|
|
142
|
-
hasUsedTrial: true,
|
|
143
|
-
trialInProgress: false,
|
|
144
|
-
trialEndedAt: serverTimestamp(),
|
|
145
|
-
updatedAt: serverTimestamp(),
|
|
146
|
-
},
|
|
147
|
-
{ merge: true }
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
if (__DEV__) {
|
|
151
|
-
console.log("[TrialService] Trial end recorded - trial now consumed");
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return true;
|
|
155
|
-
} catch (error) {
|
|
156
|
-
if (__DEV__) {
|
|
157
|
-
console.error("[TrialService] Record trial end error:", error);
|
|
158
|
-
}
|
|
159
|
-
return false;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Record trial conversion to paid subscription
|
|
165
|
-
*/
|
|
166
|
-
export async function recordTrialConversion(deviceId?: string): Promise<boolean> {
|
|
167
|
-
try {
|
|
168
|
-
const effectiveDeviceId = deviceId || await getDeviceId();
|
|
169
|
-
const db = getFirestore();
|
|
170
|
-
|
|
171
|
-
if (!db) return false;
|
|
172
|
-
|
|
173
|
-
const trialRef = doc(db, DEVICE_TRIALS_COLLECTION, effectiveDeviceId);
|
|
174
|
-
|
|
175
|
-
await setDoc(
|
|
176
|
-
trialRef,
|
|
177
|
-
{
|
|
178
|
-
hasUsedTrial: true,
|
|
179
|
-
trialInProgress: false,
|
|
180
|
-
trialConvertedAt: serverTimestamp(),
|
|
181
|
-
updatedAt: serverTimestamp(),
|
|
182
|
-
},
|
|
183
|
-
{ merge: true }
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
if (__DEV__) {
|
|
187
|
-
console.log("[TrialService] Trial conversion recorded - user converted to paid");
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return true;
|
|
191
|
-
} catch (error) {
|
|
192
|
-
if (__DEV__) {
|
|
193
|
-
console.error("[TrialService] Record conversion error:", error);
|
|
194
|
-
}
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* App Service Helpers
|
|
3
|
-
* Creates ready-to-use service implementations for configureAppServices
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { getCreditsRepository } from "../repositories/CreditsRepositoryProvider";
|
|
7
|
-
import { getRevenueCatService } from "../../revenuecat/infrastructure/services/RevenueCatService";
|
|
8
|
-
import { getPremiumEntitlement } from "../../revenuecat/domain/types/RevenueCatTypes";
|
|
9
|
-
import { creditsQueryKeys } from "../../presentation/hooks/useCredits";
|
|
10
|
-
import { paywallControl } from "../../presentation/hooks/usePaywallVisibility";
|
|
11
|
-
import {
|
|
12
|
-
getGlobalQueryClient,
|
|
13
|
-
hasGlobalQueryClient,
|
|
14
|
-
} from "@umituz/react-native-design-system";
|
|
15
|
-
import {
|
|
16
|
-
useAuthStore,
|
|
17
|
-
selectUserId,
|
|
18
|
-
} from "@umituz/react-native-auth";
|
|
19
|
-
|
|
20
|
-
export interface CreditServiceConfig {
|
|
21
|
-
entitlementId: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface ICreditService {
|
|
25
|
-
checkCredits: (cost: number) => Promise<boolean>;
|
|
26
|
-
deductCredits: (cost: number) => Promise<void>;
|
|
27
|
-
refundCredits: (amount: number, error?: unknown) => Promise<void>;
|
|
28
|
-
calculateCost: (capability: string, metadata?: Record<string, unknown>) => number;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface IPaywallService {
|
|
32
|
-
showPaywall: (requiredCredits: number) => void;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const checkPremiumStatus = async (entitlementId: string): Promise<boolean> => {
|
|
36
|
-
try {
|
|
37
|
-
const rcService = getRevenueCatService();
|
|
38
|
-
if (!rcService) return false;
|
|
39
|
-
|
|
40
|
-
const customerInfo = await rcService.getCustomerInfo();
|
|
41
|
-
if (!customerInfo) return false;
|
|
42
|
-
|
|
43
|
-
return !!getPremiumEntitlement(customerInfo, entitlementId);
|
|
44
|
-
} catch {
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Creates a credit service implementation
|
|
51
|
-
*/
|
|
52
|
-
export function createCreditService(config: CreditServiceConfig): ICreditService {
|
|
53
|
-
const { entitlementId } = config;
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
checkCredits: async (cost: number): Promise<boolean> => {
|
|
57
|
-
const userId = selectUserId(useAuthStore.getState());
|
|
58
|
-
if (!userId) return false;
|
|
59
|
-
|
|
60
|
-
// Premium users bypass credit check
|
|
61
|
-
if (await checkPremiumStatus(entitlementId)) return true;
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
const repository = getCreditsRepository();
|
|
65
|
-
const result = await repository.getCredits(userId);
|
|
66
|
-
if (!result.success || !result.data) return false;
|
|
67
|
-
return (result.data.credits ?? 0) >= cost;
|
|
68
|
-
} catch {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
deductCredits: async (cost: number): Promise<void> => {
|
|
74
|
-
const userId = selectUserId(useAuthStore.getState());
|
|
75
|
-
if (!userId) return;
|
|
76
|
-
|
|
77
|
-
// Premium users don't consume credits
|
|
78
|
-
if (await checkPremiumStatus(entitlementId)) return;
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
const repository = getCreditsRepository();
|
|
82
|
-
await repository.deductCredit(userId, cost);
|
|
83
|
-
|
|
84
|
-
if (hasGlobalQueryClient()) {
|
|
85
|
-
getGlobalQueryClient().invalidateQueries({
|
|
86
|
-
queryKey: creditsQueryKeys.user(userId),
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
} catch (error) {
|
|
90
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
91
|
-
console.error("[CreditService] Deduct error:", error);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
refundCredits: async (): Promise<void> => {
|
|
97
|
-
// No-op for now
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
calculateCost: (): number => 1,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Creates a paywall service implementation
|
|
106
|
-
*/
|
|
107
|
-
export function createPaywallService(): IPaywallService {
|
|
108
|
-
return {
|
|
109
|
-
showPaywall: () => paywallControl.open(),
|
|
110
|
-
};
|
|
111
|
-
}
|
package/src/revenuecat/README.md
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
# RevenueCat Integration
|
|
2
|
-
|
|
3
|
-
Comprehensive integration and API wrapper for subscription management with RevenueCat.
|
|
4
|
-
|
|
5
|
-
## Location
|
|
6
|
-
|
|
7
|
-
- **Base Path**: `/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-subscription/src/revenuecat/`
|
|
8
|
-
- **Domain**: `src/revenuecat/domain/`
|
|
9
|
-
- **Infrastructure**: `src/revenuecat/infrastructure/`
|
|
10
|
-
- **Presentation**: `src/revenuecat/presentation/`
|
|
11
|
-
|
|
12
|
-
## Strategy
|
|
13
|
-
|
|
14
|
-
### RevenueCat SDK Integration
|
|
15
|
-
|
|
16
|
-
Seamless RevenueCat SDK initialization and configuration.
|
|
17
|
-
|
|
18
|
-
- **Automatic Initialization**: SDK startup and configuration
|
|
19
|
-
- **User ID Management**: Auth system integration
|
|
20
|
-
- **Purchase Flow**: Managed purchase operations
|
|
21
|
-
- **Restore Operations**: Purchase restoration support
|
|
22
|
-
- **Error Handling**: RevenueCat error management
|
|
23
|
-
|
|
24
|
-
### Hook Architecture
|
|
25
|
-
|
|
26
|
-
React hooks for RevenueCat functionality.
|
|
27
|
-
|
|
28
|
-
- **useRevenueCat**: Core RevenueCat access
|
|
29
|
-
- **useCustomerInfo**: Subscription information tracking
|
|
30
|
-
- **useInitializeSubscription**: Initialization status monitoring
|
|
31
|
-
- **useSubscriptionPackages**: Package listing and selection
|
|
32
|
-
- **usePaywallFlow**: Complete paywall flow management
|
|
33
|
-
- **useRestorePurchase**: Purchase restoration
|
|
34
|
-
|
|
35
|
-
### State Management
|
|
36
|
-
|
|
37
|
-
Customer info and subscription state tracking.
|
|
38
|
-
|
|
39
|
-
- **Customer Info Tracking**: Real-time subscription updates
|
|
40
|
-
- **Offerings Management**: Package offering configuration
|
|
41
|
-
- **Purchase State**: Purchase operation states
|
|
42
|
-
- **Error States**: Comprehensive error handling
|
|
43
|
-
|
|
44
|
-
### User ID Synchronization
|
|
45
|
-
|
|
46
|
-
Auth system integration for user management.
|
|
47
|
-
|
|
48
|
-
- **Auth Sync**: Automatic user ID synchronization
|
|
49
|
-
- **Login/Logout**: User ID management on auth changes
|
|
50
|
-
- **Anonymous Users**: Anonymous user support
|
|
51
|
-
- **Migration**: User migration support
|
|
52
|
-
|
|
53
|
-
## Restrictions
|
|
54
|
-
|
|
55
|
-
### REQUIRED
|
|
56
|
-
|
|
57
|
-
- **Initialization**: Must initialize before any operations
|
|
58
|
-
- **User ID Sync**: Sync user IDs with auth system
|
|
59
|
-
- **Error Handling**: All operations must handle errors
|
|
60
|
-
- **Loading States**: Show appropriate loading indicators
|
|
61
|
-
|
|
62
|
-
### PROHIBITED
|
|
63
|
-
|
|
64
|
-
- **Direct SDK Calls**: Use hooks instead of direct RevenueCat calls
|
|
65
|
-
- **Missing User IDs**: Operations require valid user IDs
|
|
66
|
-
- **Uninitialized Access**: Don't call methods before initialization
|
|
67
|
-
- **Ignoring Errors**: All errors must be handled
|
|
68
|
-
|
|
69
|
-
### CRITICAL
|
|
70
|
-
|
|
71
|
-
- **API Key Security**: Never expose API keys in client code
|
|
72
|
-
- **User ID Consistency**: Maintain consistent user IDs
|
|
73
|
-
- **Purchase Validation**: Validate all purchase results
|
|
74
|
-
- **Entitlement Check**: Always verify entitlements
|
|
75
|
-
|
|
76
|
-
## AI Agent Guidelines
|
|
77
|
-
|
|
78
|
-
### When Modifying RevenueCat Integration
|
|
79
|
-
|
|
80
|
-
1. **SDK Version**: Check RevenueCat SDK version compatibility
|
|
81
|
-
2. **Type Definitions**: Update TypeScript types
|
|
82
|
-
3. **Error Handling**: Maintain comprehensive error handling
|
|
83
|
-
4. **Testing**: Test with different subscription states
|
|
84
|
-
|
|
85
|
-
### When Adding New Hooks
|
|
86
|
-
|
|
87
|
-
1. **Hook Pattern**: Follow existing hook patterns
|
|
88
|
-
2. **State Management**: Proper state management
|
|
89
|
-
3. **Error Handling**: Comprehensive error handling
|
|
90
|
-
4. **Documentation**: Document hook usage and return values
|
|
91
|
-
|
|
92
|
-
### When Fixing RevenueCat Bugs
|
|
93
|
-
|
|
94
|
-
1. **SDK Integration**: Check RevenueCat SDK integration
|
|
95
|
-
2. **State Updates**: Verify state update mechanisms
|
|
96
|
-
3. **User ID**: Verify user ID consistency
|
|
97
|
-
4. **Purchase Flow**: Test complete purchase flows
|
|
98
|
-
|
|
99
|
-
## Related Documentation
|
|
100
|
-
|
|
101
|
-
- [Paywall Domain](/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-subscription/src/domains/paywall/README.md)
|
|
102
|
-
- [Config Domain](/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-subscription/src/domains/config/README.md)
|
|
103
|
-
- [Infrastructure Layer](/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-subscription/src/infrastructure/README.md)
|
|
104
|
-
- [Application Layer](/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-subscription/src/application/README.md)
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# RevenueCat Application Layer
|
|
2
|
-
|
|
3
|
-
## Location
|
|
4
|
-
Application layer for RevenueCat integration, containing use cases and orchestration logic.
|
|
5
|
-
|
|
6
|
-
## Strategy
|
|
7
|
-
This directory contains use cases and application-level operations for managing RevenueCat subscriptions and purchases with proper error handling and state synchronization.
|
|
8
|
-
|
|
9
|
-
## Restrictions
|
|
10
|
-
|
|
11
|
-
### REQUIRED
|
|
12
|
-
- Must handle RevenueCat errors gracefully
|
|
13
|
-
- Must provide user ID when available
|
|
14
|
-
- Must use entitlements instead of product IDs
|
|
15
|
-
- Must keep local state synchronized
|
|
16
|
-
|
|
17
|
-
### PROHIBITED
|
|
18
|
-
- DO NOT ignore RevenueCat errors
|
|
19
|
-
- DO NOT skip user ID provision
|
|
20
|
-
- DO NOT use product IDs directly
|
|
21
|
-
- DO NOT allow state desynchronization
|
|
22
|
-
|
|
23
|
-
### CRITICAL SAFETY
|
|
24
|
-
- All errors MUST be handled gracefully
|
|
25
|
-
- User IDs MUST be provided when available
|
|
26
|
-
- Entitlements MUST be used for flexibility
|
|
27
|
-
- Local state MUST stay synchronized
|
|
28
|
-
|
|
29
|
-
## AI Agent Guidelines
|
|
30
|
-
1. Always handle RevenueCat errors with proper recovery
|
|
31
|
-
2. Provide user ID when available for better tracking
|
|
32
|
-
3. Use entitlements instead of product IDs for flexibility
|
|
33
|
-
4. Check if offerings are available before purchasing
|
|
34
|
-
5. Validate customer info after purchases
|
|
35
|
-
6. Keep local state synchronized with RevenueCat
|
|
36
|
-
7. Handle network timeouts appropriately
|
|
37
|
-
8. Log all RevenueCat operations for debugging
|
|
38
|
-
|
|
39
|
-
## Related Documentation
|
|
40
|
-
- [RevenueCat Integration](../README.md)
|
|
41
|
-
- [RevenueCat Domain](../domain/README.md)
|
|
42
|
-
- [RevenueCat Infrastructure](../infrastructure/README.md)
|
|
43
|
-
- [Application Ports](./ports/README.md)
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* RevenueCat Service Interface
|
|
3
|
-
* Port for subscription operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { PurchasesPackage, PurchasesOffering, CustomerInfo } from "react-native-purchases";
|
|
7
|
-
|
|
8
|
-
export interface InitializeResult {
|
|
9
|
-
success: boolean;
|
|
10
|
-
offering: PurchasesOffering | null;
|
|
11
|
-
isPremium: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface PurchaseResult {
|
|
15
|
-
success: boolean;
|
|
16
|
-
isPremium: boolean;
|
|
17
|
-
customerInfo?: CustomerInfo;
|
|
18
|
-
isConsumable?: boolean;
|
|
19
|
-
productId?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface RestoreResult {
|
|
23
|
-
success: boolean;
|
|
24
|
-
isPremium: boolean;
|
|
25
|
-
customerInfo?: CustomerInfo;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface IRevenueCatService {
|
|
29
|
-
/**
|
|
30
|
-
* Initialize RevenueCat SDK
|
|
31
|
-
* @param userId User identifier
|
|
32
|
-
* @param apiKey Optional API key (auto-resolved if not provided)
|
|
33
|
-
*/
|
|
34
|
-
initialize(userId: string, apiKey?: string): Promise<InitializeResult>;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Fetch offerings from RevenueCat
|
|
38
|
-
*/
|
|
39
|
-
fetchOfferings(): Promise<PurchasesOffering | null>;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Purchase a package
|
|
43
|
-
*/
|
|
44
|
-
purchasePackage(pkg: PurchasesPackage, userId: string): Promise<PurchaseResult>;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Restore purchases
|
|
48
|
-
*/
|
|
49
|
-
restorePurchases(userId: string): Promise<RestoreResult>;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Reset RevenueCat SDK (for logout)
|
|
53
|
-
*/
|
|
54
|
-
reset(): Promise<void>;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Get current customer info
|
|
58
|
-
*/
|
|
59
|
-
getCustomerInfo(): Promise<CustomerInfo | null>;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Get RevenueCat API key for current platform
|
|
63
|
-
*/
|
|
64
|
-
getRevenueCatKey(): string | null;
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Check if RevenueCat is initialized
|
|
68
|
-
*/
|
|
69
|
-
isInitialized(): boolean;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Get current user ID
|
|
73
|
-
*/
|
|
74
|
-
getCurrentUserId(): string | null;
|
|
75
|
-
}
|
|
76
|
-
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# RevenueCat Application Ports
|
|
2
|
-
|
|
3
|
-
## Location
|
|
4
|
-
Interface definitions for RevenueCat service layer.
|
|
5
|
-
|
|
6
|
-
## Strategy
|
|
7
|
-
This directory defines the ports (interfaces) that the RevenueCat infrastructure must implement, following the Dependency Inversion Principle for testability and flexibility.
|
|
8
|
-
|
|
9
|
-
## Restrictions
|
|
10
|
-
|
|
11
|
-
### REQUIRED
|
|
12
|
-
- Must define clear interfaces for all operations
|
|
13
|
-
- Must support mocking for testing
|
|
14
|
-
- Must enable implementation swapping
|
|
15
|
-
- Must maintain contracts between layers
|
|
16
|
-
|
|
17
|
-
### PROHIBITED
|
|
18
|
-
- DO NOT depend on concrete implementations
|
|
19
|
-
- DO NOT create interfaces without clear purpose
|
|
20
|
-
- DO NOT break interface contracts
|
|
21
|
-
- DO NOT couple application to infrastructure
|
|
22
|
-
|
|
23
|
-
### CRITICAL SAFETY
|
|
24
|
-
- All dependencies MUST be inverted
|
|
25
|
-
- Interfaces MUST be clearly defined
|
|
26
|
-
- Implementations MUST be swappable
|
|
27
|
-
- Contracts MUST be maintained
|
|
28
|
-
|
|
29
|
-
## AI Agent Guidelines
|
|
30
|
-
1. Define clear interfaces for all RevenueCat operations
|
|
31
|
-
2. Design interfaces for easy mocking in tests
|
|
32
|
-
3. Enable implementation swapping when needed
|
|
33
|
-
4. Keep application layer decoupled from infrastructure
|
|
34
|
-
5. Maintain clear contracts between layers
|
|
35
|
-
6. Document interface behavior thoroughly
|
|
36
|
-
7. Test with mock implementations
|
|
37
|
-
|
|
38
|
-
## Related Documentation
|
|
39
|
-
- [RevenueCat Application Layer](../README.md)
|
|
40
|
-
- [RevenueCat Infrastructure](../infrastructure/README.md)
|
|
41
|
-
- [RevenueCat Domain](../domain/README.md)
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# RevenueCat Domain
|
|
2
|
-
|
|
3
|
-
Domain entities and types for RevenueCat integration.
|
|
4
|
-
|
|
5
|
-
## Location
|
|
6
|
-
|
|
7
|
-
`src/revenuecat/domain/`
|
|
8
|
-
|
|
9
|
-
## Strategy
|
|
10
|
-
|
|
11
|
-
Domain-specific entities representing RevenueCat concepts like entitlements, offerings, and packages, with proper type mapping and validation.
|
|
12
|
-
|
|
13
|
-
## Restrictions
|
|
14
|
-
|
|
15
|
-
### REQUIRED
|
|
16
|
-
|
|
17
|
-
- MUST map RevenueCat types to domain types
|
|
18
|
-
- MUST handle optional properties safely (null safety)
|
|
19
|
-
- MUST validate RevenueCat data
|
|
20
|
-
- MUST format prices and dates consistently
|
|
21
|
-
- MUST use constants for identifiers
|
|
22
|
-
|
|
23
|
-
### PROHIBITED
|
|
24
|
-
|
|
25
|
-
- MUST NOT expose RevenueCat implementation details to other layers
|
|
26
|
-
- MUST NOT leak RevenueCat SDK types outside this module
|
|
27
|
-
- MUST NOT assume all properties are present (null safety)
|
|
28
|
-
|
|
29
|
-
### CRITICAL
|
|
30
|
-
|
|
31
|
-
- Always validate RevenueCat data before use
|
|
32
|
-
- Handle all optional properties safely
|
|
33
|
-
- Use constants for all identifiers
|
|
34
|
-
- Maintain consistent formatting for prices and dates
|
|
35
|
-
|
|
36
|
-
## AI Agent Guidelines
|
|
37
|
-
|
|
38
|
-
When working with RevenueCat domain:
|
|
39
|
-
1. Type Mapping - map RevenueCat types to domain types
|
|
40
|
-
2. Null Safety - handle optional properties safely
|
|
41
|
-
3. Validation - validate RevenueCat data
|
|
42
|
-
4. Formatting - format prices and dates consistently
|
|
43
|
-
5. Constants - use constants for identifiers
|
|
44
|
-
|
|
45
|
-
## Related Documentation
|
|
46
|
-
|
|
47
|
-
- [RevenueCat README](../README.md)
|
|
48
|
-
- [Subscription Manager](../../infrastructure/managers/README.md)
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# RevenueCat Domain Constants
|
|
2
|
-
|
|
3
|
-
## Location
|
|
4
|
-
Constants used throughout the RevenueCat integration.
|
|
5
|
-
|
|
6
|
-
## Strategy
|
|
7
|
-
This directory contains constant definitions for RevenueCat-specific values including entitlement IDs, error codes, and configuration defaults for maintainability and consistency.
|
|
8
|
-
|
|
9
|
-
## Restrictions
|
|
10
|
-
|
|
11
|
-
### REQUIRED
|
|
12
|
-
- Must use constants for all RevenueCat-specific values
|
|
13
|
-
- Must provide clear constant names
|
|
14
|
-
- Must maintain consistency across codebase
|
|
15
|
-
- Must document constant purposes
|
|
16
|
-
|
|
17
|
-
### PROHIBITED
|
|
18
|
-
- DO NOT use magic strings or numbers
|
|
19
|
-
- DO NOT duplicate constant definitions
|
|
20
|
-
- DO NOT use hardcoded values
|
|
21
|
-
- DO NOT create ambiguous constants
|
|
22
|
-
|
|
23
|
-
### CRITICAL SAFETY
|
|
24
|
-
- All RevenueCat-specific values MUST use constants
|
|
25
|
-
- Constants MUST be clearly named and documented
|
|
26
|
-
- Constant values MUST be consistent
|
|
27
|
-
- Entitlement IDs MUST match RevenueCat dashboard
|
|
28
|
-
|
|
29
|
-
## AI Agent Guidelines
|
|
30
|
-
1. Use constants for all RevenueCat-specific values
|
|
31
|
-
2. Provide clear, descriptive constant names
|
|
32
|
-
3. Maintain consistency across the codebase
|
|
33
|
-
4. Document the purpose of each constant
|
|
34
|
-
5. Organize constants by category (entitlements, offerings, errors)
|
|
35
|
-
6. Validate constants match RevenueCat dashboard configuration
|
|
36
|
-
7. Avoid magic strings and numbers throughout code
|
|
37
|
-
|
|
38
|
-
## Related Documentation
|
|
39
|
-
- [RevenueCat Domain](../README.md)
|
|
40
|
-
- [RevenueCat Errors](../errors/README.md)
|
|
41
|
-
- [RevenueCat Entities](../entities/README.md)
|