npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@digitea/licensing

v1.2.2

Published

Official lightweight client for the Digitea Runtime Licensing API

Downloads

1,162

Readme

@digitea/licensing

Le SDK officiel pour activer et vérifier les licences Digitea dans une application Node.js ou Electron.

Il permet à une application Node.js ou Electron de :

  • activer une licence sur une installation ;
  • vérifier qu’une licence est toujours active ;
  • désactiver une installation lorsque le produit l’autorise ;
  • distinguer clairement une erreur métier d’une panne réseau ;
  • générer et persister un identifiant d’instance stable.

Chaque validation consulte Digitea. Une panne réseau reste une erreur technique et n’accorde jamais automatiquement l’accès.

Important : trois interfaces différentes

| Interface | Utilisation | Identifiants | |---|---|---| | @digitea/licensing | Logiciel distribué au client | productId, licenseKey, instanceId | | Developer API | Serveur de votre application | clé dgt_sk_live_... | | Webhooks | Digitea vers votre serveur | secret whsec_... |

Une clé Developer API ou un secret webhook ne doit jamais être intégré dans Electron, un exécutable, une application mobile, un navigateur ou un dépôt public.

Installation

npm install @digitea/licensing

Prérequis :

  • Node.js 18 ou supérieur ;
  • projet ESM ou outillage capable d’importer un package ESM ;
  • accès HTTPS à https://api.getdigitea.com.

Le package ne possède aucune dépendance runtime.

Démarrage rapide

import {
  DigiteaLicensing,
  getOrCreateInstanceId,
  type InstanceStorage,
} from "@digitea/licensing";

const instanceStorage: InstanceStorage = {
  async get() {
    return settings.get("digitea.instanceId") ?? null;
  },
  async set(value) {
    await settings.set("digitea.instanceId", value);
  },
};

const licensing = new DigiteaLicensing({
  productId: "prd_votreproduit",
});

const instanceId = await getOrCreateInstanceId(instanceStorage);

const activation = await licensing.activate({
  licenseKey,
  instanceId,
  instanceName: "PC principal",
});

console.log(activation.status); // ACTIVE

const validation = await licensing.validate({
  licenseKey,
  instanceId,
});

if (validation.valid) {
  startApplication();
}

settings représente ici le stockage persistant choisi par votre application. Pour une session de renouvellement, le SDK genere automatiquement une Idempotency-Key et la reutilise sur chaque retry. Pour reprendre la meme operation apres une interruption, fournissez la meme valeur idempotencyKey. Une nouvelle cle represente une nouvelle session.

Le SDK n’impose ni fichier, ni base locale, ni trousseau système.

Configuration

const licensing = new DigiteaLicensing({
  productId: "prd_votreproduit",
  baseUrl: "https://api.getdigitea.com",
  timeoutMs: 10_000,
  retry: {
    maxRetries: 2,
    baseDelayMs: 250,
    maxDelayMs: 5_000,
  },
});

| Option | Requise | Valeur par défaut | Description | |---|---:|---:|---| | productId | oui | — | Identifiant public de votre logiciel sur Digitea | | baseUrl | non | https://api.getdigitea.com | URL de l’API Runtime | | timeoutMs | non | 10000 | Timeout de chaque tentative HTTP | | retry.maxRetries | non | 2 | Nombre maximal de nouvelles tentatives | | retry.baseDelayMs | non | 250 | Délai initial du backoff | | retry.maxDelayMs | non | 5000 | Plafond du backoff |

En dehors de localhost, une baseUrl non HTTPS est refusée.

Cycle d’utilisation recommandé

Premier lancement
  → charger ou créer instanceId
  → demander la clé au client
  → activate()

Lancements suivants
  → charger le même instanceId
  → validate()
  → démarrer uniquement si la validation réussit

Retrait de l’appareil
  → deactivate()

Ne générez pas un nouvel instanceId à chaque démarrage : chaque nouvelle valeur représente une nouvelle installation et peut consommer une place d’activation.

Activer une licence

const result = await licensing.activate({
  licenseKey: userLicenseKey,
  instanceId,
  instanceName: "MacBook de Marie",
});

Résultat :

