@toggle.tiger/toggletiger
Version:
A package to retrieve configuration from blobstore based on org, app, env, and config ID.
101 lines (100 loc) • 4.43 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { jsx as _jsx } from "react/jsx-runtime";
import axios from "axios";
import { createContext, useEffect, useRef, useState } from "react";
const initialState = {
environmentFlags: null
};
export const FeatureFlagContext = createContext(initialState);
export const FeatureFlagProvider = ({ children, sdkKey, baseUrl = "http://127.0.0.1:10000/devstoreaccount1/configurations", pollingInterval }) => {
const [environmentFlags, setEnvironmentFlags] = useState(null);
const isLoadingRef = useRef(false);
const loadConfig = () => __awaiter(void 0, void 0, void 0, function* () {
if (isLoadingRef.current) {
return;
}
isLoadingRef.current = true;
try {
const etagKey = `toggletiger_etag_${sdkKey}`;
const lastModifiedKey = `toggletiger_lastmod_${sdkKey}`;
const flagsKey = `toggletiger_flags_${sdkKey}`;
const cachedETag = localStorage.getItem(etagKey);
const cachedLastModified = localStorage.getItem(lastModifiedKey);
const cachedFlagsJson = localStorage.getItem(flagsKey);
let cachedFlags = null;
if (cachedFlagsJson) {
try {
cachedFlags = JSON.parse(cachedFlagsJson);
if (cachedFlags) {
setEnvironmentFlags(cachedFlags);
}
}
catch (_a) {
// Ignore parsing errors
}
}
const configUrl = `${baseUrl}/${sdkKey}`;
const headers = {};
if (cachedETag) {
headers["If-None-Match"] = cachedETag;
}
if (cachedLastModified) {
headers["If-Modified-Since"] = cachedLastModified;
}
const response = yield axios.get(configUrl, {
headers,
validateStatus: (status) => status === 200 || status === 304
});
if (response.status === 304) {
return;
}
if (response.status === 200) {
const newETag = response.headers.etag || response.headers.ETag;
const newLastModified = response.headers["last-modified"] ||
response.headers["Last-Modified"];
if (newETag) {
localStorage.setItem(etagKey, newETag);
}
if (newLastModified) {
localStorage.setItem(lastModifiedKey, newLastModified);
}
const config = response.data;
if (config) {
setEnvironmentFlags(config.environmentFlags);
localStorage.setItem(flagsKey, JSON.stringify(config.environmentFlags));
}
}
}
catch (error) {
if (axios.isAxiosError(error) && error.response) {
const status = error.response.status;
if (status === 304 || status === 412) {
return;
}
}
setEnvironmentFlags(null);
}
finally {
isLoadingRef.current = false;
}
});
// biome-ignore lint/correctness/useExhaustiveDependencies: sdkKey and baseUrl are stable props
useEffect(() => {
loadConfig();
if (pollingInterval && pollingInterval > 0) {
const intervalId = setInterval(() => {
loadConfig();
}, pollingInterval);
return () => clearInterval(intervalId);
}
}, [sdkKey, baseUrl, pollingInterval]);
return (_jsx(FeatureFlagContext.Provider, { value: { environmentFlags }, children: children }));
};