Files
TREK/server/tests/helpers/mcp-test-controllers.ts
T
Maurice ac96644508 refactor(server): fold the notifications domain out of services/
Four files taken apart rather than moved, because they only worked as a knot.

The mailer becomes its own leaf module. AuthService sends the password-reset
mail while NotificationsModule imports AuthModule for the demo gate in
NotificationsMcp - a mailer inside the notifications domain would have closed a
hard cycle that only a forwardRef could open again. Webhook and ntfy stay with
notifications; auth has no business importing them.

The channel registry stays a module singleton and does NOT become a provider.
PluginRuntimeService pushes its channel getter in at onModuleInit, and
notifications.bridge.ts builds its own NotificationsService for the scheduler
crons and the memories senders. A provider would hand the bridge a second, empty
registry - every plugin channel would then go quiet with no error anywhere.
CHOVR-015 drives that seam end to end: a channel published through the runtime,
delivered through the bridge. Nothing pinned it before; the existing cases all
set the source themselves.

The built-ins no longer self-register by side-effect import. They used to exist
only because notificationPreferencesService happened to `import
'./notifications/builtins'`; removing that line would have silenced email,
webhook and ntfy without a failure. They are built from the injected transports
and registered from NotificationsService's constructor, so both instances have
them.

No cached nodemailer transport: MailerService.createTransport re-reads the SMTP
config and skipTlsVerify per send, exactly as the three inline call sites did,
so an admin changing them does not have to restart.

Preferences become a provider over DatabaseService. Eight places built
NotificationsService by hand, so a tests/helpers/notifications.ts factory keeps
the next constructor parameter a one-file diff instead of an eight-file one.
2026-08-08 12:09:56 +02:00

113 lines
7.1 KiB
TypeScript

