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 and usage-limit sources are current machine state, so a * cache could restore a set the machine no longer reports. Replay sends both * as separate events. */ export function withoutEnvironmentThemes(config: ServerConfig): ServerConfig { if (config.environmentThemes === undefined && config.usageLimitSources === undefined) { return config; } const { environmentThemes: _themes, usageLimitSources: _sources, ...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 capabilities = event.config.environment.capabilities; const carriedThemes = capabilities.environmentThemes === true && Option.isSome(current) ? current.value.config.environmentThemes : undefined; const carriedSources = capabilities.usageLimitSources === true && Option.isSome(current) ? current.value.config.usageLimitSources : undefined; return Option.some({ config: { ...event.config, ...(carriedThemes === undefined ? {} : { environmentThemes: carriedThemes }), ...(carriedSources === undefined ? {} : { usageLimitSources: carriedSources }), }, 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", })); case "usageLimitSourcesUpdated": return Option.map(current, (projection) => ({ config: { ...projection.config, usageLimitSources: event.payload.sources.length > 0 ? event.payload.sources : undefined, }, latestEvent: event, source: "live", })); } }