featurefly 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ export { FeatureFlagsClient } from './shared/client';
2
+ export { InMemoryCache } from './shared/cache';
3
+ export { ConsoleLogger } from './shared/logger';
4
+ export { CircuitBreaker, CircuitOpenError } from './shared/circuit-breaker';
5
+ export { EventEmitter } from './shared/event-emitter';
6
+ export { withRetry } from './shared/retry';
7
+ export { EdgeEvaluator } from './shared/edge-evaluator';
8
+ export { FlagStreamClient } from './shared/streaming';
9
+ export { evaluateRules, evaluateRule } from './shared/targeting';
10
+ export { isInRollout, getHashBucket } from './shared/rollout';
11
+ export { assignVariation } from './shared/experiment';
12
+ export { ImpactMetrics } from './shared/metrics';
13
+ export type { FeatureFlag, WorkspaceFeatureFlag, FlagValue, FlagValueType, CreateFlagData, UpdateFlagData, SetWorkspaceFlagData, EvaluationContext, EvaluationReason, FeatureFlagEvaluation, BatchEvaluation, FeatureFlagStats, FeatureFlagsConfig, RetryConfig, CircuitBreakerConfig, LogLevel, ILogger, FeatureFlyEvent, EventHandler, EventPayloadMap, FlagEvaluatedPayload, FlagChangedPayload, RequestFailedPayload, CircuitStatePayload, TargetingOperator, TargetingCondition, TargetingRule, RolloutConfig, Variation, Experiment, ExperimentAssignment, TrackingCallback, StreamingConfig, FlagDocument, } from './shared/types';
14
+ export type { MetricsSnapshot, FlagMetric, ExperimentMetric, } from './shared/metrics';
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════════
2
+ // FeatureFly - Framework-Agnostic Feature Flags SDK
3
+ // ═══════════════════════════════════════════════════════════════════════════════
4
+ // Core client
5
+ export { FeatureFlagsClient } from './shared/client';
6
+ // Cache
7
+ export { InMemoryCache } from './shared/cache';
8
+ // Logger
9
+ export { ConsoleLogger } from './shared/logger';
10
+ // Circuit Breaker
11
+ export { CircuitBreaker, CircuitOpenError } from './shared/circuit-breaker';
12
+ // Event Emitter
13
+ export { EventEmitter } from './shared/event-emitter';
14
+ // Retry
15
+ export { withRetry } from './shared/retry';
16
+ // New Advanced Modules
17
+ export { EdgeEvaluator } from './shared/edge-evaluator';
18
+ export { FlagStreamClient } from './shared/streaming';
19
+ export { evaluateRules, evaluateRule } from './shared/targeting';
20
+ export { isInRollout, getHashBucket } from './shared/rollout';
21
+ export { assignVariation } from './shared/experiment';
22
+ export { ImpactMetrics } from './shared/metrics';
@@ -0,0 +1,54 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { FeatureFlagsClient } from '../shared/client';
3
+ import type { EvaluationContext, FlagValue } from '../shared/types';
4
+ /**
5
+ * Provider component that makes the FeatureFlagsClient available to all hooks.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * <FeatureFlyProvider client={client}>
10
+ * <App />
11
+ * </FeatureFlyProvider>
12
+ * ```
13
+ */
14
+ export declare function FeatureFlyProvider({ client, children, }: {
15
+ client: FeatureFlagsClient;
16
+ children: ReactNode;
17
+ }): import("react").FunctionComponentElement<import("react").ProviderProps<FeatureFlagsClient | null>>;
18
+ export interface UseFeatureFlagResult<T> {
19
+ value: T;
20
+ loading: boolean;
21
+ error: Error | null;
22
+ }
23
+ /**
24
+ * React hook for evaluating a single feature flag.
25
+ * Automatically re-evaluates when the flag changes via streaming or cache invalidation.
26
+ *
27
+ * @param slug Flag slug identifier
28
+ * @param defaultValue Default value while loading
29
+ * @param context Optional evaluation context
30
+ *
31
+ * @example
32
+ * ```tsx
33
+ * const { value, loading } = useFeatureFlag('new-checkout', false);
34
+ *
35
+ * if (loading) return <Spinner />;
36
+ * return value ? <NewCheckout /> : <LegacyCheckout />;
37
+ * ```
38
+ */
39
+ export declare function useFeatureFlag<T extends FlagValue = boolean>(slug: string, defaultValue: T, context?: EvaluationContext): UseFeatureFlagResult<T>;
40
+ export interface UseAllFlagsResult {
41
+ flags: Record<string, FlagValue>;
42
+ loading: boolean;
43
+ error: Error | null;
44
+ }
45
+ /**
46
+ * React hook for batch-evaluating all feature flags.
47
+ *
48
+ * @example
49
+ * ```tsx
50
+ * const { flags, loading } = useAllFlags({ workspaceId: 'ws-123' });
51
+ * if (flags['dark-mode']) { ... }
52
+ * ```
53
+ */
54
+ export declare function useAllFlags(context?: EvaluationContext): UseAllFlagsResult;
@@ -0,0 +1,126 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════════
2
+ // FeatureFly — React Hooks
3
+ // ═══════════════════════════════════════════════════════════════════════════════
4
+ //
5
+ // Thin wrapper providing React hooks for FeatureFly SDK.
6
+ // Requires React 18+ (useSyncExternalStore).
7
+ //
8
+ // Usage:
9
+ // import { FeatureFlyProvider, useFeatureFlag, useAllFlags } from 'featurefly/react';
10
+ //
11
+ // ═══════════════════════════════════════════════════════════════════════════════
12
+ import { createContext, useContext, useState, useEffect, useCallback, useMemo, createElement, } from 'react';
13
+ // ─── Context ────────────────────────────────────────────────────────────────────
14
+ const FeatureFlyContext = createContext(null);
15
+ /**
16
+ * Provider component that makes the FeatureFlagsClient available to all hooks.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * <FeatureFlyProvider client={client}>
21
+ * <App />
22
+ * </FeatureFlyProvider>
23
+ * ```
24
+ */
25
+ export function FeatureFlyProvider({ client, children, }) {
26
+ return createElement(FeatureFlyContext.Provider, { value: client }, children);
27
+ }
28
+ function useClient() {
29
+ const client = useContext(FeatureFlyContext);
30
+ if (!client) {
31
+ throw new Error('useFeatureFlag must be used within a <FeatureFlyProvider>. ' +
32
+ 'Wrap your component tree with <FeatureFlyProvider client={client}>.');
33
+ }
34
+ return client;
35
+ }
36
+ /**
37
+ * React hook for evaluating a single feature flag.
38
+ * Automatically re-evaluates when the flag changes via streaming or cache invalidation.
39
+ *
40
+ * @param slug Flag slug identifier
41
+ * @param defaultValue Default value while loading
42
+ * @param context Optional evaluation context
43
+ *
44
+ * @example
45
+ * ```tsx
46
+ * const { value, loading } = useFeatureFlag('new-checkout', false);
47
+ *
48
+ * if (loading) return <Spinner />;
49
+ * return value ? <NewCheckout /> : <LegacyCheckout />;
50
+ * ```
51
+ */
52
+ export function useFeatureFlag(slug, defaultValue, context) {
53
+ const client = useClient();
54
+ const [value, setValue] = useState(defaultValue);
55
+ const [loading, setLoading] = useState(true);
56
+ const [error, setError] = useState(null);
57
+ // Memoize context to avoid infinite re-renders
58
+ const contextKey = useMemo(() => JSON.stringify(context ?? {}), [context?.userId, context?.workspaceId, context?.attributes]);
59
+ const evaluate = useCallback(async () => {
60
+ try {
61
+ setLoading(true);
62
+ const result = await client.evaluateFlag(slug, context);
63
+ setValue(result);
64
+ setError(null);
65
+ }
66
+ catch (e) {
67
+ setError(e instanceof Error ? e : new Error(String(e)));
68
+ }
69
+ finally {
70
+ setLoading(false);
71
+ }
72
+ }, [client, slug, contextKey]);
73
+ // Initial evaluation
74
+ useEffect(() => {
75
+ evaluate();
76
+ }, [evaluate]);
77
+ // Re-evaluate on stream updates or flag changes
78
+ useEffect(() => {
79
+ const unsubs = [];
80
+ unsubs.push(client.on('flagsUpdated', () => evaluate()));
81
+ unsubs.push(client.on('flagChanged', (payload) => {
82
+ if (payload.slug === slug)
83
+ evaluate();
84
+ }));
85
+ return () => unsubs.forEach((u) => u());
86
+ }, [client, slug, evaluate]);
87
+ return { value, loading, error };
88
+ }
89
+ /**
90
+ * React hook for batch-evaluating all feature flags.
91
+ *
92
+ * @example
93
+ * ```tsx
94
+ * const { flags, loading } = useAllFlags({ workspaceId: 'ws-123' });
95
+ * if (flags['dark-mode']) { ... }
96
+ * ```
97
+ */
98
+ export function useAllFlags(context) {
99
+ const client = useClient();
100
+ const [flags, setFlags] = useState({});
101
+ const [loading, setLoading] = useState(true);
102
+ const [error, setError] = useState(null);
103
+ const contextKey = useMemo(() => JSON.stringify(context ?? {}), [context?.userId, context?.workspaceId, context?.attributes]);
104
+ const evaluate = useCallback(async () => {
105
+ try {
106
+ setLoading(true);
107
+ const result = await client.evaluateAllFlags(context);
108
+ setFlags(result);
109
+ setError(null);
110
+ }
111
+ catch (e) {
112
+ setError(e instanceof Error ? e : new Error(String(e)));
113
+ }
114
+ finally {
115
+ setLoading(false);
116
+ }
117
+ }, [client, contextKey]);
118
+ useEffect(() => {
119
+ evaluate();
120
+ }, [evaluate]);
121
+ useEffect(() => {
122
+ const unsub = client.on('flagsUpdated', () => evaluate());
123
+ return () => unsub();
124
+ }, [client, evaluate]);
125
+ return { flags, loading, error };
126
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * In-memory cache with TTL expiration and automatic cleanup.
3
+ *
4
+ * Uses a wrapper object `{ hit: true, value: T }` pattern internally
5
+ * to correctly handle falsy values (false, 0, '', null).
6
+ */
7
+ export declare class InMemoryCache {
8
+ private readonly store;
9
+ private readonly ttlMs;
10
+ private cleanupTimer;
11
+ constructor(ttlMs?: number);
12
+ /**
13
+ * Get a cached value. Returns `{ hit: true, value }` if found and not expired,
14
+ * or `{ hit: false }` otherwise. This avoids ambiguity with falsy values.
15
+ */
16
+ get<T>(key: string): {
17
+ hit: true;
18
+ value: T;
19
+ } | {
20
+ hit: false;
21
+ };
22
+ /**
23
+ * Check if a key exists AND is not expired.
24
+ */
25
+ has(key: string): boolean;
26
+ set<T>(key: string, value: T): void;
27
+ delete(key: string): boolean;
28
+ clear(): void;
29
+ getStats(): {
30
+ size: number;
31
+ keys: string[];
32
+ enabled: boolean;
33
+ };
34
+ /**
35
+ * Release the cleanup timer. Call this when the client is being disposed
36
+ * to prevent memory leaks and dangling timers.
37
+ */
38
+ destroy(): void;
39
+ private cleanup;
40
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * In-memory cache with TTL expiration and automatic cleanup.
3
+ *
4
+ * Uses a wrapper object `{ hit: true, value: T }` pattern internally
5
+ * to correctly handle falsy values (false, 0, '', null).
6
+ */
7
+ export class InMemoryCache {
8
+ constructor(ttlMs = 60000) {
9
+ this.store = new Map();
10
+ this.cleanupTimer = null;
11
+ this.ttlMs = ttlMs;
12
+ if (ttlMs > 0) {
13
+ this.cleanupTimer = setInterval(() => this.cleanup(), Math.max(ttlMs, 30000));
14
+ }
15
+ }
16
+ // ─── Read ────────────────────────────────────────────────────────────────────
17
+ /**
18
+ * Get a cached value. Returns `{ hit: true, value }` if found and not expired,
19
+ * or `{ hit: false }` otherwise. This avoids ambiguity with falsy values.
20
+ */
21
+ get(key) {
22
+ if (this.ttlMs <= 0)
23
+ return { hit: false };
24
+ const entry = this.store.get(key);
25
+ if (!entry)
26
+ return { hit: false };
27
+ if (Date.now() > entry.expiresAt) {
28
+ this.store.delete(key);
29
+ return { hit: false };
30
+ }
31
+ return { hit: true, value: entry.value };
32
+ }
33
+ /**
34
+ * Check if a key exists AND is not expired.
35
+ */
36
+ has(key) {
37
+ return this.get(key).hit;
38
+ }
39
+ // ─── Write ───────────────────────────────────────────────────────────────────
40
+ set(key, value) {
41
+ if (this.ttlMs <= 0)
42
+ return;
43
+ this.store.set(key, { value, expiresAt: Date.now() + this.ttlMs });
44
+ }
45
+ delete(key) {
46
+ return this.store.delete(key);
47
+ }
48
+ clear() {
49
+ this.store.clear();
50
+ }
51
+ // ─── Stats ───────────────────────────────────────────────────────────────────
52
+ getStats() {
53
+ return {
54
+ size: this.store.size,
55
+ keys: Array.from(this.store.keys()),
56
+ enabled: this.ttlMs > 0,
57
+ };
58
+ }
59
+ // ─── Lifecycle ───────────────────────────────────────────────────────────────
60
+ /**
61
+ * Release the cleanup timer. Call this when the client is being disposed
62
+ * to prevent memory leaks and dangling timers.
63
+ */
64
+ destroy() {
65
+ if (this.cleanupTimer) {
66
+ clearInterval(this.cleanupTimer);
67
+ this.cleanupTimer = null;
68
+ }
69
+ this.store.clear();
70
+ }
71
+ // ─── Internal ────────────────────────────────────────────────────────────────
72
+ cleanup() {
73
+ const now = Date.now();
74
+ for (const [key, entry] of this.store.entries()) {
75
+ if (now > entry.expiresAt) {
76
+ this.store.delete(key);
77
+ }
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,46 @@
1
+ import { ILogger } from './types';
2
+ export type CircuitState = 'closed' | 'open' | 'half-open';
3
+ export interface CircuitBreakerOptions {
4
+ failureThreshold: number;
5
+ resetTimeoutMs: number;
6
+ logger: ILogger;
7
+ onStateChange?: (state: CircuitState, failures: number) => void;
8
+ }
9
+ /**
10
+ * Circuit breaker to prevent cascading failures when the feature flag API is down.
11
+ *
12
+ * States:
13
+ * - CLOSED: Requests pass through. Failures increment counter.
14
+ * - OPEN: Requests are rejected immediately. After resetTimeoutMs, transitions to HALF-OPEN.
15
+ * - HALF-OPEN: One probe request is allowed. Success → CLOSED, failure → OPEN.
16
+ */
17
+ export declare class CircuitBreaker {
18
+ private state;
19
+ private failures;
20
+ private lastFailureTime;
21
+ private readonly options;
22
+ constructor(options: CircuitBreakerOptions);
23
+ getState(): CircuitState;
24
+ getFailures(): number;
25
+ /**
26
+ * Execute a function through the circuit breaker.
27
+ * If the circuit is open, throws immediately.
28
+ * If the circuit is half-open, allows one probe request.
29
+ */
30
+ execute<T>(fn: () => Promise<T>): Promise<T>;
31
+ /**
32
+ * Manually reset the circuit to closed state.
33
+ */
34
+ reset(): void;
35
+ private onSuccess;
36
+ private onFailure;
37
+ private shouldAttemptReset;
38
+ private transitionTo;
39
+ }
40
+ /**
41
+ * Error thrown when the circuit breaker is open and rejecting requests.
42
+ */
43
+ export declare class CircuitOpenError extends Error {
44
+ readonly name = "CircuitOpenError";
45
+ constructor(message: string);
46
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Circuit breaker to prevent cascading failures when the feature flag API is down.
3
+ *
4
+ * States:
5
+ * - CLOSED: Requests pass through. Failures increment counter.
6
+ * - OPEN: Requests are rejected immediately. After resetTimeoutMs, transitions to HALF-OPEN.
7
+ * - HALF-OPEN: One probe request is allowed. Success → CLOSED, failure → OPEN.
8
+ */
9
+ export class CircuitBreaker {
10
+ constructor(options) {
11
+ this.state = 'closed';
12
+ this.failures = 0;
13
+ this.lastFailureTime = 0;
14
+ this.options = options;
15
+ }
16
+ getState() {
17
+ return this.state;
18
+ }
19
+ getFailures() {
20
+ return this.failures;
21
+ }
22
+ /**
23
+ * Execute a function through the circuit breaker.
24
+ * If the circuit is open, throws immediately.
25
+ * If the circuit is half-open, allows one probe request.
26
+ */
27
+ async execute(fn) {
28
+ if (this.state === 'open') {
29
+ if (this.shouldAttemptReset()) {
30
+ this.transitionTo('half-open');
31
+ }
32
+ else {
33
+ throw new CircuitOpenError(`Circuit breaker is OPEN. ${this.failures} consecutive failures. ` +
34
+ `Will retry after ${new Date(this.lastFailureTime + this.options.resetTimeoutMs).toISOString()}`);
35
+ }
36
+ }
37
+ try {
38
+ const result = await fn();
39
+ this.onSuccess();
40
+ return result;
41
+ }
42
+ catch (error) {
43
+ this.onFailure();
44
+ throw error;
45
+ }
46
+ }
47
+ /**
48
+ * Manually reset the circuit to closed state.
49
+ */
50
+ reset() {
51
+ this.transitionTo('closed');
52
+ this.failures = 0;
53
+ this.lastFailureTime = 0;
54
+ }
55
+ // ─── Internal ────────────────────────────────────────────────────────────────
56
+ onSuccess() {
57
+ if (this.state === 'half-open' || this.failures > 0) {
58
+ this.failures = 0;
59
+ this.transitionTo('closed');
60
+ }
61
+ }
62
+ onFailure() {
63
+ this.failures++;
64
+ this.lastFailureTime = Date.now();
65
+ if (this.failures >= this.options.failureThreshold) {
66
+ this.transitionTo('open');
67
+ }
68
+ }
69
+ shouldAttemptReset() {
70
+ return Date.now() - this.lastFailureTime >= this.options.resetTimeoutMs;
71
+ }
72
+ transitionTo(newState) {
73
+ if (this.state === newState)
74
+ return;
75
+ const oldState = this.state;
76
+ this.state = newState;
77
+ this.options.logger.info(`Circuit breaker: ${oldState} → ${newState} (failures: ${this.failures})`);
78
+ this.options.onStateChange?.(newState, this.failures);
79
+ }
80
+ }
81
+ /**
82
+ * Error thrown when the circuit breaker is open and rejecting requests.
83
+ */
84
+ export class CircuitOpenError extends Error {
85
+ constructor(message) {
86
+ super(message);
87
+ this.name = 'CircuitOpenError';
88
+ Object.setPrototypeOf(this, CircuitOpenError.prototype);
89
+ }
90
+ }
@@ -0,0 +1,153 @@
1
+ import { FeatureFlag, WorkspaceFeatureFlag, CreateFlagData, UpdateFlagData, FeatureFlagStats, FeatureFlagsConfig, FlagValue, EvaluationContext, FeatureFlyEvent, EventHandler } from './types';
2
+ import { MetricsSnapshot } from './metrics';
3
+ /**
4
+ * FeatureFly SDK Client
5
+ *
6
+ * Framework-agnostic feature flags client with:
7
+ * - In-memory caching with TTL
8
+ * - Retry with exponential backoff + jitter
9
+ * - Circuit breaker for resilience
10
+ * - Typed event system
11
+ * - Local overrides for dev/testing
12
+ * - Fallback defaults for graceful degradation
13
+ * - Multi-type flag values (boolean, string, number, JSON)
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const client = new FeatureFlagsClient({
18
+ * baseUrl: 'https://api.example.com',
19
+ * apiKey: 'your-key',
20
+ * });
21
+ *
22
+ * const isEnabled = await client.evaluateFlag('new-feature', { workspaceId: '123' });
23
+ * ```
24
+ */
25
+ export declare class FeatureFlagsClient {
26
+ private readonly http;
27
+ private readonly cache;
28
+ private readonly circuitBreaker;
29
+ private readonly events;
30
+ private readonly logger;
31
+ private readonly retryConfig;
32
+ private readonly localOverrides;
33
+ private readonly fallbackDefaults;
34
+ private readonly previousValues;
35
+ private streamClient?;
36
+ private edgeEvaluator?;
37
+ private readonly metrics;
38
+ private disposed;
39
+ constructor(config: FeatureFlagsConfig);
40
+ /**
41
+ * Start or resume the SSE streaming connection.
42
+ */
43
+ startStreaming(): void;
44
+ /**
45
+ * Stop the SSE streaming connection.
46
+ */
47
+ stopStreaming(): void;
48
+ /**
49
+ * Fetch a full FlagDocument from the API to initialize Edge Evaluation mode.
50
+ * If streaming is enabled, updates will auto-refresh the document.
51
+ */
52
+ loadEdgeDocument(): Promise<void>;
53
+ private refreshEdgeDocument;
54
+ /**
55
+ * Subscribe to SDK events.
56
+ * @returns Unsubscribe function
57
+ */
58
+ on<E extends FeatureFlyEvent>(event: E, handler: EventHandler<E>): () => void;
59
+ /**
60
+ * Subscribe to an event once.
61
+ */
62
+ once<E extends FeatureFlyEvent>(event: E, handler: EventHandler<E>): () => void;
63
+ /**
64
+ * Evaluate a single flag. Returns the flag value.
65
+ *
66
+ * Resolution order:
67
+ * 1. Local overrides (dev/testing)
68
+ * 2. Cache hit
69
+ * 3. Remote API call
70
+ * 4. Fallback defaults
71
+ */
72
+ evaluateFlag<T extends FlagValue = boolean>(slug: string, context?: EvaluationContext): Promise<T>;
73
+ /**
74
+ * Evaluate all flags in a single batch request.
75
+ */
76
+ evaluateAllFlags(context?: EvaluationContext): Promise<Record<string, FlagValue>>;
77
+ createFlag(data: CreateFlagData): Promise<FeatureFlag>;
78
+ getAllFlags(): Promise<FeatureFlag[]>;
79
+ getFlagById(id: string): Promise<FeatureFlag | null>;
80
+ getFlagBySlug(slug: string): Promise<FeatureFlag | null>;
81
+ updateFlag(id: string, data: UpdateFlagData): Promise<FeatureFlag>;
82
+ deleteFlag(id: string): Promise<void>;
83
+ setWorkspaceFlag(slug: string, workspaceId: string, value: FlagValue): Promise<WorkspaceFeatureFlag>;
84
+ removeWorkspaceFlag(slug: string, workspaceId: string): Promise<void>;
85
+ getWorkspaceFlags(workspaceId: string): Promise<WorkspaceFeatureFlag[]>;
86
+ getFlagStats(): Promise<FeatureFlagStats>;
87
+ getFlagsByCategory(category: 'frontend' | 'backend' | 'both'): Promise<FeatureFlag[]>;
88
+ getFlagsByTargetService(serviceName: string): Promise<FeatureFlag[]>;
89
+ /**
90
+ * Set a local override for a flag. Overrides skip HTTP entirely.
91
+ * Useful for development and testing.
92
+ */
93
+ setLocalOverride(slug: string, value: FlagValue): void;
94
+ /**
95
+ * Remove a local override.
96
+ */
97
+ removeLocalOverride(slug: string): void;
98
+ /**
99
+ * Get all local overrides.
100
+ */
101
+ getLocalOverrides(): Record<string, FlagValue>;
102
+ /**
103
+ * Clear all local overrides.
104
+ */
105
+ clearLocalOverrides(): void;
106
+ /**
107
+ * Clear all cached data.
108
+ */
109
+ clearCache(): void;
110
+ /**
111
+ * Get cache statistics.
112
+ */
113
+ getCacheStats(): {
114
+ size: number;
115
+ keys: string[];
116
+ enabled: boolean;
117
+ };
118
+ /**
119
+ * Get current circuit breaker state.
120
+ */
121
+ getCircuitBreakerState(): {
122
+ state: string;
123
+ failures: number;
124
+ };
125
+ /**
126
+ * Reset the circuit breaker to closed state.
127
+ */
128
+ resetCircuitBreaker(): void;
129
+ /**
130
+ * Check if the client has been disposed.
131
+ */
132
+ isDisposed(): boolean;
133
+ /**
134
+ * Get a snapshot of all collected impact metrics.
135
+ * Includes per-flag evaluation counts, cache hit rates, latency percentiles,
136
+ * and experiment exposure counts.
137
+ */
138
+ getImpactMetrics(): MetricsSnapshot;
139
+ /**
140
+ * Reset all collected impact metrics counters.
141
+ */
142
+ resetMetrics(): void;
143
+ /**
144
+ * Dispose the client, releasing all resources (timers, listeners, metrics).
145
+ * After calling dispose, the client cannot be used again.
146
+ */
147
+ dispose(): void;
148
+ private fetchWithResiliency;
149
+ private buildCacheKey;
150
+ private detectChange;
151
+ private emitEvaluated;
152
+ private assertNotDisposed;
153
+ }