@capgo/capacitor-updater 8.51.0 → 8.51.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.
@@ -39,7 +39,9 @@ import java.security.SecureRandom;
39
39
  import java.util.ArrayList;
40
40
  import java.util.Date;
41
41
  import java.util.HashMap;
42
+ import java.util.HashSet;
42
43
  import java.util.Iterator;
44
+ import java.util.LinkedHashSet;
43
45
  import java.util.List;
44
46
  import java.util.Map;
45
47
  import java.util.Objects;
@@ -72,14 +74,20 @@ public class CapgoUpdater {
72
74
  private static final String FALLBACK_VERSION = "pastVersion";
73
75
  private static final String NEXT_VERSION = "nextVersion";
74
76
  private static final String PREVIEW_FALLBACK_VERSION = "previewFallbackVersion";
77
+ private static final String PENDING_DELETE_IDS = "pendingDeleteIds";
75
78
  private static final String bundleDirectory = "versions";
76
79
  private static final String TEMP_UNZIP_PREFIX = "capgo_unzip_";
80
+ private static final long DELETE_PACE_MS = 75L;
81
+ private final Object deleteLock = new Object();
77
82
  private static final String CAPACITOR_CONFIG_ASSET = "capacitor.config.json";
78
83
  private static final String BACKGROUND_RUNNER_CONFIG_KEY = "BackgroundRunner";
79
84
  private static final String BACKGROUND_RUNNER_WORKER_CLASS = "io.ionic.backgroundrunner.plugin.RunnerWorker";
80
85
 
81
86
  public static final String TAG = "Capacitor-updater";
82
87
  public SharedPreferences.Editor editor;
88
+
89
+ /** Optional gate run before any download touches disk (e.g. wait for launch cleanup). */
90
+ public Runnable downloadGate = null;
83
91
  public SharedPreferences prefs;
84
92
 
85
93
  public File documentsDir;
@@ -136,7 +144,7 @@ public class CapgoUpdater {
136
144
 
137
145
  private final FilenameFilter filter = (f, name) -> {
138
146
  // ignore directories generated by mac os x
139
- return (!name.startsWith("__MACOSX") && !name.startsWith(".") && !name.startsWith(".DS_Store"));
147
+ return !name.startsWith("__MACOSX") && !name.startsWith(".") && !name.startsWith(".DS_Store");
140
148
  };
141
149
 
142
150
  private boolean isProd() {
@@ -927,6 +935,11 @@ public class CapgoUpdater {
927
935
 
928
936
  try {
929
937
  this.deleteDirectory(entry, threadToCheck);
938
+ if (entry.exists()) {
939
+ logger.error("Orphan bundle directory still present after delete");
940
+ logger.debug("Bundle ID: " + id);
941
+ continue;
942
+ }
930
943
  this.removeBundleInfo(id);
931
944
  logger.info("Deleted orphan bundle directory");
932
945
  logger.debug("Bundle ID: " + id);
@@ -938,6 +951,43 @@ public class CapgoUpdater {
938
951
  }
939
952
  }
940
953
 
954
+ public Set<String> allowedBundleIdsForCleanup() {
955
+ final Set<String> allowedIds = new HashSet<>();
956
+ for (final BundleInfo info : this.list(true)) {
957
+ if (info == null || info.getId() == null || info.getId().isEmpty()) {
958
+ continue;
959
+ }
960
+ // DELETED tombstones must not protect leftover folders.
961
+ // DELETING stays protected so drainPendingDeletes owns the removal.
962
+ if (info.isDeleted()) {
963
+ continue;
964
+ }
965
+ allowedIds.add(info.getId());
966
+ }
967
+ final String currentId = this.getCurrentBundleId();
968
+ if (currentId != null && !currentId.isEmpty()) {
969
+ allowedIds.add(currentId);
970
+ }
971
+ final BundleInfo fallback = this.getFallbackBundle();
972
+ if (fallback != null && fallback.getId() != null && !fallback.getId().isEmpty() && !fallback.isDeleting()) {
973
+ allowedIds.add(fallback.getId());
974
+ }
975
+ final BundleInfo next = this.getNextBundle();
976
+ if (next != null && next.getId() != null && !next.getId().isEmpty() && !next.isDeleting()) {
977
+ allowedIds.add(next.getId());
978
+ }
979
+ final BundleInfo previewFallback = this.getPreviewFallbackBundle();
980
+ if (
981
+ previewFallback != null &&
982
+ previewFallback.getId() != null &&
983
+ !previewFallback.getId().isEmpty() &&
984
+ !previewFallback.isDeleting()
985
+ ) {
986
+ allowedIds.add(previewFallback.getId());
987
+ }
988
+ return allowedIds;
989
+ }
990
+
941
991
  public void cleanupOrphanedTempFolders(final Thread threadToCheck) {
942
992
  if (this.documentsDir == null) {
943
993
  logger.warn("Documents directory is null, skipping temp folder cleanup");
@@ -1221,6 +1271,27 @@ public class CapgoUpdater {
1221
1271
  );
1222
1272
  }
1223
1273
 
1274
+ private void runDownloadGate() throws IOException {
1275
+ if (this.downloadGate == null) {
1276
+ return;
1277
+ }
1278
+ try {
1279
+ this.downloadGate.run();
1280
+ } catch (final RuntimeException e) {
1281
+ throw new IOException(e.getMessage() == null ? "Download gate failed" : e.getMessage(), e);
1282
+ }
1283
+ }
1284
+
1285
+ private boolean runDownloadGateQuiet() {
1286
+ try {
1287
+ this.runDownloadGate();
1288
+ return true;
1289
+ } catch (final IOException e) {
1290
+ logger.error("Download blocked by cleanup gate: " + e.getMessage());
1291
+ return false;
1292
+ }
1293
+ }
1294
+
1224
1295
  public void downloadBackground(
1225
1296
  final String url,
1226
1297
  final String version,
@@ -1239,6 +1310,9 @@ public class CapgoUpdater {
1239
1310
  final JSONArray manifest,
1240
1311
  final boolean setNext
1241
1312
  ) {
1313
+ if (!this.runDownloadGateQuiet()) {
1314
+ return;
1315
+ }
1242
1316
  final String id = this.randomString();
1243
1317
 
1244
1318
  // Check if version is already downloading, but allow retry if previous download failed
@@ -1263,9 +1337,10 @@ public class CapgoUpdater {
1263
1337
  }
1264
1338
 
1265
1339
  public BundleInfo download(final String url, final String version, final String sessionKey, final String checksum) throws IOException {
1340
+ this.runDownloadGate();
1266
1341
  // Check for existing bundle with same version and clean up if in error state
1267
1342
  BundleInfo existingBundle = this.getBundleInfoByName(version);
1268
- if (existingBundle != null && (existingBundle.isErrorStatus() || existingBundle.isDeleted())) {
1343
+ if (existingBundle != null && (existingBundle.isErrorStatus() || existingBundle.isDeleted() || existingBundle.isDeleting())) {
1269
1344
  logger.info("Found existing failed bundle for version " + version + ", deleting before retry");
1270
1345
  this.delete(existingBundle.getId(), true);
1271
1346
  }
@@ -1311,13 +1386,14 @@ public class CapgoUpdater {
1311
1386
  final String checksum,
1312
1387
  final JSONArray manifest
1313
1388
  ) throws IOException {
1389
+ this.runDownloadGate();
1314
1390
  if (manifest == null) {
1315
1391
  return download(url, version, sessionKey, checksum);
1316
1392
  }
1317
1393
 
1318
1394
  // Check for existing bundle with same version and clean up if in error state
1319
1395
  BundleInfo existingBundle = this.getBundleInfoByName(version);
1320
- if (existingBundle != null && (existingBundle.isErrorStatus() || existingBundle.isDeleted())) {
1396
+ if (existingBundle != null && (existingBundle.isErrorStatus() || existingBundle.isDeleted() || existingBundle.isDeleting())) {
1321
1397
  logger.info("Found existing failed bundle for version " + version + ", deleting before retry");
1322
1398
  this.delete(existingBundle.getId(), true);
1323
1399
  }
@@ -1384,51 +1460,93 @@ public class CapgoUpdater {
1384
1460
  }
1385
1461
 
1386
1462
  public Boolean delete(final String id, final Boolean removeInfo) throws IOException {
1387
- final BundleInfo deleted = this.getBundleInfo(id);
1388
- if (deleted.isBuiltin() || this.getCurrentBundleId().equals(id)) {
1389
- logger.error("Cannot delete current or builtin bundle");
1390
- logger.debug("Bundle ID: " + id);
1391
- return false;
1392
- }
1393
- final BundleInfo previewFallback = this.getPreviewFallbackBundle();
1394
- if (
1395
- previewFallback != null &&
1396
- !previewFallback.isDeleted() &&
1397
- !previewFallback.isErrorStatus() &&
1398
- previewFallback.getId().equals(id)
1399
- ) {
1400
- logger.error("Cannot delete the preview fallback bundle");
1401
- logger.debug("Bundle ID: " + id);
1402
- return false;
1403
- }
1404
- final BundleInfo next = this.getNextBundle();
1405
- if (next != null && !next.isDeleted() && !next.isErrorStatus() && next.getId().equals(id)) {
1406
- logger.error("Cannot delete the next bundle");
1407
- logger.debug("Bundle ID: " + id);
1408
- return false;
1409
- }
1410
- // Cancel download for this version if active
1411
- if (this.activity != null) {
1412
- DownloadWorkerManager.cancelVersionDownload(this.activity, deleted.getVersionName());
1413
- }
1414
- final File bundle = new File(this.documentsDir, bundleDirectory + "/" + id);
1415
- if (bundle.exists()) {
1416
- this.deleteDirectory(bundle);
1417
- if (!removeInfo) {
1418
- this.saveBundleInfo(id, deleted.setStatus(BundleStatus.DELETED));
1463
+ return this.delete(id, removeInfo, true);
1464
+ }
1465
+
1466
+ public Boolean delete(final String id, final Boolean removeInfo, final boolean cancelActiveDownload) throws IOException {
1467
+ synchronized (this.deleteLock) {
1468
+ final BundleInfo deleted = this.getBundleInfo(id);
1469
+ if (deleted.isBuiltin() || this.getCurrentBundleId().equals(id)) {
1470
+ logger.error("Cannot delete current or builtin bundle");
1471
+ logger.debug("Bundle ID: " + id);
1472
+ return false;
1473
+ }
1474
+ final BundleInfo previewFallback = this.getPreviewFallbackBundle();
1475
+ if (
1476
+ previewFallback != null &&
1477
+ !previewFallback.isDeleted() &&
1478
+ !previewFallback.isErrorStatus() &&
1479
+ !previewFallback.isDeleting() &&
1480
+ previewFallback.getId().equals(id)
1481
+ ) {
1482
+ logger.error("Cannot delete the preview fallback bundle");
1483
+ logger.debug("Bundle ID: " + id);
1484
+ return false;
1485
+ }
1486
+ final BundleInfo next = this.getNextBundle();
1487
+ if (next != null && !next.isDeleted() && !next.isErrorStatus() && !next.isDeleting() && next.getId().equals(id)) {
1488
+ logger.error("Cannot delete the next bundle");
1489
+ logger.debug("Bundle ID: " + id);
1490
+ return false;
1491
+ }
1492
+
1493
+ final File bundle = this.getBundleDirectory(id);
1494
+ final boolean hadRegistry = this.hasStoredBundleInfo(id);
1495
+ final boolean hadFolder = bundle.exists();
1496
+ if (!hadRegistry && !hadFolder) {
1497
+ logger.error("Cannot delete unknown bundle");
1498
+ logger.debug("Bundle ID: " + id);
1499
+ return false;
1500
+ }
1501
+
1502
+ // Persist DELETING before touching disk so kill/OOM can resume on next launch.
1503
+ if (!deleted.isDeleting()) {
1504
+ if (!this.saveBundleInfo(id, deleted.setStatus(BundleStatus.DELETING))) {
1505
+ logger.error("Failed to persist DELETING marker, aborting disk delete");
1506
+ logger.debug("Bundle ID: " + id);
1507
+ return false;
1508
+ }
1509
+ }
1510
+
1511
+ // Cancel download for this version if active
1512
+ if (cancelActiveDownload && this.activity != null) {
1513
+ DownloadWorkerManager.cancelVersionDownload(this.activity, deleted.getVersionName());
1514
+ }
1515
+
1516
+ if (bundle.exists()) {
1517
+ try {
1518
+ this.deleteDirectory(bundle);
1519
+ } catch (final IOException e) {
1520
+ logger.error("Failed to delete bundle folder, will retry later");
1521
+ logger.debug("Bundle ID: " + id + ", Error: " + e.getMessage());
1522
+ return false;
1523
+ }
1524
+ }
1525
+
1526
+ // Only drop registry after the folder is confirmed gone.
1527
+ if (bundle.exists()) {
1528
+ logger.error("Bundle folder still present after delete, will retry later");
1529
+ logger.debug("Bundle ID: " + id);
1530
+ return false;
1531
+ }
1532
+
1533
+ final boolean finalized;
1534
+ if (Boolean.FALSE.equals(removeInfo)) {
1535
+ finalized = this.saveBundleInfo(id, deleted.setStatus(BundleStatus.DELETED));
1419
1536
  } else {
1420
- this.removeBundleInfo(id);
1537
+ finalized = this.saveBundleInfo(id, null);
1538
+ }
1539
+ if (!finalized) {
1540
+ logger.error("Failed to finalize delete registry update, will retry later");
1541
+ logger.debug("Bundle ID: " + id);
1542
+ return false;
1421
1543
  }
1544
+ this.sendStats("delete", deleted.getVersionName());
1545
+ this.dequeuePendingDelete(id);
1546
+ logger.info("Bundle deleted and confirmed gone");
1547
+ logger.debug("Bundle ID: " + id);
1422
1548
  return true;
1423
1549
  }
1424
- logger.info("Bundle not found on disk");
1425
- logger.debug("Version: " + deleted.getVersionName());
1426
- // perhaps we did not find the bundle in the files, but if the user requested a delete, we delete
1427
- if (removeInfo) {
1428
- this.removeBundleInfo(id);
1429
- }
1430
- this.sendStats("delete", deleted.getVersionName());
1431
- return false;
1432
1550
  }
1433
1551
 
1434
1552
  public Boolean delete(final String id) {
@@ -1441,6 +1559,82 @@ public class CapgoUpdater {
1441
1559
  }
1442
1560
  }
1443
1561
 
1562
+ /**
1563
+ * Resume incomplete deletes one-by-one. Safe across app kill / OOM because
1564
+ * delete() marks DELETING before disk work and only clears registry after confirm.
1565
+ */
1566
+ public void drainPendingDeletes() {
1567
+ final LinkedHashSet<String> pendingIds = new LinkedHashSet<>();
1568
+ for (final BundleInfo info : this.list(true)) {
1569
+ if (info != null && info.isDeleting() && info.getId() != null && !info.getId().isEmpty()) {
1570
+ pendingIds.add(info.getId());
1571
+ }
1572
+ }
1573
+ pendingIds.addAll(this.getPendingDeleteIds());
1574
+ for (final String id : pendingIds) {
1575
+ try {
1576
+ logger.info("Resuming pending delete for bundle: " + id);
1577
+ if (Boolean.TRUE.equals(this.delete(id, true))) {
1578
+ this.dequeuePendingDelete(id);
1579
+ }
1580
+ } catch (final Exception e) {
1581
+ logger.error("Pending delete failed, will retry next launch");
1582
+ logger.debug("Bundle ID: " + id + ", Error: " + e.getMessage());
1583
+ }
1584
+ try {
1585
+ Thread.sleep(DELETE_PACE_MS);
1586
+ } catch (final InterruptedException ie) {
1587
+ Thread.currentThread().interrupt();
1588
+ return;
1589
+ }
1590
+ }
1591
+ }
1592
+
1593
+ private Set<String> getPendingDeleteIds() {
1594
+ final Set<String> ids = new LinkedHashSet<>();
1595
+ if (this.prefs == null) {
1596
+ return ids;
1597
+ }
1598
+ final String raw = this.prefs.getString(PENDING_DELETE_IDS, "");
1599
+ if (raw == null || raw.isEmpty()) {
1600
+ return ids;
1601
+ }
1602
+ for (final String part : raw.split(",")) {
1603
+ if (part != null && !part.isEmpty()) {
1604
+ ids.add(part);
1605
+ }
1606
+ }
1607
+ return ids;
1608
+ }
1609
+
1610
+ private void enqueuePendingDelete(final String id) {
1611
+ if (id == null || id.isEmpty() || this.editor == null || this.prefs == null) {
1612
+ return;
1613
+ }
1614
+ final Set<String> ids = this.getPendingDeleteIds();
1615
+ if (!ids.add(id)) {
1616
+ return;
1617
+ }
1618
+ this.editor.putString(PENDING_DELETE_IDS, String.join(",", ids));
1619
+ this.editor.commit();
1620
+ }
1621
+
1622
+ private void dequeuePendingDelete(final String id) {
1623
+ if (id == null || id.isEmpty() || this.editor == null || this.prefs == null) {
1624
+ return;
1625
+ }
1626
+ final Set<String> ids = this.getPendingDeleteIds();
1627
+ if (!ids.remove(id)) {
1628
+ return;
1629
+ }
1630
+ if (ids.isEmpty()) {
1631
+ this.editor.remove(PENDING_DELETE_IDS);
1632
+ } else {
1633
+ this.editor.putString(PENDING_DELETE_IDS, String.join(",", ids));
1634
+ }
1635
+ this.editor.commit();
1636
+ }
1637
+
1444
1638
  private File getBundleDirectory(final String id) {
1445
1639
  return new File(this.documentsDir, bundleDirectory + "/" + id);
1446
1640
  }
@@ -1448,7 +1642,13 @@ public class CapgoUpdater {
1448
1642
  private boolean bundleExists(final String id) {
1449
1643
  final File bundle = this.getBundleDirectory(id);
1450
1644
  final BundleInfo bundleInfo = this.getBundleInfo(id);
1451
- return (bundle.isDirectory() && bundle.exists() && new File(bundle.getPath(), "/index.html").exists() && !bundleInfo.isDeleted());
1645
+ return (
1646
+ bundle.isDirectory() &&
1647
+ bundle.exists() &&
1648
+ new File(bundle.getPath(), "/index.html").exists() &&
1649
+ !bundleInfo.isDeleted() &&
1650
+ !bundleInfo.isDeleting()
1651
+ );
1452
1652
  }
1453
1653
 
1454
1654
  static final class ResetState {
@@ -1627,21 +1827,51 @@ public class CapgoUpdater {
1627
1827
  // Only attempt to delete when the fallback is a different bundle than the
1628
1828
  // currently loaded one. Otherwise we spam logs with "Cannot delete <id>"
1629
1829
  // because delete() protects the current bundle from removal.
1630
- if (
1631
- autoDeletePrevious &&
1830
+ final String previousFallbackId = fallback.getId();
1831
+ final String previousFallbackVersion = fallback.getVersionName();
1832
+ final BundleInfo nextBundle = this.getNextBundle();
1833
+ final boolean previousIsNext =
1834
+ nextBundle != null &&
1835
+ previousFallbackId != null &&
1836
+ previousFallbackId.equals(nextBundle.getId()) &&
1837
+ !nextBundle.isDeleted() &&
1838
+ !nextBundle.isErrorStatus() &&
1839
+ !nextBundle.isDeleting();
1840
+ final boolean shouldDeletePrevious =
1841
+ Boolean.TRUE.equals(autoDeletePrevious) &&
1632
1842
  !fallback.isBuiltin() &&
1633
- fallback.getId() != null &&
1634
- !fallback.getId().equals(bundle.getId()) &&
1635
- !fallbackIsPreviewFallback
1636
- ) {
1637
- final Boolean res = this.delete(fallback.getId());
1638
- if (res) {
1639
- logger.info("Deleted previous bundle: " + fallback.getVersionName());
1640
- } else {
1641
- logger.debug("Skip deleting previous bundle (same as current or protected): " + fallback.getId());
1843
+ previousFallbackId != null &&
1844
+ !previousFallbackId.equals(bundle.getId()) &&
1845
+ !fallbackIsPreviewFallback &&
1846
+ !previousIsNext;
1847
+ if (shouldDeletePrevious) {
1848
+ // Cancel any in-flight download for the old version before the async boundary
1849
+ // so a later download of the same version name is not cancelled mid-flight.
1850
+ if (this.activity != null) {
1851
+ DownloadWorkerManager.cancelVersionDownload(this.activity, previousFallbackVersion);
1852
+ }
1853
+ // Mark durable intent before fallback switch so a kill mid-flight still retries.
1854
+ if (!this.saveBundleInfo(previousFallbackId, fallback.setStatus(BundleStatus.DELETING))) {
1855
+ logger.error("Failed to persist DELETING for previous bundle; queueing durable retry");
1856
+ logger.debug("Bundle ID: " + previousFallbackId);
1857
+ this.enqueuePendingDelete(previousFallbackId);
1642
1858
  }
1643
1859
  }
1644
1860
  this.setFallbackBundle(bundle);
1861
+ if (shouldDeletePrevious) {
1862
+ new Thread(() -> {
1863
+ try {
1864
+ final Boolean res = this.delete(previousFallbackId, true, false);
1865
+ if (Boolean.TRUE.equals(res)) {
1866
+ logger.info("Deleted previous bundle: " + previousFallbackVersion);
1867
+ } else {
1868
+ logger.debug("Previous bundle delete incomplete, will retry: " + previousFallbackId);
1869
+ }
1870
+ } catch (final IOException e) {
1871
+ logger.error("Failed to delete previous bundle: " + previousFallbackId + " " + e.getMessage());
1872
+ }
1873
+ }, "CapgoUpdater-autoDeletePrevious").start();
1874
+ }
1645
1875
  }
1646
1876
 
1647
1877
  public void setError(final BundleInfo bundle) {
@@ -2484,10 +2714,10 @@ public class CapgoUpdater {
2484
2714
  this.saveBundleInfo(id, null);
2485
2715
  }
2486
2716
 
2487
- public void saveBundleInfo(final String id, final BundleInfo info) {
2717
+ public boolean saveBundleInfo(final String id, final BundleInfo info) {
2488
2718
  if (id == null || (info != null && (info.isBuiltin() || info.isUnknown()))) {
2489
2719
  logger.debug("Not saving info for bundle: [" + id + "] " + info);
2490
- return;
2720
+ return false;
2491
2721
  }
2492
2722
 
2493
2723
  if (info == null) {
@@ -2499,7 +2729,7 @@ public class CapgoUpdater {
2499
2729
  logger.debug("Storing info for bundle [" + id + "] " + update.getClass().getName() + " -> " + jsonString);
2500
2730
  this.editor.putString(id + INFO_SUFFIX, jsonString);
2501
2731
  }
2502
- this.editor.commit();
2732
+ return this.editor.commit();
2503
2733
  }
2504
2734
 
2505
2735
  private void setBundleStatus(final String id, final BundleStatus status) {
@@ -40,7 +40,7 @@ public class DelayCondition {
40
40
  public boolean equals(Object o) {
41
41
  if (this == o) return true;
42
42
  if (!(o instanceof DelayCondition that)) return false;
43
- return (getKind() == that.getKind() && Objects.equals(getValue(), that.getValue()));
43
+ return getKind() == that.getKind() && Objects.equals(getValue(), that.getValue());
44
44
  }
45
45
 
46
46
  @Override
@@ -51,6 +51,6 @@ public class DelayCondition {
51
51
  @NonNull
52
52
  @Override
53
53
  public String toString() {
54
- return ("DelayCondition{" + "kind=" + kind + ", value='" + value + '\'' + '}');
54
+ return "DelayCondition{" + "kind=" + kind + ", value='" + value + '\'' + '}';
55
55
  }
56
56
  }
@@ -22,7 +22,7 @@ public class InternalUtils {
22
22
  public static String getPackageName(PackageManager pm, String packageName) {
23
23
  try {
24
24
  PackageInfo pInfo = getPackageInfoInternal(pm, packageName);
25
- return (pInfo != null) ? pInfo.packageName : null;
25
+ return pInfo != null ? pInfo.packageName : null;
26
26
  } catch (PackageManager.NameNotFoundException e) {
27
27
  // Exception is handled internally, and null is returned to indicate the package name could not be retrieved
28
28
  return null;
@@ -273,7 +273,7 @@ public class ShakeMenu implements ShakeDetector.Listener, ThreeFingerPinchDetect
273
273
  String name = preview.optString("name", "");
274
274
  JSObject bundle = preview.getJSObject("bundle");
275
275
  String version = bundle == null ? "" : bundle.optString("version", "");
276
- String label = !name.isEmpty() ? name : (!version.isEmpty() ? version : preview.optString("id", "Preview"));
276
+ String label = !name.isEmpty() ? name : !version.isEmpty() ? version : preview.optString("id", "Preview");
277
277
  if (preview.optBoolean("isActive", false)) {
278
278
  label += " (current)";
279
279
  }
package/dist/docs.json CHANGED
@@ -4468,6 +4468,14 @@
4468
4468
  {
4469
4469
  "text": "'downloading'",
4470
4470
  "complexTypes": []
4471
+ },
4472
+ {
4473
+ "text": "'deleted'",
4474
+ "complexTypes": []
4475
+ },
4476
+ {
4477
+ "text": "'deleting'",
4478
+ "complexTypes": []
4471
4479
  }
4472
4480
  ]
4473
4481
  },
@@ -1604,7 +1604,7 @@ export interface CapacitorUpdaterPlugin {
1604
1604
  * success: The bundle has been downloaded and is ready to be **SET** as the next bundle.
1605
1605
  * error: The bundle has failed to download.
1606
1606
  */
1607
- export type BundleStatus = 'success' | 'error' | 'pending' | 'downloading';
1607
+ export type BundleStatus = 'success' | 'error' | 'pending' | 'downloading' | 'deleted' | 'deleting';
1608
1608
  export type DelayUntilNext = 'background' | 'kill' | 'nativeVersion' | 'date';
1609
1609
  /**
1610
1610
  * Classification for update-check responses that do not provide a downloadable bundle.