@hot-updater/react-native 0.23.1 → 0.24.1

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 (109) hide show
  1. package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +393 -49
  2. package/android/src/main/java/com/hotupdater/BundleMetadata.kt +204 -0
  3. package/android/src/main/java/com/hotupdater/HotUpdater.kt +48 -36
  4. package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +134 -0
  5. package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +168 -95
  6. package/android/src/main/java/com/hotupdater/OkHttpDownloadService.kt +15 -3
  7. package/android/src/main/java/com/hotupdater/SignatureVerifier.kt +17 -12
  8. package/android/src/newarch/HotUpdaterModule.kt +88 -23
  9. package/android/src/oldarch/HotUpdaterModule.kt +89 -22
  10. package/android/src/oldarch/HotUpdaterSpec.kt +6 -0
  11. package/ios/HotUpdater/Internal/BundleFileStorageService.swift +401 -77
  12. package/ios/HotUpdater/Internal/BundleMetadata.swift +177 -0
  13. package/ios/HotUpdater/Internal/HotUpdater.mm +213 -47
  14. package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +96 -25
  15. package/ios/HotUpdater/Internal/SignatureVerifier.swift +35 -29
  16. package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +2 -2
  17. package/ios/HotUpdater/Public/HotUpdater.h +8 -2
  18. package/lib/commonjs/DefaultResolver.js +38 -0
  19. package/lib/commonjs/DefaultResolver.js.map +1 -0
  20. package/lib/commonjs/checkForUpdate.js +33 -45
  21. package/lib/commonjs/checkForUpdate.js.map +1 -1
  22. package/lib/commonjs/error.js +45 -1
  23. package/lib/commonjs/error.js.map +1 -1
  24. package/lib/commonjs/fetchUpdateInfo.js +7 -45
  25. package/lib/commonjs/fetchUpdateInfo.js.map +1 -1
  26. package/lib/commonjs/index.js +249 -208
  27. package/lib/commonjs/index.js.map +1 -1
  28. package/lib/commonjs/native.js +103 -3
  29. package/lib/commonjs/native.js.map +1 -1
  30. package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
  31. package/lib/commonjs/types.js +12 -0
  32. package/lib/commonjs/types.js.map +1 -1
  33. package/lib/commonjs/wrap.js +70 -1
  34. package/lib/commonjs/wrap.js.map +1 -1
  35. package/lib/module/DefaultResolver.js +34 -0
  36. package/lib/module/DefaultResolver.js.map +1 -0
  37. package/lib/module/checkForUpdate.js +34 -43
  38. package/lib/module/checkForUpdate.js.map +1 -1
  39. package/lib/module/error.js +45 -0
  40. package/lib/module/error.js.map +1 -1
  41. package/lib/module/fetchUpdateInfo.js +7 -45
  42. package/lib/module/fetchUpdateInfo.js.map +1 -1
  43. package/lib/module/index.js +250 -203
  44. package/lib/module/index.js.map +1 -1
  45. package/lib/module/native.js +87 -2
  46. package/lib/module/native.js.map +1 -1
  47. package/lib/module/specs/NativeHotUpdater.js.map +1 -1
  48. package/lib/module/types.js +12 -0
  49. package/lib/module/types.js.map +1 -1
  50. package/lib/module/wrap.js +71 -2
  51. package/lib/module/wrap.js.map +1 -1
  52. package/lib/typescript/commonjs/DefaultResolver.d.ts +10 -0
  53. package/lib/typescript/commonjs/DefaultResolver.d.ts.map +1 -0
  54. package/lib/typescript/commonjs/checkForUpdate.d.ts +12 -13
  55. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/error.d.ts +120 -0
  57. package/lib/typescript/commonjs/error.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/fetchUpdateInfo.d.ts +3 -5
  59. package/lib/typescript/commonjs/fetchUpdateInfo.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/index.d.ts +38 -44
  61. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  62. package/lib/typescript/commonjs/native.d.ts +58 -2
  63. package/lib/typescript/commonjs/native.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +62 -0
  65. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
  66. package/lib/typescript/commonjs/types.d.ts +115 -0
  67. package/lib/typescript/commonjs/types.d.ts.map +1 -1
  68. package/lib/typescript/commonjs/wrap.d.ts +132 -7
  69. package/lib/typescript/commonjs/wrap.d.ts.map +1 -1
  70. package/lib/typescript/module/DefaultResolver.d.ts +10 -0
  71. package/lib/typescript/module/DefaultResolver.d.ts.map +1 -0
  72. package/lib/typescript/module/checkForUpdate.d.ts +12 -13
  73. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
  74. package/lib/typescript/module/error.d.ts +120 -0
  75. package/lib/typescript/module/error.d.ts.map +1 -1
  76. package/lib/typescript/module/fetchUpdateInfo.d.ts +3 -5
  77. package/lib/typescript/module/fetchUpdateInfo.d.ts.map +1 -1
  78. package/lib/typescript/module/index.d.ts +38 -44
  79. package/lib/typescript/module/index.d.ts.map +1 -1
  80. package/lib/typescript/module/native.d.ts +58 -2
  81. package/lib/typescript/module/native.d.ts.map +1 -1
  82. package/lib/typescript/module/specs/NativeHotUpdater.d.ts +62 -0
  83. package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
  84. package/lib/typescript/module/types.d.ts +115 -0
  85. package/lib/typescript/module/types.d.ts.map +1 -1
  86. package/lib/typescript/module/wrap.d.ts +132 -7
  87. package/lib/typescript/module/wrap.d.ts.map +1 -1
  88. package/package.json +6 -6
  89. package/plugin/build/withHotUpdater.js +3 -3
  90. package/src/DefaultResolver.ts +36 -0
  91. package/src/checkForUpdate.ts +51 -56
  92. package/src/error.ts +153 -0
  93. package/src/fetchUpdateInfo.ts +10 -58
  94. package/src/index.ts +315 -206
  95. package/src/native.ts +88 -2
  96. package/src/specs/NativeHotUpdater.ts +63 -0
  97. package/src/types.ts +135 -0
  98. package/src/wrap.tsx +245 -34
  99. package/android/src/main/java/com/hotupdater/HotUpdaterFactory.kt +0 -52
  100. package/ios/HotUpdater/Internal/HotUpdaterFactory.swift +0 -24
  101. package/lib/commonjs/runUpdateProcess.js +0 -69
  102. package/lib/commonjs/runUpdateProcess.js.map +0 -1
  103. package/lib/module/runUpdateProcess.js +0 -64
  104. package/lib/module/runUpdateProcess.js.map +0 -1
  105. package/lib/typescript/commonjs/runUpdateProcess.d.ts +0 -49
  106. package/lib/typescript/commonjs/runUpdateProcess.d.ts.map +0 -1
  107. package/lib/typescript/module/runUpdateProcess.d.ts +0 -49
  108. package/lib/typescript/module/runUpdateProcess.d.ts.map +0 -1
  109. package/src/runUpdateProcess.ts +0 -80
