@capawesome/capacitor-live-update 8.1.0 → 8.2.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 (28) hide show
  1. package/README.md +122 -15
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdate.java +80 -0
  4. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdateHttpClient.java +12 -1
  5. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePlugin.java +31 -1
  6. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/api/GetChannelsResponseItem.java +28 -0
  7. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/options/FetchChannelsOptions.java +38 -0
  8. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/results/ChannelResult.java +28 -0
  9. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/results/FetchChannelsResult.java +28 -0
  10. package/dist/docs.json +152 -4
  11. package/dist/esm/definitions.d.ts +85 -2
  12. package/dist/esm/definitions.js.map +1 -1
  13. package/dist/esm/web.d.ts +2 -1
  14. package/dist/esm/web.js +3 -0
  15. package/dist/esm/web.js.map +1 -1
  16. package/dist/plugin.cjs.js +3 -0
  17. package/dist/plugin.cjs.js.map +1 -1
  18. package/dist/plugin.js +3 -0
  19. package/dist/plugin.js.map +1 -1
  20. package/ios/Plugin/Classes/Options/FetchChannelsOptions.swift +26 -0
  21. package/ios/Plugin/Classes/Results/ChannelResult.swift +19 -0
  22. package/ios/Plugin/Classes/Results/FetchChannelsResult.swift +16 -0
  23. package/ios/Plugin/Enums/CustomError.swift +3 -0
  24. package/ios/Plugin/LiveUpdate.swift +43 -0
  25. package/ios/Plugin/LiveUpdateHttpClient.swift +11 -0
  26. package/ios/Plugin/LiveUpdatePlugin.swift +21 -1
  27. package/ios/Plugin/Protocols/Api/GetChannelsResponseItem.swift +4 -0
  28. package/package.json +1 -3
@@ -6,6 +6,7 @@ public enum CustomError: Error {
6
6
  case bundleIdMissing
7
7
  case bundleIndexHtmlMissing
8
8
  case bundleNotFound
9
+ case channelDiscoveryNotEnabled
9
10
  case channelMissing
10
11
  case checksumCalculationFailed
11
12
  case checksumMismatch
@@ -32,6 +33,8 @@ extension CustomError: LocalizedError {
32
33
  return NSLocalizedString("The bundle does not contain an index.html file.", comment: "bundleIndexHtmlMissing")
33
34
  case .bundleNotFound:
34
35
  return NSLocalizedString("bundle not found.", comment: "bundleNotFound")
36
+ case .channelDiscoveryNotEnabled:
37
+ return NSLocalizedString("Unauthorized. Channel Discovery may not be enabled for this app.", comment: "channelDiscoveryNotEnabled")
35
38
  case .channelMissing:
36
39
  return NSLocalizedString("channel must be provided.", comment: "channelMissing")
37
40
  case .checksumCalculationFailed:
@@ -34,6 +34,9 @@ import CommonCrypto
34
34
  // Check version and reset config if version changed
35
35
  checkAndResetConfigIfVersionChanged()
36
36
 
37
+ // Set the device ID on the HTTP client (after any potential config reset)
38
+ self.httpClient.setDeviceId(getDeviceId())
39
+
37
40
  // Start the rollback timer to rollback to the default bundle
38
41
  // if the app is not ready after a certain time
39
42
  startRollbackTimer()
@@ -80,6 +83,39 @@ import CommonCrypto
80
83
  }
81
84
  }
82
85
 
