@klikkflow/core
v1.0.0
Published
Core utilities and base classes for KlikkFlow
Downloads
22
Readme
@klikkflow/core
Centralized utilities and base classes for the KlikkFlow platform.
This package provides battle-tested utilities that should be used across all KlikkFlow packages. By using these shared utilities, we eliminate code duplication, ensure consistent behavior, and reduce maintenance burden.
📦 Installation
pnpm add @klikkflow/core🎯 Purpose
- Eliminate Duplication: Stop reimplementing error handling, logging, and validation
- Consistent Behavior: Same error handling patterns across all packages
- Battle-Tested: Utilities used in production
- Type-Safe: Full TypeScript support
- Well-Documented: Clear examples and usage patterns
🛠️ Core Utilities
Error Handler
Centralized error handling with retry logic and exponential backoff.
Features:
- Automatic retry with exponential backoff
- Customizable max retries
- Stack trace control
- Logger integration
- Async/sync operation support
import { ErrorHandler } from '@klikkflow/core';
const errorHandler = new ErrorHandler({
enableStackTrace: true,
maxRetries: 3
});
// Handle sync errors
try {
riskyOperation();
} catch (error) {
errorHandler.handle(error, 'Operation context');
}
// Handle async operations with automatic retry
const result = await errorHandler.handleAsync(
async () => {
return await fetchDataFromAPI();
},
'Fetching data from API',
3 // max retries
);
// Wrap functions for automatic error handling
const wrappedFunction = errorHandler.wrapAsync(
async (id: string) => {
return await database.findById(id);
},
'Database query'
);
const user = await wrappedFunction('user-123');Why use this instead of custom error handling?
- ✅ Exponential backoff is tricky to implement correctly
- ✅ Consistent error logging across all packages
- ✅ Configurable retry behavior
- ✅ Less boilerplate code
Logger
Structured logging with multiple log levels and custom handlers.
Features:
- Multiple log levels (debug, info, warn, error)
- Service-specific loggers with context
- Custom log handlers
- Child loggers for sub-contexts
- Console and custom output support
import { Logger } from '@klikkflow/core';
// Create a logger for your service
const logger = new Logger('MyService', {
minLevel: 'info',
enableConsole: true
});
// Basic logging
logger.debug('Debugging information', { userId: '123' });
logger.info('User logged in', { userId: '123', timestamp: Date.now() });
logger.warn('API rate limit approaching', { remaining: 10 });
logger.error('Database connection failed', new Error('Connection timeout'));
// Create child logger for sub-context
const dbLogger = logger.child('Database');
dbLogger.info('Query executed', { query: 'SELECT * FROM users', time: 45 });
// Add custom log handler (e.g., send to external service)
logger.addHandler((entry) => {
if (entry.level === 'error') {
sendToSentry(entry);
}
});Why use this instead of console.log?
- ✅ Structured logs with timestamps and context
- ✅ Filterable by log level
- ✅ Easy to send logs to external services
- ✅ Production-ready logging
- ✅ No more scattered console.log statements
Validator
Comprehensive validation with fluent API.
Features:
- Fluent validation API
- Built-in validators (email, URL, patterns)
- Custom validation functions
- Schema validation for objects
- Detailed error messages
import { Validator, SchemaValidator } from '@klikkflow/core';
// Simple field validation
const emailValidator = new Validator<string>()
.required('Email is required')
.string('Must be a string')
.email('Invalid email format');
try {
await emailValidator.validate('[email protected]', 'email');
console.log('Valid email!');
} catch (error) {
console.error(error.message);
}
// Number validation
const ageValidator = new Validator<number>()
.required()
.number()
.min(18, 'Must be at least 18')
.max(120, 'Must be at most 120');
await ageValidator.validate(25, 'age');
// String validation with pattern
const usernameValidator = new Validator<string>()
.required()
.string()
.minLength(3, 'Username must be at least 3 characters')
.maxLength(20, 'Username must be at most 20 characters')
.pattern(/^[a-zA-Z0-9_]+$/, 'Username can only contain letters, numbers, and underscores');
// URL validation
const urlValidator = new Validator<string>()
.required()
.url('Invalid URL format');
await urlValidator.validate('https://example.com', 'webhookUrl');
// Custom validation
const passwordValidator = new Validator<string>()
.required()
.string()
.minLength(8)
.custom(
(value) => /[A-Z]/.test(value),
'Password must contain at least one uppercase letter'
)
.custom(
(value) => /[0-9]/.test(value),
'Password must contain at least one number'
);
// Schema validation for objects
const userSchema = new SchemaValidator({
email: {
type: 'string',
required: true,
validator: emailValidator
},
age: {
type: 'number',
required: true,
validator: ageValidator
},
username: {
type: 'string',
required: true,
validator: usernameValidator
}
});
const userData = {
email: '[email protected]',
age: 25,
username: 'john_doe'
};
try {
await userSchema.validate(userData);
console.log('Valid user data!');
} catch (error) {
console.error('Validation errors:', error.details);
}Why use this instead of manual validation?
- ✅ Fluent, readable validation code
- ✅ Reusable validators across your app
- ✅ Comprehensive built-in validators
- ✅ Consistent error messages
- ✅ No more scattered if/else validation logic
📦 Package Contents
@klikkflow/core/
├── src/
│ ├── base/ # Base classes for services and repositories
│ ├── cache/ # Caching utilities
│ ├── decorators/ # TypeScript decorators
│ ├── errors/ # Custom error classes
│ ├── events/ # Event emitter and handling
│ ├── interfaces/ # Core interfaces
│ ├── middleware/ # Express middleware
│ ├── repository/ # Repository pattern implementations
│ ├── service/ # Base service classes
│ ├── types/ # Core type definitions
│ ├── use-cases/ # Use case base classes
│ ├── utils/ # ⭐ Core utilities (ErrorHandler, Logger, Validator)
│ └── validation/ # Validation utilities
├── package.json
├── tsconfig.json
└── README.md🚀 Quick Start
1. Install the Package
pnpm add @klikkflow/core2. Import and Use
import {
ErrorHandler,
Logger,
Validator
} from '@klikkflow/core';
// Set up logger
const logger = new Logger('MyService');
// Set up error handler with logger
const errorHandler = new ErrorHandler({ logger });
// Set up validators
const emailValidator = new Validator<string>()
.required()
.email();3. Replace Custom Implementations
Before:
// ❌ Custom error handling (duplicated across packages)
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Failed');
return response.json();
} catch (error) {
console.error('Error:', error);
// Manual retry logic here...
throw error;
}
// ❌ Custom logging (inconsistent formats)
console.log(`[${new Date().toISOString()}] INFO: User logged in`);
// ❌ Custom validation (scattered logic)
if (!email || !email.includes('@')) {
throw new Error('Invalid email');
}After:
// ✅ Using @klikkflow/core
import { ErrorHandler, Logger, Validator } from '@klikkflow/core';
const errorHandler = new ErrorHandler();
const logger = new Logger('AuthService');
const emailValidator = new Validator<string>().required().email();
// Automatic retry with exponential backoff
const data = await errorHandler.handleAsync(
async () => {
const response = await fetch(url);
if (!response.ok) throw new Error('Failed');
return response.json();
},
'Fetching user data'
);
// Structured logging
logger.info('User logged in', { userId, timestamp: Date.now() });
// Clean validation
await emailValidator.validate(email, 'email');📖 Best Practices
1. Create Package-Level Instances
// services/logger.ts
import { Logger } from '@klikkflow/core';
export const logger = new Logger('MyPackage', {
minLevel: process.env.NODE_ENV === 'production' ? 'info' : 'debug'
});
// Use throughout your package
import { logger } from './services/logger';
logger.info('Something happened');2. Combine Utilities
import { ErrorHandler, Logger } from '@klikkflow/core';
const logger = new Logger('APIService');
const errorHandler = new ErrorHandler({
logger,
maxRetries: 3
});
// ErrorHandler will use the logger automatically
await errorHandler.handleAsync(
() => callExternalAPI(),
'External API call'
);3. Create Reusable Validators
// validators/common.ts
import { Validator } from '@klikkflow/core';
export const validators = {
email: new Validator<string>().required().email(),
url: new Validator<string>().required().url(),
positiveNumber: new Validator<number>().required().number().min(0),
username: new Validator<string>()
.required()
.string()
.minLength(3)
.maxLength(20)
.pattern(/^[a-zA-Z0-9_]+$/, 'Invalid username format')
};
// Use throughout your package
import { validators } from './validators/common';
await validators.email.validate(userEmail, 'email');🔄 Migration Guide
See MIGRATION_GUIDE.md for detailed instructions on migrating from custom implementations to @klikkflow/core utilities.
🤝 Contributing
When you find yourself writing utility code, ask:
- Is this already in @klikkflow/core? Check first!
- Should this be in @klikkflow/core? If it's useful across packages, yes!
- Is this package-specific? Then keep it in your package.
If you add new utilities to this package:
- Add comprehensive documentation
- Include usage examples
- Write tests
- Update this README
📄 License
MIT License - See root LICENSE file
Stop duplicating code. Use @klikkflow/core.
