Appearance
Migrations des préférences d'appli
Une migration décrit comment conserver ou transformer les réglages d'une version publiée précédente dans la nouvelle structure. Elle se place sur le champ cible du nouveau schéma, au niveau de type. Elle ne décrit pas le passage entre deux synchronisations du même brouillon.
Copie implicite et conversion explicite
Sans migration, le moteur reprend la valeur au même chemin de l'ancienne structure si les types sont compatibles. Sinon, le nouveau défaut s'applique. Modifier un default n'écrase donc pas les réglages déjà conservés.
Une migration explicite sur un groupe prime sur la copie automatique de ses enfants. Une migration également explicite sur un enfant peut ensuite remplacer cet enfant. Fournis un résultat compatible avec la structure cible ; évite les objets partiels dont tu supposerais une fusion automatique.
Une migration ne se déclare pas sur collectionItems : elle se déclare sur la collection, avec un callback si nécessaire. Les sources explicites doivent exister dans l'ancien schéma et les données sources. Une source manquante produit une erreur ; elle n'est pas silencieusement remplacée par un défaut.
Pour une première version sans ancien contexte, ne déclare pas de migration. Pour une version ultérieure, une migration explicite peut aussi imposer un changement de valeur, même si la forme du schéma reste identique.
Les six sources
source | Propriétés | Résultat |
|---|---|---|
raw | value | Valeur littérale compatible avec le champ cible. |
path | path | Valeur à ce chemin absolu de l'ancienne version. |
migrationsGroup | migrationsGroupItems: { clé: migration } | Objet construit par les migrations enfants. |
migrationsCollection | migrationsCollectionItems: [migration, ...] | Liste construite par ces migrations. |
foreachInCollection | path, callback: migration | Transformation de chaque élément d'une ancienne collection. |
scopePath | path commençant par @reference | Valeur de l'élément courant du callback de foreachInCollection. |
Une migration sous forme de chaîne (migration: 'old.title') est un raccourci pour { source: 'path', path: 'old.title' }. value appartient à raw, pas à path.
scopePath: '@reference' reprend l'élément entier ; @reference.filename reprend un champ de son groupe. Les marqueurs @parent / @self des formulaires n'ont aucun rôle dans les migrations.
Exemple complet : déplacer un champ dans une collection
Ancien schéma (objet exporté depuis preferences.config.js) :
json
{
"type": "group",
"groupItems": {
"audioFiles": {
"type": "collection",
"collectionItems": {
"type": "group",
"groupItems": {
"filename": { "type": "string" },
"volume": { "type": "number" }
}
}
}
}
}Nouveau schéma : volume reste numérique, est déplacé dans options, et pan reçoit 0.5. La migration est bien portée par audioFiles.
json
{
"type": "group",
"groupItems": {
"audioFiles": {
"type": "collection",
"collectionItems": {
"type": "group",
"groupItems": {
"filename": { "type": "string" },
"options": {
"type": "group",
"groupItems": {
"volume": { "type": "number" },
"pan": { "type": "number", "default": 0.5 }
}
}
}
},
"migration": {
"source": "foreachInCollection",
"path": "audioFiles",
"callback": {
"source": "migrationsGroup",
"migrationsGroupItems": {
"filename": { "source": "scopePath", "path": "@reference.filename" },
"options": {
"source": "migrationsGroup",
"migrationsGroupItems": {
"volume": { "source": "scopePath", "path": "@reference.volume" },
"pan": { "source": "raw", "value": 0.5 }
}
}
}
}
}
}
}
}Valeurs métier sources pour la recette :
json
{
"audioFiles": [
{ "filename": "file1.mp3", "volume": 0.7 },
{ "filename": "file2.mp3", "volume": 0.8 }
]
}Résultat métier attendu (les identités techniques éventuellement présentes sont conservées par la plateforme) :
json
{
"audioFiles": [
{ "filename": "file1.mp3", "options": { "volume": 0.7, "pan": 0.5 } },
{ "filename": "file2.mp3", "options": { "volume": 0.8, "pan": 0.5 } }
]
}Tester un brouillon
Compiler, utiliser le watch et synchroniser les fichiers ne réinitialise pas à chaque fois les essais depuis l'ancienne version. Les réglages d'essai sont conservés séparément de la sauvegarde de la version précédente ; les valeurs retirées ou devenues incompatibles restent consultables parmi les réglages conservés du brouillon.
Dans l'onglet Préférences du portail développeur :
- Tester les migrations calcule le résultat depuis la sauvegarde source, sans modifier les essais ni créer de récompense Twitch.
- Contrôler les principales, les variantes, les collections vides/remplies, les valeurs nullables, les identités et les triggers. Vérifier aussi les réglages personnalisés : les seuls défauts ne représentent pas tous les streamers.
- Appliquer à mes réglages d'essai remplace uniquement les essais par ce résultat ; l'essai précédent est restaurable.
- Après chaque correction de migration, retester : le calcul repart toujours de la même ancienne source, même si un précédent résultat a déjà été appliqué.
Si le développeur a installé directement le brouillon, il n'a pas de sauvegarde personnelle antérieure. Le portail propose alors explicitement de partir des défauts de la version publiée précédente ; ce scénario ne suffit pas à valider les configurations réelles.
Une migration inachevée bloque le test et la soumission, mais pas la synchronisation d'une structure de préférences utilisable. Un JSON ou schéma inexploitable reste refusé. Lire les erreurs de compilation et celles de synchronisation backend renvoyées par le HUB.
Soumission et publication
La soumission verrouille les fichiers pour la review ; un refus permet de reprendre le brouillon. La publication vérifie les migrations finales et conserve les essais compatibles des développeurs déjà sur la version. Les autres streamers sont migrés depuis leur propre version et leurs propres données lors de la mise à jour.
Les variantes sont migrées en conservant la provenance des surcharges. Les synchronisations Twitch liées aux préférences sont exécutées après l'enregistrement et reprises en cas d'échec. Ne remplace pas ce flux par un script client qui recrée les triggers ou récompenses.