# Library Standards and Patterns

This document defines the standardized patterns for all libraries in the @stock-bot ecosystem.

## Export Patterns

### Standard: Named Exports Only

All libraries should use **named exports only**. Default exports have been removed for consistency and better tree-shaking.

**Example:**
```typescript
// ✅ Good - Named exports
export { createCache } from './cache';
export type { CacheOptions } from './types';

// ❌ Bad - Default export
export default createCache;
```

## Initialization Patterns

Libraries follow different initialization patterns based on their purpose:

### 1. Singleton with Global State
**Use for:** Global services that should have only one instance (config, logger)

**Example:** Config library
```typescript
let configInstance: ConfigManager | null = null;

export function initializeConfig(): AppConfig {
  if (!configInstance) {
    configInstance = new ConfigManager();
  }
  return configInstance.initialize();
}

export function getConfig(): AppConfig {
  if (!configInstance) {
    throw new Error('Config not initialized');
  }
  return configInstance.get();
}
```

### 2. Factory with Registry
**Use for:** Services that need instance reuse based on configuration (cache, logger instances)

**Example:** Cache library
```typescript
const cacheInstances = new Map<string, CacheProvider>();

export function createCache(options: CacheOptions): CacheProvider {
  if (options.shared) {
    const key = generateKey(options);
    if (cacheInstances.has(key)) {
      return cacheInstances.get(key)!;
    }
    const cache = new RedisCache(options);
    cacheInstances.set(key, cache);
    return cache;
  }
  return new RedisCache(options);
}
```

### 3. Pure Factory Functions
**Use for:** Services that need creation logic beyond simple instantiation

**Example:** Event bus with configuration processing
```typescript
export function createEventBus(config: EventBusConfig): EventBus {
  // Process config, set defaults, etc.
  const processedConfig = { ...defaultConfig, ...config };
  return new EventBus(processedConfig);
}
```

**Note:** Simple instantiation doesn't need factories - use direct class instantiation or DI container.

### 4. Direct Class Exports
**Use for:** Simple utilities or services managed by DI container

**Example:** MongoDB library
```typescript
export { MongoDBClient } from './client';
// No factory function - let DI container handle instantiation
```

### 5. Singleton Classes
**Use for:** Manager classes that coordinate multiple instances

**Example:** QueueManager
```typescript
export class QueueManager {
  private static instance: QueueManager | null = null;
  
  static initialize(config: QueueConfig): QueueManager {
    if (!QueueManager.instance) {
      QueueManager.instance = new QueueManager(config);
    }
    return QueueManager.instance;
  }
  
  static getInstance(): QueueManager {
    if (!QueueManager.instance) {
      throw new Error('QueueManager not initialized');
    }
    return QueueManager.instance;
  }
}
```

## Pattern Selection Guide

Choose the initialization pattern based on these criteria:

| Pattern | When to Use | Examples |
|---------|-------------|----------|
| **Singleton with Global State** | - One instance per process<br>- Stateful configuration<br>- Process-wide settings | config, logger setup |
| **Factory with Registry** | - Multiple instances with same config should share<br>- Connection pooling<br>- Resource optimization | cache, logger instances |
| **Pure Factory** | - Complex initialization logic<br>- Configuration processing needed<br>- Defaults to apply | event bus (if needed) |
| **Direct Class Export** | - DI container manages lifecycle<br>- Simple initialization<br>- No special setup needed | database clients (MongoDB, PostgreSQL, QuestDB), utilities |
| **Singleton Class** | - Coordinates multiple resources<br>- Central management point<br>- Graceful shutdown needed | QueueManager, ConnectionManager |

## Additional Standards

### Error Handling
- All libraries should throw descriptive errors
- Consider creating custom error classes for domain-specific errors
- Always include context in error messages

### Configuration
- Accept configuration through constructor/factory parameters
- Validate configuration using Zod schemas
- Provide sensible defaults where appropriate

### Testing
- All libraries must have unit tests
- Use consistent test file naming: `*.test.ts`
- Mock external dependencies

### Documentation
- Every library must have a README.md
- Include usage examples
- Document all public APIs with JSDoc

### TypeScript
- Export all public types
- Use strict TypeScript settings
- Avoid `any` types

### Dependencies
- Minimize external dependencies
- Use exact versions for critical dependencies
- Document peer dependencies clearly