clay-server 2.30.0 → 2.31.0-beta.1

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 (36) hide show
  1. package/lib/email-accounts.js +299 -0
  2. package/lib/email-mcp-server.js +646 -0
  3. package/lib/project-connection.js +26 -2
  4. package/lib/project-email.js +418 -0
  5. package/lib/project-sessions.js +16 -0
  6. package/lib/project-user-message.js +26 -5
  7. package/lib/project.js +72 -25
  8. package/lib/public/app.js +18 -5
  9. package/lib/public/css/filebrowser.css +80 -2
  10. package/lib/public/css/input.css +196 -0
  11. package/lib/public/css/notifications-center.css +3 -0
  12. package/lib/public/css/sidebar.css +77 -2
  13. package/lib/public/css/sticky-notes.css +0 -48
  14. package/lib/public/css/user-settings.css +85 -0
  15. package/lib/public/icons/email/gmail.svg +7 -0
  16. package/lib/public/icons/email/outlook.svg +35 -0
  17. package/lib/public/icons/email/yahoo.svg +1 -0
  18. package/lib/public/index.html +36 -3
  19. package/lib/public/modules/app-dm.js +4 -9
  20. package/lib/public/modules/app-messages.js +37 -2
  21. package/lib/public/modules/app-panels.js +2 -1
  22. package/lib/public/modules/context-sources.js +527 -1
  23. package/lib/public/modules/filebrowser.js +72 -0
  24. package/lib/public/modules/mate-sidebar.js +7 -0
  25. package/lib/public/modules/sidebar-mobile.js +1 -1
  26. package/lib/public/modules/sidebar.js +144 -2
  27. package/lib/public/modules/sticky-notes.js +1 -91
  28. package/lib/public/modules/terminal.js +0 -12
  29. package/lib/public/modules/theme.js +4 -0
  30. package/lib/public/modules/tools.js +23 -0
  31. package/lib/public/modules/user-settings.js +74 -0
  32. package/lib/sdk-bridge.js +16 -0
  33. package/lib/sdk-message-processor.js +33 -0
  34. package/lib/server-email.js +148 -0
  35. package/lib/server.js +5 -0
  36. package/package.json +3 -2
