A JavaScript SDK for Switcher API
Switcher Client JS is a feature-rich SDK for integrating Switcher API into your JS-based applications (Web, Node.js, Bun, Cloudflare Workers). It provides robust feature flag management with enterprise-grade capabilities.
- 🚀 Zero Latency: Local mode with snapshot files or in-memory for instant feature flag resolution
- 🔄 Hybrid Configuration: Silent mode with automatic fallback handling
- 🧪 Testing Ready: Built-in stub implementation for comprehensive testing
- ⚡ Performance Optimized: Throttling optimizes remote API calls to reduce bottlenecks in critical code paths
- 🛠️ Developer Tools: Runtime snapshot updates without app restart and automatic sync with remote API
Get up and running with Switcher Client in 3 simple steps:
npm install switcher-clientimport { Client } from 'switcher-client';
// 1. Initialize the client
Client.buildContext({
url: 'https://api.switcherapi.com',
apiKey: '[YOUR_API_KEY]',
domain: 'My Domain',
component: 'MyApp',
environment: 'default'
});
// 2. Get a switcher instance
const switcher = Client.getSwitcher('FEATURE01');
// 3. Check if a feature is enabled
const isFeatureEnabled = await switcher.isItOn();
console.log('Feature enabled:', isFeatureEnabled);npm install switcher-clientThe context properties store all information regarding connectivity:
import { Client } from 'switcher-client';
// Required configuration
const config = {
apiKey: '[API_KEY]', // Switcher-API key for your component
environment: 'default', // Environment name ('default' for production)
domain: 'My Domain', // Your domain name
component: 'MyApp', // Your application name
url: 'https://api.switcherapi.com' // Switcher-API endpoint (optional)
};
Client.buildContext(config);
const switcher = Client.getSwitcher();| Parameter | Type | Required | Description |
|---|---|---|---|
domain |
string | ✅ | Your Switcher domain name |
url |
string | Switcher API endpoint | |
apiKey |
string | API key for your component | |
component |
string | Your application name | |
environment |
string | Environment name (default: 'default' for production) |
Configure additional features for enhanced functionality:
Client.buildContext({
url, apiKey, domain, component, environment
}, {
local: true, // Enable local mode
freeze: false, // Prevent background updates
logger: true, // Enable request logging
snapshotLocation: './snapshot/', // Snapshot files directory
snapshotAutoUpdateInterval: 30, // Auto-update interval (seconds)
snapshotWatcher: true, // Monitor snapshot changes
silentMode: '5m', // Fallback timeout
restrictRelay: true, // Relay restrictions in local mode
regexSafe: true, // Prevent reDOS attacks
certPath: './certs/ca.pem', // SSL certificate path
autoRefreshToken: true // Automatically refresh API token
});| Option | Type | Description |
|---|---|---|
local |
boolean | Use only snapshot files/in-memory (no API calls) |
freeze |
boolean | Disable background cache updates with throttling |
logger |
boolean | Enable logging for debugging (Client.getLogger('KEY')) |
snapshotLocation |
string | Directory for snapshot files |
snapshotAutoUpdateInterval |
number | Auto-update interval in seconds (0 = disabled) |
snapshotWatcher |
boolean | Watch for snapshot file changes |
silentMode |
string | Fallback timeout (e.g., '5s', '2m', '1h') |
restrictRelay |
boolean | Enable relay restrictions in local mode |
regexSafe |
boolean | Protection against reDOS attacks |
regexMaxBlackList |
number | Max cached regex failures |
regexMaxTimeLimit |
number | Regex timeout in milliseconds |
certPath |
string | Path to SSL certificate file |
autoRefreshToken |
boolean | Automatically refresh API token |
Security Note:
regexSafeprevents ReDoS attacks. Keep this enabled in production.
Multiple ways to check if a feature is enabled:
// Non-persisted switcher instance
const switcher = Client.getSwitcher();
// Persisted switcher instance
const switcher = Client.getSwitcher('FEATURE01');
// 🚀 Synchronous (local mode only)
const isEnabled = switcher.isItOn(); // Returns: boolean
const isEnabledBool = switcher.isItOnBool(); // Returns: boolean
const detailResult = switcher.detail().isItOn(); // Returns: { result, reason, metadata }
const detailDirect = switcher.isItOnDetail(); // Returns: { result, reason, metadata }
// 🌐 Asynchronous (remote/hybrid mode)
const isEnabledAsync = await switcher.isItOn(); // Returns: Promise<boolean>
const isEnabledBoolAsync = await switcher.isItOnBool(true); // Returns: Promise<boolean>
const detailResultAsync = await switcher.detail().isItOn(); // Returns: Promise<SwitcherResult>
const detailDirectAsync = await switcher.isItOnDetail(true); // Returns: Promise<SwitcherResult>Load information into the switcher using prepare() when input comes from different parts of your code:
// Prepare the switcher with input data
await switcher.checkValue('USER_1').prepare('FEATURE01');
// Execute the check
const result = await switcher.isItOn();Fast method that includes everything in a single call:
const result = await switcher
.defaultResult(true) // 🛡️ Fallback result if API is unavailable
.throttle(1000) // ⚡ Cache result for 1 second
.checkValue('User 1') // 👤 User-based strategy
.checkNetwork('192.168.0.1') // 🌐 Network-based strategy
.isItOn('FEATURE01');Perfect for critical code blocks requiring zero-latency. API calls are scheduled after the throttle time:
const switcher = Client.getSwitcher();
// Cache result for 1 second
const result = await switcher
.throttle(1000)
.isItOn('FEATURE01');Subscribe to error events to capture issues during throttled execution:
Client.subscribeNotifyError((error) => {
console.error('Switcher error:', error);
});When using throttling, you can clear cached results for a specific switcher:
// Clear cached results for a specific switcher
Client.getSwitcher('FEATURE01').flushExecutions();Force specific switchers to resolve remotely while running in local mode. Ideal for features requiring remote validation (e.g., Relay Strategies):
const switcher = Client.getSwitcher();
// Force remote resolution for this specific call
const result = await switcher.remote().isItOn('FEATURE01');This feature allows you to specify how long the client SDK should attempt to restore connectivity in case of remote API failures.
When the API is unavailable, the SDK will automatically operate in silent mode, evaluating Switchers using a local snapshot. It is important to note that any Switcher Key configured must be able to resolve without external dependencies (e.g., Switcher Relay).
Make sure to configure the scheduled snapshot auto-update to keep the local snapshot up to date with the remote API.
Here is an example - in-memory snapshot with auto-update every 30 seconds:
Client.buildContext({
url, apiKey, domain, component, environment
}, {
snapshotAutoUpdateInterval: 30,
silentMode: '5m',
});Bypass switcher configuration for testing scenarios. Perfect for validating both enabled and disabled states:
// ✅ Force feature to be enabled
Client.assume('FEATURE01').true();
const result = switcher.isItOn('FEATURE01'); // Returns: true
// ❌ Force feature to be disabled
Client.assume('FEATURE01').false();
const result = switcher.isItOn('FEATURE01'); // Returns: false
// 🔄 Reset to normal behavior
Client.forget('FEATURE01');
const result = switcher.isItOn('FEATURE01'); // Returns: actual API/snapshot result// Add custom metadata to simulate Relay responses
Client.assume('FEATURE01')
.false()
.withMetadata({ message: 'Feature is disabled' });
const response = await switcher.detail().isItOn('FEATURE01');
console.log(response.result); // false
console.log(response.metadata.message); // "Feature is disabled"import { StrategiesType } from 'switcher-client';
// ✅ True only for specific value
Client.assume('FEATURE01')
.true()
.when(StrategiesType.VALUE, 'USER_1');
const resultUser1 = switcher.checkValue('USER_1').isItOn('FEATURE01'); // true
const resultUser2 = switcher.checkValue('USER_2').isItOn('FEATURE01'); // false
// ✅ True for multiple values
Client.assume('FEATURE01')
.true()
.when(StrategiesType.NETWORK, ['192.168.1.1', '192.168.1.2']);
const resultNetwork1 = switcher.checkNetwork('192.168.1.1').isItOn('FEATURE01'); // true
const resultNetwork2 = switcher.checkNetwork('192.168.1.3').isItOn('FEATURE01'); // falseEnable test mode to prevent snapshot file locking during automated testing:
// Add this to your test setup files
Client.testMode();💡 Tip: This prevents the Switcher Client from locking snapshot files even after test execution completes.
Validate feature flag during startup to catch configuration issues early:
try {
await Client.checkSwitchers(['FEATURE01', 'FEATURE02', 'CRITICAL_FEATURE']);
console.log('✅ All switchers configured correctly');
} catch (error) {
console.error('❌ Configuration issues found:', error.message);
process.exit(1);
}This feature validates using the current context and throws an exception if any Switcher Keys are not properly configured.
Load a local copy of your configuration to eliminate latency when local mode is activated:
// Basic snapshot loading
await Client.loadSnapshot();
// Load snapshot and enable auto-watching
await Client.loadSnapshot({ watchSnapshot: true });
// Fetch remote snapshot and enable auto-watching
await Client.loadSnapshot({ watchSnapshot: true, fetchRemote: true });Monitor snapshot changes and implement custom actions:
Client.watchSnapshot({
success: () => console.log('✅ In-memory snapshot updated'),
reject: (err) => console.error('❌ Snapshot update failed:', err)
});Enable snapshot monitoring through client configuration:
Client.buildContext(
{ domain, component, environment },
{
local: true,
snapshotLocation: './snapshot/',
snapshotWatcher: true // 👁️ Enable automatic monitoring
}
);Check if your snapshot is up to date with the remote domain:
try {
const versionInfo = await Client.checkSnapshot();
console.log('Snapshot version info:', versionInfo);
} catch (error) {
console.error('Version check failed:', error);
}💡 Use Case: Perfect for external processes that manage snapshot files independently.
Run the SDK in local mode (zero latency) while keeping snapshots automatically updated:
// Update every 3 seconds
Client.scheduleSnapshotAutoUpdate(3, {
success: (updated) => console.log('Snapshot updated', updated),
reject: (err: Error) => console.log(err)
});Client.buildContext(
{ domain, component, environment },
{
local: true,
snapshotAutoUpdateInterval: 60 // 🕐 Update every 60 seconds
}
);This project's core foundation was built and maintained by a human from day one. However, we have leveraged AI tools to assist in various aspects of the development process, such as troubleshooting, code optimization, and documentation. We have thoroughly reviewed and tested all AI-generated contributions to ensure they meet our quality standards and align with our project's goals. We are committed to transparency about our use of AI and will continue to disclose any significant AI contributions in the future.
External contributions from the community are equally valued and will be reviewed with the same standards, regardless of whether they were assisted by AI or not. We encourage all contributors to disclose their use of AI tools in their contributions to maintain transparency and foster trust within our community.
