Skip to content

Commit 89b45ca

Browse files
authored
API-контракты: полное покрытие OpenAPI + coverage-тест, MCP err.body/дрейф/новые инструменты (#86)
* feat(openapi): backfill the manifest to full coverage + anti-drift test The manifest documented ~35 operations of ~90 mounted — entire resources (sync, quarantine, users, feature-flags, backups, settings, me/*) and nearly all item-level CRUD were missing, so a client generated from /openapi.json got half the API. Backfilled every mounted admin route (request bodies wired from the real zod validators where they exist). Adds tests/integration/openapi-coverage — introspects the mounted Express router and asserts every route is either in the spec or a reviewed allow-list (autoconfig, OIDC redirects, /metrics), plus the inverse (no spec path that isn't mounted). The manifest can no longer silently drift: a new router.get(...) fails CI until it's documented. Also fixes the version served in Docker: `node dist/index.js` left npm_package_version unset so /openapi.json advertised 0.1.0 — a new appVersion() helper falls back to reading package.json. Closes #78 * feat(mcp): surface validation detail, fix schema drift, add missing tools - fail() now appends the MailApiError body, so a backend 400's {error, issues:[{path,message}]} reaches the model — it can self-correct instead of seeing a bare "Validation error". - ok() emits compact JSON (was pretty-printed), so large lists like list_quarantine across every mailbox don't flood the context window. - Schema drift fixes: webhook `events` is now the real enum (incl. send.bounced) on create+update instead of z.array(z.string()); update_smtp_account gains the active/domainId/userEnvVar/passwordEnvVar fields it was missing (so it can deactivate an account, not only delete it); dns_check gains ?refresh. - New tools (69 → 82): generate_temp_alias, update_alias, regenerate_access_rules, update_fetchmail (pause), delete_migration, bulk_quarantine, get_quarantine_message, set_user_password, reset_feature_flag, and the get_webhook / get_smtp_account / get_settings item reads. Refs #79
1 parent 38f3a38 commit 89b45ca

7 files changed

Lines changed: 808 additions & 26 deletions

File tree

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { writeFileSync } from 'node:fs';
22
import { buildOpenApiDocument } from '../lib/openapi';
3+
import { appVersion } from '../version';
34

45
/**
56
* Emit the OpenAPI document to a file (default `openapi.json`) for CI checks and
67
* client/doc generation. Usage: `pnpm openapi:emit [outfile]`.
78
*/
89
const outfile = process.argv[2] ?? 'openapi.json';
9-
const doc = buildOpenApiDocument(process.env.npm_package_version ?? '0.1.0');
10+
const doc = buildOpenApiDocument(appVersion());
1011
writeFileSync(outfile, `${JSON.stringify(doc, null, 2)}\n`);
1112
console.error(`Wrote ${outfile} (${Object.keys(doc.paths as object).length} paths)`);

mailserver-api/src/http/routes/openapi.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { Router, type Request, type Response } from 'express';
22
import { buildOpenApiDocument } from '../../lib/openapi';
3+
import { appVersion } from '../../version';
34

45
/** Serves the OpenAPI 3.1 document (unauthenticated) at `GET /openapi.json`. */
56
export function openapiRouter() {
67
const router = Router();
78
// Built once at startup; the manifest is static.
8-
const document = buildOpenApiDocument(process.env.npm_package_version ?? '0.1.0');
9+
const document = buildOpenApiDocument(appVersion());
910

1011
router.get('/openapi.json', (_req: Request, res: Response) => {
1112
res.json(document);

0 commit comments

Comments
 (0)