interface ActivationResult {
  valid: true;
  status: "ACTIVE";
  expiresAt: string | null;
  activation: {
    publicId: string;
    activatedAt: string;
  };
  activeActivations: number;
  activationLimit: number;
  idempotent: boolean;
}

L’activation est idempotente : rappeler activate() pour une instance déjà active ne consomme pas une place supplémentaire.

Erreurs métier possibles :

  • LICENSE_INVALID
  • LICENSE_EXPIRED
  • LICENSE_SUSPENDED
  • LICENSE_REVOKED
  • INVALID_PRODUCT
  • ACTIVATION_LIMIT_REACHED

Valider une licence

const result = await licensing.validate({
  licenseKey: userLicenseKey,
  instanceId,
});

if (result.valid && result.status === "ACTIVE") {
  enableLicensedFeatures();
}

Résultat :

interface ValidationResult {
  valid: true;
  status: "ACTIVE";
  expiresAt: string | null;
}

La validation vérifie simultanément :

  • la clé ;
  • le produit concerné ;
  • le statut de la licence ;
  • sa date d’expiration ;
  • l’existence d’une activation active pour cette instance.

Une instance qui n’a jamais été activée reçoit INSTANCE_NOT_ACTIVATED.

Désactiver une instance

const result = await licensing.deactivate({
  licenseKey: userLicenseKey,
  instanceId,
});

Résultat :

interface DeactivationResult {
  valid: true;
  status: "DEACTIVATED";
  activeActivations: number;
  activationLimit: number;
  idempotent: boolean;
}

La désactivation doit être autorisée dans la configuration du produit. Sinon l’API renvoie DEACTIVATION_NOT_ALLOWED.

Une désactivation déjà effectuée reste idempotente.

Générer et conserver instanceId

Pour générer uniquement une valeur :

import { generateInstanceId } from "@digitea/licensing";

const instanceId = generateInstanceId();

Pour utiliser un stockage personnalisé :

import {
  getOrCreateInstanceId,
  type InstanceStorage,
} from "@digitea/licensing";

const storage: InstanceStorage = {
  async get() {
    return persistentStore.read("instanceId");
  },
  async set(value) {
    await persistentStore.write("instanceId", value);
  },
};

const instanceId = await getOrCreateInstanceId(storage);

Propriétés importantes :

  • Digitea ne demande aucun fingerprint matériel invasif ;
  • seul le digest de instanceId est conservé côté serveur ;
  • l’identifiant doit rester stable entre les redémarrages ;
  • le développeur reste responsable de sa persistance ;
  • restaurer le stockage permet de conserver la même identité logique.

Gestion structurée des erreurs

Toutes les erreurs du SDK utilisent DigiteaLicensingError.

import {
  DigiteaLicensingError,
  type LicensingErrorCode,
} from "@digitea/licensing";

try {
  await licensing.validate({ licenseKey, instanceId });
} catch (error) {
  if (!(error instanceof DigiteaLicensingError)) {
    throw error;
  }

  console.error({
    code: error.code,
    httpStatus: error.httpStatus,
    retryable: error.retryable,
  });

  switch (error.code) {
    case "LICENSE_REVOKED":
      showLicenseRevoked();
      break;

    case "LICENSE_EXPIRED":
      showRenewalScreen();
      break;

    case "NETWORK_ERROR":
    case "TIMEOUT":
      showTemporaryConnectionProblem();
      break;

    default:
      showLicensingError(error.code);
  }
}

La classe expose :

| Champ | Type | Description | |---|---|---| | code | chaîne typée | Code métier, HTTP ou client | | message | string | Message lisible sans clé de licence | | httpStatus | number \| null | Statut HTTP lorsque disponible | | retryable | boolean | Indique une indisponibilité potentiellement temporaire |

Codes d’erreur serveur

| Code | Signification | Retry automatique | |---|---|---:| | LICENSE_INVALID | Clé inconnue ou invalide | non | | LICENSE_EXPIRED | Licence arrivée à expiration | non | | LICENSE_SUSPENDED | Licence suspendue par le vendeur | non | | LICENSE_REVOKED | Licence révoquée définitivement | non | | INSTANCE_NOT_ACTIVATED | Instance non activée ou désactivée | non | | ACTIVATION_LIMIT_REACHED | Nombre maximal d’installations atteint | non | | DEACTIVATION_NOT_ALLOWED | Désactivation interdite par le produit | non | | INVALID_PRODUCT | Licence utilisée avec un autre produit | non | | INVALID_REQUEST | Requête malformée | non | | UNAUTHORIZED | Authentification refusée | non | | FORBIDDEN | Opération interdite | non | | RATE_LIMITED | Limite de requêtes atteinte | oui | | TEMPORARILY_UNAVAILABLE | Service temporairement indisponible | oui |

