@umituz/react-native-subscription 2.37.38 → 2.37.40
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/package.json +1 -1
- package/src/domains/credits/application/CreditLimitCalculator.ts +1 -9
- package/src/domains/credits/application/CreditsInitializer.ts +5 -20
- package/src/domains/credits/application/DeductCreditsCommand.ts +13 -6
- package/src/domains/credits/application/RefundCreditsCommand.ts +1 -5
- package/src/domains/credits/application/credit-strategies/CreditAllocationOrchestrator.ts +1 -9
- package/src/domains/credits/application/credit-strategies/ICreditStrategy.ts +1 -5
- package/src/domains/credits/application/credit-strategies/TrialCreditStrategy.ts +1 -5
- package/src/domains/credits/application/creditDocumentHelpers.ts +2 -9
- package/src/domains/credits/application/creditOperationUtils.ts +1 -43
- package/src/domains/credits/core/Credits.ts +0 -23
- package/src/domains/credits/core/CreditsConstants.ts +0 -11
- package/src/domains/credits/core/CreditsMapper.ts +0 -6
- package/src/domains/credits/core/UserCreditsDocument.ts +0 -12
- package/src/domains/credits/infrastructure/CreditsRepository.ts +6 -1
- package/src/domains/credits/infrastructure/CreditsRepositoryManager.ts +0 -21
- package/src/domains/credits/infrastructure/operations/CreditsWriter.ts +52 -1
- package/src/domains/credits/presentation/deduct-credit/useDeductCredit.ts +2 -2
- package/src/domains/credits/presentation/useCredits.ts +10 -9
- package/src/domains/paywall/components/PaywallContainer.types.ts +0 -28
- package/src/domains/paywall/components/PaywallModal.styles.ts +0 -4
- package/src/domains/paywall/entities/types.ts +0 -5
- package/src/domains/paywall/hooks/usePaywallActions.ts +1 -15
- package/src/domains/revenuecat/core/errors/RevenueCatError.ts +0 -6
- package/src/domains/revenuecat/core/errors/RevenueCatErrorHandler.ts +0 -24
- package/src/domains/revenuecat/core/errors/RevenueCatErrorMessages.ts +0 -18
- package/src/domains/revenuecat/core/errors/index.ts +0 -4
- package/src/domains/revenuecat/core/types/RevenueCatConfig.ts +3 -7
- package/src/domains/revenuecat/core/types/RevenueCatData.ts +4 -9
- package/src/domains/revenuecat/core/types/RevenueCatTypes.ts +5 -65
- package/src/domains/revenuecat/core/types/index.ts +0 -4
- package/src/domains/revenuecat/infrastructure/services/UserSwitchMutex.ts +1 -24
- package/src/domains/subscription/application/SubscriptionAuthListener.ts +5 -21
- package/src/domains/subscription/application/SubscriptionInitializerTypes.ts +1 -5
- package/src/domains/subscription/application/SubscriptionSyncProcessor.ts +0 -4
- package/src/domains/subscription/application/SubscriptionSyncService.ts +4 -8
- package/src/domains/subscription/application/SubscriptionSyncUtils.ts +1 -1
- package/src/domains/subscription/application/initializer/BackgroundInitializer.ts +15 -2
- package/src/domains/subscription/application/initializer/ServiceConfigurator.ts +9 -2
- package/src/domains/subscription/application/statusChangeHandlers.ts +14 -27
- package/src/domains/subscription/application/syncIdGenerators.ts +0 -4
- package/src/domains/subscription/constants/thresholds.ts +0 -9
- package/src/domains/subscription/core/SubscriptionConstants.ts +0 -4
- package/src/domains/subscription/core/SubscriptionStatus.ts +11 -21
- package/src/domains/subscription/core/SubscriptionStatusHandlers.ts +4 -7
- package/src/domains/subscription/infrastructure/handlers/PurchaseStatusResolver.ts +1 -1
- package/src/domains/subscription/infrastructure/hooks/subscriptionQueryKeys.ts +0 -13
- package/src/domains/subscription/infrastructure/hooks/usePurchasePackage.ts +0 -18
- package/src/domains/subscription/infrastructure/hooks/useRestorePurchase.ts +3 -17
- package/src/domains/subscription/infrastructure/hooks/useRevenueCatTrialEligibility.ts +0 -17
- package/src/domains/subscription/infrastructure/hooks/useSubscriptionPackages.ts +0 -19
- package/src/domains/subscription/infrastructure/hooks/useSubscriptionQueries.ts +0 -6
- package/src/domains/subscription/infrastructure/managers/subscriptionManagerUtils.ts +0 -17
- package/src/domains/subscription/infrastructure/state/initializationState.ts +0 -25
- package/src/domains/subscription/infrastructure/utils/InitializationCache.ts +0 -21
- package/src/domains/subscription/infrastructure/utils/PremiumStatusSyncer.ts +3 -17
- package/src/domains/subscription/infrastructure/utils/authPurchaseState.ts +0 -5
- package/src/domains/subscription/infrastructure/utils/renewal/PackageTierComparator.ts +1 -0
- package/src/domains/subscription/infrastructure/utils/trialEligibilityUtils.ts +0 -18
- package/src/domains/subscription/presentation/components/details/PremiumDetailsCard.styles.ts +0 -5
- package/src/domains/subscription/presentation/components/details/PremiumDetailsCardTypes.ts +0 -5
- package/src/domains/subscription/presentation/components/feedback/paywallFeedbackStyles.ts +0 -5
- package/src/domains/subscription/presentation/stores/index.ts +0 -4
- package/src/domains/subscription/presentation/stores/purchaseLoadingStore.ts +0 -13
- package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +30 -21
- package/src/domains/subscription/presentation/usePaywallVisibility.ts +0 -9
- package/src/domains/subscription/presentation/useSubscriptionStatus.ts +8 -11
- package/src/domains/subscription/utils/authGuards.ts +3 -0
- package/src/domains/trial/application/TrialService.ts +0 -9
- package/src/domains/trial/core/TrialTypes.ts +0 -8
- package/src/domains/wallet/domain/mappers/TransactionMapper.ts +0 -5
- package/src/domains/wallet/domain/types/transaction.types.ts +0 -7
- package/src/domains/wallet/index.ts +0 -7
- package/src/domains/wallet/infrastructure/config/walletConfig.ts +0 -11
- package/src/domains/wallet/presentation/hooks/useTransactionHistory.ts +6 -3
- package/src/domains/wallet/presentation/hooks/useWallet.ts +0 -7
- package/src/domains/wallet/utils/transactionIconMap.ts +0 -10
- package/src/global.d.ts +0 -6
- package/src/index.ts +1 -4
- package/src/init/createSubscriptionInitModule.ts +12 -2
- package/src/init/index.ts +1 -5
- package/src/presentation/hooks/feedback/useFeedbackSubmit.ts +0 -11
- package/src/shared/application/FeedbackService.ts +3 -21
- package/src/shared/application/ports/ISubscriptionRepository.ts +0 -4
- package/src/shared/infrastructure/SubscriptionEventBus.ts +0 -13
- package/src/shared/infrastructure/firestore/collectionUtils.ts +1 -17
- package/src/shared/infrastructure/firestore/index.ts +0 -4
- package/src/shared/infrastructure/firestore/resultUtils.ts +0 -12
- package/src/shared/infrastructure/react-query/hooks/usePreviousUserCleanup.ts +0 -17
- package/src/shared/infrastructure/react-query/queryConfig.ts +0 -15
- package/src/shared/utils/BaseError.ts +0 -5
- package/src/shared/utils/Result.ts +0 -20
- package/src/shared/utils/dateConverter.ts +6 -46
- package/src/utils/appUtils.ts +0 -16
- package/src/utils/creditMapper.ts +0 -7
- package/src/utils/dateUtils.compare.ts +0 -24
- package/src/utils/dateUtils.core.ts +0 -39
- package/src/utils/dateUtils.format.ts +0 -41
- package/src/utils/dateUtils.math.ts +0 -41
- package/src/utils/dateUtils.ts +0 -5
- package/src/utils/packagePeriodUtils.ts +0 -20
- package/src/utils/packageTypeDetector.ts +1 -21
- package/src/utils/premiumStatusUtils.ts +1 -14
- package/src/utils/priceUtils.ts +0 -35
- package/src/utils/tierUtils.ts +1 -8
- package/src/utils/types.ts +1 -25
- package/src/utils/validation.ts +1 -7
- package/src/domains/README.md +0 -52
- package/src/domains/config/domain/README.md +0 -37
- package/src/domains/config/domain/entities/README.md +0 -41
- package/src/domains/credits/application/credit-strategies/SyncCreditStrategy.ts +0 -24
- package/src/domains/paywall/README.md +0 -101
- package/src/domains/paywall/entities/README.md +0 -40
- package/src/domains/paywall/hooks/README.md +0 -41
- package/src/domains/subscription/application/syncConstants.ts +0 -1
- package/src/domains/subscription/infrastructure/README.md +0 -41
- package/src/domains/subscription/infrastructure/config/README.md +0 -49
- package/src/domains/subscription/infrastructure/handlers/README.md +0 -41
- package/src/domains/subscription/infrastructure/hooks/README.md +0 -50
- package/src/domains/subscription/infrastructure/managers/README.md +0 -41
- package/src/domains/subscription/infrastructure/services/README.md +0 -42
- package/src/domains/subscription/infrastructure/utils/README.md +0 -41
- package/src/domains/subscription/presentation/components/README.md +0 -155
- package/src/domains/subscription/presentation/components/details/CreditRow.md +0 -92
- package/src/domains/subscription/presentation/components/details/DetailRow.md +0 -91
- package/src/domains/subscription/presentation/components/details/PremiumDetailsCard.md +0 -93
- package/src/domains/subscription/presentation/components/details/PremiumStatusBadge.md +0 -91
- package/src/domains/subscription/presentation/components/details/README.md +0 -99
- package/src/domains/subscription/presentation/components/feedback/PaywallFeedbackModal.md +0 -90
- package/src/domains/subscription/presentation/components/feedback/README.md +0 -99
- package/src/domains/subscription/presentation/components/paywall/PaywallModal.md +0 -94
- package/src/domains/subscription/presentation/components/paywall/README.md +0 -54
- package/src/domains/subscription/presentation/components/sections/README.md +0 -99
- package/src/domains/subscription/presentation/components/sections/SubscriptionSection.md +0 -94
- package/src/domains/subscription/presentation/utils/README.md +0 -31
- package/src/domains/wallet/README.md +0 -51
- package/src/domains/wallet/domain/README.md +0 -41
- package/src/domains/wallet/infrastructure/README.md +0 -41
- package/src/domains/wallet/presentation/components/README.md +0 -41
- package/src/domains/wallet/presentation/hooks/README.md +0 -41
- package/src/shared/application/ports/README.md +0 -48
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Utilities - Formatting
|
|
3
|
-
* Date display and formatting functions
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import type { DateLike } from "./dateUtils.core";
|
|
7
2
|
|
|
8
|
-
/**
|
|
9
|
-
* Format date to locale string
|
|
10
|
-
*/
|
|
11
3
|
export function formatLocale(
|
|
12
4
|
date: DateLike,
|
|
13
5
|
options?: Intl.DateTimeFormatOptions,
|
|
@@ -20,9 +12,6 @@ export function formatLocale(
|
|
|
20
12
|
return d.toLocaleDateString(locale, options);
|
|
21
13
|
}
|
|
22
14
|
|
|
23
|
-
/**
|
|
24
|
-
* Format date to relative time (e.g., "2 days ago", "in 3 hours")
|
|
25
|
-
*/
|
|
26
15
|
export function formatRelative(date: DateLike, now: Date = new Date()): string {
|
|
27
16
|
const target = new Date(date);
|
|
28
17
|
if (isNaN(target.getTime())) {
|
|
@@ -49,37 +38,22 @@ export function formatRelative(date: DateLike, now: Date = new Date()): string {
|
|
|
49
38
|
return rtf.format(diffSecs, "second");
|
|
50
39
|
}
|
|
51
40
|
|
|
52
|
-
/**
|
|
53
|
-
* Format date to short date string (e.g., "1/1/2024")
|
|
54
|
-
*/
|
|
55
41
|
export function formatShort(date: DateLike, locale: string = "en-US"): string {
|
|
56
42
|
return formatLocale(date, { month: "numeric", day: "numeric", year: "numeric" }, locale);
|
|
57
43
|
}
|
|
58
44
|
|
|
59
|
-
/**
|
|
60
|
-
* Format date to medium date string (e.g., "Jan 1, 2024")
|
|
61
|
-
*/
|
|
62
45
|
export function formatMedium(date: DateLike, locale: string = "en-US"): string {
|
|
63
46
|
return formatLocale(date, { month: "short", day: "numeric", year: "numeric" }, locale);
|
|
64
47
|
}
|
|
65
48
|
|
|
66
|
-
/**
|
|
67
|
-
* Format date to long date string (e.g., "January 1, 2024")
|
|
68
|
-
*/
|
|
69
49
|
export function formatLong(date: DateLike, locale: string = "en-US"): string {
|
|
70
50
|
return formatLocale(date, { month: "long", day: "numeric", year: "numeric" }, locale);
|
|
71
51
|
}
|
|
72
52
|
|
|
73
|
-
/**
|
|
74
|
-
* Format date to time string
|
|
75
|
-
*/
|
|
76
53
|
export function formatTime(date: DateLike, locale: string = "en-US"): string {
|
|
77
54
|
return formatLocale(date, { hour: "numeric", minute: "numeric" }, locale);
|
|
78
55
|
}
|
|
79
56
|
|
|
80
|
-
/**
|
|
81
|
-
* Format date to date and time string
|
|
82
|
-
*/
|
|
83
57
|
export function formatDateTime(date: DateLike, locale: string = "en-US"): string {
|
|
84
58
|
return formatLocale(
|
|
85
59
|
date,
|
|
@@ -88,9 +62,6 @@ export function formatDateTime(date: DateLike, locale: string = "en-US"): string
|
|
|
88
62
|
);
|
|
89
63
|
}
|
|
90
64
|
|
|
91
|
-
/**
|
|
92
|
-
* Convert milliseconds to human-readable duration
|
|
93
|
-
*/
|
|
94
65
|
export function formatDuration(ms: number): string {
|
|
95
66
|
const seconds = Math.floor(ms / 1000);
|
|
96
67
|
const minutes = Math.floor(seconds / 60);
|
|
@@ -109,30 +80,18 @@ export function formatDuration(ms: number): string {
|
|
|
109
80
|
return `${seconds}s`;
|
|
110
81
|
}
|
|
111
82
|
|
|
112
|
-
/**
|
|
113
|
-
* Format date to weekday name (e.g., "Monday")
|
|
114
|
-
*/
|
|
115
83
|
export function formatWeekday(date: DateLike, locale: string = "en-US"): string {
|
|
116
84
|
return formatLocale(date, { weekday: "long" }, locale);
|
|
117
85
|
}
|
|
118
86
|
|
|
119
|
-
/**
|
|
120
|
-
* Format date to short weekday name (e.g., "Mon")
|
|
121
|
-
*/
|
|
122
87
|
export function formatWeekdayShort(date: DateLike, locale: string = "en-US"): string {
|
|
123
88
|
return formatLocale(date, { weekday: "short" }, locale);
|
|
124
89
|
}
|
|
125
90
|
|
|
126
|
-
/**
|
|
127
|
-
* Format date to month name (e.g., "January")
|
|
128
|
-
*/
|
|
129
91
|
export function formatMonth(date: DateLike, locale: string = "en-US"): string {
|
|
130
92
|
return formatLocale(date, { month: "long" }, locale);
|
|
131
93
|
}
|
|
132
94
|
|
|
133
|
-
/**
|
|
134
|
-
* Format date to short month name (e.g., "Jan")
|
|
135
|
-
*/
|
|
136
95
|
export function formatMonthShort(date: DateLike, locale: string = "en-US"): string {
|
|
137
96
|
return formatLocale(date, { month: "short" }, locale);
|
|
138
97
|
}
|
|
@@ -1,83 +1,51 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Utilities - Math Operations
|
|
3
|
-
* Date arithmetic and manipulation functions
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import type { DateLike } from "./dateUtils.core";
|
|
7
2
|
|
|
8
|
-
/**
|
|
9
|
-
* Add days to a date
|
|
10
|
-
*/
|
|
11
3
|
export function addDays(date: DateLike, days: number): Date {
|
|
12
4
|
const result = new Date(date);
|
|
13
5
|
result.setDate(result.getDate() + days);
|
|
14
6
|
return result;
|
|
15
7
|
}
|
|
16
8
|
|
|
17
|
-
/**
|
|
18
|
-
* Add hours to a date
|
|
19
|
-
*/
|
|
20
9
|
export function addHours(date: DateLike, hours: number): Date {
|
|
21
10
|
const result = new Date(date);
|
|
22
11
|
result.setHours(result.getHours() + hours);
|
|
23
12
|
return result;
|
|
24
13
|
}
|
|
25
14
|
|
|
26
|
-
/**
|
|
27
|
-
* Add minutes to a date
|
|
28
|
-
*/
|
|
29
15
|
export function addMinutes(date: DateLike, minutes: number): Date {
|
|
30
16
|
const result = new Date(date);
|
|
31
17
|
result.setMinutes(result.getMinutes() + minutes);
|
|
32
18
|
return result;
|
|
33
19
|
}
|
|
34
20
|
|
|
35
|
-
/**
|
|
36
|
-
* Add months to a date
|
|
37
|
-
*/
|
|
38
21
|
export function addMonths(date: DateLike, months: number): Date {
|
|
39
22
|
const result = new Date(date);
|
|
40
23
|
result.setMonth(result.getMonth() + months);
|
|
41
24
|
return result;
|
|
42
25
|
}
|
|
43
26
|
|
|
44
|
-
/**
|
|
45
|
-
* Add years to a date
|
|
46
|
-
*/
|
|
47
27
|
export function addYears(date: DateLike, years: number): Date {
|
|
48
28
|
const result = new Date(date);
|
|
49
29
|
result.setFullYear(result.getFullYear() + years);
|
|
50
30
|
return result;
|
|
51
31
|
}
|
|
52
32
|
|
|
53
|
-
/**
|
|
54
|
-
* Subtract days from a date
|
|
55
|
-
*/
|
|
56
33
|
export function subtractDays(date: DateLike, days: number): Date {
|
|
57
34
|
return addDays(date, -days);
|
|
58
35
|
}
|
|
59
36
|
|
|
60
|
-
/**
|
|
61
|
-
* Get start of day (midnight)
|
|
62
|
-
*/
|
|
63
37
|
export function startOfDay(date: DateLike): Date {
|
|
64
38
|
const d = new Date(date);
|
|
65
39
|
d.setHours(0, 0, 0, 0);
|
|
66
40
|
return d;
|
|
67
41
|
}
|
|
68
42
|
|
|
69
|
-
/**
|
|
70
|
-
* Get end of day (23:59:59.999)
|
|
71
|
-
*/
|
|
72
43
|
export function endOfDay(date: DateLike): Date {
|
|
73
44
|
const d = new Date(date);
|
|
74
45
|
d.setHours(23, 59, 59, 999);
|
|
75
46
|
return d;
|
|
76
47
|
}
|
|
77
48
|
|
|
78
|
-
/**
|
|
79
|
-
* Get start of week (Sunday)
|
|
80
|
-
*/
|
|
81
49
|
export function startOfWeek(date: DateLike): Date {
|
|
82
50
|
const d = new Date(date);
|
|
83
51
|
const day = d.getDay();
|
|
@@ -85,9 +53,6 @@ export function startOfWeek(date: DateLike): Date {
|
|
|
85
53
|
return new Date(d.setDate(diff));
|
|
86
54
|
}
|
|
87
55
|
|
|
88
|
-
/**
|
|
89
|
-
* Get end of week (Saturday)
|
|
90
|
-
*/
|
|
91
56
|
export function endOfWeek(date: DateLike): Date {
|
|
92
57
|
const d = new Date(date);
|
|
93
58
|
const day = d.getDay();
|
|
@@ -95,17 +60,11 @@ export function endOfWeek(date: DateLike): Date {
|
|
|
95
60
|
return new Date(d.setDate(diff));
|
|
96
61
|
}
|
|
97
62
|
|
|
98
|
-
/**
|
|
99
|
-
* Get start of month
|
|
100
|
-
*/
|
|
101
63
|
export function startOfMonth(date: DateLike): Date {
|
|
102
64
|
const d = new Date(date);
|
|
103
65
|
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
104
66
|
}
|
|
105
67
|
|
|
106
|
-
/**
|
|
107
|
-
* Get end of month
|
|
108
|
-
*/
|
|
109
68
|
export function endOfMonth(date: DateLike): Date {
|
|
110
69
|
const d = new Date(date);
|
|
111
70
|
return new Date(d.getFullYear(), d.getMonth() + 1, 0);
|
package/src/utils/dateUtils.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Package Period Utilities
|
|
3
|
-
* Helper functions for working with subscription periods
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
7
2
|
|
|
8
|
-
/**
|
|
9
|
-
* Get period label from subscription period string
|
|
10
|
-
*/
|
|
11
3
|
export const getPeriodLabel = (period: string | null | undefined): string => {
|
|
12
4
|
if (!period) return "";
|
|
13
5
|
if (period.includes("Y") || period.includes("year")) return "yearly";
|
|
@@ -17,33 +9,21 @@ export const getPeriodLabel = (period: string | null | undefined): string => {
|
|
|
17
9
|
return "";
|
|
18
10
|
};
|
|
19
11
|
|
|
20
|
-
/**
|
|
21
|
-
* Check if a package has a yearly subscription period
|
|
22
|
-
*/
|
|
23
12
|
export const isYearlyPackage = (pkg: PurchasesPackage): boolean => {
|
|
24
13
|
const period = pkg.product.subscriptionPeriod;
|
|
25
14
|
return period?.includes("Y") || period?.includes("year") || false;
|
|
26
15
|
};
|
|
27
16
|
|
|
28
|
-
/**
|
|
29
|
-
* Check if a package has a monthly subscription period
|
|
30
|
-
*/
|
|
31
17
|
export const isMonthlyPackage = (pkg: PurchasesPackage): boolean => {
|
|
32
18
|
const period = pkg.product.subscriptionPeriod;
|
|
33
19
|
return period?.includes("M") || period?.includes("month") || false;
|
|
34
20
|
};
|
|
35
21
|
|
|
36
|
-
/**
|
|
37
|
-
* Check if a package has a weekly subscription period
|
|
38
|
-
*/
|
|
39
22
|
export const isWeeklyPackage = (pkg: PurchasesPackage): boolean => {
|
|
40
23
|
const period = pkg.product.subscriptionPeriod;
|
|
41
24
|
return period?.includes("W") || period?.includes("week") || false;
|
|
42
25
|
};
|
|
43
26
|
|
|
44
|
-
/**
|
|
45
|
-
* Find the first yearly package in an array of packages
|
|
46
|
-
*/
|
|
47
27
|
export const findYearlyPackage = (
|
|
48
28
|
packages: PurchasesPackage[]
|
|
49
29
|
): PurchasesPackage | undefined => {
|
|
@@ -1,27 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Package Type Detector
|
|
3
|
-
* Detects subscription package type from RevenueCat package identifier
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import { PACKAGE_TYPE, type PackageType } from "../domains/subscription/core/SubscriptionConstants";
|
|
7
2
|
|
|
8
3
|
export type SubscriptionPackageType = PackageType;
|
|
9
4
|
|
|
10
|
-
/**
|
|
11
|
-
* Check if identifier is a credit package (consumable purchase)
|
|
12
|
-
* Credit packages use a different system and don't need type detection
|
|
13
|
-
*/
|
|
14
5
|
export function isCreditPackage(identifier: string): boolean {
|
|
15
6
|
if (!identifier) return false;
|
|
16
|
-
// Matches "credit" as a word or part of a common naming pattern
|
|
17
|
-
// More strict to avoid false positives (e.g. "accredited")
|
|
18
7
|
return /(?:^|[._-])credit(?:$|[._-])/i.test(identifier);
|
|
19
8
|
}
|
|
20
9
|
|
|
21
|
-
/**
|
|
22
|
-
* Detect package type from product identifier
|
|
23
|
-
* Supports common RevenueCat naming patterns with regex for better accuracy
|
|
24
|
-
*/
|
|
25
10
|
export function detectPackageType(productIdentifier: string): SubscriptionPackageType {
|
|
26
11
|
if (!productIdentifier) {
|
|
27
12
|
return PACKAGE_TYPE.UNKNOWN;
|
|
@@ -29,27 +14,22 @@ export function detectPackageType(productIdentifier: string): SubscriptionPackag
|
|
|
29
14
|
|
|
30
15
|
const normalized = productIdentifier.toLowerCase();
|
|
31
16
|
|
|
32
|
-
// Skip credit packages silently - they use creditPackageConfig instead
|
|
33
17
|
if (isCreditPackage(normalized)) {
|
|
34
18
|
return PACKAGE_TYPE.UNKNOWN;
|
|
35
19
|
}
|
|
36
20
|
|
|
37
|
-
// Weekly detection: matches "weekly" or "week" as distinct parts of the ID
|
|
38
21
|
if (/\bweekly?\b|_week_|-week-|\.week\./i.test(normalized)) {
|
|
39
22
|
return PACKAGE_TYPE.WEEKLY;
|
|
40
23
|
}
|
|
41
24
|
|
|
42
|
-
// Monthly detection: matches "monthly" or "month"
|
|
43
25
|
if (/\bmonthly?\b|_month_|-month-|\.month\./i.test(normalized)) {
|
|
44
26
|
return PACKAGE_TYPE.MONTHLY;
|
|
45
27
|
}
|
|
46
28
|
|
|
47
|
-
// Yearly detection: matches "yearly", "year", or "annual"
|
|
48
29
|
if (/\byearly?\b|_year_|-year-|\.year\.|annual/i.test(normalized)) {
|
|
49
30
|
return PACKAGE_TYPE.YEARLY;
|
|
50
31
|
}
|
|
51
|
-
|
|
52
|
-
// Lifetime detection: matches "lifetime"
|
|
32
|
+
|
|
53
33
|
if (/\blifetime\b|_lifetime_|-lifetime-|\.lifetime\./i.test(normalized)) {
|
|
54
34
|
return PACKAGE_TYPE.LIFETIME;
|
|
55
35
|
}
|
|
@@ -1,27 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Premium Status Utilities
|
|
3
|
-
*
|
|
4
|
-
* Core premium status determination logic
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
import type { PremiumStatusFetcher } from './types';
|
|
8
2
|
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Get isPremium value with centralized logic
|
|
12
|
-
*/
|
|
13
3
|
export function getIsPremium(
|
|
14
4
|
isAnonymous: boolean,
|
|
15
5
|
userId: string | null,
|
|
16
6
|
isPremiumOrFetcher: boolean | PremiumStatusFetcher,
|
|
17
7
|
): Promise<boolean> {
|
|
18
|
-
// Anonymous users NEVER have premium
|
|
19
8
|
if (isAnonymous || userId === null) return Promise.resolve(false);
|
|
20
9
|
|
|
21
|
-
// Sync mode: return the provided isPremium value
|
|
22
10
|
if (typeof isPremiumOrFetcher === 'boolean') return Promise.resolve(isPremiumOrFetcher);
|
|
23
11
|
|
|
24
|
-
// Async mode: fetch premium status
|
|
25
12
|
return (async () => {
|
|
26
13
|
try {
|
|
27
14
|
return await isPremiumOrFetcher.isPremium(userId!);
|
|
@@ -31,4 +18,4 @@ export function getIsPremium(
|
|
|
31
18
|
);
|
|
32
19
|
}
|
|
33
20
|
})();
|
|
34
|
-
}
|
|
21
|
+
}
|
package/src/utils/priceUtils.ts
CHANGED
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Price Formatting Utilities
|
|
3
|
-
* Apple App Store Guideline 3.1.2 Compliance
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Format price for display
|
|
8
|
-
* @param price - Price value
|
|
9
|
-
* @param currencyCode - Currency code (e.g., 'USD', 'EUR')
|
|
10
|
-
* @returns Formatted price string
|
|
11
|
-
*/
|
|
12
1
|
export function formatPrice(price: number, currencyCode: string): string {
|
|
13
2
|
try {
|
|
14
3
|
return new Intl.NumberFormat('en-US', {
|
|
@@ -28,35 +17,11 @@ const PERIOD_SUFFIX_MAP: Record<string, string> = {
|
|
|
28
17
|
yearly: '/year',
|
|
29
18
|
};
|
|
30
19
|
|
|
31
|
-
/**
|
|
32
|
-
* Extract billing period suffix from package identifier
|
|
33
|
-
* Apple App Store Guideline 3.1.2 Compliance:
|
|
34
|
-
* - Displays billing frequency clearly and conspicuously
|
|
35
|
-
* - Format: /week, /month, /year
|
|
36
|
-
*
|
|
37
|
-
* @param identifier - RevenueCat package identifier (e.g., "$rc_weekly", "$rc_monthly", "$rc_annual")
|
|
38
|
-
* @returns Billing period suffix (e.g., "/week", "/month", "/year") or empty string
|
|
39
|
-
*/
|
|
40
20
|
export function getBillingPeriodSuffix(identifier: string): string {
|
|
41
21
|
const packageType = detectPackageType(identifier);
|
|
42
22
|
return PERIOD_SUFFIX_MAP[packageType] ?? '';
|
|
43
23
|
}
|
|
44
24
|
|
|
45
|
-
/**
|
|
46
|
-
* Format price with billing period
|
|
47
|
-
* Apple App Store Guideline 3.1.2 Compliance:
|
|
48
|
-
* - Combines price with billing frequency for clear display
|
|
49
|
-
* - Format: $2.99/week, $14.99/month, $39.99/year
|
|
50
|
-
*
|
|
51
|
-
* RevenueCat Best Practice:
|
|
52
|
-
* - Follows recommended price_per_period format
|
|
53
|
-
* - Clear and conspicuous billing frequency display
|
|
54
|
-
*
|
|
55
|
-
* @param price - Price value
|
|
56
|
-
* @param currencyCode - Currency code (e.g., 'USD', 'EUR')
|
|
57
|
-
* @param identifier - RevenueCat package identifier
|
|
58
|
-
* @returns Formatted price with billing period (e.g., "$2.99/week")
|
|
59
|
-
*/
|
|
60
25
|
export function formatPriceWithPeriod(
|
|
61
26
|
price: number,
|
|
62
27
|
currencyCode: string,
|
package/src/utils/tierUtils.ts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* User Tier Core Utilities
|
|
3
|
-
*
|
|
4
|
-
* Core logic for determining user tier and premium status
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
import { USER_TIER, type UserTierInfo } from './types';
|
|
8
2
|
|
|
9
|
-
|
|
10
3
|
export function getUserTierInfo(
|
|
11
4
|
isAnonymous: boolean,
|
|
12
5
|
userId: string | null,
|
|
@@ -38,4 +31,4 @@ export function checkPremiumAccess(
|
|
|
38
31
|
): boolean {
|
|
39
32
|
if (isAnonymous || userId === null) return false;
|
|
40
33
|
return isPremium;
|
|
41
|
-
}
|
|
34
|
+
}
|
package/src/utils/types.ts
CHANGED
|
@@ -1,40 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* User Tier Types
|
|
3
|
-
*
|
|
4
|
-
* Type definitions for user tier system
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
import { USER_TIER, type UserTierType } from '../domains/subscription/core/SubscriptionConstants';
|
|
8
2
|
|
|
9
3
|
export type UserTier = UserTierType;
|
|
10
4
|
export { USER_TIER };
|
|
11
5
|
|
|
12
6
|
export interface UserTierInfo {
|
|
13
|
-
/** User tier classification */
|
|
14
7
|
tier: UserTier;
|
|
15
|
-
|
|
16
|
-
/** Whether user has premium access */
|
|
17
8
|
isPremium: boolean;
|
|
18
|
-
|
|
19
|
-
/** Whether user is anonymous (not authenticated) */
|
|
20
9
|
isAnonymous: boolean;
|
|
21
|
-
|
|
22
|
-
/** Whether user is authenticated */
|
|
23
10
|
isAuthenticated: boolean;
|
|
24
|
-
|
|
25
|
-
/** User ID (null for anonymous users) */
|
|
26
11
|
userId: string | null;
|
|
27
12
|
}
|
|
28
13
|
|
|
29
|
-
/**
|
|
30
|
-
* Premium status fetcher interface
|
|
31
|
-
* Apps should implement this to provide premium status from their database
|
|
32
|
-
*/
|
|
33
14
|
export interface PremiumStatusFetcher {
|
|
34
|
-
/**
|
|
35
|
-
* Check if user has active premium subscription
|
|
36
|
-
* @param userId - User ID (never null, this is only called for authenticated users)
|
|
37
|
-
* @returns Promise<boolean> - Whether user has premium subscription
|
|
38
|
-
*/
|
|
39
15
|
isPremium(userId: string): Promise<boolean>;
|
|
40
|
-
}
|
|
16
|
+
}
|
package/src/utils/validation.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* User Tier Validation Utilities
|
|
3
|
-
*
|
|
4
|
-
* Type guards and validation functions for user tier system
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
import { USER_TIER, type UserTier, type UserTierInfo } from './types';
|
|
8
2
|
|
|
9
3
|
export function isValidUserTier(value: unknown): value is UserTier {
|
|
@@ -20,4 +14,4 @@ export function isUserTierInfo(value: unknown): value is UserTierInfo {
|
|
|
20
14
|
typeof obj.isAuthenticated === 'boolean' &&
|
|
21
15
|
(obj.userId === null || typeof obj.userId === 'string')
|
|
22
16
|
);
|
|
23
|
-
}
|
|
17
|
+
}
|
package/src/domains/README.md
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Domains
|
|
2
|
-
|
|
3
|
-
Specialized domain modules implementing specific business logic and features.
|
|
4
|
-
|
|
5
|
-
## Location
|
|
6
|
-
|
|
7
|
-
`src/domains/`
|
|
8
|
-
|
|
9
|
-
## Strategy
|
|
10
|
-
|
|
11
|
-
Implements Domain-Driven Design (DDD) principles with self-contained domains. Each domain includes domain layer (business logic, entities, value objects), infrastructure layer (external integrations, repositories), and presentation layer (domain-specific hooks and components).
|
|
12
|
-
|
|
13
|
-
## Restrictions
|
|
14
|
-
|
|
15
|
-
### REQUIRED
|
|
16
|
-
|
|
17
|
-
- Domains MUST NOT directly depend on each other
|
|
18
|
-
- MUST use well-defined interfaces between layers
|
|
19
|
-
- MUST depend on abstractions, not concretions (Dependency Inversion)
|
|
20
|
-
- All domains MUST be testable in isolation
|
|
21
|
-
|
|
22
|
-
### PROHIBITED
|
|
23
|
-
|
|
24
|
-
- MUST NOT share domain logic between domains (use shared kernel if needed)
|
|
25
|
-
- MUST NOT create circular dependencies between domains
|
|
26
|
-
- MUST NOT bypass domain layer from presentation
|
|
27
|
-
- MUST NOT expose infrastructure details to other domains
|
|
28
|
-
|
|
29
|
-
### CRITICAL
|
|
30
|
-
|
|
31
|
-
- Always validate invariants at domain boundaries
|
|
32
|
-
- Always implement domain errors for business rule violations
|
|
33
|
-
- Never allow inconsistent domain state
|
|
34
|
-
- Must implement proper transaction boundaries
|
|
35
|
-
- Always sanitize inputs from external sources
|
|
36
|
-
|
|
37
|
-
## AI Agent Guidelines
|
|
38
|
-
|
|
39
|
-
When working with domains:
|
|
40
|
-
1. Always respect domain boundaries
|
|
41
|
-
2. Always use dependency inversion
|
|
42
|
-
3. Always implement domain-specific errors
|
|
43
|
-
4. Always validate invariants at boundaries
|
|
44
|
-
5. Never create circular dependencies
|
|
45
|
-
|
|
46
|
-
## Related Documentation
|
|
47
|
-
|
|
48
|
-
- [Wallet Domain](wallet/README.md)
|
|
49
|
-
- [Paywall Domain](paywall/README.md)
|
|
50
|
-
- [Config Domain](config/README.md)
|
|
51
|
-
- [Domain Layer](../domain/README.md)
|
|
52
|
-
- [Infrastructure](../infrastructure/README.md)
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# Config Domain
|
|
2
|
-
|
|
3
|
-
## Location
|
|
4
|
-
Domain layer for configuration management.
|
|
5
|
-
|
|
6
|
-
## Strategy
|
|
7
|
-
This directory contains the business logic and domain models for subscription and feature configuration.
|
|
8
|
-
|
|
9
|
-
## Restrictions
|
|
10
|
-
|
|
11
|
-
### REQUIRED
|
|
12
|
-
- Must use entities for domain models
|
|
13
|
-
- Must validate in constructor
|
|
14
|
-
- Must keep entities immutable
|
|
15
|
-
|
|
16
|
-
### PROHIBITED
|
|
17
|
-
- DO NOT bypass entity validation
|
|
18
|
-
- DO NOT mutate entities after creation
|
|
19
|
-
- DO NOT leak domain logic to application layer
|
|
20
|
-
|
|
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
|
|
25
|
-
|
|
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
|
|
33
|
-
|
|
34
|
-
## Related Documentation
|
|
35
|
-
- [Config Domain](../../README.md)
|
|
36
|
-
- [Config Entities](./entities/README.md)
|
|
37
|
-
- [Config Value Objects](./value-objects/README.md)
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Config Domain Entities
|
|
2
|
-
|
|
3
|
-
## Location
|
|
4
|
-
Domain entities for configuration management.
|
|
5
|
-
|
|
6
|
-
## Strategy
|
|
7
|
-
This directory contains entity classes representing configuration concepts like packages, features, and paywalls with strict validation and immutability.
|
|
8
|
-
|
|
9
|
-
## Restrictions
|
|
10
|
-
|
|
11
|
-
### REQUIRED
|
|
12
|
-
- Must validate all configuration in constructor
|
|
13
|
-
- Must treat entities as immutable
|
|
14
|
-
- Must provide clear error messages
|
|
15
|
-
- Must use TypeScript strict mode
|
|
16
|
-
|
|
17
|
-
### PROHIBITED
|
|
18
|
-
- DO NOT modify entities after creation
|
|
19
|
-
- DO NOT bypass validation logic
|
|
20
|
-
- DO NOT expose mutable internal state
|
|
21
|
-
- DO NOT allow invalid configuration
|
|
22
|
-
|
|
23
|
-
### CRITICAL SAFETY
|
|
24
|
-
- All validation MUST happen in constructor
|
|
25
|
-
- Entities MUST fail fast on invalid input
|
|
26
|
-
- Error messages MUST be descriptive
|
|
27
|
-
- Factory functions MUST provide valid defaults
|
|
28
|
-
|
|
29
|
-
## AI Agent Guidelines
|
|
30
|
-
1. Always validate configuration data in entity constructors
|
|
31
|
-
2. Treat all entities as immutable values
|
|
32
|
-
3. Keep business logic encapsulated within entities
|
|
33
|
-
4. Provide factory functions for common configurations
|
|
34
|
-
5. Test validation logic thoroughly
|
|
35
|
-
6. Use TypeScript strict types for all properties
|
|
36
|
-
7. Return descriptive error messages for validation failures
|
|
37
|
-
|
|
38
|
-
## Related Documentation
|
|
39
|
-
- [Config Domain](../README.md)
|
|
40
|
-
- [Config Value Objects](../value-objects/README.md)
|
|
41
|
-
- [Config Utils](../../utils/README.md)
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { ICreditStrategy, type CreditAllocationParams } from "./ICreditStrategy";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Strategy for status synchronization (app open, auth state changes).
|
|
5
|
-
* ONLY preserves existing credits. NEVER allocates new credits.
|
|
6
|
-
* New credits are ONLY allocated by purchase and renewal flows.
|
|
7
|
-
*/
|
|
8
|
-
export class SyncCreditStrategy implements ICreditStrategy {
|
|
9
|
-
canHandle(params: CreditAllocationParams): boolean {
|
|
10
|
-
return params.isStatusSync;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
execute(params: CreditAllocationParams): number {
|
|
14
|
-
// Status sync only preserves existing credits, never allocates new ones
|
|
15
|
-
const existingCredits = params.existingData?.credits;
|
|
16
|
-
if (typeof existingCredits === 'number' && existingCredits >= 0) {
|
|
17
|
-
return existingCredits;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// No existing credits = no document = return 0
|
|
21
|
-
// Credits are only allocated through purchase/renewal flows
|
|
22
|
-
return 0;
|
|
23
|
-
}
|
|
24
|
-
}
|