agent-mailbox-cli 0.1.0 → 0.1.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/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 String(crypto.randomInt(100000, 999999));
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;AA2B1C,wBAAsB,UAAU,CAAC,OAAO,EAAE,eAAe,iBAkJxD"}
@@ -0,0 +1,102 @@
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
+ await sendMagicLinkEmail(email, token);
11
+ return { emailSent: true };
12
+ }
13
+ export async function authRoutes(fastify) {
14
+ // Signup
15
+ fastify.post('/v1/auth/signup', async (request, reply) => {
16
+ const { email } = request.body || {};
17
+ if (!email || !email.includes('@')) {
18
+ return reply.code(400).send({ error: 'Valid email is required' });
19
+ }
20
+ const normalized = email.toLowerCase().trim();
21
+ // Check if already exists
22
+ const existing = await pool.query('SELECT id FROM admin_users WHERE email = $1', [normalized]);
23
+ if (existing.rows.length > 0) {
24
+ return reply
25
+ .code(409)
26
+ .send({ error: 'Account already exists. Use: agentmailbox login' });
27
+ }
28
+ const result = await pool.query('INSERT INTO admin_users (email) VALUES ($1) RETURNING id', [normalized]);
29
+ await sendMagicLink(result.rows[0].id, normalized);
30
+ return reply.code(201).send({
31
+ message: 'Check your email for a 6-digit verification code.',
32
+ });
33
+ });
34
+ // Login
35
+ fastify.post('/v1/auth/login', async (request, reply) => {
36
+ const { email } = request.body || {};
37
+ if (!email || !email.includes('@')) {
38
+ return reply.code(400).send({ error: 'Valid email is required' });
39
+ }
40
+ const normalized = email.toLowerCase().trim();
41
+ const result = await pool.query('SELECT id FROM admin_users WHERE email = $1', [normalized]);
42
+ if (result.rows.length === 0) {
43
+ return reply
44
+ .code(404)
45
+ .send({ error: 'No account with this email. Run: agentmailbox signup' });
46
+ }
47
+ await sendMagicLink(result.rows[0].id, normalized);
48
+ return {
49
+ message: 'Check your email for a 6-digit verification code.',
50
+ };
51
+ });
52
+ // Verify magic link token
53
+ fastify.post('/v1/auth/verify', async (request, reply) => {
54
+ const { token } = request.body || {};
55
+ if (!token) {
56
+ return reply.code(400).send({ error: 'Token is required' });
57
+ }
58
+ const hash = hashToken(token);
59
+ // Atomic: mark used only if valid and unused
60
+ const result = await pool.query(`UPDATE magic_link_tokens
61
+ SET used_at = NOW()
62
+ WHERE token_hash = $1 AND used_at IS NULL AND expires_at > NOW()
63
+ RETURNING admin_user_id`, [hash]);
64
+ if (result.rows.length === 0) {
65
+ return reply
66
+ .code(401)
67
+ .send({ error: 'Invalid or expired code' });
68
+ }
69
+ const adminUserId = result.rows[0].admin_user_id;
70
+ // Create session
71
+ const sessionToken = generateSessionToken();
72
+ const sessionHash = hashToken(sessionToken);
73
+ const expiresAt = new Date(Date.now() + config.auth.sessionTtlDays * 24 * 60 * 60 * 1000);
74
+ await pool.query(`INSERT INTO admin_sessions (admin_user_id, token_hash, expires_at) VALUES ($1, $2, $3)`, [adminUserId, sessionHash, expiresAt]);
75
+ const user = await pool.query('SELECT email FROM admin_users WHERE id = $1', [adminUserId]);
76
+ return {
77
+ session_token: sessionToken,
78
+ admin: { id: adminUserId, email: user.rows[0].email },
79
+ expires_at: expiresAt,
80
+ };
81
+ });
82
+ // Logout
83
+ fastify.post('/v1/auth/logout', async (request, reply) => {
84
+ const header = request.headers['authorization'];
85
+ if (!header) {
86
+ return reply.code(401).send({ error: 'Missing session token' });
87
+ }
88
+ const token = typeof header === 'string' ? header.replace(/^Bearer\s+/i, '') : '';
89
+ if (!token) {
90
+ return reply.code(401).send({ error: 'Invalid session token' });
91
+ }
92
+ const hash = hashToken(token);
93
+ await pool.query('DELETE FROM admin_sessions WHERE token_hash = $1', [hash]);
94
+ return { message: 'Logged out' };
95
+ });
96
+ // Who am I
97
+ fastify.get('/v1/auth/me', { onRequest: authenticateAdmin }, async (request) => {
98
+ const admin = request.admin;
99
+ return { admin };
100
+ });
101
+ }
102
+ //# 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"}