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

react-native-reliability

v1.0.0

Published

A production-ready toolkit for React Native stability and observability

Readme

react-native-reliability

A lightweight, production-ready toolkit that improves stability and observability in React Native apps.


Why?

React Native apps fail silently in production for many common reasons:

| Problem | This toolkit | |---|---| | Unhandled async errors | safeAsync — wraps promises with timeout & error capture | | Component render crashes | ReliabilityErrorBoundary — safe fallback UI + structured logging | | Unstable network conditions | useNetworkHealth — detects offline / slow / unstable states | | Silent promise rejections | safeAsync — global error callback | | Background/foreground issues | useAppLifecycle — lifecycle state tracking | | Crash loops | useCrashRecovery — detects repeated crashes on startup |

Works with React Native CLI and Expo. Every module is fully independent — adopt only what you need.


Installation

# npm
npm install react-native-reliability

# yarn
yarn add react-native-reliability

Optional peer dependencies

Install these only for the modules you use:

# useNetworkHealth
npm install @react-native-community/netinfo

# useCrashRecovery (persistent storage across restarts)
npm install @react-native-async-storage/async-storage

Quick Start

import { ReliabilityProvider } from 'react-native-reliability';

export default function App() {
  return (
    <ReliabilityProvider>
      <MyApp />
    </ReliabilityProvider>
  );
}

Individual hooks and components work without the provider using sensible defaults.


Modules

1 — Error Boundary

Catches React render-tree crashes and renders a fallback UI.

import { ReliabilityErrorBoundary } from 'react-native-reliability';

<ReliabilityErrorBoundary
  fallback={<Text>Something went wrong. Please restart the app.</Text>}
  onError={(error, info) => {
    // send to crash analytics, record crash, etc.
    logError(error, info.componentStack);
  }}
>
  <App />
</ReliabilityErrorBoundary>

Props

| Prop | Type | Description | |---|---|---| | fallback | React.ReactNode | UI shown when the tree crashes. Renders null if omitted. | | onError | (error: Error, info: React.ErrorInfo) => void | Called when a render error is caught. | | children | React.ReactNode | The component tree to protect. |


2 — Network Health Monitor

Detects degraded connectivity without constant polling.

import { useNetworkHealth } from 'react-native-reliability';

const network = useNetworkHealth();

switch (network.status) {
  case 'offline':   /* show offline banner */ break;
  case 'slow':      /* show slow-network warning */ break;
  case 'unstable':  /* retry with backoff */ break;
  case 'healthy':   /* proceed normally */ break;
}

Requires @react-native-community/netinfo. Returns healthy (no-op) without it.

Returned object

| Field | Type | Description | |---|---|---| | status | 'healthy' \| 'slow' \| 'unstable' \| 'offline' | Overall network status | | isOffline | boolean | No internet connection | | isSlow | boolean | High latency detected | | isUnstable | boolean | Frequent disconnect/reconnect |


3 — Safe Async Wrapper

Prevents unhandled promise rejections and adds timeout protection.

import { safeAsync } from 'react-native-reliability';

safeAsync(
  () => fetchUser(userId),
  {
    timeout: 5000,
    onError: (error) => logError(error),
  }
)
  .then(handleUser)
  .catch(handleFetchError);

Options

| Option | Type | Default | Description | |---|---|---|---| | timeout | number | 10000 | Milliseconds before a TimeoutError is thrown | | onError | (error: Error) => void | — | Called for any error (including timeout) |


4 — App Lifecycle Monitor

Tracks application foreground / background / inactive state transitions.

import { useAppLifecycle } from 'react-native-reliability';

const lifecycle = useAppLifecycle();

useEffect(() => {
  if (lifecycle.state === 'background') {
    stopNetworkPolling();
    saveUserSession();
  }
  if (lifecycle.state === 'active') {
    resumeNetworkPolling();
  }
}, [lifecycle.state]);

Returned object

| Field | Type | Description | |---|---|---| | state | 'active' \| 'background' \| 'inactive' | Current lifecycle state |


5 — Crash Recovery Helper

Detects repeated crash loops on startup and lets you recover gracefully.

import { useCrashRecovery, ReliabilityErrorBoundary } from 'react-native-reliability';

function Root() {
  const crash = useCrashRecovery();

  if (crash.hasRecentCrash) {
    return (
      <SafeModeScreen
        crashCount={crash.crashCount}
        onReset={crash.clearCrashHistory}
      />
    );
  }

  return (
    <ReliabilityErrorBoundary onError={crash.recordCrash}>
      <App />
    </ReliabilityErrorBoundary>
  );
}

Requires @react-native-async-storage/async-storage for persistence across restarts.
Falls back to in-memory storage (resets on every restart) when not installed.

Returned object

| Field | Type | Description | |---|---|---| | hasRecentCrash | boolean | true when crashes ≥ crashThreshold within crashWindow | | crashCount | number | Number of crashes in the current window | | recordCrash | (error?: Error) => Promise<void> | Record a crash event | | clearCrashHistory | () => Promise<void> | Clear all stored crash data |


Provider Configuration

Override defaults globally with ReliabilityProvider:

<ReliabilityProvider
  config={{
    crashWindow: 120_000,          // 2 minute window (default: 60_000)
    crashThreshold: 3,             // crashes to trigger hasRecentCrash (default: 2)
    networkCheckUrl: 'https://api.myapp.com/health',
    slowNetworkThreshold: 3000,    // ms (default: 2000)
    unstableNetworkThreshold: 5,   // disconnects/min (default: 3)
  }}
>
  <App />
</ReliabilityProvider>

All hooks also accept these values from context automatically when wrapped in the provider.


Full Production Example

import React from 'react';
import {
  ReliabilityProvider,
  ReliabilityErrorBoundary,
  useNetworkHealth,
  useAppLifecycle,
  useCrashRecovery,
  safeAsync,
} from 'react-native-reliability';

function AppShell() {
  const network = useNetworkHealth();
  const lifecycle = useAppLifecycle();
  const crash = useCrashRecovery();

  // Show safe mode if crash loop detected
  if (crash.hasRecentCrash) {
    return <SafeModeScreen onReset={crash.clearCrashHistory} />;
  }

  return (
    <ReliabilityErrorBoundary
      onError={crash.recordCrash}
      fallback={<ErrorScreen />}
    >
      {network.isOffline && <OfflineBanner />}
      {lifecycle.state === 'active' && <MainApp />}
    </ReliabilityErrorBoundary>
  );
}

export default function App() {
  return (
    <ReliabilityProvider config={{ crashThreshold: 3 }}>
      <AppShell />
    </ReliabilityProvider>
  );
}

Design Philosophy

Stability, safety, and predictability — not analytics dashboards.

  • Never crashes the host app — all handlers are wrapped in try/catch
  • Minimal dependencies — peer deps are optional; modules work independently
  • No polling — event-driven where possible; ping on demand
  • Strict TypeScript — no any, full type coverage
  • Works in dev and production — same API, no build flags

Architecture

src/
  core/
    reliabilityProvider.tsx     ← shared config context (optional)
  modules/
    errorBoundary/
      ReliabilityErrorBoundary.tsx
    networkHealth/
      useNetworkHealth.ts
    safeAsync/
      safeAsync.ts
    lifecycle/
      useAppLifecycle.ts
    crashRecovery/
      useCrashRecovery.ts
  hooks/
    useNetworkHealth.ts         ← re-exports
    useAppLifecycle.ts
  types/
    reliabilityTypes.ts
  index.ts

License

MIT