Files
TREK/server/src/nest/trips/trips.bridge.ts
T
Maurice f0f69df67e Fold the journey domain into Nest and finish the MCP migration
journeyService (1324 LOC, 36 exports) and journeyShareService (203) become
JourneyDomainService and JourneyShareService. Every SQL statement, error string
and broadcast is the one that shipped.

The two could never be split: the share service gates on isOwner, which lives in
the domain service, so it injects it.

JourneyDomainModule is a leaf carrying just the two services. Places,
assignments and the plugin host each need a handful of journey functions;
importing JourneyModule for that would drag MemoriesModule and both photo
providers into their graphs. Same shape as TrekPhotosModule.

The 23 tools in src/mcp/tools/journey.ts become JourneyMcp. src/mcp/tools/ is
down to _shared.ts and registerTools() no longer fans out to anything.

journey.bridge.ts keeps four exports, for the journey resources in
src/mcp/resources.ts that register at import time.

McpAccessMode is host-augmentable now. journey:share is neither read nor write,
so the three share tools would have had to be opaque predicates - and predicates
bypass the access policy entirely, invisible to the boot-time scope gate. A
scope typo in one would ship as a silently ungated tool. McpAccessModeRegistry
mirrors McpAccessGroupRegistry; unaugmented, mode stays 'read' | 'write'.

Fixes a latent bug in tests/helpers/mcp-test-controllers.ts: it constructed
PlacesService with five of eight arguments. tsconfig only includes src, so
nothing typechecked it, and the missing dependencies were harmless until the
journey skeleton hooks landed on the place write paths.

journey.mcp.ts arrived from src/mcp/ at 14.5% branch coverage - the legacy
registrar had no test file of its own. 40 tool tests take it to 93.4%, and 25
cases for the skeleton lifecycle, the photo gallery and the preference row take
the domain service from 73.9% to 82.8%.
2026-08-08 23:25:57 +02:00

74 lines
4.0 KiB
TypeScript

import { db } from '../../db/database';
import { JourneyDomainService } from '../journey/journey-domain.service';
import { TrekPhotosRepository } from '../photos/trek-photos.repository';
import { DatabaseService } from '../database/database.service';
import { RealtimeService } from '../realtime/realtime.service';
import { PermissionsService } from '../permissions/permissions.service';
import { QueryHelpersService } from '../query-helpers/query-helpers.service';
import { UnsplashService } from '../unsplash/unsplash.service';
import { PlacePhotoCacheService } from '../place-photos/place-photo-cache.service';
import { RuntimeEnvService } from '../app-config/runtime-env.service';
import { TripsService } from './trips.service';
import { TodoService } from '../todo/todo.service';
import { PackingService } from '../packing/packing.service';
import { FilesService } from '../files/files.service';
import { ReservationsService } from '../reservations/reservations.service';
import { DaysService } from '../days/days.service';
import { BudgetService } from '../budget/budget.service';
import { ExchangeRatesService } from '../budget/exchange-rates.service';
import { CollabService } from '../collab/collab.service';
import { VacayService } from '../vacay/vacay.service';
import { PlacesService } from '../places/places.service';
import { MapsService } from '../maps/maps.service';
import { UserCleanupService } from '../auth/user-cleanup.service';
/**
* Non-Nest entry point for the trip domain — for the two consumers that cannot
* inject TripsService: the legacy packing-list/budget-overview prompt
* registrar in src/mcp/tools/prompts.ts (outside the container) and
* budget.mcp.ts's owner/member lookups (injecting TripsService there would
* need a forwardRef'd TripsModule↔BudgetModule cycle, so it stays on the
* bridge seam migration-graph.md planned). Exports only the legacy
* services/tripService names they consume, 1:1, so repointing was an
* import-path-only diff. Everything else injects TripsService. Delete this
* file when the prompts registrar migrates and the budget MCP surface can
* inject TripsService without a module cycle.
*
* Module-level construction is safe: `db` is the reinitialize-proof Proxy onto
* the shared better-sqlite3 singleton.
*/
const dbs = () => new DatabaseService(db);
// One instance, not one per consumer: the in-flight dedup only works if the
// stampede guard is shared (see PlacePhotoCacheService).
const photoCache = new PlacePhotoCacheService(dbs(), new RuntimeEnvService());
const journeyDomain = new JourneyDomainService(dbs(), new RealtimeService(), new TrekPhotosRepository(dbs()));
const budget = new BudgetService(dbs(), new PermissionsService(dbs()), new ExchangeRatesService(), new RealtimeService());
const trips = new TripsService(
dbs(),
new TodoService(dbs(), new PermissionsService(dbs()), new RealtimeService()),
new PackingService(dbs(), new PermissionsService(dbs()), new RealtimeService()),
new FilesService(dbs(), new PermissionsService(dbs()), new RealtimeService()),
new ReservationsService(dbs(), new PermissionsService(dbs()), budget, new RealtimeService()),
new DaysService(dbs(), new PermissionsService(dbs()), new RealtimeService(), new QueryHelpersService(dbs())),
new PermissionsService(dbs()),
budget,
new CollabService(dbs(), new PermissionsService(dbs()), new RealtimeService()),
new VacayService(dbs(), new RealtimeService()),
new RealtimeService(),
new PlacesService(dbs(), new PermissionsService(dbs()), new RealtimeService(), new MapsService(dbs(), photoCache), new QueryHelpersService(dbs()), new UnsplashService(dbs(), new RuntimeEnvService()), photoCache, journeyDomain),
new UnsplashService(dbs(), new RuntimeEnvService()),
new UserCleanupService(dbs()),
);
export function getTripOwner(tripId: string | number) {
return trips.getOwner(tripId);
}
export function listMembers(tripId: string | number, tripOwnerId: number) {
return trips.listMembers(tripId, tripOwnerId);
}
export function getTripSummary(tripId: number, viewerUserId?: number) {
return trips.getTripSummary(tripId, viewerUserId);
}