toledgram-bot-sdk 0.1.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/dist/bot.d.ts +66 -0
- package/dist/bot.d.ts.map +1 -0
- package/dist/bot.js +282 -0
- package/dist/bot.js.map +1 -0
- package/dist/client/convex.d.ts +35 -0
- package/dist/client/convex.d.ts.map +1 -0
- package/dist/client/convex.js +96 -0
- package/dist/client/convex.js.map +1 -0
- package/dist/client/sender.d.ts +50 -0
- package/dist/client/sender.d.ts.map +1 -0
- package/dist/client/sender.js +161 -0
- package/dist/client/sender.js.map +1 -0
- package/dist/client/sync.d.ts +31 -0
- package/dist/client/sync.d.ts.map +1 -0
- package/dist/client/sync.js +175 -0
- package/dist/client/sync.js.map +1 -0
- package/dist/crypto/aes.d.ts +27 -0
- package/dist/crypto/aes.d.ts.map +1 -0
- package/dist/crypto/aes.js +54 -0
- package/dist/crypto/aes.js.map +1 -0
- package/dist/crypto/bip39.d.ts +27 -0
- package/dist/crypto/bip39.d.ts.map +1 -0
- package/dist/crypto/bip39.js +126 -0
- package/dist/crypto/bip39.js.map +1 -0
- package/dist/crypto/ecies.d.ts +32 -0
- package/dist/crypto/ecies.d.ts.map +1 -0
- package/dist/crypto/ecies.js +100 -0
- package/dist/crypto/ecies.js.map +1 -0
- package/dist/crypto/envelope.d.ts +21 -0
- package/dist/crypto/envelope.d.ts.map +1 -0
- package/dist/crypto/envelope.js +70 -0
- package/dist/crypto/envelope.js.map +1 -0
- package/dist/crypto/p256.d.ts +32 -0
- package/dist/crypto/p256.d.ts.map +1 -0
- package/dist/crypto/p256.js +54 -0
- package/dist/crypto/p256.js.map +1 -0
- package/dist/crypto/wordlist.d.ts +3 -0
- package/dist/crypto/wordlist.d.ts.map +1 -0
- package/dist/crypto/wordlist.js +260 -0
- package/dist/crypto/wordlist.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/storage/conversations.d.ts +20 -0
- package/dist/storage/conversations.d.ts.map +1 -0
- package/dist/storage/conversations.js +31 -0
- package/dist/storage/conversations.js.map +1 -0
- package/dist/storage/database.d.ts +13 -0
- package/dist/storage/database.d.ts.map +1 -0
- package/dist/storage/database.js +85 -0
- package/dist/storage/database.js.map +1 -0
- package/dist/storage/files.d.ts +21 -0
- package/dist/storage/files.d.ts.map +1 -0
- package/dist/storage/files.js +74 -0
- package/dist/storage/files.js.map +1 -0
- package/dist/storage/messages.d.ts +39 -0
- package/dist/storage/messages.d.ts.map +1 -0
- package/dist/storage/messages.js +71 -0
- package/dist/storage/messages.js.map +1 -0
- package/dist/types.d.ts +104 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/examples/ai-bot.ts +78 -0
- package/examples/echo-bot.ts +39 -0
- package/examples/image-bot.ts +76 -0
- package/package.json +54 -0
package/dist/bot.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToledgramBot — main entry point for bot developers
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* const bot = new ToledgramBot({ mnemonic, backendUrl, dataDir })
|
|
6
|
+
* bot.on('message', async (msg) => { await msg.reply('Hello!') })
|
|
7
|
+
* await bot.start()
|
|
8
|
+
*/
|
|
9
|
+
import { type LocalMessage } from "./storage/messages.js";
|
|
10
|
+
import type { BotConfig, MessageHandler, FileHandler, ErrorHandler, ContentType, Conversation } from "./types.js";
|
|
11
|
+
export declare class ToledgramBot {
|
|
12
|
+
private config;
|
|
13
|
+
private connection;
|
|
14
|
+
private db;
|
|
15
|
+
private messageStore;
|
|
16
|
+
private conversationStore;
|
|
17
|
+
private fileStore;
|
|
18
|
+
private syncService;
|
|
19
|
+
private sender;
|
|
20
|
+
private privateKey;
|
|
21
|
+
private publicKeyBase64;
|
|
22
|
+
private messageHandler;
|
|
23
|
+
private fileHandler;
|
|
24
|
+
private errorHandler;
|
|
25
|
+
private activeConversations;
|
|
26
|
+
private conversationPollInterval;
|
|
27
|
+
private startedAt;
|
|
28
|
+
constructor(config: BotConfig);
|
|
29
|
+
/** Register an event handler */
|
|
30
|
+
on(event: "message", handler: MessageHandler): void;
|
|
31
|
+
on(event: "file", handler: FileHandler): void;
|
|
32
|
+
on(event: "error", handler: ErrorHandler): void;
|
|
33
|
+
/** Start the bot — authenticate and begin syncing */
|
|
34
|
+
start(): Promise<void>;
|
|
35
|
+
/** Stop the bot */
|
|
36
|
+
stop(): Promise<void>;
|
|
37
|
+
/** The bot's persona ID (available after start) */
|
|
38
|
+
get personaId(): string;
|
|
39
|
+
/** The bot's username (available after start) */
|
|
40
|
+
get username(): string;
|
|
41
|
+
/** Get messages from local DB (already decrypted) */
|
|
42
|
+
getMessages(conversationId: string, opts?: {
|
|
43
|
+
limit?: number;
|
|
44
|
+
}): LocalMessage[];
|
|
45
|
+
/** Send a text message */
|
|
46
|
+
sendText(conversationId: string, text: string): Promise<void>;
|
|
47
|
+
/** Send a file from disk */
|
|
48
|
+
sendFile(conversationId: string, filePath: string, opts?: {
|
|
49
|
+
type?: ContentType;
|
|
50
|
+
filename?: string;
|
|
51
|
+
}): Promise<void>;
|
|
52
|
+
/** Send in-memory data as a file (no disk write needed) */
|
|
53
|
+
sendBuffer(conversationId: string, data: Uint8Array, opts: {
|
|
54
|
+
type?: ContentType;
|
|
55
|
+
filename: string;
|
|
56
|
+
mimeType?: string;
|
|
57
|
+
}): Promise<void>;
|
|
58
|
+
/** Get the list of conversations */
|
|
59
|
+
getConversations(): Promise<Conversation[]>;
|
|
60
|
+
private discoverAndSync;
|
|
61
|
+
private handleNewMessage;
|
|
62
|
+
private localToMessage;
|
|
63
|
+
private downloadMessageFile;
|
|
64
|
+
private getRecipientPublicKey;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=bot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAOxE,OAAO,KAAK,EACV,SAAS,EAET,cAAc,EACd,WAAW,EACX,YAAY,EACZ,WAAW,EACX,YAAY,EAEb,MAAM,YAAY,CAAC;AAGpB,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,eAAe,CAAS;IAGhC,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,YAAY,CAA6B;IAGjD,OAAO,CAAC,mBAAmB,CAA0B;IACrD,OAAO,CAAC,wBAAwB,CACzB;IACP,OAAO,CAAC,SAAS,CAAa;gBAElB,MAAM,EAAE,SAAS;IAc7B,gCAAgC;IAChC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI;IACnD,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAC7C,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAe/C,qDAAqD;IAC/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoD5B,mBAAmB;IACb,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAa3B,mDAAmD;IACnD,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,iDAAiD;IACjD,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,qDAAqD;IACrD,WAAW,CACT,cAAc,EAAE,MAAM,EACtB,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACxB,YAAY,EAAE;IAIjB,0BAA0B;IACpB,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUnE,4BAA4B;IACtB,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,WAAW,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/C,OAAO,CAAC,IAAI,CAAC;IAShB,2DAA2D;IACrD,UAAU,CACd,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAChE,OAAO,CAAC,IAAI,CAAC;IAShB,oCAAoC;IAC9B,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YA6BnC,eAAe;IAsB7B,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,cAAc;YAkCR,mBAAmB;YAiDnB,qBAAqB;CA4BpC"}
|
package/dist/bot.js
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToledgramBot — main entry point for bot developers
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* const bot = new ToledgramBot({ mnemonic, backendUrl, dataDir })
|
|
6
|
+
* bot.on('message', async (msg) => { await msg.reply('Hello!') })
|
|
7
|
+
* await bot.start()
|
|
8
|
+
*/
|
|
9
|
+
import { ConvexConnection } from "./client/convex.js";
|
|
10
|
+
import { SyncService } from "./client/sync.js";
|
|
11
|
+
import { MessageSender } from "./client/sender.js";
|
|
12
|
+
import { LocalDatabase } from "./storage/database.js";
|
|
13
|
+
import { MessageStore } from "./storage/messages.js";
|
|
14
|
+
import { ConversationStore } from "./storage/conversations.js";
|
|
15
|
+
import { FileStore } from "./storage/files.js";
|
|
16
|
+
import { mnemonicToPrivateKey } from "./crypto/bip39.js";
|
|
17
|
+
import { derivePublicKey } from "./crypto/p256.js";
|
|
18
|
+
export class ToledgramBot {
|
|
19
|
+
config;
|
|
20
|
+
connection;
|
|
21
|
+
db;
|
|
22
|
+
messageStore;
|
|
23
|
+
conversationStore;
|
|
24
|
+
fileStore;
|
|
25
|
+
syncService = null;
|
|
26
|
+
sender = null;
|
|
27
|
+
privateKey;
|
|
28
|
+
publicKeyBase64;
|
|
29
|
+
// Event handlers
|
|
30
|
+
messageHandler = null;
|
|
31
|
+
fileHandler = null;
|
|
32
|
+
errorHandler = null;
|
|
33
|
+
// Active conversation tracking
|
|
34
|
+
activeConversations = new Set();
|
|
35
|
+
conversationPollInterval = null;
|
|
36
|
+
startedAt = 0;
|
|
37
|
+
constructor(config) {
|
|
38
|
+
this.config = config;
|
|
39
|
+
this.connection = new ConvexConnection(config.backendUrl);
|
|
40
|
+
this.db = new LocalDatabase(config.dataDir);
|
|
41
|
+
this.messageStore = new MessageStore(this.db.raw);
|
|
42
|
+
this.conversationStore = new ConversationStore(this.db.raw);
|
|
43
|
+
this.fileStore = new FileStore(this.db.raw, config.dataDir);
|
|
44
|
+
// Derive keys from mnemonic
|
|
45
|
+
this.privateKey = mnemonicToPrivateKey(config.mnemonic);
|
|
46
|
+
const publicKey = derivePublicKey(this.privateKey);
|
|
47
|
+
this.publicKeyBase64 = Buffer.from(publicKey).toString("base64");
|
|
48
|
+
}
|
|
49
|
+
on(event, handler) {
|
|
50
|
+
switch (event) {
|
|
51
|
+
case "message":
|
|
52
|
+
this.messageHandler = handler;
|
|
53
|
+
break;
|
|
54
|
+
case "file":
|
|
55
|
+
this.fileHandler = handler;
|
|
56
|
+
break;
|
|
57
|
+
case "error":
|
|
58
|
+
this.errorHandler = handler;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** Start the bot — authenticate and begin syncing */
|
|
63
|
+
async start() {
|
|
64
|
+
console.log("[Bot] Starting...");
|
|
65
|
+
this.startedAt = Date.now();
|
|
66
|
+
// 1. Authenticate
|
|
67
|
+
const auth = await this.connection.authenticate(this.config.mnemonic, this.config.username);
|
|
68
|
+
console.log(`[Bot] Authenticated as @${auth.username} (${auth.personaId})`);
|
|
69
|
+
// 2. Initialize sender
|
|
70
|
+
this.sender = new MessageSender(this.connection.httpClient, this.privateKey, auth.personaId, this.publicKeyBase64, auth.token, auth.username);
|
|
71
|
+
// 3. Initialize sync service
|
|
72
|
+
this.syncService = new SyncService(this.connection.httpClient, this.privateKey, auth.personaId, auth.token, this.messageStore, this.conversationStore);
|
|
73
|
+
// Wire up new message callback
|
|
74
|
+
this.syncService.onMessage((localMsg) => {
|
|
75
|
+
this.handleNewMessage(localMsg);
|
|
76
|
+
});
|
|
77
|
+
// 4. Discover conversations and start syncing
|
|
78
|
+
await this.discoverAndSync();
|
|
79
|
+
// 5. Poll for new conversations periodically
|
|
80
|
+
this.conversationPollInterval = setInterval(async () => {
|
|
81
|
+
try {
|
|
82
|
+
await this.discoverAndSync();
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
this.errorHandler?.(e instanceof Error ? e : new Error(String(e)));
|
|
86
|
+
}
|
|
87
|
+
}, 10000);
|
|
88
|
+
console.log("[Bot] Ready and listening for messages");
|
|
89
|
+
}
|
|
90
|
+
/** Stop the bot */
|
|
91
|
+
async stop() {
|
|
92
|
+
console.log("[Bot] Stopping...");
|
|
93
|
+
if (this.conversationPollInterval) {
|
|
94
|
+
clearInterval(this.conversationPollInterval);
|
|
95
|
+
}
|
|
96
|
+
this.syncService?.stopAll();
|
|
97
|
+
this.connection.close();
|
|
98
|
+
this.db.close();
|
|
99
|
+
console.log("[Bot] Stopped");
|
|
100
|
+
}
|
|
101
|
+
// ==================== Public API ====================
|
|
102
|
+
/** The bot's persona ID (available after start) */
|
|
103
|
+
get personaId() {
|
|
104
|
+
return this.connection.personaId;
|
|
105
|
+
}
|
|
106
|
+
/** The bot's username (available after start) */
|
|
107
|
+
get username() {
|
|
108
|
+
return this.connection.username;
|
|
109
|
+
}
|
|
110
|
+
/** Get messages from local DB (already decrypted) */
|
|
111
|
+
getMessages(conversationId, opts) {
|
|
112
|
+
return this.messageStore.list(conversationId, opts?.limit ?? 50);
|
|
113
|
+
}
|
|
114
|
+
/** Send a text message */
|
|
115
|
+
async sendText(conversationId, text) {
|
|
116
|
+
if (!this.sender)
|
|
117
|
+
throw new Error("Bot not started");
|
|
118
|
+
// Get recipient public key
|
|
119
|
+
const recipientPubKey = await this.getRecipientPublicKey(conversationId);
|
|
120
|
+
await this.sender.sendText(conversationId, text, recipientPubKey);
|
|
121
|
+
}
|
|
122
|
+
/** Send a file from disk */
|
|
123
|
+
async sendFile(conversationId, filePath, opts) {
|
|
124
|
+
if (!this.sender)
|
|
125
|
+
throw new Error("Bot not started");
|
|
126
|
+
const recipientPubKey = await this.getRecipientPublicKey(conversationId);
|
|
127
|
+
await this.sender.sendFile(conversationId, filePath, recipientPubKey, opts);
|
|
128
|
+
}
|
|
129
|
+
/** Send in-memory data as a file (no disk write needed) */
|
|
130
|
+
async sendBuffer(conversationId, data, opts) {
|
|
131
|
+
if (!this.sender)
|
|
132
|
+
throw new Error("Bot not started");
|
|
133
|
+
const recipientPubKey = await this.getRecipientPublicKey(conversationId);
|
|
134
|
+
await this.sender.sendBuffer(conversationId, data, recipientPubKey, opts);
|
|
135
|
+
}
|
|
136
|
+
/** Get the list of conversations */
|
|
137
|
+
async getConversations() {
|
|
138
|
+
const convos = (await this.connection.httpClient.query("conversations:list", {
|
|
139
|
+
token: this.connection.token,
|
|
140
|
+
personaId: this.connection.personaId,
|
|
141
|
+
}));
|
|
142
|
+
return convos.map((c) => ({
|
|
143
|
+
id: c.id,
|
|
144
|
+
type: c.type,
|
|
145
|
+
name: c.name,
|
|
146
|
+
members: (c.members ?? []).map((m) => ({
|
|
147
|
+
personaId: m.personaId,
|
|
148
|
+
username: m.username,
|
|
149
|
+
displayName: m.displayName,
|
|
150
|
+
publicKey: m.publicKey,
|
|
151
|
+
role: m.role,
|
|
152
|
+
isOnline: m.isOnline,
|
|
153
|
+
isBot: m.isBot ?? false,
|
|
154
|
+
})),
|
|
155
|
+
lastMessageAt: c.lastMessageAt,
|
|
156
|
+
reactionSalt: c.reactionSalt,
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
// ==================== Internal ====================
|
|
160
|
+
async discoverAndSync() {
|
|
161
|
+
const conversations = await this.getConversations();
|
|
162
|
+
for (const convo of conversations) {
|
|
163
|
+
// Skip saved messages conversations — bots don't need them
|
|
164
|
+
if (convo.type === "saved")
|
|
165
|
+
continue;
|
|
166
|
+
if (!this.activeConversations.has(convo.id)) {
|
|
167
|
+
this.activeConversations.add(convo.id);
|
|
168
|
+
this.conversationStore.upsert({
|
|
169
|
+
id: convo.id,
|
|
170
|
+
type: convo.type,
|
|
171
|
+
name: convo.name ?? null,
|
|
172
|
+
lastMessageAt: convo.lastMessageAt ?? null,
|
|
173
|
+
reactionSalt: convo.reactionSalt ?? null,
|
|
174
|
+
metadata: JSON.stringify({ members: convo.members }),
|
|
175
|
+
});
|
|
176
|
+
this.syncService.startSync(convo.id);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
handleNewMessage(localMsg) {
|
|
181
|
+
// Skip messages from before the bot started (avoids replaying old history)
|
|
182
|
+
if (localMsg.createdAt < this.startedAt)
|
|
183
|
+
return;
|
|
184
|
+
const msg = this.localToMessage(localMsg);
|
|
185
|
+
if (localMsg.contentType !== "text" && this.fileHandler) {
|
|
186
|
+
try {
|
|
187
|
+
this.fileHandler(msg);
|
|
188
|
+
}
|
|
189
|
+
catch (e) {
|
|
190
|
+
this.errorHandler?.(e instanceof Error ? e : new Error(String(e)));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (this.messageHandler) {
|
|
194
|
+
try {
|
|
195
|
+
this.messageHandler(msg);
|
|
196
|
+
}
|
|
197
|
+
catch (e) {
|
|
198
|
+
this.errorHandler?.(e instanceof Error ? e : new Error(String(e)));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
localToMessage(local) {
|
|
203
|
+
return {
|
|
204
|
+
id: local.id,
|
|
205
|
+
conversationId: local.conversationId,
|
|
206
|
+
senderPersonaId: local.senderPersonaId,
|
|
207
|
+
senderName: local.senderName ?? "Unknown",
|
|
208
|
+
senderDisplayName: local.senderDisplayName ?? undefined,
|
|
209
|
+
content: local.content ?? "",
|
|
210
|
+
contentType: local.contentType,
|
|
211
|
+
createdAt: local.createdAt,
|
|
212
|
+
replyToMessageId: local.replyToMessageId ?? undefined,
|
|
213
|
+
replyToPreview: local.replyToPreview ?? undefined,
|
|
214
|
+
keyMaterial: local.keyMaterial ? JSON.parse(local.keyMaterial) : undefined,
|
|
215
|
+
hasFile: !!local.encryptedFileStorageId,
|
|
216
|
+
encryptedFileStorageId: local.encryptedFileStorageId ?? undefined,
|
|
217
|
+
reply: async (text) => {
|
|
218
|
+
await this.sendText(local.conversationId, text);
|
|
219
|
+
},
|
|
220
|
+
replyWithFile: async (filePath, opts) => {
|
|
221
|
+
await this.sendFile(local.conversationId, filePath, opts);
|
|
222
|
+
},
|
|
223
|
+
replyWithBuffer: async (data, opts) => {
|
|
224
|
+
await this.sendBuffer(local.conversationId, data, opts);
|
|
225
|
+
},
|
|
226
|
+
downloadFile: async () => {
|
|
227
|
+
return this.downloadMessageFile(local);
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
async downloadMessageFile(local) {
|
|
232
|
+
// Check cache first
|
|
233
|
+
const cached = this.fileStore.getCachedPath(local.id);
|
|
234
|
+
if (cached)
|
|
235
|
+
return cached;
|
|
236
|
+
if (!local.encryptedFileStorageId || !local.keyMaterial) {
|
|
237
|
+
throw new Error("Message has no file attachment");
|
|
238
|
+
}
|
|
239
|
+
// Parse key material (SDK uses "fileKey", iOS uses "key")
|
|
240
|
+
const km = JSON.parse(local.keyMaterial);
|
|
241
|
+
const fileKeyBase64 = (km.fileKey ?? km.key);
|
|
242
|
+
if (!fileKeyBase64) {
|
|
243
|
+
throw new Error("No file key in key material");
|
|
244
|
+
}
|
|
245
|
+
// iOS stores keyMaterial as key(32) + nonce(12) = 44 bytes
|
|
246
|
+
// The nonce is also embedded in the encrypted file (combined format)
|
|
247
|
+
// so we only need the first 32 bytes as the AES key
|
|
248
|
+
let fileKeyBytes = new Uint8Array(Buffer.from(fileKeyBase64, "base64"));
|
|
249
|
+
if (fileKeyBytes.length === 44) {
|
|
250
|
+
fileKeyBytes = fileKeyBytes.slice(0, 32);
|
|
251
|
+
}
|
|
252
|
+
// Download encrypted file from Convex storage
|
|
253
|
+
const url = await this.connection.httpClient.mutation("storage:getFileUrl", {
|
|
254
|
+
token: this.connection.token,
|
|
255
|
+
storageId: local.encryptedFileStorageId,
|
|
256
|
+
});
|
|
257
|
+
if (!url) {
|
|
258
|
+
throw new Error("File not found in storage");
|
|
259
|
+
}
|
|
260
|
+
const response = await fetch(url);
|
|
261
|
+
const encryptedData = new Uint8Array(await response.arrayBuffer());
|
|
262
|
+
return this.fileStore.saveDecryptedFile(local.id, encryptedData, fileKeyBytes, km.filename, km.mimeType);
|
|
263
|
+
}
|
|
264
|
+
async getRecipientPublicKey(conversationId) {
|
|
265
|
+
// Get conversation details with member public keys
|
|
266
|
+
const convo = (await this.connection.httpClient.query("conversations:get", {
|
|
267
|
+
token: this.connection.token,
|
|
268
|
+
personaId: this.connection.personaId,
|
|
269
|
+
conversationId,
|
|
270
|
+
}));
|
|
271
|
+
if (!convo) {
|
|
272
|
+
throw new Error("Conversation not found");
|
|
273
|
+
}
|
|
274
|
+
// Find the other member's public key (for direct messages)
|
|
275
|
+
const otherMember = convo.members.find((m) => m.personaId !== this.connection.personaId);
|
|
276
|
+
if (!otherMember?.publicKey) {
|
|
277
|
+
throw new Error("Recipient public key not found");
|
|
278
|
+
}
|
|
279
|
+
return otherMember.publicKey;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=bot.js.map
|
package/dist/bot.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot.js","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convex client connection and authentication
|
|
3
|
+
* Handles login with mnemonic-derived public key
|
|
4
|
+
*/
|
|
5
|
+
import { ConvexHttpClient } from "convex/browser";
|
|
6
|
+
export interface AuthResult {
|
|
7
|
+
token: string;
|
|
8
|
+
personaId: string;
|
|
9
|
+
userId: string;
|
|
10
|
+
username: string;
|
|
11
|
+
displayName?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class ConvexConnection {
|
|
14
|
+
readonly httpClient: ConvexHttpClient;
|
|
15
|
+
private _token;
|
|
16
|
+
private _personaId;
|
|
17
|
+
private _userId;
|
|
18
|
+
private _username;
|
|
19
|
+
private _publicKeyBase64;
|
|
20
|
+
constructor(backendUrl: string);
|
|
21
|
+
get token(): string;
|
|
22
|
+
get personaId(): string;
|
|
23
|
+
get userId(): string;
|
|
24
|
+
get username(): string;
|
|
25
|
+
get publicKeyBase64(): string;
|
|
26
|
+
get isAuthenticated(): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Authenticate with the backend using a mnemonic
|
|
29
|
+
* Derives public key from mnemonic, then logs in
|
|
30
|
+
*/
|
|
31
|
+
authenticate(mnemonic: string, preferredUsername?: string): Promise<AuthResult>;
|
|
32
|
+
/** Close the connection */
|
|
33
|
+
close(): void;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=convex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convex.d.ts","sourceRoot":"","sources":["../../src/client/convex.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIlD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,gBAAgB,CAAuB;gBAEnC,UAAU,EAAE,MAAM;IAI9B,IAAI,KAAK,IAAI,MAAM,CAGlB;IAED,IAAI,SAAS,IAAI,MAAM,CAGtB;IAED,IAAI,MAAM,IAAI,MAAM,CAGnB;IAED,IAAI,QAAQ,IAAI,MAAM,CAGrB;IAED,IAAI,eAAe,IAAI,MAAM,CAG5B;IAED,IAAI,eAAe,IAAI,OAAO,CAE7B;IAED;;;OAGG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,UAAU,CAAC;IA4DtB,2BAA2B;IAC3B,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convex client connection and authentication
|
|
3
|
+
* Handles login with mnemonic-derived public key
|
|
4
|
+
*/
|
|
5
|
+
import { ConvexHttpClient } from "convex/browser";
|
|
6
|
+
import { mnemonicToPrivateKey } from "../crypto/bip39.js";
|
|
7
|
+
import { derivePublicKey } from "../crypto/p256.js";
|
|
8
|
+
export class ConvexConnection {
|
|
9
|
+
httpClient;
|
|
10
|
+
_token = null;
|
|
11
|
+
_personaId = null;
|
|
12
|
+
_userId = null;
|
|
13
|
+
_username = null;
|
|
14
|
+
_publicKeyBase64 = null;
|
|
15
|
+
constructor(backendUrl) {
|
|
16
|
+
this.httpClient = new ConvexHttpClient(backendUrl);
|
|
17
|
+
}
|
|
18
|
+
get token() {
|
|
19
|
+
if (!this._token)
|
|
20
|
+
throw new Error("Not authenticated");
|
|
21
|
+
return this._token;
|
|
22
|
+
}
|
|
23
|
+
get personaId() {
|
|
24
|
+
if (!this._personaId)
|
|
25
|
+
throw new Error("Not authenticated");
|
|
26
|
+
return this._personaId;
|
|
27
|
+
}
|
|
28
|
+
get userId() {
|
|
29
|
+
if (!this._userId)
|
|
30
|
+
throw new Error("Not authenticated");
|
|
31
|
+
return this._userId;
|
|
32
|
+
}
|
|
33
|
+
get username() {
|
|
34
|
+
if (!this._username)
|
|
35
|
+
throw new Error("Not authenticated");
|
|
36
|
+
return this._username;
|
|
37
|
+
}
|
|
38
|
+
get publicKeyBase64() {
|
|
39
|
+
if (!this._publicKeyBase64)
|
|
40
|
+
throw new Error("Not authenticated");
|
|
41
|
+
return this._publicKeyBase64;
|
|
42
|
+
}
|
|
43
|
+
get isAuthenticated() {
|
|
44
|
+
return this._token !== null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Authenticate with the backend using a mnemonic
|
|
48
|
+
* Derives public key from mnemonic, then logs in
|
|
49
|
+
*/
|
|
50
|
+
async authenticate(mnemonic, preferredUsername) {
|
|
51
|
+
// Derive keys from mnemonic
|
|
52
|
+
const privateKey = mnemonicToPrivateKey(mnemonic);
|
|
53
|
+
const publicKey = derivePublicKey(privateKey);
|
|
54
|
+
const publicKeyBase64 = Buffer.from(publicKey).toString("base64");
|
|
55
|
+
this._publicKeyBase64 = publicKeyBase64;
|
|
56
|
+
// Try login first
|
|
57
|
+
const loginResult = await this.httpClient.mutation("auth:loginWithPublicKey", {
|
|
58
|
+
publicKey: publicKeyBase64,
|
|
59
|
+
deviceId: `bot-${Date.now()}`,
|
|
60
|
+
});
|
|
61
|
+
if (loginResult) {
|
|
62
|
+
const result = loginResult;
|
|
63
|
+
this._token = result.token;
|
|
64
|
+
this._userId = result.userId;
|
|
65
|
+
// Find matching persona
|
|
66
|
+
const personas = result.personas;
|
|
67
|
+
let persona = preferredUsername
|
|
68
|
+
? personas.find((p) => p.username === preferredUsername.toLowerCase())
|
|
69
|
+
: personas[0];
|
|
70
|
+
if (!persona) {
|
|
71
|
+
persona = personas[0];
|
|
72
|
+
}
|
|
73
|
+
this._personaId = persona._id;
|
|
74
|
+
this._username = persona.username;
|
|
75
|
+
// Always switch to ensure session has correct active persona
|
|
76
|
+
await this.httpClient.mutation("auth:switchPersona", {
|
|
77
|
+
token: this._token,
|
|
78
|
+
personaId: persona._id,
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
token: this._token,
|
|
82
|
+
personaId: this._personaId,
|
|
83
|
+
userId: this._userId,
|
|
84
|
+
username: this._username,
|
|
85
|
+
displayName: persona.displayName,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
throw new Error("Login failed — no account found for this mnemonic. " +
|
|
89
|
+
"Create the bot persona in the iOS app first, then use the same mnemonic here.");
|
|
90
|
+
}
|
|
91
|
+
/** Close the connection */
|
|
92
|
+
close() {
|
|
93
|
+
// ConvexHttpClient doesn't need explicit cleanup
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=convex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convex.js","sourceRoot":"","sources":["../../src/client/convex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message sender — encrypt and send to Convex
|
|
3
|
+
* Port of iOS MessageService.swift send flow
|
|
4
|
+
*/
|
|
5
|
+
import type { ConvexHttpClient } from "convex/browser";
|
|
6
|
+
import type { ContentType } from "../types.js";
|
|
7
|
+
export declare class MessageSender {
|
|
8
|
+
private httpClient;
|
|
9
|
+
private privateKey;
|
|
10
|
+
private myPersonaId;
|
|
11
|
+
private myPublicKeyBase64;
|
|
12
|
+
private token;
|
|
13
|
+
private username;
|
|
14
|
+
constructor(httpClient: ConvexHttpClient, privateKey: Uint8Array, myPersonaId: string, myPublicKeyBase64: string, token: string, username: string);
|
|
15
|
+
/**
|
|
16
|
+
* Send a text message to a direct conversation
|
|
17
|
+
*/
|
|
18
|
+
sendText(conversationId: string, text: string, recipientPublicKeyBase64: string, opts?: {
|
|
19
|
+
replyToMessageId?: string;
|
|
20
|
+
}): Promise<{
|
|
21
|
+
messageId: string;
|
|
22
|
+
createdAt: number;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Send a file/media message to a direct conversation
|
|
26
|
+
*/
|
|
27
|
+
sendFile(conversationId: string, filePath: string, recipientPublicKeyBase64: string, opts?: {
|
|
28
|
+
type?: ContentType;
|
|
29
|
+
filename?: string;
|
|
30
|
+
replyToMessageId?: string;
|
|
31
|
+
}): Promise<{
|
|
32
|
+
messageId: string;
|
|
33
|
+
createdAt: number;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Send in-memory data as a file (no disk I/O needed)
|
|
37
|
+
*/
|
|
38
|
+
sendBuffer(conversationId: string, data: Uint8Array, recipientPublicKeyBase64: string, opts: {
|
|
39
|
+
type?: ContentType;
|
|
40
|
+
filename: string;
|
|
41
|
+
mimeType?: string;
|
|
42
|
+
replyToMessageId?: string;
|
|
43
|
+
}): Promise<{
|
|
44
|
+
messageId: string;
|
|
45
|
+
createdAt: number;
|
|
46
|
+
}>;
|
|
47
|
+
/** Upload raw bytes to Convex storage, returns storage ID */
|
|
48
|
+
private uploadToStorage;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=sender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sender.d.ts","sourceRoot":"","sources":["../../src/client/sender.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIvD,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAC;AAI7D,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAS;gBAGvB,UAAU,EAAE,gBAAgB,EAC5B,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM;IAUlB;;OAEG;IACG,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,wBAAwB,EAAE,MAAM,EAChC,IAAI,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,GACnC,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAiCpD;;OAEG;IACG,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,wBAAwB,EAAE,MAAM,EAChC,IAAI,CAAC,EAAE;QACL,IAAI,CAAC,EAAE,WAAW,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,GACA,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAuDpD;;OAEG;IACG,UAAU,CACd,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,UAAU,EAChB,wBAAwB,EAAE,MAAM,EAChC,IAAI,EAAE;QACJ,IAAI,CAAC,EAAE,WAAW,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,GACA,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAqDpD,6DAA6D;YAC/C,eAAe;CAqB9B"}
|