@flagdeck/js v0.0.34
Flagdeck JavaScript SDK
The official JavaScript/TypeScript SDK for Flagdeck, a modern feature flag and feature management system.
Installation
npm install @flagdeck/js
# or
yarn add @flagdeck/jsQuick Start
import { Flagdeck } from '@flagdeck/js';
// Initialize the client
const flagdeck = new Flagdeck({
apiKey: 'your-api-key'
});
// Check if a feature flag is enabled
async function checkFeature() {
const isEnabled = await flagdeck.isEnabled('new-feature', {
userId: 'user-123',
attributes: {
country: 'US',
plan: 'premium'
}
});
if (isEnabled) {
// Feature is enabled for this user
enableNewFeature();
} else {
// Feature is disabled
useDefaultFeature();
}
}Environment-Specific Imports
The SDK automatically detects your environment (browser or Node.js) and uses the appropriate implementation. If you want to explicitly import a specific version:
Browser Import
import { Flagdeck } from '@flagdeck/js/browser';
const flagdeck = new Flagdeck({
apiKey: 'your-api-key'
});Node.js Import
import { Flagdeck } from '@flagdeck/js/node';
const flagdeck = new Flagdeck({
apiKey: 'your-api-key'
});Working with Different Value Types
Flagdeck supports multiple value types for feature flags:
Boolean Flags
// Check if a feature is enabled
const isEnabled = await flagdeck.isEnabled('new-feature');
if (isEnabled) {
showNewFeature();
}String Variants
// Get a string variant value with default
const variant = await flagdeck.getValue<string>('experiment-variant', context, 'control');
if (variant === 'A') {
// Show variant A
} else if (variant === 'B') {
// Show variant B
}Numeric Settings
// Get a numeric configuration value with default
const limit = await flagdeck.getValue<number>('rate-limit', context, 100);
applyRateLimit(limit);JSON/Object Configuration
// Get complex configuration with TypeScript type
const config = await flagdeck.getValue<{
url: string;
timeout: number;
retries: number;
}>('api-config', context, { url: 'default.com', timeout: 5000, retries: 3 });Advanced Usage: Full Evaluation Details
When you need additional metadata about an evaluation:
// Get the full evaluation result
const result = await flagdeck.evaluateFlag('new-feature', context);
console.log(`Feature is ${result.value ? 'enabled' : 'disabled'}`);
console.log(`Source: ${result.source}`); // 'api', 'cache', etc.
console.log(`Reason: ${result.reason}`);
console.log(`Evaluated at: ${new Date(result.timestamp)}`);Multiple Flags at Once
// Get multiple flag values in a single request
const values = await flagdeck.getValues([
'feature-a',
'rate-limit',
'experiment'
], context);
console.log(values['feature-a']); // boolean
console.log(values['rate-limit']); // number
console.log(values['experiment']); // stringReal-Time Updates
Flagdeck supports real-time flag updates, allowing your application to instantly react to flag changes made in the Flagdeck dashboard without requiring page refreshes or API polling.
Enabling Real-Time Updates
Real-time updates are enabled by default in browser environments and disabled by default in server environments. You can explicitly control this behavior during initialization:
const flagdeck = new Flagdeck({
apiKey: 'your-api-key',
realTimeUpdates: true // Enable real-time updates
});Listening for Flag Changes
// Listen for changes to a specific flag
flagdeck.onFlagChange('welcome-message', (newValue, oldValue) => {
console.log(`Flag value changed from ${oldValue} to ${newValue}`);
// Update your UI based on the new value
if (newValue === true) {
showWelcomeMessage();
} else {
hideWelcomeMessage();
}
});
// Listen for a flag being enabled
flagdeck.on('enabled:feature-name', (value) => {
console.log('Feature was enabled!');
showFeature();
});
// Listen for a flag being disabled
flagdeck.on('disabled:feature-name', (value) => {
console.log('Feature was disabled!');
hideFeature();
});
// Listen for all flag changes
flagdeck.on('change', (changes) => {
console.log('Multiple flags changed:', changes);
// { flagKey1: { newValue, oldValue }, flagKey2: { newValue, oldValue } }
});
// Listen for connection events
flagdeck.on('connected', () => {
console.log('Connected to real-time updates');
});
flagdeck.on('disconnected', (error) => {
console.log('Disconnected from real-time updates', error);
});
flagdeck.on('error', (error) => {
console.error('Real-time updates error', error);
});Managing Real-Time Updates
You can enable or disable real-time updates at runtime:
// Enable real-time updates with options
flagdeck.enableRealTimeUpdates({
autoUpdate: true, // Automatically update cached values when flags change
onFlagUpdate: (flagKey, newValue) => {
console.log(`Flag ${flagKey} updated to:`, newValue);
},
onConnect: () => {
console.log('Connected to real-time updates');
},
onDisconnect: (error) => {
console.log('Disconnected from real-time updates', error);
}
});
// Disable real-time updates
flagdeck.disableRealTimeUpdates();
// Check if real-time updates are enabled
const enabled = flagdeck.areRealTimeUpdatesEnabled();
console.log('Real-time updates enabled:', enabled);
// Reset circuit breaker if connections are failing
flagdeck.resetSseCircuitBreaker();Subscribing to Specific Flags
In server environments, you can optimize performance by subscribing only to specific flags:
// In Node.js, subscribe to specific flags with options
flagdeck.subscribeToFlags(['payment-gateway', 'auth-method'], {
priority: 'high', // 'high', 'normal', or 'low'
ttl: 3600000 // Subscription time-to-live in ms (1 hour)
});Real-Time Updates Implementation Details
- Browser: Uses the native EventSource API (Server-Sent Events) with automatic reconnection
- Node.js: Uses the 'eventsource' package (must be installed separately)
- Fault Tolerance: Includes circuit breaker pattern to prevent excessive reconnection attempts
- Memory Management: Automatically cleans up unused flag subscriptions
- Performance: Optimized to minimize bandwidth and CPU usage
Evaluation Context
Most evaluation methods accept a context parameter that defines the user and environment details for targeting rules. Here's how to structure the context:
// Basic context with user ID
const context = {
userId: 'user-123'
};
// Full context with attributes
const detailedContext = {
userId: 'user-456',
sessionId: 'session-789', // Optional session identifier
attributes: {
// User attributes for targeting
email: 'user@example.com',
plan: 'premium',
country: 'US',
isAdmin: true,
// Custom business attributes
purchaseCount: 5,
lastLoginDate: '2023-04-15',
// Device/environment attributes
device: 'mobile',
browser: 'chrome',
version: '1.2.3'
}
};Configuration Options
The following options can be provided when initializing the Flagdeck SDK:
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | string | required | Your Flagdeck API key |
| enableCache | boolean | true | Cache flag evaluations in memory |
| cacheTimeout | number | 30000 | Cache timeout in milliseconds |
| timeout | number | 5000 | Network request timeout in milliseconds |
| retryConfig | object | { attempts: 3, delay: 1000, maxDelay: 5000 } | Retry configuration for network errors |
| debug | boolean | false | Enable detailed logging |
| enableOfflineMode | boolean | false | Enable offline fallback mode |
| enableAnalytics | boolean | true | Track evaluation metrics |
| realTimeUpdates | boolean | auto (true for browser, false for Node.js) | Enable real-time flag updates |
| onError | function | undefined | Global error handler |
| defaultFlagValue | any | false | Default value when evaluation fails |
| sdkPlatform | string | auto-detected | Override detected platform ('web', 'mobile', 'server') |
Error Handling
// Global error handler
const flagdeck = new Flagdeck({
apiKey: 'your-api-key',
onError: (error, flagKey) => {
console.error(`Error evaluating flag ${flagKey}:`, error);
// Log to your error tracking system
errorTracker.captureException(error);
},
defaultFlagValue: false // Value to use if evaluation fails
});
// Try/catch for specific evaluations
try {
const result = await flagdeck.evaluateFlag('new-feature');
// Use result
} catch (error) {
// Handle error
console.error('Failed to evaluate flag:', error);
}Middleware
Add custom behavior to the flag evaluation process with middleware:
flagdeck.use({
name: 'LoggingMiddleware',
beforeEvaluation: (flagKey, context) => {
console.log(`Evaluating flag: ${flagKey}`, context);
},
afterEvaluation: (flagKey, result, context) => {
console.log(`Flag ${flagKey} evaluated to:`, result.value);
return result;
},
onError: (error, flagKey) => {
console.error(`Error evaluating flag ${flagKey}:`, error);
}
});Offline Mode
Enable offline support to maintain functionality when connectivity is lost. Offline mode is essential for applications that need to maintain consistent feature flag evaluation during network outages, mobile usage with intermittent connectivity, or to reduce server load.
const flagdeck = new Flagdeck({
apiKey: 'your-api-key',
enableOfflineMode: true
});
// Save current flags for offline use
await flagdeck.saveForOffline('feature-a', true);
// Save multiple flags at once
await flagdeck.saveMultipleForOffline({
'feature-a': true,
'feature-b': false,
'limit': 100
});
// Clear offline storage
await flagdeck.clearOfflineStorage();
// When offline, the SDK will automatically use stored flag values
// No additional code needed for fallback behaviorOffline Storage Details
The SDK implements an efficient storage system with the following optimizations:
- Flag Expiration: Flags are stored with expiration times (default: 7 days)
- Automatic Pruning: Oldest flags are automatically removed when storage limits are reached
- Size Management: Storage size is monitored and optimized (100KB limit in browsers, 500KB in Node.js)
- Periodic Maintenance: The SDK automatically cleans up expired flags
- Efficient I/O: Batch operations minimize disk/localStorage writes
Environment-Specific Storage
- Browser: Uses
localStoragewith memory fallback and handles quota errors - Node.js: Uses filesystem storage in the user's home directory (
~/.flagdeck) with temp directory fallback
Important Considerations
- Offline Mode Must Be Enabled: Set
enableOfflineMode: truein your configuration options - Save Flags Proactively: Call
saveForOffline()orsaveMultipleForOffline()when your app has connectivity - Storage Limits: Be mindful of storage limits, especially for mobile browsers with tight localStorage quotas
- Flag Expiration: Stored flags expire after 7 days by default; customize expiration by providing a TTL (coming soon)
- Flushing Before App Closure: For browser applications, consider flushing before app closure:
// Ensure flags are properly saved before app-boot closes
window.addEventListener('beforeunload', async () => {
// Save important flags one last time
await flagdeck.saveMultipleForOffline({
'critical-feature': await flagdeck.getValue('critical-feature'),
'user-settings': await flagdeck.getValue('user-settings')
});
// Also flush analytics
await flagdeck.flushAnalytics();
});Best Practices
- Default Values: Always provide sensible default values as a final fallback
- Periodic Refreshes: Refresh offline flags periodically during active use
- Critical Flags: Identify and prioritize saving business-critical flags
- Storage Monitoring: For sensitive applications, monitor offline storage usage
// Example: Refresh critical flags every hour during active use
setInterval(async () => {
if (navigator.onLine) { // Check connectivity (browser only)
try {
const criticalFlags = await flagdeck.getValues([
'payment-gateway',
'auth-method',
'pricing-tiers'
]);
await flagdeck.saveMultipleForOffline(criticalFlags);
console.log('Refreshed offline flags successfully');
} catch (error) {
console.error('Failed to refresh offline flags:', error);
}
}
}, 60 * 60 * 1000); // 1 hourCache Management
The SDK automatically caches flag evaluations to improve performance. You can manage the cache manually:
// Clear the cache
flagdeck.clearCache();Analytics
The SDK collects anonymous usage statistics by default. You can flush these analytics manually before the app closes:
// Flush analytics events
await flagdeck.flushAnalytics();Cleanup
When you're done with the Flagdeck client, you should clean up resources:
// Clean up resources when done
await flagdeck.destroy();Platform Support
This SDK works across platforms:
- Browsers: All modern browsers are supported
- Node.js: Server-side environments
- React Native: Mobile applications (via the JavaScript runtime)
TypeScript Support
The SDK includes complete TypeScript definitions:
import { Flagdeck, EvaluationContext } from '@flagdeck/js';
const flagdeck = new Flagdeck({
apiKey: 'your-api-key'
});
const context: Partial<EvaluationContext> = {
userId: 'user-123',
attributes: {
plan: 'premium',
region: 'eu-west',
isAdmin: true
}
};
const result = await flagdeck.evaluateFlag('new-feature', context);Differences Between Browser and Node.js Versions
While both versions share the same API, there are some internal differences:
Storage Mechanisms:
- Browser: Uses
localStoragefor offline storage when available - Node.js: Uses file system storage in the user's home directory
- Browser: Uses
Network Implementation:
- Browser: Uses the native
fetchAPI - Node.js: Uses
node-fetchwhen the nativefetchisn't available (Node.js < 18)
- Browser: Uses the native
Environment Detection:
- Browser: Detects browser, screen, and web-specific properties
- Node.js: Detects Node.js version, platform, and server-specific properties
Real-Time Updates:
- Browser: Enabled by default, uses native EventSource API
- Node.js: Disabled by default, requires the 'eventsource' package
These differences are handled internally, allowing you to use the same API regardless of environment.
API Reference
Flagdeck
The main class for interacting with Flagdeck.
Methods
isEnabled(flagKey: string, context?: EvaluationContext, defaultValue?: boolean): Promise<boolean>- Checks if a flag is enabledgetValue<T>(flagKey: string, context?: EvaluationContext, defaultValue?: T): Promise<T>- Gets just the flag valuegetValues<T>(flagKeys: string[], context?: EvaluationContext, defaultValue?: T): Promise<Record<string, T>>- Gets multiple flag values at onceevaluateFlag(flagKey: string, context?: EvaluationContext): Promise<EvaluationResult>- Evaluates a flag with full detailsevaluate(flagKey: string, context?: EvaluationContext): Promise<EvaluationResult>- Legacy alias for evaluateFlag (deprecated)evaluateBulk(flagKeys: string[], context?: EvaluationContext): Promise<BulkEvaluationResponse>- Evaluates multiple flagsuse(middleware: EvaluationMiddleware): Flagdeck- Adds an evaluation middlewareclearCache(): void- Clears the evaluation cachesaveForOffline(flagKey: string, value: any): Promise<void>- Saves a flag for offline usesaveMultipleForOffline(flags: Record<string, any>): Promise<void>- Saves multiple flags for offline useclearOfflineStorage(): Promise<void>- Clears stored offline flagsflushAnalytics(): Promise<void>- Manually sends any pending analytics eventson(event: string, listener: Function): Flagdeck- Subscribe to events (including real-time updates)off(event: string, listener: Function): Flagdeck- Unsubscribe from eventsonFlagChange(flagKey: string, listener: (newValue: any, oldValue: any) => void): Flagdeck- Subscribe to changes for a specific flagenableRealTimeUpdates(options?: object): void- Enable real-time flag updatesdisableRealTimeUpdates(): void- Disable real-time flag updatesareRealTimeUpdatesEnabled(): boolean- Check if real-time updates are currently enabledresetSseCircuitBreaker(): void- Reset the circuit breaker if connections are failingsubscribeToFlags(flagKeys: string[], options?: object): void- Subscribe to specific flags (Node.js)destroy(): Promise<void>- Cleans up resources
License
MIT
Support
For issues, feature requests, or questions, please visit our GitHub repository or contact support@flagdeck.com.
7 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
9 months ago
9 months ago