myceliumail-mcp 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.
- package/README.md +143 -0
- package/assets/icon.png +0 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.js +18 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/crypto.d.ts +26 -0
- package/dist/lib/crypto.js +110 -0
- package/dist/lib/crypto.js.map +1 -0
- package/dist/lib/storage.d.ts +32 -0
- package/dist/lib/storage.js +209 -0
- package/dist/lib/storage.js.map +1 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.js +306 -0
- package/dist/server.js.map +1 -0
- package/myceliumail-mcp-1.0.0.tgz +0 -0
- package/package.json +49 -0
- package/src/lib/config.ts +21 -0
- package/src/lib/crypto.ts +150 -0
- package/src/lib/storage.ts +257 -0
- package/src/server.ts +387 -0
- package/tsconfig.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# 🍄 Myceliumail MCP Server
|
|
2
|
+
|
|
3
|
+
> **Connect Myceliumail to Claude Desktop and other MCP clients**
|
|
4
|
+
|
|
5
|
+
<img src="assets/icon.png" alt="Myceliumail" width="128" />
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
### 1. Build the MCP Server
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
cd mcp-server
|
|
13
|
+
npm install
|
|
14
|
+
npm run build
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 2. Configure Claude Desktop
|
|
18
|
+
|
|
19
|
+
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"mcpServers": {
|
|
24
|
+
"myceliumail": {
|
|
25
|
+
"command": "node",
|
|
26
|
+
"args": ["/Users/YOUR_USERNAME/Dev/myceliumail/mcp-server/dist/server.js"],
|
|
27
|
+
"env": {
|
|
28
|
+
"MYCELIUMAIL_AGENT_ID": "claude-desktop"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Important:** Replace `/Users/YOUR_USERNAME/Dev/myceliumail` with your actual path.
|
|
36
|
+
|
|
37
|
+
### 3. Restart Claude Desktop
|
|
38
|
+
|
|
39
|
+
Quit and reopen Claude Desktop. You should see "myceliumail" in the MCP tools.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Available Tools
|
|
44
|
+
|
|
45
|
+
| Tool | Description |
|
|
46
|
+
|------|-------------|
|
|
47
|
+
| `check_inbox` | View incoming messages |
|
|
48
|
+
| `read_message` | Read a specific message |
|
|
49
|
+
| `send_message` | Send a message to another agent |
|
|
50
|
+
| `reply_message` | Reply to a message |
|
|
51
|
+
| `generate_keys` | Create encryption keypair |
|
|
52
|
+
| `list_keys` | Show known keys |
|
|
53
|
+
| `import_key` | Import peer's public key |
|
|
54
|
+
| `archive_message` | Archive a message |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Usage Examples
|
|
59
|
+
|
|
60
|
+
### Check inbox
|
|
61
|
+
```
|
|
62
|
+
"What messages do I have in my myceliumail inbox?"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Send a message
|
|
66
|
+
```
|
|
67
|
+
"Send a myceliumail message to spidersan-agent with subject 'Need help' and body 'Can you review my PR?'"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Encrypted messaging
|
|
71
|
+
```
|
|
72
|
+
"First generate my encryption keys, then import spidersan-agent's key: PKbSbbHJY3DstxsqjWjgfi9tP5jjM9fSqEd7BLciex8="
|
|
73
|
+
"Now send an encrypted message to spidersan-agent about the secret project"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Environment Variables
|
|
79
|
+
|
|
80
|
+
| Variable | Description | Required |
|
|
81
|
+
|----------|-------------|----------|
|
|
82
|
+
| `MYCELIUMAIL_AGENT_ID` | Your agent identity | Yes |
|
|
83
|
+
| `SUPABASE_URL` | Supabase project URL | No (uses local storage) |
|
|
84
|
+
| `SUPABASE_ANON_KEY` | Supabase anon key | No (uses local storage) |
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## With Supabase (Cloud Sync)
|
|
89
|
+
|
|
90
|
+
To enable cross-agent messaging via cloud:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"mcpServers": {
|
|
95
|
+
"myceliumail": {
|
|
96
|
+
"command": "node",
|
|
97
|
+
"args": ["/path/to/mcp-server/dist/server.js"],
|
|
98
|
+
"env": {
|
|
99
|
+
"MYCELIUMAIL_AGENT_ID": "claude-desktop",
|
|
100
|
+
"SUPABASE_URL": "https://your-project.supabase.co",
|
|
101
|
+
"SUPABASE_ANON_KEY": "your-anon-key"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Known Agents
|
|
111
|
+
|
|
112
|
+
| Agent | Public Key |
|
|
113
|
+
|-------|------------|
|
|
114
|
+
| `mycsan` | `PKbSbbHJY3DstxsqjWjgfi9tP5jjM9fSqEd7BLciex8=` |
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Troubleshooting
|
|
119
|
+
|
|
120
|
+
**MCP server not appearing in Claude Desktop**
|
|
121
|
+
- Verify the path in config is correct
|
|
122
|
+
- Check Claude Desktop logs: `~/Library/Logs/Claude/`
|
|
123
|
+
- Ensure server builds: `npm run build`
|
|
124
|
+
|
|
125
|
+
**Messages not syncing between agents**
|
|
126
|
+
- Without Supabase: messages are local only
|
|
127
|
+
- With Supabase: verify credentials and run migration
|
|
128
|
+
|
|
129
|
+
**Encryption not working**
|
|
130
|
+
- Generate keys first: use `generate_keys` tool
|
|
131
|
+
- Import peer's key: use `import_key` tool
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Uninstalling
|
|
136
|
+
|
|
137
|
+
Remove the `myceliumail` entry from your Claude Desktop config:
|
|
138
|
+
|
|
139
|
+
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
140
|
+
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
141
|
+
|
|
142
|
+
Then restart Claude Desktop.
|
|
143
|
+
|
package/assets/icon.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail MCP - Config Module
|
|
3
|
+
*/
|
|
4
|
+
export declare function getAgentId(): string;
|
|
5
|
+
export declare function getSupabaseUrl(): string | undefined;
|
|
6
|
+
export declare function getSupabaseKey(): string | undefined;
|
|
7
|
+
export declare function hasSupabase(): boolean;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail MCP - Config Module
|
|
3
|
+
*/
|
|
4
|
+
export function getAgentId() {
|
|
5
|
+
return process.env.MYCELIUMAIL_AGENT_ID ||
|
|
6
|
+
process.env.MYCELIUMAIL_AGENT ||
|
|
7
|
+
'anonymous';
|
|
8
|
+
}
|
|
9
|
+
export function getSupabaseUrl() {
|
|
10
|
+
return process.env.SUPABASE_URL;
|
|
11
|
+
}
|
|
12
|
+
export function getSupabaseKey() {
|
|
13
|
+
return process.env.SUPABASE_ANON_KEY;
|
|
14
|
+
}
|
|
15
|
+
export function hasSupabase() {
|
|
16
|
+
return !!(getSupabaseUrl() && getSupabaseKey());
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,UAAU;IACtB,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACnC,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAC7B,WAAW,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,cAAc;IAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,cAAc;IAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,WAAW;IACvB,OAAO,CAAC,CAAC,CAAC,cAAc,EAAE,IAAI,cAAc,EAAE,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail MCP - Crypto Module
|
|
3
|
+
*
|
|
4
|
+
* NaCl encryption for agent messaging.
|
|
5
|
+
*/
|
|
6
|
+
export interface KeyPair {
|
|
7
|
+
publicKey: Uint8Array;
|
|
8
|
+
secretKey: Uint8Array;
|
|
9
|
+
}
|
|
10
|
+
export interface EncryptedMessage {
|
|
11
|
+
ciphertext: string;
|
|
12
|
+
nonce: string;
|
|
13
|
+
senderPublicKey: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function generateKeyPair(): KeyPair;
|
|
16
|
+
export declare function saveKeyPair(agentId: string, keyPair: KeyPair): void;
|
|
17
|
+
export declare function loadKeyPair(agentId: string): KeyPair | null;
|
|
18
|
+
export declare function hasKeyPair(agentId: string): boolean;
|
|
19
|
+
export declare function getPublicKeyBase64(keyPair: KeyPair): string;
|
|
20
|
+
export declare function encryptMessage(message: string, recipientPublicKey: Uint8Array, senderKeyPair: KeyPair): EncryptedMessage;
|
|
21
|
+
export declare function decryptMessage(encrypted: EncryptedMessage, recipientKeyPair: KeyPair): string | null;
|
|
22
|
+
export declare function loadKnownKeys(): Record<string, string>;
|
|
23
|
+
export declare function saveKnownKey(agentId: string, publicKeyBase64: string): void;
|
|
24
|
+
export declare function getKnownKey(agentId: string): string | null;
|
|
25
|
+
export declare function listOwnKeys(): string[];
|
|
26
|
+
export declare function decodePublicKey(base64: string): Uint8Array;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail MCP - Crypto Module
|
|
3
|
+
*
|
|
4
|
+
* NaCl encryption for agent messaging.
|
|
5
|
+
*/
|
|
6
|
+
import nacl from 'tweetnacl';
|
|
7
|
+
import util from 'tweetnacl-util';
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from 'fs';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { homedir } from 'os';
|
|
11
|
+
const KEYS_DIR = join(homedir(), '.myceliumail', 'keys');
|
|
12
|
+
function ensureKeysDir() {
|
|
13
|
+
if (!existsSync(KEYS_DIR)) {
|
|
14
|
+
mkdirSync(KEYS_DIR, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function generateKeyPair() {
|
|
18
|
+
return nacl.box.keyPair();
|
|
19
|
+
}
|
|
20
|
+
export function saveKeyPair(agentId, keyPair) {
|
|
21
|
+
ensureKeysDir();
|
|
22
|
+
const serialized = {
|
|
23
|
+
publicKey: util.encodeBase64(keyPair.publicKey),
|
|
24
|
+
secretKey: util.encodeBase64(keyPair.secretKey),
|
|
25
|
+
};
|
|
26
|
+
const path = join(KEYS_DIR, `${agentId}.key.json`);
|
|
27
|
+
writeFileSync(path, JSON.stringify(serialized, null, 2), { mode: 0o600 });
|
|
28
|
+
}
|
|
29
|
+
export function loadKeyPair(agentId) {
|
|
30
|
+
const path = join(KEYS_DIR, `${agentId}.key.json`);
|
|
31
|
+
if (!existsSync(path))
|
|
32
|
+
return null;
|
|
33
|
+
try {
|
|
34
|
+
const data = JSON.parse(readFileSync(path, 'utf-8'));
|
|
35
|
+
return {
|
|
36
|
+
publicKey: util.decodeBase64(data.publicKey),
|
|
37
|
+
secretKey: util.decodeBase64(data.secretKey),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function hasKeyPair(agentId) {
|
|
45
|
+
return existsSync(join(KEYS_DIR, `${agentId}.key.json`));
|
|
46
|
+
}
|
|
47
|
+
export function getPublicKeyBase64(keyPair) {
|
|
48
|
+
return util.encodeBase64(keyPair.publicKey);
|
|
49
|
+
}
|
|
50
|
+
export function encryptMessage(message, recipientPublicKey, senderKeyPair) {
|
|
51
|
+
const messageBytes = util.decodeUTF8(message);
|
|
52
|
+
const nonce = nacl.randomBytes(nacl.box.nonceLength);
|
|
53
|
+
const ciphertext = nacl.box(messageBytes, nonce, recipientPublicKey, senderKeyPair.secretKey);
|
|
54
|
+
return {
|
|
55
|
+
ciphertext: util.encodeBase64(ciphertext),
|
|
56
|
+
nonce: util.encodeBase64(nonce),
|
|
57
|
+
senderPublicKey: util.encodeBase64(senderKeyPair.publicKey),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function decryptMessage(encrypted, recipientKeyPair) {
|
|
61
|
+
try {
|
|
62
|
+
const ciphertext = util.decodeBase64(encrypted.ciphertext);
|
|
63
|
+
const nonce = util.decodeBase64(encrypted.nonce);
|
|
64
|
+
const senderPublicKey = util.decodeBase64(encrypted.senderPublicKey);
|
|
65
|
+
const decrypted = nacl.box.open(ciphertext, nonce, senderPublicKey, recipientKeyPair.secretKey);
|
|
66
|
+
if (!decrypted)
|
|
67
|
+
return null;
|
|
68
|
+
return util.encodeUTF8(decrypted);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export function loadKnownKeys() {
|
|
75
|
+
const path = join(KEYS_DIR, 'known_keys.json');
|
|
76
|
+
if (!existsSync(path))
|
|
77
|
+
return {};
|
|
78
|
+
try {
|
|
79
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return {};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function saveKnownKey(agentId, publicKeyBase64) {
|
|
86
|
+
ensureKeysDir();
|
|
87
|
+
const keys = loadKnownKeys();
|
|
88
|
+
keys[agentId] = publicKeyBase64;
|
|
89
|
+
writeFileSync(join(KEYS_DIR, 'known_keys.json'), JSON.stringify(keys, null, 2));
|
|
90
|
+
}
|
|
91
|
+
export function getKnownKey(agentId) {
|
|
92
|
+
const keys = loadKnownKeys();
|
|
93
|
+
return keys[agentId] || null;
|
|
94
|
+
}
|
|
95
|
+
export function listOwnKeys() {
|
|
96
|
+
ensureKeysDir();
|
|
97
|
+
try {
|
|
98
|
+
const files = readdirSync(KEYS_DIR);
|
|
99
|
+
return files
|
|
100
|
+
.filter(f => f.endsWith('.key.json'))
|
|
101
|
+
.map(f => f.replace('.key.json', ''));
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function decodePublicKey(base64) {
|
|
108
|
+
return util.decodeBase64(base64);
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/lib/crypto.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail MCP - Storage Module
|
|
3
|
+
*
|
|
4
|
+
* Local JSON storage with optional Supabase sync.
|
|
5
|
+
*/
|
|
6
|
+
export interface Message {
|
|
7
|
+
id: string;
|
|
8
|
+
sender: string;
|
|
9
|
+
recipient: string;
|
|
10
|
+
subject: string;
|
|
11
|
+
body: string;
|
|
12
|
+
encrypted: boolean;
|
|
13
|
+
ciphertext?: string;
|
|
14
|
+
nonce?: string;
|
|
15
|
+
senderPublicKey?: string;
|
|
16
|
+
read: boolean;
|
|
17
|
+
archived: boolean;
|
|
18
|
+
createdAt: Date;
|
|
19
|
+
}
|
|
20
|
+
export declare function sendMessage(sender: string, recipient: string, subject: string, body: string, options?: {
|
|
21
|
+
encrypted?: boolean;
|
|
22
|
+
ciphertext?: string;
|
|
23
|
+
nonce?: string;
|
|
24
|
+
senderPublicKey?: string;
|
|
25
|
+
}): Promise<Message>;
|
|
26
|
+
export declare function getInbox(agentId: string, options?: {
|
|
27
|
+
unreadOnly?: boolean;
|
|
28
|
+
limit?: number;
|
|
29
|
+
}): Promise<Message[]>;
|
|
30
|
+
export declare function getMessage(id: string): Promise<Message | null>;
|
|
31
|
+
export declare function markAsRead(id: string): Promise<boolean>;
|
|
32
|
+
export declare function archiveMessage(id: string): Promise<boolean>;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail MCP - Storage Module
|
|
3
|
+
*
|
|
4
|
+
* Local JSON storage with optional Supabase sync.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
import { homedir } from 'os';
|
|
9
|
+
import { randomUUID } from 'crypto';
|
|
10
|
+
import { getSupabaseUrl, getSupabaseKey, hasSupabase } from './config.js';
|
|
11
|
+
const DATA_DIR = join(homedir(), '.myceliumail', 'data');
|
|
12
|
+
const MESSAGES_FILE = join(DATA_DIR, 'messages.json');
|
|
13
|
+
function ensureDataDir() {
|
|
14
|
+
if (!existsSync(DATA_DIR)) {
|
|
15
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function loadLocalMessages() {
|
|
19
|
+
if (!existsSync(MESSAGES_FILE))
|
|
20
|
+
return [];
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(readFileSync(MESSAGES_FILE, 'utf-8'));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function saveLocalMessages(messages) {
|
|
29
|
+
ensureDataDir();
|
|
30
|
+
writeFileSync(MESSAGES_FILE, JSON.stringify(messages, null, 2));
|
|
31
|
+
}
|
|
32
|
+
function toMessage(stored) {
|
|
33
|
+
return { ...stored, createdAt: new Date(stored.createdAt) };
|
|
34
|
+
}
|
|
35
|
+
// Supabase helpers
|
|
36
|
+
async function supabaseRequest(path, options = {}) {
|
|
37
|
+
const url = `${getSupabaseUrl()}/rest/v1${path}`;
|
|
38
|
+
const response = await fetch(url, {
|
|
39
|
+
...options,
|
|
40
|
+
headers: {
|
|
41
|
+
'Content-Type': 'application/json',
|
|
42
|
+
'apikey': getSupabaseKey(),
|
|
43
|
+
'Authorization': `Bearer ${getSupabaseKey()}`,
|
|
44
|
+
'Prefer': options.method === 'POST' ? 'return=representation' : 'return=minimal',
|
|
45
|
+
...options.headers,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok)
|
|
49
|
+
throw new Error(await response.text());
|
|
50
|
+
if (response.status === 204)
|
|
51
|
+
return {};
|
|
52
|
+
return response.json();
|
|
53
|
+
}
|
|
54
|
+
export async function sendMessage(sender, recipient, subject, body, options) {
|
|
55
|
+
const newMessage = {
|
|
56
|
+
id: randomUUID(),
|
|
57
|
+
sender,
|
|
58
|
+
recipient,
|
|
59
|
+
subject: options?.encrypted ? '' : subject,
|
|
60
|
+
body: options?.encrypted ? '' : body,
|
|
61
|
+
encrypted: options?.encrypted || false,
|
|
62
|
+
ciphertext: options?.ciphertext,
|
|
63
|
+
nonce: options?.nonce,
|
|
64
|
+
senderPublicKey: options?.senderPublicKey,
|
|
65
|
+
read: false,
|
|
66
|
+
archived: false,
|
|
67
|
+
createdAt: new Date().toISOString(),
|
|
68
|
+
};
|
|
69
|
+
if (hasSupabase()) {
|
|
70
|
+
try {
|
|
71
|
+
const [result] = await supabaseRequest('/agent_messages', {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
body: JSON.stringify({
|
|
74
|
+
sender: newMessage.sender,
|
|
75
|
+
recipient: newMessage.recipient,
|
|
76
|
+
subject: newMessage.subject || null,
|
|
77
|
+
body: newMessage.body || null,
|
|
78
|
+
encrypted: newMessage.encrypted,
|
|
79
|
+
ciphertext: newMessage.ciphertext,
|
|
80
|
+
nonce: newMessage.nonce,
|
|
81
|
+
sender_public_key: newMessage.senderPublicKey,
|
|
82
|
+
}),
|
|
83
|
+
});
|
|
84
|
+
return toMessage({
|
|
85
|
+
...newMessage,
|
|
86
|
+
id: result.id
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Fall through to local
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Local storage
|
|
94
|
+
const messages = loadLocalMessages();
|
|
95
|
+
messages.push(newMessage);
|
|
96
|
+
saveLocalMessages(messages);
|
|
97
|
+
return toMessage(newMessage);
|
|
98
|
+
}
|
|
99
|
+
export async function getInbox(agentId, options) {
|
|
100
|
+
if (hasSupabase()) {
|
|
101
|
+
try {
|
|
102
|
+
let query = `/agent_messages?recipient=eq.${agentId}&archived=eq.false&order=created_at.desc`;
|
|
103
|
+
if (options?.unreadOnly)
|
|
104
|
+
query += '&read=eq.false';
|
|
105
|
+
if (options?.limit)
|
|
106
|
+
query += `&limit=${options.limit}`;
|
|
107
|
+
const results = await supabaseRequest(query);
|
|
108
|
+
return results.map(r => ({
|
|
109
|
+
id: r.id,
|
|
110
|
+
sender: r.sender,
|
|
111
|
+
recipient: r.recipient,
|
|
112
|
+
subject: r.subject || '',
|
|
113
|
+
body: r.body || '',
|
|
114
|
+
encrypted: r.encrypted,
|
|
115
|
+
ciphertext: r.ciphertext,
|
|
116
|
+
nonce: r.nonce,
|
|
117
|
+
senderPublicKey: r.sender_public_key,
|
|
118
|
+
read: r.read,
|
|
119
|
+
archived: r.archived,
|
|
120
|
+
createdAt: new Date(r.created_at),
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Fall through to local
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Local storage
|
|
128
|
+
const messages = loadLocalMessages();
|
|
129
|
+
let filtered = messages.filter(m => m.recipient === agentId && !m.archived);
|
|
130
|
+
if (options?.unreadOnly)
|
|
131
|
+
filtered = filtered.filter(m => !m.read);
|
|
132
|
+
filtered.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
133
|
+
if (options?.limit)
|
|
134
|
+
filtered = filtered.slice(0, options.limit);
|
|
135
|
+
return filtered.map(toMessage);
|
|
136
|
+
}
|
|
137
|
+
export async function getMessage(id) {
|
|
138
|
+
if (hasSupabase()) {
|
|
139
|
+
try {
|
|
140
|
+
const results = await supabaseRequest(`/agent_messages?id=eq.${id}`);
|
|
141
|
+
if (results.length > 0) {
|
|
142
|
+
const r = results[0];
|
|
143
|
+
return {
|
|
144
|
+
id: r.id,
|
|
145
|
+
sender: r.sender,
|
|
146
|
+
recipient: r.recipient,
|
|
147
|
+
subject: r.subject || '',
|
|
148
|
+
body: r.body || '',
|
|
149
|
+
encrypted: r.encrypted,
|
|
150
|
+
ciphertext: r.ciphertext,
|
|
151
|
+
nonce: r.nonce,
|
|
152
|
+
senderPublicKey: r.sender_public_key,
|
|
153
|
+
read: r.read,
|
|
154
|
+
archived: r.archived,
|
|
155
|
+
createdAt: new Date(r.created_at),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// Fall through
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const messages = loadLocalMessages();
|
|
164
|
+
const found = messages.find(m => m.id === id);
|
|
165
|
+
return found ? toMessage(found) : null;
|
|
166
|
+
}
|
|
167
|
+
export async function markAsRead(id) {
|
|
168
|
+
if (hasSupabase()) {
|
|
169
|
+
try {
|
|
170
|
+
await supabaseRequest(`/agent_messages?id=eq.${id}`, {
|
|
171
|
+
method: 'PATCH',
|
|
172
|
+
body: JSON.stringify({ read: true }),
|
|
173
|
+
});
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// Fall through
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const messages = loadLocalMessages();
|
|
181
|
+
const idx = messages.findIndex(m => m.id === id);
|
|
182
|
+
if (idx === -1)
|
|
183
|
+
return false;
|
|
184
|
+
messages[idx].read = true;
|
|
185
|
+
saveLocalMessages(messages);
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
export async function archiveMessage(id) {
|
|
189
|
+
if (hasSupabase()) {
|
|
190
|
+
try {
|
|
191
|
+
await supabaseRequest(`/agent_messages?id=eq.${id}`, {
|
|
192
|
+
method: 'PATCH',
|
|
193
|
+
body: JSON.stringify({ archived: true }),
|
|
194
|
+
});
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
// Fall through
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const messages = loadLocalMessages();
|
|
202
|
+
const idx = messages.findIndex(m => m.id === id);
|
|
203
|
+
if (idx === -1)
|
|
204
|
+
return false;
|
|
205
|
+
messages[idx].archived = true;
|
|
206
|
+
saveLocalMessages(messages);
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/lib/storage.ts"],"names":[],"mappings":"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"}
|