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 🙏

© 2026 – Pkg Stats / Ryan Hefner

expo-in-app-update-enterprise

v1.0.1

Published

Enterprise-grade in-app update module for Expo and React Native. Wraps Google Play In-App Updates API with policy engine, audit logging, and banking-grade security features.

Downloads

305

Readme

expo-in-app-update

npm version license platforms Expo TypeScript

Enterprise-grade in-app update module for Expo & React Native. Wraps Google Play's In-App Updates API (Android) and iTunes Lookup API (iOS) with a powerful policy engine, audit logging, and banking-grade security features.


✨ Features

| Feature | Description | |---|---| | Google Play In-App Updates | Full support for FLEXIBLE and IMMEDIATE update flows on Android | | iOS Version Checking | Automatic version comparison via iTunes Lookup API | | Policy Engine | Declarative rules — minimum version, priority threshold, staleness, max dismissals | | Audit Logger | Structured compliance events for banking / regulated industries | | UpdateProvider | React Context provider with periodic re-checking | | UpdateBanner | Animated, themeable slide-in banner for flexible updates | | ForceUpdateScreen | Full-screen blocking overlay for critical updates | | Fully Themeable | Every UI component accepts a theme object | | Accessible | WCAG-compliant — roles, labels, live regions | | TypeScript | Strict types, comprehensive JSDoc, zero any | | Testable | Built-in MockConfig for development & testing | | Expo + Bare RN | Works with Expo managed/bare and plain React Native |


📦 Installation

# Using npm
npm install expo-in-app-update-enterprise

# Using yarn
yarn add expo-in-app-update-enterprise

# Using Expo CLI
npx expo install expo-in-app-update-enterprise

Note: If you're using a bare React Native project, run npx pod-install after installation.


🚀 Quick Start

1. Wrap your app with UpdateProvider

import { UpdateProvider } from 'expo-in-app-update-enterprise';

export default function App() {
  return (
    <UpdateProvider
      policy={{
        minimumVersion: 10,
        maxDismissals: 3,
        maxStaleDaysBeforeForce: 14,
      }}
      autoCheck
      checkInterval={3_600_000} // Re-check every hour
    >
      <MyApp />
    </UpdateProvider>
  );
}

2. Use the hook anywhere in your tree

import { useUpdateContext } from 'expo-in-app-update-enterprise';

function HomeScreen() {
  const {
    updateInfo,
    isChecking,
    policyResult,
    checkForUpdate,
    startUpdate,
  } = useUpdateContext();

  if (policyResult?.isForced) {
    return <ForceUpdateScreen />;
  }

  return (
    <View>
      <Text>Current: {updateInfo?.currentVersionName}</Text>
      <Button title="Check for Update" onPress={checkForUpdate} />
    </View>
  );
}

3. Add UI components

import {
  UpdateProvider,
  UpdateBanner,
  ForceUpdateScreen,
  useUpdateContext,
} from 'expo-in-app-update-enterprise';

function AppShell() {
  const { policyResult } = useUpdateContext();

  if (policyResult?.isForced) {
    return <ForceUpdateScreen />;
  }

  return (
    <>
      <MainNavigator />
      <UpdateBanner position="bottom" />
    </>
  );
}

export default function App() {
  return (
    <UpdateProvider policy={myPolicy} autoCheck>
      <AppShell />
    </UpdateProvider>
  );
}

📖 API Reference

useInAppUpdate(options?)

React hook for controlling updates imperatively.

import { useInAppUpdate } from 'expo-in-app-update-enterprise';

Options — UseInAppUpdateOptions

| Prop | Type | Default | Description | |---|---|---|---| | policy | UpdatePolicy | — | Policy engine configuration | | autoCheck | boolean | true | Auto-check on mount | | auditConfig | AuditLoggerConfig | — | Audit logger settings | | onUpdateAvailable | (info) => void | — | Callback when update is found | | onUpdateAccepted | (info) => void | — | Callback on acceptance | | onUpdateDismissed | (info) => void | — | Callback on dismissal | | onUpdateFailed | (error, info?) => void | — | Callback on failure | | onUpdateCompleted | () => void | — | Callback on completion | | onDownloadProgress | (progress) => void | — | Callback for progress events |

