nyk
feat(refactor): ready for manual QA after main sync (#274)
b6ecafa unverified
Raw
History Blame Contribute Delete
3.69 kB
import { NextRequest, NextResponse } from 'next/server'
import { getDatabase } from '@/lib/db'
import { requireRole } from '@/lib/auth'
import { logger } from '@/lib/logger'
const PREFS_KEY = 'chat.session_prefs.v1'
const ALLOWED_COLORS = new Set(['slate', 'blue', 'green', 'amber', 'red', 'purple', 'pink', 'teal'])
type SessionPref = {
name?: string
color?: string
}
type SessionPrefs = Record<string, SessionPref>
function loadPrefs(): SessionPrefs {
const db = getDatabase()
const row = db.prepare('SELECT value FROM settings WHERE key = ?').get(PREFS_KEY) as { value: string } | undefined
if (!row?.value) return {}
try {
const parsed = JSON.parse(row.value)
return parsed && typeof parsed === 'object' ? parsed : {}
} catch {
return {}
}
}
function savePrefs(prefs: SessionPrefs, username: string) {
const db = getDatabase()
const now = Math.floor(Date.now() / 1000)
db.prepare(`
INSERT INTO settings (key, value, description, category, updated_by, updated_at)
VALUES (?, ?, ?, ?, ?, ?)
ON CONFLICT(key) DO UPDATE SET
value = excluded.value,
updated_by = excluded.updated_by,
updated_at = excluded.updated_at
`).run(
PREFS_KEY,
JSON.stringify(prefs),
'Chat local session preferences (rename + color tags)',
'chat',
username,
now,
)
}
export async function GET(request: NextRequest) {
const auth = requireRole(request, 'viewer')
if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status })
try {
return NextResponse.json({ prefs: loadPrefs() })
} catch (error) {
logger.error({ err: error }, 'GET /api/chat/session-prefs error')
return NextResponse.json({ error: 'Failed to load preferences' }, { status: 500 })
}
}
/**
* PATCH /api/chat/session-prefs
* Body: { key: "claude-code:<sessionId>", name?: string, color?: string | null }
*/
export async function PATCH(request: NextRequest) {
const auth = requireRole(request, 'operator')
if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status })
try {
const body = await request.json().catch(() => ({}))
const key = typeof body?.key === 'string' ? body.key.trim() : ''
if (!key || !/^[a-zA-Z0-9_-]+:[a-zA-Z0-9._:-]+$/.test(key)) {
return NextResponse.json({ error: 'Invalid key' }, { status: 400 })
}
const nextName = body?.name === null ? '' : (typeof body?.name === 'string' ? body.name.trim() : undefined)
const nextColor = body?.color === null ? '' : (typeof body?.color === 'string' ? body.color.trim().toLowerCase() : undefined)
if (typeof nextName === 'string' && nextName.length > 80) {
return NextResponse.json({ error: 'name must be <= 80 chars' }, { status: 400 })
}
if (typeof nextColor === 'string' && nextColor && !ALLOWED_COLORS.has(nextColor)) {
return NextResponse.json({ error: 'Invalid color' }, { status: 400 })
}
const prefs = loadPrefs()
const existing = prefs[key] || {}
const updated: SessionPref = {
...existing,
...(typeof nextName === 'string' ? { name: nextName || undefined } : {}),
...(typeof nextColor === 'string' ? { color: nextColor || undefined } : {}),
}
if (!updated.name && !updated.color) {
delete prefs[key]
} else {
prefs[key] = updated
}
savePrefs(prefs, auth.user.username)
return NextResponse.json({ ok: true, pref: prefs[key] || null })
} catch (error) {
logger.error({ err: error }, 'PATCH /api/chat/session-prefs error')
return NextResponse.json({ error: 'Failed to update preferences' }, { status: 500 })
}
}
export const dynamic = 'force-dynamic'