Files

1 line
6.7 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"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"}}}}