lightweight-sdk/packages/common/service-registry
Nicolas 544614add7
All checks were successful
CI / build-lint-test (pull_request) Successful in 34s
Simplifier : retirer le generique de @Service, ajouter services
- @Service(uid) n'a plus de parametre generique : un decorateur de
  propriete legacy ne peut de toute facon pas changer le type du champ
  qu'il decore, seule son annotation compte. Le generique n'apportait
  rien.
- Nouvelle constante exportee services = ServiceRepository.getInstance(),
  instance prete a l'emploi : services.get<T>(uid), services.has(uid),
  services.register(uid, Classe). C'est desormais le point d'entree
  recommande plutot que ServiceRepository.getInstance() directement.
- ServiceRepository.resolve() renomme en get() pour matcher
  services.get<T>(uid).
- resetForTesting() vide la map en place (Map.clear()) au lieu de
  jeter l'instance singleton, pour que la constante services capturee
  au chargement du module reste valide apres un reset dans les tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 14:31:42 +02:00
..
src Simplifier : retirer le generique de @Service, ajouter services 2026-09-18 14:31:42 +02:00
package.json Corriger pnpm-lock.yaml : entree manquante pour service-registry 2026-09-18 14:06:19 +02:00
README.md Simplifier : retirer le generique de @Service, ajouter services 2026-09-18 14:31:42 +02:00
tsconfig.json Ajouter @lightweight-sdk/service-registry (packages/common) 2026-09-18 13:59:58 +02:00

@lightweight-sdk/service-registry

Registre de services en singleton, avec enregistrement par décorateur et résolution directe. Package common : isomorphe, aucune dépendance DOM ou Node-only.

Installation

pnpm add @lightweight-sdk/service-registry

Usage

import { RegisterService, Service, services } from '@lightweight-sdk/service-registry';

export const LOGGER_UID = 'logger';

@RegisterService(LOGGER_UID)
class LoggerService {
	public log(message: string): void {
		console.log(message);
	}
}

// Injection déclarative sur une propriété
class ReportGenerator {
	@Service(LOGGER_UID)
	private readonly logger!: LoggerService;

	public run(): void {
		this.logger.log('generating report');
	}
}

// Résolution directe, n'importe où
const logger = services.get<LoggerService>(LOGGER_UID);
logger.log('hello');

Concepts

  • services — constante globale, instance prête à l'emploi du ServiceRepository. C'est le point d'entrée à utiliser partout : services.get<T>(uid), services.has(uid), services.register(uid, MaClasse).
  • ServiceRepository — la classe singleton derrière services (accès direct rarement nécessaire, exportée pour le typage et les tests).
  • @RegisterService(uid) — décorateur de classe. Instancie la classe décorée (constructeur sans argument obligatoire) et l'enregistre sous uid. C'est au développeur de choisir uid et de garantir son unicité — la registry refuse tout doublon.
  • @Service(uid) — décorateur de propriété. Injecte l'instance enregistrée sous uid dans le membre décoré. Pas de typage générique sur le décorateur : un décorateur de propriété ne peut pas changer le type du champ qu'il décore, donc c'est l'annotation du champ (private readonly logger!: LoggerService;) qui le type, comme d'habitude. La résolution est paresseuse (au premier accès à la propriété, pas à la décoration) : peu importe que la classe consommatrice soit évaluée avant ou après l'enregistrement du service. Après le premier accès, la propriété est remplacée par la valeur résolue (pas de nouvelle recherche ensuite).

Contraintes

  • Une classe décorée par @RegisterService(uid) doit avoir un constructeur sans argument obligatoire — ses propres dépendances doivent elles-mêmes être injectées via @Service ou services.get, pas passées au constructeur.
  • uid doit être unique dans toute l'application — exporter une constante partagée (comme LOGGER_UID ci-dessus) entre le point d'enregistrement et les points d'injection évite les fautes de frappe.
  • experimentalDecorators: true doit être activé côté consommateur (déjà le cas dans ce monorepo via tsconfig.base.json).

API

  • services — instance singleton prête à l'emploi (get<T>(uid), has(uid), register(uid, target)).
  • RegisterService(uid) — décorateur de classe.
  • Service(uid) — décorateur de propriété.
  • ServiceRepository — la classe singleton (getInstance(), register(uid, target), get<T>(uid), has(uid)). resetForTesting() est réservé aux tests.
  • ServiceConstructor<T>, ServiceUid — types associés.