npm package: @punk_rock_malchik/react-native-sdk
Description: React Native SDK for OTA Update System - Over-the-air updates for React Native applications
Author: Kostya Valkov
Latest version: 1.0.1

# @punk_rock_malchik/react-native-sdk

React Native SDK для системы OTA обновлений. Позволяет обновлять JavaScript bundle и ресурсы React Native приложения без перепубликации через App Store/Google Play.

[![npm version](https://badge.fury.io/js/%40punk_rock_malchik%2Freact-native-sdk.svg)](https://www.npmjs.com/package/@punk_rock_malchik/react-native-sdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Установка

```bash
npm install @punk_rock_malchik/react-native-sdk @react-native-async-storage/async-storage
```

### Дополнительные зависимости

### Для работы с файловой системой (выберите один вариант)

**Вариант 1: react-native-fs (рекомендуется для bare React Native)**

```bash
npm install react-native-fs
# Для iOS
cd ios && pod install
```

**Вариант 2: expo-file-system (только для Expo проектов)**

```bash
npm install expo-file-system
```

### Для вычисления SHA256 checksum (выберите один вариант)

**Вариант 1: react-native-crypto (рекомендуется)**

```bash
npm install react-native-crypto
# Для iOS
cd ios && pod install
```

**Вариант 2: crypto-js (легковесная альтернатива)**

```bash
npm install crypto-js
npm install --save-dev @types/crypto-js
```

**Вариант 3: expo-crypto (только для Expo проектов)**

```bash
npm install expo-crypto
```

## Быстрый старт

### Базовое использование

```typescript
import { OTAUpdate } from "@punk_rock_malchik/react-native-sdk";
import { Platform } from "react-native";
import Constants from "expo-constants";

// Инициализация SDK
const ota = new OTAUpdate(
    {
        apiBaseUrl: "http://localhost:3000/api",
        currentVersion: "1.0.0", // Текущая версия bundle
        appVersion: Constants.expoConfig?.version || "1.0.0", // Версия нативного приложения
        platform: Platform.OS === "ios" ? "ios" : "android",
        environment: __DEV__ ? "dev" : "production",
        deviceId: "unique-device-id", // Опционально, для rollout логики
    },
    {
        onCheckComplete: (response) => {
            if (response.available) {
                console.log("Доступно обновление:", response.update?.version);
            }
        },
        onDownloadProgress: (progress) => {
            console.log(`Загрузка: ${Math.round(progress.progress * 100)}%`);
        },
        onInstallComplete: (version) => {
            console.log("Обновление установлено:", version);
            // Перезагрузить приложение для применения обновления
        },
        onError: (error) => {
            console.error("Ошибка OTA:", error);
        },
    }
);

// Проверка и установка обновлений
await ota.checkAndInstall();
```

### Пример интеграции в React компонент

```typescript
import React, { useEffect, useState } from "react";
import { View, Text, Button, ActivityIndicator } from "react-native";
import { OTAUpdate } from "@punk_rock_malchik/react-native-sdk";

const App: React.FC = () => {
    const [updateStatus, setUpdateStatus] = useState<
        "checking" | "downloading" | "installing" | "idle"
    >("idle");
    const [progress, setProgress] = useState(0);
    const [updateInfo, setUpdateInfo] = useState(null);

    useEffect(() => {
        checkForUpdates();
    }, []);

    const checkForUpdates = async () => {
        try {
            setUpdateStatus("checking");

            const ota = new OTAUpdate(
                {
                    apiBaseUrl: "http://your-api-url/api",
                    currentVersion: "1.0.0",
                    appVersion: "1.0.0",
                    platform: "ios",
                    environment: "production",
                },
                {
                    onDownloadProgress: (p) => {
                        setProgress(p.progress);
                        setUpdateStatus("downloading");
                    },
                    onInstallStart: () => {
                        setUpdateStatus("installing");
                    },
                    onInstallComplete: (version) => {
                        setUpdateStatus("idle");
                        alert(
                            `Обновление ${version} установлено! Перезапустите приложение.`
                        );
                    },
                }
            );

            await ota.checkAndInstall();
        } catch (error) {
            console.error("Ошибка обновления:", error);
            setUpdateStatus("idle");
        }
    };

    return (
        <View>
            {updateStatus === "checking" && <ActivityIndicator />}
            {updateStatus === "downloading" && (
                <View>
                    <Text>
                        Загрузка обновления: {Math.round(progress * 100)}%
                    </Text>
                    <ActivityIndicator />
                </View>
            )}
            {updateStatus === "installing" && (
                <Text>Установка обновления...</Text>
            )}
            <Button title="Проверить обновления" onPress={checkForUpdates} />
        </View>
    );
};

export default App;
```

## API

### Класс OTAUpdate

Главный класс для управления обновлениями.

#### Конструктор

```typescript
new OTAUpdate(config: OTAConfig, callbacks?: OTACallbacks)
```

#### Методы

##### `checkAndInstall(): Promise<CheckUpdateResponse>`

Полный цикл: проверка → скачивание → установка.

```typescript
const response = await ota.checkAndInstall();
if (response.available) {
    console.log("Обновление установлено");
}
```

##### `checkOnly(): Promise<CheckUpdateResponse>`

Только проверка обновлений без скачивания.

```typescript
const response = await ota.checkOnly();
if (response.available) {
    console.log("Доступно обновление:", response.update?.version);
}
```

##### `downloadAndInstall(update: UpdateInfo): Promise<void>`

Скачивание и установка конкретного обновления.

##### `getCurrentVersion(): Promise<string | null>`

Получает текущую установленную версию.

##### `rollback(): Promise<string | null>`

Откатывает к предыдущей версии.

### Конфигурация (OTAConfig)

```typescript
interface OTAConfig {
    apiBaseUrl: string; // URL API (например: http://localhost:3000/api)
    currentVersion: string; // Текущая версия bundle
    appVersion: string; // Версия нативного приложения
    platform: "ios" | "android"; // Платформа
    environment: "dev" | "staging" | "production"; // Окружение
    deployment?: string; // Deployment name (опционально)
    deviceId?: string; // Device ID для rollout (опционально)
    timeout?: number; // Таймаут запросов (мс, по умолчанию 10000)
    maxRetries?: number; // Максимум попыток скачивания (по умолчанию 3)
}
```

### Callbacks (OTACallbacks)

```typescript
interface OTACallbacks {
    onCheckStart?: () => void;
    onCheckComplete?: (response: CheckUpdateResponse) => void;
    onCheckError?: (error: Error) => void;

    onDownloadStart?: () => void;
    onDownloadProgress?: (progress: DownloadProgress) => void;
    onDownloadComplete?: (filePath: string) => void;
    onDownloadError?: (error: Error) => void;

    onInstallStart?: () => void;
    onInstallComplete?: (version: string) => void;
    onInstallError?: (error: Error) => void;
}
```

## Структура SDK

```
react-native-sdk/
├── src/
│   ├── classes/
│   │   ├── OTAUpdate.ts          # Главный класс
│   │   ├── UpdateChecker.ts      # Проверка обновлений
│   │   ├── BundleDownloader.ts   # Скачивание bundle
│   │   ├── BundleInstaller.ts    # Установка bundle
│   │   └── StatisticsReporter.ts # Статистика
│   ├── types/
│   │   └── index.ts              # TypeScript типы
│   ├── utils/
│   │   ├── http.util.ts          # HTTP утилиты
│   │   └── checksum.util.ts      # Проверка checksum
│   └── index.ts                  # Главный экспорт
├── package.json
└── tsconfig.json
```

## Особенности

-   ✅ Проверка обновлений с кэшированием
-   ✅ Скачивание bundle файлов с прогрессом
-   ✅ Проверка checksum (SHA256)
-   ✅ Автоматическая установка обновлений
-   ✅ Откат к предыдущей версии при ошибках
-   ✅ Отправка статистики на сервер
-   ✅ Retry логика для скачивания
-   ✅ TypeScript поддержка
-   ✅ Event listeners для отслеживания процесса

## Примеры использования

### Только проверка обновлений

```typescript
const ota = new OTAUpdate(config);
const response = await ota.checkOnly();

if (response.available && response.update) {
    // Показать диалог пользователю
    const shouldUpdate = await showUpdateDialog(response.update);

    if (shouldUpdate) {
        await ota.downloadAndInstall(response.update);
    }
}
```

### Кастомная логика скачивания

```typescript
const checker = new UpdateChecker(config);
const response = await checker.checkForUpdates();

if (response.available && response.update) {
    const downloader = new BundleDownloader();
    const bundlePath = await downloader.download(
        response.update,
        (progress) => {
            console.log(`${progress.progress * 100}%`);
        }
    );

    // Своя логика установки
    // ...
}
```

### Откат при ошибке

```typescript
try {
    await ota.checkAndInstall();
} catch (error) {
    console.error("Ошибка обновления:", error);

    // Автоматический откат уже выполнен
    // Но можно и вручную:
    const previousVersion = await ota.rollback();
    console.log("Откат к версии:", previousVersion);
}
```

## Требования

-   React Native >= 0.70.0
-   TypeScript (рекомендуется)
-   Одна из библиотек для файловой системы:
    -   `react-native-fs` (рекомендуется для bare React Native)
    -   `expo-file-system` (для Expo проектов)
-   Одна из библиотек для криптографии:
    -   `react-native-crypto` (рекомендуется)
    -   `crypto-js` (легковесная альтернатива)
    -   `expo-crypto` (для Expo проектов)

## Troubleshooting

### Ошибка "No crypto library available"

Установите одну из библиотек для криптографии:

```bash
npm install react-native-crypto
# или
npm install crypto-js
```

### Ошибка "Neither react-native-fs nor expo-file-system is available"

Установите библиотеку для работы с файловой системой:

```bash
npm install react-native-fs
# Для iOS
cd ios && pod install
```

### Ошибка "AsyncStorage not found"

Установите:

```bash
npm install @react-native-async-storage/async-storage
```

### Bundle не применяется после установки

Убедитесь, что:

1. Bundle файл скачан и проверен checksum
2. Приложение перезапущено после установки
3. Настроена загрузка bundle из правильной директории

## Лицензия

MIT