@otakit/capacitor-updater 2.0.0 → 2.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.
Files changed (33) hide show
  1. package/{UpdatekitUpdater.podspec → OtaKitUpdater.podspec} +1 -1
  2. package/README.md +5 -8
  3. package/android/build.gradle +1 -1
  4. package/android/src/main/java/com/{updatekit → otakit}/updater/BundleInfo.java +1 -1
  5. package/android/src/main/java/com/{updatekit → otakit}/updater/BundleStatus.java +1 -1
  6. package/android/src/main/java/com/{updatekit → otakit}/updater/BundleStore.java +1 -1
  7. package/android/src/main/java/com/{updatekit → otakit}/updater/DateUtils.java +1 -1
  8. package/android/src/main/java/com/{updatekit/updater/StatsClient.java → otakit/updater/DeviceEventClient.java} +31 -20
  9. package/android/src/main/java/com/{updatekit → otakit}/updater/HashUtils.java +1 -1
  10. package/android/src/main/java/com/{updatekit → otakit}/updater/HostedManifestKeys.java +1 -1
  11. package/android/src/main/java/com/{updatekit → otakit}/updater/ManifestClient.java +19 -9
  12. package/android/src/main/java/com/{updatekit → otakit}/updater/ManifestVerifier.java +1 -1
  13. package/android/src/main/java/com/{updatekit → otakit}/updater/UpdaterPlugin.java +74 -105
  14. package/android/src/main/java/com/{updatekit → otakit}/updater/ZipUtils.java +1 -1
  15. package/dist/esm/definitions.d.ts +12 -42
  16. package/dist/esm/definitions.d.ts.map +1 -1
  17. package/dist/esm/index.d.ts.map +1 -1
  18. package/dist/esm/index.js +2 -14
  19. package/dist/esm/index.js.map +1 -1
  20. package/dist/esm/web.d.ts +4 -9
  21. package/dist/esm/web.d.ts.map +1 -1
  22. package/dist/esm/web.js +3 -12
  23. package/dist/esm/web.js.map +1 -1
  24. package/dist/plugin.cjs.js +5 -26
  25. package/dist/plugin.cjs.js.map +1 -1
  26. package/dist/plugin.js +5 -26
  27. package/dist/plugin.js.map +1 -1
  28. package/ios/Sources/UpdaterPlugin/{StatsClient.swift → DeviceEventClient.swift} +21 -21
  29. package/ios/Sources/UpdaterPlugin/Downloader.swift +1 -1
  30. package/ios/Sources/UpdaterPlugin/ManifestClient.swift +7 -3
  31. package/ios/Sources/UpdaterPlugin/UpdaterPlugin.m +2 -5
  32. package/ios/Sources/UpdaterPlugin/UpdaterPlugin.swift +67 -104
  33. package/package.json +2 -2
@@ -19,15 +19,12 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
19
19
  public let identifier = "UpdaterPlugin"
20
20
  public let jsName = "OtaKit"
21
21
  public let pluginMethods: [CAPPluginMethod] = [
22
+ CAPPluginMethod(name: "getState", returnType: CAPPluginReturnPromise),
22
23
  CAPPluginMethod(name: "check", returnType: CAPPluginReturnPromise),
23
24
  CAPPluginMethod(name: "download", returnType: CAPPluginReturnPromise),
24
25
  CAPPluginMethod(name: "apply", returnType: CAPPluginReturnPromise),
25
- CAPPluginMethod(name: "debugGetState", returnType: CAPPluginReturnPromise),
26
26
  CAPPluginMethod(name: "notifyAppReady", returnType: CAPPluginReturnPromise),
27
- CAPPluginMethod(name: "debugReset", returnType: CAPPluginReturnPromise),
28
- CAPPluginMethod(name: "debugListBundles", returnType: CAPPluginReturnPromise),
29
- CAPPluginMethod(name: "debugDeleteBundle", returnType: CAPPluginReturnPromise),
30
- CAPPluginMethod(name: "debugGetLastFailure", returnType: CAPPluginReturnPromise),
27
+ CAPPluginMethod(name: "getLastFailure", returnType: CAPPluginReturnPromise),
31
28
  ]
