npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@umituz/react-native-premium

v1.7.2

Published

Premium subscription management system for React Native apps - Centralized premium/freemium/guest tier LOGICAL determination (no database operations)

Readme

@umituz/react-native-premium

Centralized premium/freemium/guest tier determination for React Native apps

npm version License: MIT

🎯 Philosophy

This package provides ONLY tier logic determination. It does NOT handle:

  • ❌ Database operations
  • ❌ API calls
  • ❌ State management
  • ❌ Authentication logic

Why? This makes the package:

  • Database-agnostic (works with Firebase, Supabase, MongoDB, etc.)
  • Framework-agnostic (works with any state management)
  • Simple and lightweight (~2KB gzipped)
  • Easy to test (pure functions)
  • Reusable across 100+ apps (single source of truth)

✨ Features

  • 🎯 Centralized Tier Logic: Single source of truth for tier determination
  • 🚫 No Database Operations: Apps handle their own data fetching
  • Lightweight: Only ~2KB gzipped
  • 🎨 Type-Safe: Full TypeScript support
  • 🔄 Framework Agnostic: Works with any state management solution
  • 🧪 Testable: Pure functions, easy to test

📦 Installation

npm install @umituz/react-native-premium

🎭 User Tiers

The package defines three user tiers:

| Tier | Description | isPremium | isGuest | |------|-------------|-----------|---------| | Guest | Not authenticated | false | true | | Freemium | Authenticated, no premium | false | false | | Premium | Authenticated, has premium | true | false |

Key Rule: Guest users are ALWAYS freemium and NEVER premium, regardless of any other factors.

🚀 Quick Start

1. Basic Usage (Utility Functions)

import { getUserTierInfo, checkPremiumAccess } from '@umituz/react-native-premium';

// Determine tier from auth state and premium status
const tierInfo = getUserTierInfo(
  isGuest,      // boolean: is user a guest?
  userId,       // string | null: user ID (null for guests)
  isPremium     // boolean: does user have premium? (from your database)
);

// tierInfo: { tier: 'premium' | 'freemium' | 'guest', isPremium, isGuest, isAuthenticated, userId }

// Check premium access (guest users always return false)
const hasAccess = checkPremiumAccess(isGuest, userId, isPremium);

2. React Hook Usage (Recommended)

✅ Recommended: useUserTierWithRepository - Automatically fetches premium status

import { useUserTierWithRepository } from '@umituz/react-native-premium';
import { useAuth } from '@domains/auth'; // Your auth hook
import { premiumRepository } from '@/infrastructure/repositories/PremiumRepository'; // Your repository

function MyComponent() {
  const auth = useAuth();
  const { tier, isPremium, isGuest, isLoading, refresh } = useUserTierWithRepository({
    auth,
    repository: premiumRepository,
  });

  if (tier === 'guest') {
    return <GuestUpgradeCard />;
  }

  if (tier === 'freemium') {
    return <FreemiumLimits />;
  }

  return <PremiumFeatures />;
}

Alternative: useUserTier - Manual premium status fetching

import { useUserTier } from '@umituz/react-native-premium';
import { useAuth } from './useAuth'; // Your auth hook
import { usePremiumStatus } from './usePremiumStatus'; // Your premium status hook

function MyComponent() {
  const { user, isGuest } = useAuth();
  const { isPremium, isLoading, error } = usePremiumStatus(user?.uid);
  
  const { tier, isPremium: hasPremium, isGuest: isGuestUser } = useUserTier({
    isGuest,
    userId: user?.uid ?? null,
    isPremium: isPremium ?? false,
    isLoading,
    error,
  });

  if (tier === 'guest') {
    return <GuestUpgradeCard />;
  }

  if (tier === 'freemium') {
    return <FreemiumLimits />;
  }

  return <PremiumFeatures />;
}

3. Async Usage with Fetcher

import { getUserTierInfoAsync, getIsPremium } from '@umituz/react-native-premium';
import type { PremiumStatusFetcher } from '@umituz/react-native-premium';

