@umituz/react-native-subscription 2.37.107 → 2.37.109
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/paywall/hooks/usePaywallActions.ts +1 -1
- package/src/domains/revenuecat/infrastructure/services/RevenueCatInitializer.ts +1 -2
- package/src/domains/subscription/infrastructure/managers/SubscriptionManager.ts +8 -8
- package/src/domains/subscription/infrastructure/managers/SubscriptionManager.types.ts +2 -6
- package/src/domains/subscription/infrastructure/managers/premiumStatusChecker.ts +1 -2
- package/src/domains/subscription/infrastructure/managers/subscriptionManagerUtils.ts +4 -5
- package/src/domains/subscription/infrastructure/services/RevenueCatService.types.ts +1 -2
- package/src/domains/subscription/presentation/components/overlay/PurchaseLoadingOverlay.tsx +1 -1
- package/src/domains/subscription/presentation/screens/SubscriptionDetailScreen.tsx +4 -4
- package/src/domains/subscription/presentation/screens/components/SubscriptionHeader.tsx +2 -1
- package/src/domains/subscription/utils/expirationHelpers.ts +1 -1
- package/src/domains/wallet/presentation/hooks/useTransactionHistory.ts +1 -1
- package/src/index.ts +6 -4
- package/src/domains/credits/presentation/deduct-credit/index.ts +0 -1
- package/src/domains/revenuecat/infrastructure/utils/ApiKeyResolver.ts +0 -5
- package/src/domains/subscription/constants/thresholds.ts +0 -1
- package/src/domains/subscription/infrastructure/managers/SubscriptionInternalState.ts +0 -9
- package/src/domains/subscription/infrastructure/managers/managerConstants.ts +0 -3
- package/src/domains/subscription/presentation/stores/index.ts +0 -4
- package/src/domains/wallet/index.ts +0 -8
- package/src/domains/wallet/infrastructure/repositories/transaction/index.ts +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.37.
|
|
3
|
+
"version": "2.37.109",
|
|
4
4
|
"description": "Complete subscription management with RevenueCat, paywall UI, and credits system for React Native apps",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState, useCallback, useRef } from "react";
|
|
2
2
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
3
|
-
import { usePurchaseLoadingStore } from "../../subscription/presentation/stores";
|
|
3
|
+
import { usePurchaseLoadingStore } from "../../subscription/presentation/stores/purchaseLoadingStore";
|
|
4
4
|
import type { PurchaseSource } from "../../subscription/core/SubscriptionConstants";
|
|
5
5
|
|
|
6
6
|
interface UsePaywallActionsParams {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { InitializeResult } from "../../../../shared/application/ports/IRevenueCatService";
|
|
2
|
-
import { resolveApiKey } from "../utils/ApiKeyResolver";
|
|
3
2
|
import type { InitializerDeps } from "./RevenueCatInitializer.types";
|
|
4
3
|
import { FAILED_INITIALIZATION_RESULT, CONFIGURATION_RETRY_DELAY_MS, MAX_INIT_RETRIES } from "./initializerConstants";
|
|
5
4
|
import { configState } from "./ConfigurationStateManager";
|
|
@@ -40,7 +39,7 @@ export async function initializeSDK(
|
|
|
40
39
|
return initializeSDK(deps, userId, apiKey, configStartRetryCount);
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
const key = apiKey ||
|
|
42
|
+
const key = apiKey || deps.config.apiKey || null;
|
|
44
43
|
if (!key) {
|
|
45
44
|
return FAILED_INITIALIZATION_RESULT;
|
|
46
45
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
2
2
|
import type { IRevenueCatService } from "../../../../shared/application/ports/IRevenueCatService";
|
|
3
3
|
import type { PackageHandler } from "../handlers/PackageHandler";
|
|
4
|
-
import {
|
|
4
|
+
import { InitializationCache } from "../utils/InitializationCache";
|
|
5
5
|
import { ensureServiceAvailable, getCurrentUserIdOrThrow } from "./subscriptionManagerUtils";
|
|
6
6
|
import type { SubscriptionManagerConfig, PremiumStatus, RestoreResultInfo } from "./SubscriptionManager.types";
|
|
7
7
|
import { createPackageHandler } from "./packageHandlerFactory";
|
|
@@ -14,7 +14,7 @@ import { ANONYMOUS_CACHE_KEY } from "../../core/SubscriptionConstants";
|
|
|
14
14
|
class SubscriptionManagerImpl {
|
|
15
15
|
private managerConfig: SubscriptionManagerConfig | null = null;
|
|
16
16
|
private serviceInstance: IRevenueCatService | null = null;
|
|
17
|
-
private
|
|
17
|
+
private initCache = new InitializationCache();
|
|
18
18
|
private packageHandler: PackageHandler | null = null;
|
|
19
19
|
|
|
20
20
|
configure(config: SubscriptionManagerConfig): void {
|
|
@@ -45,7 +45,7 @@ class SubscriptionManagerImpl {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const cacheKey = actualUserId || ANONYMOUS_CACHE_KEY;
|
|
48
|
-
const { shouldInit, existingPromise } = this.
|
|
48
|
+
const { shouldInit, existingPromise } = this.initCache.tryAcquireInitialization(cacheKey);
|
|
49
49
|
|
|
50
50
|
if (!shouldInit && existingPromise) {
|
|
51
51
|
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
@@ -59,7 +59,7 @@ class SubscriptionManagerImpl {
|
|
|
59
59
|
|
|
60
60
|
const realUserId = actualUserId || null;
|
|
61
61
|
const promise = this.performInitialization(actualUserId);
|
|
62
|
-
this.
|
|
62
|
+
this.initCache.setPromise(promise, cacheKey, realUserId);
|
|
63
63
|
return promise;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -87,7 +87,7 @@ class SubscriptionManagerImpl {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
isInitializedForUser = (userId: string): boolean =>
|
|
90
|
-
!!(this.serviceInstance?.isInitialized() && this.
|
|
90
|
+
!!(this.serviceInstance?.isInitialized() && this.initCache.getCurrentUserId() === userId);
|
|
91
91
|
|
|
92
92
|
async getPackages(): Promise<PurchasesPackage[]> {
|
|
93
93
|
this.ensureConfigured();
|
|
@@ -109,7 +109,7 @@ class SubscriptionManagerImpl {
|
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
111
|
this.ensurePackageHandlerInitialized();
|
|
112
|
-
const resolvedUserId = explicitUserId || getCurrentUserIdOrThrow(this.
|
|
112
|
+
const resolvedUserId = explicitUserId || getCurrentUserIdOrThrow(this.initCache);
|
|
113
113
|
const result = await purchasePackageOperation(pkg, this.managerConfig, resolvedUserId, this.packageHandler!);
|
|
114
114
|
return result;
|
|
115
115
|
}
|
|
@@ -120,7 +120,7 @@ class SubscriptionManagerImpl {
|
|
|
120
120
|
await this.initialize(explicitUserId);
|
|
121
121
|
}
|
|
122
122
|
this.ensurePackageHandlerInitialized();
|
|
123
|
-
const resolvedUserId = explicitUserId || getCurrentUserIdOrThrow(this.
|
|
123
|
+
const resolvedUserId = explicitUserId || getCurrentUserIdOrThrow(this.initCache);
|
|
124
124
|
return restoreOperation(this.managerConfig, resolvedUserId, this.packageHandler!);
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -133,7 +133,7 @@ class SubscriptionManagerImpl {
|
|
|
133
133
|
|
|
134
134
|
async reset(): Promise<void> {
|
|
135
135
|
await this.serviceInstance?.reset();
|
|
136
|
-
this.
|
|
136
|
+
this.initCache.reset();
|
|
137
137
|
this.serviceInstance = null;
|
|
138
138
|
this.packageHandler = null;
|
|
139
139
|
initializationState.reset();
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import type { RevenueCatConfig } from "../../../revenuecat/core/types";
|
|
2
2
|
import type { PremiumStatus } from "../handlers/PurchaseStatusResolver";
|
|
3
|
+
import type { RestoreResultInfo } from "../handlers/package-operations/types";
|
|
3
4
|
|
|
4
5
|
export interface SubscriptionManagerConfig {
|
|
5
6
|
config: RevenueCatConfig;
|
|
6
7
|
apiKey: string;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
export type { PremiumStatus };
|
|
10
|
-
|
|
11
|
-
export interface RestoreResultInfo {
|
|
12
|
-
success: boolean;
|
|
13
|
-
productId: string | null;
|
|
14
|
-
}
|
|
10
|
+
export type { PremiumStatus, RestoreResultInfo };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { IRevenueCatService } from "../../../../shared/application/ports/IRevenueCatService";
|
|
2
2
|
import type { PackageHandler } from "../handlers/PackageHandler";
|
|
3
3
|
import type { PremiumStatus } from "./SubscriptionManager.types";
|
|
4
|
-
import { ERROR_MESSAGES } from "./managerConstants";
|
|
5
4
|
|
|
6
5
|
export const checkPremiumStatusFromService = async (
|
|
7
6
|
service: IRevenueCatService,
|
|
@@ -10,7 +9,7 @@ export const checkPremiumStatusFromService = async (
|
|
|
10
9
|
const customerInfo = await service.getCustomerInfo();
|
|
11
10
|
|
|
12
11
|
if (!customerInfo) {
|
|
13
|
-
throw new Error(
|
|
12
|
+
throw new Error("Customer info not available");
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
return packageHandler.checkPremiumStatusFromInfo(customerInfo);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SubscriptionManagerConfig } from "./SubscriptionManager.types";
|
|
2
|
-
|
|
3
2
|
import type { IRevenueCatService } from "../../../../shared/application/ports/IRevenueCatService";
|
|
4
|
-
import {
|
|
3
|
+
import { getRevenueCatService } from "../services/revenueCatServiceInstance";
|
|
4
|
+
import type { InitializationCache } from "../utils/InitializationCache";
|
|
5
5
|
|
|
6
6
|
export function ensureConfigured(config: SubscriptionManagerConfig | null): void {
|
|
7
7
|
if (!config) {
|
|
@@ -9,8 +9,8 @@ export function ensureConfigured(config: SubscriptionManagerConfig | null): void
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export function getCurrentUserIdOrThrow(
|
|
13
|
-
const userId =
|
|
12
|
+
export function getCurrentUserIdOrThrow(initCache: InitializationCache): string {
|
|
13
|
+
const userId = initCache.getCurrentUserId();
|
|
14
14
|
if (userId == null) {
|
|
15
15
|
throw new Error("SubscriptionManager not initialized - no current user ID available");
|
|
16
16
|
}
|
|
@@ -24,7 +24,6 @@ export function getOrCreateService(
|
|
|
24
24
|
return currentInstance;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
const { getRevenueCatService } = require("../services/revenueCatServiceInstance");
|
|
28
27
|
const serviceInstance = getRevenueCatService();
|
|
29
28
|
|
|
30
29
|
if (!serviceInstance) {
|
|
@@ -2,7 +2,6 @@ import Purchases from "react-native-purchases";
|
|
|
2
2
|
import type { PurchasesOffering, PurchasesPackage, CustomerInfo } from "react-native-purchases";
|
|
3
3
|
import type { IRevenueCatService, InitializeResult, PurchaseResult, RestoreResult } from "../../../../shared/application/ports/IRevenueCatService";
|
|
4
4
|
import type { RevenueCatConfig } from "../../../revenuecat/core/types";
|
|
5
|
-
import { resolveApiKey } from "../../../revenuecat/infrastructure/utils/ApiKeyResolver";
|
|
6
5
|
import { initializeSDK } from "../../../revenuecat/infrastructure/services/RevenueCatInitializer";
|
|
7
6
|
import { fetchOfferings } from "./OfferingsFetcher";
|
|
8
7
|
import { handlePurchase } from "./PurchaseHandler";
|
|
@@ -19,7 +18,7 @@ export class RevenueCatService implements IRevenueCatService {
|
|
|
19
18
|
this.listenerManager = new CustomerInfoListenerManager();
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
getRevenueCatKey = (): string | null =>
|
|
21
|
+
getRevenueCatKey = (): string | null => this.stateManager.getConfig().apiKey || null;
|
|
23
22
|
|
|
24
23
|
isInitialized = (): boolean => this.stateManager.isInitialized();
|
|
25
24
|
|
|
@@ -8,7 +8,7 @@ import React from "react";
|
|
|
8
8
|
import { View, Modal, StyleSheet } from "react-native";
|
|
9
9
|
import { AtomicSpinner, AtomicText } from "@umituz/react-native-design-system/atoms";
|
|
10
10
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
11
|
-
import { usePurchaseLoadingStore, selectIsPurchasing } from "../../stores";
|
|
11
|
+
import { usePurchaseLoadingStore, selectIsPurchasing } from "../../stores/purchaseLoadingStore";
|
|
12
12
|
|
|
13
13
|
export interface PurchaseLoadingOverlayProps {
|
|
14
14
|
/** Loading message to display */
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import React, { useMemo, useState, useCallback } from "react";
|
|
2
2
|
import { StyleSheet, View, Pressable, Alert } from "react-native";
|
|
3
|
+
import Purchases from "react-native-purchases";
|
|
3
4
|
import { AtomicIcon, AtomicText } from "@umituz/react-native-design-system/atoms";
|
|
4
5
|
import { NavigationHeader } from "@umituz/react-native-design-system/molecules";
|
|
5
6
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
7
|
+
import { useAuthStore, selectUserId } from "@umituz/react-native-auth";
|
|
6
8
|
import { ScreenLayout } from "../../../../shared/presentation";
|
|
9
|
+
import { getCreditsRepository } from "../../../credits/infrastructure/CreditsRepositoryManager";
|
|
10
|
+
import { subscriptionEventBus, SUBSCRIPTION_EVENTS } from "../../../../shared/infrastructure/SubscriptionEventBus";
|
|
7
11
|
import { SubscriptionHeader } from "./components/SubscriptionHeader";
|
|
8
12
|
import { CreditsList } from "./components/CreditsList";
|
|
9
13
|
import { UpgradePrompt } from "./components/UpgradePrompt";
|
|
@@ -109,9 +113,6 @@ const DevTestPanel: React.FC<{ statusType: string }> = ({ statusType }) => {
|
|
|
109
113
|
}, [loading]);
|
|
110
114
|
|
|
111
115
|
const handleCancel = useCallback(() => run("Cancel", async () => {
|
|
112
|
-
const { useAuthStore, selectUserId } = require("@umituz/react-native-auth");
|
|
113
|
-
const { getCreditsRepository } = require("../../../credits/infrastructure/CreditsRepositoryManager");
|
|
114
|
-
const { subscriptionEventBus, SUBSCRIPTION_EVENTS } = require("../../../../shared/infrastructure/SubscriptionEventBus");
|
|
115
116
|
const userId = selectUserId(useAuthStore.getState());
|
|
116
117
|
if (!userId) throw new Error("No userId found");
|
|
117
118
|
await getCreditsRepository().syncExpiredStatus(userId);
|
|
@@ -119,7 +120,6 @@ const DevTestPanel: React.FC<{ statusType: string }> = ({ statusType }) => {
|
|
|
119
120
|
}), [run]);
|
|
120
121
|
|
|
121
122
|
const handleRestore = useCallback(() => run("Restore", async () => {
|
|
122
|
-
const Purchases = require("react-native-purchases").default;
|
|
123
123
|
await Purchases.restorePurchases();
|
|
124
124
|
}), [run]);
|
|
125
125
|
|
|
@@ -5,9 +5,10 @@ import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
|
5
5
|
import { PremiumStatusBadge } from "../../components/details/PremiumStatusBadge";
|
|
6
6
|
import type { SubscriptionHeaderProps } from "./SubscriptionHeader.types";
|
|
7
7
|
import { createSubscriptionHeaderStyles } from "./SubscriptionHeader.styles";
|
|
8
|
-
import { EXPIRATION_WARNING_THRESHOLD_DAYS as EXPIRING_SOON_THRESHOLD_DAYS } from "../../../constants/thresholds";
|
|
9
8
|
import { SubscriptionHeaderContent } from "./SubscriptionHeaderContent";
|
|
10
9
|
|
|
10
|
+
const EXPIRING_SOON_THRESHOLD_DAYS = 7;
|
|
11
|
+
|
|
11
12
|
export const SubscriptionHeader: React.FC<SubscriptionHeaderProps> = ({
|
|
12
13
|
statusType,
|
|
13
14
|
showExpirationDate,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
const EXPIRATION_WARNING_THRESHOLD_DAYS = 7;
|
|
2
2
|
|
|
3
3
|
export function shouldHighlightExpiration(daysRemaining: number | null | undefined): boolean {
|
|
4
4
|
return daysRemaining !== null && daysRemaining !== undefined && daysRemaining > 0 && daysRemaining <= EXPIRATION_WARNING_THRESHOLD_DAYS;
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
CreditLog,
|
|
7
7
|
TransactionRepositoryConfig,
|
|
8
8
|
} from "../../domain/types/transaction.types";
|
|
9
|
-
import { TransactionRepository } from "../../infrastructure/repositories/transaction";
|
|
9
|
+
import { TransactionRepository } from "../../infrastructure/repositories/transaction/TransactionRepository";
|
|
10
10
|
|
|
11
11
|
const transactionQueryKeys = {
|
|
12
12
|
all: ["transactions"] as const,
|
package/src/index.ts
CHANGED
|
@@ -37,7 +37,7 @@ export {
|
|
|
37
37
|
// Presentation Layer - Hooks
|
|
38
38
|
export { useAuthAwarePurchase } from "./domains/subscription/presentation/useAuthAwarePurchase";
|
|
39
39
|
export { useCredits } from "./domains/credits/presentation/useCredits";
|
|
40
|
-
export { useDeductCredit } from "./domains/credits/presentation/deduct-credit";
|
|
40
|
+
export { useDeductCredit } from "./domains/credits/presentation/deduct-credit/useDeductCredit";
|
|
41
41
|
export { useFeatureGate } from "./domains/subscription/presentation/useFeatureGate";
|
|
42
42
|
export { usePaywallVisibility, paywallControl } from "./domains/subscription/presentation/usePaywallVisibility";
|
|
43
43
|
export { usePremium } from "./domains/subscription/presentation/usePremium";
|
|
@@ -99,6 +99,8 @@ export {
|
|
|
99
99
|
// Wallet Domain
|
|
100
100
|
export {
|
|
101
101
|
WalletScreen as WalletScreenContainer,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
} from './domains/wallet/presentation/screens/WalletScreen';
|
|
103
|
+
export type {
|
|
104
|
+
WalletScreenProps,
|
|
105
|
+
WalletScreenTranslations,
|
|
106
|
+
} from './domains/wallet/presentation/screens/WalletScreen.types';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { useDeductCredit } from "./useDeductCredit";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const EXPIRATION_WARNING_THRESHOLD_DAYS = 7;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { TransactionRepository } from "./TransactionRepository";
|