Returns — UseInAppUpdateResult

| Property | Type | Description | |---|---|---| | updateInfo | UpdateInfo \| null | Available update information | | downloadProgress | DownloadProgress \| null | Current download progress | | isChecking | boolean | Whether a check is in progress | | isDownloading | boolean | Whether a download is in progress | | isReadyToInstall | boolean | Whether a download completed | | error | Error \| null | Last error | | policyResult | PolicyEvaluationResult \| null | Policy engine result | | checkForUpdate() | () => Promise<UpdateInfo> | Check for updates | | startUpdate(type?) | (type?) => Promise<UpdateResult> | Start an update flow | | completeUpdate() | () => Promise<void> | Install a downloaded update | | dismissUpdate() | () => void | Dismiss the current prompt |


<UpdateProvider>

React Context provider that manages update state for the entire component tree.

import { UpdateProvider } from 'expo-in-app-update-enterprise';

Props — UpdateProviderProps

| Prop | Type | Default | Description | |---|---|---|---| | policy | UpdatePolicy | — | Policy engine configuration | | auditConfig | AuditLoggerConfig | — | Audit logger settings | | autoCheck | boolean | true | Check on mount | | checkInterval | number | 0 | Re-check interval in ms (0 = off) | | onAuditEvent | (event) => void | — | Callback for audit events | | children | ReactNode | — | Child components |


<UpdateBanner>

Animated slide-in banner for flexible update prompts.

import { UpdateBanner } from 'expo-in-app-update-enterprise';

Props — UpdateBannerProps

| Prop | Type | Default | Description | |---|---|---|---| | theme | UpdateUITheme | — | Theme overrides | | title | string | Auto | Custom title | | body | string | Auto | Custom body | | updateButtonText | string | "Update" | Update button label | | dismissButtonText | string | "Later" | Dismiss button label | | restartButtonText | string | "Restart" | Restart button label | | showProgress | boolean | true | Show progress bar | | position | 'top' \| 'bottom' | 'bottom' | Banner position | | icon | ReactNode | — | Custom icon/logo | | accessibilityLabel | string | Auto | A11y label override |


<ForceUpdateScreen>

Full-screen blocking overlay for mandatory updates.

import { ForceUpdateScreen } from 'expo-in-app-update-enterprise';

Props — ForceUpdateScreenProps

| Prop | Type | Default | Description | |---|---|---|---| | theme | UpdateUITheme | — | Theme overrides | | logo | ReactNode | Shield icon | Custom logo | | title | string | "Update Required" | Title text | | body | string | Default message | Body text | | updateButtonText | string | "Update Now" | CTA label | | secondaryMessage | string | Version info | Secondary message | | accessibilityLabel | string | Auto | A11y label override |


PolicyEngine

Evaluates declarative rules against update info to decide the update flow.

import { PolicyEngine } from 'expo-in-app-update-enterprise';

const engine = new PolicyEngine({
  minimumVersion: 15,
  recommendedVersion: 20,
  maxStaleDaysBeforeForce: 14,
  maxDismissals: 3,
  priorityThresholdForForce: 4,
  forceUpdateMessage: 'Critical security update required.',
});

const result = engine.evaluate(updateInfo, dismissCount);

if (result.isForced) {
  // Show ForceUpdateScreen
} else if (result.shouldUpdate) {
  // Show UpdateBanner
}

UpdatePolicy Configuration

| Property | Type | Description | |---|---|---| | minimumVersion | number | Force IMMEDIATE if below this version code | | recommendedVersion | number | Suggest FLEXIBLE if below this version code | | maxStaleDaysBeforeForce | number | Force after N days of availability | | maxDismissals | number | Force after N user dismissals | | priorityThresholdForForce | number | Force if priority ≥ threshold (0-5) | | forceUpdateMessage | string | Custom message for forced updates | | recommendedUpdateMessage | string | Custom message for flexible updates | | allowBackgroundUsage | boolean | Allow app use during flex download |