32
29
 
33
30
  private let store = BundleStore()
@@ -38,7 +35,7 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
38
35
  private var appReadyTimeoutMs = 10_000
39
36
  private var allowInsecureUrls = false
40
37
  private var updateMode: UpdateMode = .nextLaunch
41
- private var updateUrl = UpdaterPlugin.defaultUpdateURL
38
+ private var ingestUrl = UpdaterPlugin.defaultIngestURL
42
39
  private var cdnUrl = UpdaterPlugin.defaultCdnURL
43
40
  private var appId: String?
44
41
  private var channel: String?
@@ -49,22 +46,21 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
49
46
  private let isCheckInProgress = NSLock()
50
47
  private var checkInProgress = false
51
48
  private var foregroundObserver: NSObjectProtocol?
52
- private static let defaultUpdateURL = "https://www.otakit.app/api/v1"
49
+ private static let defaultIngestURL = "https://ingest.otakit.app/v1"
53
50
  private static let defaultCdnURL = "https://cdn.otakit.app"
54
- private static let apiPathSuffix = "/api/v1"
51
+ private static let ingestPathSuffix = "/v1"
55
52
  private static let lastCheckTimestampKey = "otakit_last_check_timestamp"
56
53
 
57
54
  public override func load() {
58
- let envUpdateUrl = ProcessInfo.processInfo.environment["OTAKIT_SERVER_URL"]
55
+ let envIngestUrl = ProcessInfo.processInfo.environment["OTAKIT_INGEST_URL"]
59
56
  let envCdnUrl = ProcessInfo.processInfo.environment["OTAKIT_CDN_URL"]
60
- updateUrl = resolveUpdateUrl(
61
- configured: getConfig().getString("serverUrl"),
62
- env: envUpdateUrl
57
+ ingestUrl = resolveIngestUrl(
58
+ configured: getConfig().getString("ingestUrl"),
59
+ env: envIngestUrl
63
60
  )
64
61
  cdnUrl = resolveCdnUrl(
65
62
  configured: getConfig().getString("cdnUrl"),
66
- env: envCdnUrl,
67
- resolvedUpdateUrl: updateUrl
63
+ env: envCdnUrl
68
64
  )
69
65
  appId = getConfig().getString("appId")
70
66
  channel = trimToNil(getConfig().getString("channel"))
@@ -86,11 +82,11 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
86
82
  return (kid: kid, key: keyData)
87
83
  }
88
84
  if manifestKeys.isEmpty && !rawKeys.isEmpty {
89
- print("[UpdateKit] ERROR: manifestKeys configured but all entries are invalid. Manifest verification will reject all updates.")
85
+ print("[OtaKit] ERROR: manifestKeys configured but all entries are invalid. Manifest verification will reject all updates.")
90
86
  manifestKeys = [(kid: "_invalid_", key: Data())]
91
87
  }
92
88
  } else if rawKeysValue != nil {
93
- print("[UpdateKit] ERROR: manifestKeys has wrong format (expected array of {kid, key}). Manifest verification will reject all updates.")
89
+ print("[OtaKit] ERROR: manifestKeys has wrong format (expected array of {kid, key}). Manifest verification will reject all updates.")
94
90
  manifestKeys = [(kid: "_invalid_", key: Data())]
95
91
  }
96
92
 
@@ -269,7 +265,7 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
269
265
  }
270
266
  }
271
267
 
