npm package: @forced-expo-update/expo-update
Description: Global Expo Updates provider + hook
Latest version: 0.0.2

# @forced-expo-update/expo-update

A tiny, zero-config Provider for **Expo Updates** that checks for updates as soon as the app opens and applies them automatically.

The goal is simple:

- Wrap your app once with a Provider
- The library will check/fetch updates on app start
- If there is an update, it will reload the app (configurable)

It also includes optional conveniences:

- Reload immediately or wait for user inactivity ("idle")
- Require a screen-level gate hook to be mounted before an update reload can happen

## Install

```bash
npm i @forced-expo-update/expo-update@update
```

This library requires these peer dependencies in your app:

- `expo-updates`
- `react`
- `react-native`

## Usage (zero config)

Add `ExpoUpdatesProvider` at the root of your app. That’s it.

```tsx
import { ExpoUpdatesProvider } from "@forced-expo-update/expo-update";

export function App() {
  return <ExpoUpdatesProvider>{/* your app */}</ExpoUpdatesProvider>;
}
```

### What happens by default

- The provider waits a small initial delay (a few seconds)
- It checks if an update is available
- If available, it fetches the update
- If a new update was downloaded, it reloads the app

This helps avoid the "update only applies on the next open" feeling.

## Enable/Disable globally

You can disable the entire behavior without removing the Provider:

```tsx
<ExpoUpdatesProvider enabled={false}>{children}</ExpoUpdatesProvider>
```

## Options

You can pass optional `options` to tune behavior.

```tsx
import { ExpoUpdatesProvider } from "@forced-expo-update/expo-update";

export function App() {
  return (
    <ExpoUpdatesProvider
      options={{
        checkIntervalMinutes: 30,
        checkOnAppStateChange: true,
        reloadImmediately: true,
        delayBeforeReloadMs: 3000,
        maxRetries: 2,
        fetchTimeoutMs: 30000,
      }}
    >
      {children}
    </ExpoUpdatesProvider>
  );
}
```

### Callbacks

```tsx
<ExpoUpdatesProvider
  options={{
    onUpdateAvailable: () => {
      // update exists on server
    },
    onUpdateDownloaded: () => {
      // update has been downloaded
    },
    onError: (error) => {
      // after max retries
      console.log(error);
    },
  }}
>
  {children}
</ExpoUpdatesProvider>
```

## Reload strategy: immediate vs idle

Sometimes you don’t want to reload while the user is actively interacting with the app.

This library supports two reload strategies:

- `"immediate"` (default): reloads as soon as an update is downloaded (after `delayBeforeReloadMs`)
- `"whenIdle"`: waits for a period of inactivity before reloading

### Idle reload

```tsx
<ExpoUpdatesProvider
  options={{
    reloadStrategy: "whenIdle",
    idleReloadAfterMs: 2 * 60 * 1000,
  }}
>
  {children}
</ExpoUpdatesProvider>
```

Important:

- Even with `"whenIdle"`, the provider still checks/fetches updates on app start
- Only the **reload** is delayed until the idle timer completes

## Screen gate (only reload if a specific screen is mounted)

In some apps you only want to apply updates when the user is on a safe screen (for example, a home screen), not in the middle of a checkout.

Enable gate mode:

```tsx
<ExpoUpdatesProvider
  options={{
    gateMode: "requireGate",
  }}
>
  {children}
</ExpoUpdatesProvider>
```

Then, in the screen(s) where it is safe to reload, mount the gate hook:

```tsx
import { useExpoUpdatesGate } from "@forced-expo-update/expo-update";

export function HomeScreen() {
  useExpoUpdatesGate();

  return null;
}
```

How it works:

- If `gateMode` is `"none"` (default), updates can reload anytime
- If `gateMode` is `"requireGate"`, the Provider will only trigger reload while at least one gate is mounted

## Manual check

If you want to manually trigger a check (for example from a settings screen):

```tsx
import { useExpoUpdates } from "@forced-expo-update/expo-update";

export function Settings() {
  const { checkForUpdates } = useExpoUpdates();

  const onPress = async () => {
    await checkForUpdates();
  };

  return null;
}
```

## Notes

- This library does nothing in development mode (`__DEV__`) to avoid disrupting your dev workflow.
- Actual update availability depends on your `expo-updates` configuration (release channels, runtime version, etc.).

## API

### `ExpoUpdatesProvider`

Props:

- `enabled?: boolean` (default `true`)
- `options?: ExpoUpdatesOptions`

### `ExpoUpdatesOptions`

- `checkIntervalMinutes?: number`
- `checkOnAppStateChange?: boolean`
- `reloadImmediately?: boolean`
- `fetchTimeoutMs?: number`
- `maxRetries?: number`
- `delayBeforeReloadMs?: number`
- `reloadStrategy?: "immediate" | "whenIdle"`
- `idleReloadAfterMs?: number`
- `gateMode?: "none" | "requireGate"`
- `onUpdateAvailable?: () => void`
- `onUpdateDownloaded?: () => void`
- `onError?: (error: Error) => void`

### Hooks

- `useExpoUpdates()`
- `useExpoUpdatesGate()`

## License

MIT