@umituz/react-native-subscription 2.14.99 → 2.14.101
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 +211 -394
- package/package.json +3 -3
- package/src/application/README.md +46 -225
- package/src/application/ports/README.md +42 -97
- package/src/domain/README.md +36 -384
- package/src/domain/constants/README.md +0 -56
- package/src/domain/entities/README.md +43 -169
- package/src/domain/entities/SubscriptionStatus.ts +1 -1
- package/src/domain/errors/README.md +33 -287
- package/src/domain/value-objects/README.md +43 -179
- package/src/domains/README.md +50 -238
- package/src/domains/README.md.bak +274 -0
- package/src/domains/config/README.md +93 -383
- package/src/domains/config/domain/README.md +23 -376
- package/src/domains/config/domain/entities/README.md +34 -343
- package/src/domains/paywall/README.md +99 -369
- package/src/domains/paywall/components/README.md +34 -178
- package/src/domains/paywall/entities/README.md +34 -193
- package/src/domains/paywall/hooks/README.md +34 -122
- package/src/domains/wallet/README.md +34 -275
- package/src/domains/wallet/README.md.bak +209 -0
- package/src/domains/wallet/domain/README.md +34 -101
- package/src/domains/wallet/domain/entities/README.md +34 -115
- package/src/domains/wallet/domain/errors/README.md +34 -151
- package/src/domains/wallet/infrastructure/README.md +34 -89
- package/src/domains/wallet/presentation/components/README.md +34 -224
- package/src/domains/wallet/presentation/components/TransactionItem.tsx +1 -1
- package/src/domains/wallet/presentation/hooks/README.md +34 -248
- package/src/infrastructure/README.md +37 -496
- package/src/infrastructure/mappers/README.md +0 -13
- package/src/infrastructure/repositories/README.md +74 -360
- package/src/infrastructure/services/ActivationHandler.ts +1 -1
- package/src/infrastructure/services/README.md +95 -370
- package/src/infrastructure/services/SubscriptionService.ts +1 -1
- package/src/presentation/README.md +123 -408
- package/src/presentation/README.md.bak +172 -0
- package/src/presentation/components/README.md +151 -179
- package/src/presentation/components/README.md.bak +217 -0
- package/src/presentation/components/details/CreditRow.md +65 -310
- package/src/presentation/components/details/DetailRow.md +63 -255
- package/src/presentation/components/details/PremiumDetailsCard.md +65 -238
- package/src/presentation/components/details/PremiumStatusBadge.md +64 -239
- package/src/presentation/components/details/README.md +97 -447
- package/src/presentation/components/feedback/PaywallFeedbackModal.md +63 -287
- package/src/presentation/components/feedback/README.md +97 -445
- package/src/presentation/components/paywall/PaywallModal.md +66 -416
- package/src/presentation/components/paywall/README.md +50 -186
- package/src/presentation/components/sections/README.md +97 -466
- package/src/presentation/components/sections/SubscriptionSection.md +92 -244
- package/src/presentation/hooks/README.md +154 -741
- package/src/presentation/hooks/useAuthAwarePurchase.md +58 -325
- package/src/presentation/hooks/useAuthGate.md +61 -375
- package/src/presentation/hooks/useAuthSubscriptionSync.md +66 -370
- package/src/presentation/hooks/useCreditChecker.md +73 -378
- package/src/presentation/hooks/useCredits.md +74 -313
- package/src/presentation/hooks/useCredits.md.bak +231 -0
- package/src/presentation/hooks/useCreditsGate.md +66 -318
- package/src/presentation/hooks/useDeductCredit.md +0 -76
- package/src/presentation/hooks/useDeductCredit.ts +1 -1
- package/src/presentation/hooks/useDevTestCallbacks.md +63 -394
- package/src/presentation/hooks/useFeatureGate.md +105 -150
- package/src/presentation/hooks/useFeatureGate.md.bak +284 -0
- package/src/presentation/hooks/useInitializeCredits.md +64 -430
- package/src/presentation/hooks/usePaywall.md +61 -306
- package/src/presentation/hooks/usePaywallOperations.md +64 -458
- package/src/presentation/hooks/usePaywallVisibility.md +67 -316
- package/src/presentation/hooks/usePremium.md +84 -226
- package/src/presentation/hooks/usePremiumGate.md +60 -395
- package/src/presentation/hooks/usePremiumWithCredits.md +64 -401
- package/src/presentation/hooks/useSubscription.md +66 -422
- package/src/presentation/hooks/useSubscriptionDetails.md +65 -410
- package/src/presentation/hooks/useSubscriptionGate.md +80 -164
- package/src/presentation/hooks/useSubscriptionSettingsConfig.md +66 -346
- package/src/presentation/hooks/useSubscriptionStatus.md +66 -396
- package/src/presentation/hooks/useUserTier.md +63 -328
- package/src/presentation/hooks/useUserTierWithRepository.md +64 -424
- package/src/presentation/screens/README.md +48 -190
- package/src/presentation/types/README.md +0 -16
- package/src/presentation/utils/README.md +0 -21
- package/src/presentation/utils/subscriptionDateUtils.ts +1 -1
- package/src/revenuecat/README.md +99 -518
- package/src/revenuecat/application/README.md +35 -150
- package/src/revenuecat/application/ports/README.md +34 -162
- package/src/revenuecat/domain/README.md +42 -141
- package/src/revenuecat/domain/constants/README.md +34 -176
- package/src/revenuecat/domain/entities/README.md +34 -374
- package/src/revenuecat/domain/errors/README.md +47 -191
- package/src/revenuecat/domain/types/README.md +34 -366
- package/src/revenuecat/domain/value-objects/README.md +34 -434
- package/src/revenuecat/infrastructure/README.md +34 -43
- package/src/revenuecat/infrastructure/config/README.md +32 -23
- package/src/revenuecat/infrastructure/handlers/README.md +34 -211
- package/src/revenuecat/infrastructure/managers/README.md +34 -42
- package/src/revenuecat/infrastructure/services/README.md +35 -318
- package/src/revenuecat/infrastructure/utils/README.md +34 -375
- package/src/revenuecat/presentation/README.md +34 -176
- package/src/revenuecat/presentation/hooks/README.md +29 -35
- package/src/utils/README.md +38 -525
|
@@ -1,390 +1,37 @@
|
|
|
1
1
|
# Config Domain
|
|
2
2
|
|
|
3
|
+
## Location
|
|
3
4
|
Domain layer for configuration management.
|
|
4
5
|
|
|
5
|
-
##
|
|
6
|
-
|
|
6
|
+
## Strategy
|
|
7
7
|
This directory contains the business logic and domain models for subscription and feature configuration.
|
|
8
8
|
|
|
9
|
-
##
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
domain/
|
|
13
|
-
├── entities/ # Configuration entities
|
|
14
|
-
└── value-objects/ # Configuration value objects
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Entities
|
|
18
|
-
|
|
19
|
-
### PackageConfig
|
|
20
|
-
|
|
21
|
-
Represents a subscription package configuration.
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
class PackageConfig {
|
|
25
|
-
readonly identifier: string;
|
|
26
|
-
readonly productId: string;
|
|
27
|
-
readonly period: PackagePeriod;
|
|
28
|
-
readonly price: Money;
|
|
29
|
-
readonly features: Feature[];
|
|
30
|
-
readonly credits?: number;
|
|
31
|
-
readonly metadata: PackageMetadata;
|
|
32
|
-
|
|
33
|
-
constructor(config: PackageConfigData) {
|
|
34
|
-
this.identifier = config.identifier;
|
|
35
|
-
this.productId = config.productId;
|
|
36
|
-
this.period = config.period;
|
|
37
|
-
this.price = new Money(config.price, config.currency);
|
|
38
|
-
this.features = config.features;
|
|
39
|
-
this.credits = config.credits;
|
|
40
|
-
this.metadata = config.metadata || {};
|
|
41
|
-
this.validate();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
private validate(): void {
|
|
45
|
-
if (!this.identifier) {
|
|
46
|
-
throw new Error('Package identifier is required');
|
|
47
|
-
}
|
|
48
|
-
if (!this.productId) {
|
|
49
|
-
throw new Error('Product ID is required');
|
|
50
|
-
}
|
|
51
|
-
if (this.price.getAmount() < 0) {
|
|
52
|
-
throw new Error('Price cannot be negative');
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
isAnnual(): boolean {
|
|
57
|
-
return this.period === 'annual';
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
isMonthly(): boolean {
|
|
61
|
-
return this.period === 'monthly';
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
isLifetime(): boolean {
|
|
65
|
-
return this.period === 'lifetime';
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
hasCredits(): boolean {
|
|
69
|
-
return !!this.credits && this.credits > 0;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
isRecommended(): boolean {
|
|
73
|
-
return this.metadata.recommended === true;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
isHighlighted(): boolean {
|
|
77
|
-
return this.metadata.highlight === true;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
getDiscountPercentage(): number | null {
|
|
81
|
-
return this.metadata.discount?.percentage ?? null;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
getBadge(): string | null {
|
|
85
|
-
return this.metadata.badge ?? null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
getPerMonthPrice(): Money | null {
|
|
89
|
-
if (this.period === 'monthly') {
|
|
90
|
-
return this.price;
|
|
91
|
-
}
|
|
92
|
-
if (this.period === 'annual') {
|
|
93
|
-
return this.price.divide(12);
|
|
94
|
-
}
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### FeatureConfig
|
|
101
|
-
|
|
102
|
-
Represents a feature configuration.
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
class FeatureConfig {
|
|
106
|
-
readonly id: string;
|
|
107
|
-
readonly name: string;
|
|
108
|
-
readonly description?: string;
|
|
109
|
-
readonly requiresPremium: boolean;
|
|
110
|
-
readonly requiresCredits: boolean;
|
|
111
|
-
readonly creditCost?: number;
|
|
112
|
-
readonly enabled: boolean;
|
|
113
|
-
readonly gateType: 'premium' | 'credits' | 'both';
|
|
114
|
-
|
|
115
|
-
constructor(config: FeatureConfigData) {
|
|
116
|
-
this.id = config.id;
|
|
117
|
-
this.name = config.name;
|
|
118
|
-
this.description = config.description;
|
|
119
|
-
this.requiresPremium = config.requiresPremium;
|
|
120
|
-
this.requiresCredits = config.requiresCredits ?? false;
|
|
121
|
-
this.creditCost = config.creditCost;
|
|
122
|
-
this.enabled = config.enabled ?? true;
|
|
123
|
-
this.gateType = config.gateType ?? this.inferGateType();
|
|
124
|
-
this.validate();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
private inferGateType(): 'premium' | 'credits' | 'both' {
|
|
128
|
-
if (this.requiresPremium && this.requiresCredits) {
|
|
129
|
-
return 'both';
|
|
130
|
-
}
|
|
131
|
-
if (this.requiresPremium) {
|
|
132
|
-
return 'premium';
|
|
133
|
-
}
|
|
134
|
-
return 'credits';
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
private validate(): void {
|
|
138
|
-
if (!this.id) {
|
|
139
|
-
throw new Error('Feature ID is required');
|
|
140
|
-
}
|
|
141
|
-
if (this.requiresCredits && !this.creditCost) {
|
|
142
|
-
throw new Error('Credit cost required when requiresCredits is true');
|
|
143
|
-
}
|
|
144
|
-
if (this.creditCost && this.creditCost < 0) {
|
|
145
|
-
throw new Error('Credit cost cannot be negative');
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
isAccessible(userHasPremium: boolean, userCredits: number): boolean {
|
|
150
|
-
if (!this.enabled) {
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (this.gateType === 'premium') {
|
|
155
|
-
return userHasPremium;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (this.gateType === 'credits') {
|
|
159
|
-
return userCredits >= (this.creditCost ?? 0);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (this.gateType === 'both') {
|
|
163
|
-
return userHasPremium && userCredits >= (this.creditCost ?? 0);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
getRequiredCredits(): number {
|
|
170
|
-
return this.creditCost ?? 0;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### PaywallConfig
|
|
176
|
-
|
|
177
|
-
Represents paywall configuration.
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
class PaywallConfig {
|
|
181
|
-
readonly id: string;
|
|
182
|
-
readonly title: string;
|
|
183
|
-
readonly subtitle?: string;
|
|
184
|
-
readonly features: string[];
|
|
185
|
-
readonly packages: PackageConfig[];
|
|
186
|
-
readonly highlightPackage?: string;
|
|
187
|
-
readonly style: PaywallStyle;
|
|
188
|
-
readonly triggers: PaywallTrigger[];
|
|
189
|
-
|
|
190
|
-
constructor(config: PaywallConfigData) {
|
|
191
|
-
this.id = config.id;
|
|
192
|
-
this.title = config.title;
|
|
193
|
-
this.subtitle = config.subtitle;
|
|
194
|
-
this.features = config.features;
|
|
195
|
-
this.packages = config.packages.map(p => new PackageConfig(p));
|
|
196
|
-
this.highlightPackage = config.highlightPackage;
|
|
197
|
-
this.style = config.style;
|
|
198
|
-
this.triggers = config.triggers ?? [];
|
|
199
|
-
this.validate();
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
private validate(): void {
|
|
203
|
-
if (!this.id) {
|
|
204
|
-
throw new Error('Paywall ID is required');
|
|
205
|
-
}
|
|
206
|
-
if (this.packages.length === 0) {
|
|
207
|
-
throw new Error('At least one package is required');
|
|
208
|
-
}
|
|
209
|
-
if (this.highlightPackage) {
|
|
210
|
-
const exists = this.packages.some(p => p.identifier === this.highlightPackage);
|
|
211
|
-
if (!exists) {
|
|
212
|
-
throw new Error('Highlight package not found');
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
getHighlightedPackage(): PackageConfig | null {
|
|
218
|
-
if (!this.highlightPackage) {
|
|
219
|
-
return this.packages.find(p => p.isHighlighted()) ?? null;
|
|
220
|
-
}
|
|
221
|
-
return this.packages.find(p => p.identifier === this.highlightPackage) ?? null;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
getPackageByIdentifier(identifier: string): PackageConfig | null {
|
|
225
|
-
return this.packages.find(p => p.identifier === identifier) ?? null;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
shouldTrigger(triggerType: string): boolean {
|
|
229
|
-
return this.triggers.some(t => t.type === triggerType);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
## Value Objects
|
|
235
|
-
|
|
236
|
-
### PackagePeriod
|
|
237
|
-
|
|
238
|
-
```typescript
|
|
239
|
-
class PackagePeriod {
|
|
240
|
-
readonly value: 'monthly' | 'annual' | 'lifetime' | 'weekly';
|
|
241
|
-
|
|
242
|
-
constructor(value: string) {
|
|
243
|
-
const valid = ['monthly', 'annual', 'lifetime', 'weekly'];
|
|
244
|
-
if (!valid.includes(value)) {
|
|
245
|
-
throw new Error(`Invalid period: ${value}`);
|
|
246
|
-
}
|
|
247
|
-
this.value = value as PackagePeriod['value'];
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
isRecurring(): boolean {
|
|
251
|
-
return this.value === 'monthly' || this.value === 'annual' || this.value === 'weekly';
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
getDurationInMonths(): number | null {
|
|
255
|
-
switch (this.value) {
|
|
256
|
-
case 'monthly': return 1;
|
|
257
|
-
case 'annual': return 12;
|
|
258
|
-
case 'weekly': return 1 / 4;
|
|
259
|
-
case 'lifetime': return null;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
toString(): string {
|
|
264
|
-
return this.value;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### Money
|
|
270
|
-
|
|
271
|
-
```typescript
|
|
272
|
-
class Money {
|
|
273
|
-
readonly amount: number;
|
|
274
|
-
readonly currency: string;
|
|
275
|
-
|
|
276
|
-
constructor(amount: number, currency: string) {
|
|
277
|
-
if (amount < 0) {
|
|
278
|
-
throw new Error('Amount cannot be negative');
|
|
279
|
-
}
|
|
280
|
-
this.amount = amount;
|
|
281
|
-
this.currency = currency;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
format(locale: string = 'en-US'): string {
|
|
285
|
-
return new Intl.NumberFormat(locale, {
|
|
286
|
-
style: 'currency',
|
|
287
|
-
currency: this.currency,
|
|
288
|
-
}).format(this.amount);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
divide(factor: number): Money {
|
|
292
|
-
return new Money(this.amount / factor, this.currency);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
multiply(factor: number): Money {
|
|
296
|
-
return new Money(this.amount * factor, this.currency);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
equals(other: Money): boolean {
|
|
300
|
-
return this.amount === other.amount && this.currency === other.currency;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
## Usage
|
|
306
|
-
|
|
307
|
-
### Creating Package Configuration
|
|
308
|
-
|
|
309
|
-
```typescript
|
|
310
|
-
import { PackageConfig } from './entities/PackageConfig';
|
|
311
|
-
|
|
312
|
-
const monthlyPackage = new PackageConfig({
|
|
313
|
-
identifier: 'premium_monthly',
|
|
314
|
-
productId: 'com.app.premium.monthly',
|
|
315
|
-
period: 'monthly',
|
|
316
|
-
price: 9.99,
|
|
317
|
-
currency: 'USD',
|
|
318
|
-
features: ['Unlimited Access', 'Ad-Free'],
|
|
319
|
-
credits: 100,
|
|
320
|
-
metadata: {
|
|
321
|
-
recommended: true,
|
|
322
|
-
badge: 'Most Popular',
|
|
323
|
-
},
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
console.log(monthlyPackage.isMonthly()); // true
|
|
327
|
-
console.log(monthlyPackage.getPerMonthPrice()?.format()); // '$9.99'
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
### Creating Feature Configuration
|
|
331
|
-
|
|
332
|
-
```typescript
|
|
333
|
-
import { FeatureConfig } from './entities/FeatureConfig';
|
|
334
|
-
|
|
335
|
-
const aiFeature = new FeatureConfig({
|
|
336
|
-
id: 'ai_generation',
|
|
337
|
-
name: 'AI Generation',
|
|
338
|
-
description: 'Generate AI content',
|
|
339
|
-
requiresPremium: false,
|
|
340
|
-
requiresCredits: true,
|
|
341
|
-
creditCost: 5,
|
|
342
|
-
enabled: true,
|
|
343
|
-
gateType: 'credits',
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
console.log(aiFeature.isAccessible(false, 10)); // true
|
|
347
|
-
console.log(aiFeature.isAccessible(false, 3)); // false
|
|
348
|
-
console.log(aiFeature.getRequiredCredits()); // 5
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
### Creating Paywall Configuration
|
|
352
|
-
|
|
353
|
-
```typescript
|
|
354
|
-
import { PaywallConfig } from './entities/PaywallConfig';
|
|
355
|
-
|
|
356
|
-
const paywall = new PaywallConfig({
|
|
357
|
-
id: 'premium_upgrade',
|
|
358
|
-
title: 'Upgrade to Premium',
|
|
359
|
-
subtitle: 'Get unlimited access',
|
|
360
|
-
features: ['Feature 1', 'Feature 2'],
|
|
361
|
-
packages: [monthlyPackage, annualPackage],
|
|
362
|
-
highlightPackage: 'premium_annual',
|
|
363
|
-
style: {
|
|
364
|
-
primaryColor: '#007AFF',
|
|
365
|
-
backgroundColor: '#FFFFFF',
|
|
366
|
-
},
|
|
367
|
-
triggers: [
|
|
368
|
-
{ type: 'credit_gate', enabled: true },
|
|
369
|
-
{ type: 'manual', enabled: true },
|
|
370
|
-
],
|
|
371
|
-
});
|
|
9
|
+
## Restrictions
|
|
372
10
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
11
|
+
### REQUIRED
|
|
12
|
+
- Must use entities for domain models
|
|
13
|
+
- Must validate in constructor
|
|
14
|
+
- Must keep entities immutable
|
|
376
15
|
|
|
377
|
-
|
|
16
|
+
### PROHIBITED
|
|
17
|
+
- DO NOT bypass entity validation
|
|
18
|
+
- DO NOT mutate entities after creation
|
|
19
|
+
- DO NOT leak domain logic to application layer
|
|
378
20
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
5. **Equality**: Implement proper equality methods
|
|
384
|
-
6. **Formatting**: Provide formatting methods
|
|
21
|
+
### CRITICAL SAFETY
|
|
22
|
+
- All business rules MUST be enforced in entities
|
|
23
|
+
- Validation failures MUST fail fast
|
|
24
|
+
- Type safety MUST be maintained at compile time
|
|
385
25
|
|
|
386
|
-
##
|
|
26
|
+
## AI Agent Guidelines
|
|
27
|
+
1. When creating new configurations, use existing entities
|
|
28
|
+
2. Always validate configuration data through entity constructors
|
|
29
|
+
3. Encapsulate business logic within domain entities
|
|
30
|
+
4. Implement proper equality methods for value objects
|
|
31
|
+
5. Provide formatting methods for display purposes
|
|
32
|
+
6. Maintain strict type safety with TypeScript
|
|
387
33
|
|
|
34
|
+
## Related Documentation
|
|
388
35
|
- [Config Domain](../../README.md)
|
|
389
36
|
- [Config Entities](./entities/README.md)
|
|
390
37
|
- [Config Value Objects](./value-objects/README.md)
|