feat: improve error logging and enhance settings sync functionality

This commit is contained in:
Linus Rath
2026-03-19 08:54:33 +01:00
parent 9b3a47f9be
commit 234129397d
3 changed files with 34 additions and 19 deletions
+6 -2
View File
@@ -47,7 +47,9 @@ export async function GET(request: NextRequest) {
}
return NextResponse.json({ settings });
} catch (error) {
logger.error('Settings load error', { error: error instanceof Error ? error.message : 'Unknown error' });
const message = error instanceof Error ? error.message : 'Unknown error';
const code = (error as NodeJS.ErrnoException).code;
logger.error('Settings load error', { error: message, code });
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
}
}
@@ -74,7 +76,9 @@ export async function POST(request: NextRequest) {
await saveUserSettings(username, serverUrl, settings);
return NextResponse.json({ ok: true });
} catch (error) {
logger.error('Settings save error', { error: error instanceof Error ? error.message : 'Unknown error' });
const message = error instanceof Error ? error.message : 'Unknown error';
const code = (error as NodeJS.ErrnoException).code;
logger.error('Settings save error', { error: message, code });
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
}
}
+5 -2
View File
@@ -1,5 +1,5 @@
import { createHash, createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';
import { readFile, writeFile, unlink, mkdir } from 'node:fs/promises';
import { readFile, writeFile, unlink, mkdir, rename } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import path from 'node:path';
import { logger } from '@/lib/logger';
@@ -45,7 +45,10 @@ export async function saveUserSettings(username: string, serverUrl: string, sett
const tag = cipher.getAuthTag();
const data = Buffer.concat([iv, tag, encrypted]);
await writeFile(getSettingsPath(username, serverUrl), data);
const targetPath = getSettingsPath(username, serverUrl);
const tmpPath = targetPath + '.tmp';
await writeFile(tmpPath, data);
await rename(tmpPath, targetPath);
}
export async function loadUserSettings(username: string, serverUrl: string): Promise<Record<string, unknown> | null> {
+23 -15
View File
@@ -562,26 +562,34 @@ if (typeof window !== 'undefined') {
applyAnimations(store.animationsEnabled);
// Shared sync function used by all store subscribers
const syncToServer = async (retries = 1): Promise<void> => {
const settings = JSON.parse(useSettingsStore.getState().exportSettings());
syncLog('Syncing settings to server...');
const res = await fetch('/api/settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: syncUsername, serverUrl: syncServerUrl, settings }),
});
if (res.status === 404) {
syncWarn('Settings sync endpoint returned 404, disabling sync');
syncEnabled = false;
} else if (res.status >= 500 && retries > 0) {
syncWarn('Settings sync got server error, retrying...');
await new Promise((r) => setTimeout(r, 2000));
return syncToServer(retries - 1);
} else if (!res.ok) {
syncError('Settings sync failed with status', res.status);
} else {
syncLog('Settings synced to server successfully');
}
};
const triggerSync = () => {
if (!syncEnabled || !syncUsername || !syncServerUrl || isLoadingFromServer) return;
if (syncTimeout) clearTimeout(syncTimeout);
syncTimeout = setTimeout(async () => {
try {
const settings = JSON.parse(useSettingsStore.getState().exportSettings());
syncLog('Syncing settings to server...');
const res = await fetch('/api/settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: syncUsername, serverUrl: syncServerUrl, settings }),
});
if (res.status === 404) {
syncWarn('Settings sync endpoint returned 404, disabling sync');
syncEnabled = false;
} else if (!res.ok) {
syncError('Settings sync failed with status', res.status);
} else {
syncLog('Settings synced to server successfully');
}
await syncToServer();
} catch (error) {
syncError('Settings sync error:', error);
}