86
+ @objc public func fetchChannels(_ options: FetchChannelsOptions) async throws -> FetchChannelsResult {
87
+ var parameters = [String: String]()
88
+ if let limit = options.getLimit() {
89
+ parameters["limit"] = String(limit)
90
+ }
91
+ if let offset = options.getOffset() {
92
+ parameters["offset"] = String(offset)
93
+ }
94
+ if let query = options.getQuery() {
95
+ parameters["query"] = query
96
+ }
97
+ var urlComponents = URLComponents(string: "https://\(config.serverDomain)/v1/apps/\(getAppId() ?? "")/channels")!
98
+ if !parameters.isEmpty {
99
+ urlComponents.queryItems = parameters.map { URLQueryItem(name: $0.key, value: $0.value) }
100
+ }
101
+ let url = try urlComponents.asURL()
102
+ let response = try await self.httpClient.request(url: url, type: [GetChannelsResponseItem].self)
103
+ if let error = response.error {
104
+ if response.response?.statusCode == 401 {
105
+ throw CustomError.channelDiscoveryNotEnabled
106
+ }
107
+ if let urlError = error.underlyingError as? URLError {
108
+ if urlError.code == .timedOut {
109
+ throw urlError
110
+ }
111
+ }
112
+ throw error
113
+ }
114
+ let items = response.value ?? []
115
+ let channels = items.map { ChannelResult(id: $0.id, name: $0.name) }
116
+ return FetchChannelsResult(channels: channels)
117
+ }
118
+
83
119
  @objc public func fetchLatestBundle(_ options: FetchLatestBundleOptions) async throws -> FetchLatestBundleResult {
84
120
  let response: GetLatestBundleResponse? = try await self.fetchLatestBundle(options)
85
121
  return FetchLatestBundleResult(artifactType: response?.artifactType, bundleId: response?.bundleId, checksum: response?.checksum, customProperties: response?.customProperties, downloadUrl: response?.url, signature: response?.signature)
@@ -604,12 +640,19 @@ import CommonCrypto
604
640
  if let _ = config.defaultChannel {
605
641
  channel = config.defaultChannel
606
642
  }
643
+ if let nativeChannel = getNativeChannel() {
644
+ channel = nativeChannel
645
+ }
607
646
  if let _ = preferences.getChannel() {
608
647
  channel = preferences.getChannel()
609
648
  }
610
649
  return channel
611
650
  }
612
651
 
652
+ private func getNativeChannel() -> String? {
653
+ return Bundle.main.object(forInfoDictionaryKey: "CapawesomeLiveUpdateDefaultChannel") as? String
654
+ }
655
+
613
656
  /// - Returns: The sha256 checksum of the file at the given URL.
