@umituz/react-native-subscription 2.37.110 → 2.37.111
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/infrastructure/CreditsRepository.ts +3 -2
- package/src/domains/credits/infrastructure/operations/CreditsWriter.ts +2 -13
- package/src/domains/revenuecat/core/types/RevenueCatData.ts +3 -9
- package/src/domains/revenuecat/infrastructure/services/userSwitchHandler.ts +5 -1
- package/src/domains/subscription/application/SubscriptionInitializerTypes.ts +2 -10
- package/src/domains/subscription/application/SubscriptionSyncProcessor.ts +6 -6
- package/src/domains/subscription/core/SubscriptionEvents.ts +3 -6
- package/src/domains/subscription/core/SubscriptionStatus.ts +4 -4
- package/src/domains/subscription/core/types/CreditInfo.ts +10 -0
- package/src/domains/subscription/core/types/PremiumStatus.ts +21 -0
- package/src/domains/subscription/core/types/SubscriptionMetadata.ts +18 -0
- package/src/domains/subscription/core/types/index.ts +3 -0
- package/src/domains/subscription/infrastructure/handlers/PurchaseStatusResolver.ts +2 -15
- package/src/domains/subscription/infrastructure/managers/SubscriptionManager.types.ts +1 -1
- package/src/domains/subscription/infrastructure/utils/PremiumStatusSyncer.ts +5 -1
- package/src/domains/subscription/presentation/components/details/PremiumDetailsCardTypes.ts +2 -6
- package/src/domains/subscription/presentation/screens/SubscriptionDetailScreen.types.ts +3 -7
- package/src/domains/subscription/presentation/useSubscriptionStatus.types.ts +3 -14
- package/src/index.ts +1 -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.111",
|
|
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",
|
|
@@ -8,7 +8,8 @@ import { refundCreditsOperation } from "../application/RefundCreditsCommand";
|
|
|
8
8
|
import { PURCHASE_TYPE, type PurchaseType } from "../../subscription/core/SubscriptionConstants";
|
|
9
9
|
import { requireFirestore, buildDocRef, type CollectionConfig } from "../../../shared/infrastructure/firestore";
|
|
10
10
|
import { fetchCredits, checkHasCredits, documentExists } from "./operations/CreditsFetcher";
|
|
11
|
-
import { syncExpiredStatus, syncPremiumMetadata, createRecoveryCreditsDocument
|
|
11
|
+
import { syncExpiredStatus, syncPremiumMetadata, createRecoveryCreditsDocument } from "./operations/CreditsWriter";
|
|
12
|
+
import type { SubscriptionMetadata } from "../../subscription/core/types";
|
|
12
13
|
import { initializeCreditsWithRetry } from "./operations/CreditsInitializer";
|
|
13
14
|
import { calculateCreditLimit } from "../application/CreditLimitCalculator";
|
|
14
15
|
|
|
@@ -81,7 +82,7 @@ export class CreditsRepository extends BaseRepository {
|
|
|
81
82
|
await syncExpiredStatus(this.getRef(db, userId));
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
async syncPremiumMetadata(userId: string, metadata:
|
|
85
|
+
async syncPremiumMetadata(userId: string, metadata: SubscriptionMetadata): Promise<void> {
|
|
85
86
|
const db = requireFirestore();
|
|
86
87
|
await syncPremiumMetadata(this.getRef(db, userId), metadata);
|
|
87
88
|
}
|
|
@@ -3,6 +3,7 @@ import { runTransaction, serverTimestamp } from "@umituz/react-native-firebase";
|
|
|
3
3
|
import { doc, getDoc, setDoc } from "firebase/firestore";
|
|
4
4
|
import { SUBSCRIPTION_STATUS } from "../../../subscription/core/SubscriptionConstants";
|
|
5
5
|
import { resolveSubscriptionStatus } from "../../../subscription/core/SubscriptionStatus";
|
|
6
|
+
import type { SubscriptionMetadata } from "../../../subscription/core/types";
|
|
6
7
|
import { toTimestamp } from "../../../../shared/utils/dateConverter";
|
|
7
8
|
import { isPast } from "../../../../utils/dateUtils";
|
|
8
9
|
import { getAppVersion, validatePlatform } from "../../../../utils/appUtils";
|
|
@@ -25,22 +26,10 @@ export async function syncExpiredStatus(ref: DocumentReference): Promise<void> {
|
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
export interface PremiumMetadata {
|
|
29
|
-
isPremium: boolean;
|
|
30
|
-
willRenew: boolean;
|
|
31
|
-
expirationDate: string | null;
|
|
32
|
-
productId: string;
|
|
33
|
-
periodType: string | null;
|
|
34
|
-
unsubscribeDetectedAt: string | null;
|
|
35
|
-
billingIssueDetectedAt: string | null;
|
|
36
|
-
store: string | null;
|
|
37
|
-
ownershipType: string | null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
29
|
// Fix: was getDoc+setDoc (non-atomic) — now uses runTransaction.
|
|
41
30
|
export async function syncPremiumMetadata(
|
|
42
31
|
ref: DocumentReference,
|
|
43
|
-
metadata:
|
|
32
|
+
metadata: SubscriptionMetadata
|
|
44
33
|
): Promise<void> {
|
|
45
34
|
await runTransaction(async (tx: Transaction) => {
|
|
46
35
|
const doc = await tx.get(ref);
|
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SubscriptionMetadata } from "../../../subscription/core/types";
|
|
2
|
+
import type { PackageType } from "./RevenueCatTypes";
|
|
2
3
|
|
|
3
|
-
export interface RevenueCatData {
|
|
4
|
-
expirationDate: string | null;
|
|
4
|
+
export interface RevenueCatData extends Omit<SubscriptionMetadata, 'willRenew' | 'productId'> {
|
|
5
5
|
willRenew: boolean | null;
|
|
6
6
|
storeTransactionId: string | null;
|
|
7
|
-
isPremium: boolean;
|
|
8
|
-
periodType: string | null;
|
|
9
7
|
packageType: PackageType | null;
|
|
10
|
-
unsubscribeDetectedAt: string | null;
|
|
11
|
-
billingIssueDetectedAt: string | null;
|
|
12
|
-
store: Store | null;
|
|
13
|
-
ownershipType: OwnershipType | null;
|
|
14
8
|
revenueCatUserId?: string | null;
|
|
15
9
|
}
|
|
@@ -193,10 +193,14 @@ export async function handleInitialConfiguration(
|
|
|
193
193
|
userId: normalizedUserId,
|
|
194
194
|
isPremium: true,
|
|
195
195
|
productId: premiumEntitlement.productIdentifier,
|
|
196
|
-
|
|
196
|
+
expirationDate: premiumEntitlement.expirationDate ?? null,
|
|
197
197
|
willRenew: premiumEntitlement.willRenew,
|
|
198
198
|
periodType: premiumEntitlement.periodType as PeriodType | undefined,
|
|
199
199
|
storeTransactionId: subscription?.storeTransactionId ?? undefined,
|
|
200
|
+
unsubscribeDetectedAt: premiumEntitlement.unsubscribeDetectedAt ?? null,
|
|
201
|
+
billingIssueDetectedAt: premiumEntitlement.billingIssueDetectedAt ?? null,
|
|
202
|
+
store: premiumEntitlement.store ?? null,
|
|
203
|
+
ownershipType: premiumEntitlement.ownershipType ?? null,
|
|
200
204
|
});
|
|
201
205
|
} else {
|
|
202
206
|
await deps.config.onPremiumStatusChanged({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CreditsConfig } from "../../credits/core/Credits";
|
|
2
2
|
import type { UserCreditsDocumentRead } from "../../credits/core/UserCreditsDocument";
|
|
3
3
|
import type { PurchaseSource, PurchaseType } from "../core/SubscriptionConstants";
|
|
4
|
-
import type {
|
|
4
|
+
import type { SubscriptionMetadata } from "../core/types";
|
|
5
5
|
|
|
6
6
|
export interface FirebaseAuthLike {
|
|
7
7
|
currentUser: { uid: string; isAnonymous: boolean } | null;
|
|
@@ -28,19 +28,11 @@ export interface SubscriptionInitConfig {
|
|
|
28
28
|
authStateTimeoutMs?: number;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export interface InitializeCreditsMetadata {
|
|
32
|
-
productId: string;
|
|
31
|
+
export interface InitializeCreditsMetadata extends Omit<SubscriptionMetadata, 'willRenew'> {
|
|
33
32
|
source: PurchaseSource;
|
|
34
33
|
type: PurchaseType;
|
|
35
|
-
expirationDate: string | null;
|
|
36
34
|
willRenew: boolean | null;
|
|
37
35
|
storeTransactionId: string | null;
|
|
38
|
-
isPremium: boolean;
|
|
39
|
-
periodType: string | null;
|
|
40
|
-
unsubscribeDetectedAt: string | null;
|
|
41
|
-
billingIssueDetectedAt: string | null;
|
|
42
|
-
store: Store | null;
|
|
43
|
-
ownershipType: OwnershipType | null;
|
|
44
36
|
revenueCatUserId?: string | null;
|
|
45
37
|
}
|
|
46
38
|
|
|
@@ -220,7 +220,7 @@ export class SubscriptionSyncProcessor {
|
|
|
220
220
|
userId,
|
|
221
221
|
event.productId!,
|
|
222
222
|
event.willRenew ?? false,
|
|
223
|
-
event.
|
|
223
|
+
event.expirationDate ?? null,
|
|
224
224
|
event.periodType ?? null,
|
|
225
225
|
event.storeTransactionId,
|
|
226
226
|
);
|
|
@@ -235,13 +235,13 @@ export class SubscriptionSyncProcessor {
|
|
|
235
235
|
await repo.syncPremiumMetadata(userId, {
|
|
236
236
|
isPremium: event.isPremium,
|
|
237
237
|
willRenew: event.willRenew ?? false,
|
|
238
|
-
expirationDate: event.
|
|
238
|
+
expirationDate: event.expirationDate ?? null,
|
|
239
239
|
productId: event.productId!,
|
|
240
240
|
periodType: event.periodType ?? null,
|
|
241
|
-
unsubscribeDetectedAt: null,
|
|
242
|
-
billingIssueDetectedAt: null,
|
|
243
|
-
store: null,
|
|
244
|
-
ownershipType: null,
|
|
241
|
+
unsubscribeDetectedAt: event.unsubscribeDetectedAt ?? null,
|
|
242
|
+
billingIssueDetectedAt: event.billingIssueDetectedAt ?? null,
|
|
243
|
+
store: event.store ?? null,
|
|
244
|
+
ownershipType: event.ownershipType ?? null,
|
|
245
245
|
});
|
|
246
246
|
this.emitCreditsUpdated(userId);
|
|
247
247
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CustomerInfo } from "react-native-purchases";
|
|
2
|
-
import type {
|
|
2
|
+
import type { PurchaseSource } from "./SubscriptionConstants";
|
|
3
|
+
import type { SubscriptionMetadata } from "./types";
|
|
3
4
|
import type { PackageType } from "../../revenuecat/core/types/RevenueCatTypes";
|
|
4
5
|
|
|
5
6
|
export interface PurchaseCompletedEvent {
|
|
@@ -17,13 +18,9 @@ export interface RenewalDetectedEvent {
|
|
|
17
18
|
customerInfo: CustomerInfo;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
export interface PremiumStatusChangedEvent {
|
|
21
|
+
export interface PremiumStatusChangedEvent extends Partial<SubscriptionMetadata> {
|
|
21
22
|
userId: string;
|
|
22
23
|
isPremium: boolean;
|
|
23
|
-
productId?: string;
|
|
24
|
-
expiresAt?: string;
|
|
25
|
-
willRenew?: boolean;
|
|
26
|
-
periodType?: PeriodType;
|
|
27
24
|
storeTransactionId?: string;
|
|
28
25
|
}
|
|
29
26
|
|
|
@@ -12,7 +12,7 @@ export type { SubscriptionStatusType };
|
|
|
12
12
|
|
|
13
13
|
export interface SubscriptionStatus {
|
|
14
14
|
isPremium: boolean;
|
|
15
|
-
|
|
15
|
+
expirationDate: string | null;
|
|
16
16
|
productId: string | null;
|
|
17
17
|
purchasedAt?: string | null;
|
|
18
18
|
customerId?: string | null;
|
|
@@ -23,7 +23,7 @@ export interface SubscriptionStatus {
|
|
|
23
23
|
|
|
24
24
|
export const createDefaultSubscriptionStatus = (): SubscriptionStatus => ({
|
|
25
25
|
isPremium: false,
|
|
26
|
-
|
|
26
|
+
expirationDate: null,
|
|
27
27
|
productId: null,
|
|
28
28
|
purchasedAt: null,
|
|
29
29
|
customerId: null,
|
|
@@ -33,8 +33,8 @@ export const createDefaultSubscriptionStatus = (): SubscriptionStatus => ({
|
|
|
33
33
|
|
|
34
34
|
export const isSubscriptionValid = (status: SubscriptionStatus | null): boolean => {
|
|
35
35
|
if (!status || !status.isPremium) return false;
|
|
36
|
-
if (!status.
|
|
37
|
-
return timezoneService.isFuture(new Date(status.
|
|
36
|
+
if (!status.expirationDate) return true;
|
|
37
|
+
return timezoneService.isFuture(new Date(status.expirationDate));
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
export interface StatusResolverInput {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credit usage information for display in subscription UI components.
|
|
3
|
+
* Single source of truth — used by SubscriptionDetailScreen and PremiumDetailsCard.
|
|
4
|
+
*/
|
|
5
|
+
export interface CreditInfo {
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
current: number;
|
|
9
|
+
total: number;
|
|
10
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolved premium status from RevenueCat CustomerInfo.
|
|
3
|
+
* Uses Date objects (presentation-ready).
|
|
4
|
+
*
|
|
5
|
+
* Extended by SubscriptionStatusResult which adds hook state (isLoading, error, refetch).
|
|
6
|
+
*/
|
|
7
|
+
export interface PremiumStatus {
|
|
8
|
+
isPremium: boolean;
|
|
9
|
+
expirationDate: Date | null;
|
|
10
|
+
willRenew: boolean;
|
|
11
|
+
productIdentifier: string | null;
|
|
12
|
+
originalPurchaseDate: Date | null;
|
|
13
|
+
latestPurchaseDate: Date | null;
|
|
14
|
+
billingIssuesDetected: boolean;
|
|
15
|
+
isSandbox: boolean;
|
|
16
|
+
periodType: string | null;
|
|
17
|
+
packageType: string | null;
|
|
18
|
+
store: string | null;
|
|
19
|
+
gracePeriodExpiresDate: Date | null;
|
|
20
|
+
unsubscribeDetectedAt: Date | null;
|
|
21
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base subscription metadata — the single source of truth for subscription state fields.
|
|
3
|
+
*
|
|
4
|
+
* All subscription-related types (RevenueCatData, PremiumStatusChangedEvent,
|
|
5
|
+
* InitializeCreditsMetadata) extend or compose from this base to eliminate
|
|
6
|
+
* field duplication and ensure consistent naming.
|
|
7
|
+
*/
|
|
8
|
+
export interface SubscriptionMetadata {
|
|
9
|
+
isPremium: boolean;
|
|
10
|
+
willRenew: boolean;
|
|
11
|
+
expirationDate: string | null;
|
|
12
|
+
productId: string;
|
|
13
|
+
periodType: string | null;
|
|
14
|
+
unsubscribeDetectedAt: string | null;
|
|
15
|
+
billingIssueDetectedAt: string | null;
|
|
16
|
+
store: string | null;
|
|
17
|
+
ownershipType: string | null;
|
|
18
|
+
}
|
|
@@ -2,22 +2,9 @@ import type { CustomerInfo } from "react-native-purchases";
|
|
|
2
2
|
import { getPremiumEntitlement } from "../../../revenuecat/core/types";
|
|
3
3
|
import { toDate } from "../../../../shared/utils/dateConverter";
|
|
4
4
|
import { detectPackageType } from "../../../../utils/packageTypeDetector";
|
|
5
|
+
import type { PremiumStatus } from "../../core/types";
|
|
5
6
|
|
|
6
|
-
export
|
|
7
|
-
isPremium: boolean;
|
|
8
|
-
expirationDate: Date | null;
|
|
9
|
-
willRenew: boolean;
|
|
10
|
-
productIdentifier: string | null;
|
|
11
|
-
originalPurchaseDate: Date | null;
|
|
12
|
-
latestPurchaseDate: Date | null;
|
|
13
|
-
billingIssuesDetected: boolean;
|
|
14
|
-
isSandbox: boolean;
|
|
15
|
-
periodType: string | null;
|
|
16
|
-
packageType: string | null;
|
|
17
|
-
store: string | null;
|
|
18
|
-
gracePeriodExpiresDate: Date | null;
|
|
19
|
-
unsubscribeDetectedAt: Date | null;
|
|
20
|
-
}
|
|
7
|
+
export type { PremiumStatus };
|
|
21
8
|
|
|
22
9
|
export class PurchaseStatusResolver {
|
|
23
10
|
static resolve(customerInfo: CustomerInfo, entitlementId: string): PremiumStatus {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RevenueCatConfig } from "../../../revenuecat/core/types";
|
|
2
|
-
import type { PremiumStatus } from "
|
|
2
|
+
import type { PremiumStatus } from "../../core/types";
|
|
3
3
|
import type { RestoreResultInfo } from "../handlers/package-operations/types";
|
|
4
4
|
|
|
5
5
|
export interface SubscriptionManagerConfig {
|
|
@@ -36,10 +36,14 @@ export async function syncPremiumStatus(
|
|
|
36
36
|
userId,
|
|
37
37
|
isPremium: true,
|
|
38
38
|
productId: premiumEntitlement.productIdentifier,
|
|
39
|
-
|
|
39
|
+
expirationDate: premiumEntitlement.expirationDate ?? null,
|
|
40
40
|
willRenew: premiumEntitlement.willRenew,
|
|
41
41
|
periodType: premiumEntitlement.periodType as PeriodType | undefined,
|
|
42
42
|
storeTransactionId: subscription?.storeTransactionId ?? undefined,
|
|
43
|
+
unsubscribeDetectedAt: premiumEntitlement.unsubscribeDetectedAt ?? null,
|
|
44
|
+
billingIssueDetectedAt: premiumEntitlement.billingIssueDetectedAt ?? null,
|
|
45
|
+
store: premiumEntitlement.store ?? null,
|
|
46
|
+
ownershipType: premiumEntitlement.ownershipType ?? null,
|
|
43
47
|
});
|
|
44
48
|
} else {
|
|
45
49
|
await config.onPremiumStatusChanged({ userId, isPremium: false });
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { SubscriptionStatusType } from "./PremiumStatusBadge";
|
|
2
|
+
import type { CreditInfo } from "../../../core/types";
|
|
2
3
|
|
|
3
|
-
export
|
|
4
|
-
id: string;
|
|
5
|
-
label: string;
|
|
6
|
-
current: number;
|
|
7
|
-
total: number;
|
|
8
|
-
}
|
|
4
|
+
export type { CreditInfo };
|
|
9
5
|
|
|
10
6
|
export interface PremiumDetailsTranslations {
|
|
11
7
|
title: string;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { SubscriptionStatusType } from "../../core/SubscriptionConstants";
|
|
2
|
+
import type { CreditInfo } from "../../core/types";
|
|
3
|
+
|
|
4
|
+
export type { CreditInfo };
|
|
2
5
|
|
|
3
6
|
export interface SubscriptionDisplayFlags {
|
|
4
7
|
showHeader: boolean;
|
|
@@ -40,13 +43,6 @@ export interface UpgradePromptConfig {
|
|
|
40
43
|
onUpgrade?: () => void;
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
export interface CreditInfo {
|
|
44
|
-
id: string;
|
|
45
|
-
label: string;
|
|
46
|
-
current: number;
|
|
47
|
-
total: number;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
46
|
export interface SubscriptionDetailConfig {
|
|
51
47
|
display: SubscriptionDisplayFlags;
|
|
52
48
|
statusType: SubscriptionStatusType;
|
|
@@ -1,17 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
willRenew: boolean;
|
|
5
|
-
productIdentifier: string | null;
|
|
6
|
-
originalPurchaseDate: Date | null;
|
|
7
|
-
latestPurchaseDate: Date | null;
|
|
8
|
-
billingIssuesDetected: boolean;
|
|
9
|
-
isSandbox: boolean;
|
|
10
|
-
periodType: string | null;
|
|
11
|
-
packageType: string | null;
|
|
12
|
-
store: string | null;
|
|
13
|
-
gracePeriodExpiresDate: Date | null;
|
|
14
|
-
unsubscribeDetectedAt: Date | null;
|
|
1
|
+
import type { PremiumStatus } from "../core/types";
|
|
2
|
+
|
|
3
|
+
export interface SubscriptionStatusResult extends PremiumStatus {
|
|
15
4
|
isLoading: boolean;
|
|
16
5
|
error: Error | null;
|
|
17
6
|
refetch: () => void;
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Domain Layer - Constants & Types
|
|
2
2
|
export * from "./domains/subscription/core/SubscriptionConstants";
|
|
3
|
+
export type { SubscriptionMetadata, PremiumStatus, CreditInfo } from "./domains/subscription/core/types";
|
|
3
4
|
export {
|
|
4
5
|
createDefaultSubscriptionStatus,
|
|
5
6
|
isSubscriptionValid,
|
|
@@ -57,7 +58,6 @@ export type {
|
|
|
57
58
|
SubscriptionDetailTranslations,
|
|
58
59
|
SubscriptionDisplayFlags,
|
|
59
60
|
UpgradePromptConfig,
|
|
60
|
-
CreditInfo,
|
|
61
61
|
} from "./domains/subscription/presentation/screens/SubscriptionDetailScreen.types";
|
|
62
62
|
export * from "./domains/paywall/components/PaywallContainer";
|
|
63
63
|
|