UNPKG

@hot-updater/react-native

Version:

React Native OTA solution for self-hosted

162 lines (152 loc) 5.23 kB
"use strict"; import React, { useEffect, useLayoutEffect, useState } from "react"; import { checkForUpdate } from "./checkForUpdate.js"; import { useEventCallback } from "./hooks/useEventCallback.js"; import { getBundleId, notifyAppReady as nativeNotifyAppReady, reload } from "./native.js"; import { useHotUpdaterStore } from "./store.js"; /** * Common options shared between auto and manual update modes */ /** * Configuration with baseURL for standard server-based updates */ /** * Configuration with resolver for custom network operations */ /** * Union type ensuring baseURL and resolver are mutually exclusive */ /** * Internal options after normalization in index.ts * Always has resolver (never baseURL) */ import { jsx as _jsx } from "react/jsx-runtime"; /** * Helper function to handle notifyAppReady flow */ const handleNotifyAppReady = async options => { try { // Always call native notifyAppReady for bundle promotion const nativeResult = nativeNotifyAppReady(); // If resolver.notifyAppReady exists, call it with simplified params if (options.resolver?.notifyAppReady) { await options.resolver.notifyAppReady({ status: nativeResult.status, crashedBundleId: nativeResult.crashedBundleId, requestHeaders: options.requestHeaders, requestTimeout: options.requestTimeout }).catch(e => { console.warn("[HotUpdater] Resolver notifyAppReady failed:", e); }); } options.onNotifyAppReady?.(nativeResult); } catch (e) { console.warn("[HotUpdater] Failed to notify app ready:", e); } }; export function wrap(options) { if (options.updateMode === "manual") { return WrappedComponent => { const ManualHOC = props => { useLayoutEffect(() => { void handleNotifyAppReady(options); }, []); return /*#__PURE__*/_jsx(WrappedComponent, { ...props }); }; return ManualHOC; }; } // updateMode: "auto" const { reloadOnForceUpdate = true, ...restOptions } = options; return WrappedComponent => { const HotUpdaterHOC = props => { const progress = useHotUpdaterStore(state => state.progress); const [message, setMessage] = useState(null); const [updateStatus, setUpdateStatus] = useState("CHECK_FOR_UPDATE"); const initHotUpdater = useEventCallback(async () => { try { setUpdateStatus("CHECK_FOR_UPDATE"); const updateInfo = await checkForUpdate({ resolver: restOptions.resolver, updateStrategy: restOptions.updateStrategy, requestHeaders: restOptions.requestHeaders, requestTimeout: restOptions.requestTimeout, onError: restOptions.onError }); setMessage(updateInfo?.message ?? null); if (!updateInfo) { restOptions.onUpdateProcessCompleted?.({ status: "UP_TO_DATE", shouldForceUpdate: false, message: null, id: getBundleId() }); setUpdateStatus("UPDATE_PROCESS_COMPLETED"); return; } if (updateInfo.shouldForceUpdate === false) { void updateInfo.updateBundle().catch(error => { restOptions.onError?.(error); }); restOptions.onUpdateProcessCompleted?.({ id: updateInfo.id, status: updateInfo.status, shouldForceUpdate: updateInfo.shouldForceUpdate, message: updateInfo.message }); setUpdateStatus("UPDATE_PROCESS_COMPLETED"); return; } // Force Update Scenario setUpdateStatus("UPDATING"); const isSuccess = await updateInfo.updateBundle(); if (!isSuccess) { throw new Error("New update was found but failed to download the bundle."); } if (reloadOnForceUpdate) { await reload(); } restOptions.onUpdateProcessCompleted?.({ id: updateInfo.id, status: updateInfo.status, shouldForceUpdate: updateInfo.shouldForceUpdate, message: updateInfo.message }); setUpdateStatus("UPDATE_PROCESS_COMPLETED"); } catch (error) { restOptions.onError?.(error); setUpdateStatus("UPDATE_PROCESS_COMPLETED"); } }); useEffect(() => { restOptions.onProgress?.(progress); }, [progress]); // Notify native side that app is ready (JS bundle fully loaded) useLayoutEffect(() => { void handleNotifyAppReady(restOptions); }, []); // Start update check useLayoutEffect(() => { initHotUpdater(); }, []); if (restOptions.fallbackComponent && updateStatus !== "UPDATE_PROCESS_COMPLETED") { const Fallback = restOptions.fallbackComponent; return /*#__PURE__*/_jsx(Fallback, { progress: progress, status: updateStatus, message: message }); } return /*#__PURE__*/_jsx(WrappedComponent, { ...props }); }; return HotUpdaterHOC; }; } //# sourceMappingURL=wrap.js.map