@gl-life/gl-life-core
v1.0.1
Published
Foundation package for GoodLife Sargam providing shared TypeScript types, utilities, error handling, logger, event bus, and configuration management
Maintainers
Readme
@gl-life/gl-life-core
Foundation package for GoodLife Sargam - Production-ready TypeScript utilities for error handling, logging, configuration, and more.
Features
- 🔒 Type-Safe Error Handling - Result and Option types for safe error handling
- 📝 Structured Logging - JSON logging with context and levels
- 🎯 Event System - Type-safe pub/sub with async support
- ⚙️ Configuration Management - Environment variables with Zod validation
- 🛠️ Utilities - Deep cloning, debounce, throttle, retry, validators
- ✅ 100% TypeScript - Full type safety and IntelliSense support
- 📦 Dual Exports - ESM and CommonJS support
- 🧪 Well-Tested - Comprehensive test coverage
Installation
npm install @gl-life/gl-life-coreyarn add @gl-life/gl-life-corepnpm add @gl-life/gl-life-coreQuick Start
import {
Result,
Logger,
LogLevel,
Config,
EventBus,
deepClone,
} from '@gl-life/gl-life-core';
// Safe error handling with Result type
const divide = (a: number, b: number): Result<number, string> => {
if (b === 0) {
return Result.err('Division by zero');
}
return Result.ok(a / b);
};
const result = divide(10, 2);
if (result.isOk()) {
console.log('Result:', result.unwrap()); // 5
}
// Structured logging
const logger = new Logger({ level: LogLevel.INFO });
logger.info('Application started', { version: '1.0.0' });
// Event bus
const eventBus = new EventBus();
eventBus.subscribe('user:login', (data) => {
console.log('User logged in:', data);
});
await eventBus.emit('user:login', { userId: 123 });
// Configuration with validation
import { z } from 'zod';
const schema = z.object({
PORT: z.number().default(3000),
HOST: z.string().default('localhost'),
});
const config = new Config({
schema,
envPrefix: 'APP_',
});
console.log(config.get('PORT')); // From APP_PORT env or default 3000Core Types
Result<T, E>
Type-safe error handling without exceptions.
import { Result } from '@gl-life/gl-life-core';
// Create results
const success = Result.ok(42);
const failure = Result.err('Something went wrong');
// Check result
if (success.isOk()) {
console.log(success.unwrap()); // 42
}
// Transform with map
const doubled = success.map(x => x * 2); // Ok(84)
// Chain operations
const result = Result.ok(10)
.map(x => x * 2)
.flatMap(x => x > 15 ? Result.ok(x) : Result.err('Too small'));
// Safe unwrapping
const value = result.unwrapOr(0); // Get value or defaultOption
Handle nullable values safely.
import { Option } from '@gl-life/gl-life-core';
// Create options
const some = Option.some(42);
const none = Option.none<number>();
// From nullable
const opt = Option.fromNullable(maybeNull);
// Transform
const doubled = some.map(x => x * 2); // Some(84)
// Filter
const filtered = some.filter(x => x > 40); // Some(42)
// Chain
const result = some
.map(x => x * 2)
.flatMap(x => x > 50 ? Option.some(x) : Option.none());
// Safe unwrapping
const value = result.unwrapOr(0);Error Handling
Specialized error classes with serialization support.
import {
AppError,
ValidationError,
DatabaseError,
AuthError,
NetworkError,
} from '@gl-life/gl-life-core';
// Base error
throw new AppError('USER_NOT_FOUND', 'User does not exist', {
userId: 123,
});
// Validation error
throw new ValidationError(
'INVALID_EMAIL',
'Email format is invalid',
{ field: 'email', value: 'bad-email', constraint: 'format' }
);
// Database error
throw new DatabaseError(
'QUERY_FAILED',
'Failed to execute query',
{ query: 'SELECT * FROM users', table: 'users' }
);
// Auth error
throw new AuthError(
'TOKEN_EXPIRED',
'Authentication token has expired',
{ userId: '123', tokenType: 'JWT', reason: 'expired' }
);
// Network error
throw new NetworkError(
'REQUEST_FAILED',
'HTTP request failed',
{ statusCode: 404, url: 'https://api.example.com', method: 'GET' }
);
// Serialization
const error = new ValidationError('ERROR_CODE', 'Message');
const json = error.toJSON();
const restored = AppError.fromJSON(json);Logging
Structured JSON logging with context and levels.
import { Logger, LogLevel } from '@gl-life/gl-life-core';
// Create logger
const logger = new Logger({
level: LogLevel.INFO,
context: { service: 'api', version: '1.0.0' },
});
// Log at different levels
logger.debug('Debug message', { details: 'extra info' });
logger.info('User logged in', { userId: 123 });
logger.warn('Rate limit approaching', { requests: 950 });
logger.error('Database connection failed', { error: 'timeout' });
// Child logger with additional context
const requestLogger = logger.createChild({
requestId: 'abc-123',
method: 'GET',
path: '/api/users',
});
requestLogger.info('Request received'); // Includes parent + child context
// Output format (JSON)
// {
// "timestamp": "2024-01-01T12:00:00.000Z",
// "level": "info",
// "message": "Request received",
// "service": "api",
// "version": "1.0.0",
// "requestId": "abc-123",
// "method": "GET",
// "path": "/api/users"
// }Event Bus
Type-safe publish-subscribe event system.
import { EventBus } from '@gl-life/gl-life-core';
const eventBus = new EventBus();
// Subscribe to events
const unsubscribe = eventBus.subscribe('user:login', (data) => {
console.log('User logged in:', data.userId);
});
// Wildcard subscriptions
eventBus.subscribe('*', (data) => {
console.log('Any event:', data);
});
// Emit events (async with error collection)
const errors = await eventBus.emit('user:login', {
userId: 123,
timestamp: new Date(),
});
// Unsubscribe
unsubscribe();
// or
eventBus.unsubscribe('user:login', handler);
// Management
eventBus.listenerCount('user:login'); // Number of handlers
eventBus.eventNames(); // All event names
eventBus.clear(); // Remove all handlers
eventBus.clear('user:login'); // Remove handlers for specific eventConfiguration
Configuration management with environment variables and Zod validation.
import { Config } from '@gl-life/gl-life-core';
import { z } from 'zod';
// Define schema
const schema = z.object({
PORT: z.number().min(1).max(65535).default(3000),
HOST: z.string().default('localhost'),
DATABASE_URL: z.string().url(),
DEBUG: z.boolean().default(false),
});
// Create config
const config = new Config({
schema,
envPrefix: 'APP_', // Loads from APP_PORT, APP_HOST, etc.
defaults: { DEBUG: true }, // Override schema defaults
});
// Get values (type-safe with generics)
const port = config.get<number>('PORT'); // 3000 or from APP_PORT
const host = config.get('HOST', 'default-host'); // With fallback
// Set values (validated against schema)
config.set('PORT', 8080);
// Check existence
if (config.has('DATABASE_URL')) {
// ...
}
// Get all config
const allConfig = config.getAll();
// Delete and clear
config.delete('PORT'); // Returns `this` for chaining
config.clear();
// Type conversion from environment
// APP_PORT=8080 → number
// APP_DEBUG=true → boolean
// APP_CONFIG='{"key":"value"}' → objectUtilities
Deep Clone
Clone objects with circular reference handling.
import { deepClone } from '@gl-life/gl-life-core';
const original = {
date: new Date(),
regex: /test/i,
map: new Map([['key', 'value']]),
set: new Set([1, 2, 3]),
nested: { deep: { value: 42 } },
};
// Handle circular references
original.self = original;
const cloned = deepClone(original);
// cloned is a deep copy, cloned.self === clonedDebounce
Delay function execution until after a wait period.
import { debounce } from '@gl-life/gl-life-core';
const search = debounce((query: string) => {
console.log('Searching for:', query);
}, 300);
search('a');
search('ab');
search('abc'); // Only this will execute after 300ms
// Cancel pending execution
search.cancel();Throttle
Limit function execution rate.
import { throttle } from '@gl-life/gl-life-core';
const onScroll = throttle(() => {
console.log('Scroll event');
}, 100);
window.addEventListener('scroll', onScroll);
// Executes at most once per 100msRetry
Retry async operations with exponential backoff.
import { retry } from '@gl-life/gl-life-core';
const fetchData = async () => {
const response = await fetch('https://api.example.com/data');
if (!response.ok) throw new Error('Fetch failed');
return response.json();
};
// Retry up to 3 times with exponential backoff
const data = await retry(fetchData, {
maxAttempts: 3,
delay: 1000, // 1s, 2s, 3s between attempts
});Sleep
Promise-based delay.
import { sleep } from '@gl-life/gl-life-core';
async function process() {
console.log('Start');
await sleep(1000); // Wait 1 second
console.log('After 1 second');
}Validators
Email and URL validation.
import { isEmail, isURL } from '@gl-life/gl-life-core';
// Email validation (RFC 5322 compliant)
isEmail('[email protected]'); // true
isEmail('invalid@'); // false
// URL validation (http/https only)
isURL('https://example.com'); // true
isURL('ftp://example.com'); // falseAPI Reference
Types
Result<T, E>- Type-safe result type for operations that may failOption<T>- Type for optional values
Errors
AppError- Base error class with code and metadataValidationError- Validation failure errorsDatabaseError- Database operation errorsAuthError- Authentication/authorization errorsNetworkError- Network request errors
Services
Logger- Structured JSON logging with levels and contextEventBus- Publish-subscribe event systemConfig- Configuration management with validation
Utilities
deepClone<T>(value: T): T- Deep clone with circular referencesdebounce<T>(fn: T, wait: number): DebouncedFunction<T>- Debounce functionthrottle<T>(fn: T, wait: number): ThrottledFunction<T>- Throttle functionretry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>- Retry with backoffsleep(ms: number): Promise<void>- Async delayisEmail(email: string): boolean- Email validatorisURL(url: string): boolean- URL validator
TypeScript Support
Full TypeScript support with comprehensive type definitions.
import type {
Result,
Option,
AppErrorJSON,
LoggerOptions,
EventHandler,
ConfigOptions,
RetryOptions,
} from '@gl-life/gl-life-core';Testing
The package includes comprehensive tests with high coverage:
npm test # Run tests
npm run test:watch # Watch mode
npm run test:coverage # Coverage reportSupport
For questions, issues, or feature requests, please contact us at [email protected].
Visit gl.life for more information about GoodLife Sargam.
License
Apache-2.0 © GoodLife
Part of the GoodLife Sargam ecosystem
For more information, visit gl.life.
