@umituz/react-native-subscription 3.1.33 → 3.1.35

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 (40) hide show
  1. package/package.json +1 -1
  2. package/src/domains/credits/application/CreditsInitializer.ts +34 -39
  3. package/src/domains/credits/application/DeductCreditsCommand.ts +13 -12
  4. package/src/domains/credits/presentation/deduct-credit/useDeductCredit.ts +9 -16
  5. package/src/domains/credits/presentation/useCredits.ts +2 -2
  6. package/src/domains/credits/presentation/useCredits.types.ts +1 -1
  7. package/src/domains/paywall/components/PaywallScreen.tsx +12 -11
  8. package/src/domains/paywall/hooks/usePaywallActions.ts +4 -3
  9. package/src/domains/paywall/hooks/usePaywallActions.utils.ts +14 -19
  10. package/src/domains/paywall/hooks/usePaywallPurchase.ts +10 -17
  11. package/src/domains/paywall/hooks/usePaywallRestore.ts +8 -15
  12. package/src/domains/revenuecat/infrastructure/services/RevenueCatInitializer.ts +6 -5
  13. package/src/domains/revenuecat/infrastructure/services/UserSwitchMutex.ts +8 -10
  14. package/src/domains/revenuecat/infrastructure/services/userSwitchCore.ts +16 -33
  15. package/src/domains/revenuecat/infrastructure/services/userSwitchHelpers.ts +3 -4
  16. package/src/domains/revenuecat/infrastructure/services/userSwitchInitializer.ts +18 -28
  17. package/src/domains/subscription/application/initializer/BackgroundInitializer.ts +17 -29
  18. package/src/domains/subscription/application/sync/CreditDocumentOperations.ts +16 -17
  19. package/src/domains/subscription/application/sync/PurchaseSyncHandler.ts +20 -23
  20. package/src/domains/subscription/application/sync/RenewalSyncHandler.ts +8 -7
  21. package/src/domains/subscription/application/sync/StatusChangeSyncHandler.ts +4 -3
  22. package/src/domains/subscription/application/sync/SyncProcessorLogger.ts +39 -64
  23. package/src/domains/subscription/application/sync/UserIdResolver.ts +5 -1
  24. package/src/domains/subscription/infrastructure/handlers/package-operations/PackageFetcher.ts +7 -6
  25. package/src/domains/subscription/infrastructure/handlers/package-operations/PackagePurchaser.ts +8 -7
  26. package/src/domains/subscription/infrastructure/hooks/usePurchasePackage.ts +4 -3
  27. package/src/domains/subscription/infrastructure/managers/SubscriptionManager.ts +20 -27
  28. package/src/domains/subscription/infrastructure/services/CustomerInfoListenerManager.ts +10 -9
  29. package/src/domains/subscription/infrastructure/services/OfferingsFetcher.ts +14 -21
  30. package/src/domains/subscription/infrastructure/services/PurchaseHandler.ts +8 -7
  31. package/src/domains/subscription/infrastructure/services/RevenueCatService.types.ts +4 -3
  32. package/src/domains/subscription/infrastructure/services/listeners/CustomerInfoHandler.ts +15 -29
  33. package/src/domains/subscription/infrastructure/services/purchase/PurchaseErrorHandler.ts +4 -2
  34. package/src/domains/subscription/infrastructure/services/purchase/PurchaseExecutor.ts +27 -33
  35. package/src/domains/subscription/infrastructure/utils/InitializationCache.ts +5 -1
  36. package/src/domains/subscription/infrastructure/utils/PremiumStatusSyncer.ts +11 -17
  37. package/src/domains/subscription/presentation/providers/SubscriptionFlowProvider.tsx +11 -12
  38. package/src/domains/subscription/presentation/useSyncStatusListener.ts +10 -9
  39. package/src/init/createSubscriptionInitModule.ts +4 -1
  40. package/src/shared/infrastructure/SubscriptionEventBus.ts +4 -1
@@ -3,6 +3,10 @@
3
3
  * Handles resolution of RevenueCat user ID to credits user ID
4
4
  */
5
5
 
