neoagent 2.0.3 → 2.0.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.
@@ -13,6 +13,30 @@ const authLimiter = rateLimit({
13
13
  legacyHeaders: false
14
14
  });
15
15
 
16
+ function establishSession(req, res, user) {
17
+ req.session.regenerate((regenerateError) => {
18
+ if (regenerateError) {
19
+ console.error('Auth session regenerate error:', regenerateError);
20
+ return res.status(500).json({ error: 'Session error' });
21
+ }
22
+
23
+ req.session.userId = user.id;
24
+ req.session.username = user.username;
25
+ req.session.save((saveError) => {
26
+ if (saveError) {
27
+ console.error('Auth session save error:', saveError);
28
+ return res.status(500).json({ error: 'Session save error' });
29
+ }
30
+
31
+ return res.json({
32
+ success: true,
33
+ redirect: '/app',
34
+ user: { id: user.id, username: user.username }
35
+ });
36
+ });
37
+ });
38
+ }
39
+
16
40
  router.get('/api/auth/status', (req, res) => {
17
41
  const count = db.prepare('SELECT COUNT(*) as count FROM users').get();
18
42
  res.json({ hasUser: count.count > 0 });
@@ -36,14 +60,9 @@ router.post('/api/auth/register', authLimiter, async (req, res) => {
36
60
  const hash = await bcrypt.hash(password, 12);
37
61
  const result = db.prepare('INSERT INTO users (username, password) VALUES (?, ?)').run(username, hash);
38
62
 
39
- req.session.regenerate((err) => {
40
- if (err) return res.status(500).json({ error: 'Session error' });
41
- req.session.userId = result.lastInsertRowid;
42
- req.session.username = username;
43
- req.session.save((err) => {
44
- if (err) return res.status(500).json({ error: 'Session save error' });
45
- res.json({ success: true, redirect: '/app', user: { id: result.lastInsertRowid, username } });
46
- });
63
+ establishSession(req, res, {
64
+ id: result.lastInsertRowid,
65
+ username
47
66
  });
48
67
  } catch (err) {
49
68
  console.error('Register error:', err);
@@ -68,17 +87,14 @@ router.post('/api/auth/login', authLimiter, async (req, res) => {
68
87
  return res.status(401).json({ error: 'Invalid credentials' });
69
88
  }
70
89
 
71
- db.prepare('UPDATE users SET last_login = datetime(\'now\') WHERE id = ?').run(user.id);
90
+ try {
91
+ db.prepare('UPDATE users SET last_login = datetime(\'now\') WHERE id = ?').run(user.id);
92
+ } catch (updateError) {
93
+ // Keep login functional even if analytics-style metadata cannot be written.
94
+ console.warn('Login last_login update failed:', updateError);
95
+ }
72
96
 
73
- req.session.regenerate((err) => {
74
- if (err) return res.status(500).json({ error: 'Session error' });
75
- req.session.userId = user.id;
76
- req.session.username = user.username;
77
- req.session.save((err) => {
78
- if (err) return res.status(500).json({ error: 'Session save error' });
79
- res.json({ success: true, redirect: '/app', user: { id: user.id, username: user.username } });
80
- });
81
- });
97
+ establishSession(req, res, user);
82
98
  } catch (err) {
83
99
  console.error('Login error:', err);
84
100
  res.status(500).json({ error: 'Login failed' });
@@ -137,12 +137,30 @@ function ingestHealthSync(userId, body = {}) {
137
137
  return ingestHealthSyncTx(userId, body);
138
138
  }
139
139
 
140
+ function hydrateRun(row) {
141
+ if (!row) return null;
142
+ return {
143
+ ...row,
144
+ summary: (() => {
145
+ try { return JSON.parse(row.summary_json || '{}'); } catch { return {}; }
146
+ })(),
147
+ };
148
+ }
149
+
140
150
  function getHealthSyncStatus(userId) {
141
151
  const lastRun = db.prepare(`
142
152
  SELECT id, source, provider, sync_window_start, sync_window_end, record_count, summary_json, created_at
143
153
  FROM health_sync_runs
144
154
  WHERE user_id = ?
145
- ORDER BY created_at DESC
155
+ ORDER BY created_at DESC, rowid DESC
156
+ LIMIT 1
157
+ `).get(userId);
158
+
159
+ const lastNonEmptyRun = db.prepare(`
160
+ SELECT id, source, provider, sync_window_start, sync_window_end, record_count, summary_json, created_at
161
+ FROM health_sync_runs
162
+ WHERE user_id = ? AND record_count > 0
163
+ ORDER BY created_at DESC, rowid DESC
146
164
  LIMIT 1
147
165
  `).get(userId);
148
166
 
@@ -155,12 +173,8 @@ function getHealthSyncStatus(userId) {
155
173
  `).all(userId);
156
174
 
157
175
  return {
158
- lastRun: lastRun ? {
159
- ...lastRun,
160
- summary: (() => {
161
- try { return JSON.parse(lastRun.summary_json || '{}'); } catch { return {}; }
162
- })(),
163
- } : null,
176
+ lastRun: hydrateRun(lastRun),
177
+ lastNonEmptyRun: hydrateRun(lastNonEmptyRun),
164
178
  metrics: metrics.map((metric) => ({
165
179
  metricType: metric.metric_type,
166
180
  sampleCount: Number(metric.sample_count || 0),