npm package: @rudderstack/feature-flags
Description: A comprehensive feature flag management system for the Rudder Integrations Library that supports multiple providers, environment-based overrides, and flexible configuration options.
Latest version: 0.2.0

# Feature Flags Module

A comprehensive feature flag management system for the Rudder Integrations Library that supports multiple providers, environment-based overrides, and flexible configuration options.

## Table of Contents

- [Overview](#overview)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
- [Usage Examples](#usage-examples)
- [Providers](#providers)
- [Environment Variables](#environment-variables)
- [Flag Registry](#flag-registry)
- [Error Handling](#error-handling)
- [Advanced Features](#advanced-features)
- [Implementation Design](#implementation-design)
- [API Reference](#api-reference)

## Overview

The Feature Flags module provides a unified interface for managing feature flags across different providers (Flagsmith, Local) with support for:

- **Multiple Providers**: Flagsmith for production, Local for development/testing
- **Environment Overrides**: Runtime configuration via environment variables
- **Rich Responses**: Detailed metadata including error states and staleness
- **Flexible Error Handling**: Configurable error behaviors
- **Type Safety**: Full TypeScript support with comprehensive interfaces
- **Registry System**: Centralized flag definition management
- **Caching**: Configurable caching with TTL support

## Quick Start

### Basic Setup

```typescript
import {
  featureFlagService,
  FeatureFlagService,
  FeatureFlagRegistry,
  FeatureFlagUser,
  TRAIT_KEYS,
} from '@rudderstack/feature-flags';

// Set up custom flags
const customFlags = [
  {
    key: 'my-feature-flag',
    name: 'My Feature Flag',
    description: 'Enable my awesome feature',
    defaultValue: false,
    type: 'boolean' as const,
  },
];

// Option 1: Use global service instance
featureFlagService.registerFlags(customFlags);
await featureFlagService.initialize();

// Option 2: Create and initialize in one step (Factory Method)
const service = await FeatureFlagService.create({}, customFlags);

// Option 3: Manual creation and initialization
const manualRegistry = new FeatureFlagRegistry();
manualRegistry.register(customFlags);
const manualService = new FeatureFlagService(manualRegistry);
await manualService.initialize();

// Create user context
const user: FeatureFlagUser = {
  workspaceId: 'my-workspace',
  traits: new Map([
    [TRAIT_KEYS.ORGANIZATION_ID, 'org-123'],
    [TRAIT_KEYS.USER_ID, 'user-456'],
  ]),
};

// Check if feature is enabled (using any of the service instances)
const result = await featureFlagService.isFeatureEnabled(user, 'my-feature-flag');
console.log(`Feature enabled: ${result.enabled}`);
```

### With Flagsmith Provider

```typescript
import { featureFlagService, FeatureFlagService } from '@rudderstack/feature-flags';

// Set up custom flags for Flagsmith
const flagsmithFlags = [
  {
    key: 'premium-features',
    name: 'Premium Features',
    description: 'Enable premium features for users',
    defaultValue: false,
    type: 'boolean' as const,
  },
  {
    key: 'api-rate-limit',
    name: 'API Rate Limit',
    description: 'API rate limit per minute',
    defaultValue: 100,
    type: 'number' as const,
  },
];

// Option 1: Using global service
featureFlagService.registerFlags(flagsmithFlags);
await featureFlagService.initialize({
  provider: 'flagsmith',
  apiKey: 'your-flagsmith-api-key',
  enableCache: true,
  cacheTtlSeconds: 300,
});

// Option 2: Using factory method
const flagsmithService = await FeatureFlagService.create(
  {
    provider: 'flagsmith',
    apiKey: 'your-flagsmith-api-key',
    enableCache: true,
    cacheTtlSeconds: 300,
  },
  flagsmithFlags,
);
```

### Initialization Patterns

The Feature Flag Service supports three initialization patterns:

#### 1. Global Service Instance (Recommended for most use cases)

```typescript
import { featureFlagService, FeatureFlagRegistry } from '@rudderstack/feature-flags';

// Optional: Set up custom registry before initialization
const customRegistry = new FeatureFlagRegistry();
customRegistry.register([
  {
    key: 'new-dashboard',
    name: 'New Dashboard',
    description: 'Enable new dashboard UI',
    defaultValue: false,
    type: 'boolean',
  },
]);

// Register flags with global service
featureFlagService.registerFlags(customRegistry.getAll());

await featureFlagService.initialize({
  provider: 'flagsmith',
  apiKey: 'your-api-key',
});
```

#### 2. Factory Method (Convenient for creating configured instances)

```typescript
import { FeatureFlagService, FeatureFlagRegistry } from '@rudderstack/feature-flags';

// Option 2a: Pass flags directly (simple approach)
const customFlags = [
  {
    key: 'api-timeout',
    name: 'API Timeout',
    description: 'API timeout in milliseconds',
    defaultValue: 5000,
    type: 'number' as const,
  },
];

const service = await FeatureFlagService.create(
  {
    provider: 'flagsmith',
    apiKey: 'your-api-key',
  },
  customFlags,
);

// Option 2b: Pass custom registry (advanced approach)
const customRegistry = new FeatureFlagRegistry();
customRegistry.register(customFlags);
// Registry can load from multiple sources, apply transformations, etc.

const advancedService = await FeatureFlagService.create(
  {
    provider: 'flagsmith',
    apiKey: 'your-api-key',
  },
  customRegistry,
);
```

#### 3. Manual Creation (Full control over registry and initialization)

```typescript
import { FeatureFlagService, FeatureFlagRegistry } from '@rudderstack/feature-flags';

const customRegistry = new FeatureFlagRegistry();
const service = new FeatureFlagService(customRegistry);
await service.initialize({
  provider: 'flagsmith',
  apiKey: 'your-api-key',
});
```

**When to use each pattern:**

- **Global Service**: For most applications where you need a single service instance. Use `registerFlags()` to add custom flags after creation.
- **Factory Method**:
  - **With flag definitions**: When you want to pass flag definitions directly (simple approach)
  - **With registry**: When you need advanced registry features like loading from multiple sources, transformations, or complex flag management
- **Manual Creation**: When you need fine-grained control over initialization, custom registries, or complex setup logic.

## Configuration

### Configuration Interface

```typescript
interface FeatureFlagConfig {
  provider: 'flagsmith' | 'local';
  apiKey?: string; // Required for Flagsmith
  enableLocalEvaluation?: boolean; // Default: false
  enableCache?: boolean; // Default: true
  cacheTtlSeconds?: number; // Default: 60
  timeoutSeconds?: number; // Default: 60
  retryAttempts?: number; // Default: 3
  enableAnalytics?: boolean; // Default: true
}
```

### Default Values

| Parameter               | Default   | Description                           |
| ----------------------- | --------- | ------------------------------------- |
| `provider`              | `'local'` | Feature flag provider                 |
| `enableLocalEvaluation` | `false`   | Enable local evaluation for Flagsmith |
| `enableCache`           | `true`    | Enable response caching               |
| `cacheTtlSeconds`       | `60`      | Cache time-to-live in seconds         |
| `timeoutSeconds`        | `60`      | Request timeout in seconds            |
| `retryAttempts`         | `3`       | Number of retry attempts              |
| `enableAnalytics`       | `true`    | Enable analytics tracking             |

### Environment Variable Override

All configuration parameters can be overridden using environment variables:

```bash
# Provider configuration
FEATURE_FLAG_PROVIDER=flagsmith
FEATURE_FLAG_API_KEY=your-api-key

# Performance settings
FEATURE_FLAG_ENABLE_CACHE=true
FEATURE_FLAG_CACHE_TTL_SECONDS=300
FEATURE_FLAG_TIMEOUT_SECONDS=30
FEATURE_FLAG_RETRY_ATTEMPTS=5

# Feature settings
FEATURE_FLAG_ENABLE_LOCAL_EVALUATION=true
FEATURE_FLAG_ENABLE_ANALYTICS=false
```

## Usage Examples

### Basic Feature Flag Checking

```typescript
// Simple boolean check
const isEnabled = await featureFlagService.isFeatureEnabled(user, 'new-dashboard');
if (isEnabled.enabled) {
  // Show new dashboard
}

// Get feature value (string, number, or boolean)
const themeResult = await featureFlagService.getFeatureValue(user, 'ui-theme');
const theme = themeResult.value; // Could be 'dark', 'light', etc.
```

### Latest vs Cached Values

```typescript
// Get cached value (faster, may be stale)
const cachedResult = await featureFlagService.isFeatureEnabled(user, 'feature-x');

// Get latest value (slower, always fresh)
const latestResult = await featureFlagService.isFeatureEnabledLatest(user, 'feature-x');

console.log(`Cached: ${cachedResult.enabled}, Latest: ${latestResult.enabled}`);
console.log(`Is stale: ${cachedResult.isStale}`);
```

### Error Handling Strategies

```typescript
import { ErrorBehaviour } from '@rudderstack/feature-flags';

// Return default value on error (silent failure)
const result1 = await featureFlagService.isFeatureEnabled(
  user,
  'feature-flag',
  ErrorBehaviour.RETURN_DEFAULT,
);

// Return rich error object (default behavior)
const result2 = await featureFlagService.isFeatureEnabled(
  user,
  'feature-flag',
  ErrorBehaviour.RETURN_RICH_ERROR,
);
if (result2.error) {
  console.error('Feature flag error:', result2.error.message);
}

// Throw error on failure
try {
  const result3 = await featureFlagService.isFeatureEnabled(
    user,
    'feature-flag',
    ErrorBehaviour.THROW_ERROR,
  );
} catch (error) {
  console.error('Feature flag failed:', error);
}
```

### Working with Rich Responses

```typescript
const response = await featureFlagService.getFeatureValue(user, 'api-rate-limit');

console.log({
  name: response.name, // 'api-rate-limit'
  enabled: response.enabled, // true/false
  value: response.value, // The actual value
  isDefault: response.isDefault, // Whether using default value
  lastUpdatedAt: response.lastUpdatedAt, // When last updated
  isStale: response.isStale, // Whether cached value is stale
  error: response.error, // Any error that occurred
  metadata: response.metadata, // Additional provider metadata
});

// Track analytics event (if supported by provider)
if (response.track) {
  response.track();
}
```

## Providers

### Local Provider

The Local provider is ideal for development, testing, and scenarios where you want to manage flags through environment variables or configuration.

**Features:**

- Environment variable overrides
- Workspace-specific configuration
- Registry-based defaults
- No external dependencies

**Configuration:**

```typescript
await featureFlagService.initialize({
  provider: 'local',
});
```

### Flagsmith Provider

The Flagsmith provider integrates with Flagsmith's feature flag service for production use.

**Features:**

- Remote flag management
- Real-time updates
- Advanced targeting
- Analytics tracking
- Local evaluation support

**Configuration:**

```typescript
await featureFlagService.initialize({
  provider: 'flagsmith',
  apiKey: 'your-flagsmith-environment-key',
  enableLocalEvaluation: true, // For one time fetching, and evaluating flags locally
  enableAnalytics: true, // Track flag usage
  enableCache: true, // Cache responses
  cacheTtlSeconds: 300, // 5-minute cache
});
```

## Environment Variables

### Global Configuration

Environment variables that affect the entire service:

```bash
# Provider selection
FEATURE_FLAG_PROVIDER=local|flagsmith

# Flagsmith API key
FEATURE_FLAG_API_KEY=your-api-key

# Performance settings
FEATURE_FLAG_ENABLE_CACHE=true
FEATURE_FLAG_CACHE_TTL_SECONDS=60
FEATURE_FLAG_TIMEOUT_SECONDS=60
FEATURE_FLAG_RETRY_ATTEMPTS=3

# Feature settings
FEATURE_FLAG_ENABLE_LOCAL_EVALUATION=false
FEATURE_FLAG_ENABLE_ANALYTICS=true
```

### Local Provider Flag Overrides

The Local provider supports runtime flag overrides through environment variables:

#### Global Flag Override

```bash
# Format: FEATURE_FLAG_LOCAL_{FLAG_NAME}
FEATURE_FLAG_LOCAL_NEW_DASHBOARD=true
FEATURE_FLAG_LOCAL_API_RATE_LIMIT=1000
FEATURE_FLAG_LOCAL_UI_THEME=dark
```

#### Workspace-Specific Override

```bash
# Format: FEATURE_FLAG_LOCAL__{WORKSPACE_ID}__{FLAG_NAME}
FEATURE_FLAG_LOCAL__workspace123__NEW_DASHBOARD=false
FEATURE_FLAG_LOCAL__workspace456__API_RATE_LIMIT=500
```

#### Priority Order

1. **Workspace-specific environment variable** (highest priority)
2. **Global environment variable**
3. **Configured flag values**
4. **Registry default values** (lowest priority)

#### Example Usage

```bash
# Global setting
export FEATURE_FLAG_LOCAL_FEATURE_X=true

# Workspace-specific override
export FEATURE_FLAG_LOCAL__prod_workspace__FEATURE_X=false
export FEATURE_FLAG_LOCAL__dev_workspace__FEATURE_X=true

# Different workspaces will get different values
```

### Value Parsing

Environment variable values are automatically parsed:

- **Booleans**: `true`, `false`, `1`, `0` (case-insensitive)
- **Numbers**: Any valid numeric string
- **Strings**: Any other value

```bash
FEATURE_FLAG_LOCAL_ENABLE_FEATURE=true        # Boolean: true
FEATURE_FLAG_LOCAL_MAX_RETRIES=5              # Number: 5
FEATURE_FLAG_LOCAL_API_VERSION=v2             # String: "v2"
```

## Flag Registry

### Registering Flags

The registry system allows you to define flag schemas and default values:

```typescript
import { FeatureFlagDefinition } from '@rudderstack/feature-flags';

// Define flag definitions
const flags: FeatureFlagDefinition[] = [
  {
    key: 'new-dashboard',
    name: 'New Dashboard',
    description: 'Enable the redesigned dashboard interface',
    defaultValue: false,
    type: 'boolean',
    category: 'ui',
    tags: ['dashboard', 'ui-refresh'],
  },
  {
    key: 'api-rate-limit',
    name: 'API Rate Limit',
    description: 'Maximum API requests per minute',
    defaultValue: 1000,
    type: 'number',
    category: 'performance',
    tags: ['api', 'rate-limiting'],
  },
  {
    key: 'ui-theme',
    name: 'UI Theme',
    description: 'Default UI theme for the application',
    defaultValue: 'light',
    type: 'string',
    category: 'ui',
    tags: ['theme', 'appearance'],
  },
];

// Register flags
featureFlagService.registerFlags(flags);
```

### Using the Registry

```typescript
// Check if flag is registered
const isRegistered = featureFlagService.getRegisteredFlag('new-dashboard');

// Get flag definition
const flagDef = featureFlagService.getRegisteredFlag('api-rate-limit');
console.log(flagDef?.description); // "Maximum API requests per minute"
```

### Loading Flags from Configuration

```typescript
import { FeatureFlagLoader } from '@rudderstack/feature-flags';

// From JSON string
const flagsFromJson = FeatureFlagLoader.fromJSON(`{
  "flags": [
    {
      "key": "feature-x",
      "name": "Feature X",
      "description": "Enable feature X",
      "defaultValue": true,
      "type": "boolean"
    }
  ]
}`);

// From configuration object
const flagsFromConfig = FeatureFlagLoader.fromObject({
  flags: [
    {
      key: 'feature-y',
      name: 'Feature Y',
      description: 'Enable feature Y',
      defaultValue: 'default-value',
      type: 'string',
    },
  ],
});

// From environment (reads FEATURE_FLAGS_CONFIG_PATH)
process.env.FEATURE_FLAGS_CONFIG_PATH = '/path/to/flags.json';
const flagsFromEnv = FeatureFlagLoader.fromEnvironment();

// Register loaded flags
featureFlagService.registerFlags(flagsFromJson);
```

## Error Handling

### Error Behaviors

The module supports three error handling strategies:

#### 1. RETURN_DEFAULT (Silent Failure)

```typescript
const result = await featureFlagService.isFeatureEnabled(
  user,
  'feature-flag',
  ErrorBehaviour.RETURN_DEFAULT,
);
// result.enabled will be the default value
// result.error will be undefined
// result.isDefault will be true
```

#### 2. RETURN_RICH_ERROR (Default)

```typescript
const result = await featureFlagService.isFeatureEnabled(
  user,
  'feature-flag',
  ErrorBehaviour.RETURN_RICH_ERROR,
);

if (result.error) {
  console.error('Error details:', {
    name: result.error.name,
    message: result.error.message,
    stack: result.error.stack,
  });
  // result.enabled will be the default value
  // result.isDefault will be true
}
```

#### 3. THROW_ERROR

```typescript
try {
  const result = await featureFlagService.isFeatureEnabled(
    user,
    'feature-flag',
    ErrorBehaviour.THROW_ERROR,
  );
} catch (error) {
  console.error('Feature flag evaluation failed:', error);
}
```

### Common Error Scenarios

- **Network timeouts** (Flagsmith provider)
- **Invalid API keys** (Flagsmith provider)
- **Malformed flag names**
- **Provider initialization failures**
- **Cache errors**

## Advanced Features

### Custom Registry

```typescript
import { FeatureFlagRegistry, FeatureFlagService } from '@rudderstack/feature-flags';

// Create custom registry
const customRegistry = new FeatureFlagRegistry();
customRegistry.register({
  key: 'custom-flag',
  name: 'Custom Flag',
  description: 'A custom flag',
  defaultValue: true,
  type: 'boolean',
});

// Use custom registry with service
// Option 1: Manual creation
const customService = new FeatureFlagService(customRegistry);
await customService.initialize();

// Option 2a: Factory method with flag definitions (simple)
const factoryService = await FeatureFlagService.create({}, [
  {
    key: 'custom-flag',
    name: 'Custom Flag',
    description: 'A custom flag',
    defaultValue: true,
    type: 'boolean' as const,
  },
]);

// Option 2b: Factory method with custom registry (advanced)
const advancedFactoryService = await FeatureFlagService.create({}, customRegistry);
```

### Registry Operations

```typescript
// Get all flags
const allFlags = customRegistry.getAll();

// Get flags by category
const uiFlags = customRegistry.getByCategory('ui');

// Check if flag exists
const exists = customRegistry.isRegistered('my-flag');

// Get default value
const defaultValue = customRegistry.getDefaultValue('my-flag');

// Clear all flags
customRegistry.clear();
```

### Workspace-Specific Configuration

```typescript
// Different behavior per workspace
const prodUser: FeatureFlagUser = {
  workspaceId: 'prod-workspace',
  traits: new Map([[TRAIT_KEYS.ORGANIZATION_ID, 'prod-org']]),
};

const devUser: FeatureFlagUser = {
  workspaceId: 'dev-workspace',
  traits: new Map([[TRAIT_KEYS.ORGANIZATION_ID, 'dev-org']]),
};

// Set environment variables for different workspaces
// FEATURE_FLAG_LOCAL__prod_workspace__NEW_FEATURE=false
// FEATURE_FLAG_LOCAL__dev_workspace__NEW_FEATURE=true

const prodResult = await featureFlagService.isFeatureEnabled(prodUser, 'new-feature');
const devResult = await featureFlagService.isFeatureEnabled(devUser, 'new-feature');

console.log(`Prod: ${prodResult.enabled}, Dev: ${devResult.enabled}`);
```

### Performance Optimization

```typescript
// Configure for high-performance scenarios
await featureFlagService.initialize({
  provider: 'flagsmith',
  apiKey: 'your-key',
  enableLocalEvaluation: true, // Reduce network calls
  enableCache: true, // Cache responses
  cacheTtlSeconds: 600, // 10-minute cache
  timeoutSeconds: 5, // Fast timeout
  retryAttempts: 1, // Minimal retries
});

// Use cached methods for better performance
const cachedResult = await featureFlagService.isFeatureEnabled(user, 'flag');

// Use latest methods only when freshness is critical
const latestResult = await featureFlagService.isFeatureEnabledLatest(user, 'flag');
```

## Implementation Design

### Architecture Overview

The Feature Flags module follows a layered architecture with clear separation of concerns:

```
┌─────────────────────────────────────────────────────────────┐
│                    Client Application                       │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────────┐
│                 Service Layer                               │
│  ┌─────────────────────────────────────────────────────┐    │
│  │            FeatureFlagService                       │    │
│  │  - Unified API                                      │    │
│  │  - Error handling strategies                        │    │
│  │  - Response processing                              │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────────┐
│                Provider Layer                               │
│  ┌─────────────────┐              ┌─────────────────────┐    │
│  │ LocalProvider   │              │ FlagsmithProvider   │    │
│  │ - Env variables │              │ - Remote API        │    │
│  │ - Registry      │              │ - SDK integration   │    │
│  │ - Workspace     │              │ - Caching           │    │
│  └─────────────────┘              └─────────────────────┘    │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────────┐
│              Infrastructure Layer                           │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────┐  │
│  │   Registry      │  │   Config        │  │   Utils     │  │
│  │ - Flag storage  │  │ - Env parsing   │  │ - Validation│  │
│  │ - Validation    │  │ - Defaults      │  │ - Helpers   │  │
│  └─────────────────┘  └─────────────────┘  └─────────────┘  │
└─────────────────────────────────────────────────────────────┘
```

### Design Principles

#### 1. Strategy Pattern

The module uses the Strategy pattern for provider selection, eliminating conditional logic in the service layer:

```typescript
// Factory creates appropriate provider
const factory = new FeatureFlagProviderFactory(registry);
this.provider = factory.create(resolvedConfig);

// Service uses provider polymorphically
const result = await this.provider.isFeatureEnabled(user, flagName);
```

#### 2. Dependency Injection

Components accept dependencies through constructors, enabling testability and flexibility:

```typescript
export class FeatureFlagService {
  constructor(registry?: IFeatureFlagRegistry) {
    this.flagRegistry = registry || new FeatureFlagRegistry();
  }
}
```

#### 3. Interface Segregation

Clear interfaces define contracts between layers:

- `IFeatureFlagService` - Service contract
- `IFeatureFlagProvider` - Provider contract
- `IFeatureFlagRegistry` - Registry contract

#### 4. Single Responsibility

Each class has a focused responsibility:

- **Service**: API orchestration and response processing
- **Providers**: Flag evaluation logic
- **Registry**: Flag definition management
- **Config**: Environment variable resolution
- **Utils**: Validation and helper functions

#### 5. Open/Closed Principle

The system is open for extension (new providers) but closed for modification:

```typescript
// Adding a new provider requires no changes to existing code
export class CustomProvider implements IFeatureFlagProvider {
  // Implementation
}

// Register in factory
case 'custom':
  return new CustomProvider(this.registry);
```

### Component Interactions

#### Initialization Flow

```
1. Client calls service.initialize(config)
2. ConfigResolver processes config + env variables
3. ProviderFactory creates appropriate provider
4. Provider initializes (SDK setup for Flagsmith)
5. Service ready for flag evaluation
```

#### Flag Evaluation Flow

```
1. Client calls service.isFeatureEnabled(user, flag)
2. Service delegates to provider.isFeatureEnabled()
3. Provider evaluates flag:
   - Local: Check env vars → registry → defaults
   - Flagsmith: Query SDK → cache → network
4. Provider returns FeatureValue
5. Service processes result based on ErrorBehaviour
6. Service returns FeatureFlagResponse to client
```

#### Environment Variable Resolution (Local Provider)

```
1. Check FEATURE_FLAG_LOCAL__{workspaceId}__{FLAG_NAME}
2. Check FEATURE_FLAG_LOCAL_{FLAG_NAME}
3. Check registry configured values
4. Return registry default value
```

### Error Handling Strategy

The module implements a comprehensive error handling strategy:

#### Provider Level

- Providers catch and wrap errors in FeatureValue.error
- Network errors, timeouts, and API failures are handled gracefully
- Providers never throw exceptions during evaluation

#### Service Level

- Service processes provider errors based on ErrorBehaviour
- Three strategies: silent failure, rich error, or exception
- Default values are always available through registry

#### Client Level

- Clients can choose error handling strategy per call
- Rich responses provide full context for debugging
- Analytics tracking remains functional even during errors

### Performance Considerations

#### Caching Strategy

- **Flagsmith**: Built-in SDK caching with configurable TTL
- **Local**: No caching needed (environment variables are fast)
- **Service**: No additional caching layer to avoid complexity

#### Network Optimization

- **Local Evaluation**: Reduces network calls for Flagsmith
- **Timeouts**: Configurable to prevent hanging requests
- **Retries**: Configurable retry attempts with exponential backoff

#### Memory Management

- **Registry**: In-memory storage for flag definitions
- **Providers**: Stateless design for easy scaling
- **SDK**: Managed lifecycle with proper cleanup

## API Reference

### Core Service

#### FeatureFlagService

```typescript
class FeatureFlagService implements IFeatureFlagService {
  constructor(registry?: IFeatureFlagRegistry);

  // Factory method overloads: Create and initialize in one step
  static create(
    config?: Partial<FeatureFlagConfig>,
    flags?: FeatureFlagDefinition[],
  ): Promise<FeatureFlagService>;
  static create(
    config?: Partial<FeatureFlagConfig>,
    registry?: IFeatureFlagRegistry,
  ): Promise<FeatureFlagService>;

  // Initialization
  initialize(config?: Partial<FeatureFlagConfig>): Promise<void>;

  // Flag evaluation (cached)
  isFeatureEnabled(
    user: FeatureFlagUser,
    flagName: string,
    onErrorBehaviour?: ErrorBehaviour,
  ): Promise<FeatureFlagResponse>;

  getFeatureValue(
    user: FeatureFlagUser,
    flagName: string,
    onErrorBehaviour?: ErrorBehaviour,
  ): Promise<FeatureFlagResponse>;

  // Flag evaluation (latest)
  isFeatureEnabledLatest(
    user: FeatureFlagUser,
    flagName: string,
    onErrorBehaviour?: ErrorBehaviour,
  ): Promise<FeatureFlagResponse>;

  getFeatureValueLatest(
    user: FeatureFlagUser,
    flagName: string,
    onErrorBehaviour?: ErrorBehaviour,
  ): Promise<FeatureFlagResponse>;

  // Registry management
  registerFlags(flags: FeatureFlagDefinition[]): void;
  getRegisteredFlag(key: string): FeatureFlagDefinition | undefined;
}
```

### Registry System

#### FeatureFlagRegistry

```typescript
class FeatureFlagRegistry implements IFeatureFlagRegistry {
  // Registration
  register(definition: FeatureFlagDefinition): void;
  register(definitions: FeatureFlagDefinition[]): void;

  // Retrieval
  get(key: string): FeatureFlagDefinition | undefined;
  getAll(): FeatureFlagDefinition[];
  getByCategory(category: string): FeatureFlagDefinition[];
  getDefaultValue(key: string): boolean | string | number;

  // Utilities
  isRegistered(key: string): boolean;
  clear(): void;
}
```

#### FeatureFlagLoader

```typescript
class FeatureFlagLoader {
  static fromJSON(json: string): FeatureFlagDefinition[];
  static fromObject(config: FeatureFlagConfig): FeatureFlagDefinition[];
  static fromEnvironment(): FeatureFlagDefinition[];
}
```

### Type Definitions

#### Core Types

```typescript
interface FeatureFlagUser {
  workspaceId: string;
  traits?: Map<TRAIT_KEYS, string>;
}

interface FeatureFlagResponse extends FeatureValue {
  isDefault: boolean;
}

interface FeatureValue {
  name: string;
  enabled: boolean;
  value?: unknown;
  metadata?: Record<string, unknown>;
  lastUpdatedAt?: Date;
  isStale?: boolean;
  error?: Error;
  track?: () => void;
}

interface FeatureFlagDefinition {
  key: string;
  name: string;
  description: string;
  defaultValue: boolean | string | number;
  type: 'boolean' | 'string' | 'number';
  category?: string;
  tags?: string[];
}

enum ErrorBehaviour {
  RETURN_DEFAULT = 'return_default',
  RETURN_RICH_ERROR = 'return_rich_error',
  THROW_ERROR = 'throw_error',
}
```

### Environment Variables Reference

#### Service Configuration

- `FEATURE_FLAG_PROVIDER` - Provider selection ('local' | 'flagsmith')
- `FEATURE_FLAG_API_KEY` - Flagsmith API key
- `FEATURE_FLAG_ENABLE_CACHE` - Enable caching (boolean)
- `FEATURE_FLAG_CACHE_TTL_SECONDS` - Cache TTL (number)
- `FEATURE_FLAG_TIMEOUT_SECONDS` - Request timeout (number)
- `FEATURE_FLAG_RETRY_ATTEMPTS` - Retry attempts (number)
- `FEATURE_FLAG_ENABLE_LOCAL_EVALUATION` - Local evaluation (boolean)
- `FEATURE_FLAG_ENABLE_ANALYTICS` - Analytics tracking (boolean)

#### Local Provider Flags

- `FEATURE_FLAG_LOCAL_{FLAG_NAME}` - Global flag override
- `FEATURE_FLAG_LOCAL__{WORKSPACE_ID}__{FLAG_NAME}` - Workspace-specific override

#### Configuration Loading

- `FEATURE_FLAGS_CONFIG_PATH` - Path to JSON configuration file

---

## Examples and Best Practices

### Production Setup

```typescript
import {
  featureFlagService,
  FeatureFlagService,
  FeatureFlagRegistry,
} from '@rudderstack/feature-flags';

// Set up production flags
const productionFlags = [
  {
    key: 'new-checkout-flow',
    name: 'New Checkout Flow',
    description: 'Enable new checkout experience',
    defaultValue: false,
    type: 'boolean' as const,
  },
  {
    key: 'max-cart-items',
    name: 'Maximum Cart Items',
    description: 'Maximum items allowed in cart',
    defaultValue: 50,
    type: 'number' as const,
  },
];

// Option 1: Global service with production config
featureFlagService.registerFlags(productionFlags);
await featureFlagService.initialize({
  provider: 'flagsmith',
  apiKey: process.env.FLAGSMITH_API_KEY,
  enableLocalEvaluation: true,
  enableCache: true,
  cacheTtlSeconds: 300,
  timeoutSeconds: 10,
  retryAttempts: 3,
  enableAnalytics: true,
});

// Option 2a: Factory method with flags (simple)
const prodService = await FeatureFlagService.create(
  {
    provider: 'flagsmith',
    apiKey: process.env.FLAGSMITH_API_KEY,
    enableLocalEvaluation: true,
    enableCache: true,
    cacheTtlSeconds: 300,
    timeoutSeconds: 10,
    retryAttempts: 3,
    enableAnalytics: true,
  },
  productionFlags,
);

// Option 2b: Factory method with registry (advanced)
const prodRegistry = new FeatureFlagRegistry();
prodRegistry.register(productionFlags);
// Registry can load additional flags from files, databases, etc.
const advancedProdService = await FeatureFlagService.create(
  {
    provider: 'flagsmith',
    apiKey: process.env.FLAGSMITH_API_KEY,
    enableLocalEvaluation: true,
    enableCache: true,
    cacheTtlSeconds: 300,
    timeoutSeconds: 10,
    retryAttempts: 3,
    enableAnalytics: true,
  },
  prodRegistry,
);
```

### Development Setup

```typescript
import { featureFlagService, FeatureFlagService } from '@rudderstack/feature-flags';

// Set up development flags
const devFlags = [
  {
    key: 'debug-mode',
    name: 'Debug Mode',
    description: 'Enable debug logging and tools',
    defaultValue: true,
    type: 'boolean' as const,
  },
  {
    key: 'mock-api-delay',
    name: 'Mock API Delay',
    description: 'Artificial delay for API calls in ms',
    defaultValue: 0,
    type: 'number' as const,
  },
];

// Option 1: Global service for development
featureFlagService.registerFlags(devFlags);
await featureFlagService.initialize({
  provider: 'local',
});

// Option 2: Factory method for development
const devService = await FeatureFlagService.create(
  {
    provider: 'local',
  },
  devFlags,
);

// Override flags via environment
process.env.FEATURE_FLAG_LOCAL_DEBUG_MODE = 'true';
process.env.FEATURE_FLAG_LOCAL_MOCK_API_DELAY = '500';
```

### Testing Setup

```typescript
// Test configuration with custom registry
const testRegistry = new FeatureFlagRegistry();
testRegistry.register([
  {
    key: 'test-feature',
    name: 'Test Feature',
    description: 'Feature for testing',
    defaultValue: false,
    type: 'boolean',
  },
]);

const testService = new FeatureFlagService(testRegistry);
await testService.initialize({ provider: 'local' });
```

This comprehensive documentation covers all aspects of the Feature Flags module, from basic usage to advanced implementation details. The module provides a robust, flexible, and well-architected solution for feature flag management in the Rudder Integrations Library.