// Define your premium status fetcher
const premiumStatusFetcher: PremiumStatusFetcher = {
  isPremium: async (userId: string) => {
    // Fetch from your database
    const userDoc = await getDoc(doc(db, 'users', userId));
    return userDoc.data()?.isPremium ?? false;
  },
};

// Get tier info asynchronously
const tierInfo = await getUserTierInfoAsync(
  isGuest,
  userId,
  premiumStatusFetcher
);

// Or just check premium status
const isPremium = await getIsPremium(isGuest, userId, premiumStatusFetcher);

📚 API Reference

Core Functions

getUserTierInfo(isGuest, userId, isPremium)

Determines user tier from auth state and premium status.

Parameters:

  • isGuest: boolean - Whether user is a guest
  • userId: string | null - User ID (null for guests)
  • isPremium: boolean - Whether user has active premium subscription

Returns: UserTierInfo

{
  tier: 'guest' | 'freemium' | 'premium';
  isPremium: boolean;
  isGuest: boolean;
  isAuthenticated: boolean;
  userId: string | null;
}

Examples:

// Guest user
getUserTierInfo(true, null, false);
// { tier: 'guest', isPremium: false, isGuest: true, isAuthenticated: false, userId: null }

// Premium user
getUserTierInfo(false, 'user123', true);
// { tier: 'premium', isPremium: true, isGuest: false, isAuthenticated: true, userId: 'user123' }

// Freemium user
getUserTierInfo(false, 'user123', false);
// { tier: 'freemium', isPremium: false, isGuest: false, isAuthenticated: true, userId: 'user123' }

checkPremiumAccess(isGuest, userId, isPremium)

Checks if user has premium access. Guest users NEVER have premium access.

Parameters:

  • isGuest: boolean - Whether user is a guest
  • userId: string | null - User ID (null for guests)
  • isPremium: boolean - Whether user has active premium subscription

Returns: boolean

Examples:

// Guest user - always false
checkPremiumAccess(true, null, true); // false

// Authenticated premium user
checkPremiumAccess(false, 'user123', true); // true

// Authenticated freemium user
checkPremiumAccess(false, 'user123', false); // false

isAuthenticated(isGuest, userId)

Checks if user is authenticated. Single source of truth for authentication check.

Parameters:

  • isGuest: boolean - Whether user is a guest
  • userId: string | null - User ID (null for guests)

Returns: boolean

isGuest(isGuest, userId)

Checks if user is a guest. Single source of truth for guest check.

Parameters:

  • isGuest: boolean - Whether user is a guest
  • userId: string | null - User ID (null for guests)

Returns: boolean

Type Guards

isValidUserTier(value)

Type guard to check if a value is a valid UserTier.

Parameters:

  • value: unknown - Value to check

Returns: value is UserTier

isUserTierInfo(value)

Type guard to check if an object is a valid UserTierInfo.

Parameters:

  • value: unknown - Value to check

Returns: value is UserTierInfo

Tier Comparison Utilities

hasTierAccess(tier1, tier2)

Compare two tiers to determine if first tier has higher or equal access than second.

Parameters:

  • tier1: UserTier - First tier to compare
  • tier2: UserTier - Second tier to compare

Returns: boolean

Tier hierarchy: guest < freemium < premium

isTierPremium(tier)

Check if tier is premium.

Parameters:

  • tier: UserTier - Tier to check

Returns: boolean

isTierFreemium(tier)

Check if tier is freemium.

Parameters:

  • tier: UserTier - Tier to check

Returns: boolean

isTierGuest(tier)

Check if tier is guest.

Parameters:

  • tier: UserTier - Tier to check

Returns: boolean

Async Functions

getIsPremium(isGuest, userId, isPremiumOrFetcher)

Get isPremium value with centralized logic. Guest users NEVER have premium.

