JSPM

  • Created
  • Published
  • Downloads 173
  • Score
    100M100P100Q117654F
  • License MIT

Lightweight dependency injection container built on Inversify for managing services and their lifecycle

Package Exports

  • @ooneex/container
  • @ooneex/container/package.json

Readme

@ooneex/container

A lightweight dependency injection container built on Inversify for managing services, their lifecycle, and dependencies. This package provides a simple yet powerful API for registering, resolving, and managing service instances with support for singletons, transients, and request-scoped dependencies.

Bun Deno Node.js TypeScript MIT License

Features

Dependency Injection - Full DI container with automatic dependency resolution

Multiple Scopes - Support for Singleton, Transient, and Request scopes

Service Aliases - Register services with string aliases for flexible resolution

Constant Values - Store and retrieve constant values across your application

Type-Safe - Full TypeScript support with proper type definitions

Inversify Based - Built on the battle-tested Inversify library

Shared Instance - Global container instance for easy access across modules

Installation

Bun

bun add @ooneex/container

pnpm

pnpm add @ooneex/container

Yarn

yarn add @ooneex/container

npm

npm install @ooneex/container

Usage

Basic Usage

import { container, EContainerScope } from '@ooneex/container';

class UserService {
  public getUsers() {
    return [{ id: 1, name: 'John' }];
  }
}

// Register as singleton (default)
container.add(UserService);

// Resolve instance
const userService = container.get(UserService);
console.log(userService.getUsers());

Different Scopes

import { container, EContainerScope } from '@ooneex/container';

class DatabaseConnection {
  public readonly id = Math.random();
}

class RequestLogger {
  public readonly id = Math.random();
}

class TemporaryWorker {
  public readonly id = Math.random();
}

// Singleton - same instance throughout app lifetime
container.add(DatabaseConnection, EContainerScope.Singleton);

// Request - new instance per request context
container.add(RequestLogger, EContainerScope.Request);

// Transient - new instance every time
container.add(TemporaryWorker, EContainerScope.Transient);

const db1 = container.get(DatabaseConnection);
const db2 = container.get(DatabaseConnection);
console.log(db1.id === db2.id); // true (singleton)

const worker1 = container.get(TemporaryWorker);
const worker2 = container.get(TemporaryWorker);
console.log(worker1.id === worker2.id); // false (transient)

Using Aliases

import { container } from '@ooneex/container';

class EmailService {
  public send(to: string, message: string) {
    console.log(`Sending to ${to}: ${message}`);
  }
}

container.add(EmailService);
container.addAlias('mailer', EmailService);

// Resolve by alias
const mailer = container.get<EmailService>('mailer');
mailer.send('user@example.com', 'Hello!');

Constants

import { container } from '@ooneex/container';

// Store configuration values
container.addConstant('app.name', 'My Application');
container.addConstant('app.version', '1.0.0');
container.addConstant('app.config', {
  debug: true,
  maxConnections: 100
});

// Retrieve constants
const appName = container.getConstant<string>('app.name');
const config = container.getConstant<{ debug: boolean }>('app.config');

console.log(appName); // "My Application"
console.log(config.debug); // true

With Decorators

import { injectable, inject, container } from '@ooneex/container';

@injectable()
class Logger {
  public log(message: string) {
    console.log(`[LOG] ${message}`);
  }
}

@injectable()
class UserRepository {
  constructor(@inject(Logger) private readonly logger: Logger) {}
  
  public findAll() {
    this.logger.log('Finding all users');
    return [];
  }
}

container.add(Logger);
container.add(UserRepository);

const repo = container.get(UserRepository);
repo.findAll();

API Reference

Classes

Container

Main dependency injection container class.

Constructor:

new Container()

Methods:

add(target: Constructor, scope?: EContainerScope): void

Registers a class with the container.

Parameters:

  • target - The class constructor to register
  • scope - Optional scope (default: EContainerScope.Singleton)

Example:

container.add(MyService);
container.add(MyService, EContainerScope.Transient);
get<T>(target: Constructor | string): T

Resolves an instance from the container.

Parameters:

  • target - Class constructor or alias string

Returns: The resolved instance

Throws: ContainerException if resolution fails

Example:

const service = container.get(MyService);
const aliased = container.get<MyService>('myService');
has(target: Constructor | string): boolean

Checks if a service is registered.

Parameters:

  • target - Class constructor or alias string

Returns: true if registered, false otherwise

Example:

if (container.has(MyService)) {
  const service = container.get(MyService);
}
remove(target: Constructor | string): void

Removes a registered service.

Parameters:

  • target - Class constructor or alias string

Example:

container.remove(MyService);
addConstant<T>(identifier: string | symbol, value: T): void

Registers a constant value.

Parameters:

  • identifier - String or symbol identifier
  • value - The constant value

Example:

container.addConstant('api.url', 'https://api.example.com');
getConstant<T>(identifier: string | symbol): T

Retrieves a constant value.

Parameters:

  • identifier - String or symbol identifier

Returns: The constant value

Throws: ContainerException if not found

Example:

const apiUrl = container.getConstant<string>('api.url');
hasConstant(identifier: string | symbol): boolean

Checks if a constant is registered.

Parameters:

  • identifier - String or symbol identifier

Returns: true if registered, false otherwise

removeConstant(identifier: string | symbol): void

Removes a registered constant.

Parameters:

  • identifier - String or symbol identifier
addAlias<T>(alias: string, target: Constructor): void

Creates an alias for a registered service.

Parameters:

  • alias - String alias name
  • target - The target class constructor

Example:

container.add(EmailService);
container.addAlias('mailer', EmailService);

Enums

EContainerScope

Value Description
Singleton Single instance shared across all requests
Transient New instance created on every resolution
Request New instance per request context

Exported Functions

injectable()

Decorator to mark a class as injectable (re-exported from Inversify).

inject()

Decorator to inject dependencies (re-exported from Inversify).

Global Instance

import { container } from '@ooneex/container';

A pre-configured global container instance is exported for convenience.

Advanced Usage

Custom Container Instance

import { Container } from '@ooneex/container';

const myContainer = new Container();
myContainer.add(MyService);

Service Factory Pattern

import { container, injectable } from '@ooneex/container';

@injectable()
class ConfigService {
  private readonly config: Record<string, unknown> = {};
  
  public set(key: string, value: unknown): void {
    this.config[key] = value;
  }
  
  public get<T>(key: string): T {
    return this.config[key] as T;
  }
}

container.add(ConfigService);

const config = container.get(ConfigService);
config.set('database.host', 'localhost');

Error Handling

import { container, ContainerException } from '@ooneex/container';

try {
  const service = container.get(UnregisteredService);
} catch (error) {
  if (error instanceof ContainerException) {
    console.error('Service not found:', error.message);
  }
}

Integration with Ooneex Framework

import { container } from '@ooneex/container';
import { decorator } from '@ooneex/service';

@decorator.service()
class PaymentService {
  public processPayment(amount: number) {
    // Payment logic
  }
}

// Service is automatically registered by the decorator
const paymentService = container.get(PaymentService);

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Development Setup

  1. Clone the repository
  2. Install dependencies: bun install
  3. Run tests: bun run test
  4. Build the project: bun run build

Guidelines

  • Write tests for new features
  • Follow the existing code style
  • Update documentation for API changes
  • Ensure all tests pass before submitting PR

Made with ❤️ by the Ooneex team