Instrumenter tous les use cases avec un seul wrapper générique
instrumentContainer<C> ajoute la traçabilité à tous les use cases du conteneur d'injection de dépendances en une seule passe, et renvoie exactement le type C — aucun appelant n'a besoin d'un cast pour récupérer son use case. Le garde de type a été ajouté après un incident réel : un simple booléen du conteneur a atteint `new Proxy()` et mis l'API en panne le 24 septembre 2026.
export function instrumentUseCase<T extends object>(name: string, instance: T): T {
return new Proxy(instance, {
get(target, prop) {
const value = (target as Record<PropertyKey, unknown>)[prop]
if (prop !== 'execute' || typeof value !== 'function') {
return typeof value === 'function' ? value.bind(target) : value
}
// …
},
})
}
export function instrumentContainer<C extends Record<string, unknown>>(
container: C,
exclude: ReadonlySet<string>,
): C {
const isUseCase = (value: unknown): value is object =>
typeof value === 'object' &&
value !== null &&
typeof (value as { execute?: unknown }).execute === 'function'
return Object.fromEntries(
Object.entries(container).map(([key, value]) =>
exclude.has(key) || !isUseCase(value)
? [key, value]
: [key, instrumentUseCase(value.constructor.name, value)],
),
) as C
}SourceVotArenasrc/lib/observability/useCaseObservability.ts