PolicyEvaluationResult

| Property | Type | Description | |---|---|---| | shouldUpdate | boolean | Whether an update action is needed | | resolvedUpdateType | UpdateType \| null | FLEXIBLE or IMMEDIATE | | triggeredRule | string | Which rule triggered ('minimumVersion', etc.) | | reason | string | Human-readable explanation | | isForced | boolean | Whether this is a forced/non-dismissible update | | message | string? | Message to display |


AuditLogger

Structured compliance logging for update lifecycle events.

import { AuditLogger } from 'expo-in-app-update-enterprise';

const logger = new AuditLogger({
  enabled: true,
  transport: async (event) => {
    await fetch('https://compliance.bank.com/audit', {
      method: 'POST',
      body: JSON.stringify(event),
    });
  },
  consoleLog: __DEV__,
  persistLocally: true,
  maxLocalEvents: 1000,
});

AuditEventType Enum

| Value | Description | |---|---| | UPDATE_CHECK | Check initiated | | UPDATE_AVAILABLE | Update found | | UPDATE_NOT_AVAILABLE | No update found | | UPDATE_STARTED | Update flow started | | UPDATE_ACCEPTED | User accepted | | UPDATE_DISMISSED | User dismissed | | UPDATE_DOWNLOADED | Download completed | | UPDATE_INSTALLED | Install completed | | UPDATE_FAILED | Update failed | | POLICY_EVALUATED | Policy engine ran | | FORCED_UPDATE_TRIGGERED | Forced update triggered | | UPDATE_COMPLETED | Restart triggered | | ERROR | Error occurred |


🏦 Banking App Configuration

For regulated environments that require strict update enforcement and compliance logging:

import {
  UpdateProvider,
  UpdateBanner,
  ForceUpdateScreen,
  useUpdateContext,
} from 'expo-in-app-update-enterprise';

const BANKING_POLICY = {
  // Force update if below version code 25 (security baseline)
  minimumVersion: 25,
  // Recommend update if below version code 30
  recommendedVersion: 30,
  // Force update if available for 7+ days
  maxStaleDaysBeforeForce: 7,
  // Force after 2 dismissals
  maxDismissals: 2,
  // Force if priority >= 4 (high/critical)
  priorityThresholdForForce: 4,
  // Custom compliance messages
  forceUpdateMessage:
    'This update contains critical security patches required by our ' +
    'banking regulations. You must update to continue.',
  recommendedUpdateMessage:
    'A new version is available with enhanced security features ' +
    'and performance improvements.',
};

const AUDIT_CONFIG = {
  enabled: true,
  transport: async (event) => {
    await complianceAPI.logEvent(event);
  },
  persistLocally: true,
  maxLocalEvents: 2000,
  globalMetadata: {
    appId: 'com.bank.mobile',
    region: 'US',
    regulatoryFramework: 'PCI-DSS',
  },
};

function BankingApp() {
  return (
    <UpdateProvider
      policy={BANKING_POLICY}
      auditConfig={AUDIT_CONFIG}
      autoCheck
      checkInterval={1_800_000} // Check every 30 minutes
      onAuditEvent={(event) => {
        analytics.track('app_update_event', event);
      }}
    >
      <AppShell />
    </UpdateProvider>
  );
}

function AppShell() {
  const { policyResult } = useUpdateContext();

  if (policyResult?.isForced) {
    return (
      <ForceUpdateScreen
        theme={{
          primaryColor: '#003366',
          backgroundColor: '#001428',
        }}
      />
    );
  }

  return (
    <>
      <MainNavigator />
      <UpdateBanner
        position="bottom"
        theme={{
          primaryColor: '#003366',
          backgroundColor: 'rgba(0, 20, 40, 0.95)',
        }}
      />
    </>
  );
}

🎨 Theming

All UI components accept an UpdateUITheme object:

interface UpdateUITheme {
  primaryColor?: string;       // Brand color (buttons, progress)
  backgroundColor?: string;    // Card / screen background
  textColor?: string;          // Primary text
  secondaryTextColor?: string; // Subtitle / secondary text
  buttonTextColor?: string;    // Button label color
  progressBarColor?: string;   // Progress bar fill
  progressBarTrackColor?: string; // Progress bar track
  borderRadius?: number;       // Corner radius
  fontFamily?: string;         // Body font family
  headingFontFamily?: string;  // Heading font family
}

📋 Type Definitions

All types are exported from the package root:

import type {
  UpdateType,
  UpdateAvailability,
  InstallStatus,
  UpdateInfo,
  DownloadProgress,
  UpdateResult,
  UpdatePolicy,
  PolicyEvaluationResult,
  AuditEvent,
  AuditEventType,
  AuditLoggerConfig,
  UpdateUITheme,
  UpdateBannerProps,
  ForceUpdateScreenProps,
  UpdateProviderProps,
  UseInAppUpdateOptions,
  UseInAppUpdateResult,
  MockConfig,
} from 'expo-in-app-update-enterprise';

See src/ExpoInAppUpdate.types.ts for full JSDoc documentation on every type.


🧪 Testing

Use MockConfig for development and testing without the Play Store:

import { MockInAppUpdate } from 'expo-in-app-update-enterprise/testing';

const mock = new MockInAppUpdate({
  updateAvailable: true,
  availableVersionCode: 5,
  availableVersionName: '2.0.0',
  updatePriority: 3,
  stalenessDays: 5,
  downloadDurationMs: 3000,
  simulateFailure: false,
  simulateCancellation: false,
});

// In your test setup:
jest.mock('expo-in-app-update-enterprise/ExpoInAppUpdateModule', () => mock);

Testing Policy Engine

import { PolicyEngine } from 'expo-in-app-update-enterprise';

describe('PolicyEngine', () => {
  it('forces update when below minimum version', () => {
    const engine = new PolicyEngine({ minimumVersion: 10 });
    const result = engine.evaluate(
      { ...mockUpdateInfo, currentVersionCode: 5 },
      0,
    );

    expect(result.isForced).toBe(true);
    expect(result.resolvedUpdateType).toBe(UpdateType.IMMEDIATE);
    expect(result.triggeredRule).toBe('minimumVersion');
  });

  it('suggests flexible update for recommended version', () => {
    const engine = new PolicyEngine({ recommendedVersion: 20 });
    const result = engine.evaluate(
      { ...mockUpdateInfo, currentVersionCode: 15 },
      0,
    );

    expect(result.shouldUpdate).toBe(true);
    expect(result.resolvedUpdateType).toBe(UpdateType.FLEXIBLE);
    expect(result.isForced).toBe(false);
  });
});

📱 Platform Support

| Feature | Android | iOS | |---|:---:|:---:| | Flexible updates | ✅ Native | ⚠️ Store redirect | | Immediate updates | ✅ Native | ⚠️ Store redirect | | Download progress | ✅ Real-time | ❌ N/A | | Version checking | ✅ Play Store | ✅ iTunes API | | Update priority | ✅ 0-5 scale | ❌ Always 0 | | Staleness days | ✅ Native | ❌ N/A | | In-app install | ✅ Native | ❌ Store only | | Policy engine | ✅ Full | ✅ Full | | Audit logging | ✅ Full | ✅ Full | | BackHandler block | ✅ Native | — N/A |


🤝 Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'feat: add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Setup

# Clone the repo
git clone https://github.com/lewisirimu/expo-in-app-update.git
cd expo-in-app-update-enterprise

# Install dependencies
yarn install

# Build
yarn build

# Run tests
yarn test

# Lint
yarn lint

Commit Convention

This project uses Conventional Commits:

  • feat: — New feature
  • fix: — Bug fix
  • docs: — Documentation only
  • refactor: — Code refactor (no feature/fix)
  • test: — Tests only
  • chore: — Build/tooling changes

📄 License

MIT © Munene

See LICENSE for details.