@umituz/react-native-subscription 2.27.67 → 2.27.69

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 (23) hide show
  1. package/package.json +1 -1
  2. package/src/domains/credits/application/CreditLimitCalculator.ts +3 -3
  3. package/src/domains/credits/application/CreditsInitializer.ts +6 -3
  4. package/src/domains/credits/application/DeductCreditsCommand.ts +2 -2
  5. package/src/domains/credits/application/credit-strategies/ICreditStrategy.ts +3 -2
  6. package/src/domains/credits/application/credit-strategies/StandardPurchaseCreditStrategy.ts +9 -1
  7. package/src/domains/credits/application/credit-strategies/TrialCreditStrategy.ts +2 -2
  8. package/src/domains/subscription/application/SubscriptionSyncService.ts +10 -2
  9. package/src/domains/subscription/application/SubscriptionSyncUtils.ts +5 -3
  10. package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +1 -1
  11. package/src/domains/subscription/infrastructure/hooks/useRevenueCat.ts +1 -1
  12. package/src/domains/subscription/infrastructure/services/PurchaseHandler.ts +1 -1
  13. package/src/domains/subscription/infrastructure/services/RestoreHandler.ts +1 -1
  14. package/src/domains/subscription/infrastructure/services/RevenueCatInitializer.ts +1 -1
  15. package/src/domains/subscription/infrastructure/services/RevenueCatService.ts +2 -2
  16. package/src/domains/trial/application/TrialService.ts +1 -0
  17. package/src/index.ts +28 -59
  18. package/src/init/createSubscriptionInitModule.ts +1 -1
  19. package/src/presentation/components/details/PremiumStatusBadge.tsx +1 -3
  20. package/src/presentation/hooks/feedback/useFeedbackSubmit.ts +1 -1
  21. package/src/shared/application/ports/IRevenueCatService.ts +32 -0
  22. package/src/utils/packageTypeDetector.ts +2 -2
  23. package/src/domain/README.md +0 -54
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-subscription",
3
- "version": "2.27.67",
3
+ "version": "2.27.69",
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
- import type { CreditsConfig } from "../../domain/entities/Credits";
2
- import { detectPackageType } from "../../utils/packageTypeDetector";
3
- import { getCreditAllocation } from "../../utils/creditMapper";
1
+ import type { CreditsConfig } from "../core/Credits";
2
+ import { detectPackageType } from "../../../utils/packageTypeDetector";
3
+ import { getCreditAllocation } from "../../../utils/creditMapper";
4
4
 
