From 113649441eef69aa63b0c846fcbb4ec48226e830 Mon Sep 17 00:00:00 2001 From: Julian Meyer Date: Mon, 14 Apr 2025 08:12:39 +0200 Subject: [PATCH] Prevent singletons with container-scoped dependencies by passing singleton-information within the resolution context and checking it during resolution. --- src/dependency-container.ts | 8 ++++++++ src/resolution-context.ts | 1 + 2 files changed, 9 insertions(+) diff --git a/src/dependency-container.ts b/src/dependency-container.ts index e829362..4d45c43 100644 --- a/src/dependency-container.ts +++ b/src/dependency-container.ts @@ -240,6 +240,13 @@ class InternalDependencyContainer implements DependencyContainer { this.executePreResolutionInterceptor(token, "Single"); + // Using a container scoped registration within a singleton is not allowed + if(registration && registration.options.lifecycle === Lifecycle.ContainerScoped && context.isSingleton) { + throw new Error( + `Attempted to use a container scoped registration "${token.toString()}" within a singleton` + ); + } + if (registration) { const result = this.resolveRegistration(registration, context) as T; this.executePostResolutionInterceptor(token, result, "Single"); @@ -313,6 +320,7 @@ class InternalDependencyContainer implements DependencyContainer { const isContainerScoped = registration.options.lifecycle === Lifecycle.ContainerScoped; + context.isSingleton = isSingleton; const returnInstance = isSingleton || isContainerScoped; let resolved: T; diff --git a/src/resolution-context.ts b/src/resolution-context.ts index 4f93da1..d69132b 100644 --- a/src/resolution-context.ts +++ b/src/resolution-context.ts @@ -2,4 +2,5 @@ import {Registration} from "./dependency-container"; export default class ResolutionContext { scopedResolutions: Map = new Map(); + isSingleton: boolean = false; }