react-native-bspatch 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +471 -0
  3. package/android/build.gradle +100 -0
  4. package/android/src/main/AndroidManifest.xml +3 -0
  5. package/android/src/main/java/vn/reactnativebspatch/BsPatchModule.kt +139 -0
  6. package/android/src/main/java/vn/reactnativebspatch/BsPatchPackage.kt +16 -0
  7. package/android/src/main/java/vn/reactnativebspatch/OtaBundleResolver.kt +227 -0
  8. package/cpp/CMakeLists.txt +43 -0
  9. package/cpp/bsdiff/bspatch.c +194 -0
  10. package/cpp/bsdiff/bspatch.h +41 -0
  11. package/cpp/bsdiff/bspatch_wrapper.c +150 -0
  12. package/cpp/bsdiff/bspatch_wrapper.h +6 -0
  13. package/cpp/bspatch_jni.cpp +41 -0
  14. package/cpp/bzip2/LICENSE +42 -0
  15. package/cpp/bzip2/blocksort.c +1094 -0
  16. package/cpp/bzip2/bzlib.c +1572 -0
  17. package/cpp/bzip2/bzlib.h +282 -0
  18. package/cpp/bzip2/bzlib_private.h +509 -0
  19. package/cpp/bzip2/compress.c +672 -0
  20. package/cpp/bzip2/crctable.c +104 -0
  21. package/cpp/bzip2/decompress.c +652 -0
  22. package/cpp/bzip2/huffman.c +205 -0
  23. package/cpp/bzip2/randtable.c +84 -0
  24. package/ios/OtaBundleResolver.swift +241 -0
  25. package/ios/RNBsPatch.h +8 -0
  26. package/ios/RNBsPatch.mm +198 -0
  27. package/lib/commonjs/NativeBsPatch.js +9 -0
  28. package/lib/commonjs/NativeBsPatch.js.map +1 -0
  29. package/lib/commonjs/crypto-js.d.js +2 -0
  30. package/lib/commonjs/crypto-js.d.js.map +1 -0
  31. package/lib/commonjs/index.js +90 -0
  32. package/lib/commonjs/index.js.map +1 -0
  33. package/lib/commonjs/ota/OtaProvider.js +306 -0
  34. package/lib/commonjs/ota/OtaProvider.js.map +1 -0
  35. package/lib/commonjs/ota/otaAssetResolver.js +145 -0
  36. package/lib/commonjs/ota/otaAssetResolver.js.map +1 -0
  37. package/lib/commonjs/ota/otaCore.js +736 -0
  38. package/lib/commonjs/ota/otaCore.js.map +1 -0
  39. package/lib/commonjs/ota/otaLogger.js +64 -0
  40. package/lib/commonjs/ota/otaLogger.js.map +1 -0
  41. package/lib/commonjs/ota/otaMetadata.js +138 -0
  42. package/lib/commonjs/ota/otaMetadata.js.map +1 -0
  43. package/lib/commonjs/ota/storage/CustomStorage.js +140 -0
  44. package/lib/commonjs/ota/storage/CustomStorage.js.map +1 -0
  45. package/lib/commonjs/ota/storage/GitHubReleaseStorage.js +96 -0
  46. package/lib/commonjs/ota/storage/GitHubReleaseStorage.js.map +1 -0
  47. package/lib/commonjs/ota/types.js +39 -0
  48. package/lib/commonjs/ota/types.js.map +1 -0
  49. package/lib/commonjs/package.json +1 -0
  50. package/lib/module/NativeBsPatch.js +5 -0
  51. package/lib/module/NativeBsPatch.js.map +1 -0
  52. package/lib/module/crypto-js.d.js +2 -0
  53. package/lib/module/crypto-js.d.js.map +1 -0
  54. package/lib/module/index.js +23 -0
  55. package/lib/module/index.js.map +1 -0
  56. package/lib/module/ota/OtaProvider.js +299 -0
  57. package/lib/module/ota/OtaProvider.js.map +1 -0
  58. package/lib/module/ota/otaAssetResolver.js +138 -0
  59. package/lib/module/ota/otaAssetResolver.js.map +1 -0
  60. package/lib/module/ota/otaCore.js +725 -0
  61. package/lib/module/ota/otaCore.js.map +1 -0
  62. package/lib/module/ota/otaLogger.js +59 -0
  63. package/lib/module/ota/otaLogger.js.map +1 -0
  64. package/lib/module/ota/otaMetadata.js +127 -0
  65. package/lib/module/ota/otaMetadata.js.map +1 -0
  66. package/lib/module/ota/storage/CustomStorage.js +134 -0
  67. package/lib/module/ota/storage/CustomStorage.js.map +1 -0
  68. package/lib/module/ota/storage/GitHubReleaseStorage.js +90 -0
  69. package/lib/module/ota/storage/GitHubReleaseStorage.js.map +1 -0
  70. package/lib/module/ota/types.js +38 -0
  71. package/lib/module/ota/types.js.map +1 -0
  72. package/lib/typescript/NativeBsPatch.d.ts +39 -0
  73. package/lib/typescript/NativeBsPatch.d.ts.map +1 -0
  74. package/lib/typescript/index.d.ts +15 -0
  75. package/lib/typescript/index.d.ts.map +1 -0
  76. package/lib/typescript/ota/OtaProvider.d.ts +10 -0
  77. package/lib/typescript/ota/OtaProvider.d.ts.map +1 -0
  78. package/lib/typescript/ota/otaAssetResolver.d.ts +15 -0
  79. package/lib/typescript/ota/otaAssetResolver.d.ts.map +1 -0
  80. package/lib/typescript/ota/otaCore.d.ts +109 -0
  81. package/lib/typescript/ota/otaCore.d.ts.map +1 -0
  82. package/lib/typescript/ota/otaLogger.d.ts +44 -0
  83. package/lib/typescript/ota/otaLogger.d.ts.map +1 -0
  84. package/lib/typescript/ota/otaMetadata.d.ts +46 -0
  85. package/lib/typescript/ota/otaMetadata.d.ts.map +1 -0
  86. package/lib/typescript/ota/storage/CustomStorage.d.ts +12 -0
  87. package/lib/typescript/ota/storage/CustomStorage.d.ts.map +1 -0
  88. package/lib/typescript/ota/storage/GitHubReleaseStorage.d.ts +20 -0
  89. package/lib/typescript/ota/storage/GitHubReleaseStorage.d.ts.map +1 -0
  90. package/lib/typescript/ota/types.d.ts +191 -0
  91. package/lib/typescript/ota/types.d.ts.map +1 -0
  92. package/package.json +89 -0
  93. package/react-native-bspatch.podspec +46 -0
  94. package/src/NativeBsPatch.ts +52 -0
  95. package/src/crypto-js.d.ts +1 -0
  96. package/src/index.ts +29 -0
  97. package/src/ota/OtaProvider.tsx +399 -0
  98. package/src/ota/otaAssetResolver.ts +182 -0
  99. package/src/ota/otaCore.ts +963 -0
  100. package/src/ota/otaLogger.ts +72 -0
  101. package/src/ota/otaMetadata.ts +149 -0
  102. package/src/ota/storage/CustomStorage.ts +143 -0
  103. package/src/ota/storage/GitHubReleaseStorage.ts +98 -0
  104. package/src/ota/types.ts +211 -0
  105. package/tools/bsdiff +0 -0
  106. package/tools/bsdiff.c +445 -0
  107. package/tools/bsdiff.h +45 -0
  108. package/tools/build_ota.sh +457 -0
  109. package/tools/setup_project.js +273 -0
  110. package/tools/update_registry.js +145 -0
  111. package/tools/upload_ota_custom.sh +138 -0
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+
3
+ import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
4
+ import { ActivityIndicator, AppState, Platform, StyleSheet, Text, View } from 'react-native';
5
+ import ReactNativeBlobUtil from 'react-native-blob-util';
6
+ import NativeBsPatch from '../NativeBsPatch';
7
+ import { initOtaAssetResolver } from './otaAssetResolver';
8
+ import { applyOtaPatchInternal, fetchOtaManifest } from './otaCore';
9
+ import { createOtaLogger, OtaEvent } from './otaLogger';
10
+ import { loadMetadata, markHealthy } from './otaMetadata';
11
+ import { OtaStatus, OtaUpdateMode } from './types';
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ const OtaContext = /*#__PURE__*/createContext(undefined);
14
+ export function OtaProvider({
15
+ children,
16
+ config,
17
+ loadingView,
18
+ useLoadingView = true
19
+ }) {
20
+ const [status, setStatus] = useState(OtaStatus.IDLE);
21
+ const [message, setMessage] = useState('Initializing...');
22
+ const [progress, setProgress] = useState(0);
23
+ const [currentVersion, setCurrentVersion] = useState(config.baseAppVersion);
24
+ const [latestVersion, setLatestVersion] = useState(config.baseAppVersion);
25
+ const [pendingCount, setPendingCount] = useState(0);
26
+ const [isChecking, setIsChecking] = useState(false);
27
+ const [metrics, setMetrics] = useState(null);
28
+ const [patches, setPatches] = useState([]);
29
+ const [isInitialized, setIsInitialized] = useState(false);
30
+ const appState = useRef(AppState.currentState);
31
+ const isCheckingRef = useRef(false);
32
+ const bootstrapDone = useRef(false);
33
+
34
+ /**
35
+ * Core apply update logic — separated so it can be mapped to button clicks
36
+ * OR called automatically by checkUpdates()
37
+ */
38
+ const executeApplyUpdate = useCallback(async (patchList, currentVer, targetVer) => {
39
+ console.log('[OtaProvider] executeApplyUpdate | targetV:', targetVer, 'currentV:', currentVer);
40
+ const directPatch = patchList.find(p => p.fromVersion === currentVer && p.toVersion === targetVer && p.platform === Platform.OS);
41
+ if (!directPatch) {
42
+ console.warn('[OtaProvider] No direct patch found for', currentVer, '->', targetVer);
43
+ setStatus(OtaStatus.ERROR);
44
+ setMessage('No direct upgrade path found.');
45
+ return;
46
+ }
47
+ try {
48
+ setStatus(OtaStatus.DOWNLOADING);
49
+ setProgress(0);
50
+ await applyOtaPatchInternal(directPatch, config, (s, msg, m) => {
51
+ setMessage(msg);
52
+ setStatus(s);
53
+ if (m) {
54
+ setMetrics(m);
55
+ // Initialize asset resolver for the new version immediately
56
+ initOtaAssetResolver(targetVer);
57
+ }
58
+ }, percent => {
59
+ setProgress(percent);
60
+ });
61
+ } catch (error) {
62
+ console.error('[OtaProvider] Update error:', error);
63
+ setStatus(OtaStatus.ERROR);
64
+ setMessage(`Update failed: ${error.message}`);
65
+ }
66
+ }, [config]);
67
+
68
+ /**
69
+ * Exposed method for manual trigger
70
+ */
71
+ const applyUpdate = useCallback(async () => {
72
+ await executeApplyUpdate(patches, currentVersion, latestVersion);
73
+ }, [executeApplyUpdate, patches, currentVersion, latestVersion]);
74
+
75
+ /**
76
+ * Check for updates from the manifest.
77
+ * Uses a ref to guard against concurrent calls (avoids stale closure).
78
+ */
79
+ const checkUpdates = useCallback(async () => {
80
+ if (isCheckingRef.current) return;
81
+ isCheckingRef.current = true;
82
+ setIsChecking(true);
83
+ setStatus(OtaStatus.CHECKING);
84
+ setMessage('Checking for updates...');
85
+ const log = createOtaLogger(config.onEvent);
86
+ log.emit(OtaEvent.CHECK_UPDATE);
87
+ try {
88
+ const remotePatches = await fetchOtaManifest(config);
89
+ const metadata = await loadMetadata(config.baseAppVersion);
90
+ const localV = metadata.currentVersion;
91
+ console.log('[OtaProvider] checkUpdates | localV:', localV, 'remotePatches count:', remotePatches.length);
92
+ const platformPatches = remotePatches.filter(p => p.platform === Platform.OS);
93
+ console.log('[OtaProvider] platformPatches count:', platformPatches.length);
94
+ const maxV = platformPatches.length > 0 ? Math.max(...platformPatches.map(p => p.toVersion)) : localV;
95
+ console.log('[OtaProvider] latestV determined:', maxV);
96
+ setPatches(platformPatches);
97
+ setCurrentVersion(localV);
98
+ setLatestVersion(maxV);
99
+ if (maxV > localV) {
100
+ setPendingCount(1);
101
+ setMessage(`Update available: V${localV} → V${maxV}`);
102
+ setStatus(OtaStatus.UPDATE_AVAILABLE);
103
+
104
+ // Trigger behaviors based on mode
105
+ if (config.updateMode === OtaUpdateMode.BACKGROUND_DOWNLOAD) {
106
+ downloadBackgroundUpdate(platformPatches, localV, maxV);
107
+ } else if (config.updateMode === OtaUpdateMode.ON_APP_START || config.updateMode === OtaUpdateMode.ON_APP_FOREGROUND) {
108
+ // Auto-apply immediately!
109
+ await executeApplyUpdate(platformPatches, localV, maxV);
110
+ }
111
+ } else {
112
+ setPendingCount(0);
113
+ setMessage(`All systems nominal (V${localV})`);
114
+ setStatus(OtaStatus.UP_TO_DATE);
115
+ }
116
+ } catch (error) {
117
+ setMessage(`Check failed: ${error.message}`);
118
+ setStatus(OtaStatus.ERROR);
119
+ } finally {
120
+ isCheckingRef.current = false;
121
+ setIsChecking(false);
122
+ }
123
+ }, [config, executeApplyUpdate]);
124
+ const downloadBackgroundUpdate = async (patchList, localV, targetV) => {
125
+ const directPatch = patchList.find(p => p.fromVersion === localV && p.toVersion === targetV);
126
+ if (!directPatch) return;
127
+ console.warn('[OtaProvider] BACKGROUND_DOWNLOAD mode is not yet implemented. ' + 'Patches were found but no download occurred. ' + 'Use MANUAL or ON_APP_START mode for now.');
128
+ };
129
+
130
+ /**
131
+ * Bootstrap: runs once on mount.
132
+ *
133
+ * Lifecycle:
134
+ * 1. Load metadata
135
+ * 2. Check if previous launch failed → rollback if needed
136
+ * 3. Mark current launch as "pending verification" (lastLaunchSuccessful=false)
137
+ * 4. App renders → markAsHealthy() sets it back to true
138
+ * 5. If crash before markAsHealthy → next boot sees false → rollback
139
+ * 6. Check for updates based on updateMode
140
+ */
141
+ useEffect(() => {
142
+ const bootstrap = async () => {
143
+ // Clean up any pending trash directories from previous resets (non-blocking)
144
+ ReactNativeBlobUtil.fs.ls(ReactNativeBlobUtil.fs.dirs.DocumentDir).then(dirs => {
145
+ for (const dir of dirs) {
146
+ if (dir.startsWith('ota_trash_')) {
147
+ ReactNativeBlobUtil.fs.unlink(`${ReactNativeBlobUtil.fs.dirs.DocumentDir}/${dir}`).catch(() => {});
148
+ }
149
+ }
150
+ }).catch(() => {});
151
+ const metadata = await loadMetadata(config.baseAppVersion);
152
+
153
+ // Display current version immediately
154
+ setCurrentVersion(metadata.currentVersion);
155
+
156
+ // Initialize asset resolver with current version (if not base)
157
+ if (metadata.currentVersion > config.baseAppVersion) {
158
+ await initOtaAssetResolver(metadata.currentVersion);
159
+ }
160
+
161
+ // (Native layer handled crash detection and any necessary rollback)
162
+ // We just mark bootstrap as done
163
+ bootstrapDone.current = true;
164
+
165
+ // Always mark as healthy after a successful JS bootstrap.
166
+ //
167
+ // The native OtaBundleResolver uses its own baseVersion (DEFAULT_BASE_VERSION=1),
168
+ // independent of the JS-side config.baseAppVersion. It marks
169
+ // lastLaunchSuccessful=false before loading ANY OTA bundle (even when
170
+ // JS baseAppVersion has been bumped to match currentVersion). If we only
171
+ // call markAsHealthy when currentVersion > JS baseAppVersion, we miss this
172
+ // case and the native layer will rollback on the very next cold boot.
173
+ //
174
+ // markAsHealthy() is safe to call unconditionally — it's a no-op when
175
+ // the metadata already has lastLaunchSuccessful=true.
176
+ console.log(`[OtaProvider] Marking V${metadata.currentVersion} as healthy`);
177
+ await markAsHealthy();
178
+
179
+ // Mode-based auto-check
180
+ const mode = config.updateMode ?? OtaUpdateMode.MANUAL;
181
+ if (mode === OtaUpdateMode.ON_APP_START || mode === OtaUpdateMode.BACKGROUND_DOWNLOAD) {
182
+ checkUpdates();
183
+ } else {
184
+ setMessage(`Ready (V${metadata.currentVersion})`);
185
+ setStatus(OtaStatus.UP_TO_DATE);
186
+ }
187
+ };
188
+ bootstrap().then(() => setIsInitialized(true)).catch(() => {
189
+ // Bootstrap failed: keep UI blocked so user sees the error state.
190
+ // setIsInitialized stays false → isBlocking remains true → the error
191
+ // message is shown via loadingView instead of a silent blank screen.
192
+ });
193
+ // eslint-disable-next-line react-hooks/exhaustive-deps
194
+ }, []);
195
+
196
+ /**
197
+ * AppState listener for ON_APP_FOREGROUND mode
198
+ */
199
+ useEffect(() => {
200
+ const subscription = AppState.addEventListener('change', nextAppState => {
201
+ if (appState.current.match(/inactive|background/) && nextAppState === 'active' && bootstrapDone.current) {
202
+ const mode = config.updateMode ?? OtaUpdateMode.MANUAL;
203
+ if (mode === OtaUpdateMode.ON_APP_FOREGROUND) {
204
+ checkUpdates();
205
+ }
206
+ }
207
+ appState.current = nextAppState;
208
+ });
209
+ return () => {
210
+ subscription.remove();
211
+ };
212
+ }, [config.updateMode, checkUpdates]);
213
+ const markAsHealthy = async () => {
214
+ const log = createOtaLogger(config.onEvent);
215
+ log.emit(OtaEvent.MARK_HEALTHY);
216
+ await markHealthy(config.baseAppVersion);
217
+ NativeBsPatch.markAsHealthy();
218
+ };
219
+ const resetToFactory = async () => {
220
+ const log = createOtaLogger(config.onEvent);
221
+ try {
222
+ setStatus(OtaStatus.APPLYING);
223
+ setMessage('Executing system wipe...');
224
+ log.emit(OtaEvent.RESET_FACTORY);
225
+ const otaDir = `${ReactNativeBlobUtil.fs.dirs.DocumentDir}/ota`;
226
+ if (await ReactNativeBlobUtil.fs.exists(otaDir)) {
227
+ // Fast atomic rename to prevent blocking the JS thread during deletion of potentially 1000s of files
228
+ const trashDir = `${ReactNativeBlobUtil.fs.dirs.DocumentDir}/ota_trash_${Date.now()}`;
229
+ await ReactNativeBlobUtil.fs.mv(otaDir, trashDir);
230
+ // Deletion is deferred to the next app bootstrap to prevent blocking the bridge before reload
231
+ }
232
+ setMessage('Reset complete. Core reload initiated...');
233
+ NativeBsPatch.reloadBundle();
234
+ } catch (error) {
235
+ setStatus(OtaStatus.ERROR);
236
+ setMessage(`Reset failed: ${error.message}`);
237
+ }
238
+ };
239
+ const value = {
240
+ status,
241
+ message,
242
+ progress,
243
+ currentVersion,
244
+ latestVersion,
245
+ pendingCount,
246
+ isChecking,
247
+ metrics,
248
+ applyUpdate,
249
+ resetToFactory,
250
+ markAsHealthy,
251
+ checkUpdate: checkUpdates
252
+ };
253
+
254
+ // Logic to determine if we should block the UI
255
+ const isBlocking = useMemo(() => {
256
+ return useLoadingView && (!isInitialized || config.updateMode === OtaUpdateMode.ON_APP_START && (status === OtaStatus.IDLE || status === OtaStatus.CHECKING || status === OtaStatus.DOWNLOADING || status === OtaStatus.APPLYING || status === OtaStatus.UPDATE_AVAILABLE));
257
+ }, [useLoadingView, isInitialized, config.updateMode, status]);
258
+ return /*#__PURE__*/_jsx(OtaContext.Provider, {
259
+ value: value,
260
+ children: !isBlocking ? children : loadingView !== undefined ? loadingView : /*#__PURE__*/_jsxs(View, {
261
+ style: styles.loadingContainer,
262
+ children: [/*#__PURE__*/_jsx(ActivityIndicator, {
263
+ size: "large",
264
+ color: "#FF00F5"
265
+ }), /*#__PURE__*/_jsx(Text, {
266
+ style: styles.loadingText,
267
+ children: message
268
+ }), status === OtaStatus.DOWNLOADING || status === OtaStatus.APPLYING ? /*#__PURE__*/_jsxs(Text, {
269
+ style: styles.progressText,
270
+ children: [progress.toFixed(1), "%"]
271
+ }) : null]
272
+ })
273
+ });
274
+ }
275
+ export function useOta() {
276
+ const context = useContext(OtaContext);
277
+ if (context === undefined) {
278
+ throw new Error('useOta must be used within an OtaProvider');
279
+ }
280
+ return context;
281
+ }
282
+ const styles = StyleSheet.create({
283
+ loadingContainer: {
284
+ flex: 1,
285
+ justifyContent: 'center',
286
+ alignItems: 'center',
287
+ backgroundColor: '#000'
288
+ },
289
+ loadingText: {
290
+ marginTop: 20,
291
+ color: '#00FFCC',
292
+ fontSize: 16
293
+ },
294
+ progressText: {
295
+ marginTop: 10,
296
+ color: '#fff'
297
+ }
298
+ });
299
+ //# sourceMappingURL=OtaProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["React","createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","ActivityIndicator","AppState","Platform","StyleSheet","Text","View","ReactNativeBlobUtil","NativeBsPatch","initOtaAssetResolver","applyOtaPatchInternal","fetchOtaManifest","createOtaLogger","OtaEvent","loadMetadata","markHealthy","OtaStatus","OtaUpdateMode","jsx","_jsx","jsxs","_jsxs","OtaContext","undefined","OtaProvider","children","config","loadingView","useLoadingView","status","setStatus","IDLE","message","setMessage","progress","setProgress","currentVersion","setCurrentVersion","baseAppVersion","latestVersion","setLatestVersion","pendingCount","setPendingCount","isChecking","setIsChecking","metrics","setMetrics","patches","setPatches","isInitialized","setIsInitialized","appState","currentState","isCheckingRef","bootstrapDone","executeApplyUpdate","patchList","currentVer","targetVer","console","log","directPatch","find","p","fromVersion","toVersion","platform","OS","warn","ERROR","DOWNLOADING","s","msg","m","percent","error","applyUpdate","checkUpdates","current","CHECKING","onEvent","emit","CHECK_UPDATE","remotePatches","metadata","localV","length","platformPatches","filter","maxV","Math","max","map","UPDATE_AVAILABLE","updateMode","BACKGROUND_DOWNLOAD","downloadBackgroundUpdate","ON_APP_START","ON_APP_FOREGROUND","UP_TO_DATE","targetV","bootstrap","fs","ls","dirs","DocumentDir","then","dir","startsWith","unlink","catch","markAsHealthy","mode","MANUAL","subscription","addEventListener","nextAppState","match","remove","MARK_HEALTHY","resetToFactory","APPLYING","RESET_FACTORY","otaDir","exists","trashDir","Date","now","mv","reloadBundle","value","checkUpdate","isBlocking","Provider","style","styles","loadingContainer","size","color","loadingText","progressText","toFixed","useOta","context","Error","create","flex","justifyContent","alignItems","backgroundColor","marginTop","fontSize"],"sourceRoot":"../../../src","sources":["ota/OtaProvider.tsx"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+
3
+ import { Image, Platform } from 'react-native';
4
+ import ReactNativeBlobUtil from 'react-native-blob-util';
5
+ import NativeBsPatch from '../NativeBsPatch';
6
+ const ASSET_STORE_DIR = `${ReactNativeBlobUtil.fs.dirs.DocumentDir}/ota/assets`;
7
+ let assetManifest = null;
8
+ let assetMap = new Map();
9
+ let assetList = [];
10
+ let isPatched = false;
11
+
12
+ /**
13
+ * Internal logger with native bridge integration.
14
+ */
15
+ const log = msg => {
16
+ const formatted = `[otaAssetResolver] ${msg}`;
17
+ console.log(formatted);
18
+ if (NativeBsPatch?.logNative) {
19
+ NativeBsPatch.logNative(formatted);
20
+ }
21
+ };
22
+
23
+ /**
24
+ * Initializes the OTA asset resolver for a specific version.
25
+ * Loads the asset manifest and prepares an O(1) lookup map for intercepted image requests.
26
+ *
27
+ * @param version - The OTA version number to load assets from.
28
+ */
29
+ export const initOtaAssetResolver = async version => {
30
+ const otaDir = `${ReactNativeBlobUtil.fs.dirs.DocumentDir}/ota`;
31
+ const versionDir = `${otaDir}/v${version}`;
32
+ const manifestPath = `${versionDir}/asset-manifest-v${version}.json`;
33
+ try {
34
+ if (await ReactNativeBlobUtil.fs.exists(manifestPath)) {
35
+ const content = await ReactNativeBlobUtil.fs.readFile(manifestPath, 'utf8');
36
+ assetManifest = JSON.parse(content);
37
+
38
+ // Pre-compute normalized paths for O(1) lookup to prevent JS thread blocking during render
39
+ const map = new Map();
40
+ const list = assetManifest.assets || [];
41
+ list.forEach(a => {
42
+ const normPath = a.originalPath.toLowerCase().replace(/\//g, '_').replace(/^(assets_)+/, '');
43
+ a._normPath = normPath; // cache for fast fallback
44
+ map.set(normPath, a);
45
+ });
46
+ assetMap = map;
47
+ assetList = list;
48
+ log(`Initialized version ${version} (${list.length} assets, mapped for O(1) lookup)`);
49
+ patchAssetResolver();
50
+ } else {
51
+ log(`Manifest NOT found at: ${manifestPath}`);
52
+ }
53
+ } catch (e) {
54
+ log(`Failed to load manifest: ${e.message}`);
55
+ }
56
+ };
57
+
58
+ /**
59
+ * Patches React Native's Image.resolveAssetSource to intercept and redirect
60
+ * asset requests to the locally downloaded OTA asset store.
61
+ */
62
+ const patchAssetResolver = () => {
63
+ if (isPatched) return;
64
+ isPatched = true;
65
+ const resolveAssetSource = Image.resolveAssetSource;
66
+ if (resolveAssetSource && typeof resolveAssetSource.setCustomSourceTransformer === 'function') {
67
+ resolveAssetSource.setCustomSourceTransformer(resolver => {
68
+ // Get the default resolution result
69
+ const res = resolver.defaultAsset();
70
+ if (!res || !assetManifest) return res;
71
+ const uri = res.uri;
72
+
73
+ // Skip remote or data URIs
74
+ // Note: We DO NOT skip 'file://' because local bundles use it for relative asset resolution.
75
+ if (!uri || uri.startsWith('http') || uri.startsWith('data')) {
76
+ return res;
77
+ }
78
+ const normUri = uri.toLowerCase().replace(/\//g, '_').replace(/^(assets_)+/, '');
79
+
80
+ // 1. Fast O(1) Map lookup
81
+ let found = assetMap.get(normUri);
82
+
83
+ // 2. Fallback O(N) fuzzy matching (without regex overhead)
84
+ if (!found) {
85
+ found = assetList.find(a => {
86
+ return a._normPath.endsWith(normUri) || normUri.endsWith(a._normPath);
87
+ });
88
+ }
89
+ if (found) {
90
+ if (found.isBase) {
91
+ if (Platform.OS === 'ios') {
92
+ // iOS: OTA bundle generates wrong relative paths for base assets, redirect to MainBundleDir
93
+ const finalUri = `file://${ReactNativeBlobUtil.fs.dirs.MainBundleDir}/${found.originalPath}`;
94
+ log(`REDIRECTED (BASE): ${uri} -> (MainBundle: ${finalUri})`);
95
+ return {
96
+ ...res,
97
+ uri: finalUri
98
+ };
99
+ } else {
100
+ // Android: let the default responder load it from apk assets (res.uri is correct)
101
+ return res;
102
+ }
103
+ }
104
+ const localPath = `${ASSET_STORE_DIR}/${found.hash}.${found.ext}`;
105
+ // iOS & Android: requires file:// prefix for absolute filesystem paths
106
+ const finalUri = `file://${localPath}`;
107
+ log(`REDIRECTED: ${uri} -> ${found.hash} (Local: ${finalUri})`);
108
+ return {
109
+ ...res,
110
+ uri: finalUri
111
+ };
112
+ }
113
+
114
+ // Diagnostic logging for missed assets that appear to be internal resources
115
+ if (uri.includes('assets')) {
116
+ log(`MISS: ${uri} (Not found in manifest)`);
117
+ }
118
+ return res;
119
+ });
120
+ log('Successfully attached CustomSourceTransformer.');
121
+ } else {
122
+ log('ERROR: setCustomSourceTransformer is not available in this React Native version.');
123
+ }
124
+ };
125
+
126
+ /**
127
+ * Resets the OTA asset resolver state.
128
+ * Call this before a major app upgrade or when unmounting the OTA context.
129
+ * Clears cached manifest data and resets the transformer patch guard so
130
+ * `initOtaAssetResolver` can re-patch cleanly on next call.
131
+ */
132
+ export const resetOtaAssetResolver = () => {
133
+ assetManifest = null;
134
+ assetMap = new Map();
135
+ assetList = [];
136
+ isPatched = false;
137
+ };
138
+ //# sourceMappingURL=otaAssetResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Image","Platform","ReactNativeBlobUtil","NativeBsPatch","ASSET_STORE_DIR","fs","dirs","DocumentDir","assetManifest","assetMap","Map","assetList","isPatched","log","msg","formatted","console","logNative","initOtaAssetResolver","version","otaDir","versionDir","manifestPath","exists","content","readFile","JSON","parse","map","list","assets","forEach","a","normPath","originalPath","toLowerCase","replace","_normPath","set","length","patchAssetResolver","e","message","resolveAssetSource","setCustomSourceTransformer","resolver","res","defaultAsset","uri","startsWith","normUri","found","get","find","endsWith","isBase","OS","finalUri","MainBundleDir","localPath","hash","ext","includes","resetOtaAssetResolver"],"sourceRoot":"../../../src","sources":["ota/otaAssetResolver.ts"],"mappings":"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","ignoreList":[]}