@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.
Files changed (141) hide show
  1. package/package.json +1 -1
  2. package/src/domains/credits/application/CreditLimitCalculator.ts +1 -9
  3. package/src/domains/credits/application/CreditsInitializer.ts +5 -20
  4. package/src/domains/credits/application/DeductCreditsCommand.ts +13 -6
  5. package/src/domains/credits/application/RefundCreditsCommand.ts +1 -5
  6. package/src/domains/credits/application/credit-strategies/CreditAllocationOrchestrator.ts +1 -9
  7. package/src/domains/credits/application/credit-strategies/ICreditStrategy.ts +1 -5
  8. package/src/domains/credits/application/credit-strategies/TrialCreditStrategy.ts +1 -5
  9. package/src/domains/credits/application/creditDocumentHelpers.ts +2 -9
  10. package/src/domains/credits/application/creditOperationUtils.ts +1 -43
  11. package/src/domains/credits/core/Credits.ts +0 -23
  12. package/src/domains/credits/core/CreditsConstants.ts +0 -11
  13. package/src/domains/credits/core/CreditsMapper.ts +0 -6
  14. package/src/domains/credits/core/UserCreditsDocument.ts +0 -12
  15. package/src/domains/credits/infrastructure/CreditsRepository.ts +6 -1
  16. package/src/domains/credits/infrastructure/CreditsRepositoryManager.ts +0 -21
  17. package/src/domains/credits/infrastructure/operations/CreditsWriter.ts +52 -1
  18. package/src/domains/credits/presentation/deduct-credit/useDeductCredit.ts +2 -2
  19. package/src/domains/credits/presentation/useCredits.ts +10 -9
  20. package/src/domains/paywall/components/PaywallContainer.types.ts +0 -28
  21. package/src/domains/paywall/components/PaywallModal.styles.ts +0 -4
  22. package/src/domains/paywall/entities/types.ts +0 -5
  23. package/src/domains/paywall/hooks/usePaywallActions.ts +1 -15
  24. package/src/domains/revenuecat/core/errors/RevenueCatError.ts +0 -6
  25. package/src/domains/revenuecat/core/errors/RevenueCatErrorHandler.ts +0 -24
  26. package/src/domains/revenuecat/core/errors/RevenueCatErrorMessages.ts +0 -18
  27. package/src/domains/revenuecat/core/errors/index.ts +0 -4
  28. package/src/domains/revenuecat/core/types/RevenueCatConfig.ts +3 -7
  29. package/src/domains/revenuecat/core/types/RevenueCatData.ts +4 -9
  30. package/src/domains/revenuecat/core/types/RevenueCatTypes.ts +5 -65
  31. package/src/domains/revenuecat/core/types/index.ts +0 -4
  32. package/src/domains/revenuecat/infrastructure/services/UserSwitchMutex.ts +1 -24
  33. package/src/domains/subscription/application/SubscriptionAuthListener.ts +5 -21
  34. package/src/domains/subscription/application/SubscriptionInitializerTypes.ts +1 -5
  35. package/src/domains/subscription/application/SubscriptionSyncProcessor.ts +0 -4
  36. package/src/domains/subscription/application/SubscriptionSyncService.ts +4 -8
  37. package/src/domains/subscription/application/SubscriptionSyncUtils.ts +1 -1
  38. package/src/domains/subscription/application/initializer/BackgroundInitializer.ts +15 -2
  39. package/src/domains/subscription/application/initializer/ServiceConfigurator.ts +9 -2
  40. package/src/domains/subscription/application/statusChangeHandlers.ts +14 -27
  41. package/src/domains/subscription/application/syncIdGenerators.ts +0 -4
  42. package/src/domains/subscription/constants/thresholds.ts +0 -9
  43. package/src/domains/subscription/core/SubscriptionConstants.ts +0 -4
  44. package/src/domains/subscription/core/SubscriptionStatus.ts +11 -21
  45. package/src/domains/subscription/core/SubscriptionStatusHandlers.ts +4 -7
  46. package/src/domains/subscription/infrastructure/handlers/PurchaseStatusResolver.ts +1 -1
  47. package/src/domains/subscription/infrastructure/hooks/subscriptionQueryKeys.ts +0 -13
  48. package/src/domains/subscription/infrastructure/hooks/usePurchasePackage.ts +0 -18
  49. package/src/domains/subscription/infrastructure/hooks/useRestorePurchase.ts +3 -17
  50. package/src/domains/subscription/infrastructure/hooks/useRevenueCatTrialEligibility.ts +0 -17
  51. package/src/domains/subscription/infrastructure/hooks/useSubscriptionPackages.ts +0 -19
  52. package/src/domains/subscription/infrastructure/hooks/useSubscriptionQueries.ts +0 -6
  53. package/src/domains/subscription/infrastructure/managers/subscriptionManagerUtils.ts +0 -17
  54. package/src/domains/subscription/infrastructure/state/initializationState.ts +0 -25
  55. package/src/domains/subscription/infrastructure/utils/InitializationCache.ts +0 -21
  56. package/src/domains/subscription/infrastructure/utils/PremiumStatusSyncer.ts +3 -17
  57. package/src/domains/subscription/infrastructure/utils/authPurchaseState.ts +0 -5
  58. package/src/domains/subscription/infrastructure/utils/renewal/PackageTierComparator.ts +1 -0
  59. package/src/domains/subscription/infrastructure/utils/trialEligibilityUtils.ts +0 -18
  60. package/src/domains/subscription/presentation/components/details/PremiumDetailsCard.styles.ts +0 -5
  61. package/src/domains/subscription/presentation/components/details/PremiumDetailsCardTypes.ts +0 -5
  62. package/src/domains/subscription/presentation/components/feedback/paywallFeedbackStyles.ts +0 -5
  63. package/src/domains/subscription/presentation/stores/index.ts +0 -4
  64. package/src/domains/subscription/presentation/stores/purchaseLoadingStore.ts +0 -13
  65. package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +30 -21
  66. package/src/domains/subscription/presentation/usePaywallVisibility.ts +0 -9
  67. package/src/domains/subscription/presentation/useSubscriptionStatus.ts +8 -11
  68. package/src/domains/subscription/utils/authGuards.ts +3 -0
  69. package/src/domains/trial/application/TrialService.ts +0 -9
  70. package/src/domains/trial/core/TrialTypes.ts +0 -8
  71. package/src/domains/wallet/domain/mappers/TransactionMapper.ts +0 -5
  72. package/src/domains/wallet/domain/types/transaction.types.ts +0 -7
  73. package/src/domains/wallet/index.ts +0 -7
  74. package/src/domains/wallet/infrastructure/config/walletConfig.ts +0 -11
  75. package/src/domains/wallet/presentation/hooks/useTransactionHistory.ts +6 -3
  76. package/src/domains/wallet/presentation/hooks/useWallet.ts +0 -7
  77. package/src/domains/wallet/utils/transactionIconMap.ts +0 -10
  78. package/src/global.d.ts +0 -6
  79. package/src/index.ts +1 -4
  80. package/src/init/createSubscriptionInitModule.ts +12 -2
  81. package/src/init/index.ts +1 -5
  82. package/src/presentation/hooks/feedback/useFeedbackSubmit.ts +0 -11
  83. package/src/shared/application/FeedbackService.ts +3 -21
  84. package/src/shared/application/ports/ISubscriptionRepository.ts +0 -4
  85. package/src/shared/infrastructure/SubscriptionEventBus.ts +0 -13
  86. package/src/shared/infrastructure/firestore/collectionUtils.ts +1 -17
  87. package/src/shared/infrastructure/firestore/index.ts +0 -4
  88. package/src/shared/infrastructure/firestore/resultUtils.ts +0 -12
  89. package/src/shared/infrastructure/react-query/hooks/usePreviousUserCleanup.ts +0 -17
  90. package/src/shared/infrastructure/react-query/queryConfig.ts +0 -15
  91. package/src/shared/utils/BaseError.ts +0 -5
  92. package/src/shared/utils/Result.ts +0 -20
  93. package/src/shared/utils/dateConverter.ts +6 -46
  94. package/src/utils/appUtils.ts +0 -16
  95. package/src/utils/creditMapper.ts +0 -7
  96. package/src/utils/dateUtils.compare.ts +0 -24
  97. package/src/utils/dateUtils.core.ts +0 -39
  98. package/src/utils/dateUtils.format.ts +0 -41
  99. package/src/utils/dateUtils.math.ts +0 -41
  100. package/src/utils/dateUtils.ts +0 -5
  101. package/src/utils/packagePeriodUtils.ts +0 -20
  102. package/src/utils/packageTypeDetector.ts +1 -21
  103. package/src/utils/premiumStatusUtils.ts +1 -14
  104. package/src/utils/priceUtils.ts +0 -35
  105. package/src/utils/tierUtils.ts +1 -8
  106. package/src/utils/types.ts +1 -25
  107. package/src/utils/validation.ts +1 -7
  108. package/src/domains/README.md +0 -52
  109. package/src/domains/config/domain/README.md +0 -37
  110. package/src/domains/config/domain/entities/README.md +0 -41
  111. package/src/domains/credits/application/credit-strategies/SyncCreditStrategy.ts +0 -24
  112. package/src/domains/paywall/README.md +0 -101
  113. package/src/domains/paywall/entities/README.md +0 -40
  114. package/src/domains/paywall/hooks/README.md +0 -41
  115. package/src/domains/subscription/application/syncConstants.ts +0 -1
  116. package/src/domains/subscription/infrastructure/README.md +0 -41
  117. package/src/domains/subscription/infrastructure/config/README.md +0 -49
  118. package/src/domains/subscription/infrastructure/handlers/README.md +0 -41
  119. package/src/domains/subscription/infrastructure/hooks/README.md +0 -50
  120. package/src/domains/subscription/infrastructure/managers/README.md +0 -41
  121. package/src/domains/subscription/infrastructure/services/README.md +0 -42
  122. package/src/domains/subscription/infrastructure/utils/README.md +0 -41
  123. package/src/domains/subscription/presentation/components/README.md +0 -155
  124. package/src/domains/subscription/presentation/components/details/CreditRow.md +0 -92
  125. package/src/domains/subscription/presentation/components/details/DetailRow.md +0 -91
  126. package/src/domains/subscription/presentation/components/details/PremiumDetailsCard.md +0 -93
  127. package/src/domains/subscription/presentation/components/details/PremiumStatusBadge.md +0 -91
  128. package/src/domains/subscription/presentation/components/details/README.md +0 -99
  129. package/src/domains/subscription/presentation/components/feedback/PaywallFeedbackModal.md +0 -90
  130. package/src/domains/subscription/presentation/components/feedback/README.md +0 -99
  131. package/src/domains/subscription/presentation/components/paywall/PaywallModal.md +0 -94
  132. package/src/domains/subscription/presentation/components/paywall/README.md +0 -54
  133. package/src/domains/subscription/presentation/components/sections/README.md +0 -99
  134. package/src/domains/subscription/presentation/components/sections/SubscriptionSection.md +0 -94
  135. package/src/domains/subscription/presentation/utils/README.md +0 -31
  136. package/src/domains/wallet/README.md +0 -51
  137. package/src/domains/wallet/domain/README.md +0 -41
  138. package/src/domains/wallet/infrastructure/README.md +0 -41
  139. package/src/domains/wallet/presentation/components/README.md +0 -41
  140. package/src/domains/wallet/presentation/hooks/README.md +0 -41
  141. package/src/shared/application/ports/README.md +0 -48
