learning_ai_common_plat/packages/react-native-platform-sdk/src/feature-flags/index.ts
saravanakumardb1 4ca9b73d75 fix(platform): build react-native-platform-sdk + fix admin-web typecheck errors
- react-native-platform-sdk: add tsconfig.json + 13 source files (core, auth, telemetry, feature-flags, kill-switch, broadcasts, surveys)
- react-native-platform-sdk: React hooks + providers wrapping platform-service APIs via fetch
- admin-web: fix ThemeEditor.tsx + themes/active/route.ts lysnrai token type access
- tracker-web: product-context import path fix (pre-existing)
2026-03-12 16:36:13 -07:00

84 lines
2.2 KiB
TypeScript

/**
* Feature Flags module — React context + hook for feature flags in React Native apps.
*/
import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
import type { PlatformSDK } from '../core.js';
export interface FeatureFlag {
key: string;
enabled: boolean;
value?: unknown;
}
interface FeatureFlagContextType {
flags: Map<string, FeatureFlag>;
isEnabled: (key: string) => boolean;
getValue: <T = unknown>(key: string, fallback: T) => T;
refresh: () => Promise<void>;
}
const FeatureFlagContext = createContext<FeatureFlagContextType | null>(null);
export function useFeatureFlags(): FeatureFlagContextType {
const ctx = useContext(FeatureFlagContext);
if (!ctx) throw new Error('useFeatureFlags must be used within a FeatureFlagProvider');
return ctx;
}
interface FeatureFlagProviderProps {
sdk: PlatformSDK;
/** Poll interval in ms (default: 60000) */
pollInterval?: number;
children: React.ReactNode;
}
export function FeatureFlagProvider({
sdk,
pollInterval = 60_000,
children,
}: FeatureFlagProviderProps): React.JSX.Element {
const [flags, setFlags] = useState<Map<string, FeatureFlag>>(new Map());
const refresh = useCallback(async () => {
try {
const res = await sdk.fetch('/api/flags/poll');
if (res.ok) {
const data = (await res.json()) as FeatureFlag[];
const map = new Map<string, FeatureFlag>();
for (const flag of data) {
map.set(flag.key, flag);
}
setFlags(map);
}
} catch {
/* fail-open: keep existing flags */
}
}, [sdk]);
const isEnabled = useCallback(
(key: string): boolean => {
return flags.get(key)?.enabled ?? false;
},
[flags]
);
const getValue = useCallback(
<T = unknown>(key: string, fallback: T): T => {
const flag = flags.get(key);
if (!flag?.enabled) return fallback;
return (flag.value as T) ?? fallback;
},
[flags]
);
useEffect(() => {
refresh();
const id = setInterval(refresh, pollInterval);
return () => clearInterval(id);
}, [refresh, pollInterval]);
const value: FeatureFlagContextType = { flags, isEnabled, getValue, refresh };
return React.createElement(FeatureFlagContext.Provider, { value }, children);
}