/** * Plugin config resolution. * * The plugin deliberately uses no runtime imports (no schemastery, no * dsh-tools): a workspace-linked bundle resolves bare `@deepseek-ai/*` * specifiers from its own directory, so it cannot see the dsh installation's * packages. Everything here is plain ESM so `node scripts/live-check.mjs` can * exercise it before the bundle is installed. */ /** Environment variable read when `cookie` is empty. */ export const DEFAULT_COOKIE_ENV = 'ACFUN_COOKIE' /** Per-request timeout in milliseconds. */ export const DEFAULT_REQUEST_TIMEOUT_MS = 30_000 /** Cooperative per-tool-call budget in milliseconds. */ export const DEFAULT_TOOL_TIMEOUT_MS = 45_000 /** Cooperative budget for a write call (login + token + action). */ export const DEFAULT_WRITE_TIMEOUT_MS = 60_000 /** Largest list size the rank tool accepts (server caps around this). */ export const RANK_MAX_LIMIT = 50 const DEFAULTS = Object.freeze({ cookie: '', cookieEnv: DEFAULT_COOKIE_ENV, allowWriteActions: false, requestTimeoutMs: DEFAULT_REQUEST_TIMEOUT_MS, timeoutMs: DEFAULT_TOOL_TIMEOUT_MS, }) /** A non-empty trimmed string, or undefined. */ function text(value) { return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined } /** A positive finite number, or undefined. */ function positive(value) { return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : undefined } /** * Resolve the row config into a plain settings object. * * Unknown keys are ignored on purpose: the profile patch may carry comments or * keys from an older version, and a stale key must not block activation. * * @param {unknown} raw - the Loader row `config` object, possibly undefined. * @param {NodeJS.ProcessEnv | Record} [env] - environment for `cookieEnv`. * @returns {{cookie: string, cookieEnv: string, allowWriteActions: boolean, requestTimeoutMs: number, timeoutMs: number, warnings: string[]}} */ export function resolveConfig(raw, env = process.env) { const source = raw !== null && typeof raw === 'object' && !Array.isArray(raw) ? raw : {} const warnings = [] if (raw !== undefined && (raw === null || typeof raw !== 'object' || Array.isArray(raw))) { warnings.push('config must be an object; using defaults') } const cookieEnv = text(source.cookieEnv) ?? DEFAULT_COOKIE_ENV const literalCookie = text(source.cookie) const envCookie = text(env?.[cookieEnv]) const cookie = literalCookie ?? envCookie ?? '' if (source.cookie !== undefined && source.cookie !== '' && literalCookie === undefined) { warnings.push('config.cookie is set but is not a non-empty string; ignoring it') } if (typeof source.allowWriteActions !== 'undefined' && typeof source.allowWriteActions !== 'boolean') { warnings.push('config.allowWriteActions is not a boolean; using false') } return { cookie, cookieEnv, cookieSource: literalCookie !== undefined ? 'config' : envCookie !== undefined ? 'env' : 'none', allowWriteActions: source.allowWriteActions === true, requestTimeoutMs: positive(source.requestTimeoutMs) ?? DEFAULT_REQUEST_TIMEOUT_MS, timeoutMs: positive(source.timeoutMs) ?? DEFAULT_TOOL_TIMEOUT_MS, warnings, } }