@yeaft/webchat-agent 1.0.656 → 1.0.658

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.
@@ -1,6 +1,7 @@
1
1
  // Re-export entry point — preserves all existing import paths.
2
2
  // Actual implementations are in server/db/*.js sub-modules.
3
3
  export { userDb } from './db/user-db.js';
4
+ export { userPreferencesDb } from './db/user-preferences-db.js';
4
5
  export { invitationDb } from './db/invitation-db.js';
5
6
  export { sessionDb } from './db/session-db.js';
6
7
  export { yeaftSessionDb } from './db/yeaft-session-db.js';
@@ -38,6 +38,12 @@ db.exec(`
38
38
  deletion_id TEXT UNIQUE
39
39
  );
40
40
 
41
+ CREATE TABLE IF NOT EXISTS user_preferences (
42
+ user_id TEXT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
43
+ sidebar_projects_ratio REAL NOT NULL DEFAULT 0.5
44
+ CHECK (sidebar_projects_ratio >= 0.15 AND sidebar_projects_ratio <= 0.85)
45
+ );
46
+
41
47
  -- Finalized deletion survives removal of the users row. This prevents a
42
48
  -- configured credential from becoming authoritative again on restart.
43
49
  CREATE TABLE IF NOT EXISTS user_deletion_tombstones (
@@ -900,6 +906,17 @@ export const stmts = {
900
906
  UPDATE users SET aad_oid = ? WHERE id = ?
901
907
  `),
902
908
 
909
+ getUserPreferences: db.prepare(`
910
+ SELECT sidebar_projects_ratio FROM user_preferences WHERE user_id = ?
911
+ `),
912
+
913
+ upsertUserPreferences: db.prepare(`
914
+ INSERT INTO user_preferences (user_id, sidebar_projects_ratio)
915
+ VALUES (?, ?)
916
+ ON CONFLICT(user_id) DO UPDATE SET
917
+ sidebar_projects_ratio = excluded.sidebar_projects_ratio
918
+ `),
919
+
903
920
  // Invitation 操作
904
921
  insertInvitation: db.prepare(`
905
922
  INSERT INTO invitations (id, created_by, created_at, expires_at, role)
@@ -0,0 +1,15 @@
1
+ import { stmts } from './connection.js';
2
+
3
+ /** Server-owned browser preferences, scoped to an authenticated user's DB id. */
4
+ export const userPreferencesDb = {
5
+ get(userId) {
6
+ const row = stmts.getUserPreferences.get(userId);
7
+ return { sidebarProjectsRatio: row?.sidebar_projects_ratio ?? 0.5 };
8
+ },
9
+
10
+ // The HTTP boundary validates the ratio; the schema also enforces its range.
11
+ update(userId, sidebarProjectsRatio) {
12
+ stmts.upsertUserPreferences.run(userId, sidebarProjectsRatio);
13
+ return this.get(userId);
14
+ },
15
+ };
@@ -1,6 +1,6 @@
1
1
  import { CONFIG } from '../config.js';
2
2
  import { hashPassword } from '../auth.js';
3
- import { userDb, sessionDb } from '../database.js';
3
+ import { userDb, userPreferencesDb, sessionDb } from '../database.js';
4
4
  import {
5
5
  activeSessions, pendingVerifications, pendingTotpVerifications, pendingTotpSetup,
6
6
  revokedTokens
@@ -83,6 +83,44 @@ export function registerUserRoutes(app, {
83
83
  }
84
84
  });
85
85
 
86
+ app.get('/api/user/preferences', requireAuth, (req, res) => {
87
+ try {
88
+ const user = loadCurrentUser(req);
89
+ if (!user) {
90
+ return res.status(404).json({ error: 'User not found' });
91
+ }
92
+ res.set('Cache-Control', 'private, no-store').json(userPreferencesDb.get(user.id));
93
+ } catch (err) {
94
+ console.error('Get preferences error:', err);
95
+ res.status(500).json({ error: 'Failed to get preferences' });
96
+ }
97
+ });
98
+
99
+ app.patch('/api/user/preferences', requireAuth, (req, res) => {
100
+ try {
101
+ const user = loadCurrentUser(req);
102
+ if (!user) {
103
+ return res.status(404).json({ error: 'User not found' });
104
+ }
105
+
106
+ const body = req.body;
107
+ if (!body || typeof body !== 'object' || Array.isArray(body)
108
+ || Object.keys(body).some(key => key !== 'sidebarProjectsRatio')
109
+ || typeof body.sidebarProjectsRatio !== 'number'
110
+ || !Number.isFinite(body.sidebarProjectsRatio)
111
+ || body.sidebarProjectsRatio < 0.15 || body.sidebarProjectsRatio > 0.85) {
112
+ return res.status(400).json({
113
+ error: 'Expected only sidebarProjectsRatio, a finite number between 0.15 and 0.85',
114
+ });
115
+ }
116
+
117
+ res.set('Cache-Control', 'private, no-store').json(userPreferencesDb.update(user.id, body.sidebarProjectsRatio));
118
+ } catch (err) {
119
+ console.error('Update preferences error:', err);
120
+ res.status(500).json({ error: 'Failed to update preferences' });
121
+ }
122
+ });
123
+
86
124
  // Update my profile (password and/or email)
87
125
  app.put('/api/user/profile', requireAuth, async (req, res) => {
88
126
  try {
@@ -1 +1 @@
1
- {"version":"1.0.656"}
1
+ {"version":"1.0.658"}