mails 0.2.0 → 1.0.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/dist/cli.js ADDED
@@ -0,0 +1,668 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+
4
+ // src/core/config.ts
5
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
6
+ import { homedir } from "os";
7
+ import { join } from "path";
8
+ var CONFIG_DIR = join(homedir(), ".mails");
9
+ var CONFIG_FILE = join(CONFIG_DIR, "config.json");
10
+ var DEFAULT_CONFIG = {
11
+ mode: "hosted",
12
+ domain: "mails.dev",
13
+ mailbox: "",
14
+ send_provider: "resend",
15
+ storage_provider: "sqlite"
16
+ };
17
+ function ensureDir() {
18
+ mkdirSync(CONFIG_DIR, { recursive: true });
19
+ }
20
+ function loadConfig() {
21
+ ensureDir();
22
+ if (!existsSync(CONFIG_FILE)) {
23
+ return { ...DEFAULT_CONFIG };
24
+ }
25
+ const raw = readFileSync(CONFIG_FILE, "utf-8");
26
+ return { ...DEFAULT_CONFIG, ...JSON.parse(raw) };
27
+ }
28
+ function saveConfig(config) {
29
+ ensureDir();
30
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + `
31
+ `);
32
+ }
33
+ function getConfigValue(key) {
34
+ const config = { ...loadConfig() };
35
+ return config[key];
36
+ }
37
+ function setConfigValue(key, value) {
38
+ const config = { ...loadConfig() };
39
+ config[key] = value;
40
+ saveConfig(config);
41
+ }
42
+
43
+ // src/providers/send/resend.ts
44
+ function createResendProvider(apiKey) {
45
+ return {
46
+ name: "resend",
47
+ async send(options) {
48
+ const body = {
49
+ from: options.from,
50
+ to: options.to,
51
+ subject: options.subject
52
+ };
53
+ if (options.text)
54
+ body.text = options.text;
55
+ if (options.html)
56
+ body.html = options.html;
57
+ if (options.replyTo)
58
+ body.reply_to = options.replyTo;
59
+ const res = await fetch("https://api.resend.com/emails", {
60
+ method: "POST",
61
+ headers: {
62
+ Authorization: `Bearer ${apiKey}`,
63
+ "Content-Type": "application/json"
64
+ },
65
+ body: JSON.stringify(body)
66
+ });
67
+ if (!res.ok) {
68
+ const err = await res.json();
69
+ throw new Error(`Resend error: ${err.message}`);
70
+ }
71
+ const data = await res.json();
72
+ return { id: data.id, provider: "resend" };
73
+ }
74
+ };
75
+ }
76
+
77
+ // src/core/send.ts
78
+ function resolveProvider() {
79
+ const config = loadConfig();
80
+ switch (config.send_provider) {
81
+ case "resend": {
82
+ if (!config.resend_api_key) {
83
+ throw new Error("resend_api_key not configured. Run: mails config set resend_api_key <key>");
84
+ }
85
+ return createResendProvider(config.resend_api_key);
86
+ }
87
+ default:
88
+ throw new Error(`Unknown send provider: ${config.send_provider}`);
89
+ }
90
+ }
91
+ async function send(options) {
92
+ const config = loadConfig();
93
+ const provider = resolveProvider();
94
+ const from = options.from ?? config.default_from;
95
+ if (!from) {
96
+ throw new Error('No "from" address. Set default_from or pass --from');
97
+ }
98
+ const to = Array.isArray(options.to) ? options.to : [options.to];
99
+ if (!options.text && !options.html) {
100
+ throw new Error("Either text or html body is required");
101
+ }
102
+ return provider.send({
103
+ from,
104
+ to,
105
+ subject: options.subject,
106
+ text: options.text,
107
+ html: options.html,
108
+ replyTo: options.replyTo
109
+ });
110
+ }
111
+
112
+ // src/cli/commands/send.ts
113
+ function parseArgs(args) {
114
+ const result = {};
115
+ for (let i = 0;i < args.length; i++) {
116
+ const arg = args[i];
117
+ if (arg.startsWith("--")) {
118
+ const key = arg.slice(2);
119
+ const value = args[i + 1];
120
+ if (value && !value.startsWith("--")) {
121
+ result[key] = value;
122
+ i++;
123
+ }
124
+ }
125
+ }
126
+ return result;
127
+ }
128
+ async function sendCommand(args) {
129
+ const opts = parseArgs(args);
130
+ if (!opts["to"]) {
131
+ console.error("Usage: mails send --to <email> --subject <subject> --body <text> [--html <html>] [--from <from>] [--reply-to <email>]");
132
+ process.exit(1);
133
+ }
134
+ if (!opts["subject"]) {
135
+ console.error("Missing --subject");
136
+ process.exit(1);
137
+ }
138
+ if (!opts["body"] && !opts["html"]) {
139
+ console.error("Missing --body or --html");
140
+ process.exit(1);
141
+ }
142
+ const result = await send({
143
+ from: opts["from"],
144
+ to: opts["to"],
145
+ subject: opts["subject"],
146
+ text: opts["body"],
147
+ html: opts["html"],
148
+ replyTo: opts["reply-to"]
149
+ });
150
+ console.log(`Sent via ${result.provider} (id: ${result.id})`);
151
+ }
152
+
153
+ // src/providers/storage/sqlite.ts
154
+ import { Database } from "bun:sqlite";
155
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
156
+ import { homedir as homedir2 } from "os";
157
+ import { join as join2 } from "path";
158
+ var SCHEMA = `
159
+ CREATE TABLE IF NOT EXISTS emails (
160
+ id TEXT PRIMARY KEY,
161
+ mailbox TEXT NOT NULL,
162
+ from_address TEXT NOT NULL,
163
+ from_name TEXT DEFAULT '',
164
+ to_address TEXT NOT NULL,
165
+ subject TEXT DEFAULT '',
166
+ body_text TEXT DEFAULT '',
167
+ body_html TEXT DEFAULT '',
168
+ code TEXT,
169
+ headers TEXT DEFAULT '{}',
170
+ metadata TEXT DEFAULT '{}',
171
+ direction TEXT NOT NULL CHECK (direction IN ('inbound', 'outbound')),
172
+ status TEXT DEFAULT 'received' CHECK (status IN ('received', 'sent', 'failed', 'queued')),
173
+ received_at TEXT NOT NULL,
174
+ created_at TEXT NOT NULL
175
+ );
176
+ CREATE INDEX IF NOT EXISTS idx_emails_mailbox ON emails(mailbox, received_at DESC);
177
+ CREATE INDEX IF NOT EXISTS idx_emails_code ON emails(mailbox) WHERE code IS NOT NULL;
178
+ `;
179
+ function createSqliteProvider(dbPath) {
180
+ const dir = join2(homedir2(), ".mails");
181
+ if (!existsSync2(dir))
182
+ mkdirSync2(dir, { recursive: true });
183
+ const path = dbPath ?? join2(dir, "mails.db");
184
+ let db;
185
+ return {
186
+ name: "sqlite",
187
+ async init() {
188
+ db = new Database(path);
189
+ db.exec("PRAGMA journal_mode=WAL;");
190
+ db.exec(SCHEMA);
191
+ },
192
+ async saveEmail(email) {
193
+ db.prepare(`
194
+ INSERT OR REPLACE INTO emails (id, mailbox, from_address, from_name, to_address, subject, body_text, body_html, code, headers, metadata, direction, status, received_at, created_at)
195
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
196
+ `).run(email.id, email.mailbox, email.from_address, email.from_name, email.to_address, email.subject, email.body_text, email.body_html, email.code, JSON.stringify(email.headers), JSON.stringify(email.metadata), email.direction, email.status, email.received_at, email.created_at);
197
+ },
198
+ async getEmails(mailbox, options) {
199
+ const limit = options?.limit ?? 20;
200
+ const offset = options?.offset ?? 0;
201
+ let query = "SELECT * FROM emails WHERE mailbox = ?";
202
+ const params = [mailbox];
203
+ if (options?.direction) {
204
+ query += " AND direction = ?";
205
+ params.push(options.direction);
206
+ }
207
+ query += " ORDER BY received_at DESC LIMIT ? OFFSET ?";
208
+ params.push(limit, offset);
209
+ const rows = db.prepare(query).all(...params);
210
+ return rows.map(rowToEmail);
211
+ },
212
+ async getEmail(id) {
213
+ const row = db.prepare("SELECT * FROM emails WHERE id = ?").get(id);
214
+ return row ? rowToEmail(row) : null;
215
+ },
216
+ async getCode(mailbox, options) {
217
+ const timeout = (options?.timeout ?? 30) * 1000;
218
+ const since = options?.since;
219
+ const deadline = Date.now() + timeout;
220
+ while (Date.now() < deadline) {
221
+ let query = "SELECT code, from_address, subject FROM emails WHERE mailbox = ? AND code IS NOT NULL";
222
+ const params = [mailbox];
223
+ if (since) {
224
+ query += " AND received_at > ?";
225
+ params.push(since);
226
+ }
227
+ query += " ORDER BY received_at DESC LIMIT 1";
228
+ const row = db.prepare(query).get(...params);
229
+ if (row) {
230
+ return { code: row.code, from: row.from_address, subject: row.subject };
231
+ }
232
+ await new Promise((r) => setTimeout(r, 1000));
233
+ }
234
+ return null;
235
+ }
236
+ };
237
+ }
238
+ function rowToEmail(row) {
239
+ return {
240
+ id: row.id,
241
+ mailbox: row.mailbox,
242
+ from_address: row.from_address,
243
+ from_name: row.from_name ?? "",
244
+ to_address: row.to_address,
245
+ subject: row.subject ?? "",
246
+ body_text: row.body_text ?? "",
247
+ body_html: row.body_html ?? "",
248
+ code: row.code ?? null,
249
+ headers: safeJsonParse(row.headers, {}),
250
+ metadata: safeJsonParse(row.metadata, {}),
251
+ direction: row.direction,
252
+ status: row.status,
253
+ received_at: row.received_at,
254
+ created_at: row.created_at
255
+ };
256
+ }
257
+ function safeJsonParse(str, fallback) {
258
+ if (!str)
259
+ return fallback;
260
+ try {
261
+ return JSON.parse(str);
262
+ } catch {
263
+ return fallback;
264
+ }
265
+ }
266
+
267
+ // src/providers/storage/db9.ts
268
+ var SCHEMA2 = `
269
+ CREATE TABLE IF NOT EXISTS emails (
270
+ id TEXT PRIMARY KEY,
271
+ mailbox TEXT NOT NULL,
272
+ from_address TEXT NOT NULL,
273
+ from_name TEXT DEFAULT '',
274
+ to_address TEXT NOT NULL,
275
+ subject TEXT DEFAULT '',
276
+ body_text TEXT DEFAULT '',
277
+ body_html TEXT DEFAULT '',
278
+ code TEXT,
279
+ headers JSONB DEFAULT '{}',
280
+ metadata JSONB DEFAULT '{}',
281
+ direction TEXT NOT NULL CHECK (direction IN ('inbound', 'outbound')),
282
+ status TEXT DEFAULT 'received' CHECK (status IN ('received', 'sent', 'failed', 'queued')),
283
+ received_at TIMESTAMPTZ NOT NULL DEFAULT now(),
284
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
285
+ );
286
+ CREATE INDEX IF NOT EXISTS idx_emails_mailbox ON emails(mailbox, received_at DESC);
287
+ CREATE INDEX IF NOT EXISTS idx_emails_code ON emails(mailbox) WHERE code IS NOT NULL;
288
+ `;
289
+ function createDb9Provider(token, databaseId) {
290
+ const baseUrl = "https://api.db9.ai";
291
+ async function sql(query) {
292
+ const res = await fetch(`${baseUrl}/customer/databases/${databaseId}/sql`, {
293
+ method: "POST",
294
+ headers: {
295
+ Authorization: `Bearer ${token}`,
296
+ "Content-Type": "application/json"
297
+ },
298
+ body: JSON.stringify({ query })
299
+ });
300
+ if (!res.ok) {
301
+ const text = await res.text();
302
+ throw new Error(`db9 error (${res.status}): ${text}`);
303
+ }
304
+ return await res.json();
305
+ }
306
+ function rowsToEmails(result) {
307
+ return result.rows.map((row) => {
308
+ const obj = {};
309
+ result.columns.forEach((col, i) => {
310
+ obj[col] = row[i];
311
+ });
312
+ return {
313
+ id: obj.id,
314
+ mailbox: obj.mailbox,
315
+ from_address: obj.from_address,
316
+ from_name: obj.from_name ?? "",
317
+ to_address: obj.to_address,
318
+ subject: obj.subject ?? "",
319
+ body_text: obj.body_text ?? "",
320
+ body_html: obj.body_html ?? "",
321
+ code: obj.code ?? null,
322
+ headers: typeof obj.headers === "string" ? JSON.parse(obj.headers) : obj.headers ?? {},
323
+ metadata: typeof obj.metadata === "string" ? JSON.parse(obj.metadata) : obj.metadata ?? {},
324
+ direction: obj.direction,
325
+ status: obj.status,
326
+ received_at: obj.received_at,
327
+ created_at: obj.created_at
328
+ };
329
+ });
330
+ }
331
+ return {
332
+ name: "db9",
333
+ async init() {
334
+ await sql(SCHEMA2);
335
+ },
336
+ async saveEmail(email) {
337
+ const esc = (s) => s.replace(/'/g, "''");
338
+ await sql(`
339
+ INSERT INTO emails (id, mailbox, from_address, from_name, to_address, subject, body_text, body_html, code, headers, metadata, direction, status, received_at, created_at)
340
+ VALUES (
341
+ '${esc(email.id)}', '${esc(email.mailbox)}', '${esc(email.from_address)}', '${esc(email.from_name)}',
342
+ '${esc(email.to_address)}', '${esc(email.subject)}', '${esc(email.body_text)}', '${esc(email.body_html)}',
343
+ ${email.code ? `'${esc(email.code)}'` : "NULL"},
344
+ '${esc(JSON.stringify(email.headers))}'::jsonb,
345
+ '${esc(JSON.stringify(email.metadata))}'::jsonb,
346
+ '${esc(email.direction)}', '${esc(email.status)}',
347
+ '${esc(email.received_at)}', '${esc(email.created_at)}'
348
+ )
349
+ ON CONFLICT (id) DO UPDATE SET
350
+ status = EXCLUDED.status,
351
+ metadata = EXCLUDED.metadata
352
+ `);
353
+ },
354
+ async getEmails(mailbox, options) {
355
+ const limit = options?.limit ?? 20;
356
+ const offset = options?.offset ?? 0;
357
+ const esc = (s) => s.replace(/'/g, "''");
358
+ let query = `SELECT * FROM emails WHERE mailbox = '${esc(mailbox)}'`;
359
+ if (options?.direction) {
360
+ query += ` AND direction = '${esc(options.direction)}'`;
361
+ }
362
+ query += ` ORDER BY received_at DESC LIMIT ${limit} OFFSET ${offset}`;
363
+ const result = await sql(query);
364
+ return rowsToEmails(result);
365
+ },
366
+ async getEmail(id) {
367
+ const esc = (s) => s.replace(/'/g, "''");
368
+ const result = await sql(`SELECT * FROM emails WHERE id = '${esc(id)}' LIMIT 1`);
369
+ const emails = rowsToEmails(result);
370
+ return emails[0] ?? null;
371
+ },
372
+ async getCode(mailbox, options) {
373
+ const timeout = (options?.timeout ?? 30) * 1000;
374
+ const since = options?.since;
375
+ const esc = (s) => s.replace(/'/g, "''");
376
+ const deadline = Date.now() + timeout;
377
+ while (Date.now() < deadline) {
378
+ let query = `SELECT code, from_address, subject FROM emails WHERE mailbox = '${esc(mailbox)}' AND code IS NOT NULL`;
379
+ if (since) {
380
+ query += ` AND received_at > '${esc(since)}'`;
381
+ }
382
+ query += " ORDER BY received_at DESC LIMIT 1";
383
+ const result = await sql(query);
384
+ if (result.row_count > 0) {
385
+ const row = result.rows[0];
386
+ const codeIdx = result.columns.indexOf("code");
387
+ const fromIdx = result.columns.indexOf("from_address");
388
+ const subIdx = result.columns.indexOf("subject");
389
+ return {
390
+ code: row[codeIdx],
391
+ from: row[fromIdx],
392
+ subject: row[subIdx]
393
+ };
394
+ }
395
+ await new Promise((r) => setTimeout(r, 2000));
396
+ }
397
+ return null;
398
+ }
399
+ };
400
+ }
401
+
402
+ // src/core/storage.ts
403
+ var _provider = null;
404
+ async function getStorage() {
405
+ if (_provider)
406
+ return _provider;
407
+ const config = loadConfig();
408
+ switch (config.storage_provider) {
409
+ case "db9": {
410
+ if (!config.db9_token) {
411
+ throw new Error("db9_token not configured. Run: mails config set db9_token <token>");
412
+ }
413
+ if (!config.db9_database_id) {
414
+ throw new Error("db9_database_id not configured. Run: mails config set db9_database_id <id>");
415
+ }
416
+ _provider = createDb9Provider(config.db9_token, config.db9_database_id);
417
+ break;
418
+ }
419
+ case "sqlite":
420
+ default: {
421
+ _provider = createSqliteProvider();
422
+ break;
423
+ }
424
+ }
425
+ await _provider.init();
426
+ return _provider;
427
+ }
428
+
429
+ // src/core/receive.ts
430
+ async function getInbox(mailbox, options) {
431
+ const storage = await getStorage();
432
+ return storage.getEmails(mailbox, options);
433
+ }
434
+ async function getEmail(id) {
435
+ const storage = await getStorage();
436
+ return storage.getEmail(id);
437
+ }
438
+ async function waitForCode(mailbox, options) {
439
+ const storage = await getStorage();
440
+ return storage.getCode(mailbox, options);
441
+ }
442
+
443
+ // src/cli/commands/inbox.ts
444
+ function parseArgs2(args) {
445
+ const result = {};
446
+ for (let i = 0;i < args.length; i++) {
447
+ const arg = args[i];
448
+ if (arg.startsWith("--")) {
449
+ const key = arg.slice(2);
450
+ const value = args[i + 1];
451
+ if (value && !value.startsWith("--")) {
452
+ result[key] = value;
453
+ i++;
454
+ }
455
+ } else if (!result._positional) {
456
+ result._positional = arg;
457
+ }
458
+ }
459
+ return result;
460
+ }
461
+ async function inboxCommand(args) {
462
+ const opts = parseArgs2(args);
463
+ if (opts._positional) {
464
+ const email = await getEmail(opts._positional);
465
+ if (!email) {
466
+ console.error(`Email not found: ${opts._positional}`);
467
+ process.exit(1);
468
+ }
469
+ console.log(`From: ${email.from_name ? `${email.from_name} <${email.from_address}>` : email.from_address}`);
470
+ console.log(`To: ${email.to_address}`);
471
+ console.log(`Subject: ${email.subject}`);
472
+ console.log(`Date: ${email.received_at}`);
473
+ if (email.code)
474
+ console.log(`Code: ${email.code}`);
475
+ console.log(`Status: ${email.status}`);
476
+ console.log("---");
477
+ console.log(email.body_text || "(no text body)");
478
+ return;
479
+ }
480
+ const config = loadConfig();
481
+ const mailbox = opts.mailbox ?? config.mailbox;
482
+ if (!mailbox) {
483
+ console.error("No mailbox specified. Use --mailbox <address> or set: mails config set mailbox <address>");
484
+ process.exit(1);
485
+ }
486
+ const limit = opts.limit ? parseInt(opts.limit) : 20;
487
+ const emails = await getInbox(mailbox, { limit });
488
+ if (emails.length === 0) {
489
+ console.log("No emails found.");
490
+ return;
491
+ }
492
+ for (const email of emails) {
493
+ const code = email.code ? ` [${email.code}]` : "";
494
+ const from = email.from_name || email.from_address;
495
+ console.log(`${email.id.slice(0, 8)} ${email.received_at.slice(0, 16)} ${from.padEnd(24).slice(0, 24)} ${email.subject.slice(0, 40)}${code}`);
496
+ }
497
+ }
498
+
499
+ // src/cli/commands/code.ts
500
+ function parseArgs3(args) {
501
+ const result = {};
502
+ for (let i = 0;i < args.length; i++) {
503
+ const arg = args[i];
504
+ if (arg.startsWith("--")) {
505
+ const key = arg.slice(2);
506
+ const value = args[i + 1];
507
+ if (value && !value.startsWith("--")) {
508
+ result[key] = value;
509
+ i++;
510
+ }
511
+ }
512
+ }
513
+ return result;
514
+ }
515
+ async function codeCommand(args) {
516
+ const opts = parseArgs3(args);
517
+ const config = loadConfig();
518
+ const mailbox = opts.to ?? config.mailbox;
519
+ if (!mailbox) {
520
+ console.error("No mailbox specified. Use --to <address> or set: mails config set mailbox <address>");
521
+ process.exit(1);
522
+ }
523
+ const timeout = opts.timeout ? parseInt(opts.timeout) : 30;
524
+ const since = opts.since ?? new Date().toISOString();
525
+ console.error(`Waiting for verification code to ${mailbox} (timeout: ${timeout}s)...`);
526
+ const result = await waitForCode(mailbox, { timeout, since });
527
+ if (result) {
528
+ console.log(result.code);
529
+ console.error(`From: ${result.from}`);
530
+ console.error(`Subject: ${result.subject}`);
531
+ } else {
532
+ console.error("No code received within timeout.");
533
+ process.exit(1);
534
+ }
535
+ }
536
+
537
+ // src/cli/commands/config.ts
538
+ async function configCommand(args) {
539
+ const subcommand = args[0];
540
+ switch (subcommand) {
541
+ case "set": {
542
+ const key = args[1];
543
+ const value = args[2];
544
+ if (!key || !value) {
545
+ console.error("Usage: mails config set <key> <value>");
546
+ process.exit(1);
547
+ }
548
+ setConfigValue(key, value);
549
+ console.log(`Set ${key} = ${value}`);
550
+ break;
551
+ }
552
+ case "get": {
553
+ const key = args[1];
554
+ if (!key) {
555
+ console.error("Usage: mails config get <key>");
556
+ process.exit(1);
557
+ }
558
+ const value = getConfigValue(key);
559
+ if (value !== undefined) {
560
+ console.log(value);
561
+ } else {
562
+ console.error(`Key "${key}" not set`);
563
+ process.exit(1);
564
+ }
565
+ break;
566
+ }
567
+ case "path": {
568
+ console.log(CONFIG_FILE);
569
+ break;
570
+ }
571
+ default: {
572
+ const config = loadConfig();
573
+ console.log(JSON.stringify(config, null, 2));
574
+ break;
575
+ }
576
+ }
577
+ }
578
+
579
+ // src/cli/commands/help.ts
580
+ function helpCommand() {
581
+ console.log(`
582
+ mails - Email infrastructure for AI agents
583
+
584
+ Usage:
585
+ mails <command> [options]
586
+
587
+ Commands:
588
+ send Send an email
589
+ inbox List received emails
590
+ code Wait for a verification code
591
+ config View or modify configuration
592
+ setup Interactive setup wizard (coming soon)
593
+ help Show this help message
594
+ version Show version
595
+
596
+ Send:
597
+ mails send --to <email> --subject <subject> --body <text>
598
+ mails send --to <email> --subject <subject> --html <html>
599
+ mails send --from "Name <email>" --to <email> --subject <subject> --body <text>
600
+
601
+ Inbox:
602
+ mails inbox List recent emails
603
+ mails inbox --mailbox <address> List emails for a specific mailbox
604
+ mails inbox <id> Show email details
605
+
606
+ Code:
607
+ mails code --to <address> Wait for a verification code
608
+ mails code --to <address> --timeout 60
609
+
610
+ Config:
611
+ mails config Show current config
612
+ mails config set <key> <value> Set a config value
613
+ mails config get <key> Get a config value
614
+ mails config path Show config file path
615
+
616
+ Config keys:
617
+ mode hosted | selfhosted
618
+ domain Your email domain
619
+ mailbox Your mailbox address
620
+ send_provider resend (default)
621
+ storage_provider sqlite | db9
622
+ resend_api_key Resend API key
623
+ db9_token db9.ai token
624
+ db9_database_id db9.ai database ID
625
+ default_from Default sender address
626
+
627
+ https://mails.dev
628
+ `.trim());
629
+ }
630
+
631
+ // src/cli/index.ts
632
+ var args = process.argv.slice(2);
633
+ var command = args[0];
634
+ async function main() {
635
+ switch (command) {
636
+ case "send":
637
+ await sendCommand(args.slice(1));
638
+ break;
639
+ case "inbox":
640
+ await inboxCommand(args.slice(1));
641
+ break;
642
+ case "code":
643
+ await codeCommand(args.slice(1));
644
+ break;
645
+ case "config":
646
+ await configCommand(args.slice(1));
647
+ break;
648
+ case "help":
649
+ case "--help":
650
+ case "-h":
651
+ case undefined:
652
+ helpCommand();
653
+ break;
654
+ case "version":
655
+ case "--version":
656
+ case "-v":
657
+ console.log("mails v1.0.1");
658
+ break;
659
+ default:
660
+ console.error(`Unknown command: ${command}`);
661
+ helpCommand();
662
+ process.exit(1);
663
+ }
664
+ }
665
+ main().catch((err) => {
666
+ console.error(err.message);
667
+ process.exit(1);
668
+ });