email: full-text search (FTS5) — backend index + /email/search + search box in the list
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import { join } from 'node:path';
|
||||
import type { EmailMessage } from 'types';
|
||||
import { createRouter } from '../../create-router';
|
||||
import { DATA_PATH } from '@@/data-path';
|
||||
import { openEmailDb, rowToSummary, getSyncMeta } from './email-db';
|
||||
import { openEmailDb, rowToSummary, getSyncMeta, searchEmails } from './email-db';
|
||||
import { accountsRouter } from './accounts';
|
||||
|
||||
export const emailRouter = createRouter();
|
||||
@@ -64,6 +64,24 @@ emailRouter.get('/events', (ctx) => {
|
||||
});
|
||||
});
|
||||
|
||||
// Full-text search across all mail (subject / sender / recipients / snippet / body), newest first.
|
||||
emailRouter.get('/search', async (ctx) => {
|
||||
const email = ctx.get('user').email;
|
||||
const q = (ctx.req.query('q') ?? '').trim();
|
||||
const page = Math.max(1, Number(ctx.req.query('page') ?? '1') || 1);
|
||||
const limit = Math.min(100, Math.max(1, Number(ctx.req.query('limit') ?? '50') || 50));
|
||||
const offset = (page - 1) * limit;
|
||||
if (!q) return ctx.json({ messages: [], total: 0 });
|
||||
|
||||
const db = openEmailDb(email);
|
||||
try {
|
||||
const { rows, total } = searchEmails(db, q, limit, offset);
|
||||
return ctx.json({ messages: rows.map(rowToSummary), total });
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
});
|
||||
|
||||
emailRouter.get('/messages', async (ctx) => {
|
||||
const email = ctx.get('user').email;
|
||||
const page = Number(ctx.req.query('page') ?? '1');
|
||||
|
||||
Reference in New Issue
Block a user