6
+ import { createLogger } from "../../../../shared/utils/logger";
7
+
8
+ const logger = createLogger("UserIdResolver");
9
+
6
10
  export class UserIdResolver {
7
11
  constructor(private getAnonymousUserId: () => Promise<string>) {}
8
12
 
@@ -14,7 +18,7 @@ export class UserIdResolver {
14
18
  }
15
19
 
16
20
  // Fallback to anonymous user ID
17
- console.warn("[UserIdResolver] revenueCatUserId is empty/null, falling back to anonymousUserId");
21
+ logger.warn("revenueCatUserId is empty/null, falling back to anonymousUserId");
18
22
  const anonymousId = await this.getAnonymousUserId();
19
23
  const trimmedAnonymous = anonymousId?.trim();
20
24
 
@@ -1,5 +1,8 @@
1
1
  import type { PurchasesPackage } from "react-native-purchases";
2
2
  import type { IRevenueCatService } from "../../../../../shared/application/ports/IRevenueCatService";
3
+ import { createLogger } from "../../../../../shared/utils/logger";
4
+
5
+ const logger = createLogger("PackageFetcher");
3
6
 
4
7
  export async function fetchPackages(
5
8
  service: IRevenueCatService
@@ -20,12 +23,10 @@ export async function fetchPackages(
20
23
  return [];
21
24
  }
22
25
 
23
- if (__DEV__) {
24
- console.log('[PackageHandler] Returning packages:', {
25
- count: packages.length,
26
- packageIds: packages.map(p => p.product.identifier),
27
- });
28
- }
26
+ logger.debug("Returning packages", {
27
+ count: packages.length,
28
+ packageIds: packages.map(p => p.product.identifier),
29
+ });
29
30
 
30
31
  return packages;
31
32
  } catch (error) {
@@ -1,18 +1,19 @@
1
1
  import type { PurchasesPackage } from "react-native-purchases";
2
2
  import type { IRevenueCatService } from "../../../../../shared/application/ports/IRevenueCatService";
3
+ import { createLogger } from "../../../../../shared/utils/logger";
4
+
5
+ const logger = createLogger("PackagePurchaser");
3
6
 
4
7
  export async function executePurchase(
5
8
  service: IRevenueCatService,
6
9
  pkg: PurchasesPackage,
7
10
  userId: string
8
11
  ): Promise<boolean> {
9
- if (typeof __DEV__ !== "undefined" && __DEV__) {
10
- console.log("[PackagePurchaser] executePurchase called", {
11
- productId: pkg.product.identifier,
12
- userId,
13
- serviceInitialized: service.isInitialized(),
14
- });
15
- }
12
+ logger.debug("executePurchase called", {
13
+ productId: pkg.product.identifier,
14
+ userId,
15
+ serviceInitialized: service.isInitialized(),
16
+ });
16
17
 
17
18
  if (!service.isInitialized()) {
18
19
  throw new Error("Service not initialized");
@@ -7,6 +7,9 @@ import {
7
7
  } from "@umituz/react-native-auth";
8
8
  import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionManager";
9
9
  import { getErrorMessage } from "../../../revenuecat/core/errors/RevenueCatErrorHandler";
10
+ import { createLogger } from "../../../../shared/utils/logger";
11
+
12
+ const logger = createLogger("usePurchasePackage");
10
13
 
11
14
  interface PurchaseMutationResult {
12
15
  success: boolean;
@@ -24,9 +27,7 @@ export const usePurchasePackage = () => {
24
27
  }
25
28
 
26
29
  const productId = pkg.product.identifier;
27
- if (typeof __DEV__ !== "undefined" && __DEV__) {
28
- console.log(`[Purchase] Initializing and purchasing. User: ${userId}`);
29
- }
30
+ logger.debug("Initializing and purchasing", { userId, productId });
30
31
 
31
32
  const success = await SubscriptionManager.purchasePackage(pkg, userId);
32
33
 
@@ -10,6 +10,9 @@ import { getPackagesOperation, purchasePackageOperation, restoreOperation } from
10
10
  import { performServiceInitialization } from "./initializationHandler";
11
11
  import { initializationState } from "../state/initializationState";
12
12
  import { ANONYMOUS_CACHE_KEY } from "../../core/SubscriptionConstants";
13
+ import { createLogger } from "../../../../shared/utils/logger";
14
+
15
+ const logger = createLogger("SubscriptionManager");
13
16
 
14
17
  class SubscriptionManagerImpl {
15
18
  private managerConfig: SubscriptionManagerConfig | null = null;
@@ -23,14 +26,14 @@ class SubscriptionManagerImpl {
23
26
 
24
27
  private ensureConfigured(): void {
25
28
  if (!this.managerConfig) {
26
- throw new Error('[SubscriptionManager] Not configured. Call configure() first.');
29
+ throw new Error('SubscriptionManager: Not configured. Call configure() first.');
27
30
  }
28
31
  }
29
32
 
30
33
  private ensurePackageHandlerInitialized(): void {
31
34
  if (this.packageHandler) return;
32
35
  if (!this.serviceInstance || !this.managerConfig) {
33
- throw new Error('[SubscriptionManager] Cannot create package handler without service and config');
36
+ throw new Error('SubscriptionManager: Cannot create package handler without service and config');
34
37
  }
35
38
  this.packageHandler = createPackageHandler(this.serviceInstance, this.managerConfig);
36
39
  }
@@ -40,20 +43,16 @@ class SubscriptionManagerImpl {
40
43
 
41
44
  const actualUserId: string = (userId && userId.length > 0) ? userId : '';
42
45
 
43
- if (typeof __DEV__ !== 'undefined' && __DEV__) {
44
- console.log('[SubscriptionManager] initialize called:', {
45
- providedUserId: userId,
46
- actualUserId: actualUserId || '(empty - RevenueCat will generate anonymous ID)',
47
- });
48
- }
46
+ logger.debug("initialize called", {
47
+ providedUserId: userId,
48
+ actualUserId: actualUserId || '(empty - RevenueCat will generate anonymous ID)',
49
+ });
49
50
 
50
51
  const cacheKey = actualUserId || ANONYMOUS_CACHE_KEY;
51
52
  const { shouldInit, existingPromise } = this.initCache.tryAcquireInitialization(cacheKey);
52
53
 
53
54
  if (!shouldInit && existingPromise) {
54
- if (typeof __DEV__ !== 'undefined' && __DEV__) {
55
- console.log('[SubscriptionManager] Using cached initialization for:', cacheKey);
56
- }
55
+ logger.debug("Using cached initialization for", cacheKey);
57
56
  return existingPromise;
58
57
  }
59
58
 
@@ -67,11 +66,9 @@ class SubscriptionManagerImpl {
67
66
  }
68
67
 
69
68
  private async performInitialization(userId: string): Promise<boolean> {
70
- if (typeof __DEV__ !== 'undefined' && __DEV__) {
71
- console.log('[SubscriptionManager] performInitialization:', {
72
- userId: userId || '(empty - anonymous)',
73
- });
74
- }
69
+ logger.debug("performInitialization", {
70
+ userId: userId || '(empty - anonymous)',
71
+ });
75
72
 
76
73
  const config = this.managerConfig!;
77
74
  const { service, success } = await performServiceInitialization(config.config, userId);
@@ -83,9 +80,7 @@ class SubscriptionManagerImpl {
83
80
  initializationState.markInitialized(notifyUserId);
84
81
  }
85
82
 
86
- if (typeof __DEV__ !== 'undefined' && __DEV__) {
87
- console.log('[SubscriptionManager] Initialization completed:', { success });
88
- }
83
+ logger.debug("Initialization completed", { success });
89
84
 
90
85
  return success;
91
86
  }
@@ -107,14 +102,12 @@ class SubscriptionManagerImpl {
107
102
  if (explicitUserId) {
108
103
  await this.initialize(explicitUserId);
109
104
  }
110
- if (typeof __DEV__ !== 'undefined' && __DEV__) {
111
- console.log('[SubscriptionManager] purchasePackage: init complete, starting purchase', {
112
- productId: pkg.product.identifier,
113
- hasPackageHandler: !!this.packageHandler,
114
- hasService: !!this.serviceInstance,
115
- serviceInitialized: this.serviceInstance?.isInitialized() ?? false,
116
- });
117
- }
105
+ logger.debug("purchasePackage: init complete, starting purchase", {
106
+ productId: pkg.product.identifier,
107
+ hasPackageHandler: !!this.packageHandler,
108
+ hasService: !!this.serviceInstance,
109
+ serviceInitialized: this.serviceInstance?.isInitialized() ?? false,
110
+ });
118
111
  this.ensurePackageHandlerInitialized();
119
112
  const resolvedUserId = explicitUserId || getCurrentUserIdOrThrow(this.initCache);
120
113
  const handler = this.packageHandler!;
@@ -2,6 +2,9 @@ import Purchases, { type CustomerInfo } from "react-native-purchases";
2
2
  import type { RevenueCatConfig } from "../../../revenuecat/core/types/RevenueCatConfig";
3
3
  import { ListenerState } from "./listeners/ListenerState";
4
4
  import { processCustomerInfo } from "./listeners/CustomerInfoHandler";
5
+ import { createLogger } from "../../../../shared/utils/logger";
6
+
7
+ const logger = createLogger("CustomerInfoListenerManager");
5
8
 
6
9
  export class CustomerInfoListenerManager {
7
10
  private state = new ListenerState();
@@ -33,7 +36,7 @@ export class CustomerInfoListenerManager {
33
36
  this._createAndAttachListener(config);
34
37
  return true;
35
38
  } catch (error) {
36
- console.error("[CustomerInfoListenerManager] Failed to setup listener:", error);
39
+ logger.error("Failed to setup listener", error);
37
40
  this.state.currentUserId = null;
38
41
  return false;
39
42
  }
@@ -41,13 +44,11 @@ export class CustomerInfoListenerManager {
41
44
 
42
45
  private _createAndAttachListener(config: RevenueCatConfig): void {
43
46
  this.state.listener = async (customerInfo: CustomerInfo) => {
44
- if (typeof __DEV__ !== "undefined" && __DEV__) {
45
- console.log("[CustomerInfoListener] 🔔 LISTENER TRIGGERED!", {
46
- userId: this.state.currentUserId,
47
- activeEntitlements: Object.keys(customerInfo.entitlements.active),
48
- entitlementsCount: Object.keys(customerInfo.entitlements.all).length,
49
- });
50
- }
47
+ logger.debug("LISTENER TRIGGERED", {
48
+ userId: this.state.currentUserId,
49
+ activeEntitlements: Object.keys(customerInfo.entitlements.active),
50
+ entitlementsCount: Object.keys(customerInfo.entitlements.all).length,
51
+ });
51
52
 
52
53
  const capturedUserId = this.state.currentUserId;
53
54
  if (!capturedUserId) {
@@ -67,7 +68,7 @@ export class CustomerInfoListenerManager {
67
68
  }
68
69
  // else: User switched during async operation, discard stale renewal state
69
70
  } catch (error) {
70
- console.error("[CustomerInfoListener] processCustomerInfo failed:", error);
71
+ logger.error("processCustomerInfo failed", error);
71
72
  }
72
73
  };
73
74
 
@@ -1,4 +1,7 @@
1
1
  import Purchases, { type PurchasesOffering } from "react-native-purchases";
2
+ import { createLogger } from "../../../../shared/utils/logger";
3
+
4
+ const logger = createLogger("OfferingsFetcher");
2
5
 
3
6
  interface OfferingsFetcherDeps {
4
7
  isInitialized: () => boolean;
@@ -14,15 +17,13 @@ export async function fetchOfferings(deps: OfferingsFetcherDeps): Promise<Purcha
14
17
  try {
15
18
  const offerings = await Purchases.getOfferings();
16
19
 
17
- if (typeof __DEV__ !== "undefined" && __DEV__) {
18
- console.log('[OfferingsFetcher] Offerings received:', {
19
- attempt,
20
- hasCurrent: !!offerings.current,
21
- currentId: offerings.current?.identifier,
22
- allOfferingsCount: Object.keys(offerings.all).length,
23
- allOfferingIds: Object.keys(offerings.all),
24
- });
25
- }
20
+ logger.debug("Offerings received", {
21
+ attempt,
22
+ hasCurrent: !!offerings.current,
23
+ currentId: offerings.current?.identifier,
24
+ allOfferingsCount: Object.keys(offerings.all).length,
25
+ allOfferingIds: Object.keys(offerings.all),
26
+ });
26
27
 
27
28
  if (offerings.current) {
28
29
  return offerings.current;
@@ -35,28 +36,20 @@ export async function fetchOfferings(deps: OfferingsFetcherDeps): Promise<Purcha
35
36
 
36
37
  // No offerings found - retry after delay (RevenueCat may still be syncing)
37
38
  if (attempt < MAX_FETCH_RETRIES) {
38
- if (typeof __DEV__ !== "undefined" && __DEV__) {
39
- console.log('[OfferingsFetcher] No offerings found, retrying...', { attempt: attempt + 1 });
40
- }
39
+ logger.debug("No offerings found, retrying...", { attempt: attempt + 1 });
41
40
  await new Promise<void>(resolve => setTimeout(resolve, FETCH_RETRY_DELAY_MS));
42
41
  continue;
43
42
  }
44
43
 
45
- if (typeof __DEV__ !== "undefined" && __DEV__) {
46
- console.warn('[OfferingsFetcher] No offerings found after all retries');
47
- }
44
+ logger.warn("No offerings found after all retries");
48
45
  return null;
49
46
  } catch (error) {
50
47
  if (attempt < MAX_FETCH_RETRIES) {
51
- if (typeof __DEV__ !== "undefined" && __DEV__) {
52
- console.warn('[OfferingsFetcher] Fetch failed, retrying...', { attempt: attempt + 1, error });
53
- }
48
+ logger.warn("Fetch failed, retrying...", error, { attempt: attempt + 1 });
54
49
  await new Promise<void>(resolve => setTimeout(resolve, FETCH_RETRY_DELAY_MS));
55
50
  continue;
56
51
  }
57
- if (typeof __DEV__ !== "undefined" && __DEV__) {
58
- console.warn('[OfferingsFetcher] Failed to fetch offerings after all retries:', error);
59
- }
52
+ logger.warn("Failed to fetch offerings after all retries", error);
60
53
  return null;
61
54
  }
62
55
  }
@@ -5,6 +5,9 @@ import { isUserCancelledError, isAlreadyPurchasedError } from "../../../revenuec
5
5
  import { validatePurchaseReady, isConsumableProduct } from "./purchase/PurchaseValidator";
6
6
  import { executePurchase } from "./purchase/PurchaseExecutor";
7
7
  import { handleAlreadyPurchasedError, handlePurchaseError } from "./purchase/PurchaseErrorHandler";
8
+ import { createLogger } from "../../../../shared/utils/logger";
9
+
10
+ const logger = createLogger("PurchaseHandler");
8
11
 
9
12
  export interface PurchaseHandlerDeps {
10
13
  config: RevenueCatConfig;
@@ -21,13 +24,11 @@ export async function handlePurchase(
21
24
  const consumableIds = deps.config.consumableProductIdentifiers || [];
22
25
  const isConsumable = isConsumableProduct(pkg, consumableIds);
23
26
 
24
- if (typeof __DEV__ !== "undefined" && __DEV__) {
25
- console.log("[PurchaseHandler] handlePurchase:", {
26
- productId: pkg.product.identifier,
27
- userId,
28
- isConsumable,
29
- });
30
- }
27
+ logger.debug("handlePurchase", {
28
+ productId: pkg.product.identifier,
29
+ userId,
30
+ isConsumable,
31
+ });
31
32
 
32
33
  try {
33
34
  const result = await executePurchase(deps.config, userId, pkg, isConsumable);
@@ -8,6 +8,9 @@ import { handlePurchase } from "./PurchaseHandler";
8
8
  import { handleRestore } from "./RestoreHandler";
9
9
  import { CustomerInfoListenerManager } from "./CustomerInfoListenerManager";
10
10
  import { ServiceStateManager } from "./ServiceStateManager";
11
+ import { createLogger } from "../../../../shared/utils/logger";
12
+
13
+ const logger = createLogger("RevenueCatService");
11
14
 
12
15
  export class RevenueCatService implements IRevenueCatService {
13
16
  private stateManager: ServiceStateManager;
@@ -83,9 +86,7 @@ export class RevenueCatService implements IRevenueCatService {
83
86
  try {
84
87
  await Purchases.logOut();
85
88
  } catch (error) {
86
- if (__DEV__) {
87
- console.warn('[RevenueCatService] logOut failed during reset', { error });
88
- }
89
+ logger.warn("logOut failed during reset", error);
89
90
  }
90
91
  }
91
92
 
@@ -4,6 +4,9 @@ import { syncPremiumStatus } from "../../utils/PremiumStatusSyncer";
4
4
  import { detectRenewal } from "../../utils/renewal/RenewalDetector";
5
5
  import { updateRenewalState } from "../../utils/renewal/RenewalStateUpdater";
6
6
  import type { RenewalState } from "../../utils/renewal/types";
7
+ import { createLogger } from "../../../../../shared/utils/logger";
8
+
9
+ const logger = createLogger("CustomerInfoHandler");
7
10
 
8
11
  async function handleRenewal(
9
12
  userId: string,
@@ -17,11 +20,7 @@ async function handleRenewal(
17
20
  try {
18
21
  await onRenewalDetected({ userId, productId, newExpirationDate: expirationDate, customerInfo });
19
22
  } catch (error) {
20
- console.error('[CustomerInfoHandler] Renewal callback failed:', {
21
- userId,
22
- productId,
23
- error: error instanceof Error ? error.message : String(error)
24
- });
23
+ logger.error("Renewal callback failed", error, { userId, productId });
25
24
  }
26
25
  }
27
26
 
@@ -38,13 +37,7 @@ async function handlePlanChange(
38
37
  try {
39
38
  await onPlanChanged({ userId, newProductId, previousProductId, isUpgrade, customerInfo });
40
39
  } catch (error) {
41
- console.error('[CustomerInfoHandler] Plan change callback failed:', {
42
- userId,
43
- newProductId,
44
- previousProductId,
45
- isUpgrade,
46
- error: error instanceof Error ? error.message : String(error)
47
- });
40
+ logger.error("Plan change callback failed", error, { userId, newProductId, previousProductId, isUpgrade });
48
41
  }
49
42
  }
50
43
 
@@ -56,10 +49,7 @@ async function handlePremiumStatusSync(
56
49
  try {
57
50
  await syncPremiumStatus(config, userId, customerInfo);
58
51
  } catch (error) {
59
- console.error('[CustomerInfoHandler] Premium status sync failed:', {
60
- userId,
61
- error: error instanceof Error ? error.message : String(error)
62
- });
52
+ logger.error("Premium status sync failed", error, { userId });
63
53
  }
64
54
  }
65
55
 
@@ -69,14 +59,12 @@ export async function processCustomerInfo(
69
59
  renewalState: RenewalState,
70
60
  config: RevenueCatConfig
71
61
  ): Promise<RenewalState> {
72
- if (typeof __DEV__ !== "undefined" && __DEV__) {
73
- console.log("[CustomerInfoHandler] processCustomerInfo called:", {
74
- userId,
75
- renewalState,
76
- entitlementId: config.entitlementIdentifier,
77
- activeEntitlements: Object.keys(customerInfo.entitlements.active),
78
- });
79
- }
62
+ logger.debug("processCustomerInfo called", {
63
+ userId,
64
+ renewalState,
65
+ entitlementId: config.entitlementIdentifier,
66
+ activeEntitlements: Object.keys(customerInfo.entitlements.active),
67
+ });
80
68
 
81
69
  const renewalResult = detectRenewal(
82
70
  renewalState,
@@ -86,7 +74,7 @@ export async function processCustomerInfo(
86
74
 
87
75
  if (renewalResult.isRenewal) {
88
76
  if (!renewalResult.productId || !renewalResult.newExpirationDate) {
89
- console.error('[CustomerInfoHandler] Invalid renewal state: missing productId or expirationDate');
77
+ logger.error("Invalid renewal state: missing productId or expirationDate");
90
78
  return renewalState;
91
79
  }
92
80
  await handleRenewal(
@@ -100,7 +88,7 @@ export async function processCustomerInfo(
100
88
 
101
89
  if (renewalResult.isPlanChange) {
102
90
  if (!renewalResult.productId || !renewalResult.previousProductId) {
103
- console.error('[CustomerInfoHandler] Invalid plan change state: missing productId(s)');
91
+ logger.error("Invalid plan change state: missing productId(s)");
104
92
  return renewalState;
105
93
  }
106
94
  await handlePlanChange(
@@ -114,9 +102,7 @@ export async function processCustomerInfo(
114
102
  }
115
103
 
116
104
  if (!renewalResult.isRenewal && !renewalResult.isPlanChange) {
117
- if (typeof __DEV__ !== "undefined" && __DEV__) {
118
- console.log("[CustomerInfoHandler] Handling premium status sync (new purchase or status update)");
119
- }
105
+ logger.debug("Handling premium status sync (new purchase or status update)");
120
106
  await handlePremiumStatusSync(config, userId, customerInfo);
121
107
  }
122
108
 
@@ -15,6 +15,9 @@ import { getSavedPurchase, clearSavedPurchase } from "../../../presentation/useA
15
15
  import { notifyPurchaseCompleted } from "../../utils/PremiumStatusSyncer";
16
16
  import { handleRestore } from "../RestoreHandler";
17
17
  import type { PurchaseHandlerDeps } from "../PurchaseHandler";
18
+ import { createLogger } from "../../../../../shared/utils/logger";
19
+
20
+ const logger = createLogger("PurchaseErrorHandler");
18
21
 
19
22
  export async function handleAlreadyPurchasedError(
20
23
  deps: PurchaseHandlerDeps,
@@ -85,11 +88,10 @@ export function handlePurchaseError(
85
88
  ? `${errorMessage} (Code: ${errorCode})`
86
89
  : errorMessage;
87
90
 
88
- console.error('[PurchaseHandler] Purchase failed', {
91
+ logger.error("Purchase failed", error, {
89
92
  productId: pkg.product.identifier,
90
93
  userId,
91
94
  errorCode,
92
- error,
93
95
  });
94
96
 
95
97
  throw new RevenueCatPurchaseError(
@@ -4,13 +4,16 @@ import type { RevenueCatConfig } from "../../../../revenuecat/core/types/Revenue
4
4
  import type { PackageType } from "../../../../revenuecat/core/types/RevenueCatTypes";
5
5
  import { notifyPurchaseCompleted, syncPremiumStatus } from "../../utils/PremiumStatusSyncer";
6
6
  import { getSavedPurchase, clearSavedPurchase } from "../../../presentation/useAuthAwarePurchase";
7
+ import { createLogger } from "../../../../../shared/utils/logger";
8
+
9
+ const logger = createLogger("PurchaseExecutor");
7
10
 
8
11
  async function attemptRecovery(config: RevenueCatConfig, userId: string, customerInfo: CustomerInfo): Promise<void> {
9
12
  try {
10
- console.warn('[PurchaseExecutor] Attempting recovery via syncPremiumStatus...');
13
+ logger.warn("Attempting recovery via syncPremiumStatus...");
11
14
  await syncPremiumStatus(config, userId, customerInfo);
12
15
  } catch (recoveryError) {
13
- console.error('[PurchaseExecutor] Recovery also failed:', recoveryError);
16
+ logger.error("Recovery also failed", recoveryError);
14
17
  }
15
18
  }
16
19
 
@@ -27,7 +30,7 @@ async function executeConsumablePurchase(
27
30
  try {
28
31
  await notifyPurchaseCompleted(config, userId, productId, customerInfo, source, packageType);
29
32
  } catch (syncError) {
30
- console.error('[PurchaseExecutor] Post-purchase sync failed, attempting recovery:', syncError);
33
+ logger.error("Post-purchase sync failed, attempting recovery", syncError);
31
34
  await attemptRecovery(config, userId, customerInfo);
32
35
  } finally {
33
36
  if (savedPurchase) {
@@ -56,34 +59,29 @@ async function executeSubscriptionPurchase(
56
59
  const savedPurchase = getSavedPurchase();
57
60
  const source = savedPurchase?.source;
58
61
 
59
- if (typeof __DEV__ !== "undefined" && __DEV__) {
60
- console.log("[PurchaseExecutor] 🔵 executeSubscriptionPurchase: START", {
62
+ logger.debug("executeSubscriptionPurchase: START", {
63
+ userId,
64
+ productId,
65
+ isPremium,
66
+ entitlementIdentifier,
67
+ activeEntitlements: Object.keys(customerInfo.entitlements.active),
68
+ source,
69
+ packageType,
70
+ timestamp: new Date().toISOString(),
71
+ });
72
+
73
+ try {
74
+ await notifyPurchaseCompleted(config, userId, productId, customerInfo, source, packageType);
75
+ logger.debug("executeSubscriptionPurchase: SUCCESS", {
61
76
  userId,
62
77
  productId,
63
78
  isPremium,
64
- entitlementIdentifier,
65
- activeEntitlements: Object.keys(customerInfo.entitlements.active),
66
- source,
67
- packageType,
68
79
  timestamp: new Date().toISOString(),
69
80
  });
70
- }
71
-
72
- try {
73
- await notifyPurchaseCompleted(config, userId, productId, customerInfo, source, packageType);
74
- if (typeof __DEV__ !== "undefined" && __DEV__) {
75
- console.log("[PurchaseExecutor] 🟢 executeSubscriptionPurchase: SUCCESS", {
76
- userId,
77
- productId,
78
- isPremium,
79
- timestamp: new Date().toISOString(),
80
- });
81
- }
82
81
  } catch (syncError) {
83
- console.error('[PurchaseExecutor] 🔴 Post-purchase sync failed, attempting recovery:', {
82
+ logger.error("Post-purchase sync failed, attempting recovery", syncError, {
84
83
  userId,
85
84
  productId,
86
- error: syncError instanceof Error ? syncError.message : String(syncError),
87
85
  timestamp: new Date().toISOString(),
88
86
  });
89
87
  await attemptRecovery(config, userId, customerInfo);
@@ -122,13 +120,11 @@ export async function executePurchase(
122
120
  pkg: PurchasesPackage,
123
121
  isConsumable: boolean
124
122
  ): Promise<PurchaseResult> {
125
- if (typeof __DEV__ !== "undefined" && __DEV__) {
126
- console.log("[PurchaseExecutor] Starting Purchases.purchasePackage:", {
127
- productId: pkg.product.identifier,
128
- userId,
129
- isConsumable,
130
- });
131
- }
123
+ logger.debug("Starting Purchases.purchasePackage", {
124
+ productId: pkg.product.identifier,
125
+ userId,
126
+ isConsumable,
127
+ });
132
128
 
133
129
  const { customerInfo } = await withTimeout(
134
130
  Purchases.purchasePackage(pkg),
@@ -136,9 +132,7 @@ export async function executePurchase(
136
132
  `Purchases.purchasePackage(${pkg.product.identifier})`
137
133
  );
138
134
 
139
- if (typeof __DEV__ !== "undefined" && __DEV__) {
140
- console.log("[PurchaseExecutor] Purchases.purchasePackage completed successfully");
141
- }
135
+ logger.debug("Purchases.purchasePackage completed successfully");
142
136
 
143
137
  const productId = pkg.product.identifier;
144
138
  const packageType = pkg.packageType ?? null;
@@ -4,6 +4,10 @@ interface CacheEntry {
4
4
  completed: boolean;
5
5
  }
6
6
 
7
+ import { createLogger } from "../../../../shared/utils/logger";
8
+
9
+ const logger = createLogger("InitializationCache");
10
+
7
11
  export class InitializationCache {
8
12
  private entries: Map<string, CacheEntry> = new Map();
9
13
 
@@ -38,7 +42,7 @@ export class InitializationCache {
38
42
  if (this.entries.get(cacheKey) === entry) {
39
43
  this.entries.delete(cacheKey);
40
44
  }
41
- console.error('[InitializationCache] Initialization failed', { cacheKey, error });
45
+ logger.error("Initialization failed", error, { cacheKey });
42
46
  return false;
43
47
  });
44
48