flagsup-ts
v1.1.0
Published
Flagsup sdk (written in ts)
Readme
flagsup-ts
flagsup-ts is a TypeScript package for managing feature flags in TypeScript projects. It offers a flexible and efficient solution for implementing feature flagging strategies, allowing developers to control feature rollout and experimentation with ease.
Installation
Use the package manager yarn or npm to install the package
# Yarn
yarn add flagsup-ts
# NPM
npm install flagsup-tsFeatures
- TypeScript Support: Built specifically for TypeScript projects, ensuring type safety and enhanced developer experience
- Dynamic EntityId Configuration: Support for both static and dynamic entityId configurations, enabling flexible flag evaluation based on user context
- Dual Client Architecture: Choose between
FlagsupClient(traditional class) orFlagsupClientBuilder(builder pattern) based on your needs - Advanced Caching: Multiple caching strategies including in-memory, localStorage, and stale-while-revalidate patterns
- Real-time Updates: Subscribe to flag changes for reactive applications
- Retry Logic: Built-in retry mechanisms with exponential backoff
Quick Start
FlagsupClient (Traditional)
import FlagsupClient from "flagsup-ts";
// Create client with configuration
const client = new FlagsupClient({
targetHostname: "https://flagsup.tekoapis.com",
defaultEntityId: "user123",
useCacheRefresh: true,
refreshInterval: 60,
});
// Evaluate flags
const result = await client.batchEvaluateFlags({
feature_a: "user123",
feature_b: {
key: "feature_b",
entityId: "user456"
},
feature_c: {
key: "key_with_dynamic_entity_id",
getEntityId: (currentUser) => currentUser?.meta_data?.seller_id,
},
});
console.log("Flags:", result.flags);FlagsupClientBuilder (Builder Pattern)
import { FlagsupClientBuilder } from "flagsup-ts";
// Configure with fluent API
const client = new FlagsupClientBuilder()
.setTargetHostname("https://flagsup.tekoapis.com")
.setDefaultEntityId("user123")
.setMaxRetries(3)
.setAllowUseStaleTime(300);
// Subscribe to updates
const unsubscribe = client.subscribe((flags) => {
console.log("Flags updated:", flags);
});
// Get flags with caching
const result = await client.getFlags({
feature_a: "user123",
feature_b: {
key: "feature_b",
entityId: "user456"
},
feature_c: {
key: "key_with_dynamic_entity_id",
getEntityId: (currentUser) => currentUser?.meta_data?.seller_id,
},
});
unsubscribe();Clients
FlagsupClient
The FlagsupClient class provides a traditional approach to feature flag management with in-memory caching and optional auto-refresh capabilities.
Configuration
const client = new FlagsupClient({
targetHostname: "https://flagsup.tekoapis.com", // API hostname
defaultEntityId: "user123", // Default entity ID
clientInstanceName: "MyFlagsupClient", // Global window object name
refreshInterval: 30, // Auto-refresh interval (seconds)
useCacheRefresh: true // Enable auto-refresh
});Key Methods
evaluateFlag(flagKey, entityId?, options?): Evaluate single flagbatchEvaluateFlags(flagKeys, getEntityIdDataSource?, defaultResponse?): Evaluate multiple flagsgetFlagStatus(flagKey, defaultStatus?): Get flag enabled/disabled statusbatchGetFlagsStatus(flagKeys, defaultStatus?): Get status for multiple flagsflushCache(): Clear all cached data
React Example
import React, { useState, useEffect } from 'react';
import FlagsupClient from 'flagsup-ts';
const client = new FlagsupClient({
targetHostname: 'https://flagsup.tekoapis.com',
defaultEntityId: 'user123',
useCacheRefresh: true,
refreshInterval: 30,
});
function FeatureComponent() {
const [flags, setFlags] = useState({});
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchFlags = async () => {
const result = await client.batchEvaluateFlags({
'new_dashboard': 'user123',
'dark_mode': 'user123',
'beta_features': 'user123'
});
if (!result.error) {
setFlags(result.flags);
}
setLoading(false);
};
fetchFlags();
}, []);
if (loading) return <div>Loading...</div>;
return (
<div>
<h1>Dashboard</h1>
{flags.new_dashboard?.enabled && <div>New Dashboard Available!</div>}
{flags.dark_mode?.enabled && <div>Dark Mode: {flags.dark_mode.treatment}</div>}
</div>
);
}FlagsupClientBuilder
The FlagsupClientBuilder uses a builder pattern for configuration and provides advanced caching with localStorage, retry logic, and real-time subscriptions.
Configuration
const client = new FlagsupClientBuilder()
.setTargetHostname("https://flagsup.tekoapis.com") // Required
.setDefaultEntityId("user123") // Optional
.setMaxRetries(3) // Optional, default: 1
.setAllowUseStaleTime(300) // Optional, default: 0
.setEnableLogging(true); // Optional, default: falseKey Methods
subscribe(callback): Subscribe to flag updates, returns unsubscribe functiongetFreshFlags(flagKeys, getEntityIdDataSource?): Fetch fresh flags bypassing cachegetFlags(flagKeys, getEntityIdDataSource?): Smart fetch using cache when available
React Example with Real-time Updates
import React, { useState, useEffect } from 'react';
import { FlagsupClientBuilder } from 'flagsup-ts';
const client = new FlagsupClientBuilder()
.setTargetHostname('https://flagsup.tekoapis.com')
.setDefaultEntityId('user123')
.setMaxRetries(3)
.setAllowUseStaleTime(300)
.setEnableLogging(true);
function FeatureFlagComponent() {
const [flags, setFlags] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// Subscribe to real-time flag updates
const unsubscribe = client.subscribe(setFlags);
// Initial flag fetch
const fetchInitialFlags = async () => {
try {
const result = await client.getFlags({
'feature_a': 'user123',
'feature_b': { key: 'feature_b', entityId: 'user456' }
});
if (result.error) {
setError(result.error);
} else {
setFlags(result.flags);
}
} catch (err) {
setError('Failed to fetch flags');
} finally {
setLoading(false);
}
};
fetchInitialFlags();
return unsubscribe; // Cleanup on unmount
}, []);
if (loading) return <div>Loading flags...</div>;
if (error) return <div>Error: {error}</div>;
if (!flags) return <div>No flags available</div>;
return (
<div>
<h2>Feature Flags</h2>
<div>Feature A: {flags.feature_a?.enabled ? 'Enabled' : 'Disabled'}</div>
<div>Feature B: {flags.feature_b?.enabled ? 'Enabled' : 'Disabled'}</div>
<div>Treatment A: {flags.feature_a?.treatment}</div>
</div>
);
}Data Types
Flag Configuration
// Simple string (uses default entity ID)
const config1 = "flag_key";
// With static entity ID
const config2 = {
key: "flag_key",
entityId: "static_id"
};
// With dynamic entity ID
const config3 = {
key: "flag_key",
getEntityId: (user) => user.id
};
// Combined configuration object
const flagKeys = {
feature_a: "user123",
feature_b: config2,
feature_c: config3
};Flag Response Data
interface EvaluatedFlagData {
enabled: boolean;
expId: number;
treatment: string;
expBranchId: number;
}
interface EvaluatedFlagsData {
[flagKey: string]: EvaluatedFlagData;
}Advanced Usage
Dynamic Entity IDs
// For user-specific flags
const userFlags = await client.batchEvaluateFlags({
'premium_features': {
key: 'premium_features',
getEntityId: (user) => user.id
},
'geo_specific': {
key: 'geo_specific',
getEntityId: (user) => user.country
}
}, currentUser);Error Handling
const result = await client.getFlags(flagKeys);
if (result.error) {
console.error('Flag evaluation failed:', result.error);
// Fallback logic
} else {
// Use result.flags
}