Two usage modes:

  1. Sync mode - When you already have isPremium value:

    const isPremium = getIsPremium(false, 'user123', true); // boolean
  2. Async mode - When you need to fetch from database:

    const isPremium = await getIsPremium(
      false,
      'user123',
      { isPremium: async (userId) => await premiumService.isPremium(userId) }
    ); // Promise<boolean>

Parameters:

  • isGuest: boolean - Whether user is a guest
  • userId: string | null - User ID (null for guests)
  • isPremiumOrFetcher: boolean | PremiumStatusFetcher - Either boolean (sync) or fetcher (async)

Returns: boolean (sync) or Promise<boolean> (async)

getUserTierInfoAsync(isGuest, userId, fetcher)

Gets tier info asynchronously with fetcher.

Parameters:

  • isGuest: boolean - Whether user is a guest
  • userId: string | null - User ID (null for guests)
  • fetcher: PremiumStatusFetcher - Premium status fetcher interface

Returns: Promise<UserTierInfo>

checkPremiumAccessAsync(isGuest, userId, fetcher)

Checks premium access asynchronously with fetcher.

Parameters:

  • isGuest: boolean - Whether user is a guest
  • userId: string | null - User ID (null for guests)
  • fetcher: PremiumStatusFetcher - Premium status fetcher interface

Returns: Promise<boolean>

React Hook

useUserTier(params)

React hook for tier determination.

Parameters:

{
  isGuest: boolean;
  userId: string | null;
  isPremium: boolean; // App should fetch from database
  isLoading?: boolean; // Optional: loading state from app
  error?: string | null; // Optional: error state from app
}

Returns: UseUserTierResult (extends UserTierInfo with isLoading and error)

🔧 Integration Examples

Example 1: Firebase Firestore

import { getUserTierInfo, getUserTierInfoAsync } from '@umituz/react-native-premium';
import type { PremiumStatusFetcher } from '@umituz/react-native-premium';
import { doc, getDoc } from 'firebase/firestore';
import { db } from './firebase';

// Option 1: Sync version (if you already have isPremium)
async function checkUserTier(userId: string | null, isGuest: boolean) {
  if (isGuest || !userId) {
    return getUserTierInfo(true, null, false);
  }

  // Fetch from your database
  const userDoc = await getDoc(doc(db, 'users', userId));
  const isPremium = userDoc.data()?.isPremium ?? false;

  return getUserTierInfo(false, userId, isPremium);
}

// Option 2: Async version with fetcher
const premiumStatusFetcher: PremiumStatusFetcher = {
  isPremium: async (userId: string) => {
    const userDoc = await getDoc(doc(db, 'users', userId));
    return userDoc.data()?.isPremium ?? false;
  },
};

const tierInfo = await getUserTierInfoAsync(isGuest, userId, premiumStatusFetcher);

Example 2: Custom API

import { getUserTierInfoAsync } from '@umituz/react-native-premium';
import type { PremiumStatusFetcher } from '@umituz/react-native-premium';

const premiumStatusFetcher: PremiumStatusFetcher = {
  isPremium: async (userId: string) => {
    const response = await fetch(`/api/users/${userId}/premium`);
    const { isPremium } = await response.json();
    return isPremium;
  },
};

const tierInfo = await getUserTierInfoAsync(isGuest, userId, premiumStatusFetcher);

Example 3: React Component with Zustand Store

import { useUserTier } from '@umituz/react-native-premium';
import { useAuthStore } from './stores/authStore';
import { usePremiumStore } from './stores/premiumStore';

function MyComponent() {
  const { user, isGuest } = useAuthStore();
  const { isPremium, isLoading, error } = usePremiumStore();

  const { tier, isPremium: hasPremium, isGuest: isGuestUser } = useUserTier({
    isGuest,
    userId: user?.uid ?? null,
    isPremium: isPremium ?? false,
    isLoading,
    error,
  });

  if (tier === 'guest') {
    return <GuestUpgradeCard />;
  }

  if (tier === 'freemium') {
    return <FreemiumLimits />;
  }

  return <PremiumFeatures />;
}

