@varia-bly/variably-sdk
v2.3.0
Published
Official JavaScript/TypeScript SDK for Variably feature flags, experimentation, LLM experiments with React hooks, and real-time dynamic configurations
Maintainers
Readme
Variably JavaScript/TypeScript SDK
Official JavaScript/TypeScript SDK for Variably feature flags and experimentation platform.
Installation
npm install @varia-bly/variably-sdk
# or
yarn add @varia-bly/variably-sdkQuick Start
import { VariablyClient } from '@varia-bly/variably-sdk';
// Initialize the client
const client = new VariablyClient({
apiKey: 'your-api-key',
baseUrl: 'https://graphql.variably.tech', // optional, defaults to production GraphQL endpoint
environment: 'production' // optional
});
// Evaluate a boolean feature flag
const userContext = {
userId: 'user-123',
email: '[email protected]',
country: 'US'
};
const isFeatureEnabled = await client.evaluateFlagBool(
'new-checkout-flow',
false, // default value
userContext
);
if (isFeatureEnabled) {
// Show new checkout flow
}
// Evaluate a feature gate
const hasAccess = await client.evaluateGate('premium-features', userContext);
// Track events
await client.track({
name: 'button_clicked',
userId: 'user-123',
properties: {
button_name: 'checkout',
page: 'product-detail'
}
});Configuration
interface VariablyConfig {
/** API key for authentication */
apiKey: string;
/** Base URL for the GraphQL API (default: https://graphql.variably.tech) */
baseUrl?: string;
/** Environment (development, staging, production) */
environment?: string;
/** Request timeout in milliseconds (default: 5000) */
timeout?: number;
/** Number of retry attempts (default: 3) */
retryAttempts?: number;
/** Enable analytics tracking (default: true) */
enableAnalytics?: boolean;
/** Cache configuration */
cache?: {
/** Cache TTL in milliseconds (default: 300000 = 5 minutes) */
ttl?: number;
/** Maximum cache size (default: 1000) */
maxSize?: number;
/** Enable cache (default: true) */
enabled?: boolean;
};
/** Real-time Feature Gate updates via WebSocket */
realTimeUpdates?: {
/** Enable real-time updates (default: false) */
enabled?: boolean;
/** Project ID to subscribe to (required if enabled) */
projectId?: string;
/** Auto-invalidate cache on updates (default: true) */
autoInvalidateCache?: boolean;
};
}Real-Time Feature Gate Updates
NEW: The SDK now supports real-time Feature Gate updates via WebSocket subscriptions. When enabled, your application receives instant notifications when Feature Gates are updated in the Variably UI, and the SDK automatically invalidates its cache to ensure fresh evaluations.
How It Works
UI Update → Backend → Valkey PubSub → GraphQL Subscription → WebSocket → SDK → Cache InvalidationWhen you update a Feature Gate in the Variably UI:
- Backend publishes the update to Valkey
- GraphQL server receives the update and broadcasts to subscribed clients
- SDK receives the WebSocket message
- Cache is automatically invalidated for the updated gate
- Next
evaluateGate()call fetches fresh data
Usage
import { VariablyClient } from '@varia-bly/variably-sdk';
const client = new VariablyClient({
apiKey: 'your-api-key',
baseUrl: 'http://localhost:4000', // or your GraphQL endpoint
// Enable real-time updates
realTimeUpdates: {
enabled: true,
projectId: 'your-project-id', // Required: The project to subscribe to
autoInvalidateCache: true // Optional: Auto-clear cache on updates (default: true)
}
});
// Now when you evaluate a gate, it will automatically receive real-time updates
const hasAccess = await client.evaluateGate('premium-features', userContext);
// When the gate is updated in the UI, the cache is automatically invalidated
// and the next evaluation will fetch fresh dataBenefits
- Instant Updates: Changes in the Variably UI are reflected immediately in your application
- Zero Configuration: Just enable and provide your project ID
- Automatic Cache Invalidation: No manual cache management required
- Graceful Degradation: If WebSocket connection fails, SDK falls back to normal HTTP with caching
- Auto-Reconnection: Built-in reconnection logic with exponential backoff
- Production Ready: Comprehensive error handling and logging
Advanced Usage
import { VariablyClient } from '@varia-bly/variably-sdk';
const client = new VariablyClient({
apiKey: 'your-api-key',
baseUrl: 'http://localhost:4000',
realTimeUpdates: {
enabled: true,
projectId: 'your-project-id',
autoInvalidateCache: true
}
});
// Check if real-time sync is active
if (client.realTimeSync?.isActive()) {
console.log('Real-time updates are active');
console.log('Connection state:', client.realTimeSync.getConnectionState());
}
// Stop real-time updates (e.g., during cleanup)
client.realTimeSync?.stop();Requirements
- GraphQL endpoint must support WebSocket subscriptions
- Project ID must be valid and have Feature Gates configured
- Network must allow WebSocket connections (ws:// or wss://)
LLM Experiments
NEW in v2.2.0: The SDK now includes comprehensive support for LLM experiments with A/B testing, prompt optimization, and React hooks.
import { VariablyLLMClient, useLLMPrompt } from '@varia-bly/variably-sdk';
// Basic LLM experiment
const llmClient = new VariablyLLMClient({
apiKey: 'your-api-key'
});
const response = await llmClient.executePrompt({
experimentId: 'exp_abc123',
userContext: { userId: 'user_123' },
variables: { topic: 'AI' }
});
console.log('Response:', response.content);
console.log('Variant:', response.variant.name);
// React Hook for LLM experiments
function MyComponent() {
const { execute, response, loading } = useLLMPrompt({
experimentId: 'exp_abc123',
apiKey: 'your-api-key'
});
return (
<div>
<button onClick={() => execute({
userContext: { userId: 'user_123' }
})}>
Generate
</button>
{loading && <p>Loading...</p>}
{response && <p>{response.content}</p>}
</div>
);
}📖 Full Documentation: See LLM_EXPERIMENTS.md for comprehensive documentation including:
- React Hooks (
useLLMPrompt,useLLMStreaming,useConversation,useLLMEvaluation) - Streaming responses
- Response evaluation and quality scoring
- Business metrics tracking
- Batch execution
- Advanced features and best practices
Advanced Usage
Environment Variables
You can create a client using environment variables:
import { createClientFromEnv } from '@varia-bly/variably-sdk';
// Uses these environment variables:
// VARIABLY_API_KEY
// VARIABLY_BASE_URL
// VARIABLY_ENVIRONMENT
// VARIABLY_TIMEOUT
// VARIABLY_ENABLE_ANALYTICS
const client = createClientFromEnv();Different Flag Types
// Boolean flags
const boolValue = await client.evaluateFlagBool('feature-enabled', false, userContext);
// String flags
const stringValue = await client.evaluateFlagString('theme', 'light', userContext);
// Number flags
const numberValue = await client.evaluateFlagNumber('max-items', 10, userContext);
// JSON flags
const jsonValue = await client.evaluateFlagJSON('config', { timeout: 5000 }, userContext);
// Get full evaluation details
const result = await client.evaluateFlag('feature-flag', 'default', userContext);
console.log(result); // { key, value, reason, cacheHit, evaluatedAt, error? }Batch Evaluation
const flags = await client.evaluateFlags([
'feature-a',
'feature-b',
'feature-c'
], userContext);
console.log(flags['feature-a'].value);Event Tracking
// Single event
await client.track({
name: 'purchase_completed',
userId: 'user-123',
properties: {
amount: 99.99,
currency: 'USD',
items: ['item-1', 'item-2']
}
});
// Batch events
await client.trackBatch([
{ name: 'page_view', userId: 'user-123', properties: { page: '/home' } },
{ name: 'button_click', userId: 'user-123', properties: { button: 'cta' } }
]);Cache Management
// Clear cache
client.clearCache();
// Get cache stats
const stats = client.cache.getStats();
console.log(stats); // { size, maxSize, hitRate, enabled }Metrics
// Get SDK metrics
const metrics = client.getMetrics();
console.log(metrics);
// {
// apiCalls: number,
// cacheHits: number,
// cacheMisses: number,
// errors: number,
// averageLatency: number,
// cacheHitRate: number,
// errorRate: number,
// flagsEvaluated: number,
// gatesEvaluated: number,
// eventsTracked: number,
// startTime: Date
// }Custom Logger
import { VariablyClient, createLogger } from '@varia-bly/variably-sdk';
const logger = createLogger({
level: 'debug',
type: 'structured' // 'console', 'silent', 'structured'
});
// Or use a custom logging function
const customLogger = createLogger({
level: 'info',
custom: (level, message, meta) => {
// Send to your logging service
console.log(`${level}: ${message}`, meta);
}
});Browser Usage
The SDK works in both Node.js and browser environments:
<script type="module">
import { VariablyClient } from 'https://unpkg.com/@varia-bly/variably-sdk@latest/dist/index.esm.js';
const client = new VariablyClient({
apiKey: 'your-api-key',
baseUrl: 'https://api.variably.com'
});
// Use the client...
</script>Error Handling
import {
VariablyError,
NetworkError,
AuthenticationError,
ValidationError
} from '@varia-bly/variably-sdk';
try {
const result = await client.evaluateFlag('my-flag', false, userContext);
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Invalid API key');
} else if (error instanceof NetworkError) {
console.error('Network error:', error.statusCode);
} else if (error instanceof ValidationError) {
console.error('Validation error:', error.field);
} else {
console.error('Unknown error:', error.message);
}
}TypeScript Support
The SDK is written in TypeScript and includes full type definitions:
import { VariablyClient, UserContext, FlagResult } from '@varia-bly/variably-sdk';
const userContext: UserContext = {
userId: 'user-123',
email: '[email protected]',
attributes: {
plan: 'premium',
signupDate: '2023-01-01'
}
};
const result: FlagResult = await client.evaluateFlag('feature', false, userContext);Development
Building
npm run buildTesting
npm testLinting
npm run lintLicense
MIT License - see LICENSE file for details.
