@hot-updater/react-native 0.11.0 → 0.12.1-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.
@@ -128,13 +128,34 @@ class HotUpdater : ReactPackage {
128
128
 
129
129
  val baseDir = context.getExternalFilesDir(null)
130
130
  val bundleStoreDir = File(baseDir, "bundle-store")
131
- val zipFilePath = File(bundleStoreDir, "build.zip")
131
+ if (!bundleStoreDir.exists()) {
132
+ bundleStoreDir.mkdirs()
133
+ }
134
+
135
+ val finalBundleDir = File(bundleStoreDir, bundleId)
136
+ if (finalBundleDir.exists()) {
137
+ Log.d("HotUpdater", "Bundle for bundleId $bundleId already exists. Using cached bundle.")
138
+ val existingIndexFile = finalBundleDir.walk().find { it.name == "index.android.bundle" }
139
+ if (existingIndexFile != null) {
140
+ // Update directory modification time to current time after update
141
+ finalBundleDir.setLastModified(System.currentTimeMillis())
142
+ setBundleURL(context, existingIndexFile.absolutePath)
143
+ cleanupOldBundles(bundleStoreDir)
144
+ return true
145
+ } else {
146
+ finalBundleDir.deleteRecursively()
147
+ }
148
+ }
132
149
 
133
- // Delete existing folder logic
134
- if (bundleStoreDir.exists()) {
135
- bundleStoreDir.deleteRecursively()
150
+ val tempDir = File(baseDir, "bundle-temp")
151
+ if (tempDir.exists()) {
152
+ tempDir.deleteRecursively()
136
153
  }
137
- bundleStoreDir.mkdirs()
154
+ tempDir.mkdirs()
155
+
156
+ val tempZipFile = File(tempDir, "build.zip")
157
+ val extractedDir = File(tempDir, "extracted")
158
+ extractedDir.mkdirs()
138
159
 
139
160
  val isSuccess =
140
161
  withContext(Dispatchers.IO) {
@@ -144,6 +165,7 @@ class HotUpdater : ReactPackage {
144
165
  downloadUrl.openConnection() as HttpURLConnection
145
166
  } catch (e: Exception) {
146
167
  Log.d("HotUpdater", "Failed to open connection: ${e.message}")
168
+ tempDir.deleteRecursively()
147
169
  return@withContext false
148
170
  }
149
171
 
@@ -152,12 +174,11 @@ class HotUpdater : ReactPackage {
152
174
  val totalSize = conn.contentLength
153
175
  if (totalSize <= 0) {
154
176
  Log.d("HotUpdater", "Invalid content length: $totalSize")
177
+ tempDir.deleteRecursively()
155
178
  return@withContext false
156
179
  }
157
-
158
- // File download
159
180
  conn.inputStream.use { input ->
160
- zipFilePath.outputStream().use { output ->
181
+ tempZipFile.outputStream().use { output ->
161
182
  val buffer = ByteArray(8 * 1024)
162
183
  var bytesRead: Int
163
184
  var totalRead = 0L
@@ -178,34 +199,80 @@ class HotUpdater : ReactPackage {
178
199
  }
179
200
  } catch (e: Exception) {
180
201
  Log.d("HotUpdater", "Failed to download data from URL: $zipUrl, Error: ${e.message}")
202
+ tempDir.deleteRecursively()
181
203
  return@withContext false
182
204
  } finally {
183
205
  conn.disconnect()
184
206
  }
185
207
 
186
- // Extract zip
187
- if (!extractZipFileAtPath(zipFilePath.absolutePath, bundleStoreDir.absolutePath)) {
208
+ if (!extractZipFileAtPath(tempZipFile.absolutePath, extractedDir.absolutePath)) {
188
209
  Log.d("HotUpdater", "Failed to extract zip file.")
210
+ tempDir.deleteRecursively()
189
211
  return@withContext false
190
212
  }
213
+ true
214
+ }
191
215
 
192
- // Find index.android.bundle
193
- val indexFile = bundleStoreDir.walk().find { it.name == "index.android.bundle" }
216
+ if (!isSuccess) {
217
+ tempDir.deleteRecursively()
218
+ return false
219
+ }
194
220
 
195
- if (indexFile != null) {
196
- val bundlePath = indexFile.absolutePath
197
- Log.d("HotUpdater", "Setting bundle URL: $bundlePath")
198
- setBundleURL(context, bundlePath)
199
- } else {
200
- Log.d("HotUpdater", "index.android.bundle not found.")
201
- return@withContext false
202
- }
221
+ val indexFileExtracted = extractedDir.walk().find { it.name == "index.android.bundle" }
222
+ if (indexFileExtracted == null) {
223
+ Log.d("HotUpdater", "index.android.bundle not found in extracted files.")
224
+ tempDir.deleteRecursively()
225
+ return false
226
+ }
203
227
 
204
- Log.d("HotUpdater", "Downloaded and extracted file successfully.")
205
- true
206
- }
228
+ // Move (or copy) contents from temp folder to finalBundleDir
229
+ if (finalBundleDir.exists()) {
230
+ finalBundleDir.deleteRecursively()
231
+ }
232
+ if (!extractedDir.renameTo(finalBundleDir)) {
233
+ extractedDir.copyRecursively(finalBundleDir, overwrite = true)
234
+ extractedDir.deleteRecursively()
235
+ }
236
+
237
+ val finalIndexFile = finalBundleDir.walk().find { it.name == "index.android.bundle" }
238
+ if (finalIndexFile == null) {
239
+ Log.d("HotUpdater", "index.android.bundle not found in final directory.")
240
+ tempDir.deleteRecursively()
241
+ return false
242
+ }
243
+
244
+ // Update final bundle directory modification time to current time after bundle update
245
+ finalBundleDir.setLastModified(System.currentTimeMillis())
246
+
247
+ val bundlePath = finalIndexFile.absolutePath
248
+ Log.d("HotUpdater", "Setting bundle URL: $bundlePath")
249
+ setBundleURL(context, bundlePath)
250
+
251
+ // Clean up old bundles in the bundle store to keep only up to 2 bundles
252
+ cleanupOldBundles(bundleStoreDir)
207
253
 
208
- return isSuccess
254
+ // Clean up temp directory
255
+ tempDir.deleteRecursively()
256
+
257
+ Log.d("HotUpdater", "Downloaded and extracted file successfully.")
258
+ return true
259
+ }
260
+
261
+ // Helper function to delete old bundles, keeping only up to 2 bundles in the bundle-store folder
262
+ private fun cleanupOldBundles(bundleStoreDir: File) {
263
+ // Get list of all directories in bundle-store folder
264
+ val bundles = bundleStoreDir.listFiles { file -> file.isDirectory }?.toList() ?: return
265
+
266
+ // Sort by last modified time in descending order to keep most recently updated bundles at the top
267
+ val sortedBundles = bundles.sortedByDescending { it.lastModified() }
268
+
269
+ // Delete all bundles except the top 2
270
+ if (sortedBundles.size > 2) {
271
+ sortedBundles.drop(2).forEach { oldBundle ->
272
+ Log.d("HotUpdater", "Removing old bundle: ${oldBundle.name}")
273
+ oldBundle.deleteRecursively()
274
+ }
275
+ }
209
276
  }
210
277
  }
211
278
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { checkForUpdate } from "./checkUpdate";
1
+ import { checkForUpdate } from "./checkForUpdate";
2
2
  import { wrap } from "./wrap";
3
3
  export type { HotUpdaterConfig } from "./wrap";
4
4
  export type { HotUpdaterEvent } from "./native";
package/dist/native.d.ts CHANGED
@@ -7,7 +7,7 @@ export declare const addListener: <T extends keyof HotUpdaterEvent>(eventName: T
7
7
  /**
8
8
  * Downloads files from given URLs.
9
9
  *
10
- * @param {string} bundleId - identifier for the bundle version.
10
+ * @param {string} bundleId - identifier for the bundle id.
11
11
  * @param {string | null} zipUrl - zip file URL. If null, it means rolling back to the built-in bundle
12
12
  * @returns {Promise<boolean>} Resolves with true if download was successful, otherwise rejects with an error.
13
13
  */
@@ -1,4 +1,4 @@
1
- import { type CheckForUpdateConfig } from "./checkUpdate";
1
+ import { type CheckForUpdateConfig } from "./checkForUpdate";
2
2
  export type RunUpdateProcessResponse = {
3
3
  status: "ROLLBACK" | "UPDATE";
4
4
  shouldForceUpdate: boolean;
package/dist/wrap.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type React from "react";
2
- import { type CheckForUpdateConfig } from "./checkUpdate";
2
+ import { type CheckForUpdateConfig } from "./checkForUpdate";
3
3
  import { HotUpdaterError } from "./error";
4
4
  import type { RunUpdateProcessResponse } from "./runUpdateProcess";
5
5
  type UpdateStatus = "CHECK_FOR_UPDATE" | "UPDATING" | "UPDATE_PROCESS_COMPLETED";
@@ -49,7 +49,6 @@ RCT_EXPORT_MODULE();
49
49
  }
50
50
 
51
51
  + (NSURL *)fallbackURL {
52
- // This supports React Native 0.72.6
53
52
  #if DEBUG
54
53
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
55
54
  #else
@@ -72,6 +71,48 @@ RCT_EXPORT_MODULE();
72
71
  return success;
73
72
  }
74
73
 
74
+ #pragma mark - Cleanup Old Bundles
75
+
76
+ - (void)cleanupOldBundlesAtDirectory:(NSString *)bundleStoreDir {
77
+ NSFileManager *fileManager = [NSFileManager defaultManager];
78
+ NSError *error = nil;
79
+ NSArray *contents = [fileManager contentsOfDirectoryAtPath:bundleStoreDir error:&error];
80
+ if (error) {
81
+ NSLog(@"Failed to list bundle store directory: %@", error);
82
+ return;
83
+ }
84
+
85
+ NSMutableArray *bundleDirs = [NSMutableArray array];
86
+ for (NSString *item in contents) {
87
+ NSString *fullPath = [bundleStoreDir stringByAppendingPathComponent:item];
88
+ BOOL isDir = NO;
89
+ if ([fileManager fileExistsAtPath:fullPath isDirectory:&isDir] && isDir) {
90
+ [bundleDirs addObject:fullPath];
91
+ }
92
+ }
93
+
94
+ // Sort in descending order by modification time (keep latest 2)
95
+ [bundleDirs sortUsingComparator:^NSComparisonResult(NSString *path1, NSString *path2) {
96
+ NSDictionary *attr1 = [fileManager attributesOfItemAtPath:path1 error:nil];
97
+ NSDictionary *attr2 = [fileManager attributesOfItemAtPath:path2 error:nil];
98
+ NSDate *date1 = attr1[NSFileModificationDate] ?: [NSDate dateWithTimeIntervalSince1970:0];
99
+ NSDate *date2 = attr2[NSFileModificationDate] ?: [NSDate dateWithTimeIntervalSince1970:0];
100
+ return [date2 compare:date1];
101
+ }];
102
+
103
+ if (bundleDirs.count > 2) {
104
+ NSArray *oldBundles = [bundleDirs subarrayWithRange:NSMakeRange(2, bundleDirs.count - 2)];
105
+ for (NSString *oldBundle in oldBundles) {
106
+ NSError *delError = nil;
107
+ if ([fileManager removeItemAtPath:oldBundle error:&delError]) {
108
+ NSLog(@"Removed old bundle: %@", oldBundle);
109
+ } else {
110
+ NSLog(@"Failed to remove old bundle %@: %@", oldBundle, delError);
111
+ }
112
+ }
113
+ }
114
+ }
115
+
75
116
  #pragma mark - Update Bundle Method
76
117
 
77
118
  - (void)updateBundle:(NSString *)bundleId zipUrl:(NSURL *)zipUrl completion:(void (^)(BOOL success))completion {
@@ -83,88 +124,158 @@ RCT_EXPORT_MODULE();
83
124
  return;
84
125
  }
85
126
 
86
- // Set app-specific path (dynamically using NSSearchPathForDirectoriesInDomains)
127
+ // Set document directory path and bundle store path
87
128
  NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
88
129
  NSString *bundleStoreDir = [documentsPath stringByAppendingPathComponent:@"bundle-store"];
89
- NSString *zipFilePath = [bundleStoreDir stringByAppendingPathComponent:@"build.zip"];
90
130
 
91
- // Delete existing folder
92
- [self deleteFolderIfExists:bundleStoreDir];
93
- // Create download folder
94
- [[NSFileManager defaultManager] createDirectoryAtPath:bundleStoreDir withIntermediateDirectories:YES attributes:nil error:nil];
131
+ NSFileManager *fileManager = [NSFileManager defaultManager];
132
+ if (![fileManager fileExistsAtPath:bundleStoreDir]) {
133
+ [fileManager createDirectoryAtPath:bundleStoreDir withIntermediateDirectories:YES attributes:nil error:nil];
134
+ }
135
+
136
+ // Final bundle path (bundle-store/<bundleId>)
137
+ NSString *finalBundleDir = [bundleStoreDir stringByAppendingPathComponent:bundleId];
138
+
139
+ // Check if cached bundle exists
140
+ if ([fileManager fileExistsAtPath:finalBundleDir]) {
141
+ NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:finalBundleDir];
142
+ NSString *foundBundle = nil;
143
+ for (NSString *file in enumerator) {
144
+ if ([file isEqualToString:@"index.ios.bundle"]) {
145
+ foundBundle = file;
146
+ break;
147
+ }
148
+ }
149
+ if (foundBundle) {
150
+ // Update modification time of final bundle
151
+ NSDictionary *attributes = @{NSFileModificationDate: [NSDate date]};
152
+ [fileManager setAttributes:attributes ofItemAtPath:finalBundleDir error:nil];
153
+ NSString *bundlePath = [finalBundleDir stringByAppendingPathComponent:foundBundle];
154
+ NSLog(@"Using cached bundle at path: %@", bundlePath);
155
+ [self setBundleURL:bundlePath];
156
+ [self cleanupOldBundlesAtDirectory:bundleStoreDir];
157
+ dispatch_async(dispatch_get_main_queue(), ^{
158
+ if (completion) completion(YES);
159
+ });
160
+ return;
161
+ } else {
162
+ [fileManager removeItemAtPath:finalBundleDir error:nil];
163
+ }
164
+ }
165
+
166
+ // Set up temporary folder (for download and extraction)
167
+ NSString *tempDir = [documentsPath stringByAppendingPathComponent:@"bundle-temp"];
168
+ if ([fileManager fileExistsAtPath:tempDir]) {
169
+ [fileManager removeItemAtPath:tempDir error:nil];
170
+ }
171
+ [fileManager createDirectoryAtPath:tempDir withIntermediateDirectories:YES attributes:nil error:nil];
172
+
173
+ NSString *tempZipFile = [tempDir stringByAppendingPathComponent:@"build.zip"];
174
+ NSString *extractedDir = [tempDir stringByAppendingPathComponent:@"extracted"];
175
+ [fileManager createDirectoryAtPath:extractedDir withIntermediateDirectories:YES attributes:nil error:nil];
95
176
 
96
177
  NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
97
178
  NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
98
179
 
99
- NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:zipUrl
100
- completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
180
+ NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:zipUrl completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
101
181
  if (error) {
102
182
  NSLog(@"Failed to download data from URL: %@, error: %@", zipUrl, error);
103
183
  if (completion) completion(NO);
104
184
  return;
105
185
  }
106
186
 
107
- NSFileManager *fileManager = [NSFileManager defaultManager];
108
-
109
- // Remove existing file
110
- if ([fileManager fileExistsAtPath:zipFilePath]) {
111
- [fileManager removeItemAtPath:zipFilePath error:nil];
187
+ // Save temporary zip file
188
+ if ([fileManager fileExistsAtPath:tempZipFile]) {
189
+ [fileManager removeItemAtPath:tempZipFile error:nil];
112
190
  }
113
191
 
114
- // Move downloaded file
115
- NSError *moveError;
116
- if (![fileManager moveItemAtURL:location toURL:[NSURL fileURLWithPath:zipFilePath] error:&moveError]) {
117
- NSLog(@"Failed to save data: %@", moveError);
192
+ NSError *moveError = nil;
193
+ if (![fileManager moveItemAtURL:location toURL:[NSURL fileURLWithPath:tempZipFile] error:&moveError]) {
194
+ NSLog(@"Failed to save downloaded file: %@", moveError);
118
195
  if (completion) completion(NO);
119
196
  return;
120
197
  }
121
198
 
122
199
  // Extract zip
123
- if (![self extractZipFileAtPath:zipFilePath toDestination:bundleStoreDir]) {
200
+ if (![self extractZipFileAtPath:tempZipFile toDestination:extractedDir]) {
124
201
  NSLog(@"Failed to extract zip file.");
125
202
  if (completion) completion(NO);
126
203
  return;
127
204
  }
128
205
 
129
- // Search for bundle file (index.ios.bundle)
130
- NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:bundleStoreDir];
131
- NSString *filename = nil;
206
+ // Search for index.ios.bundle in extracted folder
207
+ NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:extractedDir];
208
+ NSString *foundBundle = nil;
132
209
  for (NSString *file in enumerator) {
133
210
  if ([file isEqualToString:@"index.ios.bundle"]) {
134
- filename = file;
211
+ foundBundle = file;
135
212
  break;
136
213
  }
137
214
  }
138
215
 
139
- if (filename) {
140
- NSString *bundlePath = [bundleStoreDir stringByAppendingPathComponent:filename];
141
- NSLog(@"Setting bundle URL: %@", bundlePath);
142
- dispatch_async(dispatch_get_main_queue(), ^{
143
- [self setBundleURL:bundlePath];
144
- if (completion) completion(YES);
145
- });
146
- } else {
147
- NSLog(@"index.ios.bundle not found.");
216
+ if (!foundBundle) {
217
+ NSLog(@"index.ios.bundle not found in extracted files.");
218
+ if (completion) completion(NO);
219
+ return;
220
+ }
221
+
222
+ // Move extracted folder to final bundle folder
223
+ if ([fileManager fileExistsAtPath:finalBundleDir]) {
224
+ [fileManager removeItemAtPath:finalBundleDir error:nil];
225
+ }
226
+ NSError *moveFinalError = nil;
227
+ BOOL moved = [fileManager moveItemAtPath:extractedDir toPath:finalBundleDir error:&moveFinalError];
228
+ if (!moved) {
229
+ // Try copy and delete if move fails
230
+ BOOL copied = [fileManager copyItemAtPath:extractedDir toPath:finalBundleDir error:&moveFinalError];
231
+ if (copied) {
232
+ [fileManager removeItemAtPath:extractedDir error:nil];
233
+ } else {
234
+ NSLog(@"Failed to move or copy extracted bundle: %@", moveFinalError);
235
+ if (completion) completion(NO);
236
+ return;
237
+ }
238
+ }
239
+
240
+ // Recheck index.ios.bundle in final folder
241
+ NSDirectoryEnumerator *finalEnum = [fileManager enumeratorAtPath:finalBundleDir];
242
+ NSString *finalFoundBundle = nil;
243
+ for (NSString *file in finalEnum) {
244
+ if ([file isEqualToString:@"index.ios.bundle"]) {
245
+ finalFoundBundle = file;
246
+ break;
247
+ }
248
+ }
249
+
250
+ if (!finalFoundBundle) {
251
+ NSLog(@"index.ios.bundle not found in final directory.");
148
252
  if (completion) completion(NO);
253
+ return;
149
254
  }
255
+
256
+ // Update modification time of final bundle
257
+ NSDictionary *attributes = @{NSFileModificationDate: [NSDate date]};
258
+ [fileManager setAttributes:attributes ofItemAtPath:finalBundleDir error:nil];
259
+
260
+ NSString *bundlePath = [finalBundleDir stringByAppendingPathComponent:finalFoundBundle];
261
+ NSLog(@"Setting bundle URL: %@", bundlePath);
262
+ dispatch_async(dispatch_get_main_queue(), ^{
263
+ [self setBundleURL:bundlePath];
264
+ [self cleanupOldBundlesAtDirectory:bundleStoreDir];
265
+ [fileManager removeItemAtPath:tempDir error:nil];
266
+ if (completion) completion(YES);
267
+ });
150
268
  }];
151
-
152
-
153
- // Add observer for progress updates
154
- [downloadTask addObserver:self
155
- forKeyPath:@"countOfBytesReceived"
156
- options:NSKeyValueObservingOptionNew
157
- context:nil];
158
- [downloadTask addObserver:self
159
- forKeyPath:@"countOfBytesExpectedToReceive"
160
- options:NSKeyValueObservingOptionNew
161
- context:nil];
162
-
163
- __block HotUpdater *weakSelf = self;
269
+
270
+ // Register KVO for progress updates
271
+ [downloadTask addObserver:self forKeyPath:@"countOfBytesReceived" options:NSKeyValueObservingOptionNew context:nil];
272
+ [downloadTask addObserver:self forKeyPath:@"countOfBytesExpectedToReceive" options:NSKeyValueObservingOptionNew context:nil];
273
+
274
+ __weak HotUpdater *weakSelf = self;
164
275
  [[NSNotificationCenter defaultCenter] addObserverForName:@"NSURLSessionDownloadTaskDidFinishDownloading"
165
- object:downloadTask
166
- queue:[NSOperationQueue mainQueue]
167
- usingBlock:^(NSNotification * _Nonnull note) {
276
+ object:downloadTask
277
+ queue:[NSOperationQueue mainQueue]
278
+ usingBlock:^(NSNotification * _Nonnull note) {
168
279
  [weakSelf removeObserversForTask:downloadTask];
169
280
  }];
170
281
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/react-native",
3
- "version": "0.11.0",
3
+ "version": "0.12.1-0",
4
4
  "description": "React Native OTA solution for self-hosted",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -78,8 +78,8 @@
78
78
  "react-native-builder-bob": "^0.33.1"
79
79
  },
80
80
  "dependencies": {
81
- "@hot-updater/js": "0.11.0",
82
- "@hot-updater/core": "0.11.0"
81
+ "@hot-updater/js": "0.12.1-0",
82
+ "@hot-updater/core": "0.12.1-0"
83
83
  },
84
84
  "scripts": {
85
85
  "build": "rslib build",
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { checkForUpdate } from "./checkUpdate";
1
+ import { checkForUpdate } from "./checkForUpdate";
2
2
  import {
3
3
  addListener,
4
4
  getAppVersion,
package/src/native.ts CHANGED
@@ -52,7 +52,7 @@ export const addListener = <T extends keyof HotUpdaterEvent>(
52
52
  /**
53
53
  * Downloads files from given URLs.
54
54
  *
55
- * @param {string} bundleId - identifier for the bundle version.
55
+ * @param {string} bundleId - identifier for the bundle id.
56
56
  * @param {string | null} zipUrl - zip file URL. If null, it means rolling back to the built-in bundle
57
57
  * @returns {Promise<boolean>} Resolves with true if download was successful, otherwise rejects with an error.
58
58
  */
@@ -1,4 +1,4 @@
1
- import { type CheckForUpdateConfig, checkForUpdate } from "./checkUpdate";
1
+ import { type CheckForUpdateConfig, checkForUpdate } from "./checkForUpdate";
2
2
  import { reload, updateBundle } from "./native";
3
3
 
4
4
  export type RunUpdateProcessResponse =
package/src/wrap.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import type React from "react";
2
2
  import { useEffect, useLayoutEffect, useState } from "react";
3
- import { type CheckForUpdateConfig, checkForUpdate } from "./checkUpdate";
3
+ import { type CheckForUpdateConfig, checkForUpdate } from "./checkForUpdate";
4
4
  import { HotUpdaterError } from "./error";
5
5
  import { useEventCallback } from "./hooks/useEventCallback";
6
6
  import { reload, updateBundle } from "./native";
File without changes
File without changes