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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@pmeig/srv-core

v1.0.3

Published

The foundational dependency injection and application framework module for the @pmeig/srv ecosystem. Provides decorators, IoC container, lifecycle management, and application bootstrapping with NestJS-inspired architecture.

Readme

@pmeig/srv-core

The foundational dependency injection and application framework module for the @pmeig/srv ecosystem. Provides decorators, IoC container, lifecycle management, and application bootstrapping with NestJS-inspired architecture.

Installation

  npm install @pmeig/srv-core

Features

  • 🏗️ Dependency Injection - Full IoC container with constructor and parameter injection
  • 🎯 Decorator System - Comprehensive decorator framework for metadata and AOP
  • 📦 Module System - Hierarchical module organization with imports and providers
  • 🔄 Lifecycle Management - Component initialization, disposal, and refresh cycles
  • Application Context - Centralized application bootstrapping and management
  • 🛡️ Conditional Loading - Profile and condition-based component registration
  • 📊 Scoped Components - Singleton, prototype, and request-scoped instances
  • 🎨 Provider Factories - Custom factory functions for complex instantiation
  • 🔗 Named Injection - String-based and token-based dependency resolution
  • 🛠️ TypeScript First - Full type safety with reflection metadata support

Usage

Import the Module

import { ApplicationContext, Module } from '@pmeig/srv-core';

@Module({
  providers: [MyService],
  imports: [OtherModule]
})
export class AppModule {}

// Bootstrap application
ApplicationContext.run(AppModule);

Basic Components

import { Component, Service, Configuration } from '@pmeig/srv-core';

@Component
export class BasicComponent {
  getValue() {
    return 'Hello World';
  }
}

@Service
export class BusinessService {
  constructor(private readonly component: BasicComponent) {}
  
  processData() {
    return this.component.getValue().toUpperCase();
  }
}

@Configuration
export class AppConfiguration {
  // Configuration beans and factories
}

Dependency Injection

import { Component, Inject, Named } from '@pmeig/srv-core';

@Component
@Named('userService', 'UserManager') // Multiple names
export class UserService {
  getUsers() {
    return ['user1', 'user2'];
  }
}

@Component
export class UserController {
  constructor(
    private readonly userService: UserService,
    @Inject('UserManager') private readonly userManager: UserService
  ) {}
  
  async getUsers() {
    return this.userService.getUsers();
  }
}

Module Organization

import { Module, Import } from '@pmeig/srv-core';

@Module({
  providers: [DatabaseService, UserRepository],
  exports: [UserRepository] // Available to importing modules
})
export class DatabaseModule {}

@Module({
  providers: [UserService, UserController]
})
export class UserModule {}

@Module({
  imports: [DatabaseModule, UserModule],
  providers: [AppService]
})
export class AppModule {}

API Reference

Core Decorators

| Decorator | Type | Description | |-----------|------|-------------| | @Component | Class | Marks class as injectable component | | @Service | Class | Business logic component (extends @Component) | | @Configuration | Class | Configuration class with bean definitions | | @Module(config) | Class | Module definition with providers and imports | | @Import(...modules) | Class | Import other modules into current module |

Dependency Injection Decorators

| Decorator | Type | Description | |-----------|------|-------------| | @Inject(token) | Parameter | Inject dependency by name or token | | @Named(...names) | Class | Register component with specific names | | @Order(priority) | Class | Set component loading priority | | @Scope(type) | Class | Define component lifecycle scope |

Lifecycle Decorators

| Decorator | Type | Description | |-----------|------|-------------| | @Before(Component) | Class | Load before specified component | | @After(Component) | Class | Load after specified component |

Conditional Decorators

| Decorator | Type | Description | |-----------|------|-------------| | @Conditional(condition) | Class | Load component based on condition |

Component Scopes

Singleton Scope (Default)

@Component
export class SingletonService {
  // One instance per application
}

Request Scope

import { Scope } from '@pmeig/srv-core';

@Component
@Scope('request')
export class RequestScopedService {
  // New instance per request
}

Prototype Scope

@Component
@Scope('prototype')
export class PrototypeService {
  // New instance every time injected
}

Application Context

Basic Bootstrap

import { ApplicationContext, Module } from '@pmeig/srv-core';

@Module({
  providers: [AppService]
})
export class AppModule {}

// Start application
const context = await ApplicationContext.run(AppModule);

// Access services
const appService = await context.resolve(AppService);

Manual Resolution

const context = await ApplicationContext.run(AppModule);

// Resolve single instance
const service = await context.resolve(MyService);
const serviceWithDefault = await context.resolve(OptionalService, new DefaultService());

// Resolve required (throws if not found)
const requiredService = await context.resolveRequired(RequiredService);

// Resolve multiple instances
const handlers = await context.multiResolve(EventHandler);

Context Lifecycle

const context = await ApplicationContext.run(AppModule);

// Restart application
await context.restart();

// Graceful shutdown
await context.close();

Factory Providers

Simple Factory

