import type { ServerConfig, ServerConfigStreamEvent } from "@t3tools/contracts"; import * as Option from "effect/Option"; export interface ServerConfigProjection { readonly config: ServerConfig; readonly latestEvent: ServerConfigStreamEvent; readonly source: "cache" | "live"; } /** * Cached config keeps the provider and model catalog available across reconnects. * Published themes are current machine state, so a cache could restore themes * that the machine no longer publishes. Replay sends themes as a separate event. */ export function withoutEnvironmentThemes(config: ServerConfig): ServerConfig { if (config.environmentThemes === undefined) return config; const { environmentThemes: _ephemeral, ...rest } = config; return rest; } export function applyServerConfigProjection( current: Option.Option, event: ServerConfigStreamEvent, ): Option.Option { switch (event.type) { case "snapshot": { // Wire snapshots never contain published themes. Keep the previous set // until a capable server sends its authoritative theme event. A legacy // server cannot send a later removal, so a downgrade must clear the set. const carried = event.config.environment.capabilities.environmentThemes === true && Option.isSome(current) ? current.value.config.environmentThemes : undefined; return Option.some({ config: carried === undefined ? event.config : { ...event.config, environmentThemes: carried }, latestEvent: event, source: "live" as const, }); } case "keybindingsUpdated": return Option.map(current, (projection) => ({ config: { ...projection.config, keybindings: event.payload.keybindings, issues: event.payload.issues, }, latestEvent: event, source: "live", })); case "providerStatuses": return Option.map(current, (projection) => ({ config: { ...projection.config, providers: event.payload.providers, }, latestEvent: event, source: "live", })); case "settingsUpdated": return Option.map(current, (projection) => ({ config: { ...projection.config, settings: event.payload.settings, }, latestEvent: event, source: "live", })); case "environmentThemesUpdated": return Option.map(current, (projection) => ({ config: { ...projection.config, environmentThemes: event.payload.themes.length > 0 ? event.payload.themes : undefined, }, latestEvent: event, source: "live", })); } }