5
5
  export class CreditLimitCalculator {
6
6
  static calculate(productId: string | undefined, config: CreditsConfig): number {
@@ -33,7 +33,7 @@ export async function initializeCreditsTransaction(
33
33
  }
34
34
 
35
35
  const creditLimit = CreditLimitCalculator.calculate(metadata?.productId, config);
36
- const { purchaseType, purchaseHistory } = PurchaseMetadataGenerator.generate({
36
+ const { purchaseHistory } = PurchaseMetadataGenerator.generate({
37
37
  productId: metadata?.productId,
38
38
  source: metadata?.source,
39
39
  type: metadata?.type,
@@ -51,19 +51,22 @@ export async function initializeCreditsTransaction(
51
51
  // Resolve credits using Strategy Pattern
52
52
  const isStatusSync = purchaseId?.startsWith("status_sync_") ?? false;
53
53
  const isSubscriptionActive = isPremium && !isExpired;
54
+ const productId = metadata?.productId;
54
55
 
55
56
  const newCredits = creditAllocationContext.allocate({
56
57
  status,
57
58
  isStatusSync,
58
59
  existingData,
59
60
  creditLimit,
60
- isSubscriptionActive
61
+ isSubscriptionActive,
62
+ productId,
61
63
  });
62
64
 
63
65
  const creditsData: Record<string, any> = {
64
66
  isPremium, status, credits: newCredits, creditLimit,
65
67
  lastUpdatedAt: now,
66
- processedPurchases: (purchaseId ? [...(existingData?.processedPurchases || []), purchaseId].slice(-10) : existingData?.processedPurchases) || [],
68
+ // Increase history window to 50 for better idempotency
69
+ processedPurchases: (purchaseId ? [...(existingData?.processedPurchases || []), purchaseId].slice(-50) : existingData?.processedPurchases) || [],
67
70
  purchaseHistory: purchaseHistory.length ? purchaseHistory : undefined
68
71
  };
69
72
 
@@ -1,7 +1,7 @@
1
1
  import { runTransaction, serverTimestamp, type Firestore, type Transaction, type DocumentReference } from "firebase/firestore";
2
2
  import { getFirestore } from "@umituz/react-native-firebase";
3
- import type { DeductCreditsResult } from "../../../domain/entities/Credits";
4
- import { subscriptionEventBus, SUBSCRIPTION_EVENTS } from "../SubscriptionEventBus";
3
+ import type { DeductCreditsResult } from "../core/Credits";
4
+ import { subscriptionEventBus, SUBSCRIPTION_EVENTS } from "../../../shared/infrastructure/SubscriptionEventBus";
5
5
 
6
6
  export interface IDeductCreditsCommand {
7
7
  execute(userId: string, cost: number): Promise<DeductCreditsResult>;
@@ -1,5 +1,5 @@
1
- import type { SubscriptionStatusType } from "../../domain/entities/SubscriptionStatus";
2
- import type { UserCreditsDocumentRead } from "../models/UserCreditsDocument";
1
+ import type { SubscriptionStatusType } from "../../../subscription/core/SubscriptionStatus";
2
+ import type { UserCreditsDocumentRead } from "../../core/UserCreditsDocument";
3
3
 
4
4
  export interface CreditStrategyParams {
5
5
  status: SubscriptionStatusType;
@@ -7,6 +7,7 @@ export interface CreditStrategyParams {
7
7
  existingData: UserCreditsDocumentRead | null;
8
8
  creditLimit: number;
9
9
  isSubscriptionActive: boolean;
10
+ productId?: string;
10
11
  }
11
12
 
12
13
  export interface ICreditStrategy {
@@ -1,8 +1,9 @@
1
1
  import { ICreditStrategy, type CreditAllocationParams } from "./ICreditStrategy";
2
+ import { isCreditPackage } from "../../../../utils/packageTypeDetector";
2
3
 
3
4
  /**
4
5
  * Default strategy for new purchases, renewals, or upgrades.
5
- * Resets credits to the calculated credit limit.
6
+ * Resets credits for subscriptions, but ADDS credits for consumable packages.
6
7
  */
7
8
  export class StandardPurchaseCreditStrategy implements ICreditStrategy {
8
9
  canHandle(_params: CreditAllocationParams): boolean {
@@ -11,6 +12,13 @@ export class StandardPurchaseCreditStrategy implements ICreditStrategy {
11
12
  }
12
13
 
13
14
  execute(params: CreditAllocationParams): number {
15
+ // If it's a credit package (consumable), we add to existing balance
16
+ if (params.productId && isCreditPackage(params.productId)) {
17
+ const existing = params.existingData?.credits ?? 0;
18
+ return existing + params.creditLimit;
19
+ }
20
+
21
+ // Standard subscription behavior: Reset to the calculated limit (e.g. 100/mo)
14
22
  return params.creditLimit;
15
23
  }
16
24
  }
@@ -1,6 +1,6 @@
1
1
  import { ICreditStrategy, type CreditAllocationParams } from "./ICreditStrategy";
2
- import { SUBSCRIPTION_STATUS } from "../../../domain/entities/SubscriptionStatus";
3
- import { TRIAL_CONFIG } from "../TrialService";
2
+ import { SUBSCRIPTION_STATUS } from "../../../subscription/core/SubscriptionConstants";
3
+ import { TRIAL_CONFIG } from "../../../trial/core/TrialTypes";
4
4
 
5
5
  /**
6
6
  * Strategy for Trial and Trial Canceled users.
@@ -15,7 +15,11 @@ export class SubscriptionSyncService {
15
15
  async handlePurchase(userId: string, productId: string, customerInfo: CustomerInfo, source?: PurchaseSource) {
16
16
  try {
17
17
  const revenueCatData = extractRevenueCatData(customerInfo, this.entitlementId);
18
- await getCreditsRepository().initializeCredits(userId, `purchase_${productId}_${Date.now()}`, productId, source, revenueCatData);
18
+ const purchaseId = revenueCatData.originalTransactionId
19
+ ? `purchase_${revenueCatData.originalTransactionId}`
20
+ : `purchase_${productId}_${Date.now()}`;
21
+
22
+ await getCreditsRepository().initializeCredits(userId, purchaseId, productId, source, revenueCatData);
19
23
 
20
24
  // Notify listeners via Event Bus
21
25
  subscriptionEventBus.emit(SUBSCRIPTION_EVENTS.CREDITS_UPDATED, userId);
@@ -29,7 +33,11 @@ export class SubscriptionSyncService {
29
33
  try {
30
34
  const revenueCatData = extractRevenueCatData(customerInfo, this.entitlementId);
31
35
  revenueCatData.expirationDate = newExpirationDate || revenueCatData.expirationDate;
32
- await getCreditsRepository().initializeCredits(userId, `renewal_${productId}_${Date.now()}`, productId, "renewal", revenueCatData);
36
+ const purchaseId = revenueCatData.originalTransactionId
37
+ ? `renewal_${revenueCatData.originalTransactionId}_${newExpirationDate}`
38
+ : `renewal_${productId}_${Date.now()}`;
39
+
40
+ await getCreditsRepository().initializeCredits(userId, purchaseId, productId, "renewal", revenueCatData);
33
41
 
34
42
  subscriptionEventBus.emit(SUBSCRIPTION_EVENTS.CREDITS_UPDATED, userId);
35
43
  subscriptionEventBus.emit(SUBSCRIPTION_EVENTS.RENEWAL_DETECTED, { userId, productId });
@@ -1,6 +1,6 @@
1
1
  import type { CustomerInfo } from "react-native-purchases";
2
- import type { RevenueCatData } from "../../domain/types/RevenueCatData";
3
- import { type PeriodType } from "../../domain/entities/SubscriptionConstants";
2
+ import type { RevenueCatData } from "../core/RevenueCatData";
3
+ import { type PeriodType } from "../core/SubscriptionStatus";
4
4
 
5
5
  /** Extract RevenueCat data from CustomerInfo (Single Source of Truth) */
6
6
  export const extractRevenueCatData = (customerInfo: CustomerInfo, entitlementId: string): RevenueCatData => {
@@ -10,7 +10,9 @@ export const extractRevenueCatData = (customerInfo: CustomerInfo, entitlementId:
10
10
  return {
11
11
  expirationDate: entitlement?.expirationDate ?? customerInfo.latestExpirationDate ?? null,
12
12
  willRenew: entitlement?.willRenew ?? false,
13
- originalTransactionId: entitlement?.originalPurchaseDate ?? undefined,
13
+ // Use latestPurchaseDate if originalPurchaseDate is missing, or a combine id
14
+ originalTransactionId: entitlement?.originalPurchaseDate || customerInfo.firstSeen,
14
15
  periodType: entitlement?.periodType as PeriodType | undefined,
16
+ isPremium: !!customerInfo.entitlements.active[entitlementId],
15
17
  };
16
18
  };
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import type { PurchasesPackage, CustomerInfo } from "react-native-purchases";
7
- import type { IRevenueCatService } from "../../application/ports/IRevenueCatService";
7
+ import type { IRevenueCatService } from "../../../../shared/application/ports/IRevenueCatService";
8
8
  import { getPremiumEntitlement } from "../../domain/types/RevenueCatTypes";
9
9
  import { PurchaseStatusResolver, type PremiumStatus } from "./PurchaseStatusResolver";
10
10
 
@@ -6,7 +6,7 @@
6
6
  import { useState, useCallback } from "react";
7
7
  import type { PurchasesOffering, PurchasesPackage } from "react-native-purchases";
8
8
  import { getRevenueCatService } from '../../infrastructure/services/RevenueCatService';
9
- import type { PurchaseResult, RestoreResult } from '../../application/ports/IRevenueCatService';
9
+ import type { PurchaseResult, RestoreResult } from '../../../../shared/application/ports/IRevenueCatService';
10
10
 
11
11
  export interface UseRevenueCatResult {
12
12
  /** Current offering */
@@ -1,5 +1,5 @@
1
1
  import Purchases, { type PurchasesPackage } from "react-native-purchases";
2
- import type { PurchaseResult } from "../../application/ports/IRevenueCatService";
2
+ import type { PurchaseResult } from "../../../../shared/application/ports/IRevenueCatService";
3
3
  import { RevenueCatPurchaseError, RevenueCatInitializationError } from "../../domain/errors/RevenueCatError";
4
4
  import type { RevenueCatConfig } from "../../domain/value-objects/RevenueCatConfig";
5
5
  import { isUserCancelledError, getErrorMessage } from "../../domain/types/RevenueCatTypes";
@@ -1,5 +1,5 @@
1
1
  import Purchases from "react-native-purchases";
2
- import type { RestoreResult } from "../../application/ports/IRevenueCatService";
2
+ import type { RestoreResult } from "../../../../shared/application/ports/IRevenueCatService";
3
3
  import { RevenueCatRestoreError, RevenueCatInitializationError } from "../../domain/errors/RevenueCatError";
4
4
  import type { RevenueCatConfig } from "../../domain/value-objects/RevenueCatConfig";
5
5
  import { getErrorMessage } from "../../domain/types/RevenueCatTypes";
@@ -1,5 +1,5 @@
1
1
  import Purchases, { LOG_LEVEL, type CustomerInfo, type PurchasesOfferings } from "react-native-purchases";
2
- import type { InitializeResult } from "../../application/ports/IRevenueCatService";
2
+ import type { InitializeResult } from "../../../../shared/application/ports/IRevenueCatService";
3
3
  import type { RevenueCatConfig } from "../../domain/value-objects/RevenueCatConfig";
4
4
  import { resolveApiKey } from "../utils/ApiKeyResolver";
5
5
 
@@ -14,8 +14,8 @@ import type {
14
14
  InitializeResult,
15
15
  PurchaseResult,
16
16
  RestoreResult,
17
- } from "../../application/ports/IRevenueCatService";
18
- import type { RevenueCatConfig } from "../../domain/value-objects/RevenueCatConfig";
17
+ } from "../../../../shared/application/ports/IRevenueCatService";
18
+ import type { RevenueCatConfig } from "../../core/RevenueCatConfig";
19
19
  import { resolveApiKey } from "../utils/ApiKeyResolver";
20
20
  import { initializeSDK } from "./RevenueCatInitializer";
21
21
  import { fetchOfferings } from "./OfferingsFetcher";
@@ -7,6 +7,7 @@ import { PersistentDeviceIdService } from "@umituz/react-native-design-system";
7
7
  import { DeviceTrialRepository } from "../infrastructure/DeviceTrialRepository";
8
8
  import { TrialEligibilityService } from "./TrialEligibilityService";
9
9
  import type { TrialEligibilityResult } from "../core/TrialTypes";
10
+ export type { TrialEligibilityResult };
10
11
 
11
12
  const repository = new DeviceTrialRepository();
12
13
 
package/src/index.ts CHANGED
@@ -2,22 +2,20 @@
2
2
  * React Native Subscription - Public API
3
3
  */
4
4
 
5
- export * from "./domains/wallet";
6
- export * from "./domains/paywall";
7
- export * from "./domains/config";
8
-
9
- // Domain Layer - Constants & Types
10
- export * from "./domain/entities/SubscriptionConstants";
5
+ // Domain Layer - Constants & Types (Now in domains/subscription/core)
6
+ export * from "./domains/subscription/core/SubscriptionConstants";
11
7
  export {
12
8
  createDefaultSubscriptionStatus,
13
9
  isSubscriptionValid,
14
10
  resolveSubscriptionStatus,
15
- } from "./domain/entities/SubscriptionStatus";
16
- export type { SubscriptionStatus, StatusResolverInput } from "./domain/entities/SubscriptionStatus";
17
- export type { SubscriptionConfig } from "./domain/value-objects/SubscriptionConfig";
18
- export type { ISubscriptionRepository } from "./application/ports/ISubscriptionRepository";
11
+ } from "./domains/subscription/core/SubscriptionStatus";
12
+ export type { SubscriptionStatus, StatusResolverInput } from "./domains/subscription/core/SubscriptionStatus";
13
+
14
+ // Application Layer - Ports
15
+ export type { ISubscriptionRepository } from "./shared/application/ports/ISubscriptionRepository";
16
+ export type { IRevenueCatService } from "./shared/application/ports/IRevenueCatService";
19
17
 
20
- // Result Pattern (Functional Error Handling)
18
+ // Result Pattern (Now in shared/utils)
21
19
  export {
22
20
  success,
23
21
  failure,
@@ -30,39 +28,29 @@ export {
30
28
  tryCatch,
31
29
  tryCatchSync,
32
30
  combine,
33
- } from "./domain/value-objects/Result";
34
- export type { Result, Success, Failure } from "./domain/value-objects/Result";
31
+ } from "./shared/utils/Result";
32
+ export type { Result, Success, Failure } from "./shared/utils/Result";
35
33
 
36
- // Infrastructure Layer
37
- export { SubscriptionService, initializeSubscriptionService } from "./infrastructure/services/SubscriptionService";
38
- export {
39
- submitFeedback,
40
- submitPaywallFeedback,
41
- submitSettingsFeedback,
42
- type FeedbackData,
43
- type FeedbackSubmitResult,
44
- } from "./infrastructure/services/FeedbackService";
45
- export { initializeSubscription, type SubscriptionInitConfig, type CreditPackageConfig } from "./infrastructure/services/SubscriptionInitializer";
46
- export {
34
+ // Infrastructure Layer (Services & Repositories)
35
+ export { initializeSubscription, type SubscriptionInitConfig, type CreditPackageConfig } from "./domains/subscription/application/SubscriptionInitializer";
36
+ export {
47
37
  getDeviceId,
48
38
  checkTrialEligibility,
49
39
  recordTrialStart,
50
40
  recordTrialEnd,
51
41
  recordTrialConversion,
52
- TRIAL_CONFIG,
53
- type DeviceTrialRecord,
54
- type TrialEligibilityResult,
55
- } from "./infrastructure/services/TrialService";
56
- export { CreditsRepository, createCreditsRepository } from "./infrastructure/repositories/CreditsRepository";
57
- export { configureCreditsRepository, getCreditsRepository, getCreditsConfig, resetCreditsRepository, isCreditsRepositoryConfigured } from "./infrastructure/repositories/CreditsRepositoryProvider";
58
- export {
59
- getSavedPurchase,
60
- clearSavedPurchase,
61
- configureAuthProvider,
62
- type PurchaseAuthProvider,
63
- } from "./presentation/hooks/useAuthAwarePurchase";
42
+ type TrialEligibilityResult
43
+ } from "./domains/trial/application/TrialService";
44
+
45
+ export { CreditsRepository } from "./domains/credits/infrastructure/CreditsRepository";
46
+ export {
47
+ configureCreditsRepository,
48
+ getCreditsRepository,
49
+ getCreditsConfig,
50
+ isCreditsRepositoryConfigured
51
+ } from "./domains/credits/infrastructure/CreditsRepositoryProvider";
64
52
 
65
- // Presentation Layer - Hooks
53
+ // Presentation Layer - Hooks (Point to the bridge)
66
54
  export * from "./presentation/hooks";
67
55
 
68
56
  // Presentation Layer - Components
@@ -70,12 +58,7 @@ export * from "./presentation/components/details/PremiumDetailsCard";
70
58
  export * from "./presentation/components/details/PremiumStatusBadge";
71
59
  export * from "./presentation/components/sections/SubscriptionSection";
72
60
  export * from "./presentation/components/feedback/PaywallFeedbackModal";
73
- export * from "./presentation/components/overlay";
74
61
  export * from "./presentation/screens/SubscriptionDetailScreen";
75
- export * from "./presentation/types/SubscriptionDetailTypes";
76
-
77
- // Presentation Layer - Stores
78
- export * from "./presentation/stores";
79
62
 
80
63
  export type {
81
64
  CreditType,
@@ -83,27 +66,13 @@ export type {
83
66
  CreditsConfig,
84
67
  CreditsResult,
85
68
  DeductCreditsResult,
86
- CreditAllocation,
87
- PackageAllocationMap,
88
- } from "./domain/entities/Credits";
89
- export { DEFAULT_CREDITS_CONFIG } from "./domain/entities/Credits";
90
- export { InsufficientCreditsError } from "./domain/errors/InsufficientCreditsError";
69
+ } from "./domains/credits/core/Credits";
70
+
71
+ export { DEFAULT_CREDITS_CONFIG } from "./domains/credits/core/Credits";
91
72
 
92
73
  // Utils
93
74
  export * from "./utils";
94
75
 
95
- // RevenueCat
96
- export * from "./revenuecat";
97
-
98
- // App Service Helpers (for configureAppServices)
99
- export {
100
- createCreditService,
101
- createPaywallService,
102
- type CreditServiceConfig,
103
- type ICreditService,
104
- type IPaywallService,
105
- } from "./infrastructure/services/app-service-helpers";
106
-
107
76
  // Init Module Factory
108
77
  export {
109
78
  createSubscriptionInitModule,
@@ -1,5 +1,5 @@
1
1
  import type { InitModule } from '@umituz/react-native-design-system';
2
- import { initializeSubscription, type SubscriptionInitConfig } from '../infrastructure/services/SubscriptionInitializer';
2
+ import { initializeSubscription, type SubscriptionInitConfig } from '../domains/subscription/application/SubscriptionInitializer';
3
3
 
4
4
  export interface SubscriptionInitModuleConfig extends Omit<SubscriptionInitConfig, 'apiKey'> {
5
5
  getApiKey: () => string | undefined;
@@ -9,9 +9,7 @@ import { useAppDesignTokens, AtomicText } from "@umituz/react-native-design-syst
9
9
  import {
10
10
  SUBSCRIPTION_STATUS,
11
11
  type SubscriptionStatusType
12
- } from "../../../domain/entities/SubscriptionConstants";
13
-
14
- export type { SubscriptionStatusType };
12
+ } from "../../../domains/subscription/core/SubscriptionConstants";
15
13
 
16
14
  export interface PremiumStatusBadgeProps {
17
15
  status: SubscriptionStatusType;
@@ -8,7 +8,7 @@ import { useAuth } from "@umituz/react-native-auth";
8
8
  import {
9
9
  submitPaywallFeedback,
10
10
  submitSettingsFeedback,
11
- } from "../../../infrastructure/services/FeedbackService";
11
+ } from "../../../shared/application/FeedbackService";
12
12
 
13
13
  export interface UsePaywallFeedbackSubmitOptions {
14
14
  onSuccess?: () => void;
@@ -0,0 +1,32 @@
1
+ import type {
2
+ PurchasesOffering,
3
+ PurchasesPackage,
4
+ CustomerInfo,
5
+ } from "react-native-purchases";
6
+
7
+ export interface InitializeResult {
8
+ success: boolean;
9
+ offering: PurchasesOffering | null;
10
+ isPremium: boolean;
11
+ }
12
+
13
+ export interface PurchaseResult {
14
+ success: boolean;
15
+ productId: string | null;
16
+ }
17
+
18
+ export interface RestoreResult {
19
+ success: boolean;
20
+ productId: string | null;
21
+ }
22
+
23
+ export interface IRevenueCatService {
24
+ initialize(userId: string, apiKey?: string): Promise<InitializeResult>;
25
+ fetchOfferings(): Promise<PurchasesOffering | null>;
26
+ purchasePackage(pkg: PurchasesPackage, userId: string): Promise<PurchaseResult>;
27
+ restorePurchases(userId: string): Promise<RestoreResult>;
28
+ isInitialized(): boolean;
29
+ getCurrentUserId(): string | null;
30
+ getCustomerInfo(): Promise<CustomerInfo | null>;
31
+ reset(): Promise<void>;
32
+ }
@@ -3,7 +3,7 @@
3
3
  * Detects subscription package type from RevenueCat package identifier
4
4
  */
5
5
 
6
- import { PACKAGE_TYPE, type PackageType } from "../domain/entities/SubscriptionConstants";
6
+ import { PACKAGE_TYPE, type PackageType } from "../domains/subscription/core/SubscriptionConstants";
7
7
 
8
8
  export type SubscriptionPackageType = PackageType;
9
9
 
@@ -15,7 +15,7 @@ export type SubscriptionPackageType = PackageType;
15
15
  * Check if identifier is a credit package (consumable purchase)
16
16
  * Credit packages use a different system and don't need type detection
17
17
  */
18
- function isCreditPackage(identifier: string): boolean {
18
+ export function isCreditPackage(identifier: string): boolean {
19
19
  // Matches "credit" as a word or part of a common naming pattern
20
20
  return /\bcredit\b|_credit_|-credit-/i.test(identifier) || identifier.toLowerCase().includes("credit");
21
21
  }
@@ -1,54 +0,0 @@
1
- # Domain Layer
2
-
3
- Abonelik sisteminin temel domain logic'ini, entity'lerini ve value object'lerini içeren katman.
4
-
5
- ## Location
6
-
7
- `src/domain/`
8
-
9
- ## Strategy
10
-
11
- Temel iş kavramlarını, iş kurallarını ve domain logic'ini encapsulate eden katman. Framework-agnostic ve tamamen iş mantığına odaklı.
12
-
13
- ## Restrictions
14
-
15
- ### REQUIRED
16
-
17
- - MUST be framework-agnostic (no React, React Native dependencies)
18
- - MUST encapsulate business rules within entities
19
- - MUST validate all invariants on entity creation
20
- - MUST use immutable objects
21
- - MUST implement type guards for type safety
22
- - MUST define domain-specific error types
23
-
24
- ### PROHIBITED
25
-
26
- - MUST NOT contain any framework or UI code
27
- - MUST NOT have direct dependencies on infrastructure
28
- - MUST NOT expose mutable state
29
- - MUST NOT use generic error types
30
-
31
- ### CRITICAL
32
-
33
- - Keep entities pure and framework-independent
34
- - Validate all business rules on entity creation
35
- - Make all objects immutable
36
- - Encapsulate business logic within entities
37
- - Use strong typing throughout
38
-
39
- ## AI Agent Guidelines
40
-
41
- When working with domain layer:
42
- 1. Immutable Objects - entity'leri immutable olarak tasarlayın
43
- 2. Validation - entity creation'da validation yapın
44
- 3. Encapsulation - business logic'i entity içinde tutun
45
- 4. Type Safety - strong typing kullanın
46
- 5. Domain Events - önemli domain olaylarını event olarak yayınlayın
47
- 6. Error Handling - domain-specific hatalar tanımlayın
48
-
49
- ## Related Documentation
50
-
51
- - [Domain Entities](./entities/README.md)
52
- - [Value Objects](./value-objects/README.md)
53
- - [Domain Errors](./errors/README.md)
54
- - [Application Layer](../application/README.md)