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

@aveplus_dev/uemoa-qrcode-sdk

v1.0.1

Published

SDK JavaScript/TypeScript pour la generation et lecture de QR codes de paiement conformes a la norme BCEAO/UEMOA (portage du SDK Java uemoa-qrcode-sdk-core)

Readme

@aveplus_dev/uemoa-qrcode-sdk

SDK JavaScript/TypeScript pour la génération et la lecture de QR codes de paiement conformes à la norme BCEAO/UEMOA (standard EMVCo).

Portage du SDK Java de référence uemoa-qrcode-sdk-core, avec tests d'interopérabilité croisés garantissant qu'un QR généré par un SDK est lisible par les autres (Java, JavaScript, Python).


Sommaire

  1. Installation
  2. Démarrage rapide
  3. Types de QR supportés
  4. Référence de l'API
  5. Règles de validation
  6. Interopérabilité entre SDK
  7. Développement local
  8. Publication du SDK sur npm
  9. Structure du projet

1. Installation

npm install @aveplus_dev/uemoa-qrcode-sdk

Le package est publié en dual build : il fonctionne aussi bien en CommonJS (require) qu'en ESM (import), et embarque ses propres types TypeScript.


2. Démarrage rapide

import { UemoaQRService, MerchantChannel } from "@aveplus_dev/uemoa-qrcode-sdk";

const service = new UemoaQRService();

// --- Génération ---
const qrData = service.generateStaticQR({
  type: "STATIC",
  merchantChannel: MerchantChannel.STATIC_WITH_AMOUNT,
  merchantInfo: {
    alias: "shop-001",
    name: "MA BOUTIQUE",
    city: "Ouagadougou",
    countryCode: "BF",
  },
  amount: 2500,
});
// "00020101021136280012int.bceao.pi0108shop-001..."

// --- Image PNG (base64, sans le préfixe data:) ---
const imageBase64 = await service.generateQRImageFromString(qrData);

// --- Lecture d'un QR scanné ---
const details = service.getQRCodeDetails(qrData);
// { valid: true, type: "STATIC", amount: "2500",
//   channel: { code: 110, ... },
//   merchant: { alias, name, city, country }, transactionId }

// --- Validation (CRC + cohérence structurelle) ---
const isValid = service.validateQRCode(qrData); // true

3. Types de QR supportés

| Type | Usage | Méthode | |---|---|---| | Statique | QR fixe affiché en boutique, réutilisable par plusieurs clients | generateStaticQR() | | Dynamique | QR généré pour une transaction précise (montant, e-commerce) | generateDynamicQR() | | P2P | Transfert entre particuliers | generateP2PQR() |

generateQRData() route automatiquement selon le champ type.

Canaux marchands (MerchantChannel)

| Constante | Code | Description | |---|---|---| | STATIC_ONSITE | 100 | QR statique sur site | | STATIC_WITH_AMOUNT | 110 | QR statique avec montant | | STATIC_WITH_TXID | 120 | QR statique avec ID transaction | | STATIC_INVOICE | 131 | QR statique sur facture | | DYNAMIC_ONSITE | 500 | QR dynamique sur site | | DYNAMIC_ECOMMERCE_WEB | 521 | QR dynamique e-commerce Web | | DYNAMIC_ECOMMERCE_APP | 522 | QR dynamique e-commerce App | | P2P_STATIC | 731 | QR statique pour particulier |


4. Référence de l'API

UemoaQRService

Façade principale, couvre la majorité des besoins d'intégration.

| Méthode | Retour | Description | |---|---|---| | generateQRData(data) | string | Génère selon data.type | | generateStaticQR(data) | string | Génère un QR statique | | generateDynamicQR(data) | string | Génère un QR dynamique | | generateP2PQR(data) | string | Génère un QR P2P | | generateQRImageFromString(qr, size?, margin?) | Promise<string> | Image PNG en base64 | | parseQRCode(qr) | QRPaymentData | Parse, lève si invalide | | getQRCodeDetails(qr) | object | Parse, ne lève jamais ({valid:false, error} si KO) | | validateQRCode(qr) | boolean | Vérifie CRC + cohérence structurelle |

Structure des données d'entrée

interface QRPaymentData {
  type: "STATIC" | "DYNAMIC" | "P2P";
  merchantInfo?: {
    alias: string;        // identifiant du compte (obligatoire)
    name: string;         // max 25 caractères
    city: string;         // max 15 caractères
    countryCode: string;  // BF, CI, TG, SN, ML, BJ, GW, NE
    categoryCode?: string;
  };
  amount?: string | number;   // > 0, sans décimales (XOF)
  transactionId?: string;     // ^[A-Za-z0-9-]{1,25}$
  billReference?: string;     // ^[A-Za-z0-9-]{1,25}$
  subscriptionId?: string;    // ^[A-Za-z0-9-]{1,25}$
  merchantChannel?: MerchantChannelInfo;
  dynamicUrl?: string;
  additionalData?: Record<string, string>;
}

Classes bas niveau

Exportées pour les cas avancés : QRParser, CRCCalculator, EMVFormatter, StaticQRGenerator, DynamicQRGenerator, P2PQRGenerator.

Exceptions typées

| Classe | Levée quand | |---|---| | QRValidationError | Donnée d'entrée invalide (montant, pays, charset…) | | QRParsingError | QR illisible ou CRC invalide | | QRImageGenerationError | Échec de génération de l'image PNG |


5. Règles de validation

