@umituz/react-native-subscription 2.14.98 → 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/README.md +0 -1
- package/package.json +1 -1
- package/src/domains/README.md +240 -0
- package/src/domains/config/domain/README.md +390 -0
- package/src/domains/config/domain/entities/README.md +350 -0
- package/src/presentation/hooks/useDeductCredit.md +146 -130
- package/src/revenuecat/application/README.md +158 -0
- package/src/revenuecat/application/ports/README.md +169 -0
- package/src/revenuecat/domain/constants/README.md +183 -0
- package/src/revenuecat/domain/entities/README.md +382 -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/handlers/README.md +218 -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
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# RevenueCat Application Layer
|
|
2
|
+
|
|
3
|
+
Application layer for RevenueCat integration, containing use cases and orchestration logic.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This directory contains use cases and application-level operations for managing RevenueCat subscriptions and purchases.
|
|
8
|
+
|
|
9
|
+
## Structure
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
application/
|
|
13
|
+
└── ports/ # Interface definitions for RevenueCat services
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Ports
|
|
17
|
+
|
|
18
|
+
### IRevenueCatService
|
|
19
|
+
|
|
20
|
+
Main service interface for RevenueCat operations.
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
interface IRevenueCatService {
|
|
24
|
+
// Purchasing
|
|
25
|
+
purchasePackage(package: PurchasesPackage): Promise<PurchaseResult>;
|
|
26
|
+
restorePurchases(): Promise<RestoreResult>;
|
|
27
|
+
|
|
28
|
+
// Customer Info
|
|
29
|
+
getCustomerInfo(): Promise<CustomerInfo>;
|
|
30
|
+
getOfferings(): Promise<Offerings>;
|
|
31
|
+
|
|
32
|
+
// Configuration
|
|
33
|
+
configure(apiKey: string, userId?: string): Promise<void>;
|
|
34
|
+
|
|
35
|
+
// Entitlements
|
|
36
|
+
checkEntitlement(entitlementId: string): Promise<boolean>;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Use Cases
|
|
41
|
+
|
|
42
|
+
### Purchase Flow
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
async function purchasePremiumPackage(userId: string) {
|
|
46
|
+
const service = getRevenueCatService();
|
|
47
|
+
|
|
48
|
+
// 1. Get offerings
|
|
49
|
+
const offerings = await service.getOfferings();
|
|
50
|
+
const package = offerings.current?.monthly;
|
|
51
|
+
|
|
52
|
+
if (!package) {
|
|
53
|
+
throw new Error('No package available');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 2. Purchase
|
|
57
|
+
const result = await service.purchasePackage(package);
|
|
58
|
+
|
|
59
|
+
// 3. Handle result
|
|
60
|
+
if (result.error) {
|
|
61
|
+
throw new Error(result.error.message);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 4. Update local state
|
|
65
|
+
await updateSubscriptionStatus(userId, result.customerInfo);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Restore Purchases
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
async function restoreUserPurchases() {
|
|
73
|
+
const service = getRevenueCatService();
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const result = await service.restorePurchases();
|
|
77
|
+
|
|
78
|
+
if (result.error) {
|
|
79
|
+
throw new Error(result.error.message);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Update local subscription status
|
|
83
|
+
await updateSubscriptionStatusFromRestored(result.customerInfo);
|
|
84
|
+
|
|
85
|
+
return { success: true, customerInfo: result.customerInfo };
|
|
86
|
+
} catch (error) {
|
|
87
|
+
return { success: false, error };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Check Entitlement
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
async function checkPremiumAccess(userId: string): Promise<boolean> {
|
|
96
|
+
const service = getRevenueCatService();
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const hasPremium = await service.checkEntitlement('premium');
|
|
100
|
+
|
|
101
|
+
if (hasPremium) {
|
|
102
|
+
await activatePremiumStatus(userId);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return hasPremium;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error('Failed to check entitlement:', error);
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Best Practices
|
|
114
|
+
|
|
115
|
+
1. **Error Handling**: Always handle RevenueCat errors gracefully
|
|
116
|
+
2. **User ID**: Provide user ID when available for better tracking
|
|
117
|
+
3. **Entitlements**: Use entitlements instead of product IDs for flexibility
|
|
118
|
+
4. **Offerings**: Check if offerings are available before purchasing
|
|
119
|
+
5. **Validation**: Validate customer info after purchases
|
|
120
|
+
6. **Sync**: Keep local state synchronized with RevenueCat
|
|
121
|
+
7. **Timeouts**: Handle network timeouts appropriately
|
|
122
|
+
8. **Logging**: Log all RevenueCat operations for debugging
|
|
123
|
+
|
|
124
|
+
## Error Handling
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { PurchaseError } from '../domain/errors';
|
|
128
|
+
|
|
129
|
+
async function safePurchase(pkg: PurchasesPackage) {
|
|
130
|
+
try {
|
|
131
|
+
const result = await service.purchasePackage(pkg);
|
|
132
|
+
|
|
133
|
+
if (result.error) {
|
|
134
|
+
// Map RevenueCat errors to domain errors
|
|
135
|
+
if (result.error.code === 'PURCHASE_CANCELLED') {
|
|
136
|
+
throw new PurchaseError('User cancelled purchase');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
throw new PurchaseError(result.error.message);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return result;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
if (error instanceof PurchaseError) {
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
throw new PurchaseError('Purchase failed', { cause: error });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Related
|
|
154
|
+
|
|
155
|
+
- [RevenueCat Integration](../README.md)
|
|
156
|
+
- [RevenueCat Domain](../domain/README.md)
|
|
157
|
+
- [RevenueCat Infrastructure](../infrastructure/README.md)
|
|
158
|
+
- [Application Ports](./ports/README.md)
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# RevenueCat Application Ports
|
|
2
|
+
|
|
3
|
+
Interface definitions for RevenueCat service layer.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This directory defines the ports (interfaces) that the RevenueCat infrastructure must implement. Following Dependency Inversion Principle, the application layer depends on these abstractions rather than concrete implementations.
|
|
8
|
+
|
|
9
|
+
## Ports
|
|
10
|
+
|
|
11
|
+
### IRevenueCatService
|
|
12
|
+
|
|
13
|
+
Core service interface for RevenueCat operations.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
interface IRevenueCatService {
|
|
17
|
+
// Configuration
|
|
18
|
+
configure(params: {
|
|
19
|
+
apiKey: string;
|
|
20
|
+
userId?: string;
|
|
21
|
+
observerMode?: boolean;
|
|
22
|
+
}): Promise<void>;
|
|
23
|
+
|
|
24
|
+
// Purchasing Operations
|
|
25
|
+
purchasePackage(pkg: PurchasesPackage): Promise<PurchaseResult>;
|
|
26
|
+
purchaseProduct(productId: string): Promise<PurchaseResult>;
|
|
27
|
+
restorePurchases(): Promise<RestoreResult>;
|
|
28
|
+
|
|
29
|
+
// Customer Information
|
|
30
|
+
getCustomerInfo(): Promise<CustomerInfo>;
|
|
31
|
+
getCustomerInfoUserId(): string | null;
|
|
32
|
+
|
|
33
|
+
// Offerings
|
|
34
|
+
getOfferings(): Promise<Offerings>;
|
|
35
|
+
getCurrentOffering(): Promise<Offering | null>;
|
|
36
|
+
|
|
37
|
+
// Entitlements
|
|
38
|
+
checkEntitlement(entitlementId: string): Promise<boolean>;
|
|
39
|
+
checkEntitlementInfo(entitlementId: string): Promise<EntitlementInfo | null>;
|
|
40
|
+
|
|
41
|
+
// Subscriber Attributes
|
|
42
|
+
setAttributes(attributes: SubscriberAttributes): Promise<void>;
|
|
43
|
+
setEmail(email: string): Promise<void>;
|
|
44
|
+
setPhoneNumber(phoneNumber: string): Promise<void>;
|
|
45
|
+
|
|
46
|
+
// Log Out
|
|
47
|
+
logOut(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### IRevenueCatPurchaseHandler
|
|
52
|
+
|
|
53
|
+
Handles purchase callbacks and results.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
interface IRevenueCatPurchaseHandler {
|
|
57
|
+
onPurchaseStarted?(package: PurchasesPackage): void;
|
|
58
|
+
onPurchaseSuccess?(result: PurchaseResult): void;
|
|
59
|
+
onPurchaseError?(error: PurchaseError): void;
|
|
60
|
+
onPurchaseCancelled?(result: PurchaseResult): void;
|
|
61
|
+
onRestoreStarted?(): void;
|
|
62
|
+
onRestoreSuccess?(result: RestoreResult): void;
|
|
63
|
+
onRestoreError?(error: Error): void;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### IRevenueCatCustomerInfoListener
|
|
68
|
+
|
|
69
|
+
Listens to customer info changes.
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
interface IRevenueCatCustomerInfoListener {
|
|
73
|
+
onCustomerInfoChanged(customerInfo: CustomerInfo): void;
|
|
74
|
+
onEntitlementsChanged(entitlements: EntitlementInfos): void;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Usage
|
|
79
|
+
|
|
80
|
+
### Injecting Dependencies
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import type { IRevenueCatService } from './ports/IRevenueCatService';
|
|
84
|
+
|
|
85
|
+
class PurchaseManager {
|
|
86
|
+
constructor(
|
|
87
|
+
private revenueCatService: IRevenueCatService
|
|
88
|
+
) {}
|
|
89
|
+
|
|
90
|
+
async purchasePremium() {
|
|
91
|
+
const offerings = await this.revenueCatService.getOfferings();
|
|
92
|
+
const package = offerings.current?.monthly;
|
|
93
|
+
|
|
94
|
+
if (!package) {
|
|
95
|
+
throw new Error('No package available');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return await this.revenueCatService.purchasePackage(package);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Implementing Ports
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import type { IRevenueCatService } from './ports/IRevenueCatService';
|
|
107
|
+
import { Purchases } from '@revenuecat/purchases-capacitor';
|
|
108
|
+
|
|
109
|
+
class RevenueCatServiceImpl implements IRevenueCatService {
|
|
110
|
+
async configure(params: {
|
|
111
|
+
apiKey: string;
|
|
112
|
+
userId?: string;
|
|
113
|
+
observerMode?: boolean;
|
|
114
|
+
}): Promise<void> {
|
|
115
|
+
await Purchases.configure({
|
|
116
|
+
apiKey: params.apiKey,
|
|
117
|
+
appUserID: params.userId,
|
|
118
|
+
observerMode: params.observerMode ?? false,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async purchasePackage(pkg: PurchasesPackage): Promise<PurchaseResult> {
|
|
123
|
+
return await Purchases.purchasePackage({
|
|
124
|
+
aPackage: pkg,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ... other implementations
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Provide implementation
|
|
132
|
+
const revenueCatService: IRevenueCatService = new RevenueCatServiceImpl();
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Benefits of Ports
|
|
136
|
+
|
|
137
|
+
1. **Testability**: Easy to mock for testing
|
|
138
|
+
2. **Flexibility**: Can swap implementations
|
|
139
|
+
3. **Decoupling**: Application layer doesn't depend on concrete implementations
|
|
140
|
+
4. **Maintainability**: Clear contracts between layers
|
|
141
|
+
|
|
142
|
+
## Testing with Mocks
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import type { IRevenueCatService } from './ports/IRevenueCatService';
|
|
146
|
+
|
|
147
|
+
const mockRevenueCatService: IRevenueCatService = {
|
|
148
|
+
configure: vi.fn().mockResolvedValue(undefined),
|
|
149
|
+
purchasePackage: vi.fn().mockResolvedValue({
|
|
150
|
+
customerInfo: mockCustomerInfo,
|
|
151
|
+
}),
|
|
152
|
+
restorePurchases: vi.fn().mockResolvedValue({
|
|
153
|
+
customerInfo: mockCustomerInfo,
|
|
154
|
+
}),
|
|
155
|
+
getCustomerInfo: vi.fn().mockResolvedValue(mockCustomerInfo),
|
|
156
|
+
getOfferings: vi.fn().mockResolvedValue(mockOfferings),
|
|
157
|
+
checkEntitlement: vi.fn().mockResolvedValue(true),
|
|
158
|
+
// ... other methods
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Use in tests
|
|
162
|
+
const manager = new PurchaseManager(mockRevenueCatService);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Related
|
|
166
|
+
|
|
167
|
+
- [RevenueCat Application Layer](../README.md)
|
|
168
|
+
- [RevenueCat Infrastructure](../infrastructure/README.md)
|
|
169
|
+
- [RevenueCat Domain](../domain/README.md)
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# RevenueCat Domain Constants
|
|
2
|
+
|
|
3
|
+
Constants used throughout the RevenueCat integration.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This directory contains constant definitions for RevenueCat-specific values including entitlement IDs, error codes, and configuration defaults.
|
|
8
|
+
|
|
9
|
+
## Constants
|
|
10
|
+
|
|
11
|
+
### Entitlement IDs
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
export const ENTITLEMENT_IDS = {
|
|
15
|
+
PREMIUM: 'premium',
|
|
16
|
+
PRO: 'pro',
|
|
17
|
+
LIFETIME: 'lifetime',
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
export type EntitlementId = typeof ENTITLEMENT_IDS[keyof typeof ENTITLEMENT_IDS];
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Offering Identifiers
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
export const OFFERING_IDS = {
|
|
27
|
+
DEFAULT: 'default',
|
|
28
|
+
ANNUAL_OFFER: 'annual_offer',
|
|
29
|
+
LIFETIME_OFFER: 'lifetime_offer',
|
|
30
|
+
} as const;
|
|
31
|
+
|
|
32
|
+
export type OfferingId = typeof OFFERING_IDS[keyof typeof OFFERING_IDS];
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Package Periods
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
export const PACKAGE_PERIODS = {
|
|
39
|
+
MONTHLY: 'monthly',
|
|
40
|
+
ANNUAL: 'annual',
|
|
41
|
+
LIFETIME: 'lifetime',
|
|
42
|
+
WEEKLY: 'weekly',
|
|
43
|
+
} as const;
|
|
44
|
+
|
|
45
|
+
export type PackagePeriod = typeof PACKAGE_PERIODS[keyof typeof PACKAGE_PERIODS];
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Product Categories
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
export const PRODUCT_CATEGORIES = {
|
|
52
|
+
SUBSCRIPTION: 'subscription',
|
|
53
|
+
ONE_TIME_PURCHASE: 'non_subscription',
|
|
54
|
+
CONSUMABLE: 'consumable',
|
|
55
|
+
} as const;
|
|
56
|
+
|
|
57
|
+
export type ProductCategory = typeof PRODUCT_CATEGORIES[keyof typeof PRODUCT_CATEGORIES];
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Error Codes
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
export const ERROR_CODES = {
|
|
64
|
+
// Configuration Errors
|
|
65
|
+
CONFIGURATION_ERROR: 'CONFIGURATION_ERROR',
|
|
66
|
+
API_KEY_NOT_SET: 'API_KEY_NOT_SET',
|
|
67
|
+
INVALID_API_KEY: 'INVALID_API_KEY',
|
|
68
|
+
|
|
69
|
+
// Purchase Errors
|
|
70
|
+
PURCHASE_ERROR: 'PURCHASE_ERROR',
|
|
71
|
+
PURCHASE_CANCELLED: 'PURCHASE_CANCELLED',
|
|
72
|
+
PURCHASE_INVALID: 'PURCHASE_INVALID',
|
|
73
|
+
PRODUCT_NOT_AVAILABLE: 'PRODUCT_NOT_AVAILABLE',
|
|
74
|
+
|
|
75
|
+
// Network Errors
|
|
76
|
+
NETWORK_ERROR: 'NETWORK_ERROR',
|
|
77
|
+
CONNECTION_TIMEOUT: 'CONNECTION_TIMEOUT',
|
|
78
|
+
SERVER_ERROR: 'SERVER_ERROR',
|
|
79
|
+
|
|
80
|
+
// Customer Info Errors
|
|
81
|
+
CUSTOMER_INFO_ERROR: 'CUSTOMER_INFO_ERROR',
|
|
82
|
+
ENTITLEMENT_NOT_FOUND: 'ENTITLEMENT_NOT_FOUND',
|
|
83
|
+
OFFERING_NOT_FOUND: 'OFFERING_NOT_FOUND',
|
|
84
|
+
|
|
85
|
+
// Receipt Errors
|
|
86
|
+
RECEIPT_ERROR: 'RECEIPT_ERROR',
|
|
87
|
+
RECEIPT_INVALID: 'RECEIPT_INVALID',
|
|
88
|
+
RECEIPT_ALREADY_USED: 'RECEIPT_ALREADY_USES',
|
|
89
|
+
|
|
90
|
+
// User Errors
|
|
91
|
+
USER_NOT_AUTHENTICATED: 'USER_NOT_AUTHENTICATED',
|
|
92
|
+
USER_ID_NOT_SET: 'USER_ID_NOT_SET',
|
|
93
|
+
} as const;
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Configuration Defaults
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
export const CONFIG_DEFAULTS = {
|
|
100
|
+
// Timeout Settings
|
|
101
|
+
NETWORK_TIMEOUT_MS: 10000,
|
|
102
|
+
PURCHASE_TIMEOUT_MS: 30000,
|
|
103
|
+
|
|
104
|
+
// Retry Settings
|
|
105
|
+
MAX_RETRIES: 3,
|
|
106
|
+
RETRY_DELAY_MS: 1000,
|
|
107
|
+
|
|
108
|
+
// Cache Settings
|
|
109
|
+
CUSTOMER_INFO_CACHE_TTL_MS: 60000, // 1 minute
|
|
110
|
+
OFFERINGS_CACHE_TTL_MS: 300000, // 5 minutes
|
|
111
|
+
|
|
112
|
+
// Debug Settings
|
|
113
|
+
ENABLE_DEBUG_LOGS: __DEV__,
|
|
114
|
+
LOG_LEVEL: 'info' as const,
|
|
115
|
+
} as const;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Entitlement Verification
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
export const ENTITLEMENT_VERIFICATION = {
|
|
122
|
+
// Verification Modes
|
|
123
|
+
MODE_STRICT: 'strict',
|
|
124
|
+
MODE_LOOSE: 'loose',
|
|
125
|
+
|
|
126
|
+
// Grace Periods (milliseconds)
|
|
127
|
+
GRACE_PERIOD_MS: 3 * 24 * 60 * 60 * 1000, // 3 days
|
|
128
|
+
REFUND_GRACE_PERIOD_MS: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
129
|
+
} as const;
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Usage Examples
|
|
133
|
+
|
|
134
|
+
### Checking Entitlements
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { ENTITLEMENT_IDS } from './constants';
|
|
138
|
+
|
|
139
|
+
const hasPremium = await checkEntitlement(ENTITLEMENT_IDS.PREMIUM);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Filtering Offerings
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { OFFERING_IDS } from './constants';
|
|
146
|
+
|
|
147
|
+
const defaultOffering = offerings[OFFERING_IDS.DEFAULT];
|
|
148
|
+
const annualOffering = offerings[OFFERING_IDS.ANNUAL_OFFER];
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Handling Errors
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { ERROR_CODES } from './constants';
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
await purchasePackage(pkg);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
if (error.code === ERROR_CODES.PURCHASE_CANCELLED) {
|
|
160
|
+
// Handle cancellation
|
|
161
|
+
} else if (error.code === ERROR_CODES.NETWORK_ERROR) {
|
|
162
|
+
// Handle network error
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Configuration
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { CONFIG_DEFAULTS } from './constants';
|
|
171
|
+
|
|
172
|
+
const config = {
|
|
173
|
+
apiKey: 'your_api_key',
|
|
174
|
+
timeout: CONFIG_DEFAULTS.NETWORK_TIMEOUT_MS,
|
|
175
|
+
enableDebugLogs: CONFIG_DEFAULTS.ENABLE_DEBUG_LOGS,
|
|
176
|
+
};
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Related
|
|
180
|
+
|
|
181
|
+
- [RevenueCat Domain](../README.md)
|
|
182
|
+
- [RevenueCat Errors](../errors/README.md)
|
|
183
|
+
- [RevenueCat Entities](../entities/README.md)
|