Add multi-account support and CORS/logging middleware

- Add garfield, sales, leads, founder accounts to IMAP and SMTP configs
- Refactor fetcherpay config into shared helper functions
- Add CORS middleware with wildcard origin
- Add request logging middleware and MCP session lifecycle logs
- Include package-lock.json and add @types/cors dependency

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
garfieldheron
2026-04-14 08:45:45 -04:00
parent 9ecb02785c
commit 166f5d55a6
6 changed files with 2670 additions and 66 deletions

View File

@@ -1,29 +1,58 @@
import { ImapFlow } from 'imapflow';
export type Account = 'yahoo' | 'fetcherpay';
export type Account = 'yahoo' | 'fetcherpay' | 'garfield' | 'sales' | 'leads' | 'founder';
const FETCHERPAY_IMAP_HOST = process.env['FETCHERPAY_IMAP_HOST'] ?? 'mail.fetcherpay.com';
const FETCHERPAY_IMAP_PORT = parseInt(process.env['FETCHERPAY_IMAP_PORT'] ?? '30993');
function fetcherpayImapConfig(user: string, pass: string) {
return {
host: FETCHERPAY_IMAP_HOST,
port: FETCHERPAY_IMAP_PORT,
secure: true,
auth: { user, pass },
tls: { rejectUnauthorized: false },
};
}
function getConfig(account: Account = 'yahoo') {
if (account === 'fetcherpay') {
return {
host: process.env['FETCHERPAY_IMAP_HOST'] ?? 'mail.fetcherpay.com',
port: parseInt(process.env['FETCHERPAY_IMAP_PORT'] ?? '30993'),
secure: true,
auth: {
user: process.env['FETCHERPAY_EMAIL'] as string,
pass: process.env['FETCHERPAY_PASSWORD'] as string,
},
tls: { rejectUnauthorized: false }, // self-signed cert on self-hosted server
};
switch (account) {
case 'fetcherpay':
return fetcherpayImapConfig(
process.env['FETCHERPAY_EMAIL'] as string,
process.env['FETCHERPAY_PASSWORD'] as string,
);
case 'garfield':
return fetcherpayImapConfig(
process.env['GARFIELD_EMAIL'] as string,
process.env['GARFIELD_PASSWORD'] as string,
);
case 'sales':
return fetcherpayImapConfig(
process.env['SALES_EMAIL'] as string,
process.env['SALES_PASSWORD'] as string,
);
case 'leads':
return fetcherpayImapConfig(
process.env['LEADS_EMAIL'] as string,
process.env['LEADS_PASSWORD'] as string,
);
case 'founder':
return fetcherpayImapConfig(
process.env['FOUNDER_EMAIL'] as string,
process.env['FOUNDER_PASSWORD'] as string,
);
default:
return {
host: 'imap.mail.yahoo.com',
port: 993,
secure: true,
auth: {
user: process.env['YAHOO_EMAIL'] as string,
pass: process.env['YAHOO_APP_PASSWORD'] as string,
},
};
}
return {
host: 'imap.mail.yahoo.com',
port: 993,
secure: true,
auth: {
user: process.env['YAHOO_EMAIL'] as string,
pass: process.env['YAHOO_APP_PASSWORD'] as string,
},
};
}
async function withClient<T>(account: Account, fn: (client: ImapFlow) => Promise<T>): Promise<T> {
@@ -159,9 +188,15 @@ export async function readMessage(uid: number, account: Account = 'yahoo'): Prom
}
export async function getProfile(account: Account = 'yahoo'): Promise<{ email: string; name: string; account: string }> {
const email = account === 'fetcherpay'
? (process.env['FETCHERPAY_EMAIL'] ?? '')
: (process.env['YAHOO_EMAIL'] ?? '');
const emailMap: Record<Account, string> = {
yahoo: process.env['YAHOO_EMAIL'] ?? '',
fetcherpay: process.env['FETCHERPAY_EMAIL'] ?? '',
garfield: process.env['GARFIELD_EMAIL'] ?? '',
sales: process.env['SALES_EMAIL'] ?? '',
leads: process.env['LEADS_EMAIL'] ?? '',
founder: process.env['FOUNDER_EMAIL'] ?? '',
};
const email = emailMap[account] ?? '';
return { email, name: email.split('@')[0], account };
}