@umituz/react-native-subscription 2.37.12 → 2.37.14

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 (133) hide show
  1. package/package.json +1 -1
  2. package/src/domains/credits/application/PurchaseMetadataGenerator.ts +1 -1
  3. package/src/domains/credits/application/credit-strategies/CreditAllocationOrchestrator.ts +1 -1
  4. package/src/domains/credits/application/creditDocumentHelpers.ts +0 -14
  5. package/src/domains/credits/presentation/deduct-credit/index.ts +0 -1
  6. package/src/domains/credits/presentation/useCredits.ts +1 -6
  7. package/src/domains/credits/utils/creditValidation.ts +3 -3
  8. package/src/domains/paywall/components/PaywallFeatures.tsx +1 -1
  9. package/src/domains/paywall/hooks/usePaywallActions.ts +1 -1
  10. package/src/domains/revenuecat/core/errors/RevenueCatError.ts +1 -14
  11. package/src/domains/revenuecat/core/errors/RevenueCatErrorHandler.ts +1 -1
  12. package/src/domains/revenuecat/core/types/RevenueCatTypes.ts +3 -3
  13. package/src/domains/revenuecat/infrastructure/services/ConfigurationStateManager.ts +1 -1
  14. package/src/domains/revenuecat/infrastructure/services/RevenueCatInitializer.ts +0 -2
  15. package/src/domains/revenuecat/infrastructure/services/UserSwitchMutex.ts +9 -0
  16. package/src/domains/subscription/application/initializer/index.ts +1 -1
  17. package/src/domains/subscription/core/SubscriptionStatus.ts +4 -10
  18. package/src/domains/subscription/core/SubscriptionStatusHandlers.ts +1 -1
  19. package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +0 -2
  20. package/src/domains/subscription/infrastructure/hooks/usePurchasePackage.ts +1 -1
  21. package/src/domains/subscription/infrastructure/hooks/useRevenueCatTrialEligibility.ts +1 -2
  22. package/src/domains/subscription/infrastructure/hooks/useSubscriptionQueries.ts +0 -4
  23. package/src/domains/subscription/infrastructure/services/OfferingsFetcher.ts +1 -1
  24. package/src/domains/subscription/infrastructure/services/RestoreHandler.ts +1 -1
  25. package/src/domains/subscription/infrastructure/services/RevenueCatService.ts +1 -2
  26. package/src/domains/subscription/infrastructure/services/revenueCatServiceInstance.ts +0 -4
  27. package/src/domains/subscription/infrastructure/utils/renewal/index.ts +1 -1
  28. package/src/domains/subscription/presentation/components/details/CreditRow.tsx +1 -1
  29. package/src/domains/subscription/presentation/components/details/DetailRow.tsx +1 -1
  30. package/src/domains/subscription/presentation/components/feedback/FeedbackOption.tsx +0 -2
  31. package/src/domains/subscription/presentation/components/feedback/FeedbackTextInput.tsx +1 -1
  32. package/src/domains/subscription/presentation/featureGateRefs.ts +1 -1
  33. package/src/domains/subscription/presentation/screens/components/CreditsList.tsx +2 -2
  34. package/src/domains/subscription/presentation/screens/components/SubscriptionHeader.tsx +0 -2
  35. package/src/domains/subscription/presentation/stores/index.ts +0 -5
  36. package/src/domains/subscription/presentation/stores/purchaseLoadingStore.ts +3 -7
  37. package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +2 -8
  38. package/src/domains/subscription/presentation/useFeatureGate.ts +0 -2
  39. package/src/domains/subscription/presentation/usePaywallVisibility.ts +1 -1
  40. package/src/domains/subscription/utils/authGuards.ts +0 -23
  41. package/src/domains/subscription/utils/syncStatus.ts +1 -1
  42. package/src/domains/wallet/index.ts +0 -112
  43. package/src/domains/wallet/infrastructure/config/walletConfig.ts +1 -23
  44. package/src/domains/wallet/infrastructure/repositories/transaction/CollectionBuilder.ts +1 -1
  45. package/src/domains/wallet/infrastructure/repositories/transaction/index.ts +0 -9
  46. package/src/domains/wallet/presentation/components/BalanceCard.tsx +1 -1
  47. package/src/domains/wallet/presentation/components/TransactionItem.tsx +0 -2
  48. package/src/domains/wallet/presentation/components/TransactionList.tsx +3 -2
  49. package/src/domains/wallet/presentation/hooks/useTransactionHistory.ts +2 -2
  50. package/src/domains/wallet/presentation/hooks/useWallet.ts +2 -2
  51. package/src/shared/application/FeedbackService.ts +2 -2
  52. package/src/shared/infrastructure/SubscriptionEventBus.ts +1 -1
  53. package/src/shared/infrastructure/firestore/collectionUtils.ts +0 -7
  54. package/src/shared/infrastructure/firestore/resultUtils.ts +3 -39
  55. package/src/shared/presentation/layouts/ScreenLayout.tsx +1 -1
  56. package/src/shared/utils/numberUtils.core.ts +0 -27
  57. package/src/shared/utils/numberUtils.ts +1 -9
  58. package/src/shared/utils/validators.ts +0 -58
  59. package/src/domains/config/domain/entities/Plan.ts +0 -44
  60. package/src/domains/config/domain/index.ts +0 -2
  61. package/src/domains/config/domain/value-objects/Config.ts +0 -49
  62. package/src/domains/config/index.ts +0 -6
  63. package/src/domains/config/utils/planSelectors.ts +0 -56
  64. package/src/domains/paywall/components/FeatureItem.tsx +0 -50
  65. package/src/domains/paywall/components/FeatureList.tsx +0 -34
  66. package/src/domains/paywall/components/PaywallHeader.tsx +0 -112
  67. package/src/domains/paywall/hooks/usePaywallTranslations.ts +0 -78
  68. package/src/domains/paywall/hooks/useSubscriptionModal.ts +0 -45
  69. package/src/domains/paywall/index.ts +0 -13
  70. package/src/domains/revenuecat/core/constants/RevenueCatConstants.ts +0 -201
  71. package/src/domains/revenuecat/core/constants/index.ts +0 -5
  72. package/src/domains/revenuecat/core/customerInfoHelpers.ts +0 -21
  73. package/src/domains/revenuecat/core/index.ts +0 -7
  74. package/src/domains/revenuecat/index.ts +0 -7
  75. package/src/domains/revenuecat/infrastructure/index.ts +0 -5
  76. package/src/domains/revenuecat/infrastructure/services/index.ts +0 -7
  77. package/src/domains/subscription/infrastructure/hooks/customer-info/index.ts +0 -2
  78. package/src/domains/subscription/infrastructure/hooks/customer-info/types.ts +0 -9
  79. package/src/domains/subscription/infrastructure/hooks/customer-info/useCustomerInfo.ts +0 -52
  80. package/src/domains/subscription/infrastructure/hooks/useInitializeSubscription.ts +0 -30
  81. package/src/domains/subscription/infrastructure/hooks/usePaywallFlow.ts +0 -78
  82. package/src/domains/subscription/infrastructure/hooks/useRevenueCat.ts +0 -119
  83. package/src/domains/subscription/presentation/components/feedback/FeedbackConstants.ts +0 -6
  84. package/src/domains/subscription/presentation/screens/components/SubscriptionActions.tsx +0 -56
  85. package/src/domains/subscription/utils/dateFormatters.ts +0 -28
  86. package/src/domains/wallet/domain/entities/CreditCost.ts +0 -45
  87. package/src/domains/wallet/domain/entities/README.md +0 -41
  88. package/src/domains/wallet/domain/errors/README.md +0 -40
  89. package/src/domains/wallet/domain/errors/WalletError.ts +0 -17
  90. package/src/domains/wallet/domain/errors/WalletError.types.ts +0 -30
  91. package/src/domains/wallet/domain/errors/WalletErrorClasses.ts +0 -82
  92. package/src/domains/wallet/domain/errors/WalletErrorFactory.ts +0 -24
  93. package/src/domains/wallet/domain/errors/WalletErrorMessages.ts +0 -17
  94. package/src/domains/wallet/domain/types/credit-cost.types.ts +0 -86
  95. package/src/domains/wallet/domain/types/index.ts +0 -33
  96. package/src/domains/wallet/domain/types/wallet.types.ts +0 -50
  97. package/src/domains/wallet/infrastructure/services/product-metadata/CacheManager.ts +0 -30
  98. package/src/domains/wallet/infrastructure/services/product-metadata/FirebaseFetcher.ts +0 -17
  99. package/src/domains/wallet/infrastructure/services/product-metadata/ProductMetadataService.ts +0 -57
  100. package/src/domains/wallet/infrastructure/services/product-metadata/ServiceManager.ts +0 -29
  101. package/src/domains/wallet/infrastructure/services/product-metadata/index.ts +0 -7
  102. package/src/domains/wallet/presentation/hooks/index.ts +0 -8
  103. package/src/domains/wallet/presentation/hooks/useProductMetadata.ts +0 -72
  104. package/src/domains/wallet/utils/index.ts +0 -1
  105. package/src/shared/application/ActivationHandler.ts +0 -108
  106. package/src/shared/application/ports/ISubscriptionService.ts +0 -27
  107. package/src/shared/infrastructure/index.ts +0 -6
  108. package/src/shared/infrastructure/react-query/queryInvalidation.ts +0 -46
  109. package/src/shared/presentation/hooks/index.ts +0 -6
  110. package/src/shared/presentation/hooks/useAsyncState.ts +0 -72
  111. package/src/shared/presentation/hooks/useServiceCall.ts +0 -77
  112. package/src/shared/types/ReactTypes.ts +0 -80
  113. package/src/shared/utils/InsufficientCreditsError.ts +0 -32
  114. package/src/shared/utils/Logger.ts +0 -81
  115. package/src/shared/utils/SubscriptionConfig.ts +0 -15
  116. package/src/shared/utils/SubscriptionError.ts +0 -47
  117. package/src/shared/utils/appValidators.ts +0 -38
  118. package/src/shared/utils/arrayUtils.core.ts +0 -81
  119. package/src/shared/utils/arrayUtils.query.ts +0 -118
  120. package/src/shared/utils/arrayUtils.transforms.ts +0 -116
  121. package/src/shared/utils/arrayUtils.ts +0 -19
  122. package/src/shared/utils/errorUtils.ts +0 -32
  123. package/src/shared/utils/index.ts +0 -14
  124. package/src/shared/utils/numberUtils.aggregate.ts +0 -35
  125. package/src/shared/utils/numberUtils.format.ts +0 -42
  126. package/src/shared/utils/numberUtils.math.ts +0 -48
  127. package/src/shared/utils/queryKeyFactory.ts +0 -9
  128. package/src/shared/utils/stringUtils.case.ts +0 -64
  129. package/src/shared/utils/stringUtils.check.ts +0 -65
  130. package/src/shared/utils/stringUtils.format.ts +0 -84
  131. package/src/shared/utils/stringUtils.generate.ts +0 -47
  132. package/src/shared/utils/stringUtils.modify.ts +0 -67
  133. package/src/shared/utils/stringUtils.ts +0 -10
