managarten/services/mana-events/src/app.ts
Till JS 897256c985 test(mana-events): 35 server tests covering routes + sweeper
Add bun:test integration suite that exercises every public and host
endpoint plus the rate-bucket sweeper against a real Postgres. The
Hono app factory was extracted from index.ts into app.ts so tests can
build their own instance with a header-based auth mock instead of
spinning up mana-auth + JWKS.

Coverage:
- health route smoke
- public RSVP: snapshot fetch (incl. 404, cancelled, summary
  privacy), submit, validation (name, status, email, plus-ones,
  cancelled), upsert dedup (incl. null/missing email parity), summary
  aggregation across yes/no/maybe + plus-ones, rate-limit cap (5/h),
  absolute per-token cap (20)
- host events: publish (auth, idempotent token reuse, ownership),
  snapshot update (partial, ownership, 404), delete (cascade FK to
  rsvps + buckets, ownership, idempotent), get rsvps (ownership)
- sweeper: removes >2h-old buckets, keeps fresh ones, no-op on empty

Mock auth lives in a small helper that injects an X-Test-User header
into a fake middleware, so the same createApp() factory powers both
production (real jwtAuth) and tests (header mock).
2026-04-07 19:02:54 +02:00

46 lines
1.3 KiB
TypeScript

/**
* App factory — kept separate from index.ts so tests can import it
* without triggering the production bootstrap (sweeper, log, port bind).
*/
import { Hono, type MiddlewareHandler } from 'hono';
import { cors } from 'hono/cors';
import type { Config } from './config';
import type { Database } from './db/connection';
import { errorHandler } from './middleware/error-handler';
import { jwtAuth } from './middleware/jwt-auth';
import { healthRoutes } from './routes/health';
import { createEventsRoutes } from './routes/events';
import { createRsvpRoutes } from './routes/rsvp';
/**
* Build the Hono app. The auth middleware is injected so tests can swap
* the real JWKS-validating jwtAuth for a header-based mock without
* spinning up a real mana-auth instance.
*/
export function createApp(
db: Database,
config: Config,
authMiddleware: MiddlewareHandler = jwtAuth(config.manaAuthUrl)
): Hono {
const app = new Hono();
app.onError(errorHandler);
app.use(
'*',
cors({
origin: config.cors.origins,
credentials: true,
})
);
// Public — no auth
app.route('/health', healthRoutes);
app.route('/api/v1/rsvp', createRsvpRoutes(db, config));
// Authenticated host endpoints
app.use('/api/v1/events/*', authMiddleware);
app.route('/api/v1/events', createEventsRoutes(db));
return app;
}