@@ -0,0 +1,148 @@
1
+ // Server-level WebSocket handlers for email account management.
2
+ // Handles add/remove/test/list of per-user email accounts.
3
+ // Follows the same pattern as server-mates.js.
4
+
5
+ var emailAccounts = require("./email-accounts");
6
+
7
+ function attachEmail(ctx) {
8
+ var users = ctx.users;
9
+
10
+ function getUserId(ws) {
11
+ if (users.isMultiUser()) {
12
+ if (!ws._clayUser) return null;
13
+ return ws._clayUser.id;
14
+ }
15
+ return "default";
16
+ }
17
+
18
+ function sendTo(ws, obj) {
19
+ try {
20
+ if (ws.readyState === 1) ws.send(JSON.stringify(obj));
21
+ } catch (e) {}
22
+ }
23
+
24
+ function handleMessage(ws, msg) {
25
+ var userId = getUserId(ws);
26
+ if (!userId) return false;
27
+
28
+ if (msg.type === "email_accounts_list") {
29
+ var accounts = emailAccounts.listAccounts(userId);
30
+ sendTo(ws, {
31
+ type: "email_accounts_list",
32
+ accounts: accounts,
33
+ providers: emailAccounts.PROVIDER_PRESETS,
34
+ });
35
+ return true;
36
+ }
37
+
38
+ if (msg.type === "email_account_add") {
39
+ if (!msg.email || !msg.appPassword) {
40
+ sendTo(ws, { type: "email_account_add_result", ok: false, error: "Email and app password are required" });
41
+ return true;
42
+ }
43
+
44
+ var result = emailAccounts.addAccount(userId, {
45
+ email: msg.email,
46
+ provider: msg.provider || "custom",
47
+ appPassword: msg.appPassword,
48
+ label: msg.label || "",
49
+ imap: msg.imap || undefined,
50
+ smtp: msg.smtp || undefined,
51
+ });
52
+
53
+ if (result.error) {
54
+ sendTo(ws, { type: "email_account_add_result", ok: false, error: result.error });
55
+ } else {
56
+ sendTo(ws, { type: "email_account_add_result", ok: true, account: result.account });
57
+ // Also send updated list
58
+ var accounts = emailAccounts.listAccounts(userId);
59
+ sendTo(ws, { type: "email_accounts_list", accounts: accounts, providers: emailAccounts.PROVIDER_PRESETS });
60
+ }
61
+ return true;
62
+ }
63
+
64
+ if (msg.type === "email_account_remove") {
65
+ if (!msg.accountId) {
66
+ sendTo(ws, { type: "email_account_remove_result", ok: false, error: "Account ID is required" });
67
+ return true;
68
+ }
69
+
70
+ var result2 = emailAccounts.removeAccount(userId, msg.accountId);
71
+ if (result2.error) {
72
+ sendTo(ws, { type: "email_account_remove_result", ok: false, error: result2.error });
73
+ } else {
74
+ sendTo(ws, { type: "email_account_remove_result", ok: true, accountId: msg.accountId });
75
+ // Also send updated list
76
+ var accounts2 = emailAccounts.listAccounts(userId);
77
+ sendTo(ws, { type: "email_accounts_list", accounts: accounts2, providers: emailAccounts.PROVIDER_PRESETS });
78
+ }
79
+ return true;
80
+ }
81
+
82
+ if (msg.type === "email_account_test") {
83
+ // Test connection for an account that may or may not be saved yet.
84
+ // If accountId is provided, test existing account. Otherwise test with provided credentials.
85
+ var testAccount;
86
+
87
+ if (msg.accountId) {
88
+ testAccount = emailAccounts.getAccountDecrypted(userId, msg.accountId);
89
+ if (!testAccount) {
90
+ sendTo(ws, { type: "email_account_test_result", ok: false, error: "Account not found" });
91
+ return true;
92
+ }
93
+ } else {
94
+ if (!msg.email || !msg.appPassword) {
95
+ sendTo(ws, { type: "email_account_test_result", ok: false, error: "Email and app password are required" });
96
+ return true;
97
+ }
98
+ var provider = msg.provider || "custom";
99
+ var preset = emailAccounts.PROVIDER_PRESETS[provider];
100
+ testAccount = {
101
+ email: msg.email,
102
+ appPassword: msg.appPassword,
103
+ imap: msg.imap || (preset ? Object.assign({}, preset.imap) : { host: "", port: 993, tls: true }),
104
+ smtp: msg.smtp || (preset ? Object.assign({}, preset.smtp) : { host: "", port: 587 }),
105
+ };
106
+ }
107
+
108
+ emailAccounts.testConnection(testAccount).then(function (result3) {
109
+ sendTo(ws, {
110
+ type: "email_account_test_result",
111
+ ok: result3.ok,
112
+ imap: result3.imap,
113
+ smtp: result3.smtp,
114
+ accountId: msg.accountId || null,
115
+ });
116
+ }).catch(function (err) {
117
+ sendTo(ws, {
118
+ type: "email_account_test_result",
119
+ ok: false,
120
+ error: err.message || "Test failed",
121
+ accountId: msg.accountId || null,
122
+ });
123
+ });
124
+ return true;
125
+ }
126
+
127
+ return false;
128
+ }
129
+
130
+ // Send initial email accounts list when a client connects
131
+ function sendInitialState(ws) {
132
+ var userId = getUserId(ws);
133
+ if (!userId) return;
134
+ var accounts = emailAccounts.listAccounts(userId);
135
+ sendTo(ws, {
136
+ type: "email_accounts_list",
137
+ accounts: accounts,
138
+ providers: emailAccounts.PROVIDER_PRESETS,
139
+ });
140
+ }
141
+
142
+ return {
143
+ handleMessage: handleMessage,
144
+ sendInitialState: sendInitialState,
145
+ };
146
+ }
147
+
148
+ module.exports = { attachEmail: attachEmail };
package/lib/server.js CHANGED
@@ -15,6 +15,7 @@ var serverMates = require("./server-mates");
15
15
  var serverAdmin = require("./server-admin");
16
16
  var serverSettings = require("./server-settings");
17
17
  var serverPalette = require("./server-palette");
18
+ var serverEmail = require("./server-email");
18
19
 
19
20
  var { CONFIG_DIR } = require("./config");
20
21
  var { provisionLinuxUser } = require("./os-users");
@@ -1020,6 +1021,9 @@ function createServer(opts) {
1020
1021
  addProject: addProject,
1021
1022
  });
1022
1023
 
1024
+ // --- Email account handler (per-user email account management) ---
1025
+ var emailHandler = serverEmail.attachEmail({ users: users });
1026
+
1023
1027
  // --- Mate handler ---
1024
1028
  // Forward reference: mateHandler is set up after removeProject is defined
1025
1029
  var mateHandler = null;
@@ -1030,6 +1034,7 @@ function createServer(opts) {
1030
1034
  function handleDmMessage(ws, msg) {
1031
1035
  if (dmHandler.handleMessage(ws, msg)) return;
1032
1036
  if (mateHandler && mateHandler.handleMessage(ws, msg)) return;
1037
+ if (emailHandler.handleMessage(ws, msg)) return;
1033
1038
  }
1034
1039
 
1035
1040
  function removeProject(slug) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.30.0",
3
+ "version": "2.31.0-beta.1",
4
4
  "description": "Self-hosted Claude Code in your browser. Multi-session, multi-user, push notifications.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",
@@ -36,8 +36,9 @@
36
36
  "homepage": "https://github.com/chadbyte/claude-relay#readme",
37
37
  "author": "Chad",
38
38
  "dependencies": {
39
- "@anthropic-ai/claude-agent-sdk": "^0.2.92",
39
+ "@anthropic-ai/claude-agent-sdk": "^0.2.112",
40
40
  "@lydell/node-pty": "^1.2.0-beta.3",
41
+ "imapflow": "^1.3.1",
41
42
  "nodemailer": "^6.10.1",
42
43
  "qrcode-terminal": "^0.12.0",
43
44
  "web-push": "^3.6.7",