@digitea/updater
v0.1.1
Published
Official lightweight client for the Digitea Software Updates API
Maintainers
Readme
@digitea/updater
Client TypeScript officiel pour intégrer les mises à jour de votre produit SOFTWARE Digitea dans une application Node.js ou dans le processus principal d’Electron.
Le SDK permet de :
- rechercher publiquement une mise à jour compatible avec la version installée ;
- demander un lien de téléchargement autorisé pour un artifact précis ;
- gérer les timeouts, les retries, l’annulation et les erreurs typées.
Il ne télécharge pas les octets, n’installe rien et ne nécessite jamais de clé Developer API. L’installation, le remplacement des fichiers et le redémarrage de l’application restent sous le contrôle de votre logiciel.
Installation
npm install @digitea/updaterLe SDK nécessite Node.js 18 ou une version plus récente, notamment pour utiliser fetch et AbortSignal.
Le flux complet
- Créez une release publiée et ses artifacts depuis votre espace vendeur Digitea.
- Configurez dans l’application le productId public de votre produit.
- Appelez check() avec la version, la plateforme et l’architecture du build installé.
- Présentez la mise à jour à l’utilisateur et demandez son accord.
- Appelez getDownload() avec la licence et l’instance déjà activée.
- Téléchargez l’URL retournée, vérifiez sha256 lorsque la valeur est fournie, puis installez selon votre propre procédure.
Le productId est fourni dans le tableau de bord ou dans la réponse de création ou de lecture du produit. Il est public : vous pouvez le placer dans la configuration de l’application. Ne demandez pas ce paramètre au client et ne placez jamais une clé dgt_sk_live_... dans l’application distribuée.
Exemple rapide
import { DigiteaUpdater } from "@digitea/updater";
const updater = new DigiteaUpdater({
productId: process.env.DIGITEA_PRODUCT_ID ?? "prd_demo123456",
});
const update = await updater.check({
currentVersion: "1.2.0",
platform: "WINDOWS",
architecture: "X64",
channel: "STABLE",
packageType: "EXE",
});
if (update.available) {
// Demandez l’accord de l’utilisateur avant le téléchargement.
const download = await updater.getDownload({
licenseKey,
instanceId,
artifactId: update.artifactId,
});
console.log(download.downloadUrl);
}licenseKey est la clé complète remise au client après son achat. instanceId doit être le même identifiant stable que celui utilisé lors de l’activation avec @digitea/licensing. L’updater ne crée pas d’activation et ne remplace pas le SDK Licensing.
Configuration
const updater = new DigiteaUpdater({
productId: "prd_demo123456",
baseUrl: "https://api.getdigitea.com",
timeoutMs: 10_000,
retry: {
maxRetries: 2,
baseDelayMs: 250,
maxDelayMs: 5_000,
},
});| Option | Obligatoire | Valeur par défaut | Description | |---|---:|---:|---| | productId | oui | — | Identifiant public du produit SOFTWARE. | | baseUrl | non | https://api.getdigitea.com | URL de l’API. HTTPS est obligatoire ; http://localhost est accepté pour les tests locaux. | | timeoutMs | non | 10000 | Délai maximal d’une tentative réseau, en millisecondes. | | retry.maxRetries | non | 2 | Nombre de nouvelles tentatives après une panne temporaire. | | retry.baseDelayMs | non | 250 | Délai initial du backoff. | | retry.maxDelayMs | non | 5000 | Délai maximal du backoff. |
Le constructeur rejette un productId vide et une baseUrl qui n’utilise pas HTTPS, sauf pour localhost. Les options de retry sont bornées par votre configuration ; utilisez-les avec mesure pour ne pas retarder l’expérience utilisateur.
Rechercher une mise à jour avec check()
const result = await updater.check({
currentVersion: "1.2.0",
platform: "ANDROID",
architecture: "ANY",
channel: "STABLE",
packageType: "ZIP",
});Cet appel est public : il ne demande ni licenseKey ni clé vendeur.
| Paramètre | Obligatoire | Valeurs | |---|---:|---| | currentVersion | oui | Version SemVer installée, par exemple 1.2.0. | | platform | oui | WINDOWS, MACOS, LINUX, ANDROID, BROWSER, CROSS_PLATFORM. | | architecture | oui | X64, X86, ARM64, UNIVERSAL, ANY. | | channel | non | STABLE, BETA, ALPHA. Par défaut : STABLE. | | packageType | non | EXE, MSI, DMG, PKG, APPIMAGE, DEB, RPM, APK, AAB, ZIP, CRX, XPI, VSIX, SCRIPT, OTHER. |
Décrivez la plateforme, l’architecture et le package du build réellement installé. N’utilisez CROSS_PLATFORM, UNIVERSAL ou ANY que lorsqu’un artifact est réellement compatible avec ces cibles.
Réponse sans mise à jour
{
available: false,
currentVersion: "1.2.0",
latestVersion: "1.2.0",
reason: "UP_TO_DATE"
}reason peut être :
- UP_TO_DATE : la version installée est déjà au niveau de la dernière release du canal demandé ;
- NO_COMPATIBLE_ARTIFACT : une release plus récente existe, mais aucun artifact de cette release ne correspond à la plateforme, l’architecture ou au package demandé.
Quand aucune release publiée n’existe dans le canal, latestVersion vaut null et reason est absent.
Réponse avec mise à jour
{
available: true,
currentVersion: "1.2.0",
latestVersion: "1.3.0",
releaseId: "swr_demo123",
channel: "STABLE",
releaseNotes: "Corrections et améliorations.",
publishedAt: "2026-09-01T09:00:00.000Z",
artifactId: "swa_demo123",
platform: "ANDROID",
architecture: "ANY",
packageType: "ZIP",
sizeBytes: 48200123,
sha256: "64 caractères hexadécimaux",
deliveryMode: "HOSTED"
}Le résultat available: true contient toujours releaseId, artifactId, channel, publishedAt, platform, architecture, packageType et deliveryMode. releaseNotes, sizeBytes et sha256 peuvent être null selon la configuration de l’artifact.
Règles de sélection
La sélection se fait dans cet ordre :
- Digitea prend la release publiée la plus récente selon SemVer dans le canal demandé.
- Il recherche un artifact uniquement dans cette release.
- Il préfère une plateforme exacte à CROSS_PLATFORM.
- Il préfère une architecture exacte à UNIVERSAL ou ANY.
- Il applique packageType lorsqu’il est fourni.
Digitea ne revient pas automatiquement à une ancienne release si la dernière release n’a aucun build compatible. check() renvoie alors available: false avec NO_COMPATIBLE_ARTIFACT.
Une application configurée sur STABLE ne reçoit jamais une release BETA ou ALPHA. Une release DRAFT, archivée ou non publiée n’est pas proposée.
Autoriser un téléchargement avec getDownload()
const download = await updater.getDownload({
licenseKey,
instanceId,
artifactId: update.artifactId,
});Les trois paramètres sont obligatoires :
| Paramètre | Description | |---|---| | licenseKey | Clé complète du client. Ne la journalisez jamais. | | instanceId | Instance déjà activée avec cette licence. | | artifactId | Artifact retourné par check(). |
Le service vérifie la licence, le produit, l’instance active et l’appartenance de l’artifact à une release SOFTWARE publiée. Une licence expirée, suspendue ou révoquée ne peut pas obtenir de téléchargement.
Réponse
{
artifactId: "swa_demo123",
deliveryMode: "HOSTED",
downloadUrl: "https://...",
expiresIn: 300,
sha256: "64 caractères hexadécimaux"
}- HOSTED : Digitea renvoie une URL présignée valable 5 minutes. Utilisez-la rapidement et ne la stockez pas dans un cache permanent.
- EXTERNAL : Digitea renvoie l’URL HTTPS configurée par le vendeur et expiresIn vaut null.
Le SDK ne suit pas l’URL et ne vérifie pas le hash à votre place. Téléchargez le fichier avec votre propre client HTTP, comparez son SHA-256 à download.sha256 lorsqu’il est fourni, puis lancez votre installateur.
import { createHash } from "node:crypto";
const response = await fetch(download.downloadUrl);
if (!response.ok) {
throw new Error("Téléchargement impossible : HTTP " + response.status);
}
const bytes = Buffer.from(await response.arrayBuffer());
if (download.sha256) {
const actualSha256 = createHash("sha256").update(bytes).digest("hex");
if (actualSha256 !== download.sha256) {
throw new Error("Le contrôle SHA-256 de la mise à jour a échoué");
}
}Pour les gros fichiers, utilisez un téléchargement en flux afin de ne pas charger tout l’artifact en mémoire.
Intégration avec Licensing
L’updater ne valide pas une licence et ne crée pas d’activation. Pour un téléchargement autorisé, l’instance doit déjà être active avec la licence utilisée.
import { DigiteaLicensing } from "@digitea/licensing";
import { DigiteaUpdater } from "@digitea/updater";
const productId = "prd_demo123456";
const licensing = new DigiteaLicensing({ productId });
const updater = new DigiteaUpdater({ productId });
const instanceId = await loadOrCreateStableInstanceId();
await licensing.activate({ licenseKey, instanceId });
const update = await updater.check({
currentVersion: "1.2.0",
platform: "WINDOWS",
architecture: "X64",
});
if (update.available) {
const download = await updater.getDownload({
licenseKey,
instanceId,
artifactId: update.artifactId,
});
}Conservez le même productId et le même instanceId pour Licensing et Updates. Si l’activation est supprimée ou désactivée, getDownload() échoue avec INSTANCE_NOT_ACTIVATED.
Electron
Utilisez le SDK dans le processus principal Electron. Exposez au renderer uniquement les informations nécessaires à l’interface : version disponible, notes, progression et résultat de l’installation.
// main.ts
const updater = new DigiteaUpdater({ productId: "prd_demo123456" });
ipcMain.handle("updates:check", async () => updater.check({
currentVersion: app.getVersion(),
platform: "WINDOWS",
architecture: "X64",
channel: "STABLE",
packageType: "EXE",
}));Ne transmettez jamais une clé Developer API au renderer. La clé de licence client et l’URL de téléchargement doivent également rester absentes des logs et des messages inutiles.
Annuler une requête
Toutes les méthodes acceptent un AbortSignal en second argument :
const controller = new AbortController();
const pending = updater.check(
{
currentVersion: "1.2.0",
platform: "LINUX",
architecture: "X64",
},
{ signal: controller.signal },
);
controller.abort();
await pending; // rejette avec DigiteaUpdaterError et le code ABORTEDRetries et disponibilité
Le SDK rejoue automatiquement les erreurs temporaires :
- erreurs réseau ;
- timeout ;
- réponse HTTP 429 ;
- réponse HTTP 5xx ;
- erreur API TEMPORARILY_UNAVAILABLE.
Les erreurs de licence, de produit et de requête ne sont jamais rejouées. Le délai augmente progressivement jusqu’à maxDelayMs et l’en-tête Retry-After est respecté lorsqu’il est fourni.
Une panne réseau ne crée jamais de droit hors ligne et ne doit pas être traitée comme une validation de licence. Si toutes les tentatives échouent, laissez l’utilisateur réessayer plus tard.
Gérer les erreurs
Les erreurs sont des instances de DigiteaUpdaterError :
import { DigiteaUpdaterError } from "@digitea/updater";
try {
await updater.getDownload({ licenseKey, instanceId, artifactId });
} catch (error) {
if (error instanceof DigiteaUpdaterError) {
console.log({
code: error.code,
status: error.httpStatus,
retryable: error.retryable,
});
}
}| Code | Signification | Rejouable ? | |---|---|---:| | LICENSE_INVALID | Clé inconnue ou invalide. | non | | LICENSE_EXPIRED | Licence expirée. | non | | LICENSE_SUSPENDED | Licence suspendue. | non | | LICENSE_REVOKED | Licence révoquée. | non | | INSTANCE_NOT_ACTIVATED | Instance absente ou non active pour cette licence. | non | | INVALID_PRODUCT | Produit inconnu ou incompatible. | non | | INVALID_REQUEST | Paramètres invalides. | non | | RATE_LIMITED | Limite de requêtes atteinte. | oui | | TEMPORARILY_UNAVAILABLE | Service momentanément indisponible. | oui | | NETWORK_ERROR | Service inaccessible après les tentatives prévues. | oui | | TIMEOUT | Tentatives dépassées après timeoutMs. | oui | | ABORTED | Requête annulée avec AbortController. | non | | INVALID_RESPONSE | Réponse absente, non JSON ou incompatible avec le contrat. | selon la cause |
Pour RATE_LIMITED, TEMPORARILY_UNAVAILABLE, NETWORK_ERROR et TIMEOUT, affichez un message compréhensible et proposez un nouvel essai plus tard.
Sécurité et bonnes pratiques
- Le productId est public ; la licenseKey est une donnée sensible du client.
- N’utilisez jamais une clé dgt_sk_live_... avec ce SDK : elle est réservée à la Developer API sur votre serveur.
- Ne journalisez ni la licenseKey, ni downloadUrl, ni les réponses complètes de téléchargement.
- Vérifiez sha256 avant de lancer un installateur lorsque cette valeur est disponible.
- Ne considérez jamais un redirect ou une notification comme une preuve de mise à jour installée.
- Demandez l’accord de l’utilisateur avant le téléchargement et l’installation.
- Conservez la version réellement installée et relancez check() après l’installation.
- Pour une application Electron, gardez la logique de téléchargement et d’installation dans le processus principal.
Types exportés
Le paquet exporte notamment :
DigiteaUpdater
DigiteaUpdaterError
SoftwarePlatform
SoftwareArchitecture
SoftwareReleaseChannel
SoftwarePackageType
SoftwareArtifactDeliveryMode
RetryConfig
DigiteaUpdaterConfig
RequestOptions
CheckUpdateInput
CheckUpdateResult
GetDownloadInput
UpdateDownloadResult
UpdaterErrorCodeLes types TypeScript sont inclus dans le paquet dans dist/index.d.ts.
Ce que le SDK ne fait pas
- Il ne crée pas de produit, release ou artifact.
- Il ne publie pas de release.
- Il n’active pas une licence.
- Il ne demande pas de clé Developer API.
- Il ne télécharge pas automatiquement le fichier.
- Il n’installe pas et ne remplace pas votre application.
- Il n’accorde aucun mode hors ligne en cas de panne du service.
Pour gérer l’activation, la validation, la désactivation et le renouvellement d’une licence, utilisez @digitea/licensing sur npm. Pour le contrat HTTP complet, consultez la documentation Software Updates et la référence API v1.
Développement du paquet
npm run build
npm testLe guide public complet est disponible sur docs.getdigitea.com/software-updates.
