webaiapi 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +184 -2
  3. package/bin/webapi.mjs +45 -0
  4. package/dist/browser/auth-capture.d.ts +110 -0
  5. package/dist/browser/auth-capture.d.ts.map +1 -0
  6. package/dist/browser/auth-capture.js +487 -0
  7. package/dist/browser/auth-capture.js.map +1 -0
  8. package/dist/browser/credentials.d.ts +102 -0
  9. package/dist/browser/credentials.d.ts.map +1 -0
  10. package/dist/browser/credentials.js +209 -0
  11. package/dist/browser/credentials.js.map +1 -0
  12. package/dist/browser/js-eval.d.ts +44 -0
  13. package/dist/browser/js-eval.d.ts.map +1 -0
  14. package/dist/browser/js-eval.js +20 -0
  15. package/dist/browser/js-eval.js.map +1 -0
  16. package/dist/browser/login-flow.d.ts +171 -0
  17. package/dist/browser/login-flow.d.ts.map +1 -0
  18. package/dist/browser/login-flow.js +606 -0
  19. package/dist/browser/login-flow.js.map +1 -0
  20. package/dist/browser/manager.d.ts +144 -0
  21. package/dist/browser/manager.d.ts.map +1 -0
  22. package/dist/browser/manager.js +586 -0
  23. package/dist/browser/manager.js.map +1 -0
  24. package/dist/browser/platforms.d.ts +96 -0
  25. package/dist/browser/platforms.d.ts.map +1 -0
  26. package/dist/browser/platforms.js +288 -0
  27. package/dist/browser/platforms.js.map +1 -0
  28. package/dist/browser/sse-capture.d.ts +23 -0
  29. package/dist/browser/sse-capture.d.ts.map +1 -0
  30. package/dist/browser/sse-capture.js +199 -0
  31. package/dist/browser/sse-capture.js.map +1 -0
  32. package/dist/browser/stealth.d.ts +12 -0
  33. package/dist/browser/stealth.d.ts.map +1 -0
  34. package/dist/browser/stealth.js +12 -0
  35. package/dist/browser/stealth.js.map +1 -0
  36. package/dist/cli.d.ts +12 -0
  37. package/dist/cli.d.ts.map +1 -0
  38. package/dist/cli.js +441 -0
  39. package/dist/cli.js.map +1 -0
  40. package/dist/config.d.ts +90 -0
  41. package/dist/config.d.ts.map +1 -0
  42. package/dist/config.js +246 -0
  43. package/dist/config.js.map +1 -0
  44. package/dist/controllers/history-db.d.ts +56 -0
  45. package/dist/controllers/history-db.d.ts.map +1 -0
  46. package/dist/controllers/history-db.js +260 -0
  47. package/dist/controllers/history-db.js.map +1 -0
  48. package/dist/controllers/request-pool.d.ts +78 -0
  49. package/dist/controllers/request-pool.d.ts.map +1 -0
  50. package/dist/controllers/request-pool.js +222 -0
  51. package/dist/controllers/request-pool.js.map +1 -0
  52. package/dist/controllers/router.d.ts +172 -0
  53. package/dist/controllers/router.d.ts.map +1 -0
  54. package/dist/controllers/router.js +569 -0
  55. package/dist/controllers/router.js.map +1 -0
  56. package/dist/index.d.ts +72 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +61 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/log/api-logger.d.ts +55 -0
  61. package/dist/log/api-logger.d.ts.map +1 -0
  62. package/dist/log/api-logger.js +264 -0
  63. package/dist/log/api-logger.js.map +1 -0
  64. package/dist/log/debug-logger.d.ts +49 -0
  65. package/dist/log/debug-logger.d.ts.map +1 -0
  66. package/dist/log/debug-logger.js +285 -0
  67. package/dist/log/debug-logger.js.map +1 -0
  68. package/dist/log/logger.d.ts +16 -0
  69. package/dist/log/logger.d.ts.map +1 -0
  70. package/dist/log/logger.js +35 -0
  71. package/dist/log/logger.js.map +1 -0
  72. package/dist/postinstall.d.ts +3 -0
  73. package/dist/postinstall.d.ts.map +1 -0
  74. package/dist/postinstall.js +90 -0
  75. package/dist/postinstall.js.map +1 -0
  76. package/dist/providers/base.d.ts +83 -0
  77. package/dist/providers/base.d.ts.map +1 -0
  78. package/dist/providers/base.js +51 -0
  79. package/dist/providers/base.js.map +1 -0
  80. package/dist/providers/chatglm-dom-extract.d.ts +24 -0
  81. package/dist/providers/chatglm-dom-extract.d.ts.map +1 -0
  82. package/dist/providers/chatglm-dom-extract.js +175 -0
  83. package/dist/providers/chatglm-dom-extract.js.map +1 -0
  84. package/dist/providers/chatglm-dom.d.ts +110 -0
  85. package/dist/providers/chatglm-dom.d.ts.map +1 -0
  86. package/dist/providers/chatglm-dom.js +384 -0
  87. package/dist/providers/chatglm-dom.js.map +1 -0
  88. package/dist/providers/chatglm-sse.d.ts +119 -0
  89. package/dist/providers/chatglm-sse.d.ts.map +1 -0
  90. package/dist/providers/chatglm-sse.js +241 -0
  91. package/dist/providers/chatglm-sse.js.map +1 -0
  92. package/dist/providers/chatglm.d.ts +288 -0
  93. package/dist/providers/chatglm.d.ts.map +1 -0
  94. package/dist/providers/chatglm.js +1631 -0
  95. package/dist/providers/chatglm.js.map +1 -0
  96. package/dist/routes/chat.d.ts +117 -0
  97. package/dist/routes/chat.d.ts.map +1 -0
  98. package/dist/routes/chat.js +1346 -0
  99. package/dist/routes/chat.js.map +1 -0
  100. package/dist/routes/compress.d.ts +142 -0
  101. package/dist/routes/compress.d.ts.map +1 -0
  102. package/dist/routes/compress.js +551 -0
  103. package/dist/routes/compress.js.map +1 -0
  104. package/dist/routes/failover.d.ts +34 -0
  105. package/dist/routes/failover.d.ts.map +1 -0
  106. package/dist/routes/failover.js +221 -0
  107. package/dist/routes/failover.js.map +1 -0
  108. package/dist/routes/helpers.d.ts +174 -0
  109. package/dist/routes/helpers.d.ts.map +1 -0
  110. package/dist/routes/helpers.js +525 -0
  111. package/dist/routes/helpers.js.map +1 -0
  112. package/dist/routes/meta.d.ts +31 -0
  113. package/dist/routes/meta.d.ts.map +1 -0
  114. package/dist/routes/meta.js +184 -0
  115. package/dist/routes/meta.js.map +1 -0
  116. package/dist/routes/sse.d.ts +82 -0
  117. package/dist/routes/sse.d.ts.map +1 -0
  118. package/dist/routes/sse.js +77 -0
  119. package/dist/routes/sse.js.map +1 -0
  120. package/dist/server/app.d.ts +24 -0
  121. package/dist/server/app.d.ts.map +1 -0
  122. package/dist/server/app.js +292 -0
  123. package/dist/server/app.js.map +1 -0
  124. package/dist/server/middleware/api-key.d.ts +61 -0
  125. package/dist/server/middleware/api-key.d.ts.map +1 -0
  126. package/dist/server/middleware/api-key.js +95 -0
  127. package/dist/server/middleware/api-key.js.map +1 -0
  128. package/dist/server/middleware/rate-limit.d.ts +67 -0
  129. package/dist/server/middleware/rate-limit.d.ts.map +1 -0
  130. package/dist/server/middleware/rate-limit.js +134 -0
  131. package/dist/server/middleware/rate-limit.js.map +1 -0
  132. package/dist/server/middleware/timeout.d.ts +34 -0
  133. package/dist/server/middleware/timeout.d.ts.map +1 -0
  134. package/dist/server/middleware/timeout.js +64 -0
  135. package/dist/server/middleware/timeout.js.map +1 -0
  136. package/dist/server/types.d.ts +20 -0
  137. package/dist/server/types.d.ts.map +1 -0
  138. package/dist/server/types.js +2 -0
  139. package/dist/server/types.js.map +1 -0
  140. package/dist/tools/build.d.ts +14 -0
  141. package/dist/tools/build.d.ts.map +1 -0
  142. package/dist/tools/build.js +105 -0
  143. package/dist/tools/build.js.map +1 -0
  144. package/dist/tools/clean.d.ts +32 -0
  145. package/dist/tools/clean.d.ts.map +1 -0
  146. package/dist/tools/clean.js +65 -0
  147. package/dist/tools/clean.js.map +1 -0
  148. package/dist/tools/convert.d.ts +50 -0
  149. package/dist/tools/convert.d.ts.map +1 -0
  150. package/dist/tools/convert.js +289 -0
  151. package/dist/tools/convert.js.map +1 -0
  152. package/dist/tools/names.d.ts +138 -0
  153. package/dist/tools/names.d.ts.map +1 -0
  154. package/dist/tools/names.js +578 -0
  155. package/dist/tools/names.js.map +1 -0
  156. package/dist/tools/parse.d.ts +31 -0
  157. package/dist/tools/parse.d.ts.map +1 -0
  158. package/dist/tools/parse.js +273 -0
  159. package/dist/tools/parse.js.map +1 -0
  160. package/dist/tools/placeholder.d.ts +21 -0
  161. package/dist/tools/placeholder.d.ts.map +1 -0
  162. package/dist/tools/placeholder.js +135 -0
  163. package/dist/tools/placeholder.js.map +1 -0
  164. package/dist/tools/prompts.d.ts +42 -0
  165. package/dist/tools/prompts.d.ts.map +1 -0
  166. package/dist/tools/prompts.js +69 -0
  167. package/dist/tools/prompts.js.map +1 -0
  168. package/dist/tools/protocol.d.ts +58 -0
  169. package/dist/tools/protocol.d.ts.map +1 -0
  170. package/dist/tools/protocol.js +287 -0
  171. package/dist/tools/protocol.js.map +1 -0
  172. package/dist/tools/repair.d.ts +83 -0
  173. package/dist/tools/repair.d.ts.map +1 -0
  174. package/dist/tools/repair.js +510 -0
  175. package/dist/tools/repair.js.map +1 -0
  176. package/dist/tools/workspace.d.ts +40 -0
  177. package/dist/tools/workspace.d.ts.map +1 -0
  178. package/dist/tools/workspace.js +224 -0
  179. package/dist/tools/workspace.js.map +1 -0
  180. package/dist/types/message.d.ts +87 -0
  181. package/dist/types/message.d.ts.map +1 -0
  182. package/dist/types/message.js +85 -0
  183. package/dist/types/message.js.map +1 -0
  184. package/dist/types/openai.d.ts +100 -0
  185. package/dist/types/openai.d.ts.map +1 -0
  186. package/dist/types/openai.js +66 -0
  187. package/dist/types/openai.js.map +1 -0
  188. package/dist/utils/errors.d.ts +82 -0
  189. package/dist/utils/errors.d.ts.map +1 -0
  190. package/dist/utils/errors.js +115 -0
  191. package/dist/utils/errors.js.map +1 -0
  192. package/dist/utils/mutex.d.ts +31 -0
  193. package/dist/utils/mutex.d.ts.map +1 -0
  194. package/dist/utils/mutex.js +61 -0
  195. package/dist/utils/mutex.js.map +1 -0
  196. package/dist/utils/prompt.d.ts +150 -0
  197. package/dist/utils/prompt.d.ts.map +1 -0
  198. package/dist/utils/prompt.js +514 -0
  199. package/dist/utils/prompt.js.map +1 -0
  200. package/dist/utils/text.d.ts +30 -0
  201. package/dist/utils/text.d.ts.map +1 -0
  202. package/dist/utils/text.js +70 -0
  203. package/dist/utils/text.js.map +1 -0
  204. package/package.json +67 -4
  205. package/postinstall.mjs +34 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,kDAAkD;AAClD,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IAEf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAElB,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IAEvB,cAAc,EAAE,MAAM,CAAC;IAEvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IAEnB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,OAAO,CAAC;IAE1B,qBAAqB,EAAE,MAAM,CAAC;IAE9B,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;CACjB;AA2ED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAYvF;AAED,uBAAuB;AACvB,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CASpF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwBhE;AAED,wDAAwD;AACxD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO/C;AAED,MAAM,WAAW,mBAAmB;IAClC,mCAAmC;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,QAAQ,CAoDxE;AAMD,uDAAuD;AACvD,eAAO,MAAM,QAAQ,EAAE,QAAyB,CAAC;AAEjD,8DAA8D;AAC9D,wBAAgB,sBAAsB,CAAC,MAAM,GAAE,QAAmB,GAAG,MAAM,EAAE,CAM5E;AAED,uCAAuC;AACvC,wBAAgB,UAAU,CAAC,MAAM,GAAE,QAAmB,GAAG,GAAG,CAAC,MAAM,CAAC,CAQnE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,GAAE,QAAmB,EAC3B,MAAM,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAA4B,GACrD,MAAM,EAAE,CAUV"}