Erreurs propres au client SDK :

  • NETWORK_ERROR
  • TIMEOUT
  • ABORTED
  • INVALID_RESPONSE

Timeout, AbortSignal et retries

Chaque méthode accepte un AbortSignal optionnel :

const controller = new AbortController();

const validationPromise = licensing.validate(
  { licenseKey, instanceId },
  { signal: controller.signal },
);

cancelButton.addEventListener("click", () => controller.abort());

await validationPromise;

Le SDK peut réessayer uniquement :

  • une erreur réseau temporaire ;
  • un HTTP 429 ;
  • certains HTTP 5xx ;
  • TEMPORARILY_UNAVAILABLE.

Il respecte Retry-After lorsqu’il est fourni.

Le SDK ne réessaie jamais automatiquement les refus définitifs comme une licence invalide, expirée, suspendue, révoquée ou une limite d’activation atteinte.

Validation en ligne et comportement offline

Digitea ne définit actuellement aucune politique offline permissive.

Une erreur réseau :

  • ne transforme jamais une licence invalide en licence valide ;
  • ne transforme jamais une licence valide en licence invalide ;
  • reste une erreur technique distincte avec retryable: true.

Votre application doit présenter un état temporairement indisponible adapté à son usage. N’inventez pas une autorisation locale permanente à partir d’un échec réseau.

Intégration Electron

Utilisez le SDK dans le process principal, jamais dans le renderer.

// main/licensing.ts
import { ipcMain } from "electron";
import { DigiteaLicensing } from "@digitea/licensing";

const licensing = new DigiteaLicensing({
  productId: "prd_votreproduit",
});

ipcMain.handle("licensing:validate", async (_event, input) => {
  const result = await licensing.validate(input);
  return {
    valid: result.valid,
    status: result.status,
    expiresAt: result.expiresAt,
  };
});

Exposez au renderer une API IPC minimale via contextBridge. Ne transmettez pas de clé Developer API et ne désactivez pas l’isolation de contexte pour faciliter l’intégration.

Le SDK ne stocke jamais la licenseKey. Si votre application choisit de la conserver localement, utilisez un mécanisme adapté à sa plateforme et ne l’écrivez pas dans les logs, crash reports ou analytics.

Utilisation Node.js

import { DigiteaLicensing } from "@digitea/licensing";

const licensing = new DigiteaLicensing({
  productId: process.env.DIGITEA_PRODUCT_ID!,
});

const result = await licensing.validate({
  licenseKey: process.env.CUSTOMER_LICENSE_KEY!,
  instanceId: process.env.APP_INSTANCE_ID!,
});

Node.js 18+ fournit nativement fetch, AbortController et Web Crypto.

Runtime API sans SDK

Le SDK appelle exclusivement :

  • POST /v1/licenses/activate
  • POST /v1/licenses/validate
  • POST /v1/licenses/deactivate
  • POST /v1/licenses/renewal-session
  • POST /v1/licenses/renewal-session/status

Exemple curl :

curl https://api.getdigitea.com/v1/licenses/validate \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{
    "productId": "prd_votreproduit",
    "licenseKey": "<clé-de-licence-client>",
    "instanceId": "identifiant-installation-stable"
  }'

La Runtime API ne nécessite jamais :

  • une clé dgt_sk_live_... ;
  • un secret whsec_... ;
  • une session vendeur ;
  • un compte vendeur.

Developer API et webhooks

La Developer API permet à votre serveur de lister, suspendre, réactiver ou révoquer les licences de vos logiciels. Elle utilise une clé serveur dgt_sk_live_....

Les webhooks Licensing notifient notamment :

  • license.issued
  • license.activated
  • license.deactivated
  • license.suspended
  • license.reactivated
  • license.revoked
  • license.expired
  • license.renewed

