@aventii/config (1.0.1)

Published 2026-08-23 18:26:48 +00:00 by Valentin

Installation

@aventii:registry=
npm install @aventii/config@1.0.1
"@aventii/config": "1.0.1"

About this package

@aventii/config

Gestion de configuration commune aux services Aventii.

@aventii/config fournit un mécanisme générique de lecture, conversion, validation et sécurisation des variables de configuration des microservices Node.js.

Il permet notamment de :

  • déclarer les variables attendues sous forme de schéma ;
  • convertir automatiquement les valeurs vers les types attendus ;
  • appliquer des valeurs par défaut ;
  • valider les valeurs individuellement et globalement ;
  • agréger les erreurs de configuration ;
  • identifier les secrets ;
  • produire une représentation journalisable sans exposer les secrets ;
  • générer des fichiers .env dédiés à plusieurs microservices ;
  • produire un manifeste descriptif des variables attendues.

Le package ne dépend d'aucune configuration métier particulière.

Installation

Le package est distribué sur le registre npm privé Aventii.

npm install @aventii/config

Principes

@aventii/config sépare deux usages principaux :

  1. la construction de la configuration d'un microservice au démarrage ;
  2. le tooling permettant de générer des fichiers d'environnement dédiés à plusieurs services.

La configuration est construite à partir d'une source générique.

Par défaut, cette source est :

process.env

mais n'importe quel objet peut être fourni explicitement.

Le package ne charge pas lui-même un fichier .env lors de createConfig().

Création d'une configuration

Le package expose createConfig.

const {
    createConfig
} = require('@aventii/config');

const config = createConfig({
    PORT: {
        type: 'port',
        required: true
    },

    NODE_ENV: {
        type: 'string',
        enum: [
            'development',
            'production'
        ],
        default: 'development'
    },

    AUTH_TOKEN: {
        type: 'string',
        required: true,
        secret: true
    },

    USE_PROOF_OF_WORK: {
        type: 'boolean',
        default: false
    }
});

Les valeurs sont lues depuis process.env, converties puis validées.

Source personnalisée

Une source peut être injectée explicitement.

const config = createConfig(
    {
        PORT: {
            type: 'port',
            required: true
        }
    },
    {
        source: {
            PORT: '8448'
        }
    }
);

Cela facilite notamment les tests et les outils de génération.

Types supportés

Les types actuellement disponibles sont :

string
string[]
integer
number
boolean
url
port
json

string

Les chaînes sont trimées par défaut.

NAME: {
    type: 'string'
}

Pour conserver les espaces :

NAME: {
    type: 'string',
    trim: false
}

string[]

Par défaut, les valeurs sont séparées par des virgules.

CORS_ORIGINS: {
    type: 'string[]'
}

Exemple :

https://a.example.com,https://b.example.com

Un séparateur personnalisé peut être fourni :

CORS_ORIGINS: {
    type: 'string[]',
    separator: ';'
}

Les éléments vides sont supprimés.

integer

RETRY_COUNT: {
    type: 'integer'
}

Seuls les entiers sûrs JavaScript sont acceptés.

number

RATIO: {
    type: 'number'
}

La valeur doit être un nombre fini.

boolean

USE_PROOF_OF_WORK: {
    type: 'boolean'
}

Les booléens sont volontairement stricts.

Les valeurs textuelles acceptées sont uniquement :

true
false

La casse et les espaces sont ignorés.

Les formes suivantes ne sont pas acceptées :

1
0
yes
no
on
off

url

KEY_API_URL: {
    type: 'url'
}

La valeur doit être comprise par l'API URL de Node.js.

port

PORT: {
    type: 'port'
}

La valeur doit être un entier compris entre 1 et 65535.

json

OPTIONS: {
    type: 'json'
}

Une chaîne est décodée avec JSON.parse().

Une valeur déjà fournie sous forme d'objet est conservée telle quelle.

Variables obligatoires et valeurs par défaut

Une variable obligatoire est déclarée avec :

AUTH_TOKEN: {
    type: 'string',
    required: true
}

Une valeur par défaut peut être fournie :

PORT: {
    type: 'port',
    default: 8448
}

Une variable optionnelle absente reste présente dans la configuration avec la valeur :

undefined

Contraintes supplémentaires

Plusieurs règles peuvent être combinées dans une définition.

Valeurs autorisées

NODE_ENV: {
    type: 'string',
    enum: [
        'development',
        'production'
    ]
}

Minimum et maximum

Les contraintes min et max sont disponibles pour :

integer
number
port

Exemple :

RETRY_COUNT: {
    type: 'integer',
    min: 1,
    max: 5
}

