@hot-updater/react-native
Version:
React Native OTA solution for self-hosted
176 lines • 6.22 kB
TypeScript
import React from "react";
import type { HotUpdaterError } from "./error";
import { type NotifyAppReadyResult } from "./native";
import type { HotUpdaterResolver } from "./types";
export interface RunUpdateProcessResponse {
status: "ROLLBACK" | "UPDATE" | "UP_TO_DATE";
shouldForceUpdate: boolean;
message: string | null;
id: string;
}
type UpdateStatus = "CHECK_FOR_UPDATE" | "UPDATING" | "UPDATE_PROCESS_COMPLETED";
/**
* Common options shared between auto and manual update modes
*/
interface CommonHotUpdaterOptions {
/**
* Custom request headers for update checks
*/
requestHeaders?: Record<string, string>;
/**
* Request timeout in milliseconds
* @default 5000
*/
requestTimeout?: number;
/**
* Callback invoked when the app is ready and bundle verification completes.
* Provides information about bundle promotion, recovery from crashes, or stable state.
*
* @param result - Bundle state information
* @param result.status - Current bundle state:
* - "PROMOTED": Staging bundle was promoted to stable (new update applied)
* - "RECOVERED": App recovered from a crash, rollback occurred
* - "STABLE": No changes, bundle is stable
* @param result.crashedBundleId - Present only when status is "RECOVERED"
*
* @example
* ```tsx
* HotUpdater.wrap({
* baseURL: "https://api.example.com",
* updateMode: "manual",
* onNotifyAppReady: ({ status, crashedBundleId }) => {
* if (status === "RECOVERED") {
* analytics.track('bundle_rollback', { crashedBundleId });
* } else if (status === "PROMOTED") {
* analytics.track('bundle_promoted');
* }
* }
* })(App);
* ```
*/
onNotifyAppReady?: (result: NotifyAppReadyResult) => void;
}
/**
* Configuration with baseURL for standard server-based updates
*/
interface BaseURLConfig {
/**
* Base URL for update server
* @example "https://update.example.com"
*/
baseURL: string;
/**
* Resolver is not allowed when using baseURL
*/
resolver?: never;
}
/**
* Configuration with resolver for custom network operations
*/
interface ResolverConfig {
/**
* Custom resolver for network operations
*/
resolver: HotUpdaterResolver;
/**
* baseURL is not allowed when using resolver
*/
baseURL?: never;
}
/**
* Union type ensuring baseURL and resolver are mutually exclusive
*/
type NetworkConfig = BaseURLConfig | ResolverConfig;
export type AutoUpdateOptions = CommonHotUpdaterOptions & NetworkConfig & {
/**
* Update strategy
* - "fingerprint": Use fingerprint hash to check for updates
* - "appVersion": Use app version to check for updates
*/
updateStrategy: "fingerprint" | "appVersion";
/**
* Update mode
* - "auto": Automatically check and download updates
*/
updateMode: "auto";
onError?: (error: HotUpdaterError | Error | unknown) => void;
/**
* Component to show while downloading a new bundle update.
*
* When an update exists and the bundle is being downloaded, this component will block access
* to the entry point and show download progress.
*
* @see {@link https://hot-updater.dev/docs/react-native-api/wrap#fallback-component}
*
* ```tsx
* HotUpdater.wrap({
* baseURL: "<update-server-url>",
* updateStrategy: "appVersion",
* fallbackComponent: ({ progress = 0 }) => (
* <View style={styles.container}>
* <Text style={styles.text}>Updating... {progress}%</Text>
* </View>
* )
* })(App)
* ```
*
* If not defined, the bundle will download in the background without blocking the screen.
*/
fallbackComponent?: React.FC<{
status: Exclude<UpdateStatus, "UPDATE_PROCESS_COMPLETED">;
progress: number;
message: string | null;
}>;
onProgress?: (progress: number) => void;
/**
* When a force update exists, the app will automatically reload.
* If `false`, When a force update exists, the app will not reload. `shouldForceUpdate` will be returned as `true` in `onUpdateProcessCompleted`.
* If `true`, When a force update exists, the app will automatically reload.
* @default true
*/
reloadOnForceUpdate?: boolean;
/**
* Callback function that is called when the update process is completed.
*
* @see {@link https://hot-updater.dev/docs/react-native-api/wrap#onupdateprocesscompleted}
*/
onUpdateProcessCompleted?: (response: RunUpdateProcessResponse) => void;
};
export type ManualUpdateOptions = CommonHotUpdaterOptions & NetworkConfig & {
/**
* Update mode
* - "manual": Only notify app ready, user manually calls checkForUpdate()
*/
updateMode: "manual";
};
export type HotUpdaterOptions = AutoUpdateOptions | ManualUpdateOptions;
/**
* Internal options after normalization in index.ts
* Always has resolver (never baseURL)
*/
type InternalCommonOptions = {
resolver: HotUpdaterResolver;
requestHeaders?: Record<string, string>;
requestTimeout?: number;
onNotifyAppReady?: (result: NotifyAppReadyResult) => void;
};
type InternalAutoUpdateOptions = InternalCommonOptions & {
updateStrategy: "fingerprint" | "appVersion";
updateMode: "auto";
onError?: (error: HotUpdaterError | Error | unknown) => void;
fallbackComponent?: React.FC<{
status: Exclude<UpdateStatus, "UPDATE_PROCESS_COMPLETED">;
progress: number;
message: string | null;
}>;
onProgress?: (progress: number) => void;
reloadOnForceUpdate?: boolean;
onUpdateProcessCompleted?: (response: RunUpdateProcessResponse) => void;
};
type InternalManualUpdateOptions = InternalCommonOptions & {
updateMode: "manual";
};
export type InternalWrapOptions = InternalAutoUpdateOptions | InternalManualUpdateOptions;
export declare function wrap<P extends React.JSX.IntrinsicAttributes = object>(options: InternalWrapOptions): (WrappedComponent: React.ComponentType<P>) => React.ComponentType<P>;
export {};
//# sourceMappingURL=wrap.d.ts.map