@putnami/runtime
v0.0.3-5fadfe7
Published
Core utilities for dependency injection, context management, HTTP handling, and validation
Downloads
6
Readme
@putnami/runtime
Core utilities for dependency injection, context management, configuration, HTTP error handling, and logging.
Installation
bun add @putnami/runtimeFeatures
- Dependency Injection - Scope-aware DI container with singleton and request scopes
- Context Management - Async-local storage for request-scoped data propagation
- Configuration - Type-safe YAML-based configuration with validation
- Error Handling - Comprehensive HTTP exception classes and utilities
- Logging - Context-aware structured logging with JSON support
- Model Utilities - Class transformation and validation helpers
Quick Start
Dependency Injection
import { Service, get } from '@putnami/runtime';
@Service()
class UserService {
getUser(id: string) {
return { id, name: 'John Doe' };
}
}
const userService = get(UserService);
const user = userService.getUser('123');Configuration
import { Config, getConfig } from '@putnami/runtime';
import { IsString, IsNumber } from 'class-validator';
@Config({ path: 'database' })
class DatabaseConfig {
@IsString() host = 'localhost';
@IsNumber() port = 5432;
}
const dbConfig = getConfig(DatabaseConfig);
console.log(dbConfig.host);Context Management
import { runInContext, getContext } from '@putnami/runtime';
await runInContext({ userId: '123' }, async () => {
const ctx = getContext();
console.log(ctx.userId); // '123'
});Error Handling
import { NotFoundException, BadRequestException } from '@putnami/runtime';
if (!user) {
throw new NotFoundException('User not found');
}Logging
import { useLogger } from '@putnami/runtime';
const logger = useLogger('my-service');
logger.info('Processing request', { userId: '123' });
logger.error('Failed to process', error);📚 Learn More: See Getting Started Guide for a complete walkthrough.
Documentation
Comprehensive guides for all features:
- Getting Started - Installation, setup, and quick examples
- Configuration - Type-safe configuration with YAML files and validation
- Dependency Injection - DI patterns, scopes, and best practices
- Context Management - Request-scoped context and async propagation
- Error Handling - HTTP exceptions, validation errors, and error patterns
- Logging - Context-aware logging and structured output
- API Reference - Complete API documentation
API Overview
Dependency Injection
| Function | Description |
|---------|-------------|
| get<T>(ref) | Get an instance from the DI container |
| set<T>(key, value, options?) | Register an instance manually |
| clear(scope?) | Clear the container (useful for testing) |
| @Service(options?) | Mark a class as a service |
| @Component(options?) | Mark a class as a component |
| @Repository(options?) | Mark a class as a repository |
| @Injectable(options?) | Base decorator for injectable classes |
| @Inject(token) | Explicitly inject a dependency |
Configuration
| Function | Description |
|---------|-------------|
| @Config(options) | Decorator for configuration classes |
| getConfig<T>(type, options?) | Load and validate configuration |
| getEnv() | Get current environment ('local', 'test', 'production') |
| resetConfigLoader() | Reset config cache (for testing) |
Context Management
| Function | Description |
|---------|-------------|
| runInContext<C, R>(context, fn) | Run code within an async context |
| getContext<C>() | Get the current context |
Error Handling
| Class/Function | Description |
|---------------|-------------|
| HttpException | Base class for all HTTP exceptions |
| BadRequestException (400) | Client error exceptions |
| NotFoundException (404) | Resource not found |
| InternalServerErrorException (500) | Server error exceptions |
| ValidationException | Formatted validation errors |
| AggregateException | Multiple errors in one exception |
| createHttpException(status, message?) | Factory for creating exceptions |
| isHttpException(value) | Type guard for HTTP exceptions |
Logging
| Function | Description |
|---------|-------------|
| useLogger(name?) | Get a context-aware logger |
| LoggerWrapper.with(key, value) | Add context data to logs |
📚 Full API: See API Reference for complete documentation.
Common Patterns
Service with Dependencies
@Service()
class DatabaseService {
query(sql: string) { /* ... */ }
}
@Service()
class UserRepository {
constructor(private db: DatabaseService) {} // Auto-injected
findById(id: string) {
return this.db.query(`SELECT * FROM users WHERE id = ?`);
}
}Request-Scoped Services
@Service({ scope: 'request' })
class RequestContext {
userId?: string;
requestId = crypto.randomUUID();
}
@Service({ scope: 'request' })
class UserService {
constructor(private ctx: RequestContext) {}
getCurrentUser() {
return this.ctx.userId;
}
}
await runInContext({ userId: '123' }, async () => {
const userService = get(UserService);
const userId = userService.getCurrentUser(); // '123'
});Multi-Datasource Configuration
@Config({ path: 'database' })
class DatabaseConfig {
@IsString() host = 'localhost';
@IsNumber() port = 5432;
}
// Load from different paths
const authDb = getConfig(DatabaseConfig, { path: 'database.auth' });
const mainDb = getConfig(DatabaseConfig, { path: 'database.main' });Validation with Errors
import { ValidationException } from '@putnami/runtime';
import { validate } from 'class-validator';
const errors = await validate(userDto);
if (errors.length > 0) {
throw new ValidationException(errors);
// Returns 400 with formatted errors
}Project Structure
A typical project using @putnami/runtime:
src/
├── config/
│ └── database.config.ts # Configuration classes
├── services/
│ └── user.service.ts # Business logic (@Service)
├── repositories/
│ └── user.repository.ts # Data access (@Repository)
└── app/
└── routes/
└── users/
└── get.ts # Route handlersDependencies
This package relies on:
- class-validator (
^0.14.3) - Validation decorators - class-transformer (
^0.5.1) - Object transformation - reflect-metadata (
^0.2.2) - Metadata reflection - yaml (
^2.8.2) - YAML parsing
