41 lines
1.3 KiB
TypeScript
41 lines
1.3 KiB
TypeScript
import "server-only";
|
|
|
|
import { queryAdminRows } from "@/lib/admin/database";
|
|
|
|
type FeatureFlagRow = {
|
|
flag_key: string;
|
|
enabled: boolean;
|
|
rollout_percentage: number;
|
|
config: Record<string, unknown>;
|
|
};
|
|
|
|
export type RuntimeFeatureFlag = {
|
|
enabled: boolean;
|
|
config: Record<string, unknown>;
|
|
};
|
|
|
|
type Cache = { expiresAt: number; flags: Map<string, RuntimeFeatureFlag> };
|
|
const state = globalThis as typeof globalThis & { jyotishaFeatureFlagCache?: Cache };
|
|
const cacheTtlMs = 15_000;
|
|
|
|
export async function loadRuntimeFeatureFlags(keys: readonly string[]) {
|
|
const cached = state.jyotishaFeatureFlagCache;
|
|
if (cached && cached.expiresAt > Date.now() && keys.every((key) => cached.flags.has(key))) return cached.flags;
|
|
|
|
const rows = await queryAdminRows<FeatureFlagRow>(`
|
|
select flag_key,enabled,rollout_percentage,config
|
|
from public.feature_flags
|
|
where status='published' and flag_key=any($1::text[])
|
|
`, [keys]);
|
|
const flags = new Map<string, RuntimeFeatureFlag>();
|
|
for (const key of keys) flags.set(key, { enabled: false, config: {} });
|
|
for (const row of rows) {
|
|
flags.set(row.flag_key, {
|
|
enabled: row.enabled && row.rollout_percentage === 100,
|
|
config: row.config,
|
|
});
|
|
}
|
|
state.jyotishaFeatureFlagCache = { expiresAt: Date.now() + cacheTtlMs, flags };
|
|
return flags;
|
|
}
|