🎯 Core Logic

The tier determination logic is simple and consistent:

// Guest users are ALWAYS freemium, NEVER premium
if (isGuest || !userId) {
  return { tier: 'guest', isPremium: false };
}

// Authenticated users: premium or freemium
return {
  tier: isPremium ? 'premium' : 'freemium',
  isPremium,
};

📝 Best Practices

  1. Always use this package for tier determination - Don't implement your own logic
  2. Fetch premium status in your app - This package doesn't handle database operations
  3. Pass loading/error states - Use the optional isLoading and error params in useUserTier
  4. Cache premium status - Use your state management (Zustand, Redux, etc.) to cache results
  5. Use fetcher pattern for async operations - Implement PremiumStatusFetcher interface

🔍 TypeScript Types

type UserTier = 'guest' | 'freemium' | 'premium';

interface UserTierInfo {
  tier: UserTier;
  isPremium: boolean;
  isGuest: boolean;
  isAuthenticated: boolean;
  userId: string | null;
}

interface PremiumStatusFetcher {
  isPremium(userId: string): Promise<boolean>;
}

interface UseUserTierParams {
  isGuest: boolean;
  userId: string | null;
  isPremium: boolean;
  isLoading?: boolean;
  error?: string | null;
}

interface UseUserTierResult extends UserTierInfo {
  isLoading: boolean;
  error: string | null;
}

🧪 Testing

All functions are pure and easy to test:

import { getUserTierInfo, checkPremiumAccess } from '@umituz/react-native-premium';

describe('getUserTierInfo', () => {
  it('should return guest tier for guest users', () => {
    const result = getUserTierInfo(true, null, false);
    expect(result.tier).toBe('guest');
    expect(result.isPremium).toBe(false);
  });

  it('should return premium tier for authenticated premium users', () => {
    const result = getUserTierInfo(false, 'user123', true);
    expect(result.tier).toBe('premium');
    expect(result.isPremium).toBe(true);
  });

  it('should return freemium tier for authenticated non-premium users', () => {
    const result = getUserTierInfo(false, 'user123', false);
    expect(result.tier).toBe('freemium');
    expect(result.isPremium).toBe(false);
  });
});

📄 License

MIT

🤝 Contributing

This package is designed to be used across 100+ apps. When making changes:

  1. Keep it simple - only tier logic, no database operations
  2. Maintain backward compatibility - don't break existing APIs
  3. Add tests - all functions should be tested
  4. Update documentation - keep README and examples up to date

🧪 Test Coverage

This package has 100% test coverage with comprehensive test suite:

  • ✅ 60+ test cases
  • ✅ 100% code coverage
  • ✅ Edge case handling
  • ✅ Input validation tests
  • ✅ Error handling tests

Run tests:

npm test
npm run test:coverage

🔄 Version History

1.4.0

  • No wrapper needed! - getIsPremium now supports both sync and async modes
  • Sync mode: getIsPremium(isGuest, userId, isPremium: boolean) - when you already have the value
  • Async mode: getIsPremium(isGuest, userId, fetcher: PremiumStatusFetcher) - when you need to fetch
  • ✅ Function overloads for type safety
  • ✅ Works directly from package - no app-specific wrapper required

1.3.0

  • 100% test coverage with comprehensive test suite
  • ✅ Input validation for all functions
  • ✅ Type guards (isValidUserTier, isUserTierInfo)
  • ✅ Enhanced error handling with detailed messages
  • ✅ Additional utility functions (hasTierAccess, isTierPremium, isTierFreemium, isTierGuest)
  • ✅ Professional test setup with Jest
  • ✅ Edge case handling (empty strings, special characters, etc.)

1.2.0

  • Improved documentation and examples
  • Better TypeScript types
  • Enhanced async fetcher pattern

1.1.1

  • Initial stable release
  • Core tier determination logic
  • React hook support
  • Async fetcher pattern