1 line
6.7 KiB
JSON
1 line
6.7 KiB
JSON
{"repo": "1lurgee/mimo-web-search-mcp", "files": {"src/config.ts": {"ea3d3b0845e6fc948928931767698b31ea0bc24b": {"t": 1785595157.093984, "n": 5463, "h": "86f6cbabf923d8cc", "c": "/** 应用配置管理 */\n\n/** 日志级别枚举 */\nexport enum LogLevel {\n ERROR = 0,\n WARN = 1,\n INFO = 2,\n DEBUG = 3,\n}\n\n/** 配置接口 */\nexport interface AppConfig {\n /** MiMo API 密钥 */\n apiKey: string;\n /** API 基础 URL */\n baseUrl: string;\n /** 模型名称 */\n model: string;\n /** 请求超时时间(毫秒) */\n requestTimeout: number;\n /** 最大生成 token 数 */\n maxCompletionTokens: number;\n /** 采样温度 */\n temperature: number;\n /** 核采样概率 */\n topP: number;\n /** 启用思考模式 */\n thinking: boolean;\n /** 日志级别 */\n logLevel: LogLevel;\n /** 最大重试次数 */\n maxRetries: number;\n /** 重试延迟(毫秒) */\n retryDelay: number;\n /** 最大内容长度 */\n maxContentLength: number;\n /** 最大并发请求数 */\n maxConcurrent: number;\n /** 默认最大关键词数 */\n defaultMaxKeyword: number;\n /** 默认返回结果数 */\n defaultLimit: number;\n /** 查询最大字符数 */\n maxQueryLength: number;\n /** 网页抓取最大内容大小(字节) */\n maxFetchSize: number;\n /** 网页抓取超时时间(毫秒) */\n fetchTimeout: number;\n /** 启用浏览器渲染(SPA 降级,需先安装 playwright) */\n enableBrowser: boolean;\n /** 超长内容无 prompt 时是否自动调用 MiMo API 摘要(默认 true) */\n autoSummary: boolean;\n}\n\n/**\n * 解析环境变量为整数,失败返回默认值,限制在 [min, max] 范围内\n * @param value - 环境变量原始值\n * @param defaultValue - 默认值\n * @param min - 最小值(含)\n * @param max - 最大值(含)\n */\nfunction parseIntEnv(value: string | undefined, defaultValue: number, min: number, max: number): number {\n if (!value) return defaultValue;\n const parsed = parseInt(value, 10);\n if (isNaN(parsed)) return defaultValue;\n return Math.max(min, Math.min(max, parsed));\n}\n\n/**\n * 解析环境变量为浮点数,失败返回默认值,限制在 [min, max] 范围内\n * @param value - 环境变量原始值\n * @param defaultValue - 默认值\n * @param min - 最小值(含)\n * @param max - 最大值(含)\n */\nfunction parseFloatEnv(value: string | undefined, defaultValue: number, min: number, max: number): number {\n if (!value) return defaultValue;\n const parsed = parseFloat(value);\n if (isNaN(parsed)) return defaultValue;\n return Math.max(min, Math.min(max, parsed));\n}\n\n/** 解析环境变量为布尔值,失败返回默认值 */\nfunction parseBoolEnv(value: string | undefined, defaultValue: boolean): boolean {\n if (!value) return defaultValue;\n return value === \"true\" || value === \"1\";\n}\n\n\n/**\n * 验证 API 基础 URL 格式,限制为 HTTPS 协议\n * 防止 SSRF 攻击:禁止 file://、ftp:// 等非 HTTP(S) 协议\n * 注意:与 ssrf.ts 的 validateUrl(允许 http/https)语义不同——此处仅用于校验 MIMO_BASE_URL\n */\nfunction validateApiUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\n/**\n * 获取脱敏配置(安全打印到日志)\n *\n * 借鉴 grok-build 设计:api_key 被替换为 \"***REDACTED***\"\n */\nexport function getRedactedConfig(config: AppConfig): Partial<AppConfig> {\n return {\n ...config,\n apiKey: \"***REDACTED***\",\n };\n}\n\n// ── 单例缓存 ─────────────────────────────────────────\n// 首次调用解析并缓存,后续直接返回同一实例。\n// 避免 10+ 个模块各自 loadConfig() 创建独立副本,也避免缺少 MIMO_API_KEY 时\n// 每个模块 import 阶段都抛一遍异常。\nlet _cachedConfig: Readonly<AppConfig> | null = null;\n\n/** 加载并验证配置(单例:首次调用后缓存结果) */\nexport function loadConfig(): Readonly<AppConfig> {\n if (_cachedConfig) return _cachedConfig;\n\n const apiKey = process.env.MIMO_API_KEY;\n if (!apiKey) {\n throw new Error(\"MIMO_API_KEY environment variable is required.\");\n }\n\n const baseUrl = (process.env.MIMO_BASE_URL || \"https://api.xiaomimimo.com/v1\").replace(/\\/+$/, \"\");\n if (!validateApiUrl(baseUrl)) {\n throw new Error(`Invalid MIMO_BASE_URL format: ${baseUrl}`);\n }\n\n const debugValue = process.env.DEBUG;\n let logLevel: LogLevel;\n if (debugValue && /^\\d+$/.test(debugValue)) {\n // 纯数字:0=ERROR, 1=INFO, 2+=DEBUG\n const level = parseInt(debugValue, 10);\n logLevel = level >= 2 ? LogLevel.DEBUG : level >= 1 ? LogLevel.INFO : LogLevel.ERROR;\n } else if (debugValue && /mimo/i.test(debugValue)) {\n // 命名空间模式:DEBUG=mimo*、DEBUG=mimo-web-search 等\n logLevel = LogLevel.DEBUG;\n } else {\n logLevel = LogLevel.ERROR;\n }\n\n _cachedConfig = Object.freeze({\n apiKey,\n baseUrl,\n model: process.env.MIMO_MODEL || \"mimo-v2.5\",\n requestTimeout: parseIntEnv(process.env.REQUEST_TIMEOUT, 60000, 1000, 300000), // 1秒 ~ 5分钟\n maxCompletionTokens: parseIntEnv(process.env.MAX_COMPLETION_TOKENS, 1024, 1, 100000),\n temperature: parseFloatEnv(process.env.TEMPERATURE, 0.3, 0, 1.5),\n topP: parseFloatEnv(process.env.TOP_P, 0.95, 0.01, 1.0),\n thinking: parseBoolEnv(process.env.MIMO_THINKING, false),\n logLevel,\n maxRetries: parseIntEnv(process.env.MAX_RETRIES, 2, 0, 10), // 0 ~ 10 次\n retryDelay: parseIntEnv(process.env.RETRY_DELAY, 1000, 100, 60000), // 100ms ~ 1分钟\n maxContentLength: parseIntEnv(process.env.MAX_CONTENT_LENGTH, 100000, 1000, 1000000), // 1KB ~ 1MB\n maxConcurrent: parseIntEnv(process.env.MAX_CONCURRENT, 10, 1, 100), // 1 ~ 100\n defaultMaxKeyword: parseIntEnv(process.env.DEFAULT_MAX_KEYWORD, 3, 1, 50), // 1 ~ 50\n defaultLimit: parseIntEnv(process.env.DEFAULT_LIMIT, 5, 1, 50), // 1 ~ 50\n maxQueryLength: parseIntEnv(process.env.MAX_QUERY_LENGTH, 10000, 100, 100000), // 100 ~ 100K 字符\n maxFetchSize: parseIntEnv(process.env.MAX_FETCH_SIZE, 10485760, 1024, 10485760), // 1KB ~ 10MB(对齐 Claude Code MAX_HTTP_CONTENT_LENGTH)\n fetchTimeout: parseIntEnv(process.env.FETCH_TIMEOUT, 30000, 5000, 120000), // 5秒 ~ 2分钟\n enableBrowser: parseBoolEnv(process.env.MIMO_ENABLE_BROWSER, false), // 浏览器渲染(SPA 降级)\n autoSummary: parseBoolEnv(process.env.MIMO_AUTO_SUMMARY, true), // 超长内容自动摘要\n });\n return _cachedConfig;\n}\n"}}}} |