Expression régulière

COUNTRY: {
    type: 'string',
    pattern: /^[A-Z]{2}$/
}

Transformation

Une valeur peut être transformée après sa conversion et avant sa validation.

COUNTRY: {
    type: 'string',

    transform: value =>
        value.toUpperCase(),

    enum: [
        'CM',
        'MG'
    ]
}

Validation personnalisée

EVEN_NUMBER: {
    type: 'integer',

    validate: value =>
        value % 2 === 0 ||
        'doit être pair'
}

La fonction peut retourner :

true
false
une chaîne décrivant l'erreur

Les validateurs doivent être synchrones.

Validation globale

Une validation portant sur l'ensemble de la configuration peut être fournie.

const config = createConfig(
    {
        MAIL_DISABLED: {
            type: 'boolean',
            required: true
        },

        SMTP_HOST: {
            type: 'string'
        }
    },
    {
        validate: config => {
            if (
                !config.MAIL_DISABLED &&
                !config.SMTP_HOST
            ) {
                return 'SMTP_HOST requis';
            }

            return true;
        }
    }
);

La validation globale est exécutée après la validation des champs.

Elle doit également être synchrone.

Agrégation des erreurs

Les erreurs de configuration sont regroupées dans une seule ConfigError.

const {
    ConfigError
} = require('@aventii/config');

Exemple :

[config] Configuration invalide

- AUTH_TOKEN: variable obligatoire absente
- PORT: port attendu entre 1 et 65535
- NODE_ENV: valeur non autorisée, valeurs possibles : development, production

Cela permet de corriger plusieurs problèmes de configuration en une seule fois au lieu de provoquer plusieurs cycles de démarrage.

L'erreur expose également :

error.errors

qui contient la liste structurée des anomalies.

Configuration immuable

Par défaut, la configuration produite est gelée récursivement.

const config = createConfig(schema);

Cela concerne également les tableaux et objets imbriqués produits par les types string[] et json.

Cette protection peut être désactivée :

const config = createConfig(
    schema,
    {
        freeze: false
    }
);

Secrets et journalisation

Une variable peut être marquée comme secrète.

AUTH_TOKEN: {
    type: 'string',
    required: true,
    secret: true
}

Le package expose redactConfig.

const {
    redactConfig
} = require('@aventii/config');

console.log(
    redactConfig(config)
);

Exemple :

{
    AUTH_TOKEN: '[REDACTED]',
    PORT: 8448
}

Seules les variables explicitement déclarées avec secret: true sont masquées.

Métadonnées de configuration

Le package associe des métadonnées internes aux configurations créées avec createConfig().

const {
    getConfigMetadata
} = require('@aventii/config');

const metadata =
    getConfigMetadata(config);

La structure retournée contient actuellement :

{
    generatedAt,
    secretKeys
}

Un objet qui n'a pas été créé par createConfig() retourne :

null

Les métadonnées retournées sont une copie défensive.

Environnements générés

Le package réserve la variable :

AVENTII_CONFIG_GENERATED_AT

Lorsqu'elle est présente dans la source, createConfig() vérifie sa validité et mémorise sa date dans les métadonnées.

La valeur n'est pas ajoutée à la configuration métier.

Exemple de log :

[config] pmc-pdf — environnement généré le 2026-08-20T11:14:32.481Z

Le nom du service peut être fourni :

createConfig(schema, {
    name: 'pmc-pdf'
});

Le logger est configurable :

createConfig(schema, {
    logger: customLogger
});

ou désactivable :

createConfig(schema, {
    logger: null
});

Lecture d'un fichier .env

Le tooling expose readEnvFile.

const {
    readEnvFile
} = require('@aventii/config');

const source =
    readEnvFile('/path/to/.env');

La fonction utilise dotenv.parse().

Elle retourne un objet contenant les valeurs du fichier mais ne modifie pas :

process.env

readEnvFile() appartient au tooling.

createConfig() lui-même reste indépendant de tout fichier .env.

Génération de fichiers d'environnement

generateEnvFiles permet de générer un fichier dédié à chaque microservice à partir d'une source commune.

const {
    generateEnvFiles
} = require('@aventii/config');

const result = generateEnvFiles({
    services: {
        'pmc-pdf': {
            AUTH_TOKEN: {
                type: 'string',
                required: true,
                secret: true
            },

            PDF_PORT: {
                type: 'port',
                required: true
            }
        },

        'pmc-di': {
            AUTH_TOKEN: {
                type: 'string',
                required: true,
                secret: true
            },

            DI_PORT: {
                type: 'port',
                required: true
            }
        }
    },

    source: masterEnvironment,

    outputDirectory:
        './env-generated'
});

