/** * Client controller for model-proxy settings card. * Binds to `model-proxy` namespace via ctx.settingsScope and exposes * a small observable store for the card. */ import type { SettingsScope } from '@deepseek-ai/dsh-client-runtime/client'; import type { DirectoryMirror } from './catalog.js'; export type ProxyHost = { /** Stable key referenced by rules and the optional default host. */ id: string; name: string; proxyUrl: string; /** Credentials-service entry ("user:password") for this host. */ credentialRef?: string; }; export type HeaderValueSource = 'fixed' | 'sessionId' | 'provider' | 'model' | 'purpose'; export type HeaderSources = Record; export type HeaderEditorRow = { key: string; name: string; value: string; source: HeaderValueSource; }; export type ProxyRule = { /** Card key; may be absent on hand-written yaml rules until edited here. */ id?: string; provider: string; model: string; /** Reusable host selected from proxyHosts; absent means direct. */ proxyHostId?: string; /** Legacy inline URL; used only when proxyHostId is absent. */ proxyUrl?: string; enabled: boolean; /** Only apply to calls with this GenerateOptions.purpose; empty = all. */ purpose?: string; /** Legacy per-rule credential override; new UI stores this on ProxyHost. */ credentialRef?: string; /** Extra headers injected for this rule, including direct mode. */ headers?: Record; /** Header names whose values come from the request context. */ headerValueSources?: Record; }; export type ModelProxyConfig = { enabled: boolean; proxyHosts: ProxyHost[]; rules: ProxyRule[]; /** Host used when no rule matches; absent/empty means direct. */ defaultProxyHostId?: string; /** Legacy inline fallback URL; empty when defaultProxyHostId is used. */ defaultProxy: string; debug: boolean; /** Host-computed directory mirror; never edited by the card. */ catalog?: DirectoryMirror; }; export type ModelProxySnapshot = { status: 'loading' | 'ready' | 'unavailable'; value?: ModelProxyConfig; revision?: number; writable: boolean; error?: string; }; type Listener = () => void; /** * Strip unknown keys before persisting rules. * Dropped keys are logged so legacy fields do not disappear silently. */ export declare function sanitizeRules(rules: ProxyRule[]): ProxyRule[]; /** Stable-enough client-side id for rule cards (React keys / list diffs). */ export declare function makeRuleId(): string; /** Stable-enough client-side id for reusable proxy hosts. */ export declare function makeProxyHostId(): string; /** Strip unknown keys from drafted proxy hosts before persisting. */ export declare function sanitizeHosts(hosts: ProxyHost[]): ProxyHost[]; /** Migrate legacy inline URLs into reusable host entries. */ export declare function normalizeConfig(input: ModelProxyConfig): ModelProxyConfig; /** One "batch add" spec: shared fields + the model patterns to fan out over. */ export type CreatorSpec = { provider: string; /** Model ids / wildcard patterns; one rule each. Duplicates collapse. */ models: string[]; /** New UI host reference; absent means direct. */ proxyHostId?: string; /** Legacy inline URL retained for hand-written/test callers. */ proxyUrl?: string; purpose?: string; credentialRef?: string; headers?: Record; headerValueSources?: Record; enabled?: boolean; }; /** * Render a headers map as editable text: one `Name: value` per line. * Used by the card's per-rule and creator inputs. */ export declare function formatHeadersText(headers: Record | undefined): string; /** Parse `Name: value` lines; invalid input returns a displayable error. */ export declare function parseHeadersText(text: string): { headers?: Record; error?: string; }; /** Convert editable Header rows into fixed and request-context values. */ export declare function parseHeaderRows(rows: readonly HeaderEditorRow[]): { headers?: Record; sources?: HeaderSources; error?: string; }; /** Fan one creator spec out into one rule per model. */ export declare function buildCreatorRules(spec: CreatorSpec): ProxyRule[]; /** Group rules by provider, preserving input order within each group. */ export declare function groupByProvider(rules: ProxyRule[]): Array<{ provider: string; rules: ProxyRule[]; }>; /** Add stable UI-only ids to rules that came from hand-written config. */ export declare function ensureRuleIds(cfg: ModelProxyConfig): ModelProxyConfig; export declare class ModelProxyController { private readonly scope; private listeners; private snapshot; private unsub?; constructor(scope: SettingsScope); bind(): void; dispose(): void; subscribe(l: Listener): () => void; getSnapshot(): ModelProxySnapshot; private pull; private emit; /** * Persist reusable hosts before rules so references are serviceable as soon * as the rule write lands. The remaining scalar fields are written after the * two collection fields; the settings scope intentionally exposes per-field * writes rather than one atomic document replacement. */ save(next: ModelProxyConfig): Promise; setEnabled(v: boolean): Promise; setDebug(v: boolean): Promise; } export {}; //# sourceMappingURL=controller.d.ts.map