managarten/services/mana-mail/src/index.ts
Till JS a3de6b3d81 feat(mail): add mana-mail service and frontend module (Phase 1 MVP)
Backend: Hono/Bun service on port 3042 with JMAP client for Stalwart,
account provisioning (@mana.how addresses on user registration),
thread/message/send/label API endpoints, and JWT + service-key auth.

Frontend: Mail module with 3-column inbox UI (mailboxes, thread list,
detail/compose), local-first encrypted drafts in Dexie, and API-driven
thread fetching. Scoped CSS with theme tokens.

Integration: Dexie v11 schema, mail pgSchema in mana_platform,
mana-auth fire-and-forget hook for account provisioning,
getManaMailUrl() in API config, app registry + branding update.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:35:54 +02:00

72 lines
2.7 KiB
TypeScript

/**
* mana-mail — Mail service for the Mana ecosystem.
*
* Hono + Bun runtime. Provides JMAP-based email access to Stalwart,
* account provisioning (@mana.how addresses), and mail API for the frontend.
*/
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { loadConfig } from './config';
import { getDb } from './db/connection';
import { serviceErrorHandler as errorHandler } from '@mana/shared-hono';
import { jwtAuth } from './middleware/jwt-auth';
import { serviceAuth } from './middleware/service-auth';
import { JmapClient } from './services/jmap-client';
import { AccountService } from './services/account-service';
import { MailService } from './services/mail-service';
import { healthRoutes } from './routes/health';
import { createThreadRoutes } from './routes/threads';
import { createMessageRoutes } from './routes/messages';
import { createSendRoutes } from './routes/send';
import { createLabelRoutes } from './routes/labels';
import { createAccountRoutes } from './routes/accounts';
import { createInternalRoutes } from './routes/internal';
// ─── Bootstrap ──────────────────────────────────────────────
const config = loadConfig();
const db = getDb(config.databaseUrl);
// Instantiate services
const jmapClient = new JmapClient(config.stalwart);
const accountService = new AccountService(db, config.stalwart);
const mailService = new MailService(db, jmapClient, accountService);
// ─── App ────────────────────────────────────────────────────
const app = new Hono();
// Global middleware
app.onError(errorHandler);
app.use(
'*',
cors({
origin: config.cors.origins,
credentials: true,
})
);
// Health check (no auth)
app.route('/health', healthRoutes);
// User-facing routes (JWT auth)
app.use('/api/v1/mail/*', jwtAuth(config.manaAuthUrl));
app.route('/api/v1/mail', createThreadRoutes(mailService));
app.route('/api/v1/mail', createSendRoutes(mailService));
app.route('/api/v1/mail', createLabelRoutes(mailService));
app.route('/api/v1/mail', createAccountRoutes(accountService));
app.route('/api/v1/mail/messages', createMessageRoutes(mailService));
// Service-to-service routes (X-Service-Key auth)
app.use('/api/v1/internal/*', serviceAuth(config.serviceKey));
app.route('/api/v1/internal', createInternalRoutes(accountService));
// ─── Start ──────────────────────────────────────────────────
console.log(`mana-mail starting on port ${config.port}...`);
export default {
port: config.port,
fetch: app.fetch,
};