@@ -1,30 +0,0 @@
1
- /**
2
- * Initialize Subscription Hook
3
- * TanStack mutation for initializing RevenueCat
4
- */
5
-
6
- import { useMutation, useQueryClient } from "@umituz/react-native-design-system";
7
- import { SubscriptionManager } from '../../infrastructure/managers/SubscriptionManager';
8
- import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
9
- import { requireAuthentication } from "../../utils/authGuards";
10
-
11
- /**
12
- * Initialize subscription with RevenueCat
13
- */
14
- export const useInitializeSubscription = (userId: string | undefined) => {
15
- const queryClient = useQueryClient();
16
-
17
- return useMutation({
18
- mutationFn: async () => {
19
- requireAuthentication(userId);
20
- return SubscriptionManager.initialize(userId);
21
- },
22
- onSuccess: () => {
23
- if (userId) {
24
- queryClient.invalidateQueries({
25
- queryKey: SUBSCRIPTION_QUERY_KEYS.packages,
26
- });
27
- }
28
- },
29
- });
30
- };
@@ -1,78 +0,0 @@
1
- /**
2
- * Paywall Flow Hook
3
- * Manages post-onboarding paywall state with persistence
4
- */
5
-
6
- import { useState, useEffect, useCallback } from 'react';
7
- import { useStorage } from '@umituz/react-native-design-system';
8
-
9
- const PAYWALL_SHOWN_KEY = 'post_onboarding_paywall_shown';
10
-
11
- export interface UsePaywallFlowOptions {
12
- showAfterOnboarding?: boolean;
13
- }
14
-
15
- export interface UsePaywallFlowResult {
16
- showPostOnboardingPaywall: boolean;
17
- paywallShown: boolean;
18
- closePostOnboardingPaywall: (isPremium: boolean) => Promise<void>;
19
- hidePostOnboardingPaywall: () => void;
20
- markPaywallShown: () => Promise<void>;
21
- setShowPostOnboardingPaywall: (show: boolean) => void;
22
- }
23
-
24
- export const usePaywallFlow = (options: UsePaywallFlowOptions = {}): UsePaywallFlowResult => {
25
- const { showAfterOnboarding = false } = options;
26
- const { getString, setString } = useStorage();
27
- const [showPostOnboardingPaywall, setShowPostOnboardingPaywall] = useState(showAfterOnboarding);
28
- const [paywallShown, setPaywallShown] = useState(false);
29
-
30
- // Load persisted state
31
- useEffect(() => {
32
- let isMounted = true;
33
-
34
- const loadPersistedState = async () => {
35
- try {
36
- const value = await getString(PAYWALL_SHOWN_KEY, '');
37
- if (isMounted) {
38
- setPaywallShown(value === 'true');
39
- }
40
- } catch (error) {
41
- console.error('[usePaywallFlow] Failed to load paywall state', error);
42
- if (isMounted) {
43
- setPaywallShown(false); // Safe default
44
- }
45
- }
46
- };
47
-
48
- loadPersistedState();
49
-
50
- return () => {
51
- isMounted = false;
52
- };
53
- }, [getString]);
54
-
55
- const closePostOnboardingPaywall = useCallback(async (_isPremium: boolean) => {
56
- await setString(PAYWALL_SHOWN_KEY, 'true');
57
- setShowPostOnboardingPaywall(false);
58
- setPaywallShown(true);
59
- }, [setString]);
60
-
61
- const hidePostOnboardingPaywall = useCallback(() => {
62
- setShowPostOnboardingPaywall(false);
63
- }, []);
64
-
65
- const markPaywallShown = useCallback(async () => {
66
- await setString(PAYWALL_SHOWN_KEY, 'true');
67
- setPaywallShown(true);
68
- }, [setString]);
69
-
70
- return {
71
- showPostOnboardingPaywall,
72
- paywallShown,
73
- closePostOnboardingPaywall,
74
- hidePostOnboardingPaywall,
75
- markPaywallShown,
76
- setShowPostOnboardingPaywall,
77
- };
78
- };
@@ -1,119 +0,0 @@
1
- /**
2
- * useRevenueCat Hook
3
- * React hook for RevenueCat subscription management
4
- */
5
-
6
- import { useState, useCallback, useEffect, useRef } from "react";
7
- import type { PurchasesOffering, PurchasesPackage } from "react-native-purchases";
8
- import { getRevenueCatService } from '../../infrastructure/services/RevenueCatService';
9
- import type { PurchaseResult, RestoreResult } from '../../../../shared/application/ports/IRevenueCatService';
10
-
11
- export interface UseRevenueCatResult {
12
- /** Current offering */
13
- offering: PurchasesOffering | null;
14
- /** Whether RevenueCat is loading */
15
- loading: boolean;
16
- /** Initialize RevenueCat SDK */
17
- initialize: (userId: string, apiKey?: string) => Promise<void>;
18
- /** Load offerings */
19
- loadOfferings: () => Promise<void>;
20
- /** Purchase a package */
21
- purchasePackage: (pkg: PurchasesPackage, userId: string) => Promise<PurchaseResult>;
22
- /** Restore purchases */
23
- restorePurchases: (userId: string) => Promise<RestoreResult>;
24
- }
25
-
26
- /**
27
- * Hook for RevenueCat operations
28
- * Only initialize when subscription screen is opened
29
- *
30
- * @example
31
- * ```typescript
32
- * const { offering, loading, initialize, purchasePackage } = useRevenueCat();
33
- * ```
34
- */
35
- export function useRevenueCat(): UseRevenueCatResult {
36
- const [offering, setOffering] = useState<PurchasesOffering | null>(null);
37
- const [loading, setLoading] = useState(false);
38
- const isMountedRef = useRef(true);
39
-
40
- useEffect(() => {
41
- isMountedRef.current = true;
42
- return () => {
43
- isMountedRef.current = false;
44
- };
45
- }, []);
46
-
47
- const initialize = useCallback(async (userId: string, apiKey?: string) => {
48
- if (!isMountedRef.current) return;
49
-
50
- setLoading(true);
51
- try {
52
- const service = getRevenueCatService();
53
- if (!service) {
54
- return;
55
- }
56
- const result = await service.initialize(userId, apiKey);
57
- if (result.success && isMountedRef.current) {
58
- setOffering(result.offering);
59
- }
60
- } catch {
61
- // Error handling is done by service
62
- } finally {
63
- if (isMountedRef.current) {
64
- setLoading(false);
65
- }
66
- }
67
- }, []);
68
-
69
- const loadOfferings = useCallback(async () => {
70
- if (!isMountedRef.current) return;
71
-
72
- setLoading(true);
73
- try {
74
- const service = getRevenueCatService();
75
- if (!service) {
76
- return;
77
- }
78
- const fetchedOffering = await service.fetchOfferings();
79
- if (isMountedRef.current) {
80
- setOffering(fetchedOffering);
81
- }
82
- } catch {
83
- // Error handling is done by service
84
- } finally {
85
- if (isMountedRef.current) {
86
- setLoading(false);
87
- }
88
- }
89
- }, []);
90
-
91
- const purchasePackage = useCallback(async (pkg: PurchasesPackage, userId: string) => {
92
- const service = getRevenueCatService();
93
- if (!service) {
94
- throw new Error("RevenueCat service is not initialized");
95
- }
96
- return await service.purchasePackage(pkg, userId);
97
- }, []);
98
-
99
- const restorePurchases = useCallback(async (userId: string) => {
100
- const service = getRevenueCatService();
101
- if (!service) {
102
- throw new Error("RevenueCat service is not initialized");
103
- }
104
- return await service.restorePurchases(userId);
105
- }, []);
106
-
107
- // Note: State cleanup is handled by React automatically on unmount
108
- // No explicit cleanup needed for these state variables
109
-
110
- return {
111
- offering,
112
- loading,
113
- initialize,
114
- loadOfferings,
115
- purchasePackage,
116
- restorePurchases,
117
- };
118
- }
119
-
@@ -1,6 +0,0 @@
1
- export const FEEDBACK_TEXT_MAX_LENGTH = 200;
2
-
3
- export const FEEDBACK_CHECKBOX_SIZE = 22;
4
- export const FEEDBACK_CHECKBOX_RADIUS = 11;
5
-
6
- export const FEEDBACK_TEXT_MIN_HEIGHT = 80;
@@ -1,56 +0,0 @@
1
- /**
2
- * Subscription Actions Component
3
- * Displays upgrade button for non-premium users
4
- */
5
-
6
- import React, { useMemo } from "react";
7
- import { View, StyleSheet, TouchableOpacity } from "react-native";
8
- import { useAppDesignTokens, AtomicText } from "@umituz/react-native-design-system";
9
-
10
- export interface SubscriptionActionsProps {
11
- isPremium: boolean;
12
- upgradeButtonLabel?: string;
13
- onUpgrade?: () => void;
14
- }
15
-
16
- export const SubscriptionActions: React.FC<SubscriptionActionsProps> = ({
17
- isPremium,
18
- upgradeButtonLabel,
19
- onUpgrade,
20
- }) => {
21
- const tokens = useAppDesignTokens();
22
-
23
- const styles = useMemo(
24
- () =>
25
- StyleSheet.create({
26
- container: {
27
- paddingBottom: tokens.spacing.xl,
28
- },
29
- primaryButton: {
30
- paddingVertical: tokens.spacing.md,
31
- borderRadius: tokens.radius.lg,
32
- alignItems: "center",
33
- backgroundColor: tokens.colors.primary,
34
- },
35
- buttonText: {
36
- color: tokens.colors.onPrimary,
37
- fontWeight: "700",
38
- },
39
- }),
40
- [tokens]
41
- );
42
-
43
- if (isPremium || !onUpgrade || !upgradeButtonLabel) {
44
- return null;
45
- }
46
-
47
- return (
48
- <View style={styles.container}>
49
- <TouchableOpacity style={styles.primaryButton} onPress={onUpgrade}>
50
- <AtomicText type="titleMedium" style={styles.buttonText}>
51
- {upgradeButtonLabel}
52
- </AtomicText>
53
- </TouchableOpacity>
54
- </View>
55
- );
56
- };
@@ -1,28 +0,0 @@
1
- import { timezoneService } from "@umituz/react-native-design-system";
2
-
3
- export function convertFirestoreTimestampToISO(timestamp: unknown): string | null {
4
- if (!timestamp) return null;
5
-
6
- let date: Date;
7
- if (
8
- typeof timestamp === "object" &&
9
- timestamp !== null &&
10
- "toDate" in timestamp
11
- ) {
12
- date = (timestamp as { toDate: () => Date }).toDate();
13
- } else if (timestamp instanceof Date) {
14
- date = timestamp;
15
- } else {
16
- return null;
17
- }
18
-
19
- return timezoneService.formatToISOString(date);
20
- }
21
-
22
- export function formatDateForDisplay(dateStr: string | null): string | null {
23
- if (!dateStr) return null;
24
- const date = new Date(dateStr);
25
- if (isNaN(date.getTime())) return null;
26
-
27
- return timezoneService.formatToDisplayDate(date);
28
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * Credit Cost Entity
3
- *
4
- * Configurable credit cost configuration for AI operations.
5
- * Apps can override default costs based on their pricing model.
6
- */
7
-
8
- import type { AICreditCosts } from "../types/credit-cost.types";
9
- import {
10
- DEFAULT_AI_CREDIT_COSTS,
11
- createCreditCostConfig,
12
- } from "../types/credit-cost.types";
13
-
14
- export interface CreditCostEntity {
15
- costs: AICreditCosts;
16
- pricePerCredit: number;
17
- getCost: (operation: keyof AICreditCosts) => number;
18
- getDollarValue: (operation: keyof AICreditCosts) => number;
19
- getCustomCost: (operation: string) => number;
20
- }
21
-
22
- export function createCreditCostEntity(
23
- overrides?: Partial<AICreditCosts>,
24
- pricePerCredit: number = 0.1
25
- ): CreditCostEntity {
26
- const costs = createCreditCostConfig(overrides);
27
-
28
- return {
29
- costs,
30
- pricePerCredit,
31
- getCost: (operation: keyof AICreditCosts): number => {
32
- return costs[operation];
33
- },
34
- getDollarValue: (operation: keyof AICreditCosts): number => {
35
- return costs[operation] * pricePerCredit;
36
- },
37
- getCustomCost: (operation: string): number => {
38
- const costsRecord = costs as unknown as Record<string, number>;
39
- return costsRecord[operation] ?? 0;
40
- },
41
- };
42
- }
43
-
44
- export { DEFAULT_AI_CREDIT_COSTS, createCreditCostConfig };
45
- export type { AICreditCosts };
@@ -1,41 +0,0 @@
1
- # Wallet Domain Entities
2
-
3
- ## Location
4
- Core entities for credits and transaction management.
5
-
6
- ## Strategy
7
- This directory contains domain entities representing credits, transactions, and wallet-related business concepts with strict immutability and validation.
8
-
9
- ## Restrictions
10
-
11
- ### REQUIRED
12
- - Must treat entities as immutable values
13
- - Must validate in entity methods
14
- - Must use strict TypeScript types
15
- - Must keep business logic in entities
16
-
17
- ### PROHIBITED
18
- - DO NOT mutate entities after creation
19
- - DO NOT bypass validation methods
20
- - DO NOT leak entity internals
21
- - DO NOT allow invalid state
22
-
23
- ### CRITICAL SAFETY
24
- - All entities MUST be immutable
25
- - Validation MUST be performed in entity methods
26
- - Date serialization MUST be handled properly
27
- - Business rules MUST be enforced in entities
28
-
29
- ## AI Agent Guidelines
30
- 1. Treat all entities as immutable values
31
- 2. Perform validation within entity methods
32
- 3. Use strict TypeScript types for all properties
33
- 4. Keep business logic encapsulated in entities
34
- 5. Handle date serialization properly for transactions
35
- 6. Implement proper equality methods
36
- 7. Provide clear validation error messages
37
-
38
- ## Related Documentation
39
- - [Wallet Domain](../README.md)
40
- - [Credits Repository](../../infrastructure/repositories/README.md)
41
- - [useCredits Hook](../../../../presentation/hooks/useCredits.md)
@@ -1,40 +0,0 @@
1
- # Wallet Domain Errors
2
-
3
- ## Location
4
- Domain-specific errors for wallet and credit operations.
5
-
6
- ## Strategy
7
- This directory contains custom error classes representing wallet-related error conditions with specific error types and recovery strategies.
8
-
9
- ## Restrictions
10
-
11
- ### REQUIRED
12
- - Must use specific error types for different scenarios
13
- - Must include relevant context in error properties
14
- - Must handle errors gracefully at boundaries
15
- - Must log errors for debugging
16
-
17
- ### PROHIBITED
18
- - DO NOT use generic error types
19
- - DO NOT throw errors without context
20
- - DO NOT ignore error conditions
21
- - DO NOT expose technical errors to users
22
-
23
- ### CRITICAL SAFETY
24
- - All errors MUST be handled appropriately
25
- - Error context MUST be sufficient for recovery
26
- - Technical errors MUST be converted to user-friendly messages
27
- - Error codes MUST be actionable
28
-
29
- ## AI Agent Guidelines
30
- 1. Use specific error types for different scenarios (CreditsExhaustedError, DuplicatePurchaseError, etc.)
31
- 2. Include relevant data in error properties for recovery
32
- 3. Handle errors gracefully at layer boundaries
33
- 4. Log all errors with sufficient context for debugging
34
- 5. Convert technical errors to user-friendly messages
35
- 6. Follow error code reference for recovery strategies
36
- 7. Test error handling paths thoroughly
37
-
38
- ## Related Documentation
39
- - [Wallet Entities](../entities/README.md)
40
- - [Credits Repository](../../infrastructure/repositories/README.md)
@@ -1,17 +0,0 @@
1
- export type { WalletErrorCategory } from "./WalletError.types";
2
- export { WalletError } from "./WalletError.types";
3
-
4
- export {
5
- PaymentValidationError,
6
- PaymentProviderError,
7
- DuplicatePaymentError,
8
- UserValidationError,
9
- PackageValidationError,
10
- ReceiptValidationError,
11
- TransactionError,
12
- NetworkError,
13
- CreditLimitError,
14
- RefundError,
15
- } from "./WalletErrorClasses";
16
-
17
- export { handleWalletError } from "./WalletErrorFactory";
@@ -1,30 +0,0 @@
1
- export type WalletErrorCategory =
2
- | "PAYMENT"
3
- | "VALIDATION"
4
- | "INFRASTRUCTURE"
5
- | "BUSINESS";
6
-
7
- export abstract class WalletError extends Error {
8
- abstract readonly code: string;
9
- abstract readonly userMessage: string;
10
- abstract readonly category: WalletErrorCategory;
11
-
12
- constructor(
13
- message: string,
14
- public readonly cause?: Error
15
- ) {
16
- super(message);
17
- this.name = this.constructor.name;
18
- }
19
-
20
- toJSON() {
21
- return {
22
- name: this.name,
23
- code: this.code,
24
- userMessage: this.userMessage,
25
- category: this.category,
26
- message: this.message,
27
- cause: this.cause?.message,
28
- };
29
- }
30
- }
@@ -1,82 +0,0 @@
1
- import { WalletError } from "./WalletError.types";
2
- import { WALLET_ERROR_MESSAGES } from "./WalletErrorMessages";
3
-
4
- export class PaymentValidationError extends WalletError {
5
- readonly code = "PAYMENT_VALIDATION_ERROR";
6
- readonly category = "PAYMENT" as const;
7
- readonly userMessage = WALLET_ERROR_MESSAGES.PAYMENT_VALIDATION_FAILED;
8
-
9
- constructor(message: string, cause?: Error) {
10
- super(message, cause);
11
- }
12
- }
13
-
14
- export class PaymentProviderError extends WalletError {
15
- readonly code = "PAYMENT_PROVIDER_ERROR";
16
- readonly category = "PAYMENT" as const;
17
- readonly userMessage = WALLET_ERROR_MESSAGES.PAYMENT_PROVIDER_ERROR;
18
-
19
- constructor(message: string, cause?: Error) {
20
- super(message, cause);
21
- }
22
- }
23
-
24
- export class DuplicatePaymentError extends WalletError {
25
- readonly code = "DUPLICATE_PAYMENT";
26
- readonly category = "PAYMENT" as const;
27
- readonly userMessage = WALLET_ERROR_MESSAGES.DUPLICATE_PAYMENT;
28
- }
29
-
30
- export class UserValidationError extends WalletError {
31
- readonly code = "USER_VALIDATION_ERROR";
32
- readonly category = "VALIDATION" as const;
33
- readonly userMessage = WALLET_ERROR_MESSAGES.USER_VALIDATION_FAILED;
34
- }
35
-
36
- export class PackageValidationError extends WalletError {
37
- readonly code = "PACKAGE_VALIDATION_ERROR";
38
- readonly category = "VALIDATION" as const;
39
- readonly userMessage = WALLET_ERROR_MESSAGES.PACKAGE_VALIDATION_FAILED;
40
- }
41
-
42
- export class ReceiptValidationError extends WalletError {
43
- readonly code = "RECEIPT_VALIDATION_ERROR";
44
- readonly category = "VALIDATION" as const;
45
- readonly userMessage = WALLET_ERROR_MESSAGES.RECEIPT_VALIDATION_FAILED;
46
- }
47
-
48
- export class TransactionError extends WalletError {
49
- readonly code = "TRANSACTION_ERROR";
50
- readonly category = "INFRASTRUCTURE" as const;
51
- readonly userMessage = WALLET_ERROR_MESSAGES.TRANSACTION_FAILED;
52
-
53
- constructor(message: string, cause?: Error) {
54
- super(message, cause);
55
- }
56
- }
57
-
58
- export class NetworkError extends WalletError {
59
- readonly code = "NETWORK_ERROR";
60
- readonly category = "INFRASTRUCTURE" as const;
61
- readonly userMessage = WALLET_ERROR_MESSAGES.NETWORK_ERROR;
62
-
63
- constructor(message: string, cause?: Error) {
64
- super(message, cause);
65
- }
66
- }
67
-
68
- export class CreditLimitError extends WalletError {
69
- readonly code = "CREDIT_LIMIT_ERROR";
70
- readonly category = "BUSINESS" as const;
71
- readonly userMessage = WALLET_ERROR_MESSAGES.CREDIT_LIMIT_EXCEEDED;
72
- }
73
-
74
- export class RefundError extends WalletError {
75
- readonly code = "REFUND_ERROR";
76
- readonly category = "BUSINESS" as const;
77
- readonly userMessage = WALLET_ERROR_MESSAGES.REFUND_FAILED;
78
-
79
- constructor(message: string, cause?: Error) {
80
- super(message, cause);
81
- }
82
- }
@@ -1,24 +0,0 @@
1
- import { WalletError } from "./WalletError.types";
2
- import { NetworkError, UserValidationError, TransactionError } from "./WalletErrorClasses";
3
-
4
- export const handleWalletError = (error: unknown): WalletError => {
5
- if (error instanceof WalletError) {
6
- return error;
7
- }
8
-
9
- if (error instanceof Error) {
10
- const message = error.message.toLowerCase();
11
-
12
- if (message.includes("network") || message.includes("timeout")) {
13
- return new NetworkError(error.message, error);
14
- }
15
-
16
- if (message.includes("permission") || message.includes("unauthorized")) {
17
- return new UserValidationError("Authentication failed");
18
- }
19
-
20
- return new TransactionError(error.message, error);
21
- }
22
-
23
- return new TransactionError("Unexpected error occurred");
24
- };
@@ -1,17 +0,0 @@
1
- /**
2
- * Wallet Error Messages
3
- * Centralized error user messages for wallet operations
4
- */
5
-
6
- export const WALLET_ERROR_MESSAGES = {
7
- PAYMENT_VALIDATION_FAILED: "Payment validation failed. Please try again.",
8
- PAYMENT_PROVIDER_ERROR: "Payment provider error. Please try again.",
9
- DUPLICATE_PAYMENT: "This payment has already been processed.",
10
- USER_VALIDATION_FAILED: "Invalid user information. Please log in again.",
11
- PACKAGE_VALIDATION_FAILED: "Invalid credit package. Please select a valid package.",
12
- RECEIPT_VALIDATION_FAILED: "Invalid payment receipt. Please contact support.",
13
- TRANSACTION_FAILED: "Transaction failed. Please try again.",
14
- NETWORK_ERROR: "Network error. Please check your connection.",
15
- CREDIT_LIMIT_EXCEEDED: "Credit limit exceeded. Please contact support.",
16
- REFUND_FAILED: "Refund failed. Please contact support.",
17
- } as const;