Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | import { configureCache, GrowthBook } from "@growthbook/growthbook";
import { GrowthBookProvider } from "@growthbook/growthbook-react";
import { useAuthContext } from "features/auth/AuthProvider";
import Sentry from "platform/sentry";
import { ReactNode, useEffect } from "react";
import { reportExposure } from "service/experiments";
const INIT_TIMEOUT_MS = 1500;
const REFRESH_INTERVAL_MS = 60 * 1000;
// Within this window, init serves the cached payload without a network fetch.
const CACHE_STALE_TTL_MS = 5 * 60 * 1000;
configureCache({ staleTTL: CACHE_STALE_TTL_MS });
const growthbook = new GrowthBook({
apiHost: process.env.NEXT_PUBLIC_GROWTHBOOK_API_HOST,
clientKey: process.env.NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY,
enableDevMode: process.env.NEXT_PUBLIC_COUCHERS_ENV !== "prod",
trackingCallback: (experiment, result) => {
return reportExposure({
experimentKey: experiment.key,
experimentName: experiment.name ?? "",
variationId: result.variationId,
variationKey: result.key,
variationName: result.name ?? "",
hashAttribute: result.hashAttribute,
hashValue: result.hashValue,
featureId: result.featureId ?? "",
inExperiment: result.inExperiment,
bucket: result.bucket,
hashUsed: result.hashUsed,
stickyBucketUsed: result.stickyBucketUsed,
}).catch((e) => {
Sentry.captureException(e);
});
},
});
export default function FeatureFlagProvider({ children }: { children: ReactNode }) {
const { authState } = useAuthContext();
useEffect(() => {
// Dev-only: when set, flags resolve from feature-flags.dev.json instead of GrowthBook,
// mirroring the backend's FEATURE_FLAGS_FILE_OVERRIDE_PATH. Overridden flags return the file
// value; unknown flags fall through to their in-code default. GrowthBook is never contacted in
// this mode. The inline NODE_ENV check lets webpack compile the whole branch out of production
// builds, keeping the file out of production bundles.
if (process.env.NODE_ENV === "development" && process.env.NEXT_PUBLIC_FEATURE_FLAGS_OVERRIDE === "1") {
void import("feature-flags.dev.json").then((mod) => {
const overrides = mod.default as Record<string, unknown>;
growthbook.initSync({
payload: {
features: Object.fromEntries(
Object.entries(overrides).map(([key, value]) => [key, { defaultValue: value }]),
),
},
});
});
return;
}
void growthbook.init({ timeout: INIT_TIMEOUT_MS });
const id = setInterval(() => void growthbook.refreshFeatures(), REFRESH_INTERVAL_MS);
return () => clearInterval(id);
}, []);
useEffect(() => {
const userId = authState.userId;
growthbook.setAttributes(userId != null ? { id: userId.toString() } : {});
}, [authState.userId]);
return <GrowthBookProvider growthbook={growthbook}>{children}</GrowthBookProvider>;
}
|