Files
libnovel/ui/src/routes/api/settings/+server.ts
Admin 0c54c59586
All checks were successful
Release / Test backend (push) Successful in 51s
Release / Check ui (push) Successful in 47s
Release / Docker / caddy (push) Successful in 38s
Release / Docker / backend (push) Successful in 2m30s
Release / Docker / runner (push) Successful in 2m38s
Release / Docker / ui (push) Successful in 2m1s
Release / Gitea Release (push) Successful in 41s
fix: guard against font_size=0 collapsing chapter text
- Replace ?? with || when reading font_size so 0 falls back to 1.0
  (affects GET /api/settings, layout.server.ts, +layout.svelte)
- Remove the explicit 'body.fontSize !== 0' exception in PUT /api/settings
  validation so 0 is now correctly rejected as an invalid font size
- Add add_index helper + idx_chapters_idx_slug_number declaration to
  scripts/pb-init-v3.sh (idempotent UNIQUE INDEX on chapters_idx)
2026-04-04 23:26:54 +05:00

78 lines
2.9 KiB
TypeScript

import { json, error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { getSettings, saveSettings } from '$lib/server/pocketbase';
import { log } from '$lib/server/logger';
/**
* GET /api/settings
* Returns the current user's settings (auto_next, voice, speed, theme, locale, fontFamily, fontSize).
* Returns defaults if no settings record exists yet.
*/
export const GET: RequestHandler = async ({ locals }) => {
try {
const settings = await getSettings(locals.sessionId, locals.user?.id);
return json({
autoNext: settings?.auto_next ?? false,
voice: settings?.voice ?? 'af_bella',
speed: settings?.speed ?? 1.0,
theme: settings?.theme ?? 'amber',
locale: settings?.locale ?? 'en',
fontFamily: settings?.font_family ?? 'system',
fontSize: settings?.font_size || 1.0
});
} catch (e) {
log.error('settings', 'GET failed', { err: String(e) });
error(500, 'Failed to load settings');
}
};
/**
* PUT /api/settings
* Body: { autoNext: boolean, voice: string, speed: number, theme?: string, locale?: string, fontFamily?: string, fontSize?: number }
* Saves user preferences.
*/
export const PUT: RequestHandler = async ({ request, locals }) => {
const body = await request.json().catch(() => null);
if (
!body ||
typeof body.autoNext !== 'boolean' ||
typeof body.voice !== 'string' ||
typeof body.speed !== 'number'
) {
error(400, 'Invalid body — expected { autoNext, voice, speed }');
}
// theme is optional — if provided (and non-empty) it must be a known value
const validThemes = ['amber', 'slate', 'rose', 'light', 'light-slate', 'light-rose'];
if (body.theme !== undefined && body.theme !== '' && !validThemes.includes(body.theme)) {
error(400, `Invalid theme — must be one of: ${validThemes.join(', ')}`);
}
// locale is optional — if provided (and non-empty) it must be a known value
const validLocales = ['en', 'ru', 'id', 'pt', 'fr'];
if (body.locale !== undefined && body.locale !== '' && !validLocales.includes(body.locale)) {
error(400, `Invalid locale — must be one of: ${validLocales.join(', ')}`);
}
// fontFamily is optional — if provided (and non-empty) it must be a known value
const validFontFamilies = ['system', 'serif', 'mono'];
if (body.fontFamily !== undefined && body.fontFamily !== '' && !validFontFamilies.includes(body.fontFamily)) {
error(400, `Invalid fontFamily — must be one of: ${validFontFamilies.join(', ')}`);
}
// fontSize is optional — if provided it must be one of the valid steps (0 is not valid)
const validFontSizes = [0.9, 1.0, 1.15, 1.3];
if (body.fontSize !== undefined && !validFontSizes.includes(body.fontSize)) {
error(400, `Invalid fontSize — must be one of: ${validFontSizes.join(', ')}`);
}
try {
await saveSettings(locals.sessionId, body, locals.user?.id);
} catch (e) {
log.error('settings', 'PUT failed', { err: String(e) });
error(500, 'Failed to save settings');
}
return json({ ok: true });
};