fix: invalidate cached public site settings
This commit is contained in:
parent
33f25f4b21
commit
bd98282bc5
@ -67,6 +67,7 @@ import {
|
|||||||
EXTERNAL_IMAGE_API_CONFIG_KEY,
|
EXTERNAL_IMAGE_API_CONFIG_KEY,
|
||||||
normalizeExternalImageApiConfig,
|
normalizeExternalImageApiConfig,
|
||||||
} from "@/lib/external-image-api/config";
|
} from "@/lib/external-image-api/config";
|
||||||
|
import { clearScopedSiteSettingsCache } from "@/lib/site-settings/public-cache";
|
||||||
|
|
||||||
const settingSchema = z.object({
|
const settingSchema = z.object({
|
||||||
key: z.string(),
|
key: z.string(),
|
||||||
@ -270,6 +271,7 @@ export async function POST(request: Request) {
|
|||||||
value: normalizeExternalImageApiConfig(value),
|
value: normalizeExternalImageApiConfig(value),
|
||||||
updatedBy: session.user.id,
|
updatedBy: session.user.id,
|
||||||
});
|
});
|
||||||
|
clearScopedSiteSettingsCache();
|
||||||
|
|
||||||
return Response.json({
|
return Response.json({
|
||||||
setting: saved[0],
|
setting: saved[0],
|
||||||
@ -388,6 +390,7 @@ export async function POST(request: Request) {
|
|||||||
value: nextValue,
|
value: nextValue,
|
||||||
updatedBy: session.user.id,
|
updatedBy: session.user.id,
|
||||||
});
|
});
|
||||||
|
clearScopedSiteSettingsCache();
|
||||||
|
|
||||||
return Response.json({ setting: setting[0] });
|
return Response.json({ setting: setting[0] });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -98,6 +98,13 @@ import {
|
|||||||
normalizeOssImageMigrationConfig,
|
normalizeOssImageMigrationConfig,
|
||||||
OSS_MIGRATION_CONFIG_KEY,
|
OSS_MIGRATION_CONFIG_KEY,
|
||||||
} from "@/lib/storage/migration-config";
|
} from "@/lib/storage/migration-config";
|
||||||
|
import {
|
||||||
|
clearScopedSiteSettingsCache,
|
||||||
|
deleteScopedSiteSettingsCache,
|
||||||
|
getScopedSiteSettingsCache,
|
||||||
|
PUBLIC_SITE_SETTINGS_CACHE_TTL_MS,
|
||||||
|
setScopedSiteSettingsCache,
|
||||||
|
} from "@/lib/site-settings/public-cache";
|
||||||
import {
|
import {
|
||||||
getHomeChatAnimationHtmlBytes,
|
getHomeChatAnimationHtmlBytes,
|
||||||
HOME_CHAT_ANIMATION_CONFIG_KEY,
|
HOME_CHAT_ANIMATION_CONFIG_KEY,
|
||||||
@ -502,22 +509,19 @@ const PUBLIC_SITE_SETTINGS_SCOPES = new Set<string>([
|
|||||||
"home",
|
"home",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const SCOPED_SITE_SETTINGS_SERVER_CACHE_TTL_MS = 30_000;
|
|
||||||
const scopedSiteSettingsServerCache = new Map<
|
|
||||||
string,
|
|
||||||
{ data: Record<string, unknown>; expiresAt: number }
|
|
||||||
>();
|
|
||||||
|
|
||||||
function createScopedSiteSettingsResponse(
|
function createScopedSiteSettingsResponse(
|
||||||
scope: PublicSiteSettingsScope,
|
scope: PublicSiteSettingsScope,
|
||||||
data: Record<string, unknown>,
|
data: Record<string, unknown>,
|
||||||
cacheStatus: "HIT" | "MISS" = "MISS",
|
cacheStatus: "HIT" | "MISS" = "MISS",
|
||||||
cacheKey: string = scope
|
cacheKey: string = scope
|
||||||
) {
|
) {
|
||||||
scopedSiteSettingsServerCache.set(cacheKey, {
|
if (cacheStatus !== "HIT") {
|
||||||
data,
|
setScopedSiteSettingsCache(
|
||||||
expiresAt: Date.now() + SCOPED_SITE_SETTINGS_SERVER_CACHE_TTL_MS,
|
cacheKey,
|
||||||
});
|
data,
|
||||||
|
PUBLIC_SITE_SETTINGS_CACHE_TTL_MS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const response = NextResponse.json(data);
|
const response = NextResponse.json(data);
|
||||||
// Lightweight public settings change rarely; keep them browser-local briefly
|
// Lightweight public settings change rarely; keep them browser-local briefly
|
||||||
@ -883,7 +887,7 @@ export async function GET(request: NextRequest) {
|
|||||||
const cacheKey = brandName.trim()
|
const cacheKey = brandName.trim()
|
||||||
? `${scopedScope}:${brandName.trim().toLowerCase()}`
|
? `${scopedScope}:${brandName.trim().toLowerCase()}`
|
||||||
: scopedScope;
|
: scopedScope;
|
||||||
const cached = scopedSiteSettingsServerCache.get(cacheKey);
|
const cached = getScopedSiteSettingsCache(cacheKey);
|
||||||
if (cached && cached.expiresAt > Date.now()) {
|
if (cached && cached.expiresAt > Date.now()) {
|
||||||
return createScopedSiteSettingsResponse(
|
return createScopedSiteSettingsResponse(
|
||||||
scopedScope,
|
scopedScope,
|
||||||
@ -892,6 +896,9 @@ export async function GET(request: NextRequest) {
|
|||||||
cacheKey
|
cacheKey
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (cached) {
|
||||||
|
deleteScopedSiteSettingsCache(cacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
return getScopedPublicSiteSettings(scopedScope, {
|
return getScopedPublicSiteSettings(scopedScope, {
|
||||||
brandName,
|
brandName,
|
||||||
@ -2625,7 +2632,7 @@ export async function PUT(request: NextRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await persistHomeAnimationConfig();
|
await persistHomeAnimationConfig();
|
||||||
scopedSiteSettingsServerCache.clear();
|
clearScopedSiteSettingsCache();
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
...updated,
|
...updated,
|
||||||
@ -3274,7 +3281,7 @@ export async function PUT(request: NextRequest) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
scopedSiteSettingsServerCache.clear();
|
clearScopedSiteSettingsCache();
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
...created,
|
...created,
|
||||||
|
|||||||
52
lib/site-settings/public-cache.ts
Normal file
52
lib/site-settings/public-cache.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
const PUBLIC_SITE_SETTINGS_CACHE_TTL_MS = 30_000;
|
||||||
|
const PUBLIC_SITE_SETTINGS_CACHE_KEY = Symbol.for(
|
||||||
|
"ai-chatbot.public-site-settings-cache",
|
||||||
|
);
|
||||||
|
|
||||||
|
type PublicSiteSettingsCacheEntry = {
|
||||||
|
data: Record<string, unknown>;
|
||||||
|
expiresAt: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function getPublicSiteSettingsCacheStore() {
|
||||||
|
const globalCache = globalThis as typeof globalThis & {
|
||||||
|
[PUBLIC_SITE_SETTINGS_CACHE_KEY]?: Map<
|
||||||
|
string,
|
||||||
|
PublicSiteSettingsCacheEntry
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!globalCache[PUBLIC_SITE_SETTINGS_CACHE_KEY]) {
|
||||||
|
globalCache[PUBLIC_SITE_SETTINGS_CACHE_KEY] = new Map<
|
||||||
|
string,
|
||||||
|
PublicSiteSettingsCacheEntry
|
||||||
|
>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return globalCache[PUBLIC_SITE_SETTINGS_CACHE_KEY]!;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getScopedSiteSettingsCache(cacheKey: string) {
|
||||||
|
return getPublicSiteSettingsCacheStore().get(cacheKey) ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setScopedSiteSettingsCache(
|
||||||
|
cacheKey: string,
|
||||||
|
data: Record<string, unknown>,
|
||||||
|
ttlMs: number = PUBLIC_SITE_SETTINGS_CACHE_TTL_MS,
|
||||||
|
) {
|
||||||
|
getPublicSiteSettingsCacheStore().set(cacheKey, {
|
||||||
|
data,
|
||||||
|
expiresAt: Date.now() + ttlMs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteScopedSiteSettingsCache(cacheKey: string) {
|
||||||
|
getPublicSiteSettingsCacheStore().delete(cacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearScopedSiteSettingsCache() {
|
||||||
|
getPublicSiteSettingsCacheStore().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
export { PUBLIC_SITE_SETTINGS_CACHE_TTL_MS };
|
||||||
Loading…
x
Reference in New Issue
Block a user