better-auth-feature-flags
Version:
Ship features safely with feature flags, A/B testing, and progressive rollouts - Better Auth plugin for modern release management
197 lines (194 loc) • 8.18 kB
TypeScript
import * as react_jsx_runtime from 'react/jsx-runtime';
import { createAuthClient } from 'better-auth/client';
import React, { ReactNode, ComponentType } from 'react';
import { FeatureFlagsClient } from './client.js';
import { E as EvaluationContext } from './types-_f512wNn.js';
import 'better-call';
import 'better-auth';
import 'zod';
type BetterAuthClient = ReturnType<typeof createAuthClient>;
interface FeatureFlagsProviderProps {
client: BetterAuthClient & FeatureFlagsClient;
children: ReactNode;
/** Pre-populated flags for SSR, prevents content flash */
initialFlags?: Record<string, any>;
/** Fetch flags on mount (disable for SSR) */
fetchOnMount?: boolean;
/** Evaluation context, changes trigger cache invalidation */
context?: Partial<EvaluationContext>;
}
interface FeatureProps {
/** Flag key to evaluate */
flag: string;
/** Fallback content when flag disabled/missing */
fallback?: ReactNode;
/** Secondary validation (e.g., subscription tier) */
validateAccess?: (flags: Record<string, any>) => boolean;
/** Content when flag enabled and validation passes */
children: ReactNode;
}
interface VariantProps {
/** Flag key for variant evaluation */
flag: string;
/** Variant.Case and Variant.Default components */
children: ReactNode;
}
interface VariantCaseProps {
/** Variant key to match */
variant: string;
/** Content for this variant */
children: ReactNode;
}
interface VariantDefaultProps {
/** Default content when no variant matches */
children: ReactNode;
}
interface FeatureFlagErrorBoundaryProps {
/** Fallback component or element for errors */
fallback: ReactNode | ComponentType<{
error: Error;
}>;
/** Error callback for monitoring/logging */
onError?: (error: Error) => void;
/** Protected children components */
children: ReactNode;
}
declare function FeatureFlagsProvider({ client, children, initialFlags, fetchOnMount, context: additionalContext, }: FeatureFlagsProviderProps): react_jsx_runtime.JSX.Element;
/**
* Hook for boolean flag evaluation.
* @param flag Flag key to evaluate
* @param defaultValue Fallback for missing/errored flags
*/
declare function useFeatureFlag(flag: string, defaultValue?: boolean): boolean;
/**
* Hook for typed flag values (string, number, object).
* @param flag Flag key to evaluate
* @param defaultValue Type-safe fallback value
*/
declare function useFeatureFlagValue<T = any>(flag: string, defaultValue?: T): T;
/** Hook returning all cached feature flags */
declare function useFeatureFlags(): Record<string, any>;
/** Hook for A/B test variant evaluation */
declare function useVariant(flag: string): string | null;
/** Hook for flag event tracking */
declare function useTrackEvent(): (flag: string, event: string, value?: number | Record<string, any>) => Promise<{
success: boolean;
eventId: string;
sampled?: boolean;
}>;
/** Hook for flag loading state and error handling */
declare function useFeatureFlagsState(): {
loading: boolean;
error: Error | null;
refresh: () => Promise<void>;
};
/** Debug hook for cache monitoring, not for production UI */
declare function useFeatureFlagsCacheInfo(): {
cacheEnabled: boolean;
sessionId?: string;
flagCount: number;
};
/** Suspense-compatible flag evaluation - throws promise during loading */
declare function useFeatureFlagSuspense(flag: string, defaultValue?: boolean): boolean;
/** Suspense-compatible typed flag values */
declare function useFeatureFlagValueSuspense<T = any>(flag: string, defaultValue?: T): T;
/** Suspense-compatible all flags hook */
declare function useFeatureFlagsSuspense(): Record<string, any>;
/**
* Enhanced hook for flag event tracking with idempotency support
* @example
* const trackEvent = useTrackEventWithIdempotency();
* await trackEvent('feature', 'purchase', { amount: 99.99 }, { idempotencyKey: 'order-123' });
*/
declare function useTrackEventWithIdempotency(): (flag: string, event: string, value?: number | Record<string, any>, options?: {
idempotencyKey?: string;
}) => Promise<{
success: boolean;
eventId: string;
sampled?: boolean;
}>;
/**
* Hook for batch event tracking - more efficient for multiple events
* @example
* const trackBatch = useTrackEventBatch();
* await trackBatch([
* { flag: 'feature1', event: 'view', idempotencyKey: 'session-123-1' },
* { flag: 'feature2', event: 'click', data: { button: 'cta' } }
* ]);
*/
declare function useTrackEventBatch(): (events: Array<{
flag: string;
event: string;
data?: number | Record<string, any>;
timestamp?: Date;
idempotencyKey?: string;
}>, batchId?: string) => Promise<{
success: number;
failed: number;
sampled?: number;
batchId: string;
}>;
/**
* Declarative feature gating component.
* @example
* <Feature flag="new-dashboard" fallback={<OldDashboard />}>
* <NewDashboard />
* </Feature>
*/
declare function Feature({ flag, fallback, validateAccess, children, }: FeatureProps): react_jsx_runtime.JSX.Element;
/**
* A/B test variant component.
* @example
* <Variant flag="checkout-flow">
* <Variant.Case variant="v1"><CheckoutV1 /></Variant.Case>
* <Variant.Case variant="v2"><CheckoutV2 /></Variant.Case>
* <Variant.Default><CheckoutOriginal /></Variant.Default>
* </Variant>
*/
declare const Variant: React.NamedExoticComponent<VariantProps>;
/**
* Suspense-compatible feature gating component.
* Requires <Suspense> boundary to handle loading states.
* @example
* <Suspense fallback={<Loading />}>
* <FeatureSuspense flag="new-dashboard" fallback={<OldDashboard />}>
* <NewDashboard />
* </FeatureSuspense>
* </Suspense>
*/
declare function FeatureSuspense({ flag, fallback, validateAccess, children, }: FeatureProps): react_jsx_runtime.JSX.Element;
/**
* Suspense-compatible variant component.
* Requires <Suspense> boundary to handle loading states.
* @example
* <Suspense fallback={<Loading />}>
* <VariantSuspense flag="checkout-flow">
* <Variant.Case variant="v1"><CheckoutV1 /></Variant.Case>
* <Variant.Case variant="v2"><CheckoutV2 /></Variant.Case>
* <Variant.Default><CheckoutOriginal /></Variant.Default>
* </VariantSuspense>
* </Suspense>
*/
declare const VariantSuspense: React.NamedExoticComponent<VariantProps>;
interface ErrorBoundaryState {
hasError: boolean;
error: Error | null;
}
/** Error boundary for flag evaluation, prevents app crashes */
declare class FeatureFlagErrorBoundary extends React.Component<FeatureFlagErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: FeatureFlagErrorBoundaryProps);
static getDerivedStateFromError(error: Error): ErrorBoundaryState;
componentDidCatch(error: Error): void;
render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
}
/** HOC for class components, prefer hooks for new code */
declare function withFeatureFlags<P extends object>(Component: ComponentType<P & {
featureFlags: Record<string, any>;
}>): ComponentType<P>;
/**
* HOC for component-level feature gating.
* @example
* export default withFeatureFlag('beta-ui', LegacyComponent)(BetaComponent);
*/
declare function withFeatureFlag<P extends object>(flag: string, fallback?: ComponentType<P>): (Component: ComponentType<P>) => ComponentType<P>;
export { Feature, FeatureFlagErrorBoundary, type FeatureFlagErrorBoundaryProps, FeatureFlagsProvider, type FeatureFlagsProviderProps, type FeatureProps, FeatureSuspense, Variant, type VariantCaseProps, type VariantDefaultProps, type VariantProps, VariantSuspense, useFeatureFlag, useFeatureFlagSuspense, useFeatureFlagValue, useFeatureFlagValueSuspense, useFeatureFlags, useFeatureFlagsCacheInfo, useFeatureFlagsState, useFeatureFlagsSuspense, useTrackEvent, useTrackEventBatch, useTrackEventWithIdempotency, useVariant, withFeatureFlag, withFeatureFlags };