/** * Generic constructor type used for dependency registration and injection. * Represents any class constructor that can be used with the DI container. * * @template T - The type of object the constructor creates * * @example * // Use with service registration * class UserService {} * const ctor: Constructor = UserService; * serviceCollection.registerByType(ctor, { inject: [] }); */ export type Constructor = new (...args: any[]) => T; /** * Controls how service instances are shared across the container hierarchy. * Used when registering services to define their lifetime behavior. * * - `global`: Single instance shared everywhere (singleton pattern) * - `closest`: New instance per container scope (scoped lifetime) * * @example * // Singleton service - same instance everywhere * serviceCollection.register(LoggerService, { scope: 'global', inject: [] }); * * // Scoped service - new instance per scope * serviceCollection.register(RequestContext, { scope: 'closest', inject: [] }); */ export type ServiceScope = 'global' | 'closest'; /** * Configuration options for registering a service in the DI container. * Controls identification, lifetime, and dependency resolution. * * @example * // Register with constructor injection * const options: RegistrationOptions = { * scope: 'global', * inject: [DatabaseConnection, ConfigService] * }; * serviceCollection.register(UserRepository, options); * * @example * // Register with property injection * const options: RegistrationOptions = { * inject: [], * properties: { logger: Logger, config: 'appConfig' } * }; * * @example * // Register with a pre-created instance * const options: RegistrationOptions = { * inject: [], * instance: existingService * }; */ export interface RegistrationOptions { /** Service lifetime - 'global' for singleton, 'closest' for scoped */ scope?: ServiceScope; /** Optional string key for resolving by name instead of type */ key?: string; /** Pre-existing instance to use instead of creating new one */ instance?: unknown; /** Types or keys for constructor parameters, in order */ inject: (string | Constructor)[]; /** Map of property names to their injection types/keys */ properties?: Record; } /** * Field decorator that collects property injection configuration. * Updates or creates the properties mapping in registration options. * * @example * @ContainerService({ * inject: [Database], * properties: { * logger: Logger, // Inject by type * audit: 'auditLogger' // Inject by key * } * }) * class UserService { * @Inject(Logger) * private logger!: Logger; * * @Inject('auditLogger') * private audit!: Logger; * * constructor(db: Database) {} * } */ export declare function Inject(typeOrKey: Constructor | string): (_: undefined, context: ClassFieldDecoratorContext) => (this: any) => T; /** * Class decorator that automatically registers a service in the global DI container. * Use this to declaratively register services without manual registration calls. * * Services are registered at module load time, so ensure this file is imported * before attempting to resolve the decorated service. * * @param options - Registration configuration including scope and dependencies * * @example * // Simple service with constructor injection * @ContainerService({ inject: [DatabaseConnection] }) * class UserRepository { * constructor(private db: DatabaseConnection) {} * } * * @example * // Service with custom key for named resolution * @ContainerService({ key: 'primaryCache', scope: 'global', inject: [] }) * class CacheService {} * * // Later resolve by key * const cache = container.resolve('primaryCache'); */ export declare function ContainerService(options?: RegistrationOptions): (target: Constructor) => void; /** * Internal class representing a registered service's metadata. * Holds all information needed to create and configure service instances. * * @internal This is an implementation detail and should not be used directly. */ declare class Registration { classConstructor: Constructor; scope: ServiceScope; inject: (string | Constructor)[]; properties: Record; key?: string; instance?: unknown; /** * Creates a new registration record. * * @param classConstructor - The class constructor function * @param scope - Instance sharing behavior * @param inject - Constructor parameter dependencies * @param properties - Property injection mappings * @param key - Optional string identifier * @param instance - Optional pre-created instance */ constructor(classConstructor: Constructor, scope: ServiceScope, inject: (string | Constructor)[], properties?: Record, key?: string, instance?: unknown); } /** * Registry that stores service registration metadata. * Use this to register services before they can be resolved by a ServiceContainer. * * Typically you'll use the global `serviceCollection` instance rather than creating your own. * * @example * // Register a service by type * serviceCollection.registerByType(LoggerService, { inject: [] }); * * // Register with a string key * serviceCollection.register(CacheService, { key: 'cache', inject: [] }); * * // Check if service is registered * const reg = serviceCollection.tryGet(LoggerService); * if (reg) { * console.log('Logger is registered'); * } */ export declare class ServiceCollection { private servicesByKey; private servicesByClassName; /** * Registers a service with full configuration options. * The service will be resolvable by both its class name and optional key. * * @param constructor - The service class constructor * @param options - Registration configuration */ register(constructor: Constructor, options: RegistrationOptions): void; /** * Registers a service by its class type. * The service will be resolvable by its class constructor. * * @param constructor - The service class constructor * @param options - Optional registration configuration */ registerByType(constructor: Constructor, options?: RegistrationOptions): void; private checkNameCollision; private validateRegistration; /** * Attempts to retrieve a service registration. * Returns undefined if the service is not registered. * * @param key - Either a string key or class constructor * @returns The registration or undefined */ tryGet(key: string | Constructor): Registration | undefined; /** * Retrieves a service registration or throws if not found. * * @param key - Either a string key or class constructor * @returns The registration * @throws Error if the service is not registered */ get(key: string | Constructor): Registration; } /** * IoC container that resolves and manages service instances. * Creates instances based on registrations in a ServiceCollection, * handling constructor injection, property injection, and lifetime management. * * Typically you'll use the global `container` instance rather than creating your own. * * @example * // Resolve a service by class * const logger = container.resolve(LoggerService); * * // Resolve by string key * const cache = container.resolve('primaryCache'); * * @example * // Full setup workflow * serviceCollection.register(UserService, { * inject: [DatabaseConnection], * scope: 'global' * }); * * const userService = container.resolve(UserService); */ export declare class ServiceContainer { private serviceCollection; private instances; /** * Creates a new container backed by the given service collection. * * @param serviceCollection - The registry containing service registrations */ constructor(serviceCollection: ServiceCollection); /** * Resolves a service instance by class type or string key. * Creates the instance if not already cached (for global scope). * Handles constructor and property injection automatically. * * @param keyOrType - Either a string key or class constructor * @returns The resolved service instance * @throws Error if the service is not registered * * @example * const service = container.resolve(MyService); */ resolve(keyOrType: string | Constructor): T; /** * Creates a new instance of a service, resolving all constructor dependencies. */ private createInstance; /** * Injects dependencies into instance properties based on registration config. */ private injectFields; } /** * Global service collection instance for registering services. * Use this to register services that can later be resolved by the container. * * @example * import { serviceCollection } from 'relaxjs'; * * serviceCollection.register(MyService, { inject: [Dependency] }); */ export declare const serviceCollection: ServiceCollection; /** * Global service container instance for resolving dependencies. * Use this to obtain service instances with all dependencies injected. * * @example * import { container } from 'relaxjs'; * * const service = container.resolve(MyService); */ export declare const container: ServiceContainer; export {};