@scalemule/nextjs 0.0.12 → 0.0.13
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 +8 -2
- package/dist/index.mjs +8 -2
- package/dist/server/index.d.mts +10 -1
- package/dist/server/index.d.ts +10 -1
- package/dist/server/index.js +27 -6
- package/dist/server/index.mjs +27 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2908,9 +2908,15 @@ function useFeatureFlags(options = {}) {
|
|
|
2908
2908
|
setLoading(false);
|
|
2909
2909
|
}
|
|
2910
2910
|
}, [client, enabled, environment, keys, keysKey, publishableKey, gatewayUrl]);
|
|
2911
|
+
const bootstrapCoversKeys = react.useMemo(() => {
|
|
2912
|
+
if (!hasBootstrap || !keys || keys.length === 0) return false;
|
|
2913
|
+
return keys.every((k) => k in initialFlags);
|
|
2914
|
+
}, [hasBootstrap, keys, initialFlags]);
|
|
2911
2915
|
react.useEffect(() => {
|
|
2912
|
-
|
|
2913
|
-
|
|
2916
|
+
if (!bootstrapCoversKeys) {
|
|
2917
|
+
void refresh();
|
|
2918
|
+
}
|
|
2919
|
+
}, [refresh, bootstrapCoversKeys]);
|
|
2914
2920
|
const isEnabled = react.useCallback(
|
|
2915
2921
|
(flagKey, fallback = false) => {
|
|
2916
2922
|
const evaluation = flags[flagKey];
|
package/dist/index.mjs
CHANGED
|
@@ -2906,9 +2906,15 @@ function useFeatureFlags(options = {}) {
|
|
|
2906
2906
|
setLoading(false);
|
|
2907
2907
|
}
|
|
2908
2908
|
}, [client, enabled, environment, keys, keysKey, publishableKey, gatewayUrl]);
|
|
2909
|
+
const bootstrapCoversKeys = useMemo(() => {
|
|
2910
|
+
if (!hasBootstrap || !keys || keys.length === 0) return false;
|
|
2911
|
+
return keys.every((k) => k in initialFlags);
|
|
2912
|
+
}, [hasBootstrap, keys, initialFlags]);
|
|
2909
2913
|
useEffect(() => {
|
|
2910
|
-
|
|
2911
|
-
|
|
2914
|
+
if (!bootstrapCoversKeys) {
|
|
2915
|
+
void refresh();
|
|
2916
|
+
}
|
|
2917
|
+
}, [refresh, bootstrapCoversKeys]);
|
|
2912
2918
|
const isEnabled = useCallback(
|
|
2913
2919
|
(flagKey, fallback = false) => {
|
|
2914
2920
|
const evaluation = flags[flagKey];
|
package/dist/server/index.d.mts
CHANGED
|
@@ -439,6 +439,11 @@ declare function apiHandler(handler: HandlerFn, options?: HandlerOptions): (requ
|
|
|
439
439
|
* Evaluates feature flags on the server during SSR so the client
|
|
440
440
|
* has correct values on first render -- no loading flash, no race condition.
|
|
441
441
|
*
|
|
442
|
+
* Results are cached in-memory with a configurable TTL (default: 60s) to
|
|
443
|
+
* prevent excessive API calls. Since feature flags change infrequently,
|
|
444
|
+
* a short cache window is fine and avoids hammering the flags service on
|
|
445
|
+
* every page render.
|
|
446
|
+
*
|
|
442
447
|
* @example
|
|
443
448
|
* ```ts
|
|
444
449
|
* // app/layout.tsx
|
|
@@ -461,14 +466,18 @@ declare function apiHandler(handler: HandlerFn, options?: HandlerOptions): (requ
|
|
|
461
466
|
* and passes it as ip_address in the evaluation context so IP-based targeting
|
|
462
467
|
* rules work correctly.
|
|
463
468
|
*
|
|
469
|
+
* Results are cached in-memory for `cacheTtlMs` milliseconds (default: 60s).
|
|
470
|
+
* Pass `cacheTtlMs: 0` to disable caching.
|
|
471
|
+
*
|
|
464
472
|
* Returns a Record that can be passed directly to ScaleMuleProvider's
|
|
465
473
|
* bootstrapFlags prop.
|
|
466
474
|
*
|
|
467
475
|
* @param flagKeys - Array of flag keys to evaluate
|
|
468
476
|
* @param environment - Environment name (default: 'prod')
|
|
469
477
|
* @param extraContext - Additional context attributes to include
|
|
478
|
+
* @param cacheTtlMs - Cache TTL in milliseconds (default: 60000). Set to 0 to disable.
|
|
470
479
|
*/
|
|
471
|
-
declare function getBootstrapFlags(flagKeys: string[], environment?: string, extraContext?: Record<string, unknown
|
|
480
|
+
declare function getBootstrapFlags(flagKeys: string[], environment?: string, extraContext?: Record<string, unknown>, cacheTtlMs?: number): Promise<Record<string, unknown>>;
|
|
472
481
|
|
|
473
482
|
/**
|
|
474
483
|
* Next.js Middleware Helpers
|
package/dist/server/index.d.ts
CHANGED
|
@@ -439,6 +439,11 @@ declare function apiHandler(handler: HandlerFn, options?: HandlerOptions): (requ
|
|
|
439
439
|
* Evaluates feature flags on the server during SSR so the client
|
|
440
440
|
* has correct values on first render -- no loading flash, no race condition.
|
|
441
441
|
*
|
|
442
|
+
* Results are cached in-memory with a configurable TTL (default: 60s) to
|
|
443
|
+
* prevent excessive API calls. Since feature flags change infrequently,
|
|
444
|
+
* a short cache window is fine and avoids hammering the flags service on
|
|
445
|
+
* every page render.
|
|
446
|
+
*
|
|
442
447
|
* @example
|
|
443
448
|
* ```ts
|
|
444
449
|
* // app/layout.tsx
|
|
@@ -461,14 +466,18 @@ declare function apiHandler(handler: HandlerFn, options?: HandlerOptions): (requ
|
|
|
461
466
|
* and passes it as ip_address in the evaluation context so IP-based targeting
|
|
462
467
|
* rules work correctly.
|
|
463
468
|
*
|
|
469
|
+
* Results are cached in-memory for `cacheTtlMs` milliseconds (default: 60s).
|
|
470
|
+
* Pass `cacheTtlMs: 0` to disable caching.
|
|
471
|
+
*
|
|
464
472
|
* Returns a Record that can be passed directly to ScaleMuleProvider's
|
|
465
473
|
* bootstrapFlags prop.
|
|
466
474
|
*
|
|
467
475
|
* @param flagKeys - Array of flag keys to evaluate
|
|
468
476
|
* @param environment - Environment name (default: 'prod')
|
|
469
477
|
* @param extraContext - Additional context attributes to include
|
|
478
|
+
* @param cacheTtlMs - Cache TTL in milliseconds (default: 60000). Set to 0 to disable.
|
|
470
479
|
*/
|
|
471
|
-
declare function getBootstrapFlags(flagKeys: string[], environment?: string, extraContext?: Record<string, unknown
|
|
480
|
+
declare function getBootstrapFlags(flagKeys: string[], environment?: string, extraContext?: Record<string, unknown>, cacheTtlMs?: number): Promise<Record<string, unknown>>;
|
|
472
481
|
|
|
473
482
|
/**
|
|
474
483
|
* Next.js Middleware Helpers
|
package/dist/server/index.js
CHANGED
|
@@ -1772,8 +1772,17 @@ function getClient() {
|
|
|
1772
1772
|
}
|
|
1773
1773
|
return _serverClient;
|
|
1774
1774
|
}
|
|
1775
|
-
|
|
1775
|
+
var _flagCache = /* @__PURE__ */ new Map();
|
|
1776
|
+
var DEFAULT_CACHE_TTL_MS = 6e4;
|
|
1777
|
+
async function getBootstrapFlags(flagKeys, environment = "prod", extraContext = {}, cacheTtlMs = DEFAULT_CACHE_TTL_MS) {
|
|
1776
1778
|
try {
|
|
1779
|
+
const cacheKey = [...flagKeys].sort().join("|") + ":" + environment;
|
|
1780
|
+
if (cacheTtlMs > 0) {
|
|
1781
|
+
const cached = _flagCache.get(cacheKey);
|
|
1782
|
+
if (cached && Date.now() - cached.timestamp < cacheTtlMs) {
|
|
1783
|
+
return cached.result;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1777
1786
|
const hdrs = await headers.headers();
|
|
1778
1787
|
const forwardedFor = hdrs.get("x-forwarded-for");
|
|
1779
1788
|
const realIp = hdrs.get("x-real-ip") || hdrs.get("x-real-client-ip");
|
|
@@ -1785,7 +1794,19 @@ async function getBootstrapFlags(flagKeys, environment = "prod", extraContext =
|
|
|
1785
1794
|
context.ip_address = clientIp;
|
|
1786
1795
|
}
|
|
1787
1796
|
const result = await getClient().flags.evaluateBatch(flagKeys, context, environment);
|
|
1788
|
-
|
|
1797
|
+
const flagResult = result || {};
|
|
1798
|
+
if (cacheTtlMs > 0) {
|
|
1799
|
+
_flagCache.set(cacheKey, { result: flagResult, timestamp: Date.now() });
|
|
1800
|
+
if (_flagCache.size > 100) {
|
|
1801
|
+
const now = Date.now();
|
|
1802
|
+
for (const [key, entry] of _flagCache) {
|
|
1803
|
+
if (now - entry.timestamp > cacheTtlMs) {
|
|
1804
|
+
_flagCache.delete(key);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
return flagResult;
|
|
1789
1810
|
} catch {
|
|
1790
1811
|
return {};
|
|
1791
1812
|
}
|
|
@@ -1917,14 +1938,14 @@ function clearOAuthState(response) {
|
|
|
1917
1938
|
}
|
|
1918
1939
|
|
|
1919
1940
|
// src/server/secrets.ts
|
|
1920
|
-
var
|
|
1941
|
+
var DEFAULT_CACHE_TTL_MS2 = 5 * 60 * 1e3;
|
|
1921
1942
|
var secretsCache = {};
|
|
1922
1943
|
var globalConfig = {};
|
|
1923
1944
|
function configureSecrets(config) {
|
|
1924
1945
|
globalConfig = { ...globalConfig, ...config };
|
|
1925
1946
|
}
|
|
1926
1947
|
async function getAppSecret(key) {
|
|
1927
|
-
const cacheTtl = globalConfig.cacheTtlMs ??
|
|
1948
|
+
const cacheTtl = globalConfig.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS2;
|
|
1928
1949
|
const noCache = globalConfig.noCache ?? false;
|
|
1929
1950
|
if (!noCache) {
|
|
1930
1951
|
const cached = secretsCache[key];
|
|
@@ -1976,14 +1997,14 @@ async function prefetchSecrets(keys) {
|
|
|
1976
1997
|
}
|
|
1977
1998
|
|
|
1978
1999
|
// src/server/bundles.ts
|
|
1979
|
-
var
|
|
2000
|
+
var DEFAULT_CACHE_TTL_MS3 = 5 * 60 * 1e3;
|
|
1980
2001
|
var bundlesCache = {};
|
|
1981
2002
|
var globalConfig2 = {};
|
|
1982
2003
|
function configureBundles(config) {
|
|
1983
2004
|
globalConfig2 = { ...globalConfig2, ...config };
|
|
1984
2005
|
}
|
|
1985
2006
|
async function getBundle(key, resolve = true) {
|
|
1986
|
-
const cacheTtl = globalConfig2.cacheTtlMs ??
|
|
2007
|
+
const cacheTtl = globalConfig2.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS3;
|
|
1987
2008
|
const noCache = globalConfig2.noCache ?? false;
|
|
1988
2009
|
if (!noCache) {
|
|
1989
2010
|
const cached = bundlesCache[key];
|
package/dist/server/index.mjs
CHANGED
|
@@ -1770,8 +1770,17 @@ function getClient() {
|
|
|
1770
1770
|
}
|
|
1771
1771
|
return _serverClient;
|
|
1772
1772
|
}
|
|
1773
|
-
|
|
1773
|
+
var _flagCache = /* @__PURE__ */ new Map();
|
|
1774
|
+
var DEFAULT_CACHE_TTL_MS = 6e4;
|
|
1775
|
+
async function getBootstrapFlags(flagKeys, environment = "prod", extraContext = {}, cacheTtlMs = DEFAULT_CACHE_TTL_MS) {
|
|
1774
1776
|
try {
|
|
1777
|
+
const cacheKey = [...flagKeys].sort().join("|") + ":" + environment;
|
|
1778
|
+
if (cacheTtlMs > 0) {
|
|
1779
|
+
const cached = _flagCache.get(cacheKey);
|
|
1780
|
+
if (cached && Date.now() - cached.timestamp < cacheTtlMs) {
|
|
1781
|
+
return cached.result;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1775
1784
|
const hdrs = await headers();
|
|
1776
1785
|
const forwardedFor = hdrs.get("x-forwarded-for");
|
|
1777
1786
|
const realIp = hdrs.get("x-real-ip") || hdrs.get("x-real-client-ip");
|
|
@@ -1783,7 +1792,19 @@ async function getBootstrapFlags(flagKeys, environment = "prod", extraContext =
|
|
|
1783
1792
|
context.ip_address = clientIp;
|
|
1784
1793
|
}
|
|
1785
1794
|
const result = await getClient().flags.evaluateBatch(flagKeys, context, environment);
|
|
1786
|
-
|
|
1795
|
+
const flagResult = result || {};
|
|
1796
|
+
if (cacheTtlMs > 0) {
|
|
1797
|
+
_flagCache.set(cacheKey, { result: flagResult, timestamp: Date.now() });
|
|
1798
|
+
if (_flagCache.size > 100) {
|
|
1799
|
+
const now = Date.now();
|
|
1800
|
+
for (const [key, entry] of _flagCache) {
|
|
1801
|
+
if (now - entry.timestamp > cacheTtlMs) {
|
|
1802
|
+
_flagCache.delete(key);
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
return flagResult;
|
|
1787
1808
|
} catch {
|
|
1788
1809
|
return {};
|
|
1789
1810
|
}
|
|
@@ -1915,14 +1936,14 @@ function clearOAuthState(response) {
|
|
|
1915
1936
|
}
|
|
1916
1937
|
|
|
1917
1938
|
// src/server/secrets.ts
|
|
1918
|
-
var
|
|
1939
|
+
var DEFAULT_CACHE_TTL_MS2 = 5 * 60 * 1e3;
|
|
1919
1940
|
var secretsCache = {};
|
|
1920
1941
|
var globalConfig = {};
|
|
1921
1942
|
function configureSecrets(config) {
|
|
1922
1943
|
globalConfig = { ...globalConfig, ...config };
|
|
1923
1944
|
}
|
|
1924
1945
|
async function getAppSecret(key) {
|
|
1925
|
-
const cacheTtl = globalConfig.cacheTtlMs ??
|
|
1946
|
+
const cacheTtl = globalConfig.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS2;
|
|
1926
1947
|
const noCache = globalConfig.noCache ?? false;
|
|
1927
1948
|
if (!noCache) {
|
|
1928
1949
|
const cached = secretsCache[key];
|
|
@@ -1974,14 +1995,14 @@ async function prefetchSecrets(keys) {
|
|
|
1974
1995
|
}
|
|
1975
1996
|
|
|
1976
1997
|
// src/server/bundles.ts
|
|
1977
|
-
var
|
|
1998
|
+
var DEFAULT_CACHE_TTL_MS3 = 5 * 60 * 1e3;
|
|
1978
1999
|
var bundlesCache = {};
|
|
1979
2000
|
var globalConfig2 = {};
|
|
1980
2001
|
function configureBundles(config) {
|
|
1981
2002
|
globalConfig2 = { ...globalConfig2, ...config };
|
|
1982
2003
|
}
|
|
1983
2004
|
async function getBundle(key, resolve = true) {
|
|
1984
|
-
const cacheTtl = globalConfig2.cacheTtlMs ??
|
|
2005
|
+
const cacheTtl = globalConfig2.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS3;
|
|
1985
2006
|
const noCache = globalConfig2.noCache ?? false;
|
|
1986
2007
|
if (!noCache) {
|
|
1987
2008
|
const cached = bundlesCache[key];
|
package/package.json
CHANGED