import { createTestRegistry, type McpRegistry } from '@trek/nest-mcp';
import { db } from '../../src/db/database';
import { trekMcpAccessPolicy, trekMcpValidateAccess } from '../../src/mcp/nest-mcp-policy';
import { AssignmentsMcp } from '../../src/nest/assignments/assignments.mcp';
import { AssignmentsService } from '../../src/nest/assignments/assignments.service';
import { AtlasMcp } from '../../src/nest/atlas/atlas.mcp';
import { AtlasService } from '../../src/nest/atlas/atlas.service';
import { AuthService } from '../../src/nest/auth/auth.service';
import { BudgetMcp } from '../../src/nest/budget/budget.mcp';
import { BudgetService } from '../../src/nest/budget/budget.service';
import { ExchangeRatesService } from '../../src/nest/budget/exchange-rates.service';
import { CategoriesMcp } from '../../src/nest/categories/categories.mcp';
import { CategoriesService } from '../../src/nest/categories/categories.service';
import { CollabMcp } from '../../src/nest/collab/collab.mcp';
import { CollabService } from '../../src/nest/collab/collab.service';
import { CollectionsMcp } from '../../src/nest/collections/collections.mcp';
import { CollectionsService } from '../../src/nest/collections/collections.service';
import { DatabaseService } from '../../src/nest/database/database.service';
import { DayNotesMcp } from '../../src/nest/days/day-notes.mcp';
import { DayNotesService } from '../../src/nest/days/day-notes.service';
import { DaysMcp } from '../../src/nest/days/days.mcp';
import { DaysService } from '../../src/nest/days/days.service';
import { MapsMcp } from '../../src/nest/maps/maps.mcp';
import { MapsService } from '../../src/nest/maps/maps.service';
import { NotificationsMcp } from '../../src/nest/notifications/notifications.mcp';
import { NotificationsService } from '../../src/nest/notifications/notifications.service';
import { PackingMcp } from '../../src/nest/packing/packing.mcp';
import { PackingService } from '../../src/nest/packing/packing.service';
import { PermissionsService } from '../../src/nest/permissions/permissions.service';
import { PlacesMcp } from '../../src/nest/places/places.mcp';
import { PlacesService } from '../../src/nest/places/places.service';
import { ReservationsMcp } from '../../src/nest/reservations/reservations.mcp';
import { ReservationsService } from '../../src/nest/reservations/reservations.service';
import { TagsMcp } from '../../src/nest/tags/tags.mcp';
import { TagsService } from '../../src/nest/tags/tags.service';
import { SettingsService } from '../../src/nest/settings/settings.service';
import { ShareMcp } from '../../src/nest/share/share.mcp';
import { ShareService } from '../../src/nest/share/share.service';
import { TodoMcp } from '../../src/nest/todo/todo.mcp';
import { TodoService } from '../../src/nest/todo/todo.service';
import { TransitMcp } from '../../src/nest/transit/transit.mcp';
import { TransitService } from '../../src/nest/transit/transit.service';
import { FilesService } from '../../src/nest/files/files.service';
import { TripsMcp } from '../../src/nest/trips/trips.mcp';
import { TripsService } from '../../src/nest/trips/trips.service';
import { VacayMcp } from '../../src/nest/vacay/vacay.mcp';
import { VacayService } from '../../src/nest/vacay/vacay.service';
import { RealtimeService } from '../../src/nest/realtime/realtime.service';
import { QueryHelpersService } from '../../src/nest/query-helpers/query-helpers.service';
import { makeNotificationsService, makeNotificationPreferencesService } from './notifications';
/**
* Hand-wired counterpart of the boot-time discovery in McpRegistryService,
* for the no-Nest MCP harness. One line per migrated domain — add the new
* @McpController instance here when a domain moves off the legacy registrar
* fan-out. Constructing against the `db` Proxy keeps per-file vi.mock's of
* src/db/database flowing through (same pattern as todo.bridge.ts).
*/
export function createMcpTestRegistry(): McpRegistry {
const dbService = new DatabaseService(db);
const permissionsService = new PermissionsService(dbService);
const authService = new AuthService(dbService, permissionsService, new AtlasService(dbService));
const realtimeService = new RealtimeService();
const queryHelpersService = new QueryHelpersService(dbService);
const daysService = new DaysService(dbService, permissionsService, realtimeService, queryHelpersService);
const exchangeRatesService = new ExchangeRatesService();
const budgetService = new BudgetService(dbService, permissionsService, exchangeRatesService, realtimeService);
const todoService = new TodoService(dbService, permissionsService, realtimeService);
const packingService = new PackingService(dbService, permissionsService, realtimeService);
const collabService = new CollabService(dbService, permissionsService, realtimeService);
const mapsService = new MapsService(dbService);
const placesService = new PlacesService(dbService, permissionsService, realtimeService, mapsService, queryHelpersService);
const reservationsService = new ReservationsService(dbService, permissionsService, budgetService, realtimeService);
const tripsService = new TripsService(
dbService,
todoService,
packingService,
new FilesService(dbService, permissionsService, realtimeService),
new ReservationsService(dbService, permissionsService, budgetService, realtimeService),
daysService,
permissionsService,
budgetService,
collabService,
new VacayService(dbService, realtimeService),
realtimeService,
placesService,
);
return createTestRegistry(
[
new TagsMcp(new TagsService(dbService), authService),
new CategoriesMcp(new CategoriesService(dbService)),
new TodoMcp(todoService, authService),
new PackingMcp(packingService, authService),
new BudgetMcp(budgetService, exchangeRatesService, dbService, authService),
new ReservationsMcp(reservationsService, daysService, budgetService, authService),
new DayNotesMcp(new DayNotesService(dbService, permissionsService, realtimeService), authService),
new DaysMcp(daysService, dbService, placesService, authService),
new AssignmentsMcp(new AssignmentsService(dbService, permissionsService, realtimeService, queryHelpersService), daysService, authService),
new CollabMcp(collabService, authService),
new VacayMcp(new VacayService(dbService, realtimeService), authService),
new TripsMcp(tripsService, todoService, collabService, authService),
new ShareMcp(new ShareService(dbService, new SettingsService(dbService), permissionsService, queryHelpersService), authService),
new MapsMcp(mapsService),
new PlacesMcp(placesService, mapsService, dbService, authService),
new CollectionsMcp(new CollectionsService(dbService, permissionsService, realtimeService), dbService, authService),
new TransitMcp(new TransitService(), daysService, reservationsService, dbService, authService),
new AtlasMcp(new AtlasService(dbService)),
new NotificationsMcp(makeNotificationsService(dbService, realtimeService), authService),
],
{ accessPolicy: trekMcpAccessPolicy, validateAccess: trekMcpValidateAccess },
);
}