feat(keys): first-class BYOK key management — store, catalog, /api/keys
The auth/keys wave (2026-09-19): the server now owns the flat auth.json map directly (LH_AUTH_FILE from main.cjs; repo-root auth.json in dev, gitignored). The store reflects itself into the child's env at boot with fill-gap precedence — real env (incl. .env.local in dev) always wins — so every consumer keeps its plain process.env reads and saved keys take effect immediately, no restart; main.cjs's spawn-time injection retired (an env copy would shadow every settings-page change). Curated 4-key catalog (OpenRouter, Deepgram, Google search pair) with shape-only validation (no live pings — owner decision), 400s on bad pastes, last-4+length masking (plaintext never leaves the store), unknown file vars preserved + surfaced. Routes: GET /api/keys, PUT/DELETE /api/keys/:id. Tests: catalog/store/composition, with the env-sanitizing prologue (a dev shell may export real keys; tests use throwaway values only).
This commit is contained in:
@@ -190,3 +190,23 @@ export interface PromptOverrideStore {
|
||||
* on-switch with no file composes the source default, inert). */
|
||||
deleteOverride(segmentPath: string): void;
|
||||
}
|
||||
|
||||
// ─── AuthStore — BYOK provider keys (auth-keys wave, 2026-09-19) ────────────
|
||||
|
||||
/**
|
||||
* The long-standing flat {VAR: value} auth.json map (config.AUTH_FILE) —
|
||||
* the same file the Electron app has always hand-edited, now first-class
|
||||
* server-managed. Values are opaque strings: shape validation is a
|
||||
* server-band concern (core/auth-keys.ts validateKeyShape — the store
|
||||
* persists what it is given); env precedence is a server-band concern
|
||||
* too (src/server/keys.ts). Unknown vars ride along verbatim.
|
||||
*/
|
||||
export interface AuthStore {
|
||||
/** The whole map — absent or corrupt file = {} ("no keys yet", the
|
||||
* documented first-boot state). Never throws. */
|
||||
authVars(): Record<string, string>;
|
||||
/** Set one VAR (atomic write, mode 0600 always, other vars preserved). */
|
||||
setAuthVar(name: string, value: string): void;
|
||||
/** Remove one VAR if present (absent = no-op, still a silent success). */
|
||||
deleteAuthVar(name: string): void;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user