| Champ | Règle | |---|---| | amount | Strictement > 0, sans décimales (le XOF n'a pas de sous-unité). "2500.00" est toléré → 2500 ; 50.5 est rejeté | | countryCode | Doit appartenir à la zone UEMOA (8 pays) | | name | Obligatoire, max 25 caractères | | city | Obligatoire, max 15 caractères | | transactionId, billReference, subscriptionId | ^[A-Za-z0-9-]{1,25}$ | | Tous les champs texte | Doivent être représentables en ISO-8859-1 |

Contrainte de charset

Les caractères hors ISO-8859-1 (œ, , ou les orthographes de langues locales comme ɛ, ɔ, ŋ) sont rejetés avec une QRValidationError.

Raison : l'encodage ISO-8859-1 se comporte différemment selon le langage face à un caractère hors plage (remplacement silencieux en Java, exception en Python, corruption silencieuse en Node). Rejeter en amont garantit un comportement identique dans les trois SDK. Détails dans docs/DECISIONS.md.


6. Interopérabilité entre SDK

Un QR généré par ce SDK est lisible par les SDK Java et Python, et inversement. C'est garanti par deux mécanismes :

Vecteurs de test partagés — le fichier test-vectors/uemoa-qr-test-vectors.json est la source de vérité commune aux trois SDK. Il contient la spécification écrite et trois familles de vecteurs :

  • interopVectors — entrées à parser vers les mêmes données
  • canonicalVectors — sorties exactes attendues (générées par la référence Java)
  • validationVectors — entrées invalides à rejeter partout pareil

Tests croisés — la suite de tests relit des QR réellement générés par le SDK Java et vérifie que les données décodées sont identiques.

Ordre des sous-champs

import { setFieldOrderStrategy } from "@aveplus_dev/uemoa-qrcode-sdk";

setFieldOrderStrategy("java-hashmap"); // défaut : reproduit le SDK Java actuel
setFieldOrderStrategy("sorted");       // ordre canonique trié

Ce réglage n'affecte jamais la lecture : le parsing se fait par tag et non par position, et le CRC est recalculé sur les octets reçus. Les deux modes sont donc pleinement interopérables ; seule la comparaison octet-à-octet des chaînes diffère.


7. Développement local

git clone https://gitlab.avepay.net/qrcode/qrcode-module-backend-js.git
cd qrcode-module-backend-js

npm install     # installe les dépendances
npm test        # lance les 100 tests (Vitest)
npm run build   # génère dist/ (CJS + ESM + types)

Prérequis

  • Node.js 18+
  • npm 9+

Organisation des tests

| Fichier | Contenu | |---|---| | javaPortedTests.test.ts | 18 tests repris un-à-un des tests JUnit du SDK Java | | sharedVectors.test.ts | Tests pilotés par les vecteurs partagés | | crossValidation.test.ts | Tests croisés avec des QR réellement générés par Java | | charset.test.ts | Règle ISO-8859-1 et cohérence longueur TLV / octets | | crc.test.ts, emvFormatter.test.ts | Tests unitaires bas niveau | | orderStrategy.test.ts, reviewFixes.test.ts | Stratégies d'ordre et régressions |


8. Publication du SDK sur npm

Prérequis

  • Être membre de l'organisation npm aveplus_dev
  • Être authentifié : npm login puis vérifier avec npm whoami

Procédure

# 1. Vérifier que tout passe
npm test
npm run build

# 2. Incrémenter la version (semver)
npm version patch   # correction / documentation  (1.0.0 -> 1.0.1)
npm version minor   # nouvelle fonctionnalité     (1.0.1 -> 1.1.0)
npm version major   # changement incompatible     (1.1.0 -> 2.0.0)

# 3. Vérifier le contenu du package avant envoi
npm publish --dry-run

# 4. Publier
npm publish --access public

Contenu publié

Seuls dist/, test-vectors/ et docs/ sont inclus (champ files du package.json). Le code source TypeScript et les tests ne sont pas distribués.

Authentification à double facteur

L'organisation aveplus_dev impose la 2FA pour publier. Deux options :

  • 2FA activée sur le compte : ajouter --otp=XXXXXX à la commande

  • Token granulaire : créer un token avec l'option bypass 2FA, limité au scope @aveplus_dev et avec une expiration courte, puis :

    npm config set //registry.npmjs.org/:_authToken=<TOKEN>
    npm publish --access public
    npm config delete //registry.npmjs.org/:_authToken   # nettoyer après

    Ce token contourne la 2FA sur un module de paiement : ne jamais le committer, le révoquer immédiatement après usage.

Notes

  • Le package est publié en accès public. Les packages privés npm nécessitent un plan payant (erreur 402 Payment Required sinon).
  • Une version publiée ne peut pas être remplacée : toute correction passe par une nouvelle version.

9. Structure du projet

src/
  index.ts               → UemoaQRService (façade publique)
  models.ts              → MerchantInfo, QRPaymentData, MerchantChannel
  errors.ts              → exceptions typées
  crc.ts                 → CRC16-CCITT (ISO-8859-1, poly 0x1021, init 0xFFFF)
  emvFormatter.ts        → formatage / parsing TLV EMVCo
  validator.ts           → règles de validation
  parser.ts              → lecture d'un QR
  qrImage.ts             → génération d'image PNG (lib qrcode)
  generators/
    base.ts              → logique commune + stratégies d'ordre
    staticGenerator.ts
    dynamicGenerator.ts
    p2pGenerator.ts

tests/                   → 100 tests (Vitest)
test-vectors/            → vecteurs partagés entre les 3 SDK
docs/DECISIONS.md        → décisions de conception détaillées