UNPKG

@markvivanco/app-version-checker

Version:

React App version checking and update prompts for React, React Native, and web applications

377 lines (286 loc) 9.5 kB
# app-version-checker Universal app version checking and update prompts for React, React Native, and web applications. ## Features - 🔄 **Semantic Version Comparison** - Full support for major.minor.patch.build versioning - 📱 **Multi-Platform Support** - Works with iOS, Android, and Web - 🏗️ **Framework Agnostic** - Core logic has zero dependencies - ⚛️ **React Integration** - Optional React hooks and context providers - 🔌 **Pluggable Architecture** - Bring your own data source and storage - 🎯 **Smart Timing** - Configurable check intervals and "remind me later" functionality - 🏪 **App Store Integration** - Generate App Store and Play Store URLs - 📦 **Tree-Shakeable** - Import only what you need - 📝 **TypeScript** - Full type definitions included ## Installation ```bash npm install app-version-checker # or yarn add app-version-checker # or pnpm add app-version-checker ``` ## Quick Start ### Basic Usage (Vanilla JavaScript) ```typescript import { VersionChecker } from 'app-version-checker'; import { LocalStorageProvider } from 'app-version-checker/stores'; // Create your data provider class MyDataProvider { getCurrentVersion() { return '1.0.0'; } async getLatestVersion(platform) { // Fetch from your API const response = await fetch(`/api/version/${platform}`); const data = await response.json(); return data.version; } getAppStoreConfig() { return { iosAppStoreId: '123456789', androidPackageName: 'com.example.app' }; } } // Initialize the checker const checker = new VersionChecker( new MyDataProvider(), new LocalStorageProvider(), { minCheckInterval: 60 * 60 * 1000, // 1 hour remindLaterDuration: 24 * 60 * 60 * 1000, // 24 hours } ); // Check for updates const result = await checker.shouldShowUpdatePrompt(); if (result.shouldShowPrompt) { // Show your update dialog console.log(`Update available: ${result.versionInfo.latestVersion}`); } ``` ### React Usage ```tsx import React from 'react'; import { VersionCheckProvider, useVersionCheck } from 'app-version-checker/react'; import { LocalStorageProvider } from 'app-version-checker/stores'; // Your update dialog component const UpdateDialog = ({ visible, versionInfo, onUpdateNow, onRemindLater }) => { if (!visible) return null; return ( <div className="update-dialog"> <h2>Update Available!</h2> <p>Version {versionInfo.latestVersion} is now available</p> <button onClick={onUpdateNow}>Update Now</button> <button onClick={onRemindLater}>Remind Me Later</button> </div> ); }; // App component function App() { return ( <VersionCheckProvider dataProvider={new MyDataProvider()} storageProvider={new LocalStorageProvider()} dialogComponent={UpdateDialog} > <YourApp /> </VersionCheckProvider> ); } // Using the hook in a component function YourComponent() { const { isUpdateAvailable, currentVersion, checkForUpdates } = useVersionCheck(); return ( <div> <p>Current version: {currentVersion}</p> {isUpdateAvailable && <p>An update is available!</p>} <button onClick={checkForUpdates}>Check for Updates</button> </div> ); } ``` ### React Native Usage ```tsx import React from 'react'; import { VersionCheckProvider, useAppStateVersionCheck } from 'app-version-checker/react'; import { AsyncStorageProvider } from 'app-version-checker/stores'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { AppState, Linking } from 'react-native'; // Create providers const storageProvider = new AsyncStorageProvider(AsyncStorage); function App() { const handleOpenStore = async (url) => { const supported = await Linking.canOpenURL(url); if (supported) { await Linking.openURL(url); } }; return ( <VersionCheckProvider dataProvider={new MyDataProvider()} storageProvider={storageProvider} onOpenStore={handleOpenStore} checkOnForeground={true} > <AppContent /> </VersionCheckProvider> ); } // Use app state checking function AppContent() { // Automatically check when app comes to foreground useAppStateVersionCheck(AppState, true); return <YourApp />; } ``` ## Provider Interfaces ### Data Provider Implement `IVersionDataProvider` to fetch version data from your source: ```typescript interface IVersionDataProvider { getCurrentVersion(): Promise<string> | string; getLatestVersion(platform: Platform): Promise<string | null>; getAppStoreConfig(): Promise<AppStoreConfig> | AppStoreConfig; // Optional methods getCurrentPlatform?(): Platform; getFormattedVersion?(): Promise<string> | string; isUpdateMandatory?(currentVersion: string, latestVersion: string): Promise<boolean> | boolean; getChangeLog?(version: string): Promise<string | null>; } ``` ### Storage Provider Implement `IStorageProvider` to store preferences: ```typescript interface IStorageProvider { getLastCheckTime(): Promise<number | null>; setLastCheckTime(timestamp: number): Promise<void>; getRemindLaterTime(): Promise<number | null>; setRemindLaterTime(timestamp: number): Promise<void>; clearRemindLaterTime(): Promise<void>; // Optional methods getDismissCount?(): Promise<number>; incrementDismissCount?(): Promise<void>; } ``` ## Built-in Providers ### Storage Providers - **LocalStorageProvider** - For web browsers - **AsyncStorageProvider** - For React Native - **InMemoryStorageProvider** - For testing ### Example Data Providers See the `examples/` folder for sample implementations: - REST API provider - GraphQL provider - Firebase provider - Supabase provider ## Core Utilities ### Version Comparison ```typescript import { compareVersions, isUpdateAvailable } from 'app-version-checker/core'; // Compare versions compareVersions('1.0.0', '1.0.1'); // Returns -1 compareVersions('2.0.0', '1.9.9'); // Returns 1 compareVersions('1.0.0', '1.0.0'); // Returns 0 // Check if update needed isUpdateAvailable('1.0.0', '1.0.1'); // Returns true ``` ### Version Formatting ```typescript import { formatVersionWithBuild, parseVersion } from 'app-version-checker/core'; // Format with build number formatVersionWithBuild('1.0.0', '123'); // Returns '1.0.0.123' // Parse version parseVersion('1.2.3.456'); // Returns { major: 1, minor: 2, patch: 3, build: 456 } ``` ### Store URLs ```typescript import { getStoreUrl } from 'app-version-checker/core'; const url = getStoreUrl('ios', { iosAppStoreId: '123456789' }); // Returns: https://apps.apple.com/app/id123456789 ``` ## React Hooks ### useVersionCheck Main hook for accessing version check context: ```typescript const { versionInfo, // Current version information isUpdateAvailable, // Boolean flag currentVersion, // Current app version formattedVersion, // Formatted version string showUpdateDialog, // Dialog visibility state isChecking, // Loading state error, // Any errors checkForUpdates, // Manual check function handleUpdateNow, // Open app store handleRemindLater, // Set reminder } = useVersionCheck(); ``` ### usePeriodicVersionCheck Check for updates at regular intervals: ```typescript usePeriodicVersionCheck( 60 * 60 * 1000, // Check every hour true // Enabled ); ``` ### useVisibilityVersionCheck Check when page becomes visible (web): ```typescript useVisibilityVersionCheck(true); ``` ## Configuration Options ```typescript const options = { // Minimum time between version checks (milliseconds) minCheckInterval: 60 * 60 * 1000, // Default: 1 hour // Duration for "remind me later" (milliseconds) remindLaterDuration: 24 * 60 * 60 * 1000, // Default: 24 hours // Skip version checking on web platform skipWebPlatform: true, // Default: true // Custom platform detection getPlatform: () => detectPlatform(), // Optional }; ``` ## Migration from Existing Code If you have existing version checking code, here's how to migrate: 1. **Extract your version fetching logic** into a data provider 2. **Choose or implement a storage provider** for preferences 3. **Replace your version checking logic** with VersionChecker 4. **Update your UI components** to use the provided hooks See `examples/migration/` for detailed migration guides. ## Examples Check the `examples/` directory for: - React web app example - React Native app example - Next.js integration - Vue.js integration - Firebase integration - Supabase integration - Custom provider examples ## Testing The package includes utilities for testing: ```typescript import { InMemoryStorageProvider } from 'app-version-checker/stores'; // Use in-memory storage for tests const testStorage = new InMemoryStorageProvider(); // Mock your data provider const mockDataProvider = { getCurrentVersion: () => '1.0.0', getLatestVersion: () => Promise.resolve('2.0.0'), // ... }; ``` ## API Reference Full API documentation is available at [docs/api.md](docs/api.md). ## Contributing Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details. ## License MIT © [Your Name] ## Changelog See [CHANGELOG.md](CHANGELOG.md) for version history. ## Support - 📧 Email: your-email@example.com - 💬 Discord: [Join our community](https://discord.gg/example) - 🐛 Issues: [GitHub Issues](https://github.com/yourusername/app-version-checker/issues)