@@ -1,57 +1,29 @@
1
- /**
2
- * PaywallContainer Types
3
- * Props for subscription paywall
4
- */
5
-
6
1
  import type { ImageSourcePropType } from "react-native";
7
2
  import type { PaywallTranslations, PaywallLegalUrls, SubscriptionFeature } from "../entities/types";
8
3
  import type { PurchaseSource } from "../../subscription/core/SubscriptionConstants";
9
4
  import type { PackageAllocationMap } from "../../credits/core/Credits";
10
5
 
11
- /**
12
- * Trial display configuration
13
- * Controls how free trial info is displayed (Apple-compliant)
14
- */
15
6
  export interface TrialConfig {
16
- /** Enable trial display (default: false) */
17
7
  readonly enabled: boolean;
18
- /** Product IDs that have trial offers (if empty, checks all via RevenueCat) */
19
8
  readonly eligibleProductIds?: readonly string[];
20
- /** Trial duration in days (default: 7) */
21
9
  readonly durationDays?: number;
22
- /** Text to show for trial (e.g., "7 days free, then billed") */
23
10
  readonly trialText?: string;
24
11
  }
25
12
 
26
13
  export interface PaywallContainerProps {
27
- /** Paywall translations - no defaults, must be provided */
28
14
  readonly translations: PaywallTranslations;
29
- /** Legal URLs for privacy and terms */
30
15
  readonly legalUrls?: PaywallLegalUrls;
31
- /** Feature list to display */
32
16
  readonly features?: readonly SubscriptionFeature[];
33
- /** Hero image for paywall header */
34
17
  readonly heroImage?: ImageSourcePropType;
35
- /** Best value package identifier for badge */
36
18
  readonly bestValueIdentifier?: string;
37
- /** Credit amounts per product identifier (takes precedence over packageAllocations) */
38
19
  readonly creditAmounts?: Record<string, number>;
39
- /** Credits label text (e.g., "credits") */
40
20
  readonly creditsLabel?: string;
41
- /** Package allocations for auto-computing creditAmounts (used when creditAmounts not provided) */
42
21
  readonly packageAllocations?: PackageAllocationMap;
43
- /** Source of the paywall - affects pending purchase handling */
44
22
  readonly source?: PurchaseSource;
45
- /** Callback when purchase succeeds */
46
23
  readonly onPurchaseSuccess?: () => void;
47
- /** Callback when purchase fails */
48
24
  readonly onPurchaseError?: (error: Error | string) => void;
49
- /** Callback when auth is required (for anonymous users) */
50
25
  readonly onAuthRequired?: () => void;
51
- /** Visibility override */
52
26
  readonly visible?: boolean;
53
- /** Callback when paywall is closed */
54
27
  readonly onClose?: () => void;
55
- /** Trial display configuration (Apple-compliant) */
56
28
  readonly trialConfig?: TrialConfig;
57
29
  }
