@myassis/gateway 1.0.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 (65) hide show
  1. package/README.md +194 -0
  2. package/dist/.env +6 -0
  3. package/dist/api/index.js +182 -0
  4. package/dist/config/index.js +41 -0
  5. package/dist/index.js +183 -0
  6. package/dist/middleware/auth.js +53 -0
  7. package/dist/middleware/errorHandler.js +20 -0
  8. package/dist/routes/agent.js +513 -0
  9. package/dist/routes/auth.js +172 -0
  10. package/dist/routes/chat.js +45 -0
  11. package/dist/routes/config.js +21 -0
  12. package/dist/routes/models.js +123 -0
  13. package/dist/routes/service.js +240 -0
  14. package/dist/routes/settings.js +101 -0
  15. package/dist/routes/skillHub.js +126 -0
  16. package/dist/routes/skills.js +159 -0
  17. package/dist/routes/tasks.js +149 -0
  18. package/dist/routes/upload.js +129 -0
  19. package/dist/routes/version.js +66 -0
  20. package/dist/services/HMSPushService.js +24 -0
  21. package/dist/services/LocalTaskService.js +223 -0
  22. package/dist/services/NotificationService.js +242 -0
  23. package/dist/services/ServiceManager.js +348 -0
  24. package/dist/services/TaskSchedulerService.js +195 -0
  25. package/dist/services/TaskService.js +240 -0
  26. package/dist/services/WebSocketService.js +236 -0
  27. package/dist/services/agent/Agent.js +120 -0
  28. package/dist/services/agent/AgentManager.js +265 -0
  29. package/dist/services/agent/AgentStore.js +73 -0
  30. package/dist/services/dataService.js +293 -0
  31. package/dist/services/index.js +15 -0
  32. package/dist/services/llm/LLMClient.js +724 -0
  33. package/dist/services/memory/MemoryManager.js +117 -0
  34. package/dist/services/model/ModelCapabilities.js +141 -0
  35. package/dist/services/model/index.js +4 -0
  36. package/dist/services/models.js +16 -0
  37. package/dist/services/session/MigrationManager.js +176 -0
  38. package/dist/services/session/Session.js +733 -0
  39. package/dist/services/session/SessionManager.js +255 -0
  40. package/dist/services/session/SessionStore.js +186 -0
  41. package/dist/services/session/index.js +3 -0
  42. package/dist/services/skills.js +34 -0
  43. package/dist/services/systemPrompt.js +150 -0
  44. package/dist/services/task/PushTokenStore.js +124 -0
  45. package/dist/services/task/TaskStore.js +143 -0
  46. package/dist/services/tools/calculator.js +27 -0
  47. package/dist/services/tools/edit.js +318 -0
  48. package/dist/services/tools/exec.js +119 -0
  49. package/dist/services/tools/fetch.js +155 -0
  50. package/dist/services/tools/file.js +315 -0
  51. package/dist/services/tools/index.js +48 -0
  52. package/dist/services/tools/keyboard.js +145 -0
  53. package/dist/services/tools/model.js +86 -0
  54. package/dist/services/tools/mouse.js +55 -0
  55. package/dist/services/tools/screenshot.js +19 -0
  56. package/dist/services/tools/search.js +53 -0
  57. package/dist/services/tools/skill.js +108 -0
  58. package/dist/services/tools/task.js +110 -0
  59. package/dist/services/tools/types.js +1 -0
  60. package/dist/services/tools/webFetch.js +34 -0
  61. package/dist/stores/authStore.js +178 -0
  62. package/dist/stores/index.js +6 -0
  63. package/dist/stores/memoryStore.js +191 -0
  64. package/dist/stores/persistStore.js +317 -0
  65. package/package.json +94 -0
