@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.
- package/LICENSE +21 -0
- package/README.md +461 -0
- package/package.json +1 -3
- package/src/application/README.md +229 -0
- package/src/application/ports/README.md +103 -0
- package/src/domain/README.md +402 -0
- package/src/domain/constants/README.md +80 -0
- package/src/domain/entities/README.md +176 -0
- package/src/domain/errors/README.md +307 -0
- package/src/domain/value-objects/README.md +186 -0
- package/src/domains/README.md +240 -0
- package/src/domains/config/README.md +390 -0
- package/src/domains/config/domain/README.md +390 -0
- package/src/domains/config/domain/entities/README.md +350 -0
- package/src/domains/paywall/README.md +371 -0
- package/src/domains/paywall/components/PaywallHeader.tsx +8 -11
- package/src/domains/paywall/components/README.md +185 -0
- package/src/domains/paywall/entities/README.md +199 -0
- package/src/domains/paywall/hooks/README.md +129 -0
- package/src/domains/wallet/README.md +292 -0
- package/src/domains/wallet/domain/README.md +108 -0
- package/src/domains/wallet/domain/entities/README.md +122 -0
- package/src/domains/wallet/domain/errors/README.md +157 -0
- package/src/domains/wallet/infrastructure/README.md +96 -0
- package/src/domains/wallet/presentation/components/BalanceCard.tsx +6 -12
- package/src/domains/wallet/presentation/components/README.md +231 -0
- package/src/domains/wallet/presentation/hooks/README.md +255 -0
- package/src/infrastructure/README.md +514 -0
- package/src/infrastructure/mappers/README.md +34 -0
- package/src/infrastructure/models/README.md +26 -0
- package/src/infrastructure/repositories/README.md +385 -0
- package/src/infrastructure/services/README.md +374 -0
- package/src/presentation/README.md +410 -0
- package/src/presentation/components/README.md +183 -0
- package/src/presentation/components/details/CreditRow.md +337 -0
- package/src/presentation/components/details/DetailRow.md +283 -0
- package/src/presentation/components/details/PremiumDetailsCard.md +266 -0
- package/src/presentation/components/details/PremiumStatusBadge.md +266 -0
- package/src/presentation/components/details/README.md +449 -0
- package/src/presentation/components/feedback/PaywallFeedbackModal.md +314 -0
- package/src/presentation/components/feedback/README.md +447 -0
- package/src/presentation/components/paywall/PaywallModal.md +444 -0
- package/src/presentation/components/paywall/README.md +190 -0
- package/src/presentation/components/sections/README.md +468 -0
- package/src/presentation/components/sections/SubscriptionSection.md +246 -0
- package/src/presentation/hooks/README.md +743 -0
- package/src/presentation/hooks/useAuthAwarePurchase.md +359 -0
- package/src/presentation/hooks/useAuthGate.md +403 -0
- package/src/presentation/hooks/useAuthSubscriptionSync.md +398 -0
- package/src/presentation/hooks/useCreditChecker.md +407 -0
- package/src/presentation/hooks/useCredits.md +342 -0
- package/src/presentation/hooks/useCreditsGate.md +346 -0
- package/src/presentation/hooks/useDeductCredit.md +176 -0
- package/src/presentation/hooks/useDevTestCallbacks.md +422 -0
- package/src/presentation/hooks/useFeatureGate.md +157 -0
- package/src/presentation/hooks/useInitializeCredits.md +458 -0
- package/src/presentation/hooks/usePaywall.md +334 -0
- package/src/presentation/hooks/usePaywallOperations.md +486 -0
- package/src/presentation/hooks/usePaywallVisibility.md +344 -0
- package/src/presentation/hooks/usePremium.md +230 -0
- package/src/presentation/hooks/usePremiumGate.md +423 -0
- package/src/presentation/hooks/usePremiumWithCredits.md +429 -0
- package/src/presentation/hooks/useSubscription.md +450 -0
- package/src/presentation/hooks/useSubscriptionDetails.md +438 -0
- package/src/presentation/hooks/useSubscriptionGate.md +168 -0
- package/src/presentation/hooks/useSubscriptionSettingsConfig.md +374 -0
- package/src/presentation/hooks/useSubscriptionStatus.md +424 -0
- package/src/presentation/hooks/useUserTier.md +356 -0
- package/src/presentation/hooks/useUserTierWithRepository.md +452 -0
- package/src/presentation/screens/README.md +194 -0
- package/src/presentation/types/README.md +38 -0
- package/src/presentation/utils/README.md +52 -0
- package/src/revenuecat/README.md +523 -0
- package/src/revenuecat/application/README.md +158 -0
- package/src/revenuecat/application/ports/README.md +169 -0
- package/src/revenuecat/domain/README.md +147 -0
- package/src/revenuecat/domain/constants/README.md +183 -0
- package/src/revenuecat/domain/entities/README.md +382 -0
- package/src/revenuecat/domain/errors/README.md +197 -0
- package/src/revenuecat/domain/types/README.md +373 -0
- package/src/revenuecat/domain/value-objects/README.md +441 -0
- package/src/revenuecat/infrastructure/README.md +50 -0
- package/src/revenuecat/infrastructure/config/README.md +40 -0
- package/src/revenuecat/infrastructure/handlers/README.md +218 -0
- package/src/revenuecat/infrastructure/managers/README.md +49 -0
- package/src/revenuecat/infrastructure/services/README.md +325 -0
- package/src/revenuecat/infrastructure/utils/README.md +382 -0
- package/src/revenuecat/presentation/README.md +184 -0
- package/src/revenuecat/presentation/hooks/README.md +56 -0
- package/src/utils/README.md +529 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# RevenueCat Domain Entities
|
|
2
|
+
|
|
3
|
+
Core domain entities for RevenueCat integration.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This directory contains TypeScript type definitions and entities representing RevenueCat concepts like customer info, entitlements, offerings, and packages.
|
|
8
|
+
|
|
9
|
+
## Entities
|
|
10
|
+
|
|
11
|
+
### CustomerInfo
|
|
12
|
+
|
|
13
|
+
Represents the subscriber's current information and entitlements.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
interface CustomerInfo {
|
|
17
|
+
// Subscriber Information
|
|
18
|
+
originalAppUserId: string;
|
|
19
|
+
originalApplicationVersion: string | null;
|
|
20
|
+
requestDate: Date;
|
|
21
|
+
allExpirationDates: Record<string, Date | null>;
|
|
22
|
+
allPurchaseDates: Record<string, Date | null>;
|
|
23
|
+
originalPurchaseDates: Record<string, Date | null>;
|
|
24
|
+
|
|
25
|
+
// Entitlements
|
|
26
|
+
entitlements: EntitlementInfos;
|
|
27
|
+
|
|
28
|
+
// Active Subscriptions
|
|
29
|
+
activeSubscriptions: string[];
|
|
30
|
+
|
|
31
|
+
// All Purchases
|
|
32
|
+
allPurchasedProductIds: string[];
|
|
33
|
+
|
|
34
|
+
// Latest Purchase
|
|
35
|
+
latestExpirationDate: Date | null;
|
|
36
|
+
firstSeen: Date;
|
|
37
|
+
managementURL: string | null;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### EntitlementInfos
|
|
42
|
+
|
|
43
|
+
Collection of entitlement information.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
interface EntitlementInfos {
|
|
47
|
+
[key: string]: EntitlementInfo;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### EntitlementInfo
|
|
52
|
+
|
|
53
|
+
Information about a specific entitlement.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
interface EntitlementInfo {
|
|
57
|
+
// Identifier
|
|
58
|
+
identifier: string;
|
|
59
|
+
|
|
60
|
+
// Active Status
|
|
61
|
+
isActive: boolean;
|
|
62
|
+
willRenew: boolean;
|
|
63
|
+
|
|
64
|
+
// Period Type
|
|
65
|
+
periodType: 'normal' | 'trial' | 'intro';
|
|
66
|
+
|
|
67
|
+
// Product Information
|
|
68
|
+
productId: string;
|
|
69
|
+
productIdentifier: string;
|
|
70
|
+
|
|
71
|
+
// Dates
|
|
72
|
+
latestPurchaseDate: Date;
|
|
73
|
+
originalPurchaseDate: Date;
|
|
74
|
+
expirationDate: Date | null;
|
|
75
|
+
|
|
76
|
+
// Renewal Information
|
|
77
|
+
renewAt: Date | null;
|
|
78
|
+
isSandbox: boolean;
|
|
79
|
+
|
|
80
|
+
// Billing
|
|
81
|
+
billingIssueDetectedAt: Date | null;
|
|
82
|
+
|
|
83
|
+
// Cancellation
|
|
84
|
+
unsubscribeDetectedAt: Date | null;
|
|
85
|
+
|
|
86
|
+
// Store
|
|
87
|
+
store: 'app_store' | 'play_store' | 'stripe' | 'mac_app_store' | 'play_store_amazon' | 'promotional';
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Offerings
|
|
92
|
+
|
|
93
|
+
Collection of available offerings.
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
interface Offerings {
|
|
97
|
+
// All Offerings
|
|
98
|
+
all: Record<string, Offering>;
|
|
99
|
+
|
|
100
|
+
// Current Offering
|
|
101
|
+
current: Offering | null;
|
|
102
|
+
|
|
103
|
+
// Specific Offerings
|
|
104
|
+
[key: string]: Offering | null;
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Offering
|
|
109
|
+
|
|
110
|
+
A collection of packages available for purchase.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
interface Offering {
|
|
114
|
+
// Identifier
|
|
115
|
+
identifier: string;
|
|
116
|
+
|
|
117
|
+
// Server Description
|
|
118
|
+
serverDescription: string;
|
|
119
|
+
|
|
120
|
+
// Available Packages
|
|
121
|
+
availablePackages: Package[];
|
|
122
|
+
|
|
123
|
+
// Lifetime Packages
|
|
124
|
+
lifetime: Package | null;
|
|
125
|
+
|
|
126
|
+
// Annual Packages
|
|
127
|
+
annual: Package | null;
|
|
128
|
+
|
|
129
|
+
// Monthly Packages
|
|
130
|
+
monthly: Package | null;
|
|
131
|
+
|
|
132
|
+
// Weekly Packages
|
|
133
|
+
weekly: Package | null;
|
|
134
|
+
|
|
135
|
+
// Single Purchase
|
|
136
|
+
singlePurchase: Package | null;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Package
|
|
141
|
+
|
|
142
|
+
A purchasable product within an offering.
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
interface Package {
|
|
146
|
+
// Identifier
|
|
147
|
+
identifier: string;
|
|
148
|
+
|
|
149
|
+
// Package Type
|
|
150
|
+
packageType: PackageType;
|
|
151
|
+
|
|
152
|
+
// Product Information
|
|
153
|
+
product: Product;
|
|
154
|
+
|
|
155
|
+
// Offering
|
|
156
|
+
offeringIdentifier: string;
|
|
157
|
+
|
|
158
|
+
// Pricing
|
|
159
|
+
price: Price;
|
|
160
|
+
localizedPriceString: string;
|
|
161
|
+
|
|
162
|
+
// Metadata
|
|
163
|
+
metadata: PackageMetadata;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
type PackageType =
|
|
167
|
+
| 'monthly'
|
|
168
|
+
| 'annual'
|
|
169
|
+
| 'lifetime'
|
|
170
|
+
| 'weekly'
|
|
171
|
+
| 'single_purchase';
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Product
|
|
175
|
+
|
|
176
|
+
Details about a purchasable product.
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
interface Product {
|
|
180
|
+
// Identifier
|
|
181
|
+
identifier: string;
|
|
182
|
+
|
|
183
|
+
// Description
|
|
184
|
+
description: string;
|
|
185
|
+
|
|
186
|
+
// Title
|
|
187
|
+
title: string;
|
|
188
|
+
|
|
189
|
+
// Price
|
|
190
|
+
price: Price;
|
|
191
|
+
|
|
192
|
+
// Subscription Period
|
|
193
|
+
subscriptionPeriod: SubscriptionPeriod | null;
|
|
194
|
+
|
|
195
|
+
// Introductory Offer
|
|
196
|
+
introductoryPrice: IntroductoryOffer | null;
|
|
197
|
+
|
|
198
|
+
// Product Type
|
|
199
|
+
type: ProductType;
|
|
200
|
+
|
|
201
|
+
// Store
|
|
202
|
+
defaultOption: ProductOption;
|
|
203
|
+
|
|
204
|
+
// Options (for iOS)
|
|
205
|
+
options: ProductOption[];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
type ProductType = 'subscription' | 'non_subscription' | 'consumable';
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Price
|
|
212
|
+
|
|
213
|
+
Price information.
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
interface Price {
|
|
217
|
+
amount: number;
|
|
218
|
+
currencyCode: string;
|
|
219
|
+
formattedPrice: string;
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### SubscriptionPeriod
|
|
224
|
+
|
|
225
|
+
Duration of a subscription period.
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
interface SubscriptionPeriod {
|
|
229
|
+
value: number;
|
|
230
|
+
unit: 'day' | 'week' | 'month' | 'year';
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### IntroductoryOffer
|
|
235
|
+
|
|
236
|
+
Special pricing for new subscribers.
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
interface IntroductoryOffer {
|
|
240
|
+
price: Price;
|
|
241
|
+
period: SubscriptionPeriod;
|
|
242
|
+
periodNumberOfUnits: number;
|
|
243
|
+
cycles: number;
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### PurchaseResult
|
|
248
|
+
|
|
249
|
+
Result of a purchase operation.
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
interface PurchaseResult {
|
|
253
|
+
// Customer Information
|
|
254
|
+
customerInfo: CustomerInfo;
|
|
255
|
+
|
|
256
|
+
// Transaction
|
|
257
|
+
transaction: Transaction | null;
|
|
258
|
+
|
|
259
|
+
// Error (if failed)
|
|
260
|
+
error?: PurchasesError;
|
|
261
|
+
|
|
262
|
+
// Whether it was a renewal
|
|
263
|
+
isRenewal: boolean;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### RestoreResult
|
|
268
|
+
|
|
269
|
+
Result of a restore purchases operation.
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
interface RestoreResult {
|
|
273
|
+
// Customer Information
|
|
274
|
+
customerInfo: CustomerInfo;
|
|
275
|
+
|
|
276
|
+
// Error (if failed)
|
|
277
|
+
error?: PurchasesError;
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Transaction
|
|
282
|
+
|
|
283
|
+
Information about a purchase transaction.
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
interface Transaction {
|
|
287
|
+
transactionIdentifier: string;
|
|
288
|
+
productIdentifier: string;
|
|
289
|
+
purchaseDate: Date;
|
|
290
|
+
transactionDate: Date;
|
|
291
|
+
revenueCatId: string;
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Usage Examples
|
|
296
|
+
|
|
297
|
+
### Accessing Customer Info
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
const customerInfo: CustomerInfo = await getCustomerInfo();
|
|
301
|
+
|
|
302
|
+
// Check if user has premium
|
|
303
|
+
const premiumEntitlement = customerInfo.entitlements.premium;
|
|
304
|
+
if (premiumEntitlement?.isActive) {
|
|
305
|
+
console.log('User has premium');
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Get expiration date
|
|
309
|
+
const expirationDate = premiumEntitlement?.expirationDate;
|
|
310
|
+
console.log('Expires on:', expirationDate);
|
|
311
|
+
|
|
312
|
+
// Check active subscriptions
|
|
313
|
+
console.log('Active subscriptions:', customerInfo.activeSubscriptions);
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Working with Offerings
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
const offerings: Offerings = await getOfferings();
|
|
320
|
+
|
|
321
|
+
// Get current offering
|
|
322
|
+
const current = offerings.current;
|
|
323
|
+
if (current) {
|
|
324
|
+
// Get monthly package
|
|
325
|
+
const monthly = current.monthly;
|
|
326
|
+
console.log('Monthly price:', monthly?.localizedPriceString);
|
|
327
|
+
|
|
328
|
+
// Get all packages
|
|
329
|
+
current.availablePackages.forEach(pkg => {
|
|
330
|
+
console.log(pkg.identifier, pkg.localizedPriceString);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Handling Purchase Results
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
const result: PurchaseResult = await purchasePackage(selectedPackage);
|
|
339
|
+
|
|
340
|
+
if (result.error) {
|
|
341
|
+
console.error('Purchase failed:', result.error.message);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
console.log('Purchase successful!');
|
|
346
|
+
console.log('Transaction ID:', result.transaction?.transactionIdentifier);
|
|
347
|
+
|
|
348
|
+
// Check entitlement
|
|
349
|
+
if (result.customerInfo.entitlements.premium?.isActive) {
|
|
350
|
+
console.log('Premium is now active');
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Checking Entitlement Details
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
const entitlement: EntitlementInfo = customerInfo.entitlements.premium;
|
|
358
|
+
|
|
359
|
+
if (entitlement) {
|
|
360
|
+
console.log('Active:', entitlement.isActive);
|
|
361
|
+
console.log('Will Renew:', entitlement.willRenew);
|
|
362
|
+
console.log('Period Type:', entitlement.periodType);
|
|
363
|
+
console.log('Expiration:', entitlement.expirationDate);
|
|
364
|
+
console.log('Store:', entitlement.store);
|
|
365
|
+
console.log('Is Sandbox:', entitlement.isSandbox);
|
|
366
|
+
|
|
367
|
+
if (entitlement.billingIssueDetectedAt) {
|
|
368
|
+
console.warn('Billing issue detected');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (entitlement.unsubscribeDetectedAt) {
|
|
372
|
+
console.warn('User cancelled subscription');
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Related
|
|
378
|
+
|
|
379
|
+
- [RevenueCat Domain](../README.md)
|
|
380
|
+
- [RevenueCat Value Objects](../value-objects/README.md)
|
|
381
|
+
- [RevenueCat Errors](../errors/README.md)
|
|
382
|
+
- [RevenueCat Types](../types/README.md)
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# RevenueCat Domain Errors
|
|
2
|
+
|
|
3
|
+
Domain-specific errors for RevenueCat operations.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This directory contains custom error classes for RevenueCat-specific error conditions.
|
|
8
|
+
|
|
9
|
+
## Error Types
|
|
10
|
+
|
|
11
|
+
### PurchaseError
|
|
12
|
+
Base error for purchase failures.
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
class PurchaseError extends Error {
|
|
16
|
+
constructor(
|
|
17
|
+
message: string,
|
|
18
|
+
public code: string,
|
|
19
|
+
public underlyingError?: Error
|
|
20
|
+
) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = 'PurchaseError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Common Codes:**
|
|
28
|
+
- `PURCHASE_CANCELLED`: User cancelled purchase
|
|
29
|
+
- `PURCHASE_INVALID`: Invalid purchase data
|
|
30
|
+
- `NETWORK_ERROR`: Network connectivity issue
|
|
31
|
+
- `STORE_PROBLEM`: App store issue
|
|
32
|
+
|
|
33
|
+
### EntitlementNotFoundError
|
|
34
|
+
Thrown when expected entitlement is not found.
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
class EntitlementNotFoundError extends Error {
|
|
38
|
+
constructor(public entitlementId: string) {
|
|
39
|
+
super(
|
|
40
|
+
`Entitlement not found: ${entitlementId}`,
|
|
41
|
+
'ENTITLEMENT_NOT_FOUND'
|
|
42
|
+
);
|
|
43
|
+
this.name = 'EntitlementNotFoundError';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Usage:**
|
|
49
|
+
```typescript
|
|
50
|
+
import { EntitlementNotFoundError } from './errors/EntitlementNotFoundError';
|
|
51
|
+
|
|
52
|
+
function getEntitlement(customerInfo: CustomerInfo, id: string): Entitlement {
|
|
53
|
+
const entitlement = customerInfo.entitlements.active[id];
|
|
54
|
+
if (!entitlement) {
|
|
55
|
+
throw new EntitlementNotFoundError(id);
|
|
56
|
+
}
|
|
57
|
+
return entitlement;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### ConfigurationError
|
|
62
|
+
Thrown when RevenueCat configuration is invalid.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
class ConfigurationError extends Error {
|
|
66
|
+
constructor(missingConfig: string[]) {
|
|
67
|
+
super(
|
|
68
|
+
`RevenueCat not configured: ${missingConfig.join(', ')}`,
|
|
69
|
+
'CONFIGURATION_ERROR'
|
|
70
|
+
);
|
|
71
|
+
this.name = 'ConfigurationError';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Usage:**
|
|
77
|
+
```typescript
|
|
78
|
+
function validateRevenueCatConfig(config: any) {
|
|
79
|
+
const required = ['apiKey'];
|
|
80
|
+
const missing = required.filter(key => !config[key]);
|
|
81
|
+
|
|
82
|
+
if (missing.length > 0) {
|
|
83
|
+
throw new ConfigurationError(missing);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### OfferingNotFoundError
|
|
89
|
+
Thrown when requested offering is not available.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
class OfferingNotFoundError extends Error {
|
|
93
|
+
constructor(public offeringId: string) {
|
|
94
|
+
super(
|
|
95
|
+
`Offering not found: ${offeringId}`,
|
|
96
|
+
'OFFERING_NOT_FOUND'
|
|
97
|
+
);
|
|
98
|
+
this.name = 'OfferingNotFoundError';
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Error Handling Pattern
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import {
|
|
107
|
+
PurchaseError,
|
|
108
|
+
EntitlementNotFoundError,
|
|
109
|
+
ConfigurationError
|
|
110
|
+
} from './errors';
|
|
111
|
+
|
|
112
|
+
async function handlePurchase(package: Package) {
|
|
113
|
+
try {
|
|
114
|
+
const result = await Purchases.purchasePackage(package);
|
|
115
|
+
return { success: true, result };
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (error instanceof UserCancelledError) {
|
|
118
|
+
// User cancelled - not really an error
|
|
119
|
+
return { success: false, cancelled: true };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (error instanceof PurchaseError) {
|
|
123
|
+
switch (error.code) {
|
|
124
|
+
case 'PURCHASE_CANCELLED':
|
|
125
|
+
analytics.track('purchase_cancelled');
|
|
126
|
+
break;
|
|
127
|
+
case 'NETWORK_ERROR':
|
|
128
|
+
showRetryDialog();
|
|
129
|
+
break;
|
|
130
|
+
case 'STORE_PROBLEM':
|
|
131
|
+
showStoreProblemDialog();
|
|
132
|
+
break;
|
|
133
|
+
default:
|
|
134
|
+
showErrorDialog(error.message);
|
|
135
|
+
}
|
|
136
|
+
return { success: false, error };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Unexpected error
|
|
140
|
+
console.error('Unexpected purchase error:', error);
|
|
141
|
+
return { success: false, error };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Error Recovery
|
|
147
|
+
|
|
148
|
+
### Retry Logic
|
|
149
|
+
```typescript
|
|
150
|
+
async function purchaseWithRetry(pkg: Package, maxRetries = 3) {
|
|
151
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
152
|
+
try {
|
|
153
|
+
const result = await Purchases.purchasePackage(pkg);
|
|
154
|
+
return result;
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (error instanceof PurchaseError) {
|
|
157
|
+
if (error.code === 'NETWORK_ERROR' && i < maxRetries - 1) {
|
|
158
|
+
await delay(1000 * (i + 1)); // Exponential backoff
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### User-Friendly Messages
|
|
169
|
+
```typescript
|
|
170
|
+
function getUserFriendlyMessage(error: Error): string {
|
|
171
|
+
if (error instanceof PurchaseError) {
|
|
172
|
+
const messages: Record<string, string> = {
|
|
173
|
+
PURCHASE_CANCELLED: 'Purchase was cancelled',
|
|
174
|
+
NETWORK_ERROR: 'Network error. Please check your connection.',
|
|
175
|
+
STORE_PROBLEM: 'There was an issue with the app store.',
|
|
176
|
+
PURCHASE_INVALID: 'Purchase data is invalid.',
|
|
177
|
+
};
|
|
178
|
+
return messages[error.code] || 'An error occurred';
|
|
179
|
+
}
|
|
180
|
+
return error.message;
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Best Practices
|
|
185
|
+
|
|
186
|
+
1. **Specific Errors**: Use specific error types
|
|
187
|
+
2. **Error Codes**: Include machine-readable codes
|
|
188
|
+
3. **Context**: Include relevant data in error
|
|
189
|
+
4. **Recovery**: Implement recovery strategies
|
|
190
|
+
5. **User Feedback**: Convert errors to user-friendly messages
|
|
191
|
+
6. **Logging**: Log errors for debugging
|
|
192
|
+
7. **Analytics**: Track errors for monitoring
|
|
193
|
+
|
|
194
|
+
## Related
|
|
195
|
+
|
|
196
|
+
- [RevenueCat Domain](../README.md)
|
|
197
|
+
- [RevenueCat Services](../infrastructure/services/README.md)
|