Le résultat contient :

{
    generatedAt,
    files,
    manifestPath
}

Projection par service

Chaque fichier généré contient uniquement les variables déclarées dans le schéma du service concerné.

Une variable présente dans la source globale mais absente du schéma du service n'est pas écrite dans son fichier.

Exemple :

env-generated/
├── pmc-di.env.generated
├── pmc-pdf.env.generated
└── env-manifest.json

Les variables optionnelles absentes sont omises.

Les valeurs par défaut sont en revanche projetées.

Chaque configuration est validée avec createConfig() avant l'écriture du fichier correspondant.

Horodatage de génération

Tous les fichiers produits lors d'une même génération utilisent exactement le même horodatage.

Exemple :

# Generated by @aventii/config
# Service: pmc-pdf
# Generated at: 2026-08-20T11:14:32.481Z
AVENTII_CONFIG_GENERATED_AT='2026-08-20T11:14:32.481Z'

Le même horodatage est également enregistré dans le manifeste.

Manifeste d'environnement

Le manifeste peut aussi être créé indépendamment avec createEnvManifest.

const {
    createEnvManifest
} = require('@aventii/config');

const manifest =
    createEnvManifest(services);

Le manifeste décrit les variables attendues mais ne contient aucune valeur réelle.

Exemple :

{
    generatedAt: '...',
    services: {
        'pmc-pdf': {
            variables: {
                AUTH_TOKEN: {
                    type: 'string',
                    required: true,
                    secret: true,
                    hasDefault: false
                }
            }
        }
    }
}

Selon la définition, le manifeste peut également exposer :

enum
min
max
pattern

Les valeurs par défaut elles-mêmes ne sont pas exposées.

Seule leur présence est indiquée via :

hasDefault

Emplacement du manifeste

Par défaut, le manifeste est généré dans :

<outputDirectory>/env-manifest.json

Un emplacement différent peut être fourni :

generateEnvFiles({
    services,
    source,
    outputDirectory,
    manifestPath:
        './env-manifest.json'
});

Nettoyage des fichiers générés

Avant une nouvelle génération, le package supprime dans le répertoire de sortie :

*.env.generated
env-manifest.json

Les autres fichiers sont conservés.

Les noms de services utilisés pour produire les fichiers sont validés afin d'empêcher notamment l'utilisation de chemins tels que :

../pmc-pdf

API

Le package expose actuellement :

createConfig
ConfigError

getConfigMetadata
redactConfig

readEnvFile
createEnvManifest
generateEnvFiles

GENERATED_AT_KEY

Articulation avec les autres packages Aventii

Le rôle attendu de @aventii/config est généralement situé au début du cycle de vie du microservice.

process.env / fichier maître
        ↓
@aventii/config
        ↓
configuration validée et typée
        ↓
infrastructure/
        ↓
@aventii/runtime
@aventii/db
@aventii/link
@aventii/security
...

Les autres packages peuvent ainsi recevoir une configuration déjà convertie et validée.

Hors périmètre

@aventii/config ne décide pas :

  • quelles variables un produit doit définir ;
  • quelles valeurs doivent être utilisées en production ;
  • comment les secrets sont obtenus ou renouvelés ;
  • où les secrets sont stockés ;
  • comment les fichiers générés sont distribués ;
  • comment Docker ou un orchestrateur injecte les variables ;
  • quelles règles métier dépendent d'une configuration ;
  • comment un microservice doit démarrer ou s'arrêter.

Ces décisions appartiennent aux services consommateurs et à leur infrastructure.

Tests

npm test

Les tests couvrent notamment :

  • les différents types de valeurs ;
  • les valeurs par défaut ;
  • les variables obligatoires ;
  • l'agrégation des erreurs ;
  • les booléens stricts ;
  • les ports ;
  • enum, min, max et pattern ;
  • les transformations ;
  • les validations personnalisées et globales ;
  • l'interdiction des validateurs asynchrones ;
  • le gel récursif ;
  • le masquage des secrets ;
  • les métadonnées ;
  • l'horodatage des environnements générés ;
  • la lecture de fichiers .env ;
  • la génération par service ;
  • le manifeste ;
  • le nettoyage des artefacts générés ;
  • la validation des noms de services.

Dependencies

Dependencies

ID Version
dotenv ^17.4.2
Details
npm
2026-08-23 18:26:48 +00:00
58
UNLICENSED
latest
9.3 KiB
Assets (1)
Versions (2) View all
1.0.1 2026-08-23
1.0.0 2026-08-20