agent-mailbox-cli 0.1.0 → 0.1.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/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # AgentMailbox
2
+
3
+ Email addresses for AI agents. Zero cost per account.
4
+
5
+ AgentMailbox gives any AI agent its own email address at `@agentmailbox.io`. Agents can receive verification codes, order confirmations, and notifications — no Gmail or Google Workspace fees per account.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g agent-mailbox-cli
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # Set your API key
17
+ export AGENT_EMAIL_API_KEY=ae_xxxxx
18
+
19
+ # Create an email account
20
+ agentmailbox account create grocery-bot
21
+ # → grocery-bot@agentmailbox.io created
22
+
23
+ # List inbox
24
+ agentmailbox msg list grocery-bot@agentmailbox.io
25
+
26
+ # Wait for a new email (blocks until one arrives)
27
+ agentmailbox msg wait grocery-bot@agentmailbox.io --timeout 60
28
+
29
+ # Read a message
30
+ agentmailbox msg read grocery-bot@agentmailbox.io <message-id>
31
+
32
+ # Reply
33
+ agentmailbox msg reply grocery-bot@agentmailbox.io <message-id> "Got it, thanks"
34
+ ```
35
+
36
+ ## API
37
+
38
+ Base URL: `https://agent-email-api-production.up.railway.app`
39
+
40
+ Auth: `Authorization: Bearer ae_xxxxx`
41
+
42
+ ### Organizations
43
+
44
+ ```
45
+ POST /v1/orgs Create org, get API key
46
+ ```
47
+
48
+ ### Accounts
49
+
50
+ ```
51
+ POST /v1/accounts Create email account
52
+ GET /v1/accounts List accounts
53
+ DELETE /v1/accounts/:address Delete account
54
+ ```
55
+
56
+ ### Messages
57
+
58
+ ```
59
+ GET /v1/accounts/:address/messages List inbox
60
+ GET /v1/accounts/:address/messages/:id Read message
61
+ GET /v1/accounts/:address/messages/wait?timeout=30 Wait for new email
62
+ POST /v1/accounts/:address/messages/:id/reply Reply to message
63
+ POST /v1/accounts/:address/send Send new email
64
+ DELETE /v1/accounts/:address/messages/:id Delete message
65
+ ```
66
+
67
+ ## Example: Agent Signup Flow
68
+
69
+ ```javascript
70
+ const API = 'https://agent-email-api-production.up.railway.app';
71
+ const KEY = 'ae_xxxxx';
72
+
73
+ // 1. Create an email for the agent
74
+ const { account } = await fetch(`${API}/v1/accounts`, {
75
+ method: 'POST',
76
+ headers: { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json' },
77
+ body: JSON.stringify({ local_part: 'bot-123' })
78
+ }).then(r => r.json());
79
+ // → bot-123@agentmailbox.io
80
+
81
+ // 2. Sign up for a service using that email
82
+ // ... (agent signs up on grocery site with bot-123@agentmailbox.io)
83
+
84
+ // 3. Wait for verification email
85
+ const { message } = await fetch(
86
+ `${API}/v1/accounts/bot-123@agentmailbox.io/messages/wait?timeout=60`,
87
+ { headers: { 'Authorization': `Bearer ${KEY}` } }
88
+ ).then(r => r.json());
89
+
90
+ // 4. Extract verification code
91
+ const code = message.text.match(/\d{6}/)?.[0];
92
+ ```
93
+
94
+ ## Architecture
95
+
96
+ ```
97
+ Internet ──SMTP:25──▶ Fly.io (SMTP receiver) ──▶ PostgreSQL (Railway)
98
+
99
+ Agents ──HTTPS──▶ Railway (REST API) ─────────────────┘
100
+ ```
101
+
102
+ - **API**: Fastify on Railway
103
+ - **SMTP**: Node.js smtp-server on Fly.io, port 25
104
+ - **Database**: PostgreSQL on Railway
105
+ - **Domain**: agentmailbox.io (Vercel DNS, MX + SPF + DMARC configured)
106
+
107
+ ## Development
108
+
109
+ ```bash
110
+ # Start Postgres
111
+ docker compose up -d
112
+
113
+ # Init database
114
+ npm run db:init
115
+
116
+ # Run everything locally
117
+ npm run dev
118
+
119
+ # Or run API and SMTP separately
120
+ npm run dev:api
121
+ npm run dev:smtp
122
+ ```
123
+
124
+ ## Deploy
125
+
126
+ ```bash
127
+ # API → Railway
128
+ railway up -s agent-email-api
129
+
130
+ # SMTP → Fly.io
131
+ fly deploy --app agent-email-smtp
132
+ ```
@@ -1,5 +1,8 @@
1
1
  import { FastifyRequest, FastifyReply } from 'fastify';
2
- export declare function hashApiKey(key: string): string;
2
+ export declare function hashToken(key: string): string;
3
3
  export declare function generateApiKey(): string;
4
+ export declare function generateMagicToken(): string;
5
+ export declare function generateSessionToken(): string;
4
6
  export declare function authenticate(request: FastifyRequest, reply: FastifyReply): Promise<undefined>;
7
+ export declare function authenticateAdmin(request: FastifyRequest, reply: FastifyReply): Promise<undefined>;
5
8
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,sBAyBpB"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAGD,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,sBAyBpB;AAGD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,sBAiCpB"}
package/dist/api/auth.js CHANGED
@@ -1,11 +1,18 @@
1
1
  import crypto from 'crypto';
2
2
  import { pool } from '../db/index.js';
