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.
- package/lib/email-accounts.js +299 -0
- package/lib/email-mcp-server.js +646 -0
- package/lib/project-connection.js +26 -2
- package/lib/project-email.js +418 -0
- package/lib/project-sessions.js +16 -0
- package/lib/project-user-message.js +26 -5
- package/lib/project.js +72 -25
- package/lib/public/app.js +18 -5
- package/lib/public/css/filebrowser.css +80 -2
- package/lib/public/css/input.css +196 -0
- package/lib/public/css/notifications-center.css +3 -0
- package/lib/public/css/sidebar.css +77 -2
- package/lib/public/css/sticky-notes.css +0 -48
- package/lib/public/css/user-settings.css +85 -0
- package/lib/public/icons/email/gmail.svg +7 -0
- package/lib/public/icons/email/outlook.svg +35 -0
- package/lib/public/icons/email/yahoo.svg +1 -0
- package/lib/public/index.html +36 -3
- package/lib/public/modules/app-dm.js +4 -9
- package/lib/public/modules/app-messages.js +37 -2
- package/lib/public/modules/app-panels.js +2 -1
- package/lib/public/modules/context-sources.js +527 -1
- package/lib/public/modules/filebrowser.js +72 -0
- package/lib/public/modules/mate-sidebar.js +7 -0
- package/lib/public/modules/sidebar-mobile.js +1 -1
- package/lib/public/modules/sidebar.js +144 -2
- package/lib/public/modules/sticky-notes.js +1 -91
- package/lib/public/modules/terminal.js +0 -12
- package/lib/public/modules/theme.js +4 -0
- package/lib/public/modules/tools.js +23 -0
- package/lib/public/modules/user-settings.js +74 -0
- package/lib/sdk-bridge.js +16 -0
- package/lib/sdk-message-processor.js +33 -0
- package/lib/server-email.js +148 -0
- package/lib/server.js +5 -0
- 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.
|
|
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.
|
|
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",
|