fix: adminPath TTL cache in hooks.ts instead of read-once at startup

Previous approach read config.json once at module load time. If the PVC
wasn't fully mounted yet, it fell back to 'admin' and stayed there for
the lifetime of the process. New approach caches for 5 seconds and re-reads
on expiry, so it recovers from startup races and picks up changes without
requiring a restart.
This commit is contained in:
Falkan
2026-03-20 01:57:06 -04:00
parent 7239ca6d5a
commit 231eacc27c

View File

@@ -2,17 +2,29 @@ import fs from 'fs';
import path from 'path';
import type { Reroute } from '@sveltejs/kit';
// Read adminPath once at startup. Changes require a server restart.
let adminPath = 'admin';
const CONFIG_PATH = path.resolve('data', 'config.json');
// Cache adminPath with a 5-second TTL so changes take effect quickly
// but we don't hit disk on every request.
let cachedAdminPath = 'admin';
let cacheExpiry = 0;
function getAdminPath(): string {
const now = Date.now();
if (now < cacheExpiry) return cachedAdminPath;
try {
const config = JSON.parse(fs.readFileSync(path.resolve('data', 'config.json'), 'utf8'));
adminPath = (config.adminPath ?? 'admin').replace(/^\/|\/$/g, '') || 'admin';
console.log('[hooks] adminPath set to:', adminPath);
const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
cachedAdminPath = (config.adminPath ?? 'admin').replace(/^\/|\/$/g, '') || 'admin';
} catch {
// config.json missing or unreadable — fall back to 'admin'
// config.json missing or unreadable — keep current cached value
}
export { adminPath };
cacheExpiry = now + 5000;
return cachedAdminPath;
}
export { getAdminPath as adminPath };
/**
* Rewrites /<adminPath>/... to /admin/... before SvelteKit resolves the route.
@@ -20,18 +32,17 @@ export { adminPath };
* so attackers cannot enumerate the admin URL.
*/
export const reroute: Reroute = ({ url }) => {
const adminPath = getAdminPath();
const prefix = `/${adminPath}`;
// Public path → internal /admin
if (url.pathname === prefix || url.pathname.startsWith(prefix + '/')) {
console.log(`[reroute] ${url.pathname} → /admin${url.pathname.slice(prefix.length)}`);
return '/admin' + url.pathname.slice(prefix.length);
}
// Block direct /admin access when a custom path is configured
if (adminPath !== 'admin') {
if (url.pathname === '/admin' || url.pathname.startsWith('/admin/')) {
console.log(`[reroute] blocking direct /admin access → /404`);
return '/404';
}
}