@@ -8,7 +8,7 @@ import React
8
8
  private static let DEFAULT_CHANNEL = "production"
9
9
 
10
10
  // MARK: - Initialization
11
-
11
+
12
12
  /**
13
13
  * Convenience initializer that creates and configures all dependencies.
14
14
  */
@@ -27,7 +27,7 @@ import React
27
27
 
28
28
  self.init(bundleStorage: bundleStorage, preferences: preferences)
29
29
  }
30
-
30
+
31
31
  /**
32
32
  * Primary initializer with dependency injection.
33
33
  * @param bundleStorage Service for bundle storage operations
@@ -66,15 +66,14 @@ import React
66
66
  public static func getIsolationKey() -> String {
67
67
  // Get fingerprint hash from Info.plist
68
68
  let fingerprintHash = Bundle.main.object(forInfoDictionaryKey: "HOT_UPDATER_FINGERPRINT_HASH") as? String
69
-
69
+
70
70
  // Get app version and channel
71
71
  let appVersion = self.appVersion ?? "unknown"
72
72
  let appChannel = self.appChannel
73
-
73
+
74
74
  // Use fingerprint if available, otherwise use app version
75
75
  let baseKey = (fingerprintHash != nil && !fingerprintHash!.isEmpty) ? fingerprintHash! : appVersion
76
-
77
- // Build complete isolation key
76
+
78
77
  return "hotupdater_\(baseKey)_\(appChannel)_"
79
78
  }
80
79
 
@@ -122,22 +121,28 @@ import React
122
121
  do {
123
122
  // Validate parameters (this runs on calling thread - typically JS thread)
124
123
  guard let data = params else {
125
- throw NSError(domain: "HotUpdaterError", code: 101,
126
- userInfo: [NSLocalizedDescriptionKey: "Missing params dictionary"])
124
+ let error = NSError(domain: "HotUpdater", code: 0,
125
+ userInfo: [NSLocalizedDescriptionKey: "Missing or invalid parameters for updateBundle"])
126
+ reject("UNKNOWN_ERROR", error.localizedDescription, error)
127
+ return
127
128
  }
128
-
129
+
129
130
  guard let bundleId = data["bundleId"] as? String, !bundleId.isEmpty else {
130
- throw NSError(domain: "HotUpdaterError", code: 102,
131
- userInfo: [NSLocalizedDescriptionKey: "Missing or empty 'bundleId'"])
131
+ let error = NSError(domain: "HotUpdater", code: 0,
132
+ userInfo: [NSLocalizedDescriptionKey: "Missing or empty 'bundleId'"])
133
+ reject("MISSING_BUNDLE_ID", error.localizedDescription, error)
134
+ return
132
135
  }
133
-
136
+
134
137
  let fileUrlString = data["fileUrl"] as? String ?? ""
135
138
 
136
139
  var fileUrl: URL? = nil
137
140
  if !fileUrlString.isEmpty {
138
141
  guard let url = URL(string: fileUrlString) else {
139
- throw NSError(domain: "HotUpdaterError", code: 103,
140
- userInfo: [NSLocalizedDescriptionKey: "Invalid 'fileUrl' provided: \(fileUrlString)"])
142
+ let error = NSError(domain: "HotUpdater", code: 0,
143
+ userInfo: [NSLocalizedDescriptionKey: "Invalid 'fileUrl' provided: \(fileUrlString)"])
144
+ reject("INVALID_FILE_URL", error.localizedDescription, error)
145
+ return
141
146
  }
142
147
  fileUrl = url
143
148
  }
@@ -160,10 +165,10 @@ import React
160
165
  }
161
166
  }) { [weak self] result in
162
167
  guard self != nil else {
163
- let error = NSError(domain: "HotUpdaterError", code: 998,
164
- userInfo: [NSLocalizedDescriptionKey: "Self deallocated during update"])
168
+ let error = NSError(domain: "HotUpdater", code: 0,
169
+ userInfo: [NSLocalizedDescriptionKey: "Internal error: self deallocated during update"])
165
170
  DispatchQueue.main.async {
166
- reject("UPDATE_ERROR", error.localizedDescription, error)
171
+ reject("SELF_DEALLOCATED", error.localizedDescription, error)
167
172
  }
168
173
  return
169
174
  }
@@ -174,12 +179,11 @@ import React
174
179
  NSLog("[HotUpdaterImpl] Update successful for \(bundleId). Resolving promise.")
175
180
  resolve(true)
176
181
  case .failure(let error):
177
- let nsError = error as NSError
178
- NSLog("[HotUpdaterImpl] Update failed for \(bundleId) - Domain: \(nsError.domain), Code: \(nsError.code), Description: \(nsError.localizedDescription)")
182
+ NSLog("[HotUpdaterImpl] Update failed for \(bundleId) - Error: \(error)")
179
183
 
180
- // Create a meaningful error code for React Native
181
- let errorCode = "BUNDLE_STORAGE_ERROR_\(nsError.code)"
182
- reject(errorCode, nsError.localizedDescription, nsError)
184
+ let normalizedCode = HotUpdaterImpl.normalizeErrorCode(from: error)
185
+ let nsError = error as NSError
186
+ reject(normalizedCode, nsError.localizedDescription, nsError)
183
187
  }
184
188
  }
185
189
  }
@@ -188,8 +192,75 @@ import React
188
192
  let nsError = error as NSError
189
193
  NSLog("[HotUpdaterImpl] Error in updateBundleFromJS - Domain: \(nsError.domain), Code: \(nsError.code), Description: \(nsError.localizedDescription)")
190
194
 
191
- let errorCode = "UPDATE_ERROR_\(nsError.code)"
192
- reject(errorCode, nsError.localizedDescription, nsError)
195
+ reject("UNKNOWN_ERROR", nsError.localizedDescription, nsError)
193
196
  }
194
197
  }
195
- }
198
+
199
+ /**
200
+ * Normalizes native errors to a small, predictable set of JS-facing error codes.
201
+ * Rare or platform-specific codes are collapsed to UNKNOWN_ERROR to reduce surface area.
202
+ */
203
+ private static func normalizeErrorCode(from error: Error) -> String {
204
+ let baseCode: String
205
+
206
+ if let storageError = error as? BundleStorageError {
207
+ // Collapse signature sub-errors into a single public code
208
+ if case .signatureVerificationFailed = storageError {
209
+ baseCode = "SIGNATURE_VERIFICATION_FAILED"
210
+ } else {
211
+ baseCode = storageError.errorCodeString
212
+ }
213
+ } else if error is SignatureVerificationError {
214
+ baseCode = "SIGNATURE_VERIFICATION_FAILED"
215
+ } else {
216
+ baseCode = "UNKNOWN_ERROR"
217
+ }
218
+
219
+ return userFacingErrorCodes.contains(baseCode) ? baseCode : "UNKNOWN_ERROR"
220
+ }
221
+
222
+ // Error codes we intentionally expose to JS callers.
223
+ private static let userFacingErrorCodes: Set<String> = [
224
+ "MISSING_BUNDLE_ID",
225
+ "INVALID_FILE_URL",
226
+ "DIRECTORY_CREATION_FAILED",
227
+ "DOWNLOAD_FAILED",
228
+ "INCOMPLETE_DOWNLOAD",
229
+ "EXTRACTION_FORMAT_ERROR",
230
+ "INVALID_BUNDLE",
231
+ "INSUFFICIENT_DISK_SPACE",
232
+ "SIGNATURE_VERIFICATION_FAILED",
233
+ "MOVE_OPERATION_FAILED",
234
+ "BUNDLE_IN_CRASHED_HISTORY",
235
+ "SELF_DEALLOCATED",
236
+ "UNKNOWN_ERROR",
237
+ ]
238
+
239
+ // MARK: - Rollback Support
240
+
241
+ /**
242
+ * Notifies the system that the app has successfully started with the given bundle.
243
+ * If the bundle matches the staging bundle, it promotes to stable.
244
+ * @param bundleId The ID of the currently running bundle
245
+ * @return true if promotion was successful or no action was needed
246
+ */
247
+ public func notifyAppReady(bundleId: String) -> [String: Any] {
248
+ return bundleStorage.notifyAppReady(bundleId: bundleId)
249
+ }
250
+
251
+ /**
252
+ * Gets the crashed bundle history.
253
+ * @return Array of crashed bundle IDs
254
+ */
255
+ public func getCrashHistory() -> [String] {
256
+ return bundleStorage.getCrashHistory().bundles.map { $0.bundleId }
257
+ }
258
+
259
+ /**
260
+ * Clears the crashed bundle history.
261
+ * @return true if clearing was successful
262
+ */
263
+ public func clearCrashHistory() -> Bool {
264
+ return bundleStorage.clearCrashHistory()
265
+ }
266
+ }
@@ -5,35 +5,37 @@ import Security
5
5
  private let SIGNED_HASH_PREFIX = "sig:"
