@scalemule/nextjs 0.0.15 → 0.0.17

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.
package/dist/index.js CHANGED
@@ -2856,6 +2856,15 @@ function useFeatureFlags(options = {}) {
2856
2856
  enabled = true
2857
2857
  } = options;
2858
2858
  const { client, publishableKey, gatewayUrl, bootstrapFlags } = smContext;
2859
+ const warnedRef = react.useRef(false);
2860
+ react.useEffect(() => {
2861
+ if (!warnedRef.current && (!keys || keys.length === 0)) {
2862
+ warnedRef.current = true;
2863
+ console.warn(
2864
+ 'useFeatureFlags: "keys" option should be provided. Calling /evaluate/all without explicit keys is deprecated and will be blocked in a future release. Pass keys: ["flag1", "flag2"].'
2865
+ );
2866
+ }
2867
+ }, [keys]);
2859
2868
  const initialFlags = react.useMemo(() => {
2860
2869
  if (!bootstrapFlags) return {};
2861
2870
  const result = {};
@@ -2871,10 +2880,14 @@ function useFeatureFlags(options = {}) {
2871
2880
  const [loading, setLoading] = react.useState(enabled && !hasBootstrap);
2872
2881
  const [error, setError] = react.useState(null);
2873
2882
  const contextRef = react.useRef(context);
2883
+ const keysRef = react.useRef(keys);
2874
2884
  const keysKey = react.useMemo(() => keys && keys.length > 0 ? [...keys].sort().join("|") : "", [keys]);
2875
2885
  react.useEffect(() => {
2876
2886
  contextRef.current = context;
2877
2887
  }, [context]);
2888
+ react.useEffect(() => {
2889
+ keysRef.current = keys;
2890
+ }, [keys]);
2878
2891
  const refresh = react.useCallback(async () => {
2879
2892
  if (!enabled) {
2880
2893
  setLoading(false);
@@ -2882,8 +2895,9 @@ function useFeatureFlags(options = {}) {
2882
2895
  }
2883
2896
  setLoading(true);
2884
2897
  try {
2885
- const payload = keys && keys.length > 0 ? { flag_keys: keys, environment, context: contextRef.current } : { environment, context: contextRef.current };
2886
- const endpoint = keys && keys.length > 0 ? "/v1/flags/evaluate/batch" : "/v1/flags/evaluate/all";
2898
+ const currentKeys = keysRef.current;
2899
+ const payload = currentKeys && currentKeys.length > 0 ? { flag_keys: currentKeys, environment, context: contextRef.current } : { environment, context: contextRef.current };
2900
+ const endpoint = currentKeys && currentKeys.length > 0 ? "/v1/flags/evaluate/batch" : "/v1/flags/evaluate/all";
2887
2901
  let result;
2888
2902
  if (publishableKey && gatewayUrl) {
2889
2903
  const response = await fetch(`${gatewayUrl}${endpoint}`, {
@@ -2909,7 +2923,7 @@ function useFeatureFlags(options = {}) {
2909
2923
  } finally {
2910
2924
  setLoading(false);
2911
2925
  }
2912
- }, [client, enabled, environment, keys, keysKey, publishableKey, gatewayUrl]);
2926
+ }, [client, enabled, environment, keysKey, publishableKey, gatewayUrl]);
2913
2927
  const bootstrapCoversKeys = react.useMemo(() => {
2914
2928
  if (!hasBootstrap || !keys || keys.length === 0) return false;
2915
2929
  if (!keys.every((k) => k in initialFlags)) return false;
package/dist/index.mjs CHANGED
@@ -2854,6 +2854,15 @@ function useFeatureFlags(options = {}) {
2854
2854
  enabled = true
2855
2855
  } = options;
2856
2856
  const { client, publishableKey, gatewayUrl, bootstrapFlags } = smContext;
2857
+ const warnedRef = useRef(false);
2858
+ useEffect(() => {
2859
+ if (!warnedRef.current && (!keys || keys.length === 0)) {
2860
+ warnedRef.current = true;
2861
+ console.warn(
2862
+ 'useFeatureFlags: "keys" option should be provided. Calling /evaluate/all without explicit keys is deprecated and will be blocked in a future release. Pass keys: ["flag1", "flag2"].'
2863
+ );
2864
+ }
2865
+ }, [keys]);
2857
2866
  const initialFlags = useMemo(() => {
2858
2867
  if (!bootstrapFlags) return {};
2859
2868
  const result = {};
@@ -2869,10 +2878,14 @@ function useFeatureFlags(options = {}) {
2869
2878
  const [loading, setLoading] = useState(enabled && !hasBootstrap);
2870
2879
  const [error, setError] = useState(null);
2871
2880
  const contextRef = useRef(context);
2881
+ const keysRef = useRef(keys);
2872
2882
  const keysKey = useMemo(() => keys && keys.length > 0 ? [...keys].sort().join("|") : "", [keys]);
2873
2883
  useEffect(() => {
2874
2884
  contextRef.current = context;
2875
2885
  }, [context]);
2886
+ useEffect(() => {
2887
+ keysRef.current = keys;
2888
+ }, [keys]);
2876
2889
  const refresh = useCallback(async () => {
2877
2890
  if (!enabled) {
2878
2891
  setLoading(false);
@@ -2880,8 +2893,9 @@ function useFeatureFlags(options = {}) {
2880
2893
  }
2881
2894
  setLoading(true);
2882
2895
  try {
2883
- const payload = keys && keys.length > 0 ? { flag_keys: keys, environment, context: contextRef.current } : { environment, context: contextRef.current };
2884
- const endpoint = keys && keys.length > 0 ? "/v1/flags/evaluate/batch" : "/v1/flags/evaluate/all";
2896
+ const currentKeys = keysRef.current;
2897
+ const payload = currentKeys && currentKeys.length > 0 ? { flag_keys: currentKeys, environment, context: contextRef.current } : { environment, context: contextRef.current };
2898
+ const endpoint = currentKeys && currentKeys.length > 0 ? "/v1/flags/evaluate/batch" : "/v1/flags/evaluate/all";
2885
2899
  let result;
2886
2900
  if (publishableKey && gatewayUrl) {
2887
2901
  const response = await fetch(`${gatewayUrl}${endpoint}`, {
@@ -2907,7 +2921,7 @@ function useFeatureFlags(options = {}) {
2907
2921
  } finally {
2908
2922
  setLoading(false);
2909
2923
  }
2910
- }, [client, enabled, environment, keys, keysKey, publishableKey, gatewayUrl]);
2924
+ }, [client, enabled, environment, keysKey, publishableKey, gatewayUrl]);
2911
2925
  const bootstrapCoversKeys = useMemo(() => {
2912
2926
  if (!hasBootstrap || !keys || keys.length === 0) return false;
2913
2927
  if (!keys.every((k) => k in initialFlags)) return false;
@@ -1794,7 +1794,12 @@ async function getFlagClient(environment) {
1794
1794
  if (pending) return pending;
1795
1795
  const promise = (async () => {
1796
1796
  const client = new server$1.FlagClient({ apiKey, environment, gatewayUrl });
1797
- await client.init();
1797
+ await Promise.race([
1798
+ client.init(),
1799
+ new Promise(
1800
+ (_, reject) => setTimeout(() => reject(new Error("FlagClient init timeout")), 3e3)
1801
+ )
1802
+ ]);
1798
1803
  _clients.set(key, client);
1799
1804
  return client;
1800
1805
  })();
@@ -1792,7 +1792,12 @@ async function getFlagClient(environment) {
1792
1792
  if (pending) return pending;
1793
1793
  const promise = (async () => {
1794
1794
  const client = new FlagClient({ apiKey, environment, gatewayUrl });
1795
- await client.init();
1795
+ await Promise.race([
1796
+ client.init(),
1797
+ new Promise(
1798
+ (_, reject) => setTimeout(() => reject(new Error("FlagClient init timeout")), 3e3)
1799
+ )
1800
+ ]);
1796
1801
  _clients.set(key, client);
1797
1802
  return client;
1798
1803
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalemule/nextjs",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "ScaleMule SDK for Next.js applications - authentication, storage, and user management",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -48,11 +48,11 @@
48
48
  "test": "vitest run",
49
49
  "test:watch": "vitest",
50
50
  "type-check": "tsc --noEmit",
51
- "lint": "eslint src --ext .ts,.tsx",
51
+ "lint": "tsc --noEmit",
52
52
  "clean": "rm -rf dist"
53
53
  },
54
54
  "dependencies": {
55
- "@scalemule/sdk": "^0.0.14"
55
+ "@scalemule/sdk": "^0.0.16"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "next": ">=14.0.0",