@umituz/react-native-subscription 2.14.97 → 2.14.99

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.
Files changed (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +461 -0
  3. package/package.json +1 -3
  4. package/src/application/README.md +229 -0
  5. package/src/application/ports/README.md +103 -0
  6. package/src/domain/README.md +402 -0
  7. package/src/domain/constants/README.md +80 -0
  8. package/src/domain/entities/README.md +176 -0
  9. package/src/domain/errors/README.md +307 -0
  10. package/src/domain/value-objects/README.md +186 -0
  11. package/src/domains/README.md +240 -0
  12. package/src/domains/config/README.md +390 -0
  13. package/src/domains/config/domain/README.md +390 -0
  14. package/src/domains/config/domain/entities/README.md +350 -0
  15. package/src/domains/paywall/README.md +371 -0
  16. package/src/domains/paywall/components/PaywallHeader.tsx +8 -11
  17. package/src/domains/paywall/components/README.md +185 -0
  18. package/src/domains/paywall/entities/README.md +199 -0
  19. package/src/domains/paywall/hooks/README.md +129 -0
  20. package/src/domains/wallet/README.md +292 -0
  21. package/src/domains/wallet/domain/README.md +108 -0
  22. package/src/domains/wallet/domain/entities/README.md +122 -0
  23. package/src/domains/wallet/domain/errors/README.md +157 -0
  24. package/src/domains/wallet/infrastructure/README.md +96 -0
  25. package/src/domains/wallet/presentation/components/BalanceCard.tsx +6 -12
  26. package/src/domains/wallet/presentation/components/README.md +231 -0
  27. package/src/domains/wallet/presentation/hooks/README.md +255 -0
  28. package/src/infrastructure/README.md +514 -0
  29. package/src/infrastructure/mappers/README.md +34 -0
  30. package/src/infrastructure/models/README.md +26 -0
  31. package/src/infrastructure/repositories/README.md +385 -0
  32. package/src/infrastructure/services/README.md +374 -0
  33. package/src/presentation/README.md +410 -0
  34. package/src/presentation/components/README.md +183 -0
  35. package/src/presentation/components/details/CreditRow.md +337 -0
  36. package/src/presentation/components/details/DetailRow.md +283 -0
  37. package/src/presentation/components/details/PremiumDetailsCard.md +266 -0
  38. package/src/presentation/components/details/PremiumStatusBadge.md +266 -0
  39. package/src/presentation/components/details/README.md +449 -0
  40. package/src/presentation/components/feedback/PaywallFeedbackModal.md +314 -0
  41. package/src/presentation/components/feedback/README.md +447 -0
  42. package/src/presentation/components/paywall/PaywallModal.md +444 -0
  43. package/src/presentation/components/paywall/README.md +190 -0
  44. package/src/presentation/components/sections/README.md +468 -0
  45. package/src/presentation/components/sections/SubscriptionSection.md +246 -0
  46. package/src/presentation/hooks/README.md +743 -0
  47. package/src/presentation/hooks/useAuthAwarePurchase.md +359 -0
  48. package/src/presentation/hooks/useAuthGate.md +403 -0
  49. package/src/presentation/hooks/useAuthSubscriptionSync.md +398 -0
  50. package/src/presentation/hooks/useCreditChecker.md +407 -0
  51. package/src/presentation/hooks/useCredits.md +342 -0
  52. package/src/presentation/hooks/useCreditsGate.md +346 -0
  53. package/src/presentation/hooks/useDeductCredit.md +176 -0
  54. package/src/presentation/hooks/useDevTestCallbacks.md +422 -0
  55. package/src/presentation/hooks/useFeatureGate.md +157 -0
  56. package/src/presentation/hooks/useInitializeCredits.md +458 -0
  57. package/src/presentation/hooks/usePaywall.md +334 -0
  58. package/src/presentation/hooks/usePaywallOperations.md +486 -0
  59. package/src/presentation/hooks/usePaywallVisibility.md +344 -0
  60. package/src/presentation/hooks/usePremium.md +230 -0
  61. package/src/presentation/hooks/usePremiumGate.md +423 -0
  62. package/src/presentation/hooks/usePremiumWithCredits.md +429 -0
  63. package/src/presentation/hooks/useSubscription.md +450 -0
  64. package/src/presentation/hooks/useSubscriptionDetails.md +438 -0
  65. package/src/presentation/hooks/useSubscriptionGate.md +168 -0
  66. package/src/presentation/hooks/useSubscriptionSettingsConfig.md +374 -0
  67. package/src/presentation/hooks/useSubscriptionStatus.md +424 -0
  68. package/src/presentation/hooks/useUserTier.md +356 -0
  69. package/src/presentation/hooks/useUserTierWithRepository.md +452 -0
  70. package/src/presentation/screens/README.md +194 -0
  71. package/src/presentation/types/README.md +38 -0
  72. package/src/presentation/utils/README.md +52 -0
  73. package/src/revenuecat/README.md +523 -0
  74. package/src/revenuecat/application/README.md +158 -0
  75. package/src/revenuecat/application/ports/README.md +169 -0
  76. package/src/revenuecat/domain/README.md +147 -0
  77. package/src/revenuecat/domain/constants/README.md +183 -0
  78. package/src/revenuecat/domain/entities/README.md +382 -0
  79. package/src/revenuecat/domain/errors/README.md +197 -0
  80. package/src/revenuecat/domain/types/README.md +373 -0
  81. package/src/revenuecat/domain/value-objects/README.md +441 -0
  82. package/src/revenuecat/infrastructure/README.md +50 -0
  83. package/src/revenuecat/infrastructure/config/README.md +40 -0
  84. package/src/revenuecat/infrastructure/handlers/README.md +218 -0
  85. package/src/revenuecat/infrastructure/managers/README.md +49 -0
  86. package/src/revenuecat/infrastructure/services/README.md +325 -0
  87. package/src/revenuecat/infrastructure/utils/README.md +382 -0
  88. package/src/revenuecat/presentation/README.md +184 -0
  89. package/src/revenuecat/presentation/hooks/README.md +56 -0
  90. package/src/utils/README.md +529 -0
@@ -0,0 +1,292 @@
1
+ # Wallet Domain
2
+
3
+ Kredi bakiyesi yönetimi, işlem geçmişi takibi ve ürün metadata yönetimi için kapsamlı çözüm.
4
+
5
+ ## Özellikler
6
+
7
+ - **Kredi Bakiyesi Yönetimi**: Kullanıcıların kredi bakiyelerini takip edin ve yönetin
8
+ - **İşlem Geçmişi**: Tüm kredi işlemlerini geçmişte takip edin
9
+ - **Ürün Metadata**: Satın alınan ürünler için metadata yönetimi
10
+ - **Tür Desteği**: Farklı kredi türlerini (AI, premium, vb.) destekleyin
11
+
12
+ ## Kurulum
13
+
14
+ ### 1. Service Konfigürasyonu
15
+
16
+ ```typescript
17
+ import { configureProductMetadataService } from '@umituz/react-native-subscription';
18
+
19
+ // Service'i konfigüre edin
20
+ configureProductMetadataService({
21
+ firebase: firebaseInstance,
22
+ storage: storageInstance,
23
+ });
24
+ ```
25
+
26
+ ### 2. Repository Oluşturma
27
+
28
+ ```typescript
29
+ import { createTransactionRepository } from '@umituz/react-native-subscription';
30
+
31
+ const transactionRepository = createTransactionRepository({
32
+ firebase: firebaseInstance,
33
+ userId: 'user-123',
34
+ });
35
+ ```
36
+
37
+ ## Kullanım
38
+
39
+ ### useWallet Hook
40
+
41
+ Kredi bakiyesi ve temel cüzdan işlemleri için:
42
+
43
+ ```typescript
44
+ import { useWallet } from '@umituz/react-native-subscription';
45
+
46
+ function MyComponent() {
47
+ const { balance, loading, error, refresh } = useWallet({
48
+ userId: 'user-123',
49
+ });
50
+
51
+ if (loading) return <ActivityIndicator />;
52
+ if (error) return <Text>Error: {error.message}</Text>;
53
+
54
+ return (
55
+ <View>
56
+ <Text>Balance: {balance.credits}</Text>
57
+ <Button onPress={refresh} title="Refresh" />
58
+ </View>
59
+ );
60
+ }
61
+ ```
62
+
63
+ ### useTransactionHistory Hook
64
+
65
+ İşlem geçmişini görüntülemek için:
66
+
67
+ ```typescript
68
+ import { useTransactionHistory } from '@umituz/react-native-subscription';
69
+
70
+ function TransactionHistory() {
71
+ const { transactions, loading, hasMore, loadMore } = useTransactionHistory({
72
+ userId: 'user-123',
73
+ limit: 20,
74
+ });
75
+
76
+ return (
77
+ <FlatList
78
+ data={transactions}
79
+ keyExtractor={(item) => item.id}
80
+ onEndReached={hasMore ? loadMore : undefined}
81
+ renderItem={({ item }) => (
82
+ <View>
83
+ <Text>{item.reason}</Text>
84
+ <Text>{item.amount} credits</Text>
85
+ <Text>{new Date(item.timestamp).toLocaleString()}</Text>
86
+ </View>
87
+ )}
88
+ />
89
+ );
90
+ }
91
+ ```
92
+
93
+ ### useProductMetadata Hook
94
+
95
+ Ürün metadata yönetimi için:
96
+
97
+ ```typescript
98
+ import { useProductMetadata } from '@umituz/react-native-subscription';
99
+
100
+ function ProductInfo() {
101
+ const { metadata, loading, updateMetadata } = useProductMetadata({
102
+ userId: 'user-123',
103
+ productId: 'premium_monthly',
104
+ });
105
+
106
+ const handleUpdate = async () => {
107
+ await updateMetadata({
108
+ lastUsed: new Date().toISOString(),
109
+ usageCount: (metadata?.usageCount || 0) + 1,
110
+ });
111
+ };
112
+
113
+ return (
114
+ <View>
115
+ <Text>Product: {metadata?.productId}</Text>
116
+ <Text>Usage: {metadata?.usageCount} times</Text>
117
+ <Button onPress={handleUpdate} title="Update Usage" />
118
+ </View>
119
+ );
120
+ }
121
+ ```
122
+
123
+ ## Bileşenler
124
+
125
+ ### BalanceCard
126
+
127
+ Kredi bakiyesini gösteren kart bileşeni:
128
+
129
+ ```typescript
130
+ import { BalanceCard } from '@umituz/react-native-subscription';
131
+
132
+ <BalanceCard
133
+ balance={150}
134
+ currency="USD"
135
+ translations={{
136
+ title: "Your Balance",
137
+ subtitle: "Credits available",
138
+ }}
139
+ />
140
+ ```
141
+
142
+ ### TransactionItem
143
+
144
+ Tek işlem öğesi:
145
+
146
+ ```typescript
147
+ import { TransactionItem } from '@umituz/react-native-subscription';
148
+
149
+ <TransactionItem
150
+ transaction={{
151
+ id: 'tx-123',
152
+ amount: -50,
153
+ reason: 'purchase',
154
+ timestamp: '2024-01-01T00:00:00Z',
155
+ }}
156
+ translations={{
157
+ purchase: 'Purchase',
158
+ refund: 'Refund',
159
+ }}
160
+ />
161
+ ```
162
+
163
+ ### TransactionList
164
+
165
+ İşlem listesi bileşeni:
166
+
167
+ ```typescript
168
+ import { TransactionList } from '@umituz/react-native-subscription';
169
+
170
+ <TransactionList
171
+ transactions={transactions}
172
+ loading={loading}
173
+ onEndReached={loadMore}
174
+ translations={{
175
+ title: 'Transaction History',
176
+ empty: 'No transactions yet',
177
+ }}
178
+ />
179
+ ```
180
+
181
+ ### WalletScreen
182
+
183
+ Tam cüzdan ekranı:
184
+
185
+ ```typescript
186
+ import { WalletScreen } from '@umituz/react-native-subscription';
187
+
188
+ <WalletScreen
189
+ userId="user-123"
190
+ config={{
191
+ showBalance: true,
192
+ showHistory: true,
193
+ enableRefresh: true,
194
+ }}
195
+ translations={{
196
+ title: 'My Wallet',
197
+ balance: 'Balance',
198
+ history: 'History',
199
+ }}
200
+ />
201
+ ```
202
+
203
+ ## API Referansı
204
+
205
+ ### Tip Tanımlamaları
206
+
207
+ ```typescript
208
+ interface CreditBalance {
209
+ credits: number;
210
+ lastUpdated: string;
211
+ }
212
+
213
+ interface TransactionLog {
214
+ id: string;
215
+ amount: number;
216
+ reason: TransactionReason;
217
+ timestamp: string;
218
+ metadata?: Record<string, any>;
219
+ }
220
+
221
+ type TransactionReason =
222
+ | 'purchase'
223
+ | 'refund'
224
+ | 'usage'
225
+ | 'bonus'
226
+ | 'expiration';
227
+ ```
228
+
229
+ ### Yardımcı Fonksiyonlar
230
+
231
+ ```typescript
232
+ // Kredi maliyeti hesaplama
233
+ import { getCreditCost, creditsToDollars } from '@umituz/react-native-subscription';
234
+
235
+ const cost = getCreditCost('ai_generation'); // AI işlem maliyeti
236
+ const dollars = creditsToDollars(150, 0.01); // 150 kredi = $1.50
237
+ ```
238
+
239
+ ## Hata Yönetimi
240
+
241
+ ```typescript
242
+ import {
243
+ WalletError,
244
+ CreditLimitError,
245
+ handleWalletError,
246
+ } from '@umituz/react-native-subscription';
247
+
248
+ try {
249
+ // İşlem
250
+ } catch (error) {
251
+ if (error instanceof CreditLimitError) {
252
+ console.log('Yetersiz bakiye');
253
+ }
254
+ handleWalletError(error);
255
+ }
256
+ ```
257
+
258
+ ## Örnek Uygulama
259
+
260
+ ```typescript
261
+ import React from 'react';
262
+ import { View, Text, Button } from 'react-native';
263
+ import {
264
+ useWallet,
265
+ useTransactionHistory,
266
+ BalanceCard,
267
+ TransactionList,
268
+ } from '@umituz/react-native-subscription';
269
+
270
+ export default function WalletExample() {
271
+ const { balance, refresh } = useWallet({ userId: 'user-123' });
272
+ const { transactions, loading } = useTransactionHistory({
273
+ userId: 'user-123',
274
+ });
275
+
276
+ return (
277
+ <View>
278
+ <BalanceCard balance={balance} />
279
+ <Button title="Refresh" onPress={refresh} />
280
+ <TransactionList transactions={transactions} loading={loading} />
281
+ </View>
282
+ );
283
+ }
284
+ ```
285
+
286
+ ## Best Practices
287
+
288
+ 1. **Kredi Türleri**: Farklı kredi türleri için farklı cost config'leri kullanın
289
+ 2. **Hata Yönetimi**: Tüm işlemleri try-catch blokları içinde sarın
290
+ 3. **Loading State**: Yüklenme durumlarını her zaman gösterin
291
+ 4. **Refresh**: Kullanıcıya manuel refresh imkanı verin
292
+ 5. **Transaction Log**: Tüm işlemleri loglayın ve audit trail tutun
@@ -0,0 +1,108 @@
1
+ # Wallet Domain
2
+
3
+ Wallet domain containing credits and transaction management logic.
4
+
5
+ ## Overview
6
+
7
+ The wallet domain manages user credits, transactions, and credit allocation strategies. It handles credit initialization after purchase, credit deduction, and transaction history.
8
+
9
+ ## Structure
10
+
11
+ ```
12
+ wallet/
13
+ ├── domain/
14
+ │ ├── entities/ # Credit and transaction entities
15
+ │ ├── errors/ # Wallet-specific errors
16
+ │ ├── types/ # Wallet type definitions
17
+ │ └── mappers/ # Data transformation mappers
18
+ ├── infrastructure/
19
+ │ ├── repositories/ # Credits persistence
20
+ │ └── services/ # Credit operations
21
+ ├── presentation/
22
+ │ ├── hooks/ # React hooks for credits
23
+ │ ├── components/ # Credit UI components
24
+ │ └── screens/ # Credit management screens
25
+ ```
26
+
27
+ ## Core Concepts
28
+
29
+ ### Credits
30
+ User credits balance that can be consumed for premium features.
31
+
32
+ ```typescript
33
+ interface UserCredits {
34
+ credits: number;
35
+ purchasedAt: Date;
36
+ lastUpdatedAt: Date;
37
+ }
38
+ ```
39
+
40
+ ### Transactions
41
+ Record of credit transactions (additions and deductions).
42
+
43
+ ```typescript
44
+ interface Transaction {
45
+ id: string;
46
+ amount: number;
47
+ reason: string;
48
+ timestamp: Date;
49
+ type: 'purchase' | 'deduction' | 'bonus' | 'renewal';
50
+ }
51
+ ```
52
+
53
+ ### Allocation Modes
54
+
55
+ **ACCUMULATE**: Add credits to existing balance (renewals)
56
+ ```typescript
57
+ // Renewal: 100 + 100 = 200 credits
58
+ ```
59
+
60
+ **REPLACE**: Replace existing credits (new purchase)
61
+ ```typescript
62
+ // New purchase: Old balance replaced with new amount
63
+ ```
64
+
65
+ ## Key Features
66
+
67
+ - **Duplicate Protection**: Prevent duplicate credit allocations
68
+ - **Transactional Operations**: Atomic credit updates
69
+ - **Optimistic Updates**: Immediate UI with rollback
70
+ - **Transaction History**: Complete audit trail
71
+ - **Monthly Reset**: Credits reset on subscription renewal
72
+
73
+ ## Usage
74
+
75
+ ```typescript
76
+ // In hooks or components
77
+ import { useCredits } from './presentation/hooks/useCredits';
78
+ import { useDeductCredit } from './presentation/hooks/useDeductCredit';
79
+
80
+ function Feature() {
81
+ const { credits } = useCredits({ userId: user?.uid });
82
+ const { deductCredit } = useDeductCredit({
83
+ userId: user?.uid,
84
+ onCreditsExhausted: () => showPaywall(),
85
+ });
86
+
87
+ const handleUseFeature = async () => {
88
+ const success = await deductCredit(5);
89
+ if (success) {
90
+ await executeFeature();
91
+ }
92
+ };
93
+ }
94
+ ```
95
+
96
+ ## Best Practices
97
+
98
+ 1. **Check Balance First**: Verify credits before operations
99
+ 2. **Handle Exhaustion**: Provide upgrade path when credits low
100
+ 3. **Track Usage**: Log all credit transactions
101
+ 4. **Reset Credits**: Clear credits on subscription renewal
102
+ 5. **Test Edge Cases**: Zero credits, max credits, duplicates
103
+
104
+ ## Related
105
+
106
+ - [Credits README](./README.md)
107
+ - [Credits Entity](./domain/entities/Credits.md)
108
+ - [useCredits Hook](../../presentation/hooks/useCredits.md)
@@ -0,0 +1,122 @@
1
+ # Wallet Domain Entities
2
+
3
+ Core entities for credits and transaction management.
4
+
5
+ ## Overview
6
+
7
+ This directory contains domain entities representing credits, transactions, and wallet-related business concepts.
8
+
9
+ ## Entities
10
+
11
+ ### UserCredits
12
+ Represents user's credit balance and metadata.
13
+
14
+ ```typescript
15
+ interface UserCredits {
16
+ credits: number; // Current credit balance
17
+ purchasedAt: Date; // When credits were purchased
18
+ lastUpdatedAt: Date; // Last update timestamp
19
+ }
20
+
21
+ interface CreditsResult {
22
+ success: boolean;
23
+ data?: UserCredits;
24
+ error?: {
25
+ code: string;
26
+ message: string;
27
+ };
28
+ duplicate?: boolean; // If this was a duplicate operation
29
+ }
30
+ ```
31
+
32
+ **Usage:**
33
+ ```typescript
34
+ const credits: UserCredits = {
35
+ credits: 100,
36
+ purchasedAt: new Date('2024-01-01'),
37
+ lastUpdatedAt: new Date('2024-01-15'),
38
+ };
39
+ ```
40
+
41
+ ### Transaction
42
+ Represents a credit transaction record.
43
+
44
+ ```typescript
45
+ interface Transaction {
46
+ id: string;
47
+ amount: number; // Positive for additions, negative for deductions
48
+ reason: string; // Description of transaction
49
+ timestamp: Date; // When transaction occurred
50
+ type: TransactionType; // Transaction category
51
+ }
52
+
53
+ type TransactionType =
54
+ | 'purchase' // Initial purchase
55
+ | 'deduction' // Feature usage
56
+ | 'bonus' // Bonus credits
57
+ | 'renewal' // Subscription renewal
58
+ | 'adjustment'; // Manual adjustment
59
+ ```
60
+
61
+ **Usage:**
62
+ ```typescript
63
+ const transaction: Transaction = {
64
+ id: 'tx_123',
65
+ amount: -5,
66
+ reason: 'ai_generation',
67
+ timestamp: new Date(),
68
+ type: 'deduction',
69
+ };
70
+ ```
71
+
72
+ ### CreditPackage
73
+ Represents a credit package for purchase.
74
+
75
+ ```typescript
76
+ interface CreditPackage {
77
+ id: string;
78
+ amount: number; // Number of credits
79
+ price: number; // Price in currency units
80
+ currency: string; // Currency code (USD, EUR, etc.)
81
+ description?: string;
82
+ }
83
+ ```
84
+
85
+ ## Key Operations
86
+
87
+ ### Check Balance
88
+ ```typescript
89
+ function hasEnoughCredits(credits: UserCredits, required: number): boolean {
90
+ return credits.credits >= required;
91
+ }
92
+ ```
93
+
94
+ ### Calculate Remaining
95
+ ```typescript
96
+ function calculateRemaining(credits: UserCredits, spent: number): number {
97
+ return Math.max(0, credits.credits - spent);
98
+ }
99
+ ```
100
+
101
+ ### Validate Credits
102
+ ```typescript
103
+ function validateCredits(amount: number): void {
104
+ if (amount < 0) {
105
+ throw new Error('Credits cannot be negative');
106
+ }
107
+ }
108
+ ```
109
+
110
+ ## Best Practices
111
+
112
+ 1. **Immutability**: Treat entities as immutable values
113
+ 2. **Validation**: Validate in entity methods
114
+ 3. **Type Safety**: Use strict TypeScript types
115
+ 4. **Business Rules**: Keep business logic in entities
116
+ 5. **Serialization**: Handle date serialization properly
117
+
118
+ ## Related
119
+
120
+ - [Wallet Domain](../README.md)
121
+ - [Credits Repository](../../infrastructure/repositories/README.md)
122
+ - [useCredits Hook](../../../../presentation/hooks/useCredits.md)
@@ -0,0 +1,157 @@
1
+ # Wallet Domain Errors
2
+
3
+ Domain-specific errors for wallet and credit operations.
4
+
5
+ ## Overview
6
+
7
+ This directory contains custom error classes representing wallet-related error conditions.
8
+
9
+ ## Error Types
10
+
11
+ ### CreditsExhaustedError
12
+ Thrown when user doesn't have enough credits for an operation.
13
+
14
+ ```typescript
15
+ class CreditsExhaustedError extends Error {
16
+ constructor(
17
+ public currentBalance: number,
18
+ public required: number
19
+ ) {
20
+ super(
21
+ `Insufficient credits: ${currentBalance}/${required} required`,
22
+ 'CREDITS_EXHAUSTED'
23
+ );
24
+ this.name = 'CreditsExhaustedError';
25
+ }
26
+ }
27
+ ```
28
+
29
+ **Usage:**
30
+ ```typescript
31
+ import { CreditsExhaustedError } from './errors/CreditsExhaustedError';
32
+
33
+ function deductCredits(credits: UserCredits, amount: number) {
34
+ if (credits.credits < amount) {
35
+ throw new CreditsExhaustedError(credits.credits, amount);
36
+ }
37
+ // Proceed with deduction
38
+ }
39
+ ```
40
+
41
+ ### DuplicatePurchaseError
42
+ Thrown when attempting to add credits for a duplicate purchase ID.
43
+
44
+ ```typescript
45
+ class DuplicatePurchaseError extends Error {
46
+ constructor(
47
+ public purchaseId: string,
48
+ public existingCredits: UserCredits
49
+ ) {
50
+ super(
51
+ `Duplicate purchase ID: ${purchaseId}`,
52
+ 'DUPLICATE_PURCHASE'
53
+ );
54
+ this.name = 'DuplicatePurchaseError';
55
+ }
56
+ }
57
+ ```
58
+
59
+ **Usage:**
60
+ ```typescript
61
+ try {
62
+ await repository.initializeCredits(userId, purchaseId);
63
+ } catch (error) {
64
+ if (error instanceof DuplicatePurchaseError) {
65
+ console.log('Credits already added for this purchase');
66
+ }
67
+ }
68
+ ```
69
+
70
+ ### CreditsValidationError
71
+ Thrown when credit validation fails.
72
+
73
+ ```typescript
74
+ class CreditsValidationError extends Error {
75
+ constructor(
76
+ message: string,
77
+ public code: string
78
+ ) {
79
+ super(message, code);
80
+ this.name = 'CreditsValidationError';
81
+ }
82
+ }
83
+ ```
84
+
85
+ **Usage:**
86
+ ```typescript
87
+ function validateCreditAmount(amount: number) {
88
+ if (amount < 0) {
89
+ throw new CreditsValidationError(
90
+ 'Credit amount cannot be negative',
91
+ 'INVALID_AMOUNT'
92
+ );
93
+ }
94
+ if (amount > 10000) {
95
+ throw new CreditsValidationError(
96
+ 'Credit amount exceeds maximum',
97
+ 'EXCEEDS_MAXIMUM'
98
+ );
99
+ }
100
+ }
101
+ ```
102
+
103
+ ## Error Handling Pattern
104
+
105
+ ```typescript
106
+ import {
107
+ CreditsExhaustedError,
108
+ DuplicatePurchaseError,
109
+ CreditsValidationError
110
+ } from './errors';
111
+
112
+ async function handleCreditOperation(userId: string, cost: number) {
113
+ try {
114
+ const result = await repository.deductCredit(userId, cost);
115
+ return result;
116
+ } catch (error) {
117
+ if (error instanceof CreditsExhaustedError) {
118
+ // Show paywall or upgrade prompt
119
+ showPaywall({ required: cost, current: error.currentBalance });
120
+ } else if (error instanceof DuplicatePurchaseError) {
121
+ // Log and continue (not a critical error)
122
+ console.warn('Duplicate purchase detected');
123
+ } else if (error instanceof CreditsValidationError) {
124
+ // Log validation error
125
+ console.error('Validation failed:', error.message);
126
+ } else {
127
+ // Unexpected error
128
+ console.error('Unexpected error:', error);
129
+ }
130
+ throw error;
131
+ }
132
+ }
133
+ ```
134
+
135
+ ## Error Codes Reference
136
+
137
+ | Code | Description | Recovery |
138
+ |------|-------------|----------|
139
+ | `CREDITS_EXHAUSTED` | Not enough credits | Show paywall/upgrade |
140
+ | `DUPLICATE_PURCHASE` | Duplicate purchase ID | Ignore (idempotent) |
141
+ | `INVALID_AMOUNT` | Invalid credit amount | Validate input |
142
+ | `EXCEEDS_MAXIMUM` | Amount too large | Cap at maximum |
143
+ | `USER_NOT_FOUND` | User doesn't exist | Create user record |
144
+ | `INITIALIZATION_FAILED` | Credit init failed | Retry operation |
145
+
146
+ ## Best Practices
147
+
148
+ 1. **Specific Errors**: Use specific error types for different scenarios
149
+ 2. **Error Context**: Include relevant data in error properties
150
+ 3. **Graceful Handling**: Handle errors appropriately at boundaries
151
+ 4. **Logging**: Log errors for debugging
152
+ 5. **User Feedback**: Convert errors to user-friendly messages
153
+
154
+ ## Related
155
+
156
+ - [Wallet Entities](../entities/README.md)
157
+ - [Credits Repository](../../infrastructure/repositories/README.md)