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

@bigbyte/ioc

v0.8.2

Published

<div align="center">

Readme

🔄️ @bigbyte/ioc - Inversion of Control

NPM Version License TypeScript

A lightweight and powerful IoC container for TypeScript with full support for dependency injection and component lifecycle management.

📋 Table of Contents

✨ Features

  • 🔄 Automatic dependency injection based on TypeScript metadata
  • 🏗️ Component registration with strong typing
  • 🎯 Multiple component types (Service, Repository, Controller, etc.)
  • 🔍 Intelligent resolution of circular dependencies
  • 📊 Event system for dynamic components
  • 🛡️ Robust error handling with specific exceptions
  • 🎮 Flexible and extensible programmatic API
  • 🔧 Granular component configuration
  • 📝 Native TypeScript with full type support

🚀 Installation

npm install @bigbyte/ioc

🔧 Basic Usage

Manual component registration

import { componentRegistry } from '@bigbyte/ioc';

class DatabaseService {
  connect() {
    console.log('Connecting to database...');
  }
}

class UserService {
  constructor(private dbService: DatabaseService) {}
  
  getUsers() {
    this.dbService.connect();
    return ['user1', 'user2'];
  }
}

// Manual registration
componentRegistry.add(DatabaseService, []);
componentRegistry.add(UserService, [DatabaseService]);

// Get instance
const userService = componentRegistry.getByClass(UserService);
console.log(userService.instance.getUsers());

Using the Injector

import { Injector, componentRegistry } from '@bigbyte/ioc';

const injector = componentRegistry.getByClass(Injector);

// Register component
injector.add(UserService);

// Check existence
if (injector.has(UserService)) {
  const component = injector.get(UserService);
  console.log(component?.instance);
}

🔍 Detailed API

Component

Each registered component has the following properties:

interface Component {
  readonly id: string;        // Unique generated ID
  readonly name: string;      // Class name
  readonly class: any;        // Class reference
  readonly instance: any;     // Component instance
  readonly options: ComponentOptions; // Configuration
  readonly createAt: Date;    // Creation date
}

The system supports different component types to better organize your architecture:

import { ComponentType } from '@bigbyte/ioc';

enum ComponentType {
  MAIN = 'MAIN',           // Main component
  COMPONENT = 'COMPONENT', // Generic component
  SERVICE = 'SERVICE',     // Business service
  REPOSITORY = 'REPOSITORY', // Data access
  CONTROLLER = 'CONTROLLER'  // Web controller
}

Component configuration

import { ComponentOptions } from '@bigbyte/ioc';

const options: ComponentOptions = {
  injectable: true,        // Whether it can be injected (default: true)
  type: ComponentType.SERVICE  // Component type (default: COMPONENT)
};

componentRegistry.add(UserService, [DatabaseService], options);

ComponentRegistry

add(Target, dependencies, options?): string

Registers a new component in the container.

const id = componentRegistry.add(
  UserService, 
  [DatabaseService], 
  { type: ComponentType.SERVICE }
);

getByClass(Target, strict?): Component | undefined

Gets a component by its class.

const component = componentRegistry.getByClass(UserService);
// With strict=false doesn't throw exception if it doesn't exist
const optional = componentRegistry.getByClass(OptionalService, false);

getById(id): Component

Gets a component by its unique ID.

const component = componentRegistry.getById('uuid-v4');

getByName(name): Component | undefined

Gets a component by its class name.

const component = componentRegistry.getByName('UserService');

has(value): boolean

Checks if a component exists (by class or ID).

const exists = componentRegistry.has(UserService);
const existsById = componentRegistry.has('component-id');

onComponentByName(name, callback): void

Listens for component availability asynchronously. The callback reacts when the component is added.

componentRegistry.onComponentByName('UserService', (component) => {
  console.log('UserService is available:', component.instance);
});

Injector

High-level service that is part of the component registry to access it programmatically.

const injector = componentRegistry.getByClass(Injector);

injector.add(MyService);           // Add component
const component = injector.get(MyService);  // Get component
const exists = injector.has(MyService);     // Check existence

🏗️ Architecture

Registration Flow

graph TD
    A[Class + Dependencies] --> B[ComponentRegistry.add()]
    B --> C[Resolve Dependencies]
    C --> D[Create Component]
    D --> E[Create Instance]
    E --> F[Emit Events]
    F --> G[Store in Registry]

Internal Structure

  • ComponentRegistry: Centralized component management
  • Component: Instance wrapper with metadata
  • Injector: High-level API for programmatic use
  • BufferComponent: Event system for dynamic components

⚠️ Error Handling

MissingDependencyError

Thrown when a required dependency is not found in the registry:

try {
  componentRegistry.getByClass(NonExistentService);
} catch (error) {
  if (error instanceof MissingDependencyError) {
    console.log('Missing dependency:', error.message);
  }
}

NonInjectableComponentError

Thrown when trying to inject a component marked as non-injectable:

// Component marked as non-injectable
componentRegistry.add(UtilityClass, [], { injectable: false });

// This will throw NonInjectableComponentError
componentRegistry.add(ServiceClass, [UtilityClass]);

CircularDependencyError

Circular dependencies are automatically detected:

// This will cause a circular dependency error
class ServiceA {
  constructor(serviceB: ServiceB) {}
}

class ServiceB {
  constructor(serviceA: ServiceA) {}
}

🔧 Advanced Examples

Repository Pattern

interface IUserRepository {
  findById(id: string): User;
  save(user: User): void;
}

class DatabaseUserRepository implements IUserRepository {
  constructor(private dbConnection: DatabaseConnection) {}
  
  findById(id: string): User {
    // Database implementation
  }
  
  save(user: User): void {
    // Database implementation
  }
}

class UserService {
  constructor(private userRepository: IUserRepository) {}
  
  getUser(id: string): User {
    return this.userRepository.findById(id);
  }
}

// Registration with specific type
componentRegistry.add(DatabaseConnection, [], { type: ComponentType.SERVICE });
componentRegistry.add(DatabaseUserRepository, [DatabaseConnection], { 
  type: ComponentType.REPOSITORY 
});
componentRegistry.add(UserService, [DatabaseUserRepository], { 
  type: ComponentType.SERVICE 
});

Event System

// Listen for multiple components
const requiredServices = ['UserService', 'EmailService', 'LoggerService'];

requiredServices.forEach(serviceName => {
  componentRegistry.onComponentByName(serviceName, (component) => {
    console.log(`✅ ${serviceName} loaded:`, component.createAt);
  });
});

// Services can be registered in any order
componentRegistry.add(EmailService, []);
componentRegistry.add(LoggerService, []);
componentRegistry.add(UserService, [EmailService, LoggerService]);

Conditional Configuration

class CacheService {
  constructor(private isProduction: boolean) {}
}

const isProduction = process.env.NODE_ENV === 'production';

// Registration with specific configuration
componentRegistry.add(CacheService, [], {
  injectable: isProduction, // Only injectable in production
  type: ComponentType.SERVICE
});

// Conditional usage
if (componentRegistry.has(CacheService)) {
  const cache = componentRegistry.getByClass(CacheService);
  // Use cache only if available
}

📄 License

This project is licensed under the Apache 2.0 license. See the LICENSE file for more details.


Developed with ❤️ by Jose Eduardo Soria Garcia

Part of the BigByte ecosystem