6
6
 
7
7
  /// Error types for signature verification failures.
8
- ///
9
- /// **IMPORTANT**: The error messages in `errorUserInfo` are used by the JavaScript layer
10
- /// (`packages/react-native/src/types.ts`) to detect signature verification failures.
11
- /// If you change these messages, update `isSignatureVerificationError()` in types.ts accordingly.
12
8
  public enum SignatureVerificationError: Error, CustomNSError {
13
9
  case publicKeyNotConfigured
14
10
  case invalidPublicKeyFormat
11
+ case missingFileHash
15
12
  case invalidSignatureFormat
16
- case verificationFailed
17
- case hashMismatch
18
- case hashCalculationFailed
13
+ case signatureVerificationFailed
14
+ case fileHashMismatch
15
+ case fileReadFailed
19
16
  case unsignedNotAllowed
20
17
  case securityFrameworkError(OSStatus)
21
18
 
22
19
  // CustomNSError protocol implementation
23
20
  public static var errorDomain: String {
24
- return "com.hotupdater.SignatureVerificationError"
21
+ return "HotUpdater"
25
22
  }
26
23
 
27
24
  public var errorCode: Int {
25
+ return 0
26
+ }
27
+
28
+ public var errorCodeString: String {
28
29
  switch self {
29
- case .publicKeyNotConfigured: return 2001
30
- case .invalidPublicKeyFormat: return 2002
31
- case .invalidSignatureFormat: return 2003
32
- case .verificationFailed: return 2004
33
- case .hashMismatch: return 2005
34
- case .hashCalculationFailed: return 2006
35
- case .unsignedNotAllowed: return 2007
36
- case .securityFrameworkError: return 2099
30
+ case .publicKeyNotConfigured: return "PUBLIC_KEY_NOT_CONFIGURED"
31
+ case .invalidPublicKeyFormat: return "INVALID_PUBLIC_KEY_FORMAT"
32
+ case .missingFileHash: return "MISSING_FILE_HASH"
33
+ case .invalidSignatureFormat: return "INVALID_SIGNATURE_FORMAT"
34
+ case .signatureVerificationFailed: return "SIGNATURE_VERIFICATION_FAILED"
35
+ case .fileHashMismatch: return "FILE_HASH_MISMATCH"
36
+ case .fileReadFailed: return "FILE_READ_FAILED"
37
+ case .unsignedNotAllowed: return "UNSIGNED_NOT_ALLOWED"
38
+ case .securityFrameworkError: return "SECURITY_FRAMEWORK_ERROR"
37
39
  }
38
40
  }
39
41
 
@@ -49,20 +51,24 @@ public enum SignatureVerificationError: Error, CustomNSError {
49
51
  userInfo[NSLocalizedDescriptionKey] = "Public key format is invalid"
50
52
  userInfo[NSLocalizedRecoverySuggestionErrorKey] = "Ensure the public key is in PEM format (BEGIN PUBLIC KEY)"
51
53
 
54
+ case .missingFileHash:
55
+ userInfo[NSLocalizedDescriptionKey] = "File hash is missing or empty"
56
+ userInfo[NSLocalizedRecoverySuggestionErrorKey] = "Ensure the bundle update includes a valid file hash"
57
+
52
58
  case .invalidSignatureFormat:
53
- userInfo[NSLocalizedDescriptionKey] = "Signature format is invalid"
54
- userInfo[NSLocalizedRecoverySuggestionErrorKey] = "The signature must be base64-encoded"
59
+ userInfo[NSLocalizedDescriptionKey] = "Signature format is invalid or corrupted"
60
+ userInfo[NSLocalizedRecoverySuggestionErrorKey] = "The signature data is malformed or cannot be decoded. Bundle may be corrupted"
55
61
 
56
- case .verificationFailed:
62
+ case .signatureVerificationFailed:
57
63
  userInfo[NSLocalizedDescriptionKey] = "Bundle signature verification failed"
58
64
  userInfo[NSLocalizedRecoverySuggestionErrorKey] = "The bundle may be corrupted or tampered with. Rejecting update for security"
59
65
 
60
- case .hashMismatch:
61
- userInfo[NSLocalizedDescriptionKey] = "Bundle hash verification failed"
62
- userInfo[NSLocalizedRecoverySuggestionErrorKey] = "The bundle file hash does not match. File may be corrupted"
66
+ case .fileHashMismatch:
67
+ userInfo[NSLocalizedDescriptionKey] = "File hash verification failed"
68
+ userInfo[NSLocalizedRecoverySuggestionErrorKey] = "The bundle file hash does not match the expected value. File may be corrupted"
63
69
 
64
- case .hashCalculationFailed:
65
- userInfo[NSLocalizedDescriptionKey] = "Failed to calculate file hash"
70
+ case .fileReadFailed:
71
+ userInfo[NSLocalizedDescriptionKey] = "Failed to read file for verification"
66
72
  userInfo[NSLocalizedRecoverySuggestionErrorKey] = "Could not read file for hash verification"
67
73
 
68
74
  case .unsignedNotAllowed:
@@ -149,7 +155,7 @@ public class SignatureVerifier {
149
155
  // Rule: null/empty fileHash → REJECT
150
156
  guard let hash = fileHash, !hash.isEmpty else {
151
157
  NSLog("[SignatureVerifier] fileHash is null or empty. Rejecting update.")
152
- return .failure(.verificationFailed)
158
+ return .failure(.missingFileHash)
153
159
  }
154
160
 
155
161
  if isSignedFormat(hash) {
@@ -192,7 +198,7 @@ public class SignatureVerifier {
192
198
 
193
199
  guard HashUtils.verifyHash(fileURL: fileURL, expectedHash: expectedHash) else {
194
200
  NSLog("[SignatureVerifier] Hash mismatch!")
195
- return .failure(.hashMismatch)
201
+ return .failure(.fileHashMismatch)
196
202
  }
197
203
 
198
204
  NSLog("[SignatureVerifier] ✅ Hash verified successfully")
@@ -228,7 +234,7 @@ public class SignatureVerifier {
228
234
  // Calculate file hash
229
235
  guard let fileHashHex = HashUtils.calculateSHA256(fileURL: fileURL) else {
230
236
  NSLog("[SignatureVerifier] Failed to calculate file hash")
231
- return .failure(.hashCalculationFailed)
237
+ return .failure(.fileReadFailed)
232
238
  }
233
239
 
234
240
  NSLog("[SignatureVerifier] Calculated file hash: \(fileHashHex)")
@@ -264,7 +270,7 @@ public class SignatureVerifier {
264
270
 
265
271
  if let err = error?.takeRetainedValue() {
266
272
  NSLog("[SignatureVerifier] Verification failed: \(err)")
267
- return .failure(.verificationFailed)
273
+ return .failure(.signatureVerificationFailed)
268
274
  }
269
275
 
270
276
  if verified {
@@ -272,7 +278,7 @@ public class SignatureVerifier {
272
278
  return .success(())
273
279
  } else {
274
280
  NSLog("[SignatureVerifier] ❌ Signature verification failed")
275
- return .failure(.verificationFailed)
281
+ return .failure(.signatureVerificationFailed)
276
282
  }
277
283
  }
278
284
 
@@ -21,7 +21,7 @@ protocol DownloadService {
21
21
 
22
22
 
23
23
  enum DownloadError: Error {
24
- case incompleteDownload
24
+ case incompleteDownload(expected: Int64, actual: Int64)
25
25
  case invalidContentLength
26
26
  }
27
27
 
@@ -109,7 +109,7 @@ extension URLSessionDownloadService: URLSessionDownloadDelegate {
109
109
  NSLog("[DownloadService] Download incomplete: \(actualSize) / \(expectedSize) bytes")
110
110
  // Delete incomplete file
111
111
  try? FileManager.default.removeItem(at: location)
112
- completion?(.failure(DownloadError.incompleteDownload))
112
+ completion?(.failure(DownloadError.incompleteDownload(expected: expectedSize, actual: actualSize)))
113
113
  return
114
114
  }
115
115
 
@@ -10,12 +10,18 @@
10
10
  #endif // RCT_NEW_ARCH_ENABLED
11
11
 
12
12
  /**
13
- * Returns the currently active bundle URL.
14
- * Callable from Objective-C (e.g., AppDelegate).
13
+ * Returns the currently active bundle URL from the default (static) instance.
14
+ * Callable from Objective-C (e.g., AppDelegate).
15
15
  * This is implemented in HotUpdater.mm and calls the Swift static method.
16
16
  */
17
17
  + (NSURL *)bundleURL;
18
18
 
19
+ /**
20
+ * Returns the bundle URL for this specific instance.
21
+ * @return The bundle URL for this instance
22
+ */
23
+ - (NSURL *)bundleURL;
24
+
19
25
  /**
20
26
  * 다운로드 진행 상황 업데이트 시간을 추적하는 속성
21
27
  */
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createDefaultResolver = createDefaultResolver;
7
+ var _fetchUpdateInfo = require("./fetchUpdateInfo.js");
8
+ /**
9
+ * Creates a default resolver that uses baseURL for network operations.
10
+ * This encapsulates the existing baseURL logic into a resolver.
11
+ *
12
+ * @param baseURL - The base URL for the update server
13
+ * @returns A HotUpdaterResolver that uses the baseURL
14
+ */
15
+ function createDefaultResolver(baseURL) {
16
+ return {
17
+ checkUpdate: async params => {
18
+ // Build URL based on strategy (existing buildUpdateUrl logic)
19
+ let url;
20
+ if (params.updateStrategy === "fingerprint") {
21
+ if (!params.fingerprintHash) {
22
+ throw new Error("Fingerprint hash is required");
23
+ }
24
+ url = `${baseURL}/fingerprint/${params.platform}/${params.fingerprintHash}/${params.channel}/${params.minBundleId}/${params.bundleId}`;
25
+ } else {
26
+ url = `${baseURL}/app-version/${params.platform}/${params.appVersion}/${params.channel}/${params.minBundleId}/${params.bundleId}`;
27
+ }
28
+
29
+ // Use existing fetchUpdateInfo
30
+ return (0, _fetchUpdateInfo.fetchUpdateInfo)({
31
+ url,
32
+ requestHeaders: params.requestHeaders,
33
+ requestTimeout: params.requestTimeout
34
+ });
35
+ }
36
+ };
37
+ }
38
+ //# sourceMappingURL=DefaultResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_fetchUpdateInfo","require","createDefaultResolver","baseURL","checkUpdate","params","url","updateStrategy","fingerprintHash","Error","platform","channel","minBundleId","bundleId","appVersion","fetchUpdateInfo","requestHeaders","requestTimeout"],"sourceRoot":"../../src","sources":["DefaultResolver.ts"],"mappings":";;;;;;AACA,IAAAA,gBAAA,GAAAC,OAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,qBAAqBA,CAACC,OAAe,EAAsB;EACzE,OAAO;IACLC,WAAW,EAAE,MACXC,MAAiC,IACC;MAClC;MACA,IAAIC,GAAW;MACf,IAAID,MAAM,CAACE,cAAc,KAAK,aAAa,EAAE;QAC3C,IAAI,CAACF,MAAM,CAACG,eAAe,EAAE;UAC3B,MAAM,IAAIC,KAAK,CAAC,8BAA8B,CAAC;QACjD;QACAH,GAAG,GAAG,GAAGH,OAAO,gBAAgBE,MAAM,CAACK,QAAQ,IAAIL,MAAM,CAACG,eAAe,IAAIH,MAAM,CAACM,OAAO,IAAIN,MAAM,CAACO,WAAW,IAAIP,MAAM,CAACQ,QAAQ,EAAE;MACxI,CAAC,MAAM;QACLP,GAAG,GAAG,GAAGH,OAAO,gBAAgBE,MAAM,CAACK,QAAQ,IAAIL,MAAM,CAACS,UAAU,IAAIT,MAAM,CAACM,OAAO,IAAIN,MAAM,CAACO,WAAW,IAAIP,MAAM,CAACQ,QAAQ,EAAE;MACnI;;MAEA;MACA,OAAO,IAAAE,gCAAe,EAAC;QACrBT,GAAG;QACHU,cAAc,EAAEX,MAAM,CAACW,cAAc;QACrCC,cAAc,EAAEZ,MAAM,CAACY;MACzB,CAAC,CAAC;IACJ;EACF,CAAC;AACH","ignoreList":[]}
@@ -4,11 +4,11 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.checkForUpdate = checkForUpdate;
7
- exports.getUpdateSource = void 0;
8
7
  var _reactNative = require("react-native");
9
8
  var _error = require("./error.js");
10
- var _fetchUpdateInfo = require("./fetchUpdateInfo.js");
11
9
  var _native = require("./native.js");
10
+ // Internal type that includes resolver for use within index.ts
11
+
12
12
  async function checkForUpdate(options) {
13
13
  if (__DEV__) {
14
14
  return null;
@@ -27,52 +27,40 @@ async function checkForUpdate(options) {
27
27
  return null;
28
28
  }
29
29
  const fingerprintHash = (0, _native.getFingerprintHash)();
30
- return (0, _fetchUpdateInfo.fetchUpdateInfo)({
31
- source: options.source,
32
- params: {
33
- bundleId: currentBundleId,
34
- appVersion: currentAppVersion,
30
+ if (!options.resolver?.checkUpdate) {
31
+ options.onError?.(new _error.HotUpdaterError("Resolver is required but not configured"));
32
+ return null;
33
+ }
34
+ let updateInfo = null;
35
+ try {
36
+ updateInfo = await options.resolver.checkUpdate({
35
37
  platform,
38
+ appVersion: currentAppVersion,
39
+ bundleId: currentBundleId,
36
40
  minBundleId,
37
41
  channel,
38
- fingerprintHash
39
- },
40
- requestHeaders: options.requestHeaders,
41
- onError: options.onError,
42
- requestTimeout: options.requestTimeout
43
- }).then(updateInfo => {
44
- if (!updateInfo) {
45
- return null;
42
+ updateStrategy: options.updateStrategy,
43
+ fingerprintHash,
44
+ requestHeaders: options.requestHeaders,
45
+ requestTimeout: options.requestTimeout
46
+ });
47
+ } catch (error) {
48
+ options.onError?.(error);
49
+ return null;
50
+ }
51
+ if (!updateInfo) {
52
+ return null;
53
+ }
54
+ return {
55
+ ...updateInfo,
56
+ updateBundle: async () => {
57
+ return (0, _native.updateBundle)({
58
+ bundleId: updateInfo.id,
59
+ fileUrl: updateInfo.fileUrl,
60
+ fileHash: updateInfo.fileHash,
61
+ status: updateInfo.status
62
+ });
46
63
  }
47
- return {
48
- ...updateInfo,
49
- updateBundle: async () => {
50
- return (0, _native.updateBundle)({
51
- bundleId: updateInfo.id,
52
- fileUrl: updateInfo.fileUrl,
53
- fileHash: updateInfo.fileHash,
54
- status: updateInfo.status
55
- });
56
- }
57
- };
58
- });
64
+ };
59
65
  }
60
- const getUpdateSource = (baseUrl, options) => params => {
61
- switch (options.updateStrategy) {
62
- case "fingerprint":
63
- {
64
- if (!params.fingerprintHash) {
65
- throw new _error.HotUpdaterError("Fingerprint hash is required");
66
- }
67
- return `${baseUrl}/fingerprint/${params.platform}/${params.fingerprintHash}/${params.channel}/${params.minBundleId}/${params.bundleId}`;
68
- }
69
- case "appVersion":
70
- {
71
- return `${baseUrl}/app-version/${params.platform}/${params.appVersion}/${params.channel}/${params.minBundleId}/${params.bundleId}`;
72
- }
73
- default:
74
- return baseUrl;
75
- }
76
- };
77
- exports.getUpdateSource = getUpdateSource;
78
66
  //# sourceMappingURL=checkForUpdate.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","_error","_fetchUpdateInfo","_native","checkForUpdate","options","__DEV__","includes","Platform","OS","onError","HotUpdaterError","currentAppVersion","getAppVersion","platform","currentBundleId","getBundleId","minBundleId","getMinBundleId","channel","getChannel","fingerprintHash","getFingerprintHash","fetchUpdateInfo","source","params","bundleId","appVersion","requestHeaders","requestTimeout","then","updateInfo","updateBundle","id","fileUrl","fileHash","status","getUpdateSource","baseUrl","updateStrategy","exports"],"sourceRoot":"../../src","sources":["checkForUpdate.ts"],"mappings":";;;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;AACA,IAAAE,gBAAA,GAAAF,OAAA;AACA,IAAAG,OAAA,GAAAH,OAAA;AA4BO,eAAeI,cAAcA,CAClCC,OAA8B,EACQ;EACtC,IAAIC,OAAO,EAAE;IACX,OAAO,IAAI;EACb;EAEA,IAAI,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,CAACC,QAAQ,CAACC,qBAAQ,CAACC,EAAE,CAAC,EAAE;IAC7CJ,OAAO,CAACK,OAAO,GACb,IAAIC,sBAAe,CAAC,iDAAiD,CACvE,CAAC;IACD,OAAO,IAAI;EACb;EAEA,MAAMC,iBAAiB,GAAG,IAAAC,qBAAa,EAAC,CAAC;EACzC,MAAMC,QAAQ,GAAGN,qBAAQ,CAACC,EAAuB;EACjD,MAAMM,eAAe,GAAG,IAAAC,mBAAW,EAAC,CAAC;EACrC,MAAMC,WAAW,GAAG,IAAAC,sBAAc,EAAC,CAAC;EACpC,MAAMC,OAAO,GAAG,IAAAC,kBAAU,EAAC,CAAC;EAE5B,IAAI,CAACR,iBAAiB,EAAE;IACtBP,OAAO,CAACK,OAAO,GAAG,IAAIC,sBAAe,CAAC,2BAA2B,CAAC,CAAC;IACnE,OAAO,IAAI;EACb;EAEA,MAAMU,eAAe,GAAG,IAAAC,0BAAkB,EAAC,CAAC;EAE5C,OAAO,IAAAC,gCAAe,EAAC;IACrBC,MAAM,EAAEnB,OAAO,CAACmB,MAAM;IACtBC,MAAM,EAAE;MACNC,QAAQ,EAAEX,eAAe;MACzBY,UAAU,EAAEf,iBAAiB;MAC7BE,QAAQ;MACRG,WAAW;MACXE,OAAO;MACPE;IACF,CAAC;IACDO,cAAc,EAAEvB,OAAO,CAACuB,cAAc;IACtClB,OAAO,EAAEL,OAAO,CAACK,OAAO;IACxBmB,cAAc,EAAExB,OAAO,CAACwB;EAC1B,CAAC,CAAC,CAACC,IAAI,CAAEC,UAAU,IAAK;IACtB,IAAI,CAACA,UAAU,EAAE;MACf,OAAO,IAAI;IACb;IAEA,OAAO;MACL,GAAGA,UAAU;MACbC,YAAY,EAAE,MAAAA,CAAA,KAAY;QACxB,OAAO,IAAAA,oBAAY,EAAC;UAClBN,QAAQ,EAAEK,UAAU,CAACE,EAAE;UACvBC,OAAO,EAAEH,UAAU,CAACG,OAAO;UAC3BC,QAAQ,EAAEJ,UAAU,CAACI,QAAQ;UAC7BC,MAAM,EAAEL,UAAU,CAACK;QACrB,CAAC,CAAC;MACJ;IACF,CAAC;EACH,CAAC,CAAC;AACJ;AAYO,MAAMC,eAAe,GAC1BA,CAACC,OAAe,EAAEjC,OAA+B,KAChDoB,MAA0B,IAAK;EAC9B,QAAQpB,OAAO,CAACkC,cAAc;IAC5B,KAAK,aAAa;MAAE;QAClB,IAAI,CAACd,MAAM,CAACJ,eAAe,EAAE;UAC3B,MAAM,IAAIV,sBAAe,CAAC,8BAA8B,CAAC;QAC3D;QACA,OAAO,GAAG2B,OAAO,gBAAgBb,MAAM,CAACX,QAAQ,IAAIW,MAAM,CAACJ,eAAe,IAAII,MAAM,CAACN,OAAO,IAAIM,MAAM,CAACR,WAAW,IAAIQ,MAAM,CAACC,QAAQ,EAAE;MACzI;IACA,KAAK,YAAY;MAAE;QACjB,OAAO,GAAGY,OAAO,gBAAgBb,MAAM,CAACX,QAAQ,IAAIW,MAAM,CAACE,UAAU,IAAIF,MAAM,CAACN,OAAO,IAAIM,MAAM,CAACR,WAAW,IAAIQ,MAAM,CAACC,QAAQ,EAAE;MACpI;IACA;MACE,OAAOY,OAAO;EAClB;AACF,CAAC;AAACE,OAAA,CAAAH,eAAA,GAAAA,eAAA","ignoreList":[]}
1
+ {"version":3,"names":["_reactNative","require","_error","_native","checkForUpdate","options","__DEV__","includes","Platform","OS","onError","HotUpdaterError","currentAppVersion","getAppVersion","platform","currentBundleId","getBundleId","minBundleId","getMinBundleId","channel","getChannel","fingerprintHash","getFingerprintHash","resolver","checkUpdate","updateInfo","appVersion","bundleId","updateStrategy","requestHeaders","requestTimeout","error","updateBundle","id","fileUrl","fileHash","status"],"sourceRoot":"../../src","sources":["checkForUpdate.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AAoCA;;AAKO,eAAeG,cAAcA,CAClCC,OAAsC,EACA;EACtC,IAAIC,OAAO,EAAE;IACX,OAAO,IAAI;EACb;EAEA,IAAI,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,CAACC,QAAQ,CAACC,qBAAQ,CAACC,EAAE,CAAC,EAAE;IAC7CJ,OAAO,CAACK,OAAO,GACb,IAAIC,sBAAe,CAAC,iDAAiD,CACvE,CAAC;IACD,OAAO,IAAI;EACb;EAEA,MAAMC,iBAAiB,GAAG,IAAAC,qBAAa,EAAC,CAAC;EACzC,MAAMC,QAAQ,GAAGN,qBAAQ,CAACC,EAAuB;EACjD,MAAMM,eAAe,GAAG,IAAAC,mBAAW,EAAC,CAAC;EACrC,MAAMC,WAAW,GAAG,IAAAC,sBAAc,EAAC,CAAC;EACpC,MAAMC,OAAO,GAAG,IAAAC,kBAAU,EAAC,CAAC;EAE5B,IAAI,CAACR,iBAAiB,EAAE;IACtBP,OAAO,CAACK,OAAO,GAAG,IAAIC,sBAAe,CAAC,2BAA2B,CAAC,CAAC;IACnE,OAAO,IAAI;EACb;EAEA,MAAMU,eAAe,GAAG,IAAAC,0BAAkB,EAAC,CAAC;EAE5C,IAAI,CAACjB,OAAO,CAACkB,QAAQ,EAAEC,WAAW,EAAE;IAClCnB,OAAO,CAACK,OAAO,GACb,IAAIC,sBAAe,CAAC,yCAAyC,CAC/D,CAAC;IACD,OAAO,IAAI;EACb;EAEA,IAAIc,UAAgC,GAAG,IAAI;EAE3C,IAAI;IACFA,UAAU,GAAG,MAAMpB,OAAO,CAACkB,QAAQ,CAACC,WAAW,CAAC;MAC9CV,QAAQ;MACRY,UAAU,EAAEd,iBAAiB;MAC7Be,QAAQ,EAAEZ,eAAe;MACzBE,WAAW;MACXE,OAAO;MACPS,cAAc,EAAEvB,OAAO,CAACuB,cAAc;MACtCP,eAAe;MACfQ,cAAc,EAAExB,OAAO,CAACwB,cAAc;MACtCC,cAAc,EAAEzB,OAAO,CAACyB;IAC1B,CAAC,CAAC;EACJ,CAAC,CAAC,OAAOC,KAAK,EAAE;IACd1B,OAAO,CAACK,OAAO,GAAGqB,KAAc,CAAC;IACjC,OAAO,IAAI;EACb;EAEA,IAAI,CAACN,UAAU,EAAE;IACf,OAAO,IAAI;EACb;EAEA,OAAO;IACL,GAAGA,UAAU;IACbO,YAAY,EAAE,MAAAA,CAAA,KAAY;MACxB,OAAO,IAAAA,oBAAY,EAAC;QAClBL,QAAQ,EAAEF,UAAU,CAACQ,EAAE;QACvBC,OAAO,EAAET,UAAU,CAACS,OAAO;QAC3BC,QAAQ,EAAEV,UAAU,CAACU,QAAQ;QAC7BC,MAAM,EAAEX,UAAU,CAACW;MACrB,CAAC,CAAC;IACJ;EACF,CAAC;AACH","ignoreList":[]}
@@ -3,7 +3,51 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.HotUpdaterError = void 0;
6
+ exports.HotUpdaterErrorCode = exports.HotUpdaterError = void 0;
7
+ exports.isHotUpdaterError = isHotUpdaterError;
8
+ /**
9
+ * Hot Updater Error Codes
10
+ *
11
+ * This file defines all possible error codes that can be thrown by the native
12
+ * updateBundle function. These error codes are shared across iOS and Android
13
+ * implementations to ensure consistent error handling.
14
+ *
15
+ * Error Classification:
16
+ * - Parameter Validation: Invalid or missing function parameters
17
+ * - Bundle Storage: Errors during download, extraction, and storage
18
+ * - Signature Verification: Cryptographic verification failures (collapsed to a single public code)
19
+ * - Internal: Platform-specific or unexpected errors
20
+ *
21
+ * Retryability:
22
+ * - Retryable: DOWNLOAD_FAILED, INCOMPLETE_DOWNLOAD
23
+ * - Non-retryable: Most validation and verification errors
24
+ */
25
+ let HotUpdaterErrorCode = exports.HotUpdaterErrorCode = /*#__PURE__*/function (HotUpdaterErrorCode) {
26
+ HotUpdaterErrorCode["MISSING_BUNDLE_ID"] = "MISSING_BUNDLE_ID";
27
+ HotUpdaterErrorCode["INVALID_FILE_URL"] = "INVALID_FILE_URL";
28
+ HotUpdaterErrorCode["DIRECTORY_CREATION_FAILED"] = "DIRECTORY_CREATION_FAILED";
29
+ HotUpdaterErrorCode["DOWNLOAD_FAILED"] = "DOWNLOAD_FAILED";
30
+ HotUpdaterErrorCode["INCOMPLETE_DOWNLOAD"] = "INCOMPLETE_DOWNLOAD";
31
+ HotUpdaterErrorCode["EXTRACTION_FORMAT_ERROR"] = "EXTRACTION_FORMAT_ERROR";
32
+ HotUpdaterErrorCode["INVALID_BUNDLE"] = "INVALID_BUNDLE";
33
+ HotUpdaterErrorCode["INSUFFICIENT_DISK_SPACE"] = "INSUFFICIENT_DISK_SPACE";
34
+ HotUpdaterErrorCode["SIGNATURE_VERIFICATION_FAILED"] = "SIGNATURE_VERIFICATION_FAILED";
35
+ HotUpdaterErrorCode["MOVE_OPERATION_FAILED"] = "MOVE_OPERATION_FAILED";
36
+ HotUpdaterErrorCode["BUNDLE_IN_CRASHED_HISTORY"] = "BUNDLE_IN_CRASHED_HISTORY";
37
+ HotUpdaterErrorCode["SELF_DEALLOCATED"] = "SELF_DEALLOCATED";
38
+ HotUpdaterErrorCode["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
39
+ return HotUpdaterErrorCode;
40
+ }({});
41
+ /**
42
+ * Type guard to check if an error is a HotUpdaterError
43
+ */
44
+ function isHotUpdaterError(error) {
45
+ return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" && Object.values(HotUpdaterErrorCode).includes(error.code);
46
+ }
47
+
48
+ /**
49
+ * Base error class for Hot Updater
50
+ */
7
51
  class HotUpdaterError extends Error {
8
52
  constructor(message) {
9
53
  super(message);
@@ -1 +1 @@
1
- {"version":3,"names":["HotUpdaterError","Error","constructor","message","name","exports"],"sourceRoot":"../../src","sources":["error.ts"],"mappings":";;;;;;AAAO,MAAMA,eAAe,SAASC,KAAK,CAAC;EACzCC,WAAWA,CAACC,OAAe,EAAE;IAC3B,KAAK,CAACA,OAAO,CAAC;IACd,IAAI,CAACC,IAAI,GAAG,iBAAiB;EAC/B;AACF;AAACC,OAAA,CAAAL,eAAA,GAAAA,eAAA","ignoreList":[]}
1
+ {"version":3,"names":["HotUpdaterErrorCode","exports","isHotUpdaterError","error","code","Object","values","includes","HotUpdaterError","Error","constructor","message","name"],"sourceRoot":"../../src","sources":["error.ts"],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAhBA,IAkBYA,mBAAmB,GAAAC,OAAA,CAAAD,mBAAA,0BAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAnBA,mBAAmB;EAAA,OAAnBA,mBAAmB;AAAA;AAmH/B;AACA;AACA;AACO,SAASE,iBAAiBA,CAC/BC,KAAc,EAC2C;EACzD,OACE,OAAOA,KAAK,KAAK,QAAQ,IACzBA,KAAK,KAAK,IAAI,IACd,MAAM,IAAIA,KAAK,IACf,OAAOA,KAAK,CAACC,IAAI,KAAK,QAAQ,IAC9BC,MAAM,CAACC,MAAM,CAACN,mBAAmB,CAAC,CAACO,QAAQ,CACzCJ,KAAK,CAACC,IACR,CAAC;AAEL;;AAEA;AACA;AACA;AACO,MAAMI,eAAe,SAASC,KAAK,CAAC;EACzCC,WAAWA,CAACC,OAAe,EAAE;IAC3B,KAAK,CAACA,OAAO,CAAC;IACd,IAAI,CAACC,IAAI,GAAG,iBAAiB;EAC/B;AACF;AAACX,OAAA,CAAAO,eAAA,GAAAA,eAAA","ignoreList":[]}
@@ -4,60 +4,22 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.fetchUpdateInfo = void 0;
7
- function buildRequestHeaders(params, requestHeaders) {
8
- const updateStrategy = params.fingerprintHash ? "fingerprint" : "appVersion";
9
- return {
10
- "Content-Type": "application/json",
11
- "x-app-platform": params.platform,
12
- "x-bundle-id": params.bundleId,
13
- ...(updateStrategy === "fingerprint" ? {
14
- "x-fingerprint-hash": params.fingerprintHash
15
- } : {
16
- "x-app-version": params.appVersion
17
- }),
18
- ...(params.minBundleId && {
19
- "x-min-bundle-id": params.minBundleId
20
- }),
21
- ...(params.channel && {
22
- "x-channel": params.channel
23
- }),
24
- ...requestHeaders
25
- };
26
- }
27
- async function resolveSource(source, params) {
28
- if (typeof source !== "function") {
29
- return {
30
- url: source
31
- };
32
- }
33
- const result = source(params);
34
- if (typeof result === "string") {
35
- return {
36
- url: result
37
- };
38
- }
39
- return {
40
- info: await result
41
- };
42
- }
43
7
  const fetchUpdateInfo = async ({
44
- source,
45
- params,
8
+ url,
46
9
  requestHeaders,
47
10
  onError,
48
11
  requestTimeout = 5000
49
12
  }) => {
50
13
  try {
51
- const resolvedSource = await resolveSource(source, params);
52
- if ("info" in resolvedSource) {
53
- return resolvedSource.info;
54
- }
55
14
  const controller = new AbortController();
56
15
  const timeoutId = setTimeout(() => {
57
16
  controller.abort();
58
17
  }, requestTimeout);
59
- const headers = buildRequestHeaders(params, requestHeaders);
60
- const response = await fetch(resolvedSource.url, {
18
+ const headers = {
19
+ "Content-Type": "application/json",
20
+ ...requestHeaders
21
+ };
22
+ const response = await fetch(url, {
61
23
  signal: controller.signal,
62
24
  headers
63
25
  });
@@ -67,7 +29,7 @@ const fetchUpdateInfo = async ({
67
29
  }
68
30
  return response.json();
69
31
  } catch (error) {
70
- if (error.name === "AbortError") {
32
+ if (error instanceof Error && error.name === "AbortError") {
71
33
  onError?.(new Error("Request timed out"));
72
34
  } else {
73
35
  onError?.(error);