0.0.34 • Published 7 months ago

@flagdeck/js v0.0.34

Weekly downloads
-
License
-
Repository
-
Last release
7 months ago

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/js

Quick 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']); // string

Real-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:

OptionTypeDefaultDescription
apiKeystringrequiredYour Flagdeck API key
enableCachebooleantrueCache flag evaluations in memory
cacheTimeoutnumber30000Cache timeout in milliseconds
timeoutnumber5000Network request timeout in milliseconds
retryConfigobject{ attempts: 3, delay: 1000, maxDelay: 5000 }Retry configuration for network errors
debugbooleanfalseEnable detailed logging
enableOfflineModebooleanfalseEnable offline fallback mode
enableAnalyticsbooleantrueTrack evaluation metrics
realTimeUpdatesbooleanauto (true for browser, false for Node.js)Enable real-time flag updates
onErrorfunctionundefinedGlobal error handler
defaultFlagValueanyfalseDefault value when evaluation fails
sdkPlatformstringauto-detectedOverride 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 behavior

Offline 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 localStorage with memory fallback and handles quota errors
  • Node.js: Uses filesystem storage in the user's home directory (~/.flagdeck) with temp directory fallback

Important Considerations

  1. Offline Mode Must Be Enabled: Set enableOfflineMode: true in your configuration options
  2. Save Flags Proactively: Call saveForOffline() or saveMultipleForOffline() when your app has connectivity
  3. Storage Limits: Be mindful of storage limits, especially for mobile browsers with tight localStorage quotas
  4. Flag Expiration: Stored flags expire after 7 days by default; customize expiration by providing a TTL (coming soon)
  5. 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 hour

Cache 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:

  1. Storage Mechanisms:

    • Browser: Uses localStorage for offline storage when available
    • Node.js: Uses file system storage in the user's home directory
  2. Network Implementation:

    • Browser: Uses the native fetch API
    • Node.js: Uses node-fetch when the native fetch isn't available (Node.js < 18)
  3. Environment Detection:

    • Browser: Detects browser, screen, and web-specific properties
    • Node.js: Detects Node.js version, platform, and server-specific properties
  4. 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 enabled
  • getValue<T>(flagKey: string, context?: EvaluationContext, defaultValue?: T): Promise<T> - Gets just the flag value
  • getValues<T>(flagKeys: string[], context?: EvaluationContext, defaultValue?: T): Promise<Record<string, T>> - Gets multiple flag values at once
  • evaluateFlag(flagKey: string, context?: EvaluationContext): Promise<EvaluationResult> - Evaluates a flag with full details
  • evaluate(flagKey: string, context?: EvaluationContext): Promise<EvaluationResult> - Legacy alias for evaluateFlag (deprecated)
  • evaluateBulk(flagKeys: string[], context?: EvaluationContext): Promise<BulkEvaluationResponse> - Evaluates multiple flags
  • use(middleware: EvaluationMiddleware): Flagdeck - Adds an evaluation middleware
  • clearCache(): void - Clears the evaluation cache
  • saveForOffline(flagKey: string, value: any): Promise<void> - Saves a flag for offline use
  • saveMultipleForOffline(flags: Record<string, any>): Promise<void> - Saves multiple flags for offline use
  • clearOfflineStorage(): Promise<void> - Clears stored offline flags
  • flushAnalytics(): Promise<void> - Manually sends any pending analytics events
  • on(event: string, listener: Function): Flagdeck - Subscribe to events (including real-time updates)
  • off(event: string, listener: Function): Flagdeck - Unsubscribe from events
  • onFlagChange(flagKey: string, listener: (newValue: any, oldValue: any) => void): Flagdeck - Subscribe to changes for a specific flag
  • enableRealTimeUpdates(options?: object): void - Enable real-time flag updates
  • disableRealTimeUpdates(): void - Disable real-time flag updates
  • areRealTimeUpdatesEnabled(): boolean - Check if real-time updates are currently enabled
  • resetSseCircuitBreaker(): void - Reset the circuit breaker if connections are failing
  • subscribeToFlags(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.

0.0.34

7 months ago

0.0.33

8 months ago

0.0.32

8 months ago

0.0.31

8 months ago

0.0.29

8 months ago

0.0.28

8 months ago

0.0.27

8 months ago

0.0.26

8 months ago

0.0.25

8 months ago

0.0.24

8 months ago

0.0.23

8 months ago

0.0.22

8 months ago

0.0.21

8 months ago

0.0.20

8 months ago

0.0.19

8 months ago

0.0.18

8 months ago

0.0.17

8 months ago

0.0.16

8 months ago

0.0.15

8 months ago

0.0.14

8 months ago

0.0.13

8 months ago

0.0.11

8 months ago

0.0.10

8 months ago

0.0.9

8 months ago

0.0.8

8 months ago

0.0.7

8 months ago

0.0.6

8 months ago

0.0.5

8 months ago

0.0.4

8 months ago

0.0.3

8 months ago

0.0.2

8 months ago

0.0.1

9 months ago

0.1.0

9 months ago