@@ -0,0 +1,513 @@
1
+ import { Router } from 'express';
2
+ import { requireAuth } from '@/middleware/auth.js';
3
+ import { sessionManager } from '@/services/session';
4
+ import { initAgentManager, agentManager } from '@/services/agent/AgentManager';
5
+ import { AgentStore } from '@/services/agent/AgentStore';
6
+ import { getLogger } from '@pocketclaw/shared';
7
+ const logger = getLogger('AgentRoutes');
8
+ import { sessionStore } from '@/services/session/SessionStore';
9
+ const router = Router();
10
+ // 所有路由需要认证
11
+ router.use(requireAuth);
12
+ // Middleware: ensure agentManager is initialized
13
+ function ensureAgentManager(req, res, next) {
14
+ try {
15
+ // Get or create AgentStore using SessionStore's db instance
16
+ const db = sessionStore.getDb();
17
+ const agentStore = new AgentStore(db);
18
+ // Initialize AgentManager if not already done
19
+ if (!agentManager) {
20
+ initAgentManager(agentStore);
21
+ }
22
+ agentManager.initialize();
23
+ req.agentManager = agentManager;
24
+ next();
25
+ }
26
+ catch (error) {
27
+ logger.error('Failed to initialize agentManager:', error);
28
+ res.status(500).json({ success: false, error: 'Failed to initialize agent manager' });
29
+ }
30
+ }
31
+ // ============ Agent CRUD ============
32
+ /**
33
+ * GET /api/agent/list
34
+ * Get all agents for current user
35
+ */
36
+ router.get('/list', ensureAgentManager, async (req, res) => {
37
+ try {
38
+ const userId = req.userId;
39
+ const agentList = agentManager.getAgentList();
40
+ res.json({ success: true, data: agentList });
41
+ }
42
+ catch (error) {
43
+ logger.error(`Get agent list error: ${error}`);
44
+ res.status(500).json({ success: false, error: 'Failed to get agent list' });
45
+ }
46
+ });
47
+ /**
48
+ * GET /api/agent/:id
49
+ * Get agent details
50
+ */
51
+ router.get('/:id', ensureAgentManager, async (req, res) => {
52
+ try {
53
+ const userId = req.userId;
54
+ const agent = agentManager.getAgent(req.params.id);
55
+ if (!agent) {
56
+ return res.status(404).json({ success: false, error: 'Agent not found' });
57
+ }
58
+ res.json({
59
+ success: true,
60
+ data: {
61
+ id: agent.id,
62
+ name: agent.name,
63
+ description: agent.description,
64
+ systemPrompt: agent.systemPrompt,
65
+ avatar: agent.avatar,
66
+ config: agent.config,
67
+ createdAt: agent.createdAt,
68
+ updatedAt: agent.updatedAt,
69
+ }
70
+ });
71
+ }
72
+ catch (error) {
73
+ logger.error(`Get agent error: ${error}`);
74
+ res.status(500).json({ success: false, error: 'Failed to get agent' });
75
+ }
76
+ });
77
+ /**
78
+ * POST /api/agent/create
79
+ * Create new agent
80
+ */
81
+ router.post('/create', ensureAgentManager, async (req, res) => {
82
+ try {
83
+ const userId = req.userId;
84
+ const { name, description, systemPrompt, avatar, config } = req.body;
85
+ if (!name) {
86
+ return res.status(400).json({ success: false, error: 'Name is required' });
87
+ }
88
+ const agent = agentManager.createAgent({
89
+ name,
90
+ description,
91
+ systemPrompt,
92
+ avatar,
93
+ config,
94
+ });
95
+ res.json({
96
+ success: true,
97
+ data: {
98
+ id: agent.id,
99
+ name: agent.name,
100
+ description: agent.description,
101
+ systemPrompt: agent.systemPrompt,
102
+ avatar: agent.avatar,
103
+ createdAt: agent.createdAt,
104
+ updatedAt: agent.updatedAt,
105
+ }
106
+ });
107
+ }
108
+ catch (error) {
109
+ logger.error(`Create agent error: ${error}`);
110
+ const message = error instanceof Error ? error.message : 'Failed to create agent';
111
+ res.status(400).json({ success: false, error: message });
112
+ }
113
+ });
114
+ /**
115
+ * PUT /api/agent/:id
116
+ * Update agent
117
+ */
118
+ router.put('/:id', ensureAgentManager, async (req, res) => {
119
+ try {
120
+ const userId = req.userId;
121
+ logger.debug('update agent', req.body);
122
+ const { name, description, systemPrompt, avatar, config } = req.body;
123
+ const agent = agentManager.updateAgent(req.params.id, {
124
+ name,
125
+ description,
126
+ systemPrompt,
127
+ avatar,
128
+ config,
129
+ });
130
+ if (!agent) {
131
+ return res.status(404).json({ success: false, error: 'Agent not found' });
132
+ }
133
+ res.json({
134
+ success: true,
135
+ data: {
136
+ id: agent.id,
137
+ name: agent.name,
138
+ description: agent.description,
139
+ systemPrompt: agent.systemPrompt,
140
+ avatar: agent.avatar,
141
+ updatedAt: agent.updatedAt,
142
+ }
143
+ });
144
+ }
145
+ catch (error) {
146
+ logger.error(`Update agent error: ${error}`);
147
+ const message = error instanceof Error ? error.message : 'Failed to update agent';
148
+ res.status(400).json({ success: false, error: message });
149
+ }
150
+ });
151
+ /**
152
+ * DELETE /api/agent/:id
153
+ * Delete agent
154
+ */
155
+ router.delete('/:id', ensureAgentManager, async (req, res) => {
156
+ try {
157
+ const userId = req.userId;
158
+ const deleted = agentManager.deleteAgent(req.params.id);
159
+ if (!deleted) {
160
+ return res.status(404).json({ success: false, error: 'Agent not found' });
161
+ }
162
+ res.json({ success: true });
163
+ }
164
+ catch (error) {
165
+ logger.error(`Delete agent error: ${error}`);
166
+ const message = error instanceof Error ? error.message : 'Failed to delete agent';
167
+ res.status(400).json({ success: false, error: message });
168
+ }
169
+ });
170
+ // ============ Current Agent ============
171
+ /**
172
+ * GET /api/agent/current
173
+ * Get current agent
174
+ */
175
+ router.get('/current', ensureAgentManager, async (req, res) => {
176
+ try {
177
+ const userId = req.userId;
178
+ const current = agentManager.getCurrentAgent();
179
+ res.json({
180
+ success: true, data: current ? {
181
+ id: current.id,
182
+ userId: current.userId,
183
+ name: current.name,
184
+ description: current.description,
185
+ systemPrompt: current.systemPrompt,
186
+ avatar: current.avatar,
187
+ config: current.config,
188
+ createdAt: current.createdAt,
189
+ updatedAt: current.updatedAt,
190
+ } : null
191
+ });
192
+ }
193
+ catch (error) {
194
+ logger.error(`Get current agent error: ${error}`);
195
+ res.status(500).json({ success: false, error: 'Failed to get current agent' });
196
+ }
197
+ });
198
+ /**
199
+ * POST /api/agent/set-current
200
+ * Set current agent
201
+ */
202
+ router.post('/set-current', ensureAgentManager, async (req, res) => {
203
+ try {
204
+ const userId = req.userId;
205
+ const { agentId } = req.body;
206
+ agentManager.setCurrentAgent(agentId || null);
207
+ res.json({ success: true });
208
+ }
209
+ catch (error) {
210
+ logger.error(`Set current agent error: ${error}`);
211
+ res.status(500).json({ success: false, error: 'Failed to set current agent' });
212
+ }
213
+ });
214
+ // ============ Session Management under Agent ============
215
+ /**
216
+ * GET /api/agent/:id/sessions
217
+ * Get all sessions under an agent
218
+ */
219
+ router.get('/:id/sessions', ensureAgentManager, async (req, res) => {
220
+ try {
221
+ const userId = req.userId;
222
+ const agent = agentManager.getAgent(req.params.id);
223
+ if (!agent) {
224
+ return res.status(404).json({ success: false, error: 'Agent not found' });
225
+ }
226
+ const sessions = agentManager.getAgentSessions(req.params.id);
227
+ res.json({ success: true, data: sessions });
228
+ }
229
+ catch (error) {
230
+ logger.error(`Get agent sessions error: `, error);
231
+ res.status(500).json({ success: false, error: 'Failed to get sessions' });
232
+ }
233
+ });
234
+ /**
235
+ * POST /api/agent/:id/sessions
236
+ * Create new session under agent
237
+ */
238
+ router.post('/:id/sessions', ensureAgentManager, async (req, res) => {
239
+ try {
240
+ const userId = req.userId;
241
+ const agent = agentManager.getAgent(req.params.id);
242
+ if (!agent) {
243
+ return res.status(404).json({ success: false, error: 'Agent not found' });
244
+ }
245
+ const { title, selectModelId } = req.body;
246
+ const session = agent.createSession({
247
+ title: title || '新会话',
248
+ selectModelId,
249
+ });
250
+ res.json({
251
+ success: true,
252
+ data: {
253
+ id: session.id,
254
+ title: session.title,
255
+ selectModelId: session.selectModelId,
256
+ createdAt: session.createdAt,
257
+ updatedAt: session.updatedAt,
258
+ }
259
+ });
260
+ }
261
+ catch (error) {
262
+ logger.error(`Create session error: ${error}`);
263
+ res.status(500).json({ success: false, error: 'Failed to create session' });
264
+ }
265
+ });
266
+ /**
267
+ * PUT /api/agent/:id/sessions/:sessionId
268
+ * Update session under agent
269
+ */
270
+ router.put('/:id/sessions/:sessionId', ensureAgentManager, async (req, res) => {
271
+ try {
272
+ const userId = req.userId;
273
+ const agent = agentManager.getAgent(req.params.id);
274
+ if (!agent) {
275
+ return res.status(404).json({ success: false, error: 'Agent not found' });
276
+ }
277
+ const { title, selectModelId, unreadCount } = req.body;
278
+ const session = agent.updateSession(req.params.sessionId, { title, selectModelId, unreadCount });
279
+ res.json({
280
+ success: true,
281
+ data: {
282
+ id: session.id,
283
+ title: session.title,
284
+ selectModelId: session.selectModelId,
285
+ createdAt: session.createdAt,
286
+ updatedAt: session.updatedAt,
287
+ }
288
+ });
289
+ }
290
+ catch (error) {
291
+ logger.error(`Update session error: ${error}`);
292
+ res.status(500).json({ success: false, error: 'Failed to update session' });
293
+ }
294
+ });
295
+ /**
296
+ * DELETE /api/agent/:id/sessions/:sessionId
297
+ * Delete session under agent
298
+ */
299
+ router.delete('/:id/sessions/:sessionId', ensureAgentManager, async (req, res) => {
300
+ try {
301
+ const userId = req.userId;
302
+ const agent = agentManager.getAgent(req.params.id);
303
+ if (!agent) {
304
+ return res.status(404).json({ success: false, error: 'Agent not found' });
305
+ }
306
+ const deleted = agent.deleteSession(req.params.sessionId);
307
+ res.json({ success: deleted });
308
+ }
309
+ catch (error) {
310
+ logger.error(`Delete session error: ${error}`);
311
+ res.status(500).json({ success: false, error: 'Failed to delete session' });
312
+ }
313
+ });
314
+ // ============ Session Messages ============
315
+ /**
316
+ * GET /api/agent/sessions/:sessionId/messages
317
+ * Get messages for a session
318
+ */
319
+ router.get('/sessions/:sessionId/messages', ensureAgentManager, async (req, res) => {
320
+ try {
321
+ const userId = req.userId;
322
+ const { sessionId } = req.params;
323
+ const page = parseInt(req.query.page) || 1;
324
+ const pageSize = parseInt(req.query.pageSize) || 20;
325
+ // Find session directly
326
+ const session = sessionManager.getSession(sessionId);
327
+ if (session) {
328
+ session.loadMessages(); // Ensure messages are loaded
329
+ const messages = session.getMessagesByPage(page, pageSize);
330
+ return res.json({
331
+ success: true,
332
+ data: messages.messages.reverse(), // Return in chronological order
333
+ pagination: {
334
+ page,
335
+ pageSize,
336
+ total: messages.total,
337
+ hasMore: messages.hasMore,
338
+ },
339
+ });
340
+ }
341
+ res.status(404).json({ success: false, error: 'Session not found' });
342
+ }
343
+ catch (error) {
344
+ logger.error(`Get messages error: ${error}`);
345
+ res.status(500).json({ success: false, error: 'Failed to get messages' });
346
+ }
347
+ });
348
+ /**
349
+ * DELETE /api/agent/sessions/:sessionId/messages/:messageId
350
+ * Delete a specific message
351
+ */
352
+ router.delete('/sessions/:sessionId/messages/:messageId', ensureAgentManager, async (req, res) => {
353
+ try {
354
+ const userId = req.userId;
355
+ const { sessionId, messageId } = req.params;
356
+ // Find session directly
357
+ const session = sessionManager.getSession(sessionId);
358
+ if (session) {
359
+ session.deleteMessage(messageId);
360
+ return res.json({ success: true });
361
+ }
362
+ res.status(404).json({ success: false, error: 'Session or message not found' });
363
+ }
364
+ catch (error) {
365
+ logger.error(`Delete message error: ${error}`);
366
+ res.status(500).json({ success: false, error: 'Failed to delete message' });
367
+ }
368
+ });
369
+ /**
370
+ * PUT /api/agent/sessions/:sessionId/messages/:messageId/feedback
371
+ * Update message feedback (like/dislike)
372
+ */
373
+ router.put('/sessions/:sessionId/messages/:messageId/feedback', ensureAgentManager, async (req, res) => {
374
+ try {
375
+ const userId = req.userId;
376
+ const { sessionId, messageId } = req.params;
377
+ const { feedback } = req.body; // 'like' | 'dislike' | null
378
+ if (feedback !== null && feedback !== 'like' && feedback !== 'dislike') {
379
+ return res.status(400).json({ success: false, error: 'Invalid feedback value. Must be "like", "dislike", or null' });
380
+ }
381
+ const session = sessionManager.getSession(sessionId);
382
+ if (session) {
383
+ session.updateMessageFeedback(messageId, feedback);
384
+ return res.json({ success: true, data: { messageId, feedback } });
385
+ }
386
+ res.status(404).json({ success: false, error: 'Session or message not found' });
387
+ }
388
+ catch (error) {
389
+ logger.error(`Update message feedback error: ${error}`);
390
+ res.status(500).json({ success: false, error: 'Failed to update message feedback' });
391
+ }
392
+ });
393
+ /**
394
+ * DELETE /api/agent/sessions/:sessionId/messages
395
+ * Clear all messages in a session
396
+ */
397
+ router.delete('/sessions/:sessionId/messages', ensureAgentManager, async (req, res) => {
398
+ try {
399
+ const userId = req.userId;
400
+ const { sessionId } = req.params;
401
+ // Find session directly
402
+ const session = sessionManager.getSession(sessionId);
403
+ if (session) {
404
+ session.clearMessages();
405
+ return res.json({ success: true });
406
+ }
407
+ res.status(404).json({ success: false, error: 'Session not found' });
408
+ }
409
+ catch (error) {
410
+ logger.error(`Clear messages error: ${error}`);
411
+ res.status(500).json({ success: false, error: 'Failed to clear messages' });
412
+ }
413
+ });
414
+ /**
415
+ * POST /api/agent/sessions/:sessionId/stream
416
+ * Stream chat response
417
+ */
418
+ router.post('/sessions/:sessionId/stream', ensureAgentManager, async (req, res) => {
419
+ try {
420
+ const userId = req.userId;
421
+ const { sessionId } = req.params;
422
+ const { content, attachments, userMessageId, assistantMessageId, taskId } = req.body;
423
+ if (!content) {
424
+ return res.status(400).json({ success: false, error: 'Content is required' });
425
+ }
426
+ // Find session directly
427
+ const session = sessionManager.getSession(sessionId);
428
+ if (session) {
429
+ // Set SSE headers
430
+ res.setHeader('Content-Type', 'text/event-stream');
431
+ res.setHeader('Cache-Control', 'no-cache');
432
+ res.setHeader('Connection', 'keep-alive');
433
+ res.flushHeaders();
434
+ // Stream response
435
+ await session.streamChat(content, attachments || [], res, userMessageId, assistantMessageId);
436
+ return;
437
+ }
438
+ res.status(404).json({ success: false, error: 'Session not found' });
439
+ }
440
+ catch (error) {
441
+ logger.error(`Stream chat error: ${error}`);
442
+ if (error.message.includes('未提供认证 Token')) {
443
+ res.status(401).json({ success: false, error: 'Token失效' });
444
+ }
445
+ if (!res.headersSent) {
446
+ res.status(500).json({ success: false, error: 'Failed to stream chat' });
447
+ }
448
+ else {
449
+ sendSSE(res, { type: 'error', error: error.message });
450
+ res.end();
451
+ }
452
+ }
453
+ });
454
+ // SSE 辅助方法:发送数据并立即 flush
455
+ const sendSSE = (res, data) => {
456
+ res.write(`data: ${JSON.stringify(data)}\n\n`);
457
+ res.flush?.();
458
+ };
459
+ /**
460
+ * POST /api/agent/sessions/:sessionId/reset
461
+ * Stop session generation
462
+ */
463
+ router.post('/sessions/:sessionId/reset', async (req, res) => {
464
+ try {
465
+ const userId = req.userId;
466
+ const { sessionId } = req.params;
467
+ const stopped = sessionManager.stopSession(sessionId);
468
+ res.json({ success: true, data: { stopped } });
469
+ }
470
+ catch (error) {
471
+ logger.error(`Reset session error: ${error}`);
472
+ const message = error instanceof Error ? error.message : 'Failed to reset session';
473
+ res.status(500).json({ success: false, error: message });
474
+ }
475
+ });
476
+ /**
477
+ * POST /api/agent/sessions/:sessionId/set-current
478
+ * Mark session as current (clears unread count)
479
+ */
480
+ router.post('/sessions/:sessionId/set-current', async (req, res) => {
481
+ try {
482
+ const userId = req.userId;
483
+ const { sessionId } = req.params;
484
+ sessionManager.setCurrentSession(sessionId);
485
+ // 同步清除 session 的未读数
486
+ const session = sessionManager.getSession(sessionId);
487
+ if (session) {
488
+ session.clearUnreadCount();
489
+ }
490
+ res.json({ success: true });
491
+ }
492
+ catch (error) {
493
+ logger.error(`Set current session error: ${error}`);
494
+ const message = error instanceof Error ? error.message : 'Failed to set current session';
495
+ res.status(500).json({ success: false, error: message });
496
+ }
497
+ });
498
+ /**
499
+ * GET /api/agent/sessions/unread-count
500
+ * Get total unread count across all sessions
501
+ */
502
+ router.get('/sessions/unread-count', async (req, res) => {
503
+ try {
504
+ const userId = req.userId;
505
+ const total = sessionManager.getTotalUnreadCount();
506
+ res.json({ success: true, data: { total } });
507
+ }
508
+ catch (error) {
509
+ logger.error(`Get unread count error: ${error}`);
510
+ res.status(500).json({ success: false, error: 'Failed to get unread count' });
511
+ }
512
+ });
513
+ export default router;
@@ -0,0 +1,172 @@
1
+ import { Router } from 'express';
2
+ import { authApi } from '../api/index.js';
3
+ import { authStore } from '../stores/index.js';
4
+ import { optionalAuth, requireAuth } from '../middleware/auth.js';
5
+ import { getLogger } from '@pocketclaw/shared';
6
+ import { getPlatform } from '@pocketclaw/shared/dist/utils/system.js';
7
+ const logger = getLogger('auth');
8
+ const router = Router();
9
+ // Check auth status - 解码请求中的 token 返回认证状态
10
+ router.get('/isAuth', optionalAuth, async (req, res) => {
11
+ const userId = req.userId;
12
+ res.json({
13
+ authenticated: !!userId,
14
+ user: userId ? { id: userId } : null,
15
+ });
16
+ });
17
+ // Get publish token - 获取发布技能库所需的 token
18
+ router.get('/publish-token', requireAuth, async (req, res) => {
19
+ res.json({
20
+ success: true,
21
+ token: req.token,
22
+ user: { id: req.userId },
23
+ });
24
+ });
25
+ // Register - 使用 authApi 注册
26
+ router.post('/register', async (req, res) => {
27
+ try {
28
+ const { username, password } = req.body;
29
+ if (!username || !password) {
30
+ res.status(400).json({ success: false, error: 'Missing required fields' });
31
+ return;
32
+ }
33
+ // 使用 authApi.register(服务端路由期望 account 字段)
34
+ const response = await authApi.register({
35
+ account: username,
36
+ password,
37
+ nickname: username,
38
+ platform: getPlatform(),
39
+ });
40
+ if (response.success && response.data) {
41
+ const expiresIn = response.data.expiresIn || 86400;
42
+ authStore.save({
43
+ token: response.data.accessToken,
44
+ refreshToken: response.data.refreshToken,
45
+ expiresIn,
46
+ expiresAt: Date.now() + expiresIn * 1000,
47
+ user: response.data.user,
48
+ });
49
+ res.status(201).json({
50
+ success: true,
51
+ user: response.data.user,
52
+ });
53
+ }
54
+ else {
55
+ res.status(400).json({ success: false, error: response.error || 'Registration failed' });
56
+ }
57
+ }
58
+ catch (error) {
59
+ logger.error('Register error:', error);
60
+ res.status(error.status || 500).json({
61
+ success: false,
62
+ error: error.message || 'Registration failed',
63
+ });
64
+ }
65
+ });
66
+ // Login - 使用 authApi 登录
67
+ router.post('/login', async (req, res) => {
68
+ try {
69
+ const { username, password } = req.body;
70
+ logger.debug('Login attempt for:', username);
71
+ if (!username || !password) {
72
+ res.status(400).json({ success: false, error: 'Missing required fields' });
73
+ return;
74
+ }
75
+ // 使用 authApi.login(服务端路由期望 email 字段)
76
+ const response = await authApi.login({
77
+ account: username,
78
+ password,
79
+ platform: getPlatform(),
80
+ });
81
+ if (response.success && response.data) {
82
+ const expiresIn = response.data.expiresIn || 86400;
83
+ authStore.save({
84
+ token: response.data.accessToken,
85
+ refreshToken: response.data.refreshToken,
86
+ expiresIn,
87
+ expiresAt: Date.now() + expiresIn * 1000,
88
+ user: response.data.user,
89
+ });
90
+ res.json({
91
+ success: true,
92
+ user: response.data.user,
93
+ });
94
+ }
95
+ else {
96
+ res.status(401).json({ success: false, error: response.error || 'Invalid credentials' });
97
+ }
98
+ }
99
+ catch (error) {
100
+ logger.error('Login error:', error);
101
+ res.status(error.status || 500).json({
102
+ success: false,
103
+ error: error.message || 'Login failed',
104
+ });
105
+ }
106
+ });
107
+ // Refresh token - 使用 authApi 刷新
108
+ router.post('/refresh', async (req, res) => {
109
+ try {
110
+ const { refreshToken } = req.body;
111
+ if (!refreshToken) {
112
+ res.status(400).json({ success: false, error: 'Missing refresh token' });
113
+ return;
114
+ }
115
+ const response = await authApi.refresh(refreshToken);
116
+ if (response.success && response.accessToken) {
117
+ authStore.updateToken(response.accessToken, response.refreshToken);
118
+ res.json({ success: true });
119
+ }
120
+ else {
121
+ res.status(401).json({ success: false, error: response.error || 'Invalid refresh token' });
122
+ }
123
+ }
124
+ catch (error) {
125
+ logger.error('Refresh error:', error);
126
+ res.status(error.status || 500).json({
127
+ success: false,
128
+ error: error.message || 'Refresh failed',
129
+ });
130
+ }
131
+ });
132
+ // Logout - 清除本地存储
133
+ router.post('/logout', requireAuth, async (req, res) => {
134
+ try {
135
+ // refreshToken 在请求 body 中
136
+ const { refreshToken } = req.body;
137
+ // 尝试转发登出请求到 Server(忽略错误)
138
+ if (refreshToken) {
139
+ authApi.logout().catch(() => { });
140
+ }
141
+ authStore.clear();
142
+ res.json({ success: true });
143
+ }
144
+ catch (error) {
145
+ authStore.clear();
146
+ res.json({ success: true });
147
+ }
148
+ });
149
+ // Delete account - 删除账号
150
+ router.post('/account/delete', requireAuth, async (req, res) => {
151
+ try {
152
+ const { password } = req.body;
153
+ if (!password) {
154
+ res.status(400).json({ success: false, error: 'Missing password' });
155
+ return;
156
+ }
157
+ // 转发删除账号请求到 Server(带上 token)
158
+ const response = await authApi.deleteAccount({ password }, req.token);
159
+ if (response.success) {
160
+ authStore.clear();
161
+ }
162
+ res.json(response);
163
+ }
164
+ catch (error) {
165
+ logger.error('Delete account error:', error);
166
+ res.status(error.status || 500).json({
167
+ success: false,
168
+ error: error.message || 'Delete account failed',
169
+ });
170
+ }
171
+ });
172
+ export default router;