npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vgerbot/ioc

v1.3.0

Published

A lightweight inversion of control container for Javascript powered by TypeScript

Downloads

214

Readme

@vgerbot/ioc

Codacy Badge Codacy Badge

A lightweight inversion of control (IoC) container for JavaScript powered by TypeScript, supporting dependency injection, lifecycle management, aspect-oriented programming (AOP), and other enterprise-grade features.

🌟 Key Features

  • 🔄 Dependency Injection: Complete dependency injection support, including constructor injection and property injection
  • 🔄 Lifecycle Management: Support for PreInject, PostInject, PreDestroy, and other lifecycle hooks
  • 🎯 Multiple Scopes: Support for Singleton, Transient, Global Shared Singleton, and other scopes
  • ✂️ AOP Support: Complete aspect-oriented programming support, including Before, After, Around, and other advice types
  • 🏭 Factory Pattern: Support for factory methods and custom instance creation strategies
  • 🔗 Multiple Binding Types: Support for symbol binding, alias binding, value binding, and more
  • 📊 Expression Evaluation: Support for JSON path, environment variables, command-line arguments, and other expression evaluation
  • 📡 Event System: Built-in event emitter supporting container lifecycle events

📦 Installation

npm install @vgerbot/ioc reflect-metadata

🚀 Quick Start

Basic Usage

import 'reflect-metadata';
import { ApplicationContext, Inject, Injectable } from '@vgerbot/ioc';

@Injectable()
class UserService {
    getUser(id: number) {
        return { id, name: 'John Doe' };
    }
}

class UserController {
    @Inject()
    private userService!: UserService;

    getUser(id: number) {
        return this.userService.getUser(id);
    }
}

const context = new ApplicationContext();
const controller = context.getInstance(UserController);
console.log(controller.getUser(1)); // { id: 1, name: 'John Doe' }

Constructor Injection

class DatabaseService {
    connect() {
        console.log('Database connected');
    }
}

class UserService {
    constructor(
        @Inject() private db: DatabaseService
    ) {}

    getUsers() {
        this.db.connect();
        return ['user1', 'user2'];
    }
}

const context = new ApplicationContext();
const userService = context.getInstance(UserService);
userService.getUsers();

🎯 Scope Management

The IoC container supports multiple instance scopes that control how and when instances are created and managed. Understanding these scopes is crucial for proper resource management and application architecture.

Scope Types Overview

| Scope | Description | Instance Lifecycle | Use Cases | |-------|-------------|-------------------|-----------| | Singleton | One instance per container | Created once, reused within container | Services, repositories, configurations | | Transient | New instance every time | Created on each request | Stateless operations, temporary objects | | Global Shared Singleton | One instance across all containers | Created once, shared globally | Global state, system-wide configurations |

Singleton

import { Scope, InstanceScope } from '@vgerbot/ioc';

@Scope(InstanceScope.SINGLETON)
class DatabaseConnection {
    private static connectionCount = 0;
    
    constructor() {
        DatabaseConnection.connectionCount++;
        console.log(`Connection #${DatabaseConnection.connectionCount} created`);
    }
}

const context = new ApplicationContext();
const conn1 = context.getInstance(DatabaseConnection);
const conn2 = context.getInstance(DatabaseConnection);
console.log(conn1 === conn2); // true - same instance

Transient

@Scope(InstanceScope.TRANSIENT)
class HttpRequest {
    private id = Math.random().toString(36);
    
    getId() {
        return this.id;
    }
}

const context = new ApplicationContext();
const req1 = context.getInstance(HttpRequest);
const req2 = context.getInstance(HttpRequest);
console.log(req1.getId() === req2.getId()); // false - different instances
console.log(req1 === req2); // false

Global Shared Singleton

@Scope(InstanceScope.GLOBAL_SHARED_SINGLETON)
class GlobalConfig {
    private config = { version: '1.0.0' };
    
    getVersion() {
        return this.config.version;
    }
    
    updateVersion(version: string) {
        this.config.version = version;
    }
}

const context1 = new ApplicationContext();
const context2 = new ApplicationContext();
const config1 = context1.getInstance(GlobalConfig);
const config2 = context2.getInstance(GlobalConfig);

console.log(config1 === config2); // true - shared across containers
config1.updateVersion('2.0.0');
console.log(config2.getVersion()); // '2.0.0' - shared state

🔄 Lifecycle Management

import { PreInject, PostInject, PreDestroy } from '@vgerbot/ioc';

class DatabaseService {
    connect() {
        console.log('Database connected');
    }
}

class UserService {
    @Inject()
    private db!: DatabaseService;

    @PreInject()
    beforeInject() {
        console.log('Before injection - db is', this.db); // undefined
    }

    @PostInject()
    afterInject() {
        console.log('After injection - db is', this.db); // DatabaseService instance
        this.db.connect();
    }

    @PreDestroy()
    beforeDestroy() {
        console.log('Cleaning up UserService');
    }
}

✂️ Aspect-Oriented Programming (AOP)

Before Advice

import { Aspect, JoinPoint, UseAspects, Advice } from '@vgerbot/ioc';

class LoggingAspect implements Aspect {
    execute(joinPoint: JoinPoint) {
        console.log(`Calling method: ${joinPoint.method}`);
        console.log(`Arguments:`, joinPoint.args);
    }
}

class UserService {
    @UseAspects(Advice.Before, [LoggingAspect])
    getUser(id: number) {
        return { id, name: 'John Doe' };
    }
}

Around Advice

import { ProceedingAspect, ProceedingJoinPoint } from '@vgerbot/ioc';

