hydro-ai-helper 1.8.5
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.
- package/.eslintrc.json +31 -0
- package/.github/workflows/sync-releases-to-gitee.yml +119 -0
- package/.github/workflows/sync-to-gitee.yml +53 -0
- package/.vercelignore +31 -0
- package/CONTRIBUTING.md +165 -0
- package/README.md +273 -0
- package/TROUBLESHOOTING.md +355 -0
- package/api/badge-active.ts +88 -0
- package/api/badge-installs.ts +75 -0
- package/api/report.ts +242 -0
- package/assets/screenshots/1.png +0 -0
- package/assets/screenshots/2.png +0 -0
- package/assets/screenshots/3.png +0 -0
- package/assets/screenshots/4.png +0 -0
- package/assets/screenshots/5.png +0 -0
- package/assets/screenshots/6.png +0 -0
- package/assets/screenshots/7.png +0 -0
- package/dist/__tests__/__mocks__/hydrooj.js +29 -0
- package/dist/__tests__/__mocks__/hydrooj.js.map +1 -0
- package/dist/constants/jailbreakRules.js +29 -0
- package/dist/constants/jailbreakRules.js.map +1 -0
- package/dist/constants/permissions.js +42 -0
- package/dist/constants/permissions.js.map +1 -0
- package/dist/handlers/adminConfigHandler.js +347 -0
- package/dist/handlers/adminConfigHandler.js.map +1 -0
- package/dist/handlers/adminHandler.js +378 -0
- package/dist/handlers/adminHandler.js.map +1 -0
- package/dist/handlers/analyticsHandler.js +433 -0
- package/dist/handlers/analyticsHandler.js.map +1 -0
- package/dist/handlers/dashboardHandler.js +22 -0
- package/dist/handlers/dashboardHandler.js.map +1 -0
- package/dist/handlers/exportHandler.js +118 -0
- package/dist/handlers/exportHandler.js.map +1 -0
- package/dist/handlers/studentHandler.js +430 -0
- package/dist/handlers/studentHandler.js.map +1 -0
- package/dist/handlers/teacherHandler.js +246 -0
- package/dist/handlers/teacherHandler.js.map +1 -0
- package/dist/handlers/testHandler.js +27 -0
- package/dist/handlers/testHandler.js.map +1 -0
- package/dist/handlers/updateHandler.js +84 -0
- package/dist/handlers/updateHandler.js.map +1 -0
- package/dist/handlers/versionHandler.js +61 -0
- package/dist/handlers/versionHandler.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +151 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/crypto.js +110 -0
- package/dist/lib/crypto.js.map +1 -0
- package/dist/lib/httpHelpers.js +61 -0
- package/dist/lib/httpHelpers.js.map +1 -0
- package/dist/lib/queryHelpers.js +81 -0
- package/dist/lib/queryHelpers.js.map +1 -0
- package/dist/models/aiConfig.js +255 -0
- package/dist/models/aiConfig.js.map +1 -0
- package/dist/models/conversation.js +209 -0
- package/dist/models/conversation.js.map +1 -0
- package/dist/models/jailbreakLog.js +68 -0
- package/dist/models/jailbreakLog.js.map +1 -0
- package/dist/models/message.js +174 -0
- package/dist/models/message.js.map +1 -0
- package/dist/models/pluginInstall.js +95 -0
- package/dist/models/pluginInstall.js.map +1 -0
- package/dist/models/rateLimitRecord.js +54 -0
- package/dist/models/rateLimitRecord.js.map +1 -0
- package/dist/models/versionCache.js +89 -0
- package/dist/models/versionCache.js.map +1 -0
- package/dist/services/effectivenessService.js +131 -0
- package/dist/services/effectivenessService.js.map +1 -0
- package/dist/services/exportService.js +152 -0
- package/dist/services/exportService.js.map +1 -0
- package/dist/services/migrationService.js +90 -0
- package/dist/services/migrationService.js.map +1 -0
- package/dist/services/openaiClient.js +412 -0
- package/dist/services/openaiClient.js.map +1 -0
- package/dist/services/promptService.js +467 -0
- package/dist/services/promptService.js.map +1 -0
- package/dist/services/rateLimitService.js +108 -0
- package/dist/services/rateLimitService.js.map +1 -0
- package/dist/services/telemetryService.js +173 -0
- package/dist/services/telemetryService.js.map +1 -0
- package/dist/services/updateService.js +388 -0
- package/dist/services/updateService.js.map +1 -0
- package/dist/services/versionService.js +289 -0
- package/dist/services/versionService.js.map +1 -0
- package/dist/types/hydrooj.js +7 -0
- package/dist/types/hydrooj.js.map +1 -0
- package/dist/types/mongo.js +7 -0
- package/dist/types/mongo.js.map +1 -0
- package/dist/utils/domainHelper.js +16 -0
- package/dist/utils/domainHelper.js.map +1 -0
- package/dist/utils/mongo.js +16 -0
- package/dist/utils/mongo.js.map +1 -0
- package/frontend/admin/ConfigPanel.tsx +1379 -0
- package/frontend/admin/VersionBadge.tsx +655 -0
- package/frontend/ai_helper.page.tsx +52 -0
- package/frontend/ai_helper_admin_config.page.tsx +47 -0
- package/frontend/ai_helper_analytics.page.tsx +52 -0
- package/frontend/ai_helper_conversation_detail.page.tsx +55 -0
- package/frontend/ai_helper_conversations.page.tsx +56 -0
- package/frontend/components/AIHelperDashboard.tsx +125 -0
- package/frontend/problem_detail.page.tsx +395 -0
- package/frontend/student/AIAssistantPanel.tsx +1839 -0
- package/frontend/student/AIChatPanel.tsx +944 -0
- package/frontend/student/ThreeColumnLayout.tsx +240 -0
- package/frontend/teacher/AnalyticsPage.tsx +614 -0
- package/frontend/teacher/ConversationDetail.tsx +504 -0
- package/frontend/teacher/ConversationList.tsx +568 -0
- package/frontend/teacher/ExportDialog.tsx +291 -0
- package/frontend/test.page.ts +88 -0
- package/frontend/utils/domainUtils.ts +37 -0
- package/index.js +6 -0
- package/jest.config.js +17 -0
- package/lib/mongodb.ts +60 -0
- package/locales/en.yaml +4 -0
- package/locales/zh.yaml +77 -0
- package/package.json +48 -0
- package/public/.gitkeep +0 -0
- package/public/README.md +1 -0
- package/src/__tests__/__mocks__/hydrooj.ts +27 -0
- package/src/__tests__/services/exportService.test.ts +156 -0
- package/src/__tests__/services/promptService.test.ts +141 -0
- package/src/__tests__/services/rateLimitService.test.ts +145 -0
- package/src/__tests__/utils/domainHelper.test.ts +47 -0
- package/src/constants/jailbreakRules.ts +28 -0
- package/src/constants/permissions.ts +43 -0
- package/src/handlers/adminConfigHandler.ts +363 -0
- package/src/handlers/adminHandler.ts +427 -0
- package/src/handlers/analyticsHandler.ts +517 -0
- package/src/handlers/dashboardHandler.ts +20 -0
- package/src/handlers/exportHandler.ts +134 -0
- package/src/handlers/studentHandler.ts +483 -0
- package/src/handlers/teacherHandler.ts +317 -0
- package/src/handlers/testHandler.ts +25 -0
- package/src/handlers/updateHandler.ts +85 -0
- package/src/handlers/versionHandler.ts +62 -0
- package/src/index.ts +198 -0
- package/src/lib/crypto.ts +125 -0
- package/src/lib/httpHelpers.ts +75 -0
- package/src/lib/queryHelpers.ts +108 -0
- package/src/models/aiConfig.ts +375 -0
- package/src/models/conversation.ts +328 -0
- package/src/models/jailbreakLog.ts +108 -0
- package/src/models/message.ts +246 -0
- package/src/models/pluginInstall.ts +138 -0
- package/src/models/rateLimitRecord.ts +81 -0
- package/src/models/versionCache.ts +127 -0
- package/src/services/effectivenessService.ts +161 -0
- package/src/services/exportService.ts +191 -0
- package/src/services/migrationService.ts +111 -0
- package/src/services/openaiClient.ts +548 -0
- package/src/services/promptService.ts +573 -0
- package/src/services/rateLimitService.ts +122 -0
- package/src/services/telemetryService.ts +218 -0
- package/src/services/updateService.ts +441 -0
- package/src/services/versionService.ts +351 -0
- package/src/types/hydrooj-extensions.d.ts +55 -0
- package/src/types/hydrooj.ts +38 -0
- package/src/types/mongo.ts +23 -0
- package/src/utils/domainHelper.ts +16 -0
- package/src/utils/mongo.ts +15 -0
- package/templates/ai-helper/admin_config.html +8 -0
- package/templates/ai-helper/analytics.html +8 -0
- package/templates/ai-helper/dashboard.html +8 -0
- package/templates/ai-helper/teacher_conversation_detail.html +8 -0
- package/templates/ai-helper/teacher_conversations.html +8 -0
- package/tests/integration/README.md +86 -0
- package/tests/integration/curl/01-admin-config-set.sh +56 -0
- package/tests/integration/curl/02-student-chat.sh +67 -0
- package/tests/integration/curl/03-teacher-list.sh +52 -0
- package/tests/integration/curl/04-teacher-detail.sh +37 -0
- package/tests/integration/curl/05-export.sh +49 -0
- package/tests/integration/curl/06-analytics.sh +43 -0
- package/tests/performance/README.md +85 -0
- package/tests/performance/data/prepare-sample-data.md +57 -0
- package/tests/performance/scripts/export-csv-k6.js +41 -0
- package/tests/performance/scripts/student-chat-k6.js +44 -0
- package/tests/performance/scripts/teacher-conversations-k6.js +33 -0
- package/tsconfig.json +42 -0
- package/tsconfig.vercel.json +27 -0
- package/types/hydrooj/index.d.ts +73 -0
- package/vercel.json +3 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
# Vercel 部署故障排查
|
|
2
|
+
|
|
3
|
+
## 问题:构建失败 - TypeScript 编译错误
|
|
4
|
+
|
|
5
|
+
### 错误现象
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Running "npm run build"
|
|
9
|
+
> hydro-ai-helper@1.8.0 build
|
|
10
|
+
> tsc
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
然后构建失败或超时。
|
|
14
|
+
|
|
15
|
+
### 原因分析
|
|
16
|
+
|
|
17
|
+
Vercel 默认会运行 `npm run build`,但我们的 `tsconfig.json` 是为 HydroOJ 插件设计的,包含了 `src/` 和 `frontend/` 目录,这些目录依赖 HydroOJ 的类型定义,在 Vercel 环境中无法编译。
|
|
18
|
+
|
|
19
|
+
### 解决方案
|
|
20
|
+
|
|
21
|
+
#### ✅ 方案 1:禁用构建命令(已实施)
|
|
22
|
+
|
|
23
|
+
在 `vercel.json` 中添加 `buildCommand: null`:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"version": 2,
|
|
28
|
+
"buildCommand": null,
|
|
29
|
+
"functions": {
|
|
30
|
+
"api/*.ts": {
|
|
31
|
+
"runtime": "nodejs20.x"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**原理**:Vercel Functions 原生支持 TypeScript,不需要预编译。
|
|
38
|
+
|
|
39
|
+
#### 方案 2:创建 Vercel 专用配置(备选)
|
|
40
|
+
|
|
41
|
+
创建 `tsconfig.vercel.json`,只编译 `api/` 和 `lib/` 目录:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"compilerOptions": {
|
|
46
|
+
"target": "ES2020",
|
|
47
|
+
"module": "commonjs",
|
|
48
|
+
"outDir": ".vercel/output",
|
|
49
|
+
"strict": false,
|
|
50
|
+
"skipLibCheck": true
|
|
51
|
+
},
|
|
52
|
+
"include": ["api/**/*", "lib/**/*"],
|
|
53
|
+
"exclude": ["node_modules", "src", "frontend", "dist"]
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
然后修改 `package.json`:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "tsc -p tsconfig.vercel.json",
|
|
63
|
+
"build:plugin": "tsc"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 问题:MongoDB 连接失败
|
|
71
|
+
|
|
72
|
+
### 错误现象
|
|
73
|
+
|
|
74
|
+
Vercel 函数日志显示:
|
|
75
|
+
```
|
|
76
|
+
MongoServerError: bad auth : authentication failed
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 解决方案
|
|
80
|
+
|
|
81
|
+
1. **检查环境变量**
|
|
82
|
+
- Vercel Dashboard → 项目 → Settings → Environment Variables
|
|
83
|
+
- 确认 `MONGODB_URI` 和 `MONGODB_DB` 已设置
|
|
84
|
+
|
|
85
|
+
2. **检查密码编码**
|
|
86
|
+
- 如果密码包含特殊字符,需要 URL 编码:
|
|
87
|
+
- `@` → `%40`
|
|
88
|
+
- `#` → `%23`
|
|
89
|
+
- `%` → `%25`
|
|
90
|
+
|
|
91
|
+
3. **检查网络访问**
|
|
92
|
+
- MongoDB Atlas → Network Access
|
|
93
|
+
- 确认包含 `0.0.0.0/0`(允许所有 IP)
|
|
94
|
+
|
|
95
|
+
4. **测试连接字符串**
|
|
96
|
+
```bash
|
|
97
|
+
# 使用 mongosh 测试
|
|
98
|
+
mongosh "mongodb+srv://user:pass@cluster.mongodb.net/"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 问题:函数超时
|
|
104
|
+
|
|
105
|
+
### 错误现象
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
Function execution timed out
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 解决方案
|
|
112
|
+
|
|
113
|
+
1. **检查 MongoDB 集群状态**
|
|
114
|
+
- 免费集群会自动暂停
|
|
115
|
+
- 在 MongoDB Atlas 中手动唤醒
|
|
116
|
+
|
|
117
|
+
2. **优化连接池**
|
|
118
|
+
- 已在 `lib/mongodb.ts` 中实现
|
|
119
|
+
- 使用全局变量缓存连接
|
|
120
|
+
|
|
121
|
+
3. **增加超时时间**(如果需要)
|
|
122
|
+
```json
|
|
123
|
+
// vercel.json
|
|
124
|
+
{
|
|
125
|
+
"functions": {
|
|
126
|
+
"api/*.ts": {
|
|
127
|
+
"runtime": "nodejs20.x",
|
|
128
|
+
"maxDuration": 10
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 问题:徽章显示 "invalid"
|
|
137
|
+
|
|
138
|
+
### 错误现象
|
|
139
|
+
|
|
140
|
+
GitHub README 徽章显示灰色 "invalid"。
|
|
141
|
+
|
|
142
|
+
### 解决方案
|
|
143
|
+
|
|
144
|
+
1. **测试 API 端点**
|
|
145
|
+
```bash
|
|
146
|
+
curl https://your-vercel-app.vercel.app/api/badge-installs
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
2. **检查返回格式**
|
|
150
|
+
- 必须是 Shields.io JSON 格式:
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"schemaVersion": 1,
|
|
154
|
+
"label": "installations",
|
|
155
|
+
"message": "123",
|
|
156
|
+
"color": "blue"
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
3. **查看 Vercel 日志**
|
|
161
|
+
- Vercel Dashboard → 项目 → Functions → Logs
|
|
162
|
+
- 查看具体错误信息
|
|
163
|
+
|
|
164
|
+
4. **检查 CORS**
|
|
165
|
+
- 徽章端点已配置 CORS
|
|
166
|
+
- 确认 `Access-Control-Allow-Origin: *` 头存在
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 问题:徽章显示 "error"
|
|
171
|
+
|
|
172
|
+
### 错误现象
|
|
173
|
+
|
|
174
|
+
徽章显示红色 "error"。
|
|
175
|
+
|
|
176
|
+
### 解决方案
|
|
177
|
+
|
|
178
|
+
1. **检查数据库连接**
|
|
179
|
+
- 确认 MongoDB 连接正常
|
|
180
|
+
- 查看 Vercel 函数日志
|
|
181
|
+
|
|
182
|
+
2. **检查数据**
|
|
183
|
+
```javascript
|
|
184
|
+
// 使用 MongoDB Compass 或 mongosh
|
|
185
|
+
use hydro_ai_stats
|
|
186
|
+
db.plugin_stats.find().pretty()
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
3. **检查聚合查询**
|
|
190
|
+
```javascript
|
|
191
|
+
// 测试聚合查询
|
|
192
|
+
db.plugin_stats.aggregate([
|
|
193
|
+
{
|
|
194
|
+
$group: {
|
|
195
|
+
_id: null,
|
|
196
|
+
total: { $sum: { $ifNull: ['$stats.activeUsers7d', 0] } }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
])
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 问题:插件端上报失败
|
|
205
|
+
|
|
206
|
+
### 错误现象
|
|
207
|
+
|
|
208
|
+
HydroOJ 日志显示:
|
|
209
|
+
```
|
|
210
|
+
[TelemetryService] Report failed: 404 Not Found
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 解决方案
|
|
214
|
+
|
|
215
|
+
1. **检查 REPORT_URL**
|
|
216
|
+
```bash
|
|
217
|
+
grep REPORT_URL src/services/telemetryService.ts
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
2. **测试端点**
|
|
221
|
+
```bash
|
|
222
|
+
curl -X POST https://your-vercel-app.vercel.app/api/report \
|
|
223
|
+
-H "Content-Type: application/json" \
|
|
224
|
+
-d '{
|
|
225
|
+
"instance_id": "test",
|
|
226
|
+
"event": "install",
|
|
227
|
+
"version": "1.8.0",
|
|
228
|
+
"installed_at": "2024-01-01T00:00:00Z",
|
|
229
|
+
"stats": {
|
|
230
|
+
"active_users_7d": 0,
|
|
231
|
+
"total_conversations": 0
|
|
232
|
+
},
|
|
233
|
+
"domain_hash": "test",
|
|
234
|
+
"timestamp": "2024-01-01T00:00:00Z"
|
|
235
|
+
}'
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
3. **检查 Vercel 部署状态**
|
|
239
|
+
- Vercel Dashboard → 项目 → Deployments
|
|
240
|
+
- 确认最新部署成功
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 问题:依赖安装警告
|
|
245
|
+
|
|
246
|
+
### 错误现象
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
npm warn deprecated rimraf@3.0.2
|
|
250
|
+
npm warn deprecated eslint@8.57.1
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### 解决方案
|
|
254
|
+
|
|
255
|
+
这些是警告,不是错误,不影响部署。可以忽略。
|
|
256
|
+
|
|
257
|
+
如果想消除警告,可以更新依赖:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
npm update
|
|
261
|
+
npm audit fix
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 验证部署成功
|
|
267
|
+
|
|
268
|
+
### 1. 检查 Vercel 部署状态
|
|
269
|
+
|
|
270
|
+
访问 Vercel Dashboard,确认:
|
|
271
|
+
- ✅ 部署状态:Ready
|
|
272
|
+
- ✅ 函数列表:显示 3 个函数(report, badge-installs, badge-active)
|
|
273
|
+
|
|
274
|
+
### 2. 测试所有端点
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
# 测试心跳端点
|
|
278
|
+
curl -X POST https://your-vercel-app.vercel.app/api/report \
|
|
279
|
+
-H "Content-Type: application/json" \
|
|
280
|
+
-d '{"instance_id":"test","event":"install","version":"1.8.0","installed_at":"2024-01-01T00:00:00Z","stats":{"active_users_7d":10,"total_conversations":50},"domain_hash":"test","timestamp":"2024-01-01T00:00:00Z"}'
|
|
281
|
+
|
|
282
|
+
# 预期:{"success": true}
|
|
283
|
+
|
|
284
|
+
# 测试安装数徽章
|
|
285
|
+
curl https://your-vercel-app.vercel.app/api/badge-installs
|
|
286
|
+
|
|
287
|
+
# 预期:{"schemaVersion":1,"label":"installations","message":"1","color":"blue"}
|
|
288
|
+
|
|
289
|
+
# 测试活跃用户徽章
|
|
290
|
+
curl https://your-vercel-app.vercel.app/api/badge-active
|
|
291
|
+
|
|
292
|
+
# 预期:{"schemaVersion":1,"label":"active users (7d)","message":"10","color":"green"}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### 3. 检查 MongoDB 数据
|
|
296
|
+
|
|
297
|
+
```javascript
|
|
298
|
+
use hydro_ai_stats
|
|
299
|
+
|
|
300
|
+
// 查看数据
|
|
301
|
+
db.plugin_stats.find().pretty()
|
|
302
|
+
|
|
303
|
+
// 验证索引
|
|
304
|
+
db.plugin_stats.getIndexes()
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### 4. 验证插件端
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
# 查看 HydroOJ 日志
|
|
311
|
+
pm2 logs hydrooj | grep TelemetryService
|
|
312
|
+
|
|
313
|
+
# 预期输出
|
|
314
|
+
[TelemetryService] Initialized successfully
|
|
315
|
+
[TelemetryService] Report sent successfully (install)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 常见问题汇总
|
|
321
|
+
|
|
322
|
+
| 问题 | 原因 | 解决方案 |
|
|
323
|
+
|------|------|---------|
|
|
324
|
+
| 构建失败 | TypeScript 配置不兼容 | 添加 `buildCommand: null` |
|
|
325
|
+
| MongoDB 连接失败 | 环境变量或网络访问 | 检查 Vercel 环境变量和 Atlas 配置 |
|
|
326
|
+
| 函数超时 | 集群暂停或连接慢 | 唤醒集群,优化连接池 |
|
|
327
|
+
| 徽章 invalid | API 返回格式错误 | 检查 API 端点返回 |
|
|
328
|
+
| 徽章 error | 数据库查询失败 | 检查数据库连接和数据 |
|
|
329
|
+
| 上报失败 | URL 不正确 | 检查 REPORT_URL 配置 |
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## 获取帮助
|
|
334
|
+
|
|
335
|
+
如果以上方案都无法解决问题:
|
|
336
|
+
|
|
337
|
+
1. **查看 Vercel 日志**
|
|
338
|
+
- Vercel Dashboard → 项目 → Functions → Logs
|
|
339
|
+
- 复制完整错误信息
|
|
340
|
+
|
|
341
|
+
2. **查看 MongoDB Atlas 日志**
|
|
342
|
+
- MongoDB Atlas → Cluster → Metrics
|
|
343
|
+
- 检查连接数和操作数
|
|
344
|
+
|
|
345
|
+
3. **提交 Issue**
|
|
346
|
+
- 访问 https://github.com/AltureT/hydro-ai-helper/issues
|
|
347
|
+
- 提供完整的错误日志和配置信息
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 相关文档
|
|
352
|
+
|
|
353
|
+
- [DEPLOYMENT_PHASE2.md](./DEPLOYMENT_PHASE2.md) - 详细部署指南
|
|
354
|
+
- [QUICKSTART.md](./QUICKSTART.md) - 快速开始指南
|
|
355
|
+
- [VERCEL_CONFIG.md](./VERCEL_CONFIG.md) - Vercel 配置指南
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { VercelRequest, VercelResponse } from '@vercel/node';
|
|
2
|
+
import { getDb, PLUGIN_STATS_COLLECTION } from '../lib/mongodb';
|
|
3
|
+
|
|
4
|
+
const CORS_HEADERS: Record<string, string> = {
|
|
5
|
+
'Access-Control-Allow-Origin': '*',
|
|
6
|
+
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
|
7
|
+
'Access-Control-Allow-Headers': 'Content-Type'
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const compactFormatter = new Intl.NumberFormat('en', {
|
|
11
|
+
notation: 'compact',
|
|
12
|
+
compactDisplay: 'short',
|
|
13
|
+
maximumFractionDigits: 1
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
function applyCors(res: VercelResponse): void {
|
|
17
|
+
Object.entries(CORS_HEADERS).forEach(([key, value]) => {
|
|
18
|
+
res.setHeader(key, value);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function formatCount(value: number): string {
|
|
23
|
+
if (!Number.isFinite(value)) {
|
|
24
|
+
return '0';
|
|
25
|
+
}
|
|
26
|
+
return compactFormatter.format(value);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default async function handler(
|
|
30
|
+
req: VercelRequest,
|
|
31
|
+
res: VercelResponse
|
|
32
|
+
): Promise<void> {
|
|
33
|
+
applyCors(res);
|
|
34
|
+
|
|
35
|
+
if (req.method === 'OPTIONS') {
|
|
36
|
+
res.status(204).end();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (req.method !== 'GET') {
|
|
41
|
+
res.setHeader('Allow', 'GET, OPTIONS');
|
|
42
|
+
res.status(405).json({
|
|
43
|
+
schemaVersion: 1,
|
|
44
|
+
label: 'active users (7d)',
|
|
45
|
+
message: 'method not allowed',
|
|
46
|
+
color: 'lightgrey'
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const db = await getDb();
|
|
53
|
+
const [result] = await db
|
|
54
|
+
.collection(PLUGIN_STATS_COLLECTION)
|
|
55
|
+
.aggregate([
|
|
56
|
+
{
|
|
57
|
+
$group: {
|
|
58
|
+
_id: null,
|
|
59
|
+
total: {
|
|
60
|
+
$sum: { $ifNull: ['$stats.activeUsers7d', 0] }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
])
|
|
65
|
+
.toArray();
|
|
66
|
+
|
|
67
|
+
const total =
|
|
68
|
+
result && typeof result.total === 'number' ? result.total : 0;
|
|
69
|
+
|
|
70
|
+
console.info('[badge-active] total', total);
|
|
71
|
+
|
|
72
|
+
res.setHeader('Cache-Control', 'public, max-age=0, s-maxage=300');
|
|
73
|
+
res.status(200).json({
|
|
74
|
+
schemaVersion: 1,
|
|
75
|
+
label: 'active users (7d)',
|
|
76
|
+
message: formatCount(total),
|
|
77
|
+
color: 'green'
|
|
78
|
+
});
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error('[badge-active] error', error);
|
|
81
|
+
res.status(500).json({
|
|
82
|
+
schemaVersion: 1,
|
|
83
|
+
label: 'active users (7d)',
|
|
84
|
+
message: 'error',
|
|
85
|
+
color: 'lightgrey'
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { VercelRequest, VercelResponse } from '@vercel/node';
|
|
2
|
+
import { getDb, PLUGIN_STATS_COLLECTION } from '../lib/mongodb';
|
|
3
|
+
|
|
4
|
+
const CORS_HEADERS: Record<string, string> = {
|
|
5
|
+
'Access-Control-Allow-Origin': '*',
|
|
6
|
+
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
|
7
|
+
'Access-Control-Allow-Headers': 'Content-Type'
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const compactFormatter = new Intl.NumberFormat('en', {
|
|
11
|
+
notation: 'compact',
|
|
12
|
+
compactDisplay: 'short',
|
|
13
|
+
maximumFractionDigits: 1
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
function applyCors(res: VercelResponse): void {
|
|
17
|
+
Object.entries(CORS_HEADERS).forEach(([key, value]) => {
|
|
18
|
+
res.setHeader(key, value);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function formatCount(value: number): string {
|
|
23
|
+
if (!Number.isFinite(value)) {
|
|
24
|
+
return '0';
|
|
25
|
+
}
|
|
26
|
+
return compactFormatter.format(value);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default async function handler(
|
|
30
|
+
req: VercelRequest,
|
|
31
|
+
res: VercelResponse
|
|
32
|
+
): Promise<void> {
|
|
33
|
+
applyCors(res);
|
|
34
|
+
|
|
35
|
+
if (req.method === 'OPTIONS') {
|
|
36
|
+
res.status(204).end();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (req.method !== 'GET') {
|
|
41
|
+
res.setHeader('Allow', 'GET, OPTIONS');
|
|
42
|
+
res.status(405).json({
|
|
43
|
+
schemaVersion: 1,
|
|
44
|
+
label: 'installations',
|
|
45
|
+
message: 'method not allowed',
|
|
46
|
+
color: 'lightgrey'
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const db = await getDb();
|
|
53
|
+
const count = await db
|
|
54
|
+
.collection(PLUGIN_STATS_COLLECTION)
|
|
55
|
+
.countDocuments();
|
|
56
|
+
|
|
57
|
+
console.info('[badge-installs] count', count);
|
|
58
|
+
|
|
59
|
+
res.setHeader('Cache-Control', 'public, max-age=0, s-maxage=300');
|
|
60
|
+
res.status(200).json({
|
|
61
|
+
schemaVersion: 1,
|
|
62
|
+
label: 'installations',
|
|
63
|
+
message: formatCount(count),
|
|
64
|
+
color: 'blue'
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('[badge-installs] error', error);
|
|
68
|
+
res.status(500).json({
|
|
69
|
+
schemaVersion: 1,
|
|
70
|
+
label: 'installations',
|
|
71
|
+
message: 'error',
|
|
72
|
+
color: 'lightgrey'
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|