Les webhooks sont signés avec un secret séparé whsec_..., un timestamp et HMAC-SHA256. Ils ne sont pas traités par ce SDK Runtime.

Consultez le portail développeur Digitea pour la référence API, la vérification HMAC et les exemples prêts à adapter.

Exports publics

DigiteaLicensing
DigiteaLicensingConfig
ActivateInput
ActivationResult
ValidateInput
ValidationResult
DeactivateInput
DeactivationResult
LicenseStatus
LicensingErrorCode
LicensingClientErrorCode
DigiteaLicensingError
InstanceStorage
RequestOptions
RetryConfig
generateIdempotencyKey
CreateRenewalSessionInput
RenewalStatusInput
RenewalSessionResult
RenewalStatusResult
generateInstanceId

Les statuts et codes d’erreur exportés correspondent au contrat public de l’API Digitea.

Sécurité

  • N’intégrez jamais une Developer API key dans une application distribuée.
  • Ne journalisez jamais licenseKey.
  • Ne placez jamais de secret webhook dans le client.
  • Utilisez uniquement HTTPS en production.
  • Persistez instanceId, mais ne l’utilisez pas comme secret.
  • Ne construisez pas un fingerprint matériel invasif.
  • Gardez les erreurs réseau distinctes des refus de licence.
  • Ne mettez pas en cache les réponses Runtime dans un CDN.

Le SDK évite volontairement d’inclure la clé de licence dans ses messages d’erreur.

TypeScript

Le package fournit directement ses déclarations :

import type {
  ActivateInput,
  ActivationResult,
  DigiteaLicensingConfig,
  LicenseStatus,
  LicensingErrorCode,
} from "@digitea/licensing";

Aucun paquet @types/* supplémentaire n’est nécessaire.

Support navigateurs

Le client repose sur Fetch et peut être compilé par certains bundlers navigateur. Cependant, les appels restent soumis à la politique CORS de Digitea.

Les cibles officiellement recommandées pour cette première version sont :

  • Node.js ;
  • process principal Electron.

Ne placez jamais une Developer API key dans du JavaScript navigateur.

FAQ

La licence est-elle liée au matériel ?

Non. Digitea utilise un identifiant stable fourni par l’application et n’impose aucun fingerprint matériel.

Le SDK conserve-t-il la clé de licence ?

Non. Il utilise la clé uniquement pour la requête en cours.

Puis-je réutiliser instanceId après redémarrage ?

Oui, c’est précisément son objectif. Il doit être persisté.

Pourquoi validate renvoie INSTANCE_NOT_ACTIVATED ?

L’instance doit d’abord appeler activate(), ou elle a déjà été désactivée.

Une licence perpétuelle doit-elle être validée ?

Oui. Perpétuelle signifie sans date d’expiration, pas sans contrôle de suspension ou révocation.

Une validation déclenche-t-elle un webhook ?

Non. Les validations fréquentes ne génèrent pas de webhook.

Puis-je utiliser le SDK hors ligne ?

Aucune politique offline permissive n’est fournie actuellement. Une indisponibilité réseau reste une erreur technique.

Ressources

Licence

MIT © Digitea

Renouveler une licence limitée

validate() expose renewable. Quand cette valeur est vraie, votre application peut demander une session de paiement Digitea :

const renewal = await licensing.createRenewalSession({
  licenseKey,
  instanceId,
});

await openInBrowser(renewal.checkoutUrl);

Le SDK n’effectue aucun paiement local et ne modifie aucune date. Après confirmation, appelez de nouveau validate() pour obtenir le nouvel expiresAt. Les licences perpétuelles, suspendues ou révoquées ne peuvent pas ouvrir de session.

Responsabilités et identifiants

Le vendeur conserve le productId public de son logiciel dans sa configuration. Le client fournit la licenseKey complète après son achat. Le SDK génère et persiste un instanceId stable, puis l’envoie avec la clé pour activate(), validate(), deactivate() ou createRenewalSession().

Le licenseId public permet au vendeur de retrouver une licence dans la Developer API, mais ne permet pas de valider une installation. La Developer API ne liste pas les produits et ne révèle jamais les clés complètes ; les releases et artifacts se gèrent dans le dashboard vendeur.