3
- export function hashApiKey(key) {
3
+ export function hashToken(key) {
4
4
  return crypto.createHash('sha256').update(key).digest('hex');
5
5
  }
6
6
  export function generateApiKey() {
7
7
  return 'ae_' + crypto.randomBytes(24).toString('hex');
8
8
  }
9
+ export function generateMagicToken() {
10
+ return 'ml_' + crypto.randomBytes(16).toString('hex');
11
+ }
12
+ export function generateSessionToken() {
13
+ return 'as_' + crypto.randomBytes(24).toString('hex');
14
+ }
15
+ // Org-level API key auth (existing)
9
16
  export async function authenticate(request, reply) {
10
17
  const header = request.headers['authorization'] || request.headers['x-api-key'];
11
18
  if (!header) {
@@ -15,11 +22,35 @@ export async function authenticate(request, reply) {
15
22
  if (!key) {
16
23
  return reply.code(401).send({ error: 'Invalid API key' });
17
24
  }
18
- const hash = hashApiKey(key);
25
+ const hash = hashToken(key);
19
26
  const result = await pool.query('SELECT id, name FROM orgs WHERE api_key_hash = $1', [hash]);
20
27
  if (result.rows.length === 0) {
21
28
  return reply.code(401).send({ error: 'Invalid API key' });
22
29
  }
23
30
  request.org = result.rows[0];
24
31
  }
32
+ // Admin session auth
33
+ export async function authenticateAdmin(request, reply) {
34
+ const header = request.headers['authorization'];
35
+ if (!header) {
36
+ return reply.code(401).send({ error: 'Missing session token. Run: agentmailbox login' });
37
+ }
38
+ const token = typeof header === 'string' ? header.replace(/^Bearer\s+/i, '') : '';
39
+ if (!token || !token.startsWith('as_')) {
40
+ return reply.code(401).send({ error: 'Invalid session token' });
41
+ }
42
+ const hash = hashToken(token);
43
+ const result = await pool.query(`SELECT s.id, s.admin_user_id, s.expires_at, u.email
44
+ FROM admin_sessions s
45
+ JOIN admin_users u ON u.id = s.admin_user_id
46
+ WHERE s.token_hash = $1`, [hash]);
47
+ if (result.rows.length === 0 ||
48
+ new Date(result.rows[0].expires_at) < new Date()) {
49
+ return reply.code(401).send({ error: 'Session expired. Run: agentmailbox login' });
50
+ }
51
+ request.admin = {
52
+ id: result.rows[0].admin_user_id,
53
+ email: result.rows[0].email,
54
+ };
55
+ }
25
56
  //# sourceMappingURL=auth.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAuB,EACvB,KAAmB;IAEnB,MAAM,MAAM,GACV,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACnE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,GAAG,GACP,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,mDAAmD,EACnD,CAAC,IAAI,CAAC,CACP,CAAC;IAEF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC5D,CAAC;IAEA,OAAe,CAAC,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACxC,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ export declare function authRoutes(fastify: FastifyInstance): Promise<void>;
3
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/api/routes/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAkC1C,wBAAsB,UAAU,CAAC,OAAO,EAAE,eAAe,iBA8JxD"}
@@ -0,0 +1,115 @@
1
+ import { pool } from '../../db/index.js';
2
+ import { hashToken, generateMagicToken, generateSessionToken, authenticateAdmin, } from '../auth.js';
3
+ import { sendMagicLinkEmail } from '../../email/send.js';
4
+ import { config } from '../../config.js';
5
+ async function sendMagicLink(adminUserId, email) {
6
+ const token = generateMagicToken();
7
+ const hash = hashToken(token);
8
+ const expiresAt = new Date(Date.now() + config.auth.magicLinkTtlMinutes * 60 * 1000);
9
+ await pool.query(`INSERT INTO magic_link_tokens (admin_user_id, token_hash, expires_at) VALUES ($1, $2, $3)`, [adminUserId, hash, expiresAt]);
10
+ try {
11
+ await sendMagicLinkEmail(email, token);
12
+ }
13
+ catch (err) {
14
+ console.error('Failed to send magic link email:', err);
15
+ // Return the token directly if email sending fails (dev mode)
16
+ return { emailSent: false, token };
17
+ }
18
+ return { emailSent: true };
19
+ }
20
+ export async function authRoutes(fastify) {
21
+ // Signup
22
+ fastify.post('/v1/auth/signup', async (request, reply) => {
23
+ const { email } = request.body || {};
24
+ if (!email || !email.includes('@')) {
25
+ return reply.code(400).send({ error: 'Valid email is required' });
26
+ }
27
+ const normalized = email.toLowerCase().trim();
28
+ // Check if already exists
29
+ const existing = await pool.query('SELECT id FROM admin_users WHERE email = $1', [normalized]);
30
+ if (existing.rows.length > 0) {
31
+ return reply
32
+ .code(409)
33
+ .send({ error: 'Account already exists. Use: agentmailbox login' });
34
+ }
35
+ const result = await pool.query('INSERT INTO admin_users (email) VALUES ($1) RETURNING id', [normalized]);
36
+ const { emailSent, token } = await sendMagicLink(result.rows[0].id, normalized);
37
+ return reply.code(201).send({
38
+ message: emailSent
39
+ ? 'Check your email for a verification code.'
40
+ : 'Email sending failed. Use this code to verify:',
41
+ ...(token ? { code: token } : {}),
42
+ });
43
+ });
44
+ // Login
45
+ fastify.post('/v1/auth/login', async (request, reply) => {
46
+ const { email } = request.body || {};
47
+ if (!email || !email.includes('@')) {
48
+ return reply.code(400).send({ error: 'Valid email is required' });
49
+ }
50
+ const normalized = email.toLowerCase().trim();
51
+ const result = await pool.query('SELECT id FROM admin_users WHERE email = $1', [normalized]);
52
+ if (result.rows.length === 0) {
53
+ return reply
54
+ .code(404)
55
+ .send({ error: 'No account with this email. Run: agentmailbox signup' });
56
+ }
57
+ const { emailSent, token } = await sendMagicLink(result.rows[0].id, normalized);
58
+ return {
59
+ message: emailSent
60
+ ? 'Check your email for a verification code.'
61
+ : 'Email sending failed. Use this code to verify:',
62
+ ...(token ? { code: token } : {}),
63
+ };
64
+ });
65
+ // Verify magic link token
66
+ fastify.post('/v1/auth/verify', async (request, reply) => {
67
+ const { token } = request.body || {};
68
+ if (!token) {
69
+ return reply.code(400).send({ error: 'Token is required' });
70
+ }
71
+ const hash = hashToken(token);
72
+ // Atomic: mark used only if valid and unused
73
+ const result = await pool.query(`UPDATE magic_link_tokens
74
+ SET used_at = NOW()
75
+ WHERE token_hash = $1 AND used_at IS NULL AND expires_at > NOW()
76
+ RETURNING admin_user_id`, [hash]);
77
+ if (result.rows.length === 0) {
78
+ return reply
79
+ .code(401)
80
+ .send({ error: 'Invalid or expired code' });
81
+ }
82
+ const adminUserId = result.rows[0].admin_user_id;
83
+ // Create session
84
+ const sessionToken = generateSessionToken();
85
+ const sessionHash = hashToken(sessionToken);
86
+ const expiresAt = new Date(Date.now() + config.auth.sessionTtlDays * 24 * 60 * 60 * 1000);
87
+ await pool.query(`INSERT INTO admin_sessions (admin_user_id, token_hash, expires_at) VALUES ($1, $2, $3)`, [adminUserId, sessionHash, expiresAt]);
88
+ const user = await pool.query('SELECT email FROM admin_users WHERE id = $1', [adminUserId]);
89
+ return {
90
+ session_token: sessionToken,
91
+ admin: { id: adminUserId, email: user.rows[0].email },
92
+ expires_at: expiresAt,
93
+ };
94
+ });
95
+ // Logout
96
+ fastify.post('/v1/auth/logout', async (request, reply) => {
97
+ const header = request.headers['authorization'];
98
+ if (!header) {
99
+ return reply.code(401).send({ error: 'Missing session token' });
100
+ }
101
+ const token = typeof header === 'string' ? header.replace(/^Bearer\s+/i, '') : '';
102
+ if (!token) {
103
+ return reply.code(401).send({ error: 'Invalid session token' });
104
+ }
105
+ const hash = hashToken(token);
106
+ await pool.query('DELETE FROM admin_sessions WHERE token_hash = $1', [hash]);
107
+ return { message: 'Logged out' };
108
+ });
109
+ // Who am I
110
+ fastify.get('/v1/auth/me', { onRequest: authenticateAdmin }, async (request) => {
111
+ const admin = request.admin;
112
+ return { admin };
113
+ });
114
+ }
115
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/api/routes/auth.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"orgs.d.ts","sourceRoot":"","sources":["../../../src/api/routes/orgs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI1C,wBAAsB,SAAS,CAAC,OAAO,EAAE,eAAe,iBAwBvD"}
1
+ {"version":3,"file":"orgs.d.ts","sourceRoot":"","sources":["../../../src/api/routes/orgs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI1C,wBAAsB,SAAS,CAAC,OAAO,EAAE,eAAe,iBAqEvD"}
@@ -1,20 +1,43 @@
1
1
  import { pool } from '../../db/index.js';
2
- import { generateApiKey, hashApiKey } from '../auth.js';
2
+ import { generateApiKey, hashToken, authenticateAdmin } from '../auth.js';
3
3
  export async function orgRoutes(fastify) {
4
- // Create org — this is the only unauthenticated endpoint
5
- fastify.post('/v1/orgs', async (request, reply) => {
4
+ // Create org — requires admin auth
5
+ fastify.post('/v1/orgs', { onRequest: authenticateAdmin }, async (request, reply) => {
6
+ const admin = request.admin;
6
7
  const { name } = request.body || {};
7
8
  if (!name) {
8
9
  return reply.code(400).send({ error: 'name is required' });
9
10
  }
10
11
  const apiKey = generateApiKey();
11
- const hash = hashApiKey(apiKey);
12
- const result = await pool.query('INSERT INTO orgs (name, api_key_hash) VALUES ($1, $2) RETURNING id, name, created_at', [name, hash]);
12
+ const hash = hashToken(apiKey);
13
+ const result = await pool.query('INSERT INTO orgs (name, api_key_hash, admin_user_id) VALUES ($1, $2, $3) RETURNING id, name, created_at', [name, hash, admin.id]);
13
14
  return reply.code(201).send({
14
15
  org: result.rows[0],
15
16
  api_key: apiKey,
16
17
  note: 'Save this API key — it cannot be retrieved again.',
17
18
  });
18
19
  });
20
+ // List orgs for admin
21
+ fastify.get('/v1/orgs', { onRequest: authenticateAdmin }, async (request) => {
22
+ const admin = request.admin;
23
+ const result = await pool.query('SELECT id, name, created_at FROM orgs WHERE admin_user_id = $1 ORDER BY created_at DESC', [admin.id]);
24
+ return { orgs: result.rows };
25
+ });
26
+ // Rotate API key
27
+ fastify.post('/v1/orgs/:orgId/rotate-key', { onRequest: authenticateAdmin }, async (request, reply) => {
28
+ const admin = request.admin;
29
+ const { orgId } = request.params;
30
+ const apiKey = generateApiKey();
31
+ const hash = hashToken(apiKey);
32
+ const result = await pool.query('UPDATE orgs SET api_key_hash = $1 WHERE id = $2 AND admin_user_id = $3 RETURNING id, name', [hash, orgId, admin.id]);
33
+ if (result.rows.length === 0) {
34
+ return reply.code(404).send({ error: 'Org not found' });
35
+ }
36
+ return {
37
+ org: result.rows[0],
38
+ api_key: apiKey,
39
+ note: 'Save this API key — it cannot be retrieved again.',
40
+ };
41
+ });
19
42
  }
20
43
  //# sourceMappingURL=orgs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"orgs.js","sourceRoot":"","sources":["../../../src/api/routes/orgs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAwB;IACtD,yDAAyD;IACzD,OAAO,CAAC,IAAI,CAET,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACtC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAEhC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,sFAAsF,EACtF,CAAC,IAAI,EAAE,IAAI,CAAC,CACb,CAAC;QAEF,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YACnB,OAAO,EAAE,MAAM;YACf,IAAI,EAAE,mDAAmD;SAC1D,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"orgs.js","sourceRoot":"","sources":["../../../src/api/routes/orgs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE1E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAwB;IACtD,mCAAmC;IACnC,OAAO,CAAC,IAAI,CAET,UAAU,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACxE,MAAM,KAAK,GAAI,OAAe,CAAC,KAAK,CAAC;QACrC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAE/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,yGAAyG,EACzG,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CACvB,CAAC;QAEF,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YACnB,OAAO,EAAE,MAAM;YACf,IAAI,EAAE,mDAAmD;SAC1D,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,sBAAsB;IACtB,OAAO,CAAC,GAAG,CACT,UAAU,EACV,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAChC,KAAK,EAAE,OAAO,EAAE,EAAE;QAChB,MAAM,KAAK,GAAI,OAAe,CAAC,KAAK,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,yFAAyF,EACzF,CAAC,KAAK,CAAC,EAAE,CAAC,CACX,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC,CACF,CAAC;IAEF,iBAAiB;IACjB,OAAO,CAAC,IAAI,CAGV,4BAA4B,EAC5B,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAChC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,MAAM,KAAK,GAAI,OAAe,CAAC,KAAK,CAAC;QACrC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QAEjC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAE/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,2FAA2F,EAC3F,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,CACxB,CAAC;QAEF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,OAAO;YACL,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YACnB,OAAO,EAAE,MAAM;YACf,IAAI,EAAE,mDAAmD;SAC1D,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAOA,wBAAsB,eAAe;;;GA2BpC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAQA,wBAAsB,eAAe;;;GA4BpC"}
@@ -4,6 +4,7 @@ import { config } from '../config.js';
4
4
  import { orgRoutes } from './routes/orgs.js';
5
5
  import { accountRoutes } from './routes/accounts.js';
6
6
  import { messageRoutes } from './routes/messages.js';
7
+ import { authRoutes } from './routes/auth.js';
7
8
  export async function createApiServer() {
8
9
  const fastify = Fastify({
9
10
  logger: true,
@@ -12,6 +13,7 @@ export async function createApiServer() {
12
13
  // Health check
13
14
  fastify.get('/health', async () => ({ status: 'ok' }));
14
15
  // Routes
16
+ await fastify.register(authRoutes);
15
17
  await fastify.register(orgRoutes);
16
18
  await fastify.register(accountRoutes);
17
19
  await fastify.register(messageRoutes);
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,IAAI,MAAM,eAAe,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,OAAO,GAAG,OAAO,CAAC;QACtB,MAAM,EAAE,IAAI;KACb,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE7B,eAAe;IACf,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEvD,SAAS;IACT,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACtC,MAAM,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IAEtC,OAAO;QACL,KAAK,CAAC,KAAK;YACT,MAAM,OAAO,CAAC,MAAM,CAAC;gBACnB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI;gBACrB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI;aACtB,CAAC,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,KAAK,CAAC,IAAI;YACR,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,IAAI,MAAM,eAAe,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,OAAO,GAAG,OAAO,CAAC;QACtB,MAAM,EAAE,IAAI;KACb,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE7B,eAAe;IACf,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEvD,SAAS;IACT,MAAM,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACnC,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACtC,MAAM,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IAEtC,OAAO;QACL,KAAK,CAAC,KAAK;YACT,MAAM,OAAO,CAAC,MAAM,CAAC;gBACnB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI;gBACrB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI;aACtB,CAAC,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,KAAK,CAAC,IAAI;YACR,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ export interface CliConfig {
2
+ api_url: string;
3
+ session_token?: string;
4
+ email?: string;
5
+ }
6
+ export declare function loadConfig(): CliConfig;
7
+ export declare function saveConfig(config: CliConfig): void;
8
+ export declare function clearSession(): void;
9
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,UAAU,IAAI,SAAS,CAWtC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAGlD;AAED,wBAAgB,YAAY,IAAI,IAAI,CAKnC"}
@@ -0,0 +1,28 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ const CONFIG_DIR = path.join(os.homedir(), '.agentmailbox');
5
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
6
+ export function loadConfig() {
7
+ try {
8
+ const raw = fs.readFileSync(CONFIG_FILE, 'utf-8');
9
+ return JSON.parse(raw);
10
+ }
11
+ catch {
12
+ return {
13
+ api_url: process.env.AGENT_EMAIL_API_URL ||
14
+ 'https://agent-email-api-production.up.railway.app',
15
+ };
16
+ }
17
+ }
18
+ export function saveConfig(config) {
19
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
20
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + '\n');
21
+ }
22
+ export function clearSession() {
23
+ const config = loadConfig();
24
+ delete config.session_token;
25
+ delete config.email;
26
+ saveConfig(config);
27
+ }
28
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AAC5D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAQzD,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,OAAO,EACL,OAAO,CAAC,GAAG,CAAC,mBAAmB;gBAC/B,mDAAmD;SACtD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAiB;IAC1C,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,aAAa,CAAC;IAC5B,OAAO,MAAM,CAAC,KAAK,CAAC;IACpB,UAAU,CAAC,MAAM,CAAC,CAAC;AACrB,CAAC"}
package/dist/cli/index.js CHANGED
@@ -1,16 +1,32 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
+ import { createInterface } from 'readline';
4
+ import { loadConfig, saveConfig, clearSession } from './config.js';
3
5
  const program = new Command();
4
- const API_URL = process.env.AGENT_EMAIL_API_URL || 'https://agent-email-api-production.up.railway.app';
5
- const API_KEY = process.env.AGENT_EMAIL_API_KEY || '';
6
- async function api(method, path, body) {
6
+ function getApiUrl() {
7
+ return (process.env.AGENT_EMAIL_API_URL ||
8
+ loadConfig().api_url ||
9
+ 'https://agent-email-api-production.up.railway.app');
10
+ }
11
+ function getAuthHeader() {
12
+ // API key takes precedence (for org-level ops like accounts/messages)
13
+ const apiKey = process.env.AGENT_EMAIL_API_KEY;
14
+ if (apiKey)
15
+ return `Bearer ${apiKey}`;
16
+ // Fall back to session token (for admin ops like org create)
17
+ const cfg = loadConfig();
18
+ if (cfg.session_token)
19
+ return `Bearer ${cfg.session_token}`;
20
+ return '';
21
+ }
22
+ async function api(method, path, body, authOverride) {
7
23
  const headers = {
8
24
  'Content-Type': 'application/json',
9
25
  };
10
- if (API_KEY) {
11
- headers['Authorization'] = `Bearer ${API_KEY}`;
12
- }
13
- const res = await fetch(`${API_URL}${path}`, {
26
+ const auth = authOverride || getAuthHeader();
27
+ if (auth)
28
+ headers['Authorization'] = auth;
29
+ const res = await fetch(`${getApiUrl()}${path}`, {
14
30
  method,
15
31
  headers,
16
32
  body: body ? JSON.stringify(body) : undefined,
@@ -24,17 +40,100 @@ async function api(method, path, body) {
24
40
  }
25
41
  return data;
26
42
  }
43
+ function prompt(question) {
44
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
45
+ return new Promise((resolve) => {
46
+ rl.question(question, (answer) => {
47
+ rl.close();
48
+ resolve(answer.trim());
49
+ });
50
+ });
51
+ }
27
52
  program
28
53
  .name('agentmailbox')
29
- .description('CLI for AgentEmail service')
30
- .version('0.1.0');
54
+ .description('Email addresses for AI agents')
55
+ .version('0.2.0');
56
+ // Auth commands
57
+ program
58
+ .command('signup')
59
+ .argument('<email>', 'Your email address')
60
+ .description('Create an admin account')
61
+ .action(async (email) => {
62
+ const data = await api('POST', '/v1/auth/signup', { email }, '');
63
+ console.log(data.message);
64
+ if (data.code) {
65
+ console.log(`Code: ${data.code}`);
66
+ }
67
+ const code = await prompt('Paste the code from your email: ');
68
+ const verify = await api('POST', '/v1/auth/verify', { token: code }, '');
69
+ const cfg = loadConfig();
70
+ cfg.session_token = verify.session_token;
71
+ cfg.email = verify.admin.email;
72
+ saveConfig(cfg);
73
+ console.log(`Logged in as ${verify.admin.email}`);
74
+ });
75
+ program
76
+ .command('login')
77
+ .argument('<email>', 'Your email address')
78
+ .description('Log in with magic link')
79
+ .action(async (email) => {
80
+ const data = await api('POST', '/v1/auth/login', { email }, '');
81
+ console.log(data.message);
82
+ if (data.code) {
83
+ console.log(`Code: ${data.code}`);
84
+ }
85
+ const code = await prompt('Paste the code from your email: ');
86
+ const verify = await api('POST', '/v1/auth/verify', { token: code }, '');
87
+ const cfg = loadConfig();
88
+ cfg.session_token = verify.session_token;
89
+ cfg.email = verify.admin.email;
90
+ saveConfig(cfg);
91
+ console.log(`Logged in as ${verify.admin.email}`);
92
+ });
93
+ program
94
+ .command('logout')
95
+ .description('Log out')
96
+ .action(async () => {
97
+ const cfg = loadConfig();
98
+ if (cfg.session_token) {
99
+ try {
100
+ await api('POST', '/v1/auth/logout', undefined, `Bearer ${cfg.session_token}`);
101
+ }
102
+ catch { }
103
+ }
104
+ clearSession();
105
+ console.log('Logged out.');
106
+ });
107
+ program
108
+ .command('whoami')
109
+ .description('Show current user')
110
+ .action(async () => {
111
+ const cfg = loadConfig();
112
+ if (!cfg.session_token) {
113
+ console.log('Not logged in. Run: agentmailbox login <email>');
114
+ return;
115
+ }
116
+ try {
117
+ const data = await api('GET', '/v1/auth/me', undefined, `Bearer ${cfg.session_token}`);
118
+ console.log(`Logged in as ${data.admin.email}`);
119
+ }
120
+ catch {
121
+ console.log('Session expired. Run: agentmailbox login <email>');
122
+ }
123
+ });
31
124
  // Org commands
32
125
  const org = program.command('org');
33
126
  org
34
127
  .command('create')
35
128
  .argument('<name>', 'Organization name')
129
+ .description('Create an org and get an API key')
36
130
  .action(async (name) => {
37
- const data = await api('POST', '/v1/orgs', { name });
131
+ const cfg = loadConfig();
132
+ if (!cfg.session_token) {
133
+ console.error('Not logged in. Run: agentmailbox login <email>');
134
+ process.exit(1);
135
+ }
136
+ const data = await api('POST', '/v1/orgs', { name }, `Bearer ${cfg.session_token}`);
38
137
  console.log('Organization created:');
39
138
  console.log(` ID: ${data.org.id}`);
40
139
  console.log(` Name: ${data.org.name}`);
@@ -43,6 +142,38 @@ org
43
142
  console.log('Save this API key — it cannot be retrieved again.');
44
143
  console.log(`Export it: export AGENT_EMAIL_API_KEY=${data.api_key}`);
45
144
  });
145
+ org
146
+ .command('list')
147
+ .description('List your orgs')
148
+ .action(async () => {
149
+ const cfg = loadConfig();
150
+ if (!cfg.session_token) {
151
+ console.error('Not logged in. Run: agentmailbox login <email>');
152
+ process.exit(1);
153
+ }
154
+ const data = await api('GET', '/v1/orgs', undefined, `Bearer ${cfg.session_token}`);
155
+ if (data.orgs.length === 0) {
156
+ console.log('No orgs. Create one: agentmailbox org create <name>');
157
+ return;
158
+ }
159
+ for (const o of data.orgs) {
160
+ console.log(` ${o.id} ${o.name} created ${o.created_at}`);
161
+ }
162
+ });
163
+ org
164
+ .command('rotate-key')
165
+ .argument('<org-id>', 'Org ID')
166
+ .description('Rotate API key for an org')
167
+ .action(async (orgId) => {
168
+ const cfg = loadConfig();
169
+ if (!cfg.session_token) {
170
+ console.error('Not logged in. Run: agentmailbox login <email>');
171
+ process.exit(1);
172
+ }
173
+ const data = await api('POST', `/v1/orgs/${orgId}/rotate-key`, undefined, `Bearer ${cfg.session_token}`);
174
+ console.log(`New API Key: ${data.api_key}`);
175
+ console.log('Save this API key — the old one is now invalid.');
176
+ });
46
177
  // Account commands
47
178
  const account = program.command('account');
48
179
  account
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -7,11 +7,23 @@ export declare const config: {
7
7
  port: number;
8
8
  host: string;
9
9
  domain: string;
10
+ relaySecret: string;
10
11
  };
11
12
  api: {
12
13
  port: number;
13
14
  host: string;
14
15
  };
16
+ auth: {
17
+ magicLinkTtlMinutes: number;
18
+ sessionTtlDays: number;
19
+ fromAddress: string;
20
+ };
21
+ outboundSmtp: {
22
+ host: string;
23
+ port: number;
24
+ user: string;
25
+ pass: string;
26
+ };
15
27
  dkim: {
16
28
  selector: string;
17
29
  privateKey: string;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAEvB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;CAiBlB,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAEvB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BlB,CAAC"}
package/dist/config.js CHANGED
@@ -7,11 +7,23 @@ export const config = {
7
7
  port: parseInt(process.env.SMTP_PORT || '2525', 10),
8
8
  host: process.env.SMTP_HOST || '0.0.0.0',
9
9
  domain: process.env.SMTP_DOMAIN || 'agentmailbox.io',
10
+ relaySecret: process.env.SMTP_RELAY_SECRET || '',
10
11
  },
11
12
  api: {
12
13
  port: parseInt(process.env.API_PORT || '3025', 10),
13
14
  host: process.env.API_HOST || '0.0.0.0',
14
15
  },
16
+ auth: {
17
+ magicLinkTtlMinutes: parseInt(process.env.AUTH_MAGIC_LINK_TTL || '15', 10),
18
+ sessionTtlDays: parseInt(process.env.AUTH_SESSION_TTL_DAYS || '30', 10),
19
+ fromAddress: process.env.AUTH_FROM_ADDRESS || 'auth@agentmailbox.io',
20
+ },
21
+ outboundSmtp: {
22
+ host: process.env.OUTBOUND_SMTP_HOST || 'mail.agentmailbox.io',
23
+ port: parseInt(process.env.OUTBOUND_SMTP_PORT || '25', 10),
24
+ user: process.env.OUTBOUND_SMTP_USER || '',
25
+ pass: process.env.OUTBOUND_SMTP_PASS || '',
26
+ },
15
27
  dkim: {
16
28
  selector: process.env.DKIM_SELECTOR || 'default',
17
29
  privateKey: process.env.DKIM_PRIVATE_KEY || '',
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAEvB,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,QAAQ,EAAE;QACR,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,sCAAsC;KACxE;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,EAAE,EAAE,CAAC;QACnD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,SAAS;QACxC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,iBAAiB;KACrD;IACD,GAAG,EAAE;QACH,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,MAAM,EAAE,EAAE,CAAC;QAClD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,SAAS;KACxC;IACD,IAAI,EAAE;QACJ,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,SAAS;QAChD,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE;KAC/C;CACF,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAEvB,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,QAAQ,EAAE;QACR,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,sCAAsC;KACxE;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,EAAE,EAAE,CAAC;QACnD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,SAAS;QACxC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,iBAAiB;QACpD,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE;KACjD;IACD,GAAG,EAAE;QACH,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,MAAM,EAAE,EAAE,CAAC;QAClD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,SAAS;KACxC;IACD,IAAI,EAAE;QACJ,mBAAmB,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,IAAI,EAAE,EAAE,CAAC;QAC1E,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,IAAI,EAAE,EAAE,CAAC;QACvE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,sBAAsB;KACrE;IACD,YAAY,EAAE;QACZ,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,sBAAsB;QAC9D,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,IAAI,EAAE,EAAE,CAAC;QAC1D,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE;QAC1C,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE;KAC3C;IACD,IAAI,EAAE;QACJ,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,SAAS;QAChD,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE;KAC/C;CACF,CAAC"}
@@ -36,3 +36,38 @@ CREATE INDEX IF NOT EXISTS idx_messages_account_received ON messages(account_id,
36
36
  CREATE INDEX IF NOT EXISTS idx_accounts_org ON accounts(org_id);
37
37
  CREATE INDEX IF NOT EXISTS idx_accounts_address ON accounts(address);
38
38
  CREATE INDEX IF NOT EXISTS idx_orgs_api_key_hash ON orgs(api_key_hash);
39
+
40
+ -- Admin auth
41
+ CREATE TABLE IF NOT EXISTS admin_users (
42
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
43
+ email TEXT NOT NULL UNIQUE,
44
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
45
+ );
46
+
47
+ CREATE TABLE IF NOT EXISTS magic_link_tokens (
48
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
49
+ admin_user_id UUID NOT NULL REFERENCES admin_users(id) ON DELETE CASCADE,
50
+ token_hash TEXT NOT NULL UNIQUE,
51
+ expires_at TIMESTAMPTZ NOT NULL,
52
+ used_at TIMESTAMPTZ,
53
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
54
+ );
55
+
56
+ CREATE TABLE IF NOT EXISTS admin_sessions (
57
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
58
+ admin_user_id UUID NOT NULL REFERENCES admin_users(id) ON DELETE CASCADE,
59
+ token_hash TEXT NOT NULL UNIQUE,
60
+ expires_at TIMESTAMPTZ NOT NULL,
61
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
62
+ );
63
+
64
+ -- Add owner to orgs (nullable for backward compat)
65
+ DO $$ BEGIN
66
+ ALTER TABLE orgs ADD COLUMN admin_user_id UUID REFERENCES admin_users(id);
67
+ EXCEPTION WHEN duplicate_column THEN NULL;
68
+ END $$;
69
+
70
+ CREATE INDEX IF NOT EXISTS idx_admin_users_email ON admin_users(email);
71
+ CREATE INDEX IF NOT EXISTS idx_magic_link_tokens_hash ON magic_link_tokens(token_hash);
72
+ CREATE INDEX IF NOT EXISTS idx_admin_sessions_hash ON admin_sessions(token_hash);
73
+ CREATE INDEX IF NOT EXISTS idx_orgs_admin ON orgs(admin_user_id);
@@ -0,0 +1,2 @@
1
+ export declare function sendMagicLinkEmail(to: string, code: string): Promise<void>;
2
+ //# sourceMappingURL=send.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/email/send.ts"],"names":[],"mappings":"AAaA,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,iBAShE"}
@@ -0,0 +1,21 @@
1
+ import nodemailer from 'nodemailer';
2
+ import { config } from '../config.js';
3
+ const transporter = nodemailer.createTransport({
4
+ host: config.outboundSmtp.host,
5
+ port: config.outboundSmtp.port,
6
+ secure: false,
7
+ ...(config.outboundSmtp.user
8
+ ? { auth: { user: config.outboundSmtp.user, pass: config.outboundSmtp.pass } }
9
+ : {}),
10
+ tls: { rejectUnauthorized: false },
11
+ });
12
+ export async function sendMagicLinkEmail(to, code) {
13
+ const text = `Your AgentMailbox verification code:\n\n${code}\n\nPaste this code in your terminal to complete login.\nThis code expires in ${config.auth.magicLinkTtlMinutes} minutes.`;
14
+ await transporter.sendMail({
15
+ from: `AgentMailbox <${config.auth.fromAddress}>`,
16
+ to,
17
+ subject: `Your login code: ${code}`,
18
+ text,
19
+ });
20
+ }
21
+ //# sourceMappingURL=send.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/email/send.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,WAAW,GAAG,UAAU,CAAC,eAAe,CAAC;IAC7C,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI;IAC9B,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI;IAC9B,MAAM,EAAE,KAAK;IACb,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI;QAC1B,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE;QAC9E,CAAC,CAAC,EAAE,CAAC;IACP,GAAG,EAAE,EAAE,kBAAkB,EAAE,KAAK,EAAE;CAC5B,CAAC,CAAC;AAEV,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EAAU,EAAE,IAAY;IAC/D,MAAM,IAAI,GAAG,2CAA2C,IAAI,iFAAiF,MAAM,CAAC,IAAI,CAAC,mBAAmB,WAAW,CAAC;IAExL,MAAM,WAAW,CAAC,QAAQ,CAAC;QACzB,IAAI,EAAE,iBAAiB,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG;QACjD,EAAE;QACF,OAAO,EAAE,oBAAoB,IAAI,EAAE;QACnC,IAAI;KACL,CAAC,CAAC;AACL,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"receiver.d.ts","sourceRoot":"","sources":["../../src/smtp/receiver.ts"],"names":[],"mappings":"AAKA,wBAAgB,kBAAkB;;;EA2GjC"}
1
+ {"version":3,"file":"receiver.d.ts","sourceRoot":"","sources":["../../src/smtp/receiver.ts"],"names":[],"mappings":"AASA,wBAAgB,kBAAkB;;;EAyFjC"}
@@ -1,18 +1,35 @@
1
1
  import { SMTPServer } from 'smtp-server';
2
2
  import { simpleParser } from 'mailparser';
3
+ import nodemailer from 'nodemailer';
3
4
  import { pool } from '../db/index.js';
4
5
  import { config } from '../config.js';
6
+ // Direct transport for relaying to external MX servers
7
+ const directTransport = nodemailer.createTransport({ direct: true });
5
8
  export function createSmtpReceiver() {
6
9
  const domain = config.smtp.domain;
10
+ const relaySecret = config.smtp.relaySecret;
7
11
  const server = new SMTPServer({
8
12
  authOptional: true,
9
- disabledCommands: ['AUTH'],
10
13
  banner: `AgentEmail SMTP`,
11
14
  size: 10 * 1024 * 1024, // 10MB max
12
- onRcptTo(address, _session, callback) {
15
+ onAuth(auth, _session, callback) {
16
+ if (relaySecret &&
17
+ auth.username === 'relay' &&
18
+ auth.password === relaySecret) {
19
+ callback(null, { user: 'relay' });
20
+ }
21
+ else {
22
+ callback(new Error('Invalid credentials'));
23
+ }
24
+ },
25
+ onRcptTo(address, session, callback) {
13
26
  const addr = address.address.toLowerCase();
27
+ const isRelay = session.user === 'relay';
14
28
  if (addr.endsWith(`@${domain}`)) {
15
- callback();
29
+ callback(); // Accept mail for our domain
30
+ }
31
+ else if (isRelay) {
32
+ callback(); // Authenticated relay to external
16
33
  }
17
34
  else {
18
35
  callback(new Error(`Not accepting mail for ${addr}`));
@@ -25,39 +42,21 @@ export function createSmtpReceiver() {
25
42
  try {
26
43
  const raw = Buffer.concat(chunks).toString('utf-8');
27
44
  const parsed = await simpleParser(raw);
45
+ const isRelay = session.user === 'relay';
28
46
  const fromAddress = session.envelope.mailFrom &&
29
47
  typeof session.envelope.mailFrom === 'object'
30
48
  ? session.envelope.mailFrom.address
31
49
  : '';
32
50
  const recipients = session.envelope.rcptTo.map((r) => r.address.toLowerCase());
33
51
  for (const toAddress of recipients) {
34
- const result = await pool.query('SELECT id FROM accounts WHERE address = $1', [toAddress]);
35
- if (result.rows.length === 0) {
36
- console.log(`No account for ${toAddress}, skipping`);
37
- continue;
52
+ if (toAddress.endsWith(`@${domain}`)) {
53
+ // Inbound: store in DB
54
+ await storeInbound(parsed, fromAddress, toAddress, raw);
55
+ }
56
+ else if (isRelay) {
57
+ // Relay: deliver to external MX
58
+ await relayOutbound(fromAddress, toAddress, raw);
38
59
  }
39
- const accountId = result.rows[0].id;
40
- await pool.query(`INSERT INTO messages
41
- (account_id, message_id, from_address, to_address, subject, text_body, html_body, raw, headers, direction)
42
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, 'inbound')`, [
43
- accountId,
44
- parsed.messageId || null,
45
- fromAddress,
46
- toAddress,
47
- parsed.subject || null,
48
- parsed.text || null,
49
- parsed.html || null,
50
- raw,
51
- JSON.stringify(parsed.headerLines?.map((h) => ({
52
- key: h.key,
53
- line: h.line,
54
- })) || []),
55
- ]);
56
- // Notify listeners waiting for new messages
57
- await pool.query(`SELECT pg_notify('new_message', $1)`, [
58
- accountId,
59
- ]);
60
- console.log(`Stored message for ${toAddress} from ${fromAddress}: ${parsed.subject}`);
61
60
  }
62
61
  callback();
63
62
  }
@@ -85,4 +84,42 @@ export function createSmtpReceiver() {
85
84
  },
86
85
  };
87
86
  }
87
+ async function storeInbound(parsed, fromAddress, toAddress, raw) {
88
+ const result = await pool.query('SELECT id FROM accounts WHERE address = $1', [toAddress]);
89
+ if (result.rows.length === 0) {
90
+ console.log(`No account for ${toAddress}, skipping`);
91
+ return;
92
+ }
93
+ const accountId = result.rows[0].id;
94
+ await pool.query(`INSERT INTO messages
95
+ (account_id, message_id, from_address, to_address, subject, text_body, html_body, raw, headers, direction)
96
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, 'inbound')`, [
97
+ accountId,
98
+ parsed.messageId || null,
99
+ fromAddress,
100
+ toAddress,
101
+ parsed.subject || null,
102
+ parsed.text || null,
103
+ parsed.html || null,
104
+ raw,
105
+ JSON.stringify(parsed.headerLines?.map((h) => ({
106
+ key: h.key,
107
+ line: h.line,
108
+ })) || []),
109
+ ]);
110
+ await pool.query(`SELECT pg_notify('new_message', $1)`, [accountId]);
111
+ console.log(`Stored message for ${toAddress} from ${fromAddress}: ${parsed.subject}`);
112
+ }
113
+ async function relayOutbound(from, to, raw) {
114
+ try {
115
+ await directTransport.sendMail({
116
+ envelope: { from, to: [to] },
117
+ raw,
118
+ });
119
+ console.log(`Relayed email from ${from} to ${to}`);
120
+ }
121
+ catch (err) {
122
+ console.error(`Failed to relay to ${to}:`, err);
123
+ }
124
+ }
88
125
  //# sourceMappingURL=receiver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"receiver.js","sourceRoot":"","sources":["../../src/smtp/receiver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,UAAU,kBAAkB;IAChC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;IAElC,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC;QAC5B,YAAY,EAAE,IAAI;QAClB,gBAAgB,EAAE,CAAC,MAAM,CAAC;QAC1B,MAAM,EAAE,iBAAiB;QACzB,IAAI,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,WAAW;QAEnC,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ;YAClC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YAC3C,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,EAAE,CAAC,EAAE,CAAC;gBAChC,QAAQ,EAAE,CAAC;YACb,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,KAAK,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;QAED,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ;YAC9B,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YACzD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;gBAC1B,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;oBACpD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;oBAEvC,MAAM,WAAW,GACf,OAAO,CAAC,QAAQ,CAAC,QAAQ;wBACzB,OAAO,OAAO,CAAC,QAAQ,CAAC,QAAQ,KAAK,QAAQ;wBAC3C,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO;wBACnC,CAAC,CAAC,EAAE,CAAC;oBACT,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACnD,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CACxB,CAAC;oBAEF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;wBACnC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,4CAA4C,EAC5C,CAAC,SAAS,CAAC,CACZ,CAAC;wBAEF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BAC7B,OAAO,CAAC,GAAG,CAAC,kBAAkB,SAAS,YAAY,CAAC,CAAC;4BACrD,SAAS;wBACX,CAAC;wBAED,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;wBAEpC,MAAM,IAAI,CAAC,KAAK,CACd;;sEAEwD,EACxD;4BACE,SAAS;4BACT,MAAM,CAAC,SAAS,IAAI,IAAI;4BACxB,WAAW;4BACX,SAAS;4BACT,MAAM,CAAC,OAAO,IAAI,IAAI;4BACtB,MAAM,CAAC,IAAI,IAAI,IAAI;4BACnB,MAAM,CAAC,IAAI,IAAI,IAAI;4BACnB,GAAG;4BACH,IAAI,CAAC,SAAS,CACZ,MAAM,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAgC,EAAE,EAAE,CAAC,CAAC;gCAC7D,GAAG,EAAE,CAAC,CAAC,GAAG;gCACV,IAAI,EAAE,CAAC,CAAC,IAAI;6BACb,CAAC,CAAC,IAAI,EAAE,CACV;yBACF,CACF,CAAC;wBAEF,4CAA4C;wBAC5C,MAAM,IAAI,CAAC,KAAK,CAAC,qCAAqC,EAAE;4BACtD,SAAS;yBACV,CAAC,CAAC;wBAEH,OAAO,CAAC,GAAG,CACT,sBAAsB,SAAS,SAAS,WAAW,KAAK,MAAM,CAAC,OAAO,EAAE,CACzE,CAAC;oBACJ,CAAC;oBAED,QAAQ,EAAE,CAAC;gBACb,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;oBAC9C,QAAQ,CAAC,GAAY,CAAC,CAAC;gBACzB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;IAEH,OAAO;QACL,KAAK;YACH,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC3C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE;oBACrD,OAAO,CAAC,GAAG,CACT,8BAA8B,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,SAAS,MAAM,EAAE,CACpF,CAAC;oBACF,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC;gBACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC7B,CAAC,CAAC,CAAC;QACL,CAAC;QACD,IAAI;YACF,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBACnC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YAChC,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"receiver.js","sourceRoot":"","sources":["../../src/smtp/receiver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,uDAAuD;AACvD,MAAM,eAAe,GAAG,UAAU,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,IAAI,EAAS,CAAC,CAAC;AAE5E,MAAM,UAAU,kBAAkB;IAChC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;IAClC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;IAE5C,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC;QAC5B,YAAY,EAAE,IAAI;QAClB,MAAM,EAAE,iBAAiB;QACzB,IAAI,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,WAAW;QAEnC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ;YAC7B,IACE,WAAW;gBACX,IAAI,CAAC,QAAQ,KAAK,OAAO;gBACzB,IAAI,CAAC,QAAQ,KAAK,WAAW,EAC7B,CAAC;gBACD,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QAED,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ;YACjC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,OAAO,GAAI,OAAe,CAAC,IAAI,KAAK,OAAO,CAAC;YAElD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,EAAE,CAAC,EAAE,CAAC;gBAChC,QAAQ,EAAE,CAAC,CAAC,6BAA6B;YAC3C,CAAC;iBAAM,IAAI,OAAO,EAAE,CAAC;gBACnB,QAAQ,EAAE,CAAC,CAAC,kCAAkC;YAChD,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,KAAK,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;QAED,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ;YAC9B,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YACzD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;gBAC1B,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;oBACpD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;oBACvC,MAAM,OAAO,GAAI,OAAe,CAAC,IAAI,KAAK,OAAO,CAAC;oBAElD,MAAM,WAAW,GACf,OAAO,CAAC,QAAQ,CAAC,QAAQ;wBACzB,OAAO,OAAO,CAAC,QAAQ,CAAC,QAAQ,KAAK,QAAQ;wBAC3C,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO;wBACnC,CAAC,CAAC,EAAE,CAAC;oBACT,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACnD,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CACxB,CAAC;oBAEF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;wBACnC,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,MAAM,EAAE,CAAC,EAAE,CAAC;4BACrC,uBAAuB;4BACvB,MAAM,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;wBAC1D,CAAC;6BAAM,IAAI,OAAO,EAAE,CAAC;4BACnB,gCAAgC;4BAChC,MAAM,aAAa,CAAC,WAAW,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;wBACnD,CAAC;oBACH,CAAC;oBAED,QAAQ,EAAE,CAAC;gBACb,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;oBAC9C,QAAQ,CAAC,GAAY,CAAC,CAAC;gBACzB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;IAEH,OAAO;QACL,KAAK;YACH,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC3C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE;oBACrD,OAAO,CAAC,GAAG,CACT,8BAA8B,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,SAAS,MAAM,EAAE,CACpF,CAAC;oBACF,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC;gBACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC7B,CAAC,CAAC,CAAC;QACL,CAAC;QACD,IAAI;YACF,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBACnC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YAChC,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,MAAW,EACX,WAAmB,EACnB,SAAiB,EACjB,GAAW;IAEX,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,4CAA4C,EAC5C,CAAC,SAAS,CAAC,CACZ,CAAC;IAEF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,kBAAkB,SAAS,YAAY,CAAC,CAAC;QACrD,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEpC,MAAM,IAAI,CAAC,KAAK,CACd;;4DAEwD,EACxD;QACE,SAAS;QACT,MAAM,CAAC,SAAS,IAAI,IAAI;QACxB,WAAW;QACX,SAAS;QACT,MAAM,CAAC,OAAO,IAAI,IAAI;QACtB,MAAM,CAAC,IAAI,IAAI,IAAI;QACnB,MAAM,CAAC,IAAI,IAAI,IAAI;QACnB,GAAG;QACH,IAAI,CAAC,SAAS,CACZ,MAAM,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAgC,EAAE,EAAE,CAAC,CAAC;YAC7D,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,IAAI,EAAE,CAAC,CAAC,IAAI;SACb,CAAC,CAAC,IAAI,EAAE,CACV;KACF,CACF,CAAC;IAEF,MAAM,IAAI,CAAC,KAAK,CAAC,qCAAqC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CACT,sBAAsB,SAAS,SAAS,WAAW,KAAK,MAAM,CAAC,OAAO,EAAE,CACzE,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,EAAU,EAAE,GAAW;IAChE,IAAI,CAAC;QACH,MAAM,eAAe,CAAC,QAAQ,CAAC;YAC7B,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE;YAC5B,GAAG;SACJ,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,OAAO,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAClD,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-mailbox-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Email addresses for AI agents. Zero cost per account.",
5
5
  "type": "module",
6
6
  "keywords": [