La page Télécharger a deux onglets de plus, Mods et Skins, qui listent le catalogue hébergé par le site du
projet (https://prism.am) et installent un élément en un clic. Le jeu fait tout lui-même, en natif
(crates/downloader/src/repository.rs pour le réseau, apps/desktop/src/app/hosted.rs pour l'orchestration) : jamais
le thread des mods, jamais la WebView.
Contrat de l'API (côté site)
GET <catalogBase>/api/catalog?kind=mod|skin répond { "items": [ … ] }. Seuls les éléments approuvés sont listés.
| Champ | Rôle |
|---|---|
id |
slug : 1 à 64 caractères A-Za-z0-9._-, ni . ni - au début, pas de . à la fin ; c'est l'identifiant du mod ou du skin installé |
kind |
mod ou skin (un élément d'un autre type est ignoré) |
name, author, version |
affichés tels quels (version est libre) ; 80, 80 et 32 caractères au plus |
seq |
entier qui croît à chaque version approuvée ; sert à détecter une mise à jour |
description, descriptionFr? |
600 caractères au plus ; le français lit descriptionFr, les autres langues description |
permissions |
liste de textes (network, stage, skinImport…), affichée avant l'installation d'un mod |
sha256, size |
64 chiffres hexadécimaux, octets ; vérifiés après le téléchargement |
filename |
informatif (le jeu nomme lui-même son fichier temporaire) |
url |
absolue ou relative au site, sur l'hôte du catalogue seulement (même schéma, même hôte, même port) |
updatedAt, screenshots? |
updatedAt est lu ; screenshots et tout champ inconnu sont tolérés et ignorés |
Un élément invalide (slug, empreinte, taille hors bornes — 64 Mio pour un mod, 256 Mio pour un skin —, URL ailleurs, type différent, doublon) est ignoré sans casser la liste. La liste est lue dans 1 Mio au plus, 500 éléments au plus.
Adresse du catalogue
Par défaut https://prism.am. Dans l'ordre : la variable d'environnement PRISM_CATALOG, puis le réglage
catalogUrl (Réglages → Bibliothèque → Téléchargements → Catalogue), puis la valeur par défaut.
- Le réglage exige
https;httpn'y est accepté que pourlocalhostou une adresse de boucle locale. - La variable seule peut nommer un serveur
http(par exemple le serveur de test actuel, sans DNS :PRISM_CATALOG=http://15.235.95.198) ; elle autorise alorshttpet un port, uniquement pour l'hôte nommé. - Le réglage
catalogUrln'est jamais exporté avec les réglages.
Ce que fait le réseau
- La liste est demandée quand l'onglet s'ouvre, jamais avant. Aucun identifiant n'est envoyé (ni cookie, ni jeton,
ni identifiant de machine ou de joueur) : seulement
Acceptet l'agent utilisateur du jeu. - Chaque requête porte une
HostPolicylimitée à l'hôte du catalogue : redirections suivies à la main, un seul hôte (une redirection vers un autre hôte est refusée), 3 sauts au plus. Pour un catalogue enhttpspublic, une adresse privée ou locale est refusée à la résolution comme pour les sources de mods. - Délais et tailles bornés ; un catalogue injoignable donne l'état calme « Catalogue indisponible » avec un bouton Réessayer, sans toucher aux autres onglets.
Installation
- L'élément est téléchargé dans un fichier temporaire (
<data>/catalog-tmp/<n>/…), avec progression et bouton Annuler. Le flux est borné par la taille annoncée. - La taille exacte et le SHA-256 sont vérifiés ; au moindre écart (fichier trop long, trop court, empreinte différente) le fichier est supprimé et l'erreur « ne correspond pas à ce que le catalogue annonçait » s'affiche.
- Le fichier vérifié est confié exactement à l'import existant :
ModInstaller::install_packagepour un.pvmod(ce que fait la page Mods),skin::Library::importpour un skin.zip(ce que fait la page Skins). Toutes leurs validations s'appliquent (zip-slip, plafonds, identifiants). - Le fichier temporaire est supprimé à la fin ; les dossiers oubliés par une interruption le sont à la prochaine ouverture d'un onglet (au bout d'une heure).
Collisions. Un mod de même identifiant est remplacé par l'import existant (c'est sa mise à jour explicite : la
confirmation dit la version remplacée). Un skin n'écrase jamais un skin : l'import lui donne un identifiant libre
(neon-2) ; une mise à jour de skin s'ajoute donc à côté de l'actuel.
Un mod installé est actif tout de suite (c'est le comportement de l'import .pvmod, disabledMods est vide par
défaut). C'est pourquoi la confirmation précède l'installation. Après coup, l'interface le dit (« il est actif :
vérifiez-le, ainsi que ses permissions, dans la page Mods ») avec un bouton qui ouvre la page Mods.
Permissions
Pour un mod, les permissions du catalogue s'affichent en badges avec une explication en clair, sur la carte puis dans la
confirmation d'installation. Ce sont les permissions annoncées par le site ; ce qui compte est le manifeste du
paquet. Une fois installé, le jeu compare : si le paquet déclare une permission que le catalogue n'annonçait pas,
l'interface l'écrit (« le paquet demande des permissions que le catalogue n'annonçait pas : … »). Les retraits
existants (networkDenied, stageDenied, page Mods) s'appliquent comme pour tout mod.
Installé / Mise à jour
Le jeu garde <data>/catalog-installed.json : pour chaque élément installé depuis le catalogue, l'identifiant local
(celui du manifeste d'un mod, celui que l'import a choisi pour un skin), seq et version.
- Avec ce lien (et tant que l'élément local existe) : mise à jour si
seqdu catalogue est plus grand. - Sans lien (installé à la main) : comparaison des versions quand les deux sont des nombres séparés par des points
(
1.2.10, unvinitial et une fin-preou+buildsont ignorés) ; sinon l'élément compte comme installé. - Aucun élément local de ce nom : disponible.
Interface
CatalogTab.svelte est un composant générique, sans styles par thème : il lit les jetons --pv-* (les huit thèmes
et le classique) et réutilise Button, Badge et IconButton. Textes en en/fr/zh (catalog.*).
Tests
crates/downloader/src/repository/tests.rs: serveur HTTP local réel et transport réel — liste (champs inconnus, éléments invalides ignorés, rien d'identifiant envoyé), erreurs de liste (500, pas du JSON, trop gros, injoignable, redirection vers un autre hôte), fichier valide avec progression, mauvaise empreinte, fichier trop court ou trop long, 404, redirection vers un autre hôte, annulation, fichier existant jamais écrasé, règles de l'adresse de base.apps/desktop/src/app/hosted.rs(noms de fichiers sûrs sous Windows, registre) etprotocol/tests.rs(contrat).apps/web/src/lib/catalog.test.ts(états, versions, langue, permissions) ettests/catalog-tabs.spec.ts(onglets, confirmation, installation, annulation, échec d'intégrité, indisponible, langue ; classic, cabinet, slant).
Ce qui n'est pas vérifié nativement
Le serveur réel (prism.am ou l'adresse de test), l'installation d'un vrai .pvmod ou skin du catalogue dans le jeu
lancé, et le rendu dans la vraie WebView ne sont pas exercés : les tests Rust utilisent un serveur local, l'interface
est vue avec le mock.