/**
 * SettingsResolver — single read-side entry point. Implements the
 * precedence chain:
 *
 *   bootstrap     → env > default        (env-only; no store layer)
 *   workspace-*   → store > default      (env is NOT consulted at resolve time)
 *   user-*        → handled by auth.db readers (not this module)
 *
 * Env values for workspace-* keys are read ONCE by the first-run importer
 * and mirrored into the store on cold boot; after that, the store is
 * canonical. This avoids the "env shadows store" confusion that the UI
 * banner used to apologise for — if a user updates ANTHROPIC_API_KEY in
 * Railway after the importer has run, the change is silently ignored
 * until they update via the UI or CLI.
 *
 * Studiograph is single-workspace-per-process: the deployment IS the
 * workspace, so there is no separate "instance" tier and no scope
 * cascade. The old `'store-workspace'` and `'store-instance'` source
 * values collapse to a single `'store'`.
 */
import { getKeyDef } from './registry.js';
export class SettingsResolver {
    deps;
    constructor(deps) {
        this.deps = deps;
    }
    /**
     * Resolve a key by canonical name. Returns the parsed value plus the
     * source that won. Caller is responsible for handling `undefined` —
     * the resolver does not throw on missing values.
     */
    resolveWithSource(name, ctx = {}) {
        const def = getKeyDef(name);
        if (!def) {
            throw new Error(`SettingsResolver: unknown key "${name}". Add it to the registry.`);
        }
        return this.resolveDef(def, ctx);
    }
    resolve(name, ctx = {}) {
        return this.resolveWithSource(name, ctx).value;
    }
    resolveDef(def, ctx) {
        // Bootstrap: env-only. These keys (master.key, jwt.secret, the CLI
        // credentials, railway.token) load before the encrypted store exists,
        // so they have no store layer to read from. Env wins; fall through to
        // default.
        if (def.classification === 'bootstrap') {
            for (const alias of def.envAliases) {
                const raw = process.env[alias];
                if (raw === undefined || raw === '')
                    continue;
                return { value: raw, source: 'env', envAlias: alias };
            }
            return { value: def.default, source: def.default !== undefined ? 'default' : 'unset' };
        }
        // Workspace-* keys: store > default. Env is NOT consulted at resolve
        // time — the first-run importer mirrors env into the store on cold
        // boot, then env stops being read. Operators who update env after
        // the importer has run must update via UI or CLI for the change to
        // take effect.
        if (def.classification === 'workspace-secret' ||
            def.classification === 'workspace-setting') {
            const fromStore = this.readFromStore(def);
            if (fromStore !== undefined)
                return { value: fromStore, source: 'store' };
        }
        if (def.default !== undefined) {
            return { value: def.default, source: 'default' };
        }
        return { value: undefined, source: 'unset' };
    }
    readFromStore(def) {
        if (def.classification.endsWith('-secret')) {
            const v = this.deps.secrets.unsafeGetForResolver(def.name);
            return v;
        }
        return this.deps.settings.get(def.name);
    }
}
//# sourceMappingURL=SettingsResolver.js.map