import { queryOptions } from '@tanstack/react-query' import { apiJSON } from '@/lib/api-client' export type AppSettings = Record export const BIRD_SETTING_KEYS = [ 'bird_router_id', 'bird_local_ipv4', 'bird_local_ipv6', 'bird_local_asn', 'bird_bgp_source_ipv4', 'bird_bgp_source_ipv6', ] as const export const REVISION_SETTING_KEYS = ['revision_retention_minutes'] as const export const RUNTIME_LOGS_SETTING_KEYS = [ 'runtime_logs_auto_enabled', 'runtime_logs_max_file_mb', 'runtime_logs_auto_schedule', 'runtime_logs_auto_mode', ] as const export const KNOWN_SETTING_KEYS = [ ...BIRD_SETTING_KEYS, ...REVISION_SETTING_KEYS, ...RUNTIME_LOGS_SETTING_KEYS, ] as const export type KnownSettingKey = (typeof KNOWN_SETTING_KEYS)[number] export type BirdSettingKey = (typeof BIRD_SETTING_KEYS)[number] export type RevisionSettingKey = (typeof REVISION_SETTING_KEYS)[number] export type RuntimeLogsSettingKey = (typeof RUNTIME_LOGS_SETTING_KEYS)[number] export const NUMERIC_SETTING_KEYS = new Set([ 'bird_local_asn', 'revision_retention_minutes', 'runtime_logs_max_file_mb', ]) export const BOOLEAN_SETTING_KEYS = new Set(['runtime_logs_auto_enabled']) export const settingsKeys = { all: ['settings'] as const, } export function settingsQueryOptions() { return queryOptions({ queryKey: settingsKeys.all, queryFn: () => apiJSON('/v1/settings'), staleTime: 30_000, }) } export function parseKnownValue(key: KnownSettingKey, value: unknown): string { if (NUMERIC_SETTING_KEYS.has(key)) { if (typeof value === 'number' && Number.isFinite(value)) return String(value) if (typeof value === 'string') return value return '' } if (typeof value === 'string') return value return '' } export interface PartitionedSettings { bird: Partial> revision: Partial> runtimeLogs: Partial> additional: { id: number; key: string; value: string }[] } export function partitionSettings(settings: AppSettings): PartitionedSettings { const bird: Partial> = {} const revision: Partial> = {} const runtimeLogs: Partial> = {} const additional: { id: number; key: string; value: string }[] = [] let id = 1 for (const [key, value] of Object.entries(settings)) { if ((BIRD_SETTING_KEYS as readonly string[]).includes(key)) { bird[key as BirdSettingKey] = parseKnownValue(key as KnownSettingKey, value) } else if (key === 'revision_retention_minutes') { revision.revision_retention_minutes = parseKnownValue( key as RevisionSettingKey, value, ) } else if ((RUNTIME_LOGS_SETTING_KEYS as readonly string[]).includes(key)) { const rk = key as RuntimeLogsSettingKey if (rk === 'runtime_logs_auto_enabled') { runtimeLogs.runtime_logs_auto_enabled = value === true || value === 1 || value === 'true' || value === '1' ? 'true' : 'false' } else if (rk === 'runtime_logs_auto_mode') { const m = String(value ?? '').trim() runtimeLogs.runtime_logs_auto_mode = m === 'delete' ? 'delete' : m === 'truncate' ? 'truncate' : '' } else { runtimeLogs[rk] = parseKnownValue(rk, value) } } else { additional.push({ id: id++, key, value: typeof value === 'string' ? value : String(value), }) } } return { bird, revision, runtimeLogs, additional } } export function buildPayload( keys: readonly KnownSettingKey[], form: Record, ): Record { const payload: Record = {} for (const key of keys) { const value = String(form[key] ?? '').trim() if (BOOLEAN_SETTING_KEYS.has(key)) { payload[key] = value === 'true' continue } if (!value) continue if (NUMERIC_SETTING_KEYS.has(key)) payload[key] = Number(value) else payload[key] = value } return payload }