UNPKG

@sleekio/sdk

Version:

Modern A/B Testing SDK for JavaScript Applications - Production-ready with graceful fallbacks

370 lines (319 loc) 9.11 kB
/** * Production Usage Examples for Sleek SDK * * This file demonstrates how to safely integrate Sleek SDK in production * environments with proper error handling and fallback mechanisms. */ import { createAnonymousSleek, createAuthenticatedSleek } from "sleek-sdk"; // ===== PRODUCTION CONFIGURATION ===== const PRODUCTION_CONFIG = { // Fast timeouts to prevent blocking user experience requestTimeout: 2000, // 2 seconds max retryAttempts: 1, // Single retry only // Efficient batching batchEvents: true, batchSize: 25, flushInterval: 15000, // 15 seconds // Graceful fallbacks gracefulFallback: true, enableLogging: false, // No console logs in production // Custom headers (if needed for authentication) headers: { "X-Client-Version": "1.0.0", // 'Authorization': 'Bearer your-token' // If API requires auth }, // User management settings userManager: { useLocalStorage: true, useSessionStorage: true, cookieExpireDays: 365, useDeviceFingerprint: false, // Privacy-friendly }, }; // ===== SAFE INITIALIZATION ===== /** * Initialize SDK with error boundaries */ function initializeSleekSDK(apiUrl, userId = null, userProperties = {}) { try { if (userId) { return createAuthenticatedSleek( apiUrl, userId, userProperties, PRODUCTION_CONFIG ); } else { return createAnonymousSleek(apiUrl, PRODUCTION_CONFIG); } } catch (error) { console.error("Failed to initialize Sleek SDK:", error); // Return a mock SDK that always returns 'control' return createMockSleekSDK(); } } /** * Mock SDK for when initialization fails */ function createMockSleekSDK() { return { getVariant: () => Promise.resolve("control"), getVariantConfig: () => Promise.resolve({}), track: () => {}, // No-op trackConversion: () => {}, // No-op isAnonymous: () => true, getUserId: () => "mock_user", cleanup: () => {}, }; } // ===== PRODUCTION USAGE PATTERNS ===== /** * Example 1: E-commerce Product Page */ class ProductPageExperiment { constructor(sleekSDK) { this.sleek = sleekSDK; this.experimentId = "product_page_layout_v2"; } async initialize() { try { // Get variant with timeout protection const variant = await Promise.race([ this.sleek.getVariant(this.experimentId), new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), 1000) ), ]); this.applyVariant(variant); this.trackPageView(); } catch (error) { console.warn("Experiment failed, using default layout:", error.message); this.applyVariant("control"); } } applyVariant(variant) { switch (variant) { case "new_layout": this.enableNewLayout(); break; case "minimal_layout": this.enableMinimalLayout(); break; default: this.enableDefaultLayout(); } } enableNewLayout() { document.body.classList.add("new-product-layout"); } enableMinimalLayout() { document.body.classList.add("minimal-product-layout"); } enableDefaultLayout() { document.body.classList.add("default-product-layout"); } trackPageView() { // Safe tracking with error handling try { this.sleek.track(this.experimentId, "page_view", { page: "product", timestamp: Date.now(), url: window.location.href, }); } catch (error) { // Silently fail - don't break user experience console.warn("Failed to track page view:", error.message); } } trackPurchase(orderValue, currency = "USD") { try { this.sleek.trackConversion(this.experimentId, { value: orderValue, currency, event_type: "purchase", }); } catch (error) { console.warn("Failed to track purchase:", error.message); } } } /** * Example 2: Feature Flag with Gradual Rollout */ class FeatureFlagManager { constructor(sleekSDK) { this.sleek = sleekSDK; this.features = new Map(); } async isFeatureEnabled(featureName, defaultValue = false) { try { // Use experiment ID as feature flag const variant = await this.sleek.getVariant(`feature_${featureName}`); const isEnabled = variant === "enabled"; // Cache result this.features.set(featureName, isEnabled); return isEnabled; } catch (error) { console.warn( `Feature flag check failed for ${featureName}:`, error.message ); return defaultValue; } } async getFeatureConfig(featureName, defaultConfig = {}) { try { const config = await this.sleek.getVariantConfig( `feature_${featureName}` ); return { ...defaultConfig, ...config }; } catch (error) { console.warn(`Feature config failed for ${featureName}:`, error.message); return defaultConfig; } } trackFeatureUsage(featureName, action, properties = {}) { try { this.sleek.track(`feature_${featureName}`, action, { feature: featureName, ...properties, }); } catch (error) { console.warn( `Failed to track feature usage for ${featureName}:`, error.message ); } } } /** * Example 3: React Component with Hooks */ function useExperiment(experimentId, defaultVariant = "control") { const [variant, setVariant] = useState(defaultVariant); const [config, setConfig] = useState({}); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { let mounted = true; async function loadExperiment() { try { setLoading(true); setError(null); // Initialize SDK (you'd pass this from context in real app) const sleek = initializeSleekSDK("https://sleek-api.vercel.app"); const [variantResult, configResult] = await Promise.all([ sleek.getVariant(experimentId), sleek.getVariantConfig(experimentId), ]); if (mounted) { setVariant(variantResult); setConfig(configResult); } } catch (err) { if (mounted) { setError(err.message); setVariant(defaultVariant); // Fallback to default } } finally { if (mounted) { setLoading(false); } } } loadExperiment(); return () => { mounted = false; }; }, [experimentId, defaultVariant]); const track = useCallback( (eventName, properties = {}) => { try { // Get SDK from context in real app const sleek = initializeSleekSDK("https://sleek-api.vercel.app"); sleek.track(experimentId, eventName, properties); } catch (error) { console.warn("Failed to track event:", error.message); } }, [experimentId] ); return { variant, config, loading, error, track }; } // ===== INITIALIZATION EXAMPLES ===== // Example 1: Anonymous user (most common) const sleekAnonymous = initializeSleekSDK("https://sleek-api.vercel.app"); // Example 2: Authenticated user const sleekAuthenticated = initializeSleekSDK( "https://sleek-api.vercel.app", "user_12345", { email: "user@example.com", plan: "premium", signup_date: "2024-01-15", } ); // Example 3: With custom configuration const sleekCustom = createAnonymousSleek("https://sleek-api.vercel.app", { ...PRODUCTION_CONFIG, requestTimeout: 1500, // Even faster timeout batchSize: 50, // Larger batches }); // ===== CLEANUP AND MEMORY MANAGEMENT ===== /** * Proper cleanup when user navigates away or component unmounts */ function cleanupSleekSDK(sleekInstance) { try { // Flush any pending events sleekInstance.flushEvents?.(); // Clean up timers and listeners sleekInstance.cleanup?.(); } catch (error) { console.warn("Error during SDK cleanup:", error.message); } } // Browser: Clean up on page unload if (typeof window !== "undefined") { window.addEventListener("beforeunload", () => { cleanupSleekSDK(sleekAnonymous); }); } // React: Clean up in useEffect // useEffect(() => { // return () => cleanupSleekSDK(sleekInstance); // }, []); // ===== ERROR MONITORING INTEGRATION ===== /** * Integrate with error monitoring services */ function setupErrorMonitoring(sleekInstance) { // Example with Sentry if (typeof Sentry !== "undefined") { const originalTrack = sleekInstance.track; sleekInstance.track = function (experimentId, eventName, properties) { try { return originalTrack.call(this, experimentId, eventName, properties); } catch (error) { Sentry.captureException(error, { tags: { component: "sleek-sdk", experiment_id: experimentId, event_name: eventName, }, }); throw error; } }; } } export { initializeSleekSDK, createMockSleekSDK, ProductPageExperiment, FeatureFlagManager, useExperiment, cleanupSleekSDK, setupErrorMonitoring, PRODUCTION_CONFIG, };