@@ -1,7 +1,3 @@
1
- /**
2
- * PaywallModal Styles
3
- */
4
-
5
1
  import { StyleSheet } from "react-native";
6
2
 
7
3
  export const paywallModalStyles = StyleSheet.create({
@@ -1,8 +1,3 @@
1
- /**
2
- * Paywall Types
3
- * All paywall-related type definitions
4
- */
5
-
6
1
  export interface SubscriptionFeature {
7
2
  icon: string;
8
3
  text: string;
@@ -1,7 +1,3 @@
1
- /**
2
- * usePaywallActions Hook
3
- * Encapsulates purchase and restore flow for the paywall.
4
- */
5
1
  import { useState, useCallback, useRef, useEffect } from "react";
6
2
  import type { PurchasesPackage } from "react-native-purchases";
7
3
  import { usePurchaseLoadingStore } from "../../subscription/presentation/stores";
@@ -52,7 +48,6 @@ export function usePaywallActions({
52
48
  });
53
49
 
54
50
  const handlePurchase = useCallback(async () => {
55
-
56
51
  if (!selectedPlanId) {
57
52
  return;
58
53
  }
@@ -71,7 +66,7 @@ export function usePaywallActions({
71
66
 
72
67
  if (!pkg) {
73
68
  if (typeof __DEV__ !== "undefined" && __DEV__) {
74
- console.error("[usePaywallActions] Package not found", {
69
+ console.error("[usePaywallActions] Package not found", {
75
70
  selectedPlanId,
76
71
  availablePackages: packages.map(p => p.product.identifier),
77
72
  });
@@ -85,18 +80,12 @@ export function usePaywallActions({
85
80
  startPurchase(selectedPlanId, "manual");
86
81
 
87
82
  try {
88
-
89
83
  const success = await onPurchaseRef.current(pkg);
90
84
 
91
85
  if (success === true) {
92
86
  onPurchaseSuccessRef.current?.();
93
87
  onCloseRef.current?.();
94
- } else if (success === false) {
95
- if (typeof __DEV__ !== "undefined" && __DEV__) {
96
- console.warn("[usePaywallActions] ⚠️ Purchase returned false (user cancelled or failed)");
97
- }
98
88
  }
99
- // else: success is undefined/null - no action needed
100
89
  } catch (error) {
101
90
  const err = error instanceof Error ? error : new Error(String(error));
102
91
  onPurchaseErrorRef.current?.(err);
@@ -107,7 +96,6 @@ export function usePaywallActions({
107
96
  }, [selectedPlanId, packages, isProcessing, startPurchase, endPurchase]);
108
97
 
109
98
  const handleRestore = useCallback(async () => {
110
-
111
99
  if (!onRestoreRef.current) {
112
100
  const err = new Error("Restore handler not configured");
113
101
  onPurchaseErrorRef.current?.(err);
@@ -120,13 +108,11 @@ export function usePaywallActions({
120
108
 
121
109
  setIsLocalProcessing(true);
122
110
  try {
123
-
124
111
  const success = await onRestoreRef.current();
125
112
 
126
113
  if (success === true) {
127
114
  onPurchaseSuccessRef.current?.();
128
115
  }
129
- // else: success is false/undefined - restore failed or user cancelled, no action needed
130
116
  } catch (error) {
131
117
  const err = error instanceof Error ? error : new Error(String(error));
132
118
  onPurchaseErrorRef.current?.(err);
@@ -1,8 +1,3 @@
1
- /**
2
- * RevenueCat Error Classes
3
- * Domain-specific error types for RevenueCat operations
4
- */
5
-
6
1
  import { BaseError } from "../../../../shared/utils/BaseError";
7
2
 
8
3
  class RevenueCatError extends BaseError {
@@ -49,4 +44,3 @@ export class RevenueCatNetworkError extends RevenueCatError {
49
44
  this.name = "RevenueCatNetworkError";
50
45
  }
51
46
  }
52
-
@@ -1,8 +1,3 @@
1
- /**
2
- * RevenueCat Error Handler
3
- * Error code mapping and message resolution utilities
4
- */
5
-
6
1
  import Purchases from "react-native-purchases";
7
2
  import {
8
3
  ERROR_MESSAGES_MAP,
@@ -11,12 +6,7 @@ import {
11
6
  type PurchasesErrorCode,
12
7
  } from "./RevenueCatErrorMessages";
13
8
 
14
- /**
15
- * Error Code to Enum Mapping
16
- * Maps both string keys and numeric codes to Purchases error enum values
17
- */
18
9
  const ERROR_CODE_MAP = new Map<string, PurchasesErrorCode>([
19
- // String error codes
20
10
  ["PURCHASE_CANCELLED_ERROR", Purchases.PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR],
21
11
  ["PURCHASE_NOT_ALLOWED_ERROR", Purchases.PURCHASES_ERROR_CODE.PURCHASE_NOT_ALLOWED_ERROR],
22
12
  ["PURCHASE_INVALID_ERROR", Purchases.PURCHASES_ERROR_CODE.PURCHASE_INVALID_ERROR],
@@ -31,7 +21,6 @@ const ERROR_CODE_MAP = new Map<string, PurchasesErrorCode>([
31
21
  ["STORE_PROBLEM_ERROR", Purchases.PURCHASES_ERROR_CODE.STORE_PROBLEM_ERROR],
32
22
  ["PAYMENT_PENDING_ERROR", Purchases.PURCHASES_ERROR_CODE.PAYMENT_PENDING_ERROR],
33
23
 
34
- // Numeric error codes as fallback
35
24
  ["1", Purchases.PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR],
36
25
  ["2", Purchases.PURCHASES_ERROR_CODE.STORE_PROBLEM_ERROR],
37
26
  ["3", Purchases.PURCHASES_ERROR_CODE.PURCHASE_NOT_ALLOWED_ERROR],
@@ -47,13 +36,6 @@ const ERROR_CODE_MAP = new Map<string, PurchasesErrorCode>([
47
36
  ["0", Purchases.PURCHASES_ERROR_CODE.UNKNOWN_ERROR],
48
37
  ]);
49
38
 
50
- /**
51
- * Get error message configuration for a given error code
52
- * Strategy Pattern with Map lookup - O(1) complexity
53
- *
54
- * @param errorCode - Error code string from RevenueCat error
55
- * @returns ErrorMessage configuration
56
- */
57
39
  function getErrorMessageForCode(errorCode: string | null | undefined): ErrorMessage {
58
40
  if (!errorCode) {
59
41
  return DEFAULT_ERROR_MESSAGE;
@@ -70,12 +52,6 @@ function getErrorMessageForCode(errorCode: string | null | undefined): ErrorMess
70
52
  return DEFAULT_ERROR_MESSAGE;
71
53
  }
72
54
 
73
- /**
74
- * Get error message from RevenueCat error object
75
- *
76
- * @param error - RevenueCat error object
77
- * @returns ErrorMessage configuration
78
- */
79
55
  export function getErrorMessage(error: unknown): ErrorMessage {
80
56
  if (!error || typeof error !== "object") {
81
57
  return DEFAULT_ERROR_MESSAGE;
@@ -1,28 +1,13 @@
1
- /**
2
- * RevenueCat Error Messages
3
- * User-friendly error message configurations
4
- */
5
-
6
1
  import Purchases from "react-native-purchases";
7
2
 
8
- /**
9
- * Error Message Configuration
10
- */
11
3
  export interface ErrorMessage {
12
4
  title: string;
13
5
  message: string;
14
6
  shouldShowAlert?: boolean;
15
7
  }
16
8
 
17
- /**
18
- * RevenueCat Error Code Type
19
- */
20
9
  export type PurchasesErrorCode = typeof Purchases.PURCHASES_ERROR_CODE[keyof typeof Purchases.PURCHASES_ERROR_CODE];
21
10
 
22
- /**
23
- * User-friendly error messages mapped by error code enum
24
- * Strategy Pattern: Each error code has its own message configuration
25
- */
26
11
  export const ERROR_MESSAGES_MAP = new Map<PurchasesErrorCode, ErrorMessage>([
27
12
  [
28
13
  Purchases.PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR,
@@ -130,9 +115,6 @@ export const ERROR_MESSAGES_MAP = new Map<PurchasesErrorCode, ErrorMessage>([
130
115
  ],
131
116
  ]);
132
117
 
133
- /**
134
- * Default error message for unknown errors
135
- */
136
118
  export const DEFAULT_ERROR_MESSAGE: ErrorMessage = {
137
119
  title: "Error",
138
120
  message: "An error occurred. Please try again.",
@@ -1,7 +1,3 @@
1
- /**
2
- * RevenueCat Domain - Error Handling
3
- */
4
-
5
1
  export * from "./RevenueCatError";
6
2
  export * from "./RevenueCatErrorMessages";
7
3
  export * from "./RevenueCatErrorHandler";
@@ -1,10 +1,6 @@
1
1
  import type { CustomerInfo } from "react-native-purchases";
2
2
  import type { PackageType } from "./RevenueCatTypes";
3
3
 
4
- /**
5
- * RevenueCat Configuration
6
- * All callbacks receive data directly from RevenueCat SDK
7
- */
8
4
  export interface RevenueCatConfig {
9
5
  apiKey?: string;
10
6
  entitlementIdentifier: string;
@@ -15,14 +11,14 @@ export interface RevenueCatConfig {
15
11
  productId?: string,
16
12
  expiresAt?: string,
17
13
  willRenew?: boolean,
18
- periodType?: string // From RevenueCat SDK (NORMAL, INTRO, TRIAL)
14
+ periodType?: string
19
15
  ) => Promise<void> | void;
20
16
  onPurchaseCompleted?: (
21
17
  userId: string,
22
18
  productId: string,
23
19
  customerInfo: CustomerInfo,
24
- source?: string, // Purchase source tracking (app-specific)
25
- packageType?: PackageType | null // From PurchasesPackage.packageType - subscription duration (WEEKLY, MONTHLY, ANNUAL, etc.)
20
+ source?: string,
21
+ packageType?: PackageType | null
26
22
  ) => Promise<void> | void;
27
23
  onRestoreCompleted?: (
28
24
  userId: string,
@@ -1,19 +1,14 @@
1
1
  import type { Store, OwnershipType, PackageType } from "./RevenueCatTypes";
2
2
 
3
- /**
4
- * RevenueCat subscription data (Single Source of Truth)
5
- * Used across the subscription package for storing RevenueCat data in Firestore
6
- * All fields come directly from RevenueCat SDK - no manual definitions
7
- */
8
3
  export interface RevenueCatData {
9
4
  expirationDate: string | null;
10
5
  willRenew: boolean | null;
11
6
  originalTransactionId: string | null;
12
7
  isPremium: boolean;
13
- periodType: string | null; // From RevenueCat SDK (NORMAL, INTRO, TRIAL) - pricing type
14
- packageType: PackageType | null; // From PurchasesPackage.packageType - subscription duration (WEEKLY, MONTHLY, ANNUAL, etc.)
8
+ periodType: string | null;
9
+ packageType: PackageType | null;
15
10
  unsubscribeDetectedAt: string | null;
16
11
  billingIssueDetectedAt: string | null;
17
- store: Store | null; // From PurchasesEntitlementInfo['store']
18
- ownershipType: OwnershipType | null; // From PurchasesEntitlementInfo['ownershipType']
12
+ store: Store | null;
13
+ ownershipType: OwnershipType | null;
19
14
  }
@@ -1,39 +1,9 @@
1
- /**
2
- * RevenueCat Type Definitions
3
- * Proper typing for RevenueCat entitlements and errors
4
- */
5
-
6
1
  import type { CustomerInfo, PurchasesEntitlementInfo, PurchasesPackage } from "react-native-purchases";
7
2
 
8
- /**
9
- * Default entitlement identifier
10
- * Can be overridden in RevenueCatConfig
11
- */
12
- const DEFAULT_ENTITLEMENT_ID = "premium";
13
-
14
- /**
15
- * Store type - Directly from RevenueCat SDK
16
- * Automatically stays in sync with RevenueCat SDK updates
17
- */
18
3
  export type Store = PurchasesEntitlementInfo['store'];
19
-
20
- /**
21
- * OwnershipType - Directly from RevenueCat SDK
22
- * Automatically stays in sync with RevenueCat SDK updates
23
- */
24
4
  export type OwnershipType = PurchasesEntitlementInfo['ownershipType'];
25
-
26
- /**
27
- * PackageType - Directly from RevenueCat SDK
28
- * Represents subscription duration (WEEKLY, MONTHLY, ANNUAL, LIFETIME, etc.)
29
- * Automatically stays in sync with RevenueCat SDK updates
30
- */
31
5
  export type PackageType = PurchasesPackage['packageType'];
32
6
 
33
- /**
34
- * RevenueCat Entitlement Info
35
- * Represents active entitlement data from CustomerInfo
36
- */
37
7
  interface RevenueCatEntitlement {
38
8
  identifier: string;
39
9
  productIdentifier: string;
@@ -45,11 +15,10 @@ interface RevenueCatEntitlement {
45
15
  expirationDate: string | null;
46
16
  unsubscribeDetectedAt: string | null;
47
17
  billingIssueDetectedAt: string | null;
18
+ store: Store | null;
19
+ ownershipType: OwnershipType | null;
48
20
  }
49
21
 
50
- /**
51
- * RevenueCat Purchase Error with userCancelled flag
52
- */
53
22
  interface RevenueCatPurchaseErrorInfo extends Error {
54
23
  userCancelled?: boolean;
55
24
  code?: string;
@@ -57,12 +26,9 @@ interface RevenueCatPurchaseErrorInfo extends Error {
57
26
  underlyingErrorMessage?: string;
58
27
  }
59
28
 
60
- /**
61
- * Extract entitlement from CustomerInfo
62
- */
63
29
  export function getPremiumEntitlement(
64
30
  customerInfo: CustomerInfo,
65
- entitlementIdentifier: string = DEFAULT_ENTITLEMENT_ID
31
+ entitlementIdentifier: string
66
32
  ): RevenueCatEntitlement | null {
67
33
  const entitlement = customerInfo.entitlements.active[entitlementIdentifier];
68
34
  if (!entitlement) {
@@ -80,19 +46,15 @@ export function getPremiumEntitlement(
80
46
  expirationDate: entitlement.expirationDate,
81
47
  unsubscribeDetectedAt: entitlement.unsubscribeDetectedAt,
82
48
  billingIssueDetectedAt: entitlement.billingIssueDetectedAt,
49
+ store: entitlement.store ?? null,
50
+ ownershipType: entitlement.ownershipType ?? null,
83
51
  };
84
52
  }
85
53
 
86
- /**
87
- * Type guard for RevenueCat purchase error
88
- */
89
54
  function isRevenueCatPurchaseError(error: unknown): error is RevenueCatPurchaseErrorInfo {
90
55
  return error instanceof Error && ("userCancelled" in error || "code" in error);
91
56
  }
92
57
 
93
- /**
94
- * Extract error code from RevenueCat error
95
- */
96
58
  export function getErrorCode(error: unknown): string | null {
97
59
  if (!isRevenueCatPurchaseError(error)) {
98
60
  return null;
@@ -100,57 +62,35 @@ export function getErrorCode(error: unknown): string | null {
100
62
  return error.code || error.readableErrorCode || null;
101
63
  }
102
64
 
103
- /**
104
- * Check if error is a user cancellation
105
- * Checks both userCancelled flag and PURCHASE_CANCELLED_ERROR code
106
- */
107
65
  export function isUserCancelledError(error: unknown): boolean {
108
66
  if (!isRevenueCatPurchaseError(error)) {
109
67
  return false;
110
68
  }
111
-
112
- // Check userCancelled flag
113
69
  if (error.userCancelled === true) {
114
70
  return true;
115
71
  }
116
-
117
- // Check error code
118
72
  const code = getErrorCode(error);
119
73
  return code === "PURCHASE_CANCELLED_ERROR" || code === "1";
120
74
  }
121
75
 
122
- /**
123
- * Check if error is a network error
124
- */
125
76
  export function isNetworkError(error: unknown): boolean {
126
77
  const code = getErrorCode(error);
127
78
  return code === "NETWORK_ERROR" || code === "7";
128
79
  }
129
80
 
130
- /**
131
- * Check if error is already purchased
132
- */
133
81
  export function isAlreadyPurchasedError(error: unknown): boolean {
134
82
  const code = getErrorCode(error);
135
83
  return code === "PRODUCT_ALREADY_PURCHASED_ERROR" || code === "6";
136
84
  }
137
85
 
138
- /**
139
- * Check if error is invalid credentials
140
- */
141
86
  export function isInvalidCredentialsError(error: unknown): boolean {
142
87
  const code = getErrorCode(error);
143
88
  return code === "INVALID_CREDENTIALS_ERROR" || code === "9";
144
89
  }
145
90
 
146
- /**
147
- * Extract raw error message from error object
148
- * For user-friendly messages, use getErrorMessageForCode from errors module
149
- */
150
91
  export function getRawErrorMessage(error: unknown, fallback: string): string {
151
92
  if (error instanceof Error) {
152
93
  return error.message;
153
94
  }
154
95
  return fallback;
155
96
  }
156
-
@@ -1,7 +1,3 @@
1
- /**
2
- * RevenueCat Domain - Types
3
- */
4
-
5
1
  export * from "./RevenueCatTypes";
6
2
  export * from "./RevenueCatConfig";
7
3
  export * from "./RevenueCatData";
@@ -1,21 +1,10 @@
1
- /**
2
- * UserSwitchMutex
3
- * Prevents concurrent Purchases.logIn() calls that cause RevenueCat 429 errors
4
- */
5
-
6
1
  class UserSwitchMutexImpl {
7
2
  private activeSwitchPromise: Promise<any> | null = null;
8
3
  private activeUserId: string | null = null;
9
4
  private lastSwitchTime = 0;
10
- private readonly MIN_SWITCH_INTERVAL_MS = 1000; // Minimum 1 second between switches
5
+ private readonly MIN_SWITCH_INTERVAL_MS = 1000;
11
6
 
12
- /**
13
- * Acquires the lock for user switch operation
14
- * Returns existing promise if a switch is in progress for the same user
15
- * Waits if a switch is in progress for a different user
16
- */
17
7
  async acquire(userId: string): Promise<{ shouldProceed: boolean; existingPromise?: Promise<any> }> {
18
- // If a switch is in progress for the exact same user, return the existing promise
19
8
  if (this.activeSwitchPromise && this.activeUserId === userId) {
20
9
  if (typeof __DEV__ !== 'undefined' && __DEV__) {
21
10
  console.log('[UserSwitchMutex] Switch already in progress for this user, returning existing promise');
@@ -23,7 +12,6 @@ class UserSwitchMutexImpl {
23
12
  return { shouldProceed: false, existingPromise: this.activeSwitchPromise };
24
13
  }
25
14
 
26
- // If a switch is in progress for a different user, wait for it to complete
27
15
  if (this.activeSwitchPromise) {
28
16
  if (typeof __DEV__ !== 'undefined' && __DEV__) {
29
17
  console.log('[UserSwitchMutex] Waiting for active switch to complete...');
@@ -31,10 +19,8 @@ class UserSwitchMutexImpl {
31
19
  try {
32
20
  await this.activeSwitchPromise;
33
21
  } catch {
34
- // Ignore error, just wait for completion
35
22
  }
36
23
 
37
- // Add a small delay to avoid rapid-fire requests
38
24
  const timeSinceLastSwitch = Date.now() - this.lastSwitchTime;
39
25
  if (timeSinceLastSwitch < this.MIN_SWITCH_INTERVAL_MS) {
40
26
  const delayNeeded = this.MIN_SWITCH_INTERVAL_MS - timeSinceLastSwitch;
@@ -44,12 +30,10 @@ class UserSwitchMutexImpl {
44
30
  await new Promise<void>(resolve => setTimeout(() => resolve(), delayNeeded));
45
31
  }
46
32
 
47
- // Re-check after delay: another caller may have acquired the lock during our wait
48
33
  if (this.activeSwitchPromise) {
49
34
  if (this.activeUserId === userId) {
50
35
  return { shouldProceed: false, existingPromise: this.activeSwitchPromise };
51
36
  }
52
- // Another switch started for a different user — recurse to wait again
53
37
  return this.acquire(userId);
54
38
  }
55
39
  }
@@ -58,14 +42,10 @@ class UserSwitchMutexImpl {
58
42
  return { shouldProceed: true };
59
43
  }
60
44
 
61
- /**
62
- * Sets the active promise for the current switch operation
63
- */
64
45
  setPromise(promise: Promise<any>): void {
65
46
  this.activeSwitchPromise = promise;
66
47
  this.lastSwitchTime = Date.now();
67
48
 
68
- // Clear the lock when the promise completes (success or failure)
69
49
  promise
70
50
  .finally(() => {
71
51
  if (this.activeSwitchPromise === promise) {
@@ -75,9 +55,6 @@ class UserSwitchMutexImpl {
75
55
  });
76
56
  }
77
57
 
78
- /**
79
- * Resets the mutex state
80
- */
81
58
  reset(): void {
82
59
  this.activeSwitchPromise = null;
83
60
  this.activeUserId = null;
@@ -1,9 +1,5 @@
1
1
  import type { FirebaseAuthLike } from "./SubscriptionInitializerTypes";
2
2
 
3
- /**
4
- * Gets the current user ID from Firebase auth.
5
- * Returns undefined for anonymous users to let RevenueCat generate its own anonymous ID.
6
- */
7
3
  export const getCurrentUserId = (getAuth: () => FirebaseAuthLike | null): string | undefined => {
8
4
  const auth = getAuth();
9
5
  if (!auth) {
@@ -16,19 +12,12 @@ export const getCurrentUserId = (getAuth: () => FirebaseAuthLike | null): string
16
12
  }
17
13
 
18
14
  if (user.isAnonymous) {
19
- if (typeof __DEV__ !== 'undefined' && __DEV__) {
20
- console.log(`[SubscriptionAuthListener] Anonymous user - using Firebase anonymous UID: ${user.uid}`);
21
- }
15
+ return undefined;
22
16
  }
23
17
 
24
18
  return user.uid;
25
19
  };
26
20
 
27
- /**
28
- * Sets up auth state listener that will re-initialize subscription
29
- * when user auth state changes (login/logout).
30
- * Returns undefined for anonymous users to let RevenueCat generate its own anonymous ID.
31
- */
32
21
  export const setupAuthStateListener = (
33
22
  getAuth: () => FirebaseAuthLike | null,
34
23
  onUserChange: (userId: string | undefined) => void
@@ -39,16 +28,11 @@ export const setupAuthStateListener = (
39
28
  }
40
29
 
41
30
  return auth.onAuthStateChanged((user) => {
42
- const userId = user ? user.uid : undefined;
43
-
44
- if (typeof __DEV__ !== 'undefined' && __DEV__) {
45
- console.log('[SubscriptionAuthListener] 🔔 Auth state changed:', {
46
- hasUser: !!user,
47
- isAnonymous: user?.isAnonymous,
48
- userId: userId || '(undefined - no user)',
49
- });
31
+ if (!user || user.isAnonymous) {
32
+ onUserChange(undefined);
33
+ return;
50
34
  }
51
35
 
52
- onUserChange(userId);
36
+ onUserChange(user.uid);
53
37
  });
54
38
  };
@@ -1,7 +1,3 @@
1
- /**
2
- * Subscription Initializer Types
3
- */
4
-
5
1
  import type { CreditsConfig } from "../../credits/core/Credits";
6
2
  import type { UserCreditsDocumentRead } from "../../credits/core/UserCreditsDocument";
7
3
  import type { PurchaseSource, PurchaseType } from "../core/SubscriptionConstants";
@@ -40,7 +36,7 @@ export interface InitializeCreditsMetadata {
40
36
  willRenew: boolean | null;
41
37
  originalTransactionId: string | null;
42
38
  isPremium: boolean;
43
- periodType: string | null; // Raw value from RevenueCat SDK
39
+ periodType: string | null;
44
40
  unsubscribeDetectedAt: string | null;
45
41
  billingIssueDetectedAt: string | null;
46
42
  store: Store | null;
@@ -69,19 +69,15 @@ export class SubscriptionSyncProcessor {
69
69
  ) {
70
70
  const creditsUserId = await this.getCreditsUserId(userId);
71
71
 
72
- // Expired subscription case
73
72
  if (!isPremium && productId) {
74
73
  await handleExpiredSubscription(creditsUserId);
75
74
  return;
76
75
  }
77
76
 
78
- // Free user case - no Firestore document needed
79
- // Credits absence means no subscription (app handles null gracefully)
80
77
  if (!isPremium && !productId) {
81
78
  return;
82
79
  }
83
80
 
84
- // Premium user case - productId is required
85
81
  if (!productId) {
86
82
  return;
87
83
  }
@@ -22,9 +22,9 @@ export class SubscriptionSyncService {
22
22
  console.error('[SubscriptionSyncService] Purchase processing failed', {
23
23
  userId,
24
24
  productId,
25
- source,
26
- error
25
+ error: error instanceof Error ? error.message : String(error)
27
26
  });
27
+ throw error;
28
28
  }
29
29
  }
30
30
 
@@ -37,7 +37,7 @@ export class SubscriptionSyncService {
37
37
  userId,
38
38
  productId,
39
39
  newExpirationDate,
40
- error
40
+ error: error instanceof Error ? error.message : String(error)
41
41
  });
42
42
  }
43
43
  }
@@ -58,12 +58,8 @@ export class SubscriptionSyncService {
58
58
  userId,
59
59
  isPremium,
60
60
  productId,
61
- expiresAt,
62
- willRenew,
63
- periodType,
64
- error
61
+ error: error instanceof Error ? error.message : String(error)
65
62
  });
66
63
  }
67
64
  }
68
65
  }
69
-
@@ -1,6 +1,6 @@
1
1
  import type { CustomerInfo } from "react-native-purchases";
2
2
  import type { RevenueCatData } from "../../revenuecat/core/types";
3
- import { PERIOD_TYPE, type PeriodType } from "../core/SubscriptionStatus";
3
+ import { PERIOD_TYPE, type PeriodType } from "../core/SubscriptionConstants";
4
4
 
5
5
  function validatePeriodType(periodType: string | undefined): PeriodType | null {
6
6
  if (!periodType) return null;