@agentmbox/plugin-agentmbox 1.0.1 → 1.0.2
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/package.json +1 -1
- package/bun.lock +0 -659
- package/src/actions/getEmails.ts +0 -153
- package/src/actions/sendEmail.ts +0 -132
- package/src/index.ts +0 -95
- package/src/providers/emailProvider.ts +0 -82
- package/src/services/AgentMBoxOnboardingService.ts +0 -447
- package/src/services/AgentMBoxService.ts +0 -216
- package/src/types/index.ts +0 -167
- package/tsconfig.json +0 -20
|
@@ -1,447 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AgentMBox Onboarding Service
|
|
3
|
-
* Handles autonomous account creation and setup for AgentMBox
|
|
4
|
-
* The agent pays for its own subscription using its Solana wallet
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { Service, type IAgentRuntime, logger } from "@elizaos/core";
|
|
8
|
-
import {
|
|
9
|
-
type PaymentStatus,
|
|
10
|
-
type PaymentCheckResponse,
|
|
11
|
-
type ApiKeyResponse,
|
|
12
|
-
type Mailbox,
|
|
13
|
-
} from "../types";
|
|
14
|
-
|
|
15
|
-
export interface OnboardingStatus {
|
|
16
|
-
stage:
|
|
17
|
-
| "pending"
|
|
18
|
-
| "account_created"
|
|
19
|
-
| "api_key_created"
|
|
20
|
-
| "awaiting_payment"
|
|
21
|
-
| "paid"
|
|
22
|
-
| "mailbox_created"
|
|
23
|
-
| "complete"
|
|
24
|
-
| "error";
|
|
25
|
-
paymentAddress?: string;
|
|
26
|
-
mailbox?: string;
|
|
27
|
-
error?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export class AgentMBoxOnboardingService extends Service {
|
|
31
|
-
private apiKey: string = "";
|
|
32
|
-
private mailbox: string | undefined;
|
|
33
|
-
private baseUrl: string = "https://agentmbox.com/api/v1";
|
|
34
|
-
private cfg: {
|
|
35
|
-
ownerEmail: string;
|
|
36
|
-
password: string;
|
|
37
|
-
mailboxLocalPart: string;
|
|
38
|
-
} | null = null;
|
|
39
|
-
private status: OnboardingStatus = { stage: "pending" };
|
|
40
|
-
|
|
41
|
-
static serviceName = "agentmbox-onboarding" as const;
|
|
42
|
-
|
|
43
|
-
constructor(runtime?: IAgentRuntime) {
|
|
44
|
-
super(runtime!);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
get serviceName(): string {
|
|
48
|
-
return AgentMBoxOnboardingService.serviceName;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
get capabilityDescription(): string {
|
|
52
|
-
return "AgentMBox autonomous onboarding - creates account, pays for subscription, sets up mailbox";
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
getApiKey(): string {
|
|
56
|
-
return this.apiKey;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
getMailbox(): string | undefined {
|
|
60
|
-
return this.mailbox;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
private generatePassword(length: number = 32): string {
|
|
64
|
-
const chars =
|
|
65
|
-
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*";
|
|
66
|
-
let password = "";
|
|
67
|
-
const array = new Uint8Array(length);
|
|
68
|
-
crypto.getRandomValues(array);
|
|
69
|
-
for (let i = 0; i < length; i++) {
|
|
70
|
-
password += chars[array[i] % chars.length];
|
|
71
|
-
}
|
|
72
|
-
return password;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
private async getAgentWallet(): Promise<{
|
|
76
|
-
publicKey: string;
|
|
77
|
-
privateKey: Uint8Array;
|
|
78
|
-
} | null> {
|
|
79
|
-
if (!this.runtime) return null;
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
const privateKeyBase58 = String(
|
|
83
|
-
this.runtime.getSetting("SOLANA_PRIVATE_KEY") || "",
|
|
84
|
-
);
|
|
85
|
-
if (privateKeyBase58) {
|
|
86
|
-
const { default: bs58 } = await import("bs58");
|
|
87
|
-
const { Keypair } = await import("@solana/web3.js");
|
|
88
|
-
const privateKey = bs58.decode(privateKeyBase58);
|
|
89
|
-
const keypair = Keypair.fromSecretKey(privateKey);
|
|
90
|
-
return {
|
|
91
|
-
publicKey: keypair.publicKey.toBase58(),
|
|
92
|
-
privateKey,
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const walletService = await this.runtime.getService("wallet");
|
|
97
|
-
if (walletService) {
|
|
98
|
-
const keypair = await (walletService as any).getKeypair?.();
|
|
99
|
-
if (keypair) {
|
|
100
|
-
return {
|
|
101
|
-
publicKey: keypair.publicKey.toBase58(),
|
|
102
|
-
privateKey: keypair.secretKey,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
} catch (error) {
|
|
107
|
-
logger.warn("Could not get agent wallet");
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
private async request<T>(
|
|
114
|
-
endpoint: string,
|
|
115
|
-
options: RequestInit = {},
|
|
116
|
-
): Promise<T> {
|
|
117
|
-
const url = `${this.baseUrl}${endpoint}`;
|
|
118
|
-
const headers: Record<string, string> = {
|
|
119
|
-
"Content-Type": "application/json",
|
|
120
|
-
...(options.headers as Record<string, string>),
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const response = await fetch(url, { ...options, headers });
|
|
124
|
-
const data = await response.json();
|
|
125
|
-
|
|
126
|
-
if (!response.ok) {
|
|
127
|
-
const error = (data as { error?: string }).error || `${response.status}`;
|
|
128
|
-
throw new Error(error);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return data as T;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private async authenticatedRequest<T>(
|
|
135
|
-
endpoint: string,
|
|
136
|
-
options: RequestInit = {},
|
|
137
|
-
): Promise<T> {
|
|
138
|
-
if (!this.apiKey) {
|
|
139
|
-
throw new Error("API key not set");
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const url = `${this.baseUrl}${endpoint}`;
|
|
143
|
-
const headers: Record<string, string> = {
|
|
144
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
145
|
-
"Content-Type": "application/json",
|
|
146
|
-
...(options.headers as Record<string, string>),
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const response = await fetch(url, { ...options, headers });
|
|
150
|
-
const data = await response.json();
|
|
151
|
-
|
|
152
|
-
if (!response.ok) {
|
|
153
|
-
const error = (data as { error?: string }).error || `${response.status}`;
|
|
154
|
-
throw new Error(error);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return data as T;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
async startOnboarding(runtime: IAgentRuntime): Promise<OnboardingStatus> {
|
|
161
|
-
this.runtime = runtime;
|
|
162
|
-
|
|
163
|
-
const existingApiKey = String(
|
|
164
|
-
runtime.getSetting("AGENTMBOX_API_KEY") || "",
|
|
165
|
-
);
|
|
166
|
-
if (existingApiKey && existingApiKey.startsWith("ai_")) {
|
|
167
|
-
this.apiKey = existingApiKey;
|
|
168
|
-
return await this.checkExistingSetup();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const agentName =
|
|
172
|
-
runtime.character?.name?.toLowerCase().replace(/\s+/g, "-") || "agent";
|
|
173
|
-
const mailboxSetting = String(
|
|
174
|
-
runtime.getSetting("AGENTMBOX_MAILBOX") || "",
|
|
175
|
-
);
|
|
176
|
-
this.cfg = {
|
|
177
|
-
ownerEmail:
|
|
178
|
-
String(runtime.getSetting("AGENTMBOX_OWNER_EMAIL")) ||
|
|
179
|
-
`agent-${agentName}@owner.local`,
|
|
180
|
-
password: this.generatePassword(32),
|
|
181
|
-
mailboxLocalPart: mailboxSetting
|
|
182
|
-
? mailboxSetting.split("@")[0]
|
|
183
|
-
: agentName,
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
// Step 1: Create account
|
|
188
|
-
await this.createAccount();
|
|
189
|
-
this.status = { stage: "account_created" };
|
|
190
|
-
logger.info("AgentMBox account created");
|
|
191
|
-
|
|
192
|
-
// Step 2: Create API key
|
|
193
|
-
const apiKeyResponse = await this.createApiKey(agentName);
|
|
194
|
-
this.apiKey = apiKeyResponse.key;
|
|
195
|
-
this.status = { stage: "api_key_created" };
|
|
196
|
-
logger.info("AgentMBox API key created");
|
|
197
|
-
|
|
198
|
-
// Step 3: Get payment address
|
|
199
|
-
const payment = await this.getPaymentStatus();
|
|
200
|
-
this.status = {
|
|
201
|
-
stage: "awaiting_payment",
|
|
202
|
-
paymentAddress: payment.solanaAddress,
|
|
203
|
-
};
|
|
204
|
-
logger.info("Payment address: " + payment.solanaAddress);
|
|
205
|
-
|
|
206
|
-
// Step 4: Pay for subscription
|
|
207
|
-
await this.payForSubscription(payment.solanaAddress, runtime);
|
|
208
|
-
this.status = { stage: "paid" };
|
|
209
|
-
logger.info("Payment completed");
|
|
210
|
-
|
|
211
|
-
// Step 5: Create mailbox
|
|
212
|
-
const mailbox = await this.createMailbox(this.cfg!.mailboxLocalPart);
|
|
213
|
-
this.mailbox = mailbox.address;
|
|
214
|
-
this.status = {
|
|
215
|
-
stage: "complete",
|
|
216
|
-
mailbox: mailbox.address,
|
|
217
|
-
};
|
|
218
|
-
logger.info("Mailbox created: " + mailbox.address);
|
|
219
|
-
|
|
220
|
-
return this.status;
|
|
221
|
-
} catch (error) {
|
|
222
|
-
const errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
223
|
-
logger.error("AgentMBox onboarding failed: " + errorMsg);
|
|
224
|
-
this.status = { stage: "error", error: errorMsg };
|
|
225
|
-
throw error;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
private async checkExistingSetup(): Promise<OnboardingStatus> {
|
|
230
|
-
try {
|
|
231
|
-
const payment = await this.getPaymentStatus();
|
|
232
|
-
|
|
233
|
-
if (payment.paid) {
|
|
234
|
-
const mailbox = await this.getOrCreateMailbox();
|
|
235
|
-
this.status = mailbox
|
|
236
|
-
? { stage: "complete", mailbox: mailbox.address }
|
|
237
|
-
: { stage: "paid" };
|
|
238
|
-
} else {
|
|
239
|
-
const wallet = await this.getAgentWallet();
|
|
240
|
-
if (wallet && this.runtime) {
|
|
241
|
-
await this.payForSubscription(payment.solanaAddress, this.runtime);
|
|
242
|
-
this.status = { stage: "paid" };
|
|
243
|
-
const mailbox = await this.getOrCreateMailbox();
|
|
244
|
-
if (mailbox) {
|
|
245
|
-
this.status = { stage: "complete", mailbox: mailbox.address };
|
|
246
|
-
}
|
|
247
|
-
} else {
|
|
248
|
-
this.status = {
|
|
249
|
-
stage: "awaiting_payment",
|
|
250
|
-
paymentAddress: payment.solanaAddress,
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
} catch (error) {
|
|
255
|
-
logger.warn("Could not check existing setup");
|
|
256
|
-
this.status = { stage: "pending" };
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return this.status;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
private async payForSubscription(
|
|
263
|
-
paymentAddress: string,
|
|
264
|
-
runtime: IAgentRuntime,
|
|
265
|
-
): Promise<void> {
|
|
266
|
-
const wallet = await this.getAgentWallet();
|
|
267
|
-
|
|
268
|
-
if (!wallet) {
|
|
269
|
-
logger.warn("No agent wallet found, waiting for manual payment");
|
|
270
|
-
await this.waitForPayment();
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
logger.info("Using agent wallet to pay for subscription");
|
|
275
|
-
|
|
276
|
-
try {
|
|
277
|
-
const { Connection, Keypair } = await import("@solana/web3.js");
|
|
278
|
-
const { transfer, getOrCreateAssociatedTokenAccount } =
|
|
279
|
-
await import("@solana/spl-token");
|
|
280
|
-
|
|
281
|
-
const connection = new Connection("https://api.mainnet-beta.solana.com");
|
|
282
|
-
const signer = Keypair.fromSecretKey(wallet.privateKey);
|
|
283
|
-
|
|
284
|
-
const usdcMintStr = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGZwyTDt1v";
|
|
285
|
-
const { PublicKey } = await import("@solana/web3.js");
|
|
286
|
-
const usdcMint = new PublicKey(usdcMintStr);
|
|
287
|
-
const toPublicKey = new PublicKey(paymentAddress);
|
|
288
|
-
|
|
289
|
-
const fromTokenAccount = await getOrCreateAssociatedTokenAccount(
|
|
290
|
-
connection,
|
|
291
|
-
signer,
|
|
292
|
-
usdcMint,
|
|
293
|
-
signer.publicKey,
|
|
294
|
-
);
|
|
295
|
-
|
|
296
|
-
const toTokenAccount = await getOrCreateAssociatedTokenAccount(
|
|
297
|
-
connection,
|
|
298
|
-
signer,
|
|
299
|
-
usdcMint,
|
|
300
|
-
toPublicKey,
|
|
301
|
-
);
|
|
302
|
-
|
|
303
|
-
const amount = 5_000_000;
|
|
304
|
-
|
|
305
|
-
await transfer(
|
|
306
|
-
connection,
|
|
307
|
-
signer,
|
|
308
|
-
fromTokenAccount.address,
|
|
309
|
-
toTokenAccount.address,
|
|
310
|
-
signer.publicKey,
|
|
311
|
-
amount,
|
|
312
|
-
);
|
|
313
|
-
|
|
314
|
-
logger.info("USDC transfer complete");
|
|
315
|
-
await this.waitForPayment();
|
|
316
|
-
} catch (error) {
|
|
317
|
-
logger.error("Failed to transfer USDC, waiting for manual payment");
|
|
318
|
-
await this.waitForPayment();
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
async stop(): Promise<void> {
|
|
323
|
-
logger.info("AgentMBox onboarding service stopped");
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
private async createAccount(): Promise<void> {
|
|
327
|
-
if (!this.cfg) throw new Error("Config not set");
|
|
328
|
-
|
|
329
|
-
const response = await this.request<{ id: string }>("/auth/signup", {
|
|
330
|
-
method: "POST",
|
|
331
|
-
body: JSON.stringify({
|
|
332
|
-
email: this.cfg.ownerEmail,
|
|
333
|
-
password: this.cfg.password,
|
|
334
|
-
}),
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
logger.info("Account created: " + response.id);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
private async createApiKey(name: string): Promise<ApiKeyResponse> {
|
|
341
|
-
const response = await this.request<ApiKeyResponse>("/keys", {
|
|
342
|
-
method: "POST",
|
|
343
|
-
body: JSON.stringify({ name }),
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
logger.info("API key created: " + response.key.substring(0, 12) + "...");
|
|
347
|
-
return response;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
private async getPaymentStatus(): Promise<PaymentStatus> {
|
|
351
|
-
return this.authenticatedRequest<PaymentStatus>("/payment");
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
private async waitForPayment(
|
|
355
|
-
maxAttempts: number = 60,
|
|
356
|
-
intervalMs: number = 5000,
|
|
357
|
-
): Promise<PaymentCheckResponse> {
|
|
358
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
359
|
-
try {
|
|
360
|
-
const result = await this.authenticatedRequest<PaymentCheckResponse>(
|
|
361
|
-
"/payment/check",
|
|
362
|
-
{
|
|
363
|
-
method: "POST",
|
|
364
|
-
},
|
|
365
|
-
);
|
|
366
|
-
|
|
367
|
-
if (result.paid) {
|
|
368
|
-
return result;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
logger.info(
|
|
372
|
-
"Waiting for payment... (" + attempt + "/" + maxAttempts + ")",
|
|
373
|
-
);
|
|
374
|
-
} catch (e) {
|
|
375
|
-
logger.warn(
|
|
376
|
-
"Payment check failed: " +
|
|
377
|
-
(e instanceof Error ? e.message : "unknown"),
|
|
378
|
-
);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
if (attempt < maxAttempts) {
|
|
382
|
-
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
throw new Error("Payment not received after " + maxAttempts + " attempts");
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
private async createMailbox(localPart: string): Promise<Mailbox> {
|
|
390
|
-
const response = await this.authenticatedRequest<{ mailbox: Mailbox }>(
|
|
391
|
-
"/mailboxes",
|
|
392
|
-
{
|
|
393
|
-
method: "POST",
|
|
394
|
-
body: JSON.stringify({
|
|
395
|
-
localPart,
|
|
396
|
-
displayName: this.cfg?.mailboxLocalPart || "Agent Mailbox",
|
|
397
|
-
}),
|
|
398
|
-
},
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
return response.mailbox;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
async getOrCreateMailbox(): Promise<Mailbox | null> {
|
|
405
|
-
try {
|
|
406
|
-
const response = await this.authenticatedRequest<{
|
|
407
|
-
mailboxes: Mailbox[];
|
|
408
|
-
}>("/mailboxes");
|
|
409
|
-
|
|
410
|
-
if (response.mailboxes.length > 0) {
|
|
411
|
-
return response.mailboxes[0];
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
if (this.cfg?.mailboxLocalPart) {
|
|
415
|
-
return await this.createMailbox(this.cfg.mailboxLocalPart);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
return null;
|
|
419
|
-
} catch (error) {
|
|
420
|
-
logger.error("Failed to get/create mailbox");
|
|
421
|
-
return null;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
getStatus(): OnboardingStatus {
|
|
426
|
-
return this.status;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
async getPaymentAddress(): Promise<string | null> {
|
|
430
|
-
if (this.status.paymentAddress) {
|
|
431
|
-
return this.status.paymentAddress;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
try {
|
|
435
|
-
const payment = await this.getPaymentStatus();
|
|
436
|
-
return payment.solanaAddress;
|
|
437
|
-
} catch {
|
|
438
|
-
return null;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
isOnboardingComplete(): boolean {
|
|
443
|
-
return this.status.stage === "complete";
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
export default AgentMBoxOnboardingService;
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { Service, type IAgentRuntime, logger } from "@elizaos/core";
|
|
2
|
-
import {
|
|
3
|
-
type AgentMBoxConfig,
|
|
4
|
-
type EmailListResponse,
|
|
5
|
-
type EmailDetailResponse,
|
|
6
|
-
type SendEmailRequest,
|
|
7
|
-
type SendEmailResponse,
|
|
8
|
-
type MailboxListResponse,
|
|
9
|
-
type CreateMailboxRequest,
|
|
10
|
-
type CreateMailboxResponse,
|
|
11
|
-
type PaymentStatus,
|
|
12
|
-
type PaymentCheckResponse,
|
|
13
|
-
type DomainListResponse,
|
|
14
|
-
type DomainResponse,
|
|
15
|
-
type DomainVerifyResponse,
|
|
16
|
-
type ApiKeyResponse,
|
|
17
|
-
isAgentMBoxError,
|
|
18
|
-
} from "../types";
|
|
19
|
-
|
|
20
|
-
export class AgentMBoxService extends Service {
|
|
21
|
-
private apiKey: string = "";
|
|
22
|
-
private mailbox: string | undefined;
|
|
23
|
-
private baseUrl: string = "https://agentmbox.com/api/v1";
|
|
24
|
-
|
|
25
|
-
static serviceName = "agentmbox" as const;
|
|
26
|
-
|
|
27
|
-
constructor(runtime?: IAgentRuntime) {
|
|
28
|
-
super(runtime!);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
get serviceName(): string {
|
|
32
|
-
return AgentMBoxService.serviceName;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
get capabilityDescription(): string {
|
|
36
|
-
return "AgentMBox email service - allows sending and receiving emails";
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async initialize(runtime: IAgentRuntime): Promise<void> {
|
|
40
|
-
const apiKey = String(runtime.getSetting("AGENTMBOX_API_KEY") || "");
|
|
41
|
-
const mailbox = String(runtime.getSetting("AGENTMBOX_MAILBOX") || "");
|
|
42
|
-
const baseUrl = String(runtime.getSetting("AGENTMBOX_BASE_URL") || "");
|
|
43
|
-
|
|
44
|
-
// API key will be set by onboarding if not provided
|
|
45
|
-
// The service will work once onboarding completes
|
|
46
|
-
if (apiKey && !apiKey.startsWith("ai_")) {
|
|
47
|
-
logger.warn("AgentMBox API key should start with 'ai_'");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const agentName =
|
|
51
|
-
runtime.character?.name?.toLowerCase().replace(/\s+/g, "-") || "agent";
|
|
52
|
-
const defaultMailbox = mailbox || `${agentName}@agentmbox.com`;
|
|
53
|
-
|
|
54
|
-
this.apiKey = apiKey;
|
|
55
|
-
this.mailbox = defaultMailbox;
|
|
56
|
-
this.baseUrl = baseUrl || "https://agentmbox.com/api/v1";
|
|
57
|
-
this.runtime = runtime;
|
|
58
|
-
|
|
59
|
-
if (!this.apiKey.startsWith("ai_")) {
|
|
60
|
-
logger.warn("AgentMBox API key should start with 'ai_'");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
logger.info("AgentMBox service initialized for: " + this.mailbox);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async stop(): Promise<void> {
|
|
67
|
-
logger.info("AgentMBox service stopped");
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private async request<T>(
|
|
71
|
-
endpoint: string,
|
|
72
|
-
options: RequestInit = {},
|
|
73
|
-
): Promise<T> {
|
|
74
|
-
if (!this.apiKey) {
|
|
75
|
-
throw new Error(
|
|
76
|
-
"AgentMBox API key not configured. Ensure onboarding has completed or set AGENTMBOX_API_KEY.",
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const url = `${this.baseUrl}${endpoint}`;
|
|
81
|
-
const headers: Record<string, string> = {
|
|
82
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
83
|
-
"Content-Type": "application/json",
|
|
84
|
-
...(options.headers as Record<string, string>),
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const response = await fetch(url, { ...options, headers });
|
|
88
|
-
const data = await response.json();
|
|
89
|
-
|
|
90
|
-
if (!response.ok) {
|
|
91
|
-
if (isAgentMBoxError(data)) {
|
|
92
|
-
throw new Error(
|
|
93
|
-
`AgentMBox API error (${response.status}): ${data.error}`,
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
throw new Error(`AgentMBox API error: ${response.status}`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return data as T;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private getMailboxParam(): string {
|
|
103
|
-
if (!this.mailbox) {
|
|
104
|
-
throw new Error("Mailbox not configured");
|
|
105
|
-
}
|
|
106
|
-
return "?mailbox=" + encodeURIComponent(this.mailbox);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async listEmails(limit = 50, offset = 0): Promise<EmailListResponse> {
|
|
110
|
-
const mailboxParam = this.getMailboxParam();
|
|
111
|
-
return this.request<EmailListResponse>(
|
|
112
|
-
"/mail" + mailboxParam + "&limit=" + limit + "&offset=" + offset,
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async getEmail(emailId: string): Promise<EmailDetailResponse> {
|
|
117
|
-
const mailboxParam = this.getMailboxParam();
|
|
118
|
-
return this.request<EmailDetailResponse>("/mail/" + emailId + mailboxParam);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async sendEmail(request: SendEmailRequest): Promise<SendEmailResponse> {
|
|
122
|
-
const from = request.from || this.mailbox;
|
|
123
|
-
if (!from) {
|
|
124
|
-
throw new Error("Sender address not specified");
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return this.request<SendEmailResponse>("/mail/send", {
|
|
128
|
-
method: "POST",
|
|
129
|
-
body: JSON.stringify({ ...request, from }),
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
async deleteEmail(emailId: string): Promise<{ success: boolean }> {
|
|
134
|
-
const mailboxParam = this.getMailboxParam();
|
|
135
|
-
return this.request<{ success: boolean }>(
|
|
136
|
-
"/mail/" + emailId + mailboxParam,
|
|
137
|
-
{
|
|
138
|
-
method: "DELETE",
|
|
139
|
-
},
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
async listMailboxes(): Promise<MailboxListResponse> {
|
|
144
|
-
return this.request<MailboxListResponse>("/mailboxes");
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
async createMailbox(
|
|
148
|
-
request: CreateMailboxRequest,
|
|
149
|
-
): Promise<CreateMailboxResponse> {
|
|
150
|
-
return this.request<CreateMailboxResponse>("/mailboxes", {
|
|
151
|
-
method: "POST",
|
|
152
|
-
body: JSON.stringify(request),
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async deleteMailbox(mailboxId: string): Promise<{ success: boolean }> {
|
|
157
|
-
return this.request<{ success: boolean }>("/mailboxes/" + mailboxId, {
|
|
158
|
-
method: "DELETE",
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
async getPaymentStatus(): Promise<PaymentStatus> {
|
|
163
|
-
return this.request<PaymentStatus>("/payment");
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async checkPayment(): Promise<PaymentCheckResponse> {
|
|
167
|
-
return this.request<PaymentCheckResponse>("/payment/check", {
|
|
168
|
-
method: "POST",
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async listDomains(): Promise<DomainListResponse> {
|
|
173
|
-
return this.request<DomainListResponse>("/domains");
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async addDomain(domain: string): Promise<DomainResponse> {
|
|
177
|
-
return this.request<DomainResponse>("/domains", {
|
|
178
|
-
method: "POST",
|
|
179
|
-
body: JSON.stringify({ domain }),
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async verifyDomain(domainId: string): Promise<DomainVerifyResponse> {
|
|
184
|
-
return this.request<DomainVerifyResponse>(
|
|
185
|
-
"/domains/" + domainId + "/verify",
|
|
186
|
-
{
|
|
187
|
-
method: "POST",
|
|
188
|
-
},
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
async deleteDomain(domainId: string): Promise<{ success: boolean }> {
|
|
193
|
-
return this.request<{ success: boolean }>("/domains/" + domainId, {
|
|
194
|
-
method: "DELETE",
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async createApiKey(name: string): Promise<ApiKeyResponse> {
|
|
199
|
-
return this.request<ApiKeyResponse>("/keys", {
|
|
200
|
-
method: "POST",
|
|
201
|
-
body: JSON.stringify({ name }),
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async getStatus(): Promise<{ paid: boolean; paidUntil: string | null }> {
|
|
206
|
-
try {
|
|
207
|
-
const status = await this.getPaymentStatus();
|
|
208
|
-
return { paid: status.paid, paidUntil: status.paidUntil };
|
|
209
|
-
} catch (error) {
|
|
210
|
-
logger.error("Failed to get AgentMBox status");
|
|
211
|
-
return { paid: false, paidUntil: null };
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export default AgentMBoxService;
|