272
- @objc func debugGetState(_ call: CAPPluginCall) {
268
+ @objc func getState(_ call: CAPPluginCall) {
273
269
  let current = store.getCurrentBundle()
274
270
  let staged: [String: Any]? = {
275
271
  guard let stagedId = store.getStagedBundleId() else {
@@ -394,9 +390,10 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
394
390
  notifyListeners("appReady", data: current.toDictionary())
395
391
  }
396
392
 
397
- sendStats(
393
+ sendDeviceEvent(
398
394
  action: .applied,
399
395
  bundleVersion: current.version,
396
+ runtimeVersion: current.runtimeVersion,
400
397
  channel: current.channel,
401
398
  releaseId: current.releaseId
402
399
  )
@@ -410,58 +407,7 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
410
407
  call.resolve()
411
408
  }
412
409
 
413
- @objc func debugReset(_ call: CAPPluginCall) {
414
- cancelTrialTimeout()
415
- store.setCurrentBundleId(nil)
416
- store.setStagedBundleId(nil)
417
- store.setFallbackBundleId(nil)
418
- store.setFailedBundle(nil)
419
- applyServerBasePath(nil)
420
- call.resolve()
421
- reloadWebView()
422
- }
423
-
424
- @objc func debugListBundles(_ call: CAPPluginCall) {
425
- let bundles = store.listDownloadedBundles().map { $0.toDictionary() }
426
- call.resolve(["bundles": bundles])
427
- }
428
-
429
- @objc func debugDeleteBundle(_ call: CAPPluginCall) {
430
- guard let bundleId = call.getString("bundleId") else {
431
- call.reject("Missing bundleId")
432
- return
433
- }
434
- guard store.bundleExists(id: bundleId) else {
435
- call.reject("Bundle not found")
436
- return
437
- }
438
-
439
- let current = store.getCurrentBundle()
440
- if current.id == bundleId {
441
- call.reject("Cannot delete current bundle")
442
- return
443
- }
444
-
445
- let fallback = store.getFallbackBundle()
446
- if fallback.id == bundleId {
447
- call.reject("Cannot delete fallback bundle")
448
- return
449
- }
450
-
451
- if store.getStagedBundleId() == bundleId {
452
- call.reject("Cannot delete staged bundle")
453
- return
454
- }
455
-
456
- do {
457
- try store.deleteBundle(id: bundleId)
458
- call.resolve()
459
- } catch {
460
- call.reject("Failed to delete bundle: \(error.localizedDescription)")
461
- }
462
- }
463
-
464
- @objc func debugGetLastFailure(_ call: CAPPluginCall) {
410
+ @objc func getLastFailure(_ call: CAPPluginCall) {
465
411
  guard let failed = store.getFailedBundle() else {
466
412
  call.resolve()
467
413
  return
@@ -593,12 +539,13 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
593
539
  code: 1,
594
540
  userInfo: [NSLocalizedDescriptionKey: "Insufficient disk space"]
595
541
  )
596
- sendStats(
542
+ sendDeviceEvent(
597
543
  action: .downloadError,
598
544
  bundleVersion: version,
545
+ runtimeVersion: runtimeVersion,
599
546
  channel: channel,
600
547
  releaseId: releaseId,
601
- errorMessage: "insufficient_disk_space"
548
+ detail: "insufficient_disk_space"
602
549
  )
603
550
  throw error
604
551
  }
@@ -608,7 +555,7 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
608
555
  let zipURL = try await downloader.download(from: url)
609
556
 
610
557
  let extractDirectory = fileManager.temporaryDirectory
611
- .appendingPathComponent("updatekit-extract-\(UUID().uuidString)", isDirectory: true)
558
+ .appendingPathComponent("otakit-extract-\(UUID().uuidString)", isDirectory: true)
612
559
  defer {
613
560
  try? fileManager.removeItem(at: zipURL)
614
561
  try? fileManager.removeItem(at: extractDirectory)
@@ -659,9 +606,10 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
659
606
  cleanupSupersededStagedBundle(previousStagedId: previousStagedId, replacementId: bundleId)
660
607
 
661
608
  notifyListeners("downloadComplete", data: info.toDictionary())
662
- sendStats(
609
+ sendDeviceEvent(
663
610
  action: .downloaded,
664
611
  bundleVersion: version,
612
+ runtimeVersion: runtimeVersion,
665
613
  channel: channel,
666
614
  releaseId: releaseId
667
615
  )
@@ -671,12 +619,13 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
671
619
  "version": version,
672
620
  "error": error.localizedDescription,
673
621
  ])
674
- sendStats(
622
+ sendDeviceEvent(
675
623
  action: .downloadError,
676
624
  bundleVersion: version,
625
+ runtimeVersion: runtimeVersion,
677
626
  channel: channel,
678
627
  releaseId: releaseId,
679
- errorMessage: error.localizedDescription
628
+ detail: error.localizedDescription
680
629
  )
681
630
  throw error
682
631
  }
@@ -808,12 +757,13 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
808
757
  store.setFailedBundle(failed)
809
758
  store.setStagedBundleId(nil)
810
759
 
811
- sendStats(
760
+ sendDeviceEvent(
812
761
  action: .rollback,
813
762
  bundleVersion: current.version,
763
+ runtimeVersion: current.runtimeVersion,
814
764
  channel: current.channel,
815
765
  releaseId: current.releaseId,
816
- errorMessage: reason
766
+ detail: reason
817
767
  )
818
768
 
819
769
  let fallback = store.getFallbackBundle()
@@ -906,9 +856,7 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
906
856
  if let runtimeVersion = latest.runtimeVersion {
907
857
  payload["runtimeVersion"] = runtimeVersion
908
858
  }
909
- if let releaseId = latest.releaseId {
910
- payload["releaseId"] = releaseId
911
- }
859
+ payload["releaseId"] = latest.releaseId
912
860
  return payload
913
861
  }
914
862
 
@@ -932,9 +880,8 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
932
880
  return false
933
881
  }
934
882
 
935
- if let latestReleaseId = latest.releaseId,
936
- let bundleReleaseId = bundle.releaseId,
937
- latestReleaseId == bundleReleaseId {
883
+ if let bundleReleaseId = bundle.releaseId,
884
+ latest.releaseId == bundleReleaseId {
938
885
  return true
939
886
  }
940
887
 
@@ -1023,26 +970,41 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1023
970
  return "\(normalized)-\(suffix)"
1024
971
  }
1025
972
 
1026
- private func sendStats(
1027
- action: StatsAction,
973
+ private func sendDeviceEvent(
974
+ action: DeviceEventAction,
1028
975
  bundleVersion: String? = nil,
976
+ runtimeVersion: String? = nil,
1029
977
  channel: String? = nil,
1030
978
  releaseId: String? = nil,
1031
- errorMessage: String? = nil
979
+ detail: String? = nil
1032
980
  ) {
1033
981
  guard let appId else {
1034
982
  return
1035
983
  }
1036
- StatsClient.send(
1037
- updateUrl: updateUrl,
984
+ guard let bundleVersion = trimToNil(bundleVersion) else {
985
+ print("[OtaKit] Skipping device event without bundleVersion")
986
+ return
987
+ }
988
+ guard let releaseId = trimToNil(releaseId) else {
989
+ print("[OtaKit] Skipping device event without releaseId")
990
+ return
991
+ }
992
+ let nativeBuild = store.nativeBuild.trimmingCharacters(in: .whitespacesAndNewlines)
993
+ guard !nativeBuild.isEmpty else {
994
+ print("[OtaKit] Skipping device event without nativeBuild")
995
+ return
996
+ }
997
+ DeviceEventClient.send(
998
+ ingestUrl: ingestUrl,
1038
999
  appId: appId,
1039
1000
  platform: "ios",
1040
1001
  action: action,
1041
1002
  bundleVersion: bundleVersion,
1042
1003
  channel: channel,
1004
+ runtimeVersion: trimToNil(runtimeVersion),
1043
1005
  releaseId: releaseId,
1044
- nativeBuild: store.nativeBuild,
1045
- errorMessage: errorMessage
1006
+ nativeBuild: nativeBuild,
1007
+ detail: detail
1046
1008
  )
1047
1009
  }
1048
1010
 
@@ -1061,21 +1023,27 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1061
1023
  return trimmed.isEmpty ? nil : trimmed
1062
1024
  }
1063
1025
 
1064
- private func resolveUpdateUrl(configured: String?, env: String?) -> String {
1026
+ private func resolveIngestUrl(
1027
+ configured: String?,
1028
+ env: String?
1029
+ ) -> String {
1065
1030
  let configuredValue = configured?.trimmingCharacters(in: .whitespacesAndNewlines)
1066
1031
  if let configuredValue, !configuredValue.isEmpty {
1067
- return normalizeUpdateUrl(configuredValue)
1032
+ return normalizeIngestUrl(configuredValue)
1068
1033
  }
1069
1034
 
1070
1035
  let envValue = env?.trimmingCharacters(in: .whitespacesAndNewlines)
1071
1036
  if let envValue, !envValue.isEmpty {
1072
- return normalizeUpdateUrl(envValue)
1037
+ return normalizeIngestUrl(envValue)
1073
1038
  }
1074
1039
 
1075
- return UpdaterPlugin.defaultUpdateURL
1040
+ return UpdaterPlugin.defaultIngestURL
1076
1041
  }
1077
1042
 
1078
- private func resolveCdnUrl(configured: String?, env: String?, resolvedUpdateUrl: String) -> String {
1043
+ private func resolveCdnUrl(
1044
+ configured: String?,
1045
+ env: String?
1046
+ ) -> String {
1079
1047
  let configuredValue = configured?.trimmingCharacters(in: .whitespacesAndNewlines)
1080
1048
  if let configuredValue, !configuredValue.isEmpty {
1081
1049
  return normalizeCdnUrl(configuredValue)
@@ -1086,15 +1054,10 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1086
1054
  return normalizeCdnUrl(envValue)
1087
1055
  }
1088
1056
 
1089
- if resolvedUpdateUrl.lowercased() != UpdaterPlugin.defaultUpdateURL.lowercased(),
1090
- resolvedUpdateUrl.lowercased().hasSuffix(UpdaterPlugin.apiPathSuffix) {
1091
- return String(resolvedUpdateUrl.dropLast(UpdaterPlugin.apiPathSuffix.count))
1092
- }
1093
-
1094
1057
  return UpdaterPlugin.defaultCdnURL
1095
1058
  }
1096
1059
 
1097
- private func normalizeUpdateUrl(_ raw: String) -> String {
1060
+ private func normalizeIngestUrl(_ raw: String) -> String {
1098
1061
  let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
1099
1062
  let withoutTrailingSlash = trimmed.replacingOccurrences(
1100
1063
  of: "/+$",
@@ -1102,11 +1065,11 @@ public class UpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
1102
1065
  options: .regularExpression
1103
1066
  )
1104
1067
 
1105
- if withoutTrailingSlash.lowercased().hasSuffix(UpdaterPlugin.apiPathSuffix) {
1068
+ if withoutTrailingSlash.lowercased().hasSuffix(UpdaterPlugin.ingestPathSuffix) {
1106
1069
  return withoutTrailingSlash
1107
1070
  }
1108
1071
 
1109
- return withoutTrailingSlash + UpdaterPlugin.apiPathSuffix
1072
+ return withoutTrailingSlash + UpdaterPlugin.ingestPathSuffix
1110
1073
  }
1111
1074
 
1112
1075
  private func normalizeCdnUrl(_ raw: String) -> String {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otakit/capacitor-updater",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Capacitor plugin for OTA updates",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -16,7 +16,7 @@
16
16
  "dist/",
17
17
  "ios/Sources/",
18
18
  "ios/Tests/",
19
- "UpdatekitUpdater.podspec"
19
+ "OtaKitUpdater.podspec"
20
20
  ],
21
21
  "author": "OtaKit",
22
22
  "license": "MIT",