UNPKG

better-experiments

Version:
223 lines (218 loc) 7.29 kB
/** * Core types for Better-Experiments A/B testing framework */ interface ABTestConfig { /** Unique identifier for the test */ testId: string; /** Array of variant names/identifiers */ variants: VariantValue[]; /** Weight distribution for variants (optional, defaults to equal distribution) */ weights?: number[]; /** Whether the test is currently active */ active?: boolean; /** Test metadata */ metadata?: { name?: string; description?: string; createdAt?: Date; createdBy?: string; }; } interface UserAssignment { /** Unique identifier for this assignment */ id: string; /** Test identifier */ testId: string; /** User identifier (cookie ID, user ID, etc.) */ userId: string; /** Assigned variant */ variant: VariantValue; /** Timestamp of assignment */ assignedAt: Date; /** Optional metadata for this assignment */ metadata?: Record<string, any>; } interface TestAssignment<T = any> { /** The variant value assigned to the user */ variant: T; /** Full assignment details */ assignment: UserAssignment; /** Method to track conversions for this assignment */ convert(event?: string, metadata?: Record<string, any>): Promise<void>; } interface ConversionEvent { /** Unique identifier for this conversion */ id: string; /** Test identifier */ testId: string; /** User identifier */ userId: string; /** Event name/type */ event: string; /** Assigned variant at time of conversion */ variant: VariantValue; /** Assignment ID that led to this conversion */ assignmentId: string; /** Timestamp of conversion */ convertedAt: Date; /** Optional metadata */ metadata?: Record<string, any>; } interface TestResults { /** Test configuration */ config: ABTestConfig; /** Results per variant */ variants: VariantResults[]; /** Test statistics */ stats: TestStats; } interface VariantResults { /** Variant name */ variant: VariantValue; /** Total users assigned to this variant */ totalUsers: number; /** Total conversions for this variant */ totalConversions: number; /** Conversion rate (conversions / users) */ conversionRate: number; /** Conversion events breakdown */ events: Record<string, number>; } interface TestStats { /** Total test duration in days */ durationDays: number; /** Statistical significance (if calculable) */ significance?: number; /** Confidence interval */ confidenceInterval?: number; /** Whether results are statistically significant */ isSignificant?: boolean; /** Recommended winner variant (if any) */ winner?: VariantValue; } interface StorageAdapter { /** Save test configuration */ saveTest(config: ABTestConfig): Promise<void>; /** Get test configuration */ getTest(testId: string): Promise<ABTestConfig | null>; /** Get all tests */ getAllTests(): Promise<ABTestConfig[]>; /** Save user assignment */ saveAssignment(assignment: UserAssignment): Promise<void>; /** Get user assignment for a test */ getAssignment(testId: string, userId: string): Promise<UserAssignment | null>; /** Get assignment by unique ID */ getAssignmentById(assignmentId: string): Promise<UserAssignment | null>; /** Save conversion event */ saveConversion(event: ConversionEvent): Promise<void>; /** Get all conversions for a test */ getConversions(testId: string): Promise<ConversionEvent[]>; /** Get test results with statistics */ getTestResults(testId: string): Promise<TestResults | null>; } interface BetterExperimentConfig { /** Storage adapter for persisting data */ storage?: StorageAdapter; /** Cookie configuration for browser environments */ cookie?: { name?: string; domain?: string; path?: string; secure?: boolean; sameSite?: "strict" | "lax" | "none"; maxAge?: number; }; /** Debug mode */ debug?: boolean; } type VariantValue = string | number | boolean | object; /** * BetterExperiments client - the main interface for A/B testing */ declare class BetterExperiments { private storage; private debug; private cookieConfig; constructor(config?: BetterExperimentConfig); /** * Run an A/B test - returns assignment object with convert method */ test(testId: string, variants: VariantValue[], options?: { userId?: string; weights?: number[]; metadata?: Partial<ABTestConfig["metadata"]>; }): Promise<TestAssignment<VariantValue>>; /** * Create a new test manually (optional - tests are auto-created) */ createTest(config: Omit<ABTestConfig, "metadata"> & { metadata?: Partial<ABTestConfig["metadata"]>; }): Promise<ABTestConfig>; /** * Get test results and statistics */ getResults(testId: string): Promise<TestResults | null>; /** * Get all tests */ getTests(): Promise<ABTestConfig[]>; /** * Stop/deactivate a test */ stopTest(testId: string): Promise<void>; /** * Get user's assignment for a specific test */ getAssignment(testId: string, userId?: string): Promise<UserAssignment | null>; /** * Track conversion using assignment (internal method) */ private trackConversion; /** * Private methods */ private resolveUserId; private defaultGetUserId; private getCookieUserId; private setCookieUserId; private assignVariant; private generateEqualWeights; private validateTestConfig; } /** * In-memory storage adapter for development and testing * Data is lost when the process restarts */ declare class MemoryStorage implements StorageAdapter { private tests; private assignments; private conversions; saveTest(config: ABTestConfig): Promise<void>; getTest(testId: string): Promise<ABTestConfig | null>; getAllTests(): Promise<ABTestConfig[]>; saveAssignment(assignment: UserAssignment): Promise<void>; getAssignment(testId: string, userId: string): Promise<UserAssignment | null>; getAssignmentById(assignmentId: string): Promise<UserAssignment | null>; saveConversion(event: ConversionEvent): Promise<void>; getConversions(testId: string): Promise<ConversionEvent[]>; getTestResults(testId: string): Promise<TestResults | null>; /** * Utility methods for debugging/testing */ clear(): Promise<void>; getStats(): Promise<{ testsCount: number; assignmentsCount: number; conversionsCount: number; }>; } /** * Create a deterministic numeric hash from a string using MurmurHash3. * This ensures the same user gets the same variant across sessions. * The output is an unsigned 32-bit integer. * @param input The string to hash (e.g., testId + userId). * @returns An unsigned 32-bit integer hash. */ declare function createUserHash(input: string): number; export { BetterExperiments, MemoryStorage, createUserHash }; export type { ABTestConfig, BetterExperimentConfig, ConversionEvent, StorageAdapter, TestResults, TestStats, UserAssignment, VariantResults, VariantValue };