class TimingAspect implements ProceedingAspect {
    execute(joinPoint: ProceedingJoinPoint) {
        const start = Date.now();
        const result = joinPoint.proceed();
        const duration = Date.now() - start;
        console.log(`Method ${joinPoint.method} took ${duration}ms`);
        return result;
    }
}

class UserService {
    @UseAspects(Advice.Around, [TimingAspect])
    getUser(id: number) {
        // Simulate async operation
        return new Promise(resolve => {
            setTimeout(() => resolve({ id, name: 'John Doe' }), 100);
        });
    }
}

AfterReturn Advice

class TransformAspect implements Aspect {
    execute(joinPoint: JoinPoint) {
        // Modify return value
        return {
            ...joinPoint.returnValue,
            transformed: true
        };
    }
}

class UserService {
    @UseAspects(Advice.AfterReturn, [TransformAspect])
    getUser(id: number) {
        return { id, name: 'John Doe' };
    }
}

🏭 Factory Pattern and Binding

Factory Methods

import { Factory } from '@vgerbot/ioc';

class DatabaseConfig {
    constructor(public host: string, public port: number) {}
}

class ConfigFactory {
    @Factory('database-config')
    createDatabaseConfig(): DatabaseConfig {
        return new DatabaseConfig('localhost', 5432);
    }
}

const context = new ApplicationContext();
const config = context.getInstance('database-config') as DatabaseConfig;
console.log(config.host); // 'localhost'

Symbol Binding

import { Bind, Injectable } from '@vgerbot/ioc';

const USER_SERVICE = Symbol('UserService');

@Bind(USER_SERVICE)
class UserService {
    getUsers() {
        return ['user1', 'user2'];
    }
}

@Injectable({ produce: USER_SERVICE })
class MockUserService {
    getUsers() {
        return ['mock-user1', 'mock-user2'];
    }
}

const context = new ApplicationContext();

// Get instance by symbol
const userService = context.getInstance(USER_SERVICE);

Value Binding

import { Value, Env } from '@vgerbot/ioc';

class ApiService {
    @Value('config.api.baseUrl')
    private baseUrl!: string;

    @Env('NODE_ENV')
    private environment!: string;

    getApiUrl() {
        return `${this.baseUrl}/api`;
    }
}

const context = new ApplicationContext();
// Set JSON data
context.recordJSONData('config', {
    api: {
        baseUrl: 'https://api.example.com'
    }
});

const apiService = context.getInstance(ApiService);
console.log(apiService.getApiUrl()); // https://api.example.com/api

🎛️ Advanced Features

Custom Instantiation Processor

import { PartialInstAwareProcessor } from '@vgerbot/ioc';

class CustomInstAwareProcessor implements PartialInstAwareProcessor {
    beforeInstantiation<T>(constructor: any, args: unknown[]): T | undefined | void {
        console.log(`Creating instance of ${constructor.name}`);
        // Can return custom instance or undefined to let container continue
    }

    afterInstantiation<T extends object>(instance: T): T {
        console.log(`Instance created: ${instance.constructor.name}`);
        // Can modify instance and return it
        return instance;
    }
}

const context = new ApplicationContext();
context.registerInstAwareProcessor(CustomInstAwareProcessor);

Event Listening

const context = new ApplicationContext();

// Listen for pre-destroy events
context.onPreDestroy(() => {
    console.log('Container is about to be destroyed');
});

// Listen for specific instance pre-destroy events
context.onPreDestroyThat((instance) => {
    console.log(`Instance ${instance.constructor.name} is about to be destroyed`);
});

// Destroy container
context.destroy();

Function Invocation with Injection

import { Inject } from '@vgerbot/ioc';

class UserService {
    getUser(id: number) {
        return { id, name: 'John Doe' };
    }
}

function processUser(userService: UserService, userId: number) {
    return userService.getUser(userId);
}

const context = new ApplicationContext();

// Auto-inject function parameters
const result = context.invoke(processUser, {
    injections: [UserService, 42]
});

// Or use decorator to mark function parameters
function processUserWithDecorator(
    @Inject() userService: UserService,
    userId: number
) {
    return userService.getUser(userId);
}

const result2 = context.invoke(processUserWithDecorator, {
    args: [undefined, 42] // First parameter will be auto-injected
});

🔧 Configuration Options

import { ApplicationContext, InstanceScope } from '@vgerbot/ioc';

const context = new ApplicationContext({
    // Default scope
    defaultScope: InstanceScope.SINGLETON,
    
    // Lazy mode
    lazyMode: true
});

📋 API Reference

Decorators

  • @Injectable(options?) - Mark injectable class
  • @Inject(identifier?) - Dependency injection decorator
  • @Scope(scope) - Set instance scope
  • @Bind(identifier) - Bind identifier
  • @Factory(identifier) - Factory method
  • @Value(path) - Value injection
  • @Env(key) - Environment variable injection
  • @PreInject() - Pre-injection hook
  • @PostInject() - Post-injection hook
  • @PreDestroy() - Pre-destroy hook
  • @UseAspects(advice, aspects) - AOP aspects

Core Classes

  • ApplicationContext - Application context and container
  • InstanceScope - Instance scope enumeration
  • Advice - AOP advice type enumeration

Interfaces

  • Aspect - Aspect interface
  • ProceedingAspect - Around advice interface
  • InstanceResolution - Instance resolution interface
  • Evaluator - Expression evaluator interface

🤝 Contributing

Contributions are welcome! Please check the GitHub repository for more information.

📄 License

This project is licensed under the MIT License.