@Module({
  providers: [
    {
      provide: 'DATABASE_CONNECTION',
      useFactory: async (context) => {
        const config = await context.resolve(DatabaseConfig);
        return createConnection(config);
      }
    }
  ]
})
export class DatabaseModule {}

Factory with Dependencies

@Module({
  providers: [
    {
      provide: HttpClient,
      useFactory: async (context) => {
        const config = await context.resolveRequired(HttpConfig);
        const logger = await context.resolve(Logger);
        return new HttpClient(config, logger);
      }
    }
  ]
})
export class HttpModule {}

Conditional Loading

Custom Conditions

import { Conditional, ApplicationContext } from '@pmeig/srv-core';

@Component
@Conditional((target, context) => {
  // Load only in development
  return process.env.NODE_ENV === 'development';
})
export class DevOnlyService {}

Combining Conditions

import { Conditionals } from '@pmeig/srv-core';

const DevAndTest = Conditionals.or(
  (target, context) => process.env.NODE_ENV === 'development',
  (target, context) => process.env.NODE_ENV === 'test'
);

@Component
@Conditional(DevAndTest)
export class DevTestService {}

Lifecycle Management

Component Lifecycle Interfaces

import { 
  Initializable, 
  Disposable, 
  Destroyable, 
  Refreshable 
} from '@pmeig/srv-core';

@Component
export class LifecycleService implements Initializable, Disposable {
  async initialize() {
    console.log('Service starting...');
  }
  
  async dispose() {
    console.log('Service shutting down...');
  }
}

Lifecycle Events

import { Bootable } from '@pmeig/srv-core';

@Component
export class AppBootstrap implements Bootable {
  async run(context: ApplicationContext, ...args: any[]) {
    console.log('Application starting with args:', args);
    // Perform startup tasks
  }
  
  async close(context: ApplicationContext) {
    console.log('Application shutting down');
    // Perform cleanup tasks
  }
}

Component Ordering

Priority-Based Loading

@Component
@Order(-100) // Load early
export class DatabaseService {}

@Component
@Order(100) // Load late
export class WebService {}

@Component // Default order: 0
export class BusinessService {}

Dependency-Based Ordering

@Component
@After(DatabaseService) // Load after database
export class UserService {}

@Component
@Before(WebService) // Load before web layer
export class SecurityService {}

Advanced Patterns

Module Composition

@Module({
  imports: [DatabaseModule, CacheModule],
  providers: [UserService]
})
export class UserModule {}

@Module({
  imports: [UserModule, AuthModule],
  providers: [ApiController]
})
export class ApiModule {}

@Module({
  imports: [ApiModule, HealthModule]
})
export class AppModule {}

Dynamic Module Registration

@Component
@Import(DatabaseModule, CacheModule) // Import at component level
export class DynamicService {
  // Service with dynamic dependencies
}

Provider Aliasing

@Module({
  providers: [
    UserService,
    {
      provide: 'UserManager',
      useFactory: (context) => context.resolve(UserService)
    }
  ]
})
export class UserModule {}

Context Resolution

Finding Components by Decorator

const context = await ApplicationContext.run(AppModule);

// Find all components with specific decorator
const services = await context.withDecorator(Service);
const controllers = await context.withDecorator('Controller');

Checking Component Availability

const hasUserService = await context.has(UserService);
const hasNamedService = await context.has('UserManager');

if (hasUserService) {
  const service = await context.resolve(UserService);
}

Dependencies

  • reflect-metadata: ^0.2.2 - Reflection metadata support
  • @types/node: ^22.15.19 - Node.js type definitions
  • typescript: ^5.8.3 - TypeScript compiler

Compatibility

  • Node.js: 18+
  • TypeScript: 5.8.3+
  • Modern ES2022+ environment
  • Reflection metadata support required

Common Patterns

Service Layer Architecture

@Module({
  providers: [UserRepository, UserValidator, UserService]
})
export class UserModule {}

@Service
export class UserService {
  constructor(
    private readonly repository: UserRepository,
    private readonly validator: UserValidator
  ) {}
  
  async createUser(userData: any) {
    await this.validator.validate(userData);
    return this.repository.save(userData);
  }
}

Configuration Management

@Configuration
export class AppConfig {
  @Named('databaseUrl')
  getDatabaseUrl() {
    return process.env.DATABASE_URL || 'localhost:5432';
  }
}

@Service
export class DatabaseService {
  constructor(@Inject('databaseUrl') private readonly url: string) {}
}

Troubleshooting

Common Issues

Circular dependency detected

  • Review component dependencies and break cycles
  • Use factory providers to defer resolution
  • Consider redesigning component relationships

Component not found

  • Ensure component is decorated with @Component or related decorator
  • Check that component is included in module providers
  • Verify import statements and module registration

Reflection metadata errors

  • Ensure import 'reflect-metadata' is at the top of main file
  • Check TypeScript configuration for decorator support
  • Verify emitDecoratorMetadata is enabled

Scope-related issues

  • Understand scope lifecycles and appropriate usage
  • Check that request-scoped components are used in request context
  • Verify singleton vs prototype behavior expectations

License

This project is licensed under the ISC License.

Support

For issues and questions, please open an issue on the GitHub repository.