export type UserSyncTheme = 'light' | 'dark' | 'system'; export type UserSyncPreferences = { theme?: UserSyncTheme; language?: string; defaultModel?: string; defaultProviderAccountId?: string; sidebarCollapsed?: boolean; devModeUnlocked?: boolean; selectedBundles?: string[]; enabledSkills?: string[]; disabledSkills?: string[]; }; export type UserSyncProviderAccount = { id: string; vendorId: string; label: string; authMode: string; baseUrl?: string; apiProtocol?: string; model?: string; fallbackModels?: string[]; fallbackAccountIds?: string[]; enabled: boolean; isDefault: boolean; metadata: Record; updatedAt?: string; }; export type UserSyncPartner = { id: string; displayName: string; templateRoleId: string; description?: string; avatarTone?: string; avatarDataUrl?: string; prompt?: string; skillIds?: string[]; createdAt?: string; updatedAt?: string; }; export type UserSyncUsageAggregate = { date: string; model?: string; providerAccountId?: string; inputTokens: number; outputTokens: number; cacheReadTokens: number; cacheWriteTokens: number; estimatedCostUsd: number; requestCount: number; }; export type UserSyncBootstrap = { preferences: UserSyncPreferences; providerAccounts: UserSyncProviderAccount[]; partners: UserSyncPartner[]; usageAggregates: UserSyncUsageAggregate[]; }; type UnknownRecord = Record; function isRecord(value: unknown): value is UnknownRecord { return Boolean(value) && typeof value === 'object' && !Array.isArray(value); } function text(value: unknown): string | undefined { if (typeof value !== 'string') return undefined; const trimmed = value.trim(); return trimmed || undefined; } function bool(value: unknown): boolean | undefined { return typeof value === 'boolean' ? value : undefined; } function stringArray(value: unknown): string[] | undefined { if (!Array.isArray(value)) return undefined; const seen = new Set(); const result: string[] = []; for (const item of value) { const clean = text(item); if (clean && !seen.has(clean)) { seen.add(clean); result.push(clean); } } return result.length ? result : undefined; } function plainMetadata(value: unknown): Record { if (!isRecord(value)) return {}; const result: Record = {}; for (const [key, entry] of Object.entries(value)) { if (entry === undefined || typeof entry === 'function') continue; result[key] = entry; } return result; } function compact>(value: T): Partial { return Object.fromEntries( Object.entries(value).filter(([, entry]) => entry !== undefined), ) as Partial; } function oneOfTheme(value: unknown): UserSyncTheme | undefined { return value === 'light' || value === 'dark' || value === 'system' ? value : undefined; } function numberValue(value: unknown): number | undefined { return typeof value === 'number' && Number.isFinite(value) ? value : undefined; } export function toUserSyncPreferences( input: unknown, defaultProviderAccountId?: string | null, ): UserSyncPreferences { const record = isRecord(input) ? input : {}; return compact({ theme: oneOfTheme(record.theme), language: text(record.language), defaultModel: text(record.defaultModel ?? record.default_model), defaultProviderAccountId: text(defaultProviderAccountId) ?? text(record.defaultProviderAccountId ?? record.default_provider_account_id), sidebarCollapsed: bool(record.sidebarCollapsed ?? record.sidebar_collapsed), devModeUnlocked: bool(record.devModeUnlocked ?? record.dev_mode_unlocked), selectedBundles: stringArray(record.selectedBundles ?? record.selected_bundles), enabledSkills: stringArray(record.enabledSkills ?? record.enabled_skills), disabledSkills: stringArray(record.disabledSkills ?? record.disabled_skills), }); } export function toUserSyncProviderAccount(input: unknown): UserSyncProviderAccount { const record = isRecord(input) ? input : {}; return compact({ id: text(record.id), vendorId: text(record.vendorId ?? record.vendor_id), label: text(record.label), authMode: text(record.authMode ?? record.auth_mode), baseUrl: text(record.baseUrl ?? record.base_url), apiProtocol: text(record.apiProtocol ?? record.api_protocol), model: text(record.model), fallbackModels: stringArray(record.fallbackModels ?? record.fallback_models), fallbackAccountIds: stringArray(record.fallbackAccountIds ?? record.fallback_account_ids), enabled: bool(record.enabled) ?? true, isDefault: bool(record.isDefault ?? record.is_default) ?? false, metadata: plainMetadata(record.metadata), updatedAt: text(record.updatedAt ?? record.updated_at), }) as UserSyncProviderAccount; } export function toUserSyncPartner(input: unknown): UserSyncPartner { const record = isRecord(input) ? input : {}; return compact({ id: text(record.id), displayName: text(record.displayName ?? record.display_name), // Keep the wire field for backend compatibility, but no longer preserve // legacy role-template ids in the desktop state. templateRoleId: 'custom', description: text(record.description), avatarTone: text(record.avatarTone ?? record.avatar_tone), avatarDataUrl: text(record.avatarDataUrl ?? record.avatar_data_url), prompt: text(record.prompt), skillIds: stringArray(record.skillIds ?? record.skill_ids), createdAt: text(record.createdAt ?? record.created_at), updatedAt: text(record.updatedAt ?? record.updated_at), }) as UserSyncPartner; } export function toServerUserSyncPreferences(input: unknown): UnknownRecord { const preferences = toUserSyncPreferences(input); return compact({ theme: preferences.theme, language: preferences.language, default_model: preferences.defaultModel, default_provider_account_id: preferences.defaultProviderAccountId, sidebar_collapsed: preferences.sidebarCollapsed, dev_mode_unlocked: preferences.devModeUnlocked, selected_bundles: preferences.selectedBundles, enabled_skills: preferences.enabledSkills, disabled_skills: preferences.disabledSkills, }); } export function toServerUserSyncProviderAccount(input: unknown): UnknownRecord { const account = toUserSyncProviderAccount(input); return compact({ id: account.id, vendor_id: account.vendorId, label: account.label, auth_mode: account.authMode, base_url: account.baseUrl, api_protocol: account.apiProtocol, model: account.model, fallback_models: account.fallbackModels, fallback_account_ids: account.fallbackAccountIds, enabled: account.enabled, is_default: account.isDefault, metadata: account.metadata, updated_at: account.updatedAt, }); } export function toServerUserSyncPartner(input: unknown): UnknownRecord { const partner = toUserSyncPartner(input); return compact({ id: partner.id, display_name: partner.displayName, template_role_id: partner.templateRoleId, description: partner.description, avatar_tone: partner.avatarTone, avatar_data_url: partner.avatarDataUrl, prompt: partner.prompt, skill_ids: partner.skillIds, created_at: partner.createdAt, updated_at: partner.updatedAt, }); } export function normalizeUserSyncBootstrap(input: unknown): UserSyncBootstrap { const record = isRecord(input) ? input : {}; const rawProviderAccounts = record.providerAccounts ?? record.provider_accounts; const rawPartners = record.partners; const rawUsageAggregates = record.usageAggregates ?? record.usage_aggregates; const providerAccounts = Array.isArray(rawProviderAccounts) ? rawProviderAccounts.map(toUserSyncProviderAccount).filter(hasProviderIdentity) : []; const partners = Array.isArray(rawPartners) ? rawPartners.map(toUserSyncPartner).filter(hasPartnerIdentity) : []; const usageAggregates = Array.isArray(rawUsageAggregates) ? rawUsageAggregates.map(toUserSyncUsageAggregate).filter(hasUsageDate) : []; return { preferences: toUserSyncPreferences(record.preferences), providerAccounts, partners, usageAggregates, }; } function hasProviderIdentity(account: UserSyncProviderAccount): boolean { return Boolean(account.id && account.vendorId && account.label && account.authMode); } function hasPartnerIdentity(partner: UserSyncPartner): boolean { return Boolean(partner.id && partner.displayName); } function hasUsageDate(aggregate: UserSyncUsageAggregate): boolean { return Boolean(aggregate.date); } function toUserSyncUsageAggregate(input: unknown): UserSyncUsageAggregate { const record = isRecord(input) ? input : {}; return compact({ date: text(record.date), model: text(record.model), providerAccountId: text(record.providerAccountId ?? record.provider_account_id), inputTokens: numberValue(record.inputTokens ?? record.input_tokens) ?? 0, outputTokens: numberValue(record.outputTokens ?? record.output_tokens) ?? 0, cacheReadTokens: numberValue(record.cacheReadTokens ?? record.cache_read_tokens) ?? 0, cacheWriteTokens: numberValue(record.cacheWriteTokens ?? record.cache_write_tokens) ?? 0, estimatedCostUsd: numberValue(record.estimatedCostUsd ?? record.estimated_cost_usd) ?? 0, requestCount: numberValue(record.requestCount ?? record.request_count) ?? 0, }) as UserSyncUsageAggregate; }