@myflags/react
Version:
React bindings for MyFlags feature flag management
169 lines (164 loc) • 5.08 kB
JavaScript
// src/Provider.tsx
import { createContext, useContext, useEffect as useEffect2, useState as useState2 } from "react";
import { MyFlagsSDK } from "@myflags/core";
// src/hooks/useIndexedDB.ts
import { useState, useCallback, useEffect, useRef } from "react";
var DB_NAME = "myflags";
var DB_VERSION = 1;
var STORE_NAME = "flags";
function useIndexedDB(key, initialValue) {
const [storedValue, setStoredValue] = useState(initialValue);
const [isDbReady, setIsDbReady] = useState(false);
const pendingWrites = useRef([]);
const openDB = useCallback(() => {
return new Promise((resolve, reject) => {
if (typeof window === "undefined" || !window.indexedDB) {
reject("IndexedDB not supported");
return;
}
const request = window.indexedDB.open(DB_NAME, DB_VERSION);
request.onerror = () => {
reject("Error opening IndexedDB");
};
request.onsuccess = (event) => {
const db = event.target.result;
resolve(db);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(STORE_NAME)) {
db.createObjectStore(STORE_NAME, { keyPath: "id" });
}
};
});
}, []);
const getValueFromDB = useCallback(async () => {
if (typeof window === "undefined" || !window.indexedDB) {
return initialValue;
}
try {
const db = await openDB();
return new Promise((resolve) => {
const transaction = db.transaction(STORE_NAME, "readonly");
const store = transaction.objectStore(STORE_NAME);
const request = store.get(key);
request.onerror = () => {
resolve(initialValue);
};
request.onsuccess = () => {
const result = request.result;
db.close();
if (result) {
resolve(result.value);
} else {
resolve(initialValue);
}
};
});
} catch {
return initialValue;
}
}, [key, initialValue, openDB]);
const setValueInDB = useCallback(
async (valueToStore) => {
if (typeof window === "undefined" || !window.indexedDB) {
console.warn("[MyFlags] IndexedDB not supported in this environment");
return;
}
try {
const db = await openDB();
const transaction = db.transaction(STORE_NAME, "readwrite");
const store = transaction.objectStore(STORE_NAME);
store.put({ id: key, value: valueToStore });
transaction.oncomplete = () => {
db.close();
};
transaction.onerror = () => {
db.close();
};
} catch (error) {
console.error("[MyFlags] Error in setValueInDB:", error);
}
},
[key, openDB]
);
useEffect(() => {
const initializeDB = async () => {
try {
const value = await getValueFromDB();
setStoredValue(value);
setIsDbReady(true);
if (pendingWrites.current.length > 0) {
for (const value2 of pendingWrites.current) {
await setValueInDB(value2);
}
pendingWrites.current = [];
}
} catch {
setIsDbReady(true);
}
};
initializeDB();
}, [getValueFromDB, setValueInDB]);
const setValue = useCallback(
(value) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
if (isDbReady) {
setValueInDB(valueToStore);
} else {
pendingWrites.current.push(valueToStore);
}
} catch (error) {
console.error("[MyFlags] Error in setValue:", error);
}
},
[storedValue, isDbReady, setValueInDB]
);
return [storedValue, setValue];
}
// src/Provider.tsx
import { jsx } from "react/jsx-runtime";
var MyFlagsContext = createContext(null);
function MyFlagsProvider(props) {
const [flags, setFlags] = useIndexedDB("flags", {});
const [client] = useState2(() => new MyFlagsSDK(props.config));
useEffect2(() => {
const unsubscribe = client.subscribe(setFlags);
return () => unsubscribe();
}, [client]);
return /* @__PURE__ */ jsx(MyFlagsContext.Provider, { value: flags, children: props.children });
}
function useMyFlagsContext() {
const context = useContext(MyFlagsContext);
if (!context) throw new Error("MyFlagsContext not found");
return context;
}
// src/hooks/useFlag.ts
function useFlag(name, defaultValue = false) {
const context = useMyFlagsContext();
return context[name] || defaultValue;
}
// src/components/FeatureFlag.tsx
import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
var FeatureFlag = ({
name,
children,
defaultValue = false
}) => {
const isEnabled = useFlag(name, defaultValue);
return /* @__PURE__ */ jsx2(Fragment, { children: children(isEnabled) });
};
// src/hooks/useFlags.ts
function useFlags() {
const context = useMyFlagsContext();
return context;
}
export {
FeatureFlag,
MyFlagsProvider,
useFlag,
useFlags
};
//# sourceMappingURL=index.js.map