614
657
  private func getChecksumForFile(url: URL) throws -> String {
615
658
  let handle = try FileHandle(forReadingFrom: url)
@@ -5,6 +5,7 @@ import Alamofire
5
5
  public class LiveUpdateHttpClient: NSObject {
6
6
 
7
7
  private let config: LiveUpdateConfig
8
+ private var deviceId: String?
8
9
 
9
10
  public static func getChecksumFromResponse(response: HTTPURLResponse) -> String? {
10
11
  guard let headers = response.allHeaderFields as? [String: String] else { return nil }
@@ -20,10 +21,17 @@ public class LiveUpdateHttpClient: NSObject {
20
21
  self.config = config
21
22
  }
22
23
 
24
+ public func setDeviceId(_ deviceId: String) {
25
+ self.deviceId = deviceId
26
+ }
27
+
23
28
  public func download(url: URL, destination: @escaping DownloadRequest.Destination, callback: ((Progress) -> Void)?) async throws -> AFDownloadResponse<Data> {
24
29
  var request = URLRequest(url: url)
25
30
  request.httpMethod = HTTPMethod.get.rawValue
26
31
  request.timeoutInterval = Double(config.httpTimeout) / 1000.0
32
+ if let deviceId = deviceId, !deviceId.isEmpty {
33
+ request.setValue(deviceId, forHTTPHeaderField: "X-Capawesome-Device-Id")
34
+ }
27
35
  return try await withCheckedThrowingContinuation { continuation in
28
36
  AF.download(request, to: destination).downloadProgress { progress in
29
37
  if let callback = callback {
@@ -39,6 +47,9 @@ public class LiveUpdateHttpClient: NSObject {
39
47
  var request = URLRequest(url: url)
40
48
  request.httpMethod = HTTPMethod.get.rawValue
41
49
  request.timeoutInterval = Double(config.httpTimeout) / 1000.0
50
+ if let deviceId = deviceId, !deviceId.isEmpty {
51
+ request.setValue(deviceId, forHTTPHeaderField: "X-Capawesome-Device-Id")
52
+ }
42
53
  return try await withCheckedThrowingContinuation { continuation in
43
54
  AF.request(request).validate().responseDecodable(of: type) { response in
44
55
  continuation.resume(returning: response)
@@ -8,7 +8,7 @@ import Capacitor
8
8
  @objc(LiveUpdatePlugin)
9
9
  public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
10
10
  public static let tag = "LiveUpdate"
11
- public static let version = "8.1.0"
11
+ public static let version = "8.2.0"
12
12
  public static let userDefaultsPrefix = "CapawesomeLiveUpdate" // DO NOT CHANGE
13
13
 
14
14
  public let identifier = "LiveUpdatePlugin"
@@ -17,6 +17,7 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
17
17
  CAPPluginMethod(name: "clearBlockedBundles", returnType: CAPPluginReturnPromise),
18
18
  CAPPluginMethod(name: "deleteBundle", returnType: CAPPluginReturnPromise),
19
19
  CAPPluginMethod(name: "downloadBundle", returnType: CAPPluginReturnPromise),
20
+ CAPPluginMethod(name: "fetchChannels", returnType: CAPPluginReturnPromise),
20
21
  CAPPluginMethod(name: "fetchLatestBundle", returnType: CAPPluginReturnPromise),
21
22
  CAPPluginMethod(name: "getBlockedBundles", returnType: CAPPluginReturnPromise),
22
23
  CAPPluginMethod(name: "getBundles", returnType: CAPPluginReturnPromise),
@@ -111,6 +112,25 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
111
112
  }
112
113
  }
113
114
 
115
+ @objc func fetchChannels(_ call: CAPPluginCall) {
116
+ Task {
117
+ do {
118
+ guard let appId = config?.appId, !appId.isEmpty else {
119
+ call.reject(CustomError.appIdMissing.localizedDescription)
120
+ return
121
+ }
122
+
123
+ let options = FetchChannelsOptions(call)
124
+ let result = try await implementation?.fetchChannels(options)
125
+ if let result = result?.toJSObject() as? JSObject {
126
+ self.resolveCall(call, result)
127
+ }
128
+ } catch {
129
+ rejectCall(call, error)
130
+ }
131
+ }
132
+ }
133
+
114
134
  @objc func fetchLatestBundle(_ call: CAPPluginCall) {
115
135
  Task {
116
136
  do {
@@ -0,0 +1,4 @@
1
+ public struct GetChannelsResponseItem: Codable {
2
+ var id: String
3
+ var name: String
4
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capawesome/capacitor-live-update",
3
- "version": "8.1.0",
3
+ "version": "8.2.0",
4
4
  "description": "Capacitor plugin to update your app remotely in real-time.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -71,7 +71,6 @@
71
71
  "@capacitor/docgen": "0.3.1",
72
72
  "@capacitor/ios": "8.0.0",
73
73
  "@ionic/eslint-config": "0.4.0",
74
- "@ionic/swiftlint-config": "2.0.0",
75
74
  "eslint": "8.57.0",
76
75
  "prettier": "3.4.2",
77
76
  "prettier-plugin-java": "2.6.7",
@@ -83,7 +82,6 @@
83
82
  "peerDependencies": {
84
83
  "@capacitor/core": ">=8.0.0"
85
84
  },
86
- "swiftlint": "@ionic/swiftlint-config",
87
85
  "eslintConfig": {
88
86
  "extends": "@ionic/eslint-config/recommended"
89
87
  },