package/dist/config.js ADDED
@@ -0,0 +1,246 @@
1
+ /**
2
+ * 配置管理 —— `src/utils/config.py` 的 TypeScript 移植。
3
+ *
4
+ * 与原实现的差异(都是有意为之,已在 `.codebuddy/memory` 记录):
5
+ *
6
+ * 1. **零依赖**:不再用 pydantic-settings,`.env` 与进程环境变量由本模块自己读
7
+ * (自带极简 dotenv 解析,约 30 行)。
8
+ * 2. **`DEBUG` 兼容非布尔字符串**:实测某些系统预置 `DEBUG=release`,pydantic 会
9
+ * 直接校验失败导致服务起不来。Python 侧只能靠 `apis.sh` 在 shell 层兜底,
10
+ * 这里在**代码层**兜底并告警 —— 换任何启动方式都不会再踩。
11
+ * 3. **砍掉从未生效的配置**(用 `grep settings\\.<name>` 逐个核对过使用点):
12
+ * - `redis_url` / `max_instances` / `max_requests_per_instance` /
13
+ * `health_check_interval` / `request_queue_max_size`:**0 处引用**
14
+ * - `browser_pool.*` / `user_data_dir`:只被 `browser/pool.py` 引用(该模块
15
+ * 只在 `shutdown_event` 里调一次 `clear_all()`,池从未被填充,重写时丢弃)
16
+ * - `accounts` / `platforms`:只被 `load_config(config_file)` 的 YAML 分支引用,
17
+ * 而该函数始终以无参调用 → YAML 分支从未执行
18
+ */
19
+ import { readFileSync, statSync } from 'node:fs';
20
+ import { createRequire } from 'node:module';
21
+ import { logger } from './log/logger.js';
22
+ /** 环境变量名 → 字段名。键名与 pydantic-settings 的推导结果保持一致。 */
23
+ const ENV_KEYS = {
24
+ APP_NAME: 'appName',
25
+ APP_VERSION: 'appVersion',
26
+ DEBUG: 'debug',
27
+ API_HOST: 'apiHost',
28
+ API_PORT: 'apiPort',
29
+ API_PREFIX: 'apiPrefix',
30
+ BROWSER_HEADLESS: 'browserHeadless',
31
+ BROWSER_TIMEOUT: 'browserTimeout',
32
+ REQUEST_TIMEOUT: 'requestTimeout',
33
+ LOG_LEVEL: 'logLevel',
34
+ LOG_DIR: 'logDir',
35
+ DEBUG_LOGS: 'debugLogs',
36
+ AVAILABLE_MODELS: 'availableModels',
37
+ API_KEYS: 'apiKeys',
38
+ API_KEY_REQUIRED: 'apiKeyRequired',
39
+ RATE_LIMIT_PER_MINUTE: 'rateLimitPerMinute',
40
+ RATE_LIMIT_ENABLED: 'rateLimitEnabled',
41
+ DEFAULT_WORKSPACE_PATHS: 'defaultWorkspacePaths',
42
+ AUTH_DIR: 'authDir',
43
+ };
44
+ /**
45
+ * 从 `package.json` 读版本号。
46
+ *
47
+ * 为什么不写死:写死会出现「npm 上发的是 0.1.0、`/v1/health` 却报 0.2.0」这种
48
+ * 前后不一致(实测就踩到过:代码默认 0.2.0 / package.json 0.1.0 / .env 又写 0.1.0)。
49
+ * `package.json` 随包发布,作为唯一事实来源最可靠。
50
+ * ⚠️ 仍然允许用 `APP_VERSION` 环境变量覆盖。
51
+ */
52
+ function readPackageVersion() {
53
+ try {
54
+ const require = createRequire(import.meta.url);
55
+ const pkg = require('../package.json');
56
+ return pkg.version ?? '0.0.0';
57
+ }
58
+ catch {
59
+ return '0.0.0';
60
+ }
61
+ }
62
+ const DEFAULTS = {
63
+ appName: 'webaiapi',
64
+ appVersion: readPackageVersion(),
65
+ debug: false,
66
+ apiHost: '0.0.0.0',
67
+ apiPort: 8631,
68
+ apiPrefix: '/v1',
69
+ browserHeadless: true,
70
+ browserTimeout: 60,
71
+ requestTimeout: 300,
72
+ logLevel: 'INFO',
73
+ logDir: 'logs',
74
+ debugLogs: false,
75
+ availableModels: 'mix',
76
+ apiKeys: '',
77
+ apiKeyRequired: false,
78
+ rateLimitPerMinute: 60,
79
+ rateLimitEnabled: false,
80
+ defaultWorkspacePaths: '',
81
+ authDir: '~/.ai-api/auth',
82
+ };
83
+ const TRUE_VALUES = new Set(['true', '1', 'yes', 'on']);
84
+ const FALSE_VALUES = new Set(['false', '0', 'no', 'off', '']);
85
+ /**
86
+ * 宽松布尔解析。
87
+ *
88
+ * Python 版的 `Settings.debug: bool` 遇到 `DEBUG=release` 会直接抛
89
+ * `ValidationError`,导致服务完全起不来(`apis.sh` 里那段 shell 兜底就是为此)。
90
+ * 这里改为:能识别的按值解析,识别不了的回退默认值并告警。
91
+ *
92
+ * @param raw 原始字符串;`undefined` 表示未设置
93
+ * @param key 用于告警的键名
94
+ * @param fallback 无法识别时的回退值
95
+ */
96
+ export function toBool(raw, key, fallback) {
97
+ if (raw === undefined)
98
+ return fallback;
99
+ const norm = raw.trim().toLowerCase();
100
+ if (TRUE_VALUES.has(norm))
101
+ return true;
102
+ if (FALSE_VALUES.has(norm))
103
+ return false;
104
+ console.warn(`[config] 环境变量 ${key}='${raw}' 不是合法布尔值,已回退为 ${fallback}` +
105
+ `(Python 版会因此启动失败,这里做了兼容)`);
106
+ return fallback;
107
+ }
108
+ /** 整数解析;非法值回退默认并告警。 */
109
+ export function toInt(raw, key, fallback) {
110
+ if (raw === undefined || raw.trim() === '')
111
+ return fallback;
112
+ const parsed = Number.parseInt(raw.trim(), 10);
113
+ if (!Number.isFinite(parsed)) {
114
+ console.warn(`[config] 环境变量 ${key}='${raw}' 不是合法整数,已回退为 ${fallback}`);
115
+ return fallback;
116
+ }
117
+ return parsed;
118
+ }
119
+ /**
120
+ * 极简 `.env` 解析(不覆盖已存在的进程环境变量)。
121
+ *
122
+ * 支持:`KEY=value`、`export KEY=value`、`#` 注释、单/双引号、值内含 `=`。
123
+ */
124
+ export function parseDotEnv(text) {
125
+ const out = {};
126
+ for (const rawLine of text.split(/\r?\n/)) {
127
+ const line = rawLine.trim();
128
+ if (!line || line.startsWith('#'))
129
+ continue;
130
+ const withoutExport = line.startsWith('export ') ? line.slice(7).trim() : line;
131
+ const eq = withoutExport.indexOf('=');
132
+ if (eq <= 0)
133
+ continue;
134
+ const key = withoutExport.slice(0, eq).trim();
135
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key))
136
+ continue;
137
+ let value = withoutExport.slice(eq + 1).trim();
138
+ const quoted = (value.startsWith('"') && value.endsWith('"') && value.length >= 2) ||
139
+ (value.startsWith("'") && value.endsWith("'") && value.length >= 2);
140
+ if (quoted)
141
+ value = value.slice(1, -1);
142
+ out[key] = value;
143
+ }
144
+ return out;
145
+ }
146
+ /** 展开开头的 `~` 为用户主目录(Python 侧的 `os.path.expanduser`)。 */
147
+ export function expandHome(path) {
148
+ if (path === '~')
149
+ return process.env['HOME'] ?? path;
150
+ if (path.startsWith('~/')) {
151
+ const home = process.env['HOME'] ?? '';
152
+ return home ? `${home}${path.slice(1)}` : path;
153
+ }
154
+ return path;
155
+ }
156
+ /**
157
+ * 组装配置。
158
+ *
159
+ * 优先级:`.env` 文件 < 进程环境变量 < 默认值(即环境变量覆盖 `.env`)。
160
+ */
161
+ export function loadSettings(options = {}) {
162
+ const { env = process.env, dotEnvPath = '.env', readFile = defaultReadFile, } = options;
163
+ let fileVars = {};
164
+ if (dotEnvPath !== null) {
165
+ try {
166
+ fileVars = parseDotEnv(readFile(dotEnvPath));
167
+ }
168
+ catch {
169
+ // .env 不存在是正常情况(生产环境可以只用进程环境变量)
170
+ fileVars = {};
171
+ }
172
+ }
173
+ const pick = (key) => env[key] ?? fileVars[key];
174
+ /* ===== 无效键告警(**只查 `.env` 文件**,不看进程环境变量)=====
175
+ * 为什么需要:Python 版留下的 `.env` 里有 REDIS_URL / MAX_INSTANCES /
176
+ * USER_DATA_DIR 等一堆键,TS 版**根本不读**。它们不会报错、不会警告,
177
+ * 用户改了却发现"没生效" —— 这类静默无效正是最难查的失败模式。
178
+ *
179
+ * 只检查 `.env` 文件里的键(那是**本项目的配置**,写进去就是有意图的);
180
+ * 不检查 `process.env`(那里混着 PATH/HOME/CI 等无关变量,会满屏误报)。
181
+ */
182
+ const unknownKeys = Object.keys(fileVars).filter((k) => !(k in ENV_KEYS));
183
+ if (unknownKeys.length > 0) {
184
+ logger.warn(`.env 里有 ${unknownKeys.length} 个配置项不会被读取(拼写错误或已废弃):` +
185
+ `${unknownKeys.join(', ')}。当前生效的键见 .env.example。`);
186
+ }
187
+ const out = { ...DEFAULTS };
188
+ for (const [envKey, field] of Object.entries(ENV_KEYS)) {
189
+ const raw = pick(envKey);
190
+ if (raw === undefined)
191
+ continue;
192
+ const fallback = DEFAULTS[field];
193
+ if (typeof fallback === 'boolean') {
194
+ out[field] = toBool(raw, envKey, fallback);
195
+ }
196
+ else if (typeof fallback === 'number') {
197
+ out[field] = toInt(raw, envKey, fallback);
198
+ }
199
+ else {
200
+ out[field] = raw;
201
+ }
202
+ }
203
+ return out;
204
+ }
205
+ function defaultReadFile(path) {
206
+ return readFileSync(path, 'utf8');
207
+ }
208
+ /** 全局配置单例(等价于 Python 的 `settings = load_config()`)。 */
209
+ export const settings = loadSettings();
210
+ /** 对外展示的模型列表(逗号分隔 → 数组),等价于 `get_available_models_list()`。 */
211
+ export function getAvailableModelsList(source = settings) {
212
+ if (!source.availableModels)
213
+ return [];
214
+ return source.availableModels
215
+ .split(',')
216
+ .map((m) => m.trim())
217
+ .filter(Boolean);
218
+ }
219
+ /** API Key 集合,等价于 `get_api_keys()`。 */
220
+ export function getApiKeys(source = settings) {
221
+ if (!source.apiKeys)
222
+ return new Set();
223
+ return new Set(source.apiKeys
224
+ .split(',')
225
+ .map((k) => k.trim())
226
+ .filter(Boolean));
227
+ }
228
+ /**
229
+ * 默认工作目录列表,等价于 `get_default_workspace_paths()`。
230
+ *
231
+ * 只保留**实际存在**的目录;未配置时回退当前工作目录。
232
+ */
233
+ export function getDefaultWorkspacePaths(source = settings, exists = defaultIsDirectory) {
234
+ if (source.defaultWorkspacePaths) {
235
+ return source.defaultWorkspacePaths
236
+ .split(',')
237
+ .map((p) => p.trim())
238
+ .filter((p) => p !== '' && exists(p));
239
+ }
240
+ const cwd = process.cwd();
241
+ return exists(cwd) ? [cwd] : [];
242
+ }
243
+ function defaultIsDirectory(path) {
244
+ return statSync(path).isDirectory();
245
+ }
246
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ export interface HistoryMessage {
2
+ role: string;
3
+ content: string;
4
+ platform: string | null;
5
+ account_id: string | null;
6
+ model: string | null;
7
+ created_at: number;
8
+ }
9
+ export interface HistoryStats {
10
+ total_messages: number;
11
+ conversations: number;
12
+ ttl_days: number;
13
+ }
14
+ export interface AddMessageParams {
15
+ conversationId: string;
16
+ role: string;
17
+ content: string;
18
+ platform?: string | null;
19
+ accountId?: string | null;
20
+ model?: string | null;
21
+ }
22
+ /** 默认 db 路径:`~/.ai-api/history.db`(与 `authDir` 同级)。 */
23
+ export declare function defaultHistoryDbPath(): string;
24
+ export declare class HistoryDB {
25
+ private readonly ttlDays;
26
+ readonly dbPath: string;
27
+ private db;
28
+ private readonly lock;
29
+ constructor(dbPath?: string, ttlDays?: number);
30
+ /** 是否可用(不可用时所有方法都是安全空操作)。 */
31
+ get available(): boolean;
32
+ /** 打开连接并建表。失败则退化成「无历史」模式。 */
33
+ private initDb;
34
+ /** 添加一条消息。 */
35
+ addMessage(params: AddMessageParams): Promise<void>;
36
+ /**
37
+ * 取最近 N 条消息(**按时间升序**返回,便于直接拼接成上下文)。
38
+ *
39
+ * 实现方式与原实现一致:SQL 用 `ORDER BY created_at DESC LIMIT ?` 取最新的 N 条,
40
+ * 再在内存里反转成「旧 → 新」。
41
+ */
42
+ getRecentMessages(conversationId: string, limit?: number): Promise<HistoryMessage[]>;
43
+ /** 该对话最近一条消息所属的平台(用于检测跨平台切换)。 */
44
+ getLastPlatform(conversationId: string): Promise<string | null>;
45
+ /** 清理超过 TTL 的历史消息,返回删除条数。 */
46
+ cleanupOld(days?: number): Promise<number>;
47
+ /** 数据库统计。 */
48
+ stats(): Promise<HistoryStats>;
49
+ /** 关闭连接(优雅退出时调用)。 */
50
+ close(): void;
51
+ }
52
+ /** 获取全局历史数据库实例(单例)。 */
53
+ export declare function getHistoryDb(): HistoryDB;
54
+ /** 重置单例(测试用)。 */
55
+ export declare function __setHistoryDbForTest(db: HistoryDB | null): void;
56
+ //# sourceMappingURL=history-db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-db.d.ts","sourceRoot":"","sources":["../../src/controllers/history-db.ts"],"names":[],"mappings":"AAsFA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,uDAAuD;AACvD,wBAAgB,oBAAoB,IAAI,MAAM,CAG7C;AAED,qBAAa,SAAS;IASlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAR1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,OAAO,CAAC,EAAE,CAA+B;IAEzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IAEpC,YACE,MAAM,CAAC,EAAE,MAAM,EACE,OAAO,SAAI,EAI7B;IAED,6BAA6B;IAC7B,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,6BAA6B;IAC7B,OAAO,CAAC,MAAM;IAsCd,cAAc;IACR,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBxD;IAED;;;;;OAKG;IACG,iBAAiB,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA8BrF;IAED,iCAAiC;IAC3B,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBpE;IAED,6BAA6B;IACvB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsB/C;IAED,aAAa;IACP,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC,CAyBnC;IAED,qBAAqB;IACrB,KAAK,IAAI,IAAI,CAOZ;CACF;AAID,uBAAuB;AACvB,wBAAgB,YAAY,IAAI,SAAS,CAGxC;AAED,iBAAiB;AACjB,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAEhE"}
@@ -0,0 +1,260 @@
1
+ /**
2
+ * 历史消息数据库 —— `legacy-python/src/controllers/history_db.py` 的移植(SQLite)。
3
+ *
4
+ * 用途:
5
+ * 1. 切换模型/账号时注入最近 N 条原文,保持对话连续性;
6
+ * 2. 跨平台故障切换时,新平台能拿到上下文继续回答。
7
+ *
8
+ * 表结构(与 Python 完全一致,便于两个版本共用同一个 db 文件):
9
+ * ```sql
10
+ * messages(
11
+ * id INTEGER PRIMARY KEY AUTOINCREMENT,
12
+ * conversation_id TEXT NOT NULL,
13
+ * role TEXT NOT NULL,
14
+ * content TEXT NOT NULL,
15
+ * platform TEXT,
16
+ * account_id TEXT,
17
+ * model TEXT,
18
+ * created_at REAL NOT NULL
19
+ * )
20
+ * INDEX idx_conv_time ON messages(conversation_id, created_at)
21
+ * ```
22
+ *
23
+ * ## 与原实现的差异
24
+ * - 用 **Node 内置 `node:sqlite`**(Node 22.5+),不引入 `better-sqlite3`
25
+ * 这类需要本机编译的原生依赖 —— 这对 npm 分发是决定性的
26
+ * (否则用户 `npm i` 时还要有 C++ 工具链)。
27
+ * - 线程模型:Python 用 `threading.Lock` + 每次开新连接(为绕开 sqlite 的跨线程限制)。
28
+ * Node 是单线程事件循环,`DatabaseSync` 是同步 API,**不存在跨线程问题**,
29
+ * 因此改为「进程内一个长连接 + 一个 Mutex」保护写序列。
30
+ * - ⚠️ **降级行为**:若运行环境没有 `node:sqlite`(Node < 22.5),
31
+ * 本模块**不会让服务起不来**,而是打印一条明确告警并退化成「无历史」模式。
32
+ * 历史只是增强(丢了它 Provider 会退回去发完整提示词),不该拖垮整个网关。
33
+ */
34
+ import { createRequire } from 'node:module';
35
+ import { mkdirSync } from 'node:fs';
36
+ import { dirname, join } from 'node:path';
37
+ import { settings, expandHome } from '../config.js';
38
+ import { logger } from '../log/logger.js';
39
+ import { Mutex } from '../utils/mutex.js';
40
+ let sqliteModule;
41
+ /** 惰性加载 `node:sqlite`(失败只警告一次,并永久记住结果)。 */
42
+ function loadSqlite() {
43
+ if (sqliteModule !== undefined)
44
+ return sqliteModule;
45
+ try {
46
+ const require = createRequire(import.meta.url);
47
+ sqliteModule = require('node:sqlite');
48
+ }
49
+ catch {
50
+ sqliteModule = null;
51
+ logger.warn('[history] 当前 Node 不支持内置 `node:sqlite`(需要 Node 22.5+),' +
52
+ '历史消息功能已禁用:跨平台/换号时不会注入历史上下文。' +
53
+ '这不影响正常对话(Provider 会发送完整提示词)。');
54
+ }
55
+ return sqliteModule;
56
+ }
57
+ /** 默认 db 路径:`~/.ai-api/history.db`(与 `authDir` 同级)。 */
58
+ export function defaultHistoryDbPath() {
59
+ const authDir = expandHome(settings.authDir ?? '~/.ai-api/auth');
60
+ return join(dirname(authDir), 'history.db');
61
+ }
62
+ export class HistoryDB {
63
+ ttlDays;
64
+ dbPath;
65
+ db = null;
66
+ lock = new Mutex();
67
+ constructor(dbPath, ttlDays = 7) {
68
+ this.ttlDays = ttlDays;
69
+ this.dbPath = dbPath ?? defaultHistoryDbPath();
70
+ this.initDb();
71
+ }
72
+ /** 是否可用(不可用时所有方法都是安全空操作)。 */
73
+ get available() {
74
+ return this.db !== null;
75
+ }
76
+ /** 打开连接并建表。失败则退化成「无历史」模式。 */
77
+ initDb() {
78
+ const sqlite = loadSqlite();
79
+ if (!sqlite)
80
+ return;
81
+ try {
82
+ mkdirSync(dirname(this.dbPath), { recursive: true });
83
+ this.db = new sqlite.DatabaseSync(this.dbPath);
84
+ try {
85
+ // WAL 模式提升并发读写性能(与原实现一致)
86
+ this.db.exec('PRAGMA journal_mode=WAL');
87
+ }
88
+ catch {
89
+ // 某些文件系统(网络盘)不支持 WAL,忽略即可
90
+ }
91
+ this.db.exec(`
92
+ CREATE TABLE IF NOT EXISTS messages (
93
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
94
+ conversation_id TEXT NOT NULL,
95
+ role TEXT NOT NULL,
96
+ content TEXT NOT NULL,
97
+ platform TEXT,
98
+ account_id TEXT,
99
+ model TEXT,
100
+ created_at REAL NOT NULL
101
+ )
102
+ `);
103
+ this.db.exec('CREATE INDEX IF NOT EXISTS idx_conv_time ON messages(conversation_id, created_at)');
104
+ logger.debug(`✓ 历史数据库已初始化: ${this.dbPath}`);
105
+ }
106
+ catch (error) {
107
+ logger.error(`历史数据库初始化失败(已降级为无历史模式): ${String(error)}`);
108
+ this.db = null;
109
+ }
110
+ }
111
+ /** 添加一条消息。 */
112
+ async addMessage(params) {
113
+ const { conversationId, role, content, platform, accountId, model } = params;
114
+ if (!this.db || !conversationId || !content)
115
+ return;
116
+ const release = await this.lock.acquire();
117
+ try {
118
+ this.db
119
+ .prepare(`INSERT INTO messages
120
+ (conversation_id, role, content, platform, account_id, model, created_at)
121
+ VALUES (?, ?, ?, ?, ?, ?, ?)`)
122
+ .run(conversationId, role, content, platform ?? null, accountId ?? null, model ?? null, Date.now() / 1000);
123
+ }
124
+ catch (error) {
125
+ logger.error(`写入历史消息失败: ${String(error)}`);
126
+ }
127
+ finally {
128
+ release();
129
+ }
130
+ }
131
+ /**
132
+ * 取最近 N 条消息(**按时间升序**返回,便于直接拼接成上下文)。
133
+ *
134
+ * 实现方式与原实现一致:SQL 用 `ORDER BY created_at DESC LIMIT ?` 取最新的 N 条,
135
+ * 再在内存里反转成「旧 → 新」。
136
+ */
137
+ async getRecentMessages(conversationId, limit = 20) {
138
+ if (!this.db || !conversationId)
139
+ return [];
140
+ const release = await this.lock.acquire();
141
+ try {
142
+ const rows = this.db
143
+ .prepare(`SELECT role, content, platform, account_id, model, created_at
144
+ FROM messages
145
+ WHERE conversation_id = ?
146
+ ORDER BY created_at DESC
147
+ LIMIT ?`)
148
+ .all(conversationId, limit);
149
+ // 反转为升序(旧 → 新)
150
+ return rows.reverse().map((row) => ({
151
+ role: String(row['role'] ?? ''),
152
+ content: String(row['content'] ?? ''),
153
+ platform: row['platform'] == null ? null : String(row['platform']),
154
+ account_id: row['account_id'] == null ? null : String(row['account_id']),
155
+ model: row['model'] == null ? null : String(row['model']),
156
+ created_at: Number(row['created_at'] ?? 0),
157
+ }));
158
+ }
159
+ catch (error) {
160
+ logger.error(`读取历史消息失败: ${String(error)}`);
161
+ return [];
162
+ }
163
+ finally {
164
+ release();
165
+ }
166
+ }
167
+ /** 该对话最近一条消息所属的平台(用于检测跨平台切换)。 */
168
+ async getLastPlatform(conversationId) {
169
+ if (!this.db || !conversationId)
170
+ return null;
171
+ const release = await this.lock.acquire();
172
+ try {
173
+ const row = this.db
174
+ .prepare(`SELECT platform FROM messages
175
+ WHERE conversation_id = ? AND platform IS NOT NULL
176
+ ORDER BY created_at DESC
177
+ LIMIT 1`)
178
+ .get(conversationId);
179
+ return row?.['platform'] == null ? null : String(row['platform']);
180
+ }
181
+ catch (error) {
182
+ logger.error(`读取最近平台失败: ${String(error)}`);
183
+ return null;
184
+ }
185
+ finally {
186
+ release();
187
+ }
188
+ }
189
+ /** 清理超过 TTL 的历史消息,返回删除条数。 */
190
+ async cleanupOld(days) {
191
+ if (!this.db)
192
+ return 0;
193
+ const ttl = days ?? this.ttlDays;
194
+ const cutoff = Date.now() / 1000 - ttl * 86400;
195
+ const release = await this.lock.acquire();
196
+ try {
197
+ const result = this.db
198
+ .prepare('DELETE FROM messages WHERE created_at < ?')
199
+ .run(cutoff);
200
+ const deleted = Number(result.changes);
201
+ if (deleted > 0) {
202
+ logger.info(`✓ 清理过期历史消息: ${deleted} 条(>${ttl}天)`);
203
+ }
204
+ return deleted;
205
+ }
206
+ catch (error) {
207
+ logger.error(`清理历史消息失败: ${String(error)}`);
208
+ return 0;
209
+ }
210
+ finally {
211
+ release();
212
+ }
213
+ }
214
+ /** 数据库统计。 */
215
+ async stats() {
216
+ if (!this.db) {
217
+ return { total_messages: 0, conversations: 0, ttl_days: this.ttlDays };
218
+ }
219
+ const release = await this.lock.acquire();
220
+ try {
221
+ const totalRow = this.db.prepare('SELECT COUNT(*) AS c FROM messages').get();
222
+ const convRow = this.db
223
+ .prepare('SELECT COUNT(DISTINCT conversation_id) AS c FROM messages')
224
+ .get();
225
+ return {
226
+ total_messages: Number(totalRow?.['c'] ?? 0),
227
+ conversations: Number(convRow?.['c'] ?? 0),
228
+ ttl_days: this.ttlDays,
229
+ };
230
+ }
231
+ catch (error) {
232
+ logger.error(`统计历史数据库失败: ${String(error)}`);
233
+ return { total_messages: 0, conversations: 0, ttl_days: this.ttlDays };
234
+ }
235
+ finally {
236
+ release();
237
+ }
238
+ }
239
+ /** 关闭连接(优雅退出时调用)。 */
240
+ close() {
241
+ try {
242
+ this.db?.close();
243
+ }
244
+ catch {
245
+ // 忽略
246
+ }
247
+ this.db = null;
248
+ }
249
+ }
250
+ let historyDb = null;
251
+ /** 获取全局历史数据库实例(单例)。 */
252
+ export function getHistoryDb() {
253
+ historyDb ??= new HistoryDB();
254
+ return historyDb;
255
+ }
256
+ /** 重置单例(测试用)。 */
257
+ export function __setHistoryDbForTest(db) {
258
+ historyDb = db;
259
+ }
260
+ //# sourceMappingURL=history-db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-db.js","sourceRoot":"","sources":["../../src/controllers/history-db.ts"],"names":[],"mappings":"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"}