diff --git a/installer/PSLauncher.iss b/installer/PSLauncher.iss
index a003d66..63655ff 100644
--- a/installer/PSLauncher.iss
+++ b/installer/PSLauncher.iss
@@ -11,7 +11,7 @@
#define MyAppName "PROSERVE Launcher"
#define MyAppShortName "PS_Launcher"
-#define MyAppVersion "1.0.6"
+#define MyAppVersion "1.0.7"
#define MyAppPublisher "ASTERION VR"
#define MyAppURL "https://asterionvr.com"
#define MyAppExeName "PS_Launcher.exe"
diff --git a/src/PSLauncher.App/PSLauncher.App.csproj b/src/PSLauncher.App/PSLauncher.App.csproj
index 20e5ecb..792e394 100644
--- a/src/PSLauncher.App/PSLauncher.App.csproj
+++ b/src/PSLauncher.App/PSLauncher.App.csproj
@@ -18,9 +18,9 @@
PROSERVE Launcher
© 2026 ASTERION VR — All rights reserved
PSLauncher.App
- 1.0.6
- 1.0.6.0
- 1.0.6.0
+ 1.0.7
+ 1.0.7.0
+ 1.0.7.0
true
diff --git a/src/PSLauncher.App/ViewModels/MainViewModel.cs b/src/PSLauncher.App/ViewModels/MainViewModel.cs
index 6644782..c6e7f61 100644
--- a/src/PSLauncher.App/ViewModels/MainViewModel.cs
+++ b/src/PSLauncher.App/ViewModels/MainViewModel.cs
@@ -763,7 +763,13 @@ public sealed partial class MainViewModel : ObservableObject
// on garde le cache silencieusement (pas de crash).
await RefreshLicenseFromServerAsync(CancellationToken.None);
- var result = await _updateChecker.CheckAsync(CancellationToken.None);
+ // Passe canSeeBetas depuis la license courante — UpdateChecker exclut les
+ // betas de la sélection LatestRemote quand le client n'a pas les droits.
+ // Évite le popup « MAJ dispo : 1.5.4.32 beta » pour un client qui ne peut
+ // pas voir cette version dans la liste après filtrage RebuildList.
+ var result = await _updateChecker.CheckAsync(
+ _license?.CanSeeBetas ?? false,
+ CancellationToken.None);
if (result.Error is not null)
{
StatusMessage = Strings.StatusError(result.Error);
diff --git a/src/PSLauncher.Core/Updates/IUpdateChecker.cs b/src/PSLauncher.Core/Updates/IUpdateChecker.cs
index d94dcbc..0042647 100644
--- a/src/PSLauncher.Core/Updates/IUpdateChecker.cs
+++ b/src/PSLauncher.Core/Updates/IUpdateChecker.cs
@@ -4,7 +4,14 @@ namespace PSLauncher.Core.Updates;
public interface IUpdateChecker
{
- Task CheckAsync(CancellationToken ct);
+ ///
+ /// Si false, les versions marquées sont
+ /// exclues de la sélection du LatestRemote — pas de popup « MAJ dispo »
+ /// pour une beta que le client ne pourrait de toute façon pas voir dans la
+ /// liste après filtrage license côté MainViewModel.RebuildList. Le
+ /// manifest complet est quand même retourné pour le rendu ultérieur.
+ ///
+ Task CheckAsync(bool canSeeBetas, CancellationToken ct);
}
public sealed record UpdateCheckResult(
diff --git a/src/PSLauncher.Core/Updates/UpdateChecker.cs b/src/PSLauncher.Core/Updates/UpdateChecker.cs
index 87cfb52..14de0a6 100644
--- a/src/PSLauncher.Core/Updates/UpdateChecker.cs
+++ b/src/PSLauncher.Core/Updates/UpdateChecker.cs
@@ -21,7 +21,7 @@ public sealed class UpdateChecker : IUpdateChecker
_logger = logger;
}
- public async Task CheckAsync(CancellationToken ct)
+ public async Task CheckAsync(bool canSeeBetas, CancellationToken ct)
{
try
{
@@ -32,8 +32,16 @@ public sealed class UpdateChecker : IUpdateChecker
// ordonnant via VersionOrder — ça respecte la règle « non-beta > beta au
// même préfixe 3-digit » (ex : 1.5.4 non-beta > 1.5.4.32 beta), sinon
// c'est du SemVer strict.
- var latest = manifest.Versions
- .Where(v => v.AvailableForDownload)
+ //
+ // Filtre isBeta : les clients sans droits beta ne doivent JAMAIS voir une
+ // beta comme LatestRemote — sinon le popup « MAJ dispo » leur propose une
+ // version qu'ils ne pourront pas installer (filtrée en aval par RebuildList).
+ // Le filtre est appliqué avant le tri VersionOrder pour éviter qu'une beta
+ // ne se glisse comme "latest" chez un client non-autorisé, même si elle
+ // aurait été détrônée par une non-beta au même préfixe 3-digit.
+ var candidates = manifest.Versions.Where(v => v.AvailableForDownload);
+ if (!canSeeBetas) candidates = candidates.Where(v => !v.IsBeta);
+ var latest = candidates
.OrderByDescending(v => v, Comparer.Create(VersionOrder.Compare))
.FirstOrDefault();