diff --git a/server/src/db/migrations.ts b/server/src/db/migrations.ts index bbf68c0d2..154ad0686 100644 --- a/server/src/db/migrations.ts +++ b/server/src/db/migrations.ts @@ -1,5 +1,5 @@ import { readEnv } from '../app-config'; -import { encrypt_api_key } from '../services/apiKeyCrypto'; +import { encrypt_api_key } from '../nest/common/crypto/apiKeyCrypto'; import Database from 'better-sqlite3'; import fs from 'fs'; diff --git a/server/src/middleware/auth.ts b/server/src/middleware/auth.ts index e5ab0482c..d485f4e80 100644 --- a/server/src/middleware/auth.ts +++ b/server/src/middleware/auth.ts @@ -5,7 +5,7 @@ import { db } from '../db/database'; import { JWT_SECRET } from '../config'; import { AuthRequest, OptionalAuthRequest, User } from '../types'; import { applyIdempotency } from './idempotency'; -import { isDemoEmail } from '../services/demo'; +import { isDemoEmail } from '../nest/common/demo'; export function extractToken(req: Request): string | null { // Prefer httpOnly cookie; fall back to Authorization: Bearer (MCP, API clients) diff --git a/server/src/middleware/mfaPolicy.ts b/server/src/middleware/mfaPolicy.ts index dad4a7b6c..2d09f9b90 100644 --- a/server/src/middleware/mfaPolicy.ts +++ b/server/src/middleware/mfaPolicy.ts @@ -2,7 +2,7 @@ import { Request, Response, NextFunction } from 'express'; import { readEnv } from '../app-config'; import { db } from '../db/database'; import { extractToken, verifyJwtAndLoadUser } from './auth'; -import { DEMO_EMAILS } from '../services/demo'; +import { DEMO_EMAILS } from '../nest/common/demo'; /** Paths that never require MFA (public or pre-auth). */ export function isPublicApiPath(method: string, pathNoQuery: string): boolean { diff --git a/server/src/nest/admin/admin.service.ts b/server/src/nest/admin/admin.service.ts index f108b274c..ba2194b83 100644 --- a/server/src/nest/admin/admin.service.ts +++ b/server/src/nest/admin/admin.service.ts @@ -15,11 +15,11 @@ import { revokeUserSessions, revokeUserSessionsForClient } from '../../mcp/sessi import { invalidateMcpSessions } from '../../mcp'; import { emitUserDeleted } from '../../plugin-user-lifecycle'; import type { User, Addon } from '../../types'; -import { maybe_encrypt_api_key, decrypt_api_key } from '../../services/apiKeyCrypto'; -import { avatarUrl } from '../../services/avatarUrl'; +import { maybe_encrypt_api_key, decrypt_api_key } from '../common/crypto/apiKeyCrypto'; +import { avatarUrl } from '../common/avatarUrl'; import { prepareLlmAddonConfigForWrite, maskLlmAddonConfig } from '../../services/llmConfig'; import { getPhotoProviderConfig } from '../../services/memories/helpersService'; -import { validatePassword } from '../../services/passwordPolicy'; +import { validatePassword } from '../common/passwordPolicy'; import { deleteUserCompletely } from '../../services/userCleanupService'; import { getPreferencesMatrix, setAdminPreferences } from '../../services/notificationPreferencesService'; import { DatabaseService } from '../database/database.service'; diff --git a/server/src/nest/auth/auth-public.controller.ts b/server/src/nest/auth/auth-public.controller.ts index faf9d010b..2fae17540 100644 --- a/server/src/nest/auth/auth-public.controller.ts +++ b/server/src/nest/auth/auth-public.controller.ts @@ -6,7 +6,7 @@ import { RateLimitService } from '../common/rate-limit.service'; import { OptionalJwtGuard } from './optional-jwt.guard'; import { getClientIp } from '../audit/client-ip'; import { AuditService } from '../audit/audit.service'; -import { willDropSecureCookie } from '../../services/cookie'; +import { willDropSecureCookie } from '../common/cookie'; import type { User } from '../../types'; const WINDOW = 15 * 60 * 1000; diff --git a/server/src/nest/auth/auth.bridge.ts b/server/src/nest/auth/auth.bridge.ts index 12f2f4308..f712d6cd6 100644 --- a/server/src/nest/auth/auth.bridge.ts +++ b/server/src/nest/auth/auth.bridge.ts @@ -35,7 +35,7 @@ const auth = new AuthService( ); export { stripUserForClient } from './auth.helpers'; -export { avatarUrl } from '../../services/avatarUrl'; +export { avatarUrl } from '../common/avatarUrl'; export function isDemoUser(userId: number): boolean { return auth.isDemoUser(userId); diff --git a/server/src/nest/auth/auth.controller.ts b/server/src/nest/auth/auth.controller.ts index f44edb345..e5b0eb432 100644 --- a/server/src/nest/auth/auth.controller.ts +++ b/server/src/nest/auth/auth.controller.ts @@ -39,7 +39,7 @@ import { JwtAuthGuard } from './jwt-auth.guard'; import { CurrentUser } from './current-user.decorator'; import { getClientIp } from '../audit/client-ip'; import { AuditService } from '../audit/audit.service'; -import { isDemoEmail } from '../../services/demo'; +import { isDemoEmail } from '../common/demo'; import type { User } from '../../types'; const WINDOW = 15 * 60 * 1000; diff --git a/server/src/nest/auth/auth.helpers.ts b/server/src/nest/auth/auth.helpers.ts index 43cb5911f..fe646d357 100644 --- a/server/src/nest/auth/auth.helpers.ts +++ b/server/src/nest/auth/auth.helpers.ts @@ -3,7 +3,7 @@ import crypto from 'crypto'; import path from 'path'; import fs from 'fs'; import { User } from '../../types'; -import { decrypt_api_key } from '../../services/apiKeyCrypto'; +import { decrypt_api_key } from '../common/crypto/apiKeyCrypto'; /** * Pure half of the auth domain (no DB, no injected deps) — the DB half lives diff --git a/server/src/nest/auth/auth.service.ts b/server/src/nest/auth/auth.service.ts index ef225c70f..5e8a1bd62 100644 --- a/server/src/nest/auth/auth.service.ts +++ b/server/src/nest/auth/auth.service.ts @@ -13,9 +13,9 @@ import { DatabaseService } from '../database/database.service'; import { PermissionsService } from '../permissions/permissions.service'; import { AtlasService } from '../atlas/atlas.service'; import { getCountryFromCoords } from '../atlas/atlas-geo'; -import { validatePassword } from '../../services/passwordPolicy'; -import { encryptMfaSecret, decryptMfaSecret } from '../../services/mfaCrypto'; -import { decrypt_api_key, maybe_encrypt_api_key, encrypt_api_key } from '../../services/apiKeyCrypto'; +import { validatePassword } from '../common/passwordPolicy'; +import { encryptMfaSecret, decryptMfaSecret } from '../common/crypto/mfaCrypto'; +import { decrypt_api_key, maybe_encrypt_api_key, encrypt_api_key } from '../common/crypto/apiKeyCrypto'; import { createEphemeralToken } from '../../services/ephemeralTokens'; // Import from sessionManager directly, NOT the ../../mcp barrel: the barrel pulls // the whole tools fan-out (and via the domain bridges, the Nest services) into @@ -27,11 +27,11 @@ import { emitUserDeleted } from '../../plugin-user-lifecycle'; import { getFlightDistanceKm } from '../../services/distanceService'; import { verifyJwtAndLoadUser } from '../../middleware/auth'; import { User } from '../../types'; -import { DEMO_EMAIL_PRIMARY, isDemoEmail } from '../../services/demo'; -import { avatarUrl } from '../../services/avatarUrl'; +import { DEMO_EMAIL_PRIMARY, isDemoEmail } from '../common/demo'; +import { avatarUrl } from '../common/avatarUrl'; import { joinTripAsMember } from '../../services/tripMembership'; import { isPasskeyConfigured } from '../../services/webauthnConfig'; -import { setAuthCookie, clearAuthCookie } from '../../services/cookie'; +import { setAuthCookie, clearAuthCookie } from '../common/cookie'; import { sendPasswordResetEmail } from '../../services/notifications'; import { getAppUrl } from '../../app-config'; import { diff --git a/server/src/nest/auth/passkey.controller.ts b/server/src/nest/auth/passkey.controller.ts index 4993ff77f..f2b1982dd 100644 --- a/server/src/nest/auth/passkey.controller.ts +++ b/server/src/nest/auth/passkey.controller.ts @@ -4,7 +4,7 @@ import { RateLimitService } from '../common/rate-limit.service'; import { JwtAuthGuard } from './jwt-auth.guard'; import { PasskeyEnabledGuard } from './passkey-enabled.guard'; import { CurrentUser } from './current-user.decorator'; -import { setAuthCookie } from '../../services/cookie'; +import { setAuthCookie } from '../common/cookie'; import { getClientIp } from '../audit/client-ip'; import { AuditService } from '../audit/audit.service'; import { PasskeyService } from './passkey.service'; diff --git a/server/src/nest/auth/passkey.service.ts b/server/src/nest/auth/passkey.service.ts index 60ce165e2..ea944599a 100644 --- a/server/src/nest/auth/passkey.service.ts +++ b/server/src/nest/auth/passkey.service.ts @@ -8,7 +8,7 @@ import { type AuthenticatorTransportFuture, } from '@simplewebauthn/server'; import { resolveWebauthnConfig } from '../../services/webauthnConfig'; -import { avatarUrl } from '../../services/avatarUrl'; +import { avatarUrl } from '../common/avatarUrl'; import { stripUserForClient } from './auth.helpers'; import { AuthService } from './auth.service'; import { DatabaseService } from '../database/database.service'; diff --git a/server/src/nest/budget/budget.service.ts b/server/src/nest/budget/budget.service.ts index 139fa7db1..3a97ba961 100644 --- a/server/src/nest/budget/budget.service.ts +++ b/server/src/nest/budget/budget.service.ts @@ -4,7 +4,7 @@ import type { TrekWsPayload, TrekWsTripEventName } from '@trek/shared'; import { RealtimeService } from '../realtime/realtime.service'; import { PermissionsService } from '../permissions/permissions.service'; import { verifyTripAccess } from '../../services/tripAccess'; -import { avatarUrl } from '../../services/avatarUrl'; +import { avatarUrl } from '../common/avatarUrl'; import type { User, BudgetItem, BudgetItemMember, BudgetItemPayer } from '../../types'; import { ExchangeRatesService } from './exchange-rates.service'; diff --git a/server/src/nest/collab/collab.service.ts b/server/src/nest/collab/collab.service.ts index cf6a4d17b..32bb005b3 100644 --- a/server/src/nest/collab/collab.service.ts +++ b/server/src/nest/collab/collab.service.ts @@ -6,7 +6,7 @@ import type { TrekWsPayload, TrekWsTripEventName } from '@trek/shared'; import { RealtimeService } from '../realtime/realtime.service'; import { PermissionsService } from '../permissions/permissions.service'; import { verifyTripAccess } from '../../services/tripAccess'; -import { avatarUrl } from '../../services/avatarUrl'; +import { avatarUrl } from '../common/avatarUrl'; import { checkSsrf, createPinnedDispatcher } from '../../utils/ssrfGuard'; import type { CollabNote, CollabPoll, CollabMessage, TripFile, User } from '../../types'; diff --git a/server/src/nest/collections/collections.controller.ts b/server/src/nest/collections/collections.controller.ts index 45d23955c..02a704159 100644 --- a/server/src/nest/collections/collections.controller.ts +++ b/server/src/nest/collections/collections.controller.ts @@ -29,7 +29,7 @@ import { JwtAuthGuard } from '../auth/jwt-auth.guard'; import { CurrentUser } from '../auth/current-user.decorator'; import { PLACE_IMAGE_UPLOAD } from '../common/place-image-upload'; import { placeImageUrl } from '../../services/placeImage'; -import { isDemoEmail } from '../../services/demo'; +import { isDemoEmail } from '../common/demo'; import { CollectionCreateDto, CollectionUpdateDto, diff --git a/server/src/services/avatarUrl.ts b/server/src/nest/common/avatarUrl.ts similarity index 100% rename from server/src/services/avatarUrl.ts rename to server/src/nest/common/avatarUrl.ts diff --git a/server/src/services/conflictResult.ts b/server/src/nest/common/conflictResult.ts similarity index 100% rename from server/src/services/conflictResult.ts rename to server/src/nest/common/conflictResult.ts diff --git a/server/src/services/cookie.ts b/server/src/nest/common/cookie.ts similarity index 98% rename from server/src/services/cookie.ts rename to server/src/nest/common/cookie.ts index abb586c2b..76ce00226 100644 --- a/server/src/services/cookie.ts +++ b/server/src/nest/common/cookie.ts @@ -1,6 +1,6 @@ import { Request, Response } from 'express'; -import { readEnv } from '../app-config'; -import { SESSION_DURATION_MS, SESSION_DURATION_REMEMBER_MS } from '../config'; +import { readEnv } from '../../app-config'; +import { SESSION_DURATION_MS, SESSION_DURATION_REMEMBER_MS } from '../../config'; const COOKIE_NAME = 'trek_session'; diff --git a/server/src/services/apiKeyCrypto.ts b/server/src/nest/common/crypto/apiKeyCrypto.ts similarity index 96% rename from server/src/services/apiKeyCrypto.ts rename to server/src/nest/common/crypto/apiKeyCrypto.ts index 6dc0b0bdf..96eccea5c 100644 --- a/server/src/services/apiKeyCrypto.ts +++ b/server/src/nest/common/crypto/apiKeyCrypto.ts @@ -1,5 +1,5 @@ import * as crypto from 'node:crypto'; -import { ENCRYPTION_KEY } from '../config'; +import { ENCRYPTION_KEY } from '../../../config'; const ENCRYPTED_PREFIX = 'enc:v1:'; diff --git a/server/src/services/mfaCrypto.ts b/server/src/nest/common/crypto/mfaCrypto.ts similarity index 94% rename from server/src/services/mfaCrypto.ts rename to server/src/nest/common/crypto/mfaCrypto.ts index 2a64743ff..214933b9f 100644 --- a/server/src/services/mfaCrypto.ts +++ b/server/src/nest/common/crypto/mfaCrypto.ts @@ -1,5 +1,5 @@ import crypto from 'crypto'; -import { ENCRYPTION_KEY } from '../config'; +import { ENCRYPTION_KEY } from '../../../config'; function getKey(): Buffer { return crypto.createHash('sha256').update(`${ENCRYPTION_KEY}:mfa:v1`).digest(); diff --git a/server/src/services/demo.ts b/server/src/nest/common/demo.ts similarity index 100% rename from server/src/services/demo.ts rename to server/src/nest/common/demo.ts diff --git a/server/src/services/passwordPolicy.ts b/server/src/nest/common/passwordPolicy.ts similarity index 100% rename from server/src/services/passwordPolicy.ts rename to server/src/nest/common/passwordPolicy.ts diff --git a/server/src/services/timezoneService.ts b/server/src/nest/common/timezoneService.ts similarity index 100% rename from server/src/services/timezoneService.ts rename to server/src/nest/common/timezoneService.ts diff --git a/server/src/nest/files/files.controller.ts b/server/src/nest/files/files.controller.ts index 372348062..c637d722d 100644 --- a/server/src/nest/files/files.controller.ts +++ b/server/src/nest/files/files.controller.ts @@ -28,7 +28,7 @@ import { CurrentUser } from '../auth/current-user.decorator'; import { MAX_FILE_SIZE, MAX_VIDEO_SIZE, BLOCKED_EXTENSIONS, filesDir, isVideoExtension } from './files.constants'; import { getAllowedExtensions } from './files.bridge'; import { FileUploadDto, FileUpdateDto, FileLinkDto } from './files.dto'; -import { isDemoEmail } from '../../services/demo'; +import { isDemoEmail } from '../common/demo'; const UPLOAD = { storage: diskStorage({ diff --git a/server/src/nest/files/files.service.ts b/server/src/nest/files/files.service.ts index 787cc40ab..f58cc71a2 100644 --- a/server/src/nest/files/files.service.ts +++ b/server/src/nest/files/files.service.ts @@ -5,7 +5,7 @@ import type { Request } from 'express'; import type { TrekWsPayload, TrekWsTripEventName } from '@trek/shared'; import { RealtimeService } from '../realtime/realtime.service'; import { PermissionsService } from '../permissions/permissions.service'; -import { avatarUrl } from '../../services/avatarUrl'; +import { avatarUrl } from '../common/avatarUrl'; import { consumeEphemeralToken } from '../../services/ephemeralTokens'; import { verifyJwtAndLoadUser } from '../../middleware/auth'; import type { User, TripFile } from '../../types'; diff --git a/server/src/nest/maps/maps.service.ts b/server/src/nest/maps/maps.service.ts index ba1d172d6..a91f9bdd0 100644 --- a/server/src/nest/maps/maps.service.ts +++ b/server/src/nest/maps/maps.service.ts @@ -9,7 +9,7 @@ import type { } from '@trek/shared'; import { readEnv, getAppUrl } from '../../app-config'; import { safeFetchFollow, SsrfBlockedError } from '../../utils/ssrfGuard'; -import { decrypt_api_key } from '../../services/apiKeyCrypto'; +import { decrypt_api_key } from '../common/crypto/apiKeyCrypto'; // ── Photo cache (disk-backed) ──────────────────────────────────────────────── import * as placePhotoCache from '../../services/placePhotoCache'; import { DatabaseService } from '../database/database.service'; diff --git a/server/src/nest/notifications/notifications.service.ts b/server/src/nest/notifications/notifications.service.ts index 66dbf7f16..99542981c 100644 --- a/server/src/nest/notifications/notifications.service.ts +++ b/server/src/nest/notifications/notifications.service.ts @@ -25,7 +25,7 @@ import { } from '../../services/notificationPreferencesService'; import { getChannel, listChannels, type ChannelMessage, type ExternalChannel } from '../../services/notifications/channelRegistry'; import { getAction } from '../../services/inAppNotificationActions'; -import { avatarUrl } from '../../services/avatarUrl'; +import { avatarUrl } from '../common/avatarUrl'; import { DatabaseService } from '../database/database.service'; import { RealtimeService } from '../realtime/realtime.service'; diff --git a/server/src/nest/oidc/oidc.controller.ts b/server/src/nest/oidc/oidc.controller.ts index da14496d3..bae630917 100644 --- a/server/src/nest/oidc/oidc.controller.ts +++ b/server/src/nest/oidc/oidc.controller.ts @@ -2,7 +2,7 @@ import { Controller, Get, Query, Req, Res } from '@nestjs/common'; import type { Request, Response } from 'express'; import { readEnv } from '../../app-config'; import { OidcService, OIDC_STATE_TTL_MS } from './oidc.service'; -import { cookieOptions } from '../../services/cookie'; +import { cookieOptions } from '../common/cookie'; const OIDC_STATE_COOKIE = 'trek_oidc_state'; diff --git a/server/src/nest/oidc/oidc.service.ts b/server/src/nest/oidc/oidc.service.ts index 9fa964106..02f1a5bb5 100644 --- a/server/src/nest/oidc/oidc.service.ts +++ b/server/src/nest/oidc/oidc.service.ts @@ -8,9 +8,9 @@ import type { Request, Response } from 'express'; import { readEnv, getAppUrl } from '../../app-config'; import { JWT_SECRET, SESSION_DURATION_SECONDS } from '../../config'; import { User } from '../../types'; -import { decrypt_api_key } from '../../services/apiKeyCrypto'; +import { decrypt_api_key } from '../common/crypto/apiKeyCrypto'; import { joinTripAsMember } from '../../services/tripMembership'; -import { setAuthCookie } from '../../services/cookie'; +import { setAuthCookie } from '../common/cookie'; import { AuthService } from '../auth/auth.service'; import { DatabaseService } from '../database/database.service'; diff --git a/server/src/nest/packing/packing.controller.ts b/server/src/nest/packing/packing.controller.ts index 35a66fb6d..fc2f92259 100644 --- a/server/src/nest/packing/packing.controller.ts +++ b/server/src/nest/packing/packing.controller.ts @@ -14,7 +14,7 @@ import { import type { TrekWsPayload, TrekWsTripEventName } from '@trek/shared'; import type { User } from '../../types'; import { PackingService } from './packing.service'; -import { isUpdateConflict } from '../../services/conflictResult'; +import { isUpdateConflict } from '../common/conflictResult'; import { JwtAuthGuard } from '../auth/jwt-auth.guard'; import { CurrentUser } from '../auth/current-user.decorator'; import { diff --git a/server/src/nest/packing/packing.service.ts b/server/src/nest/packing/packing.service.ts index 8bd60ff65..b6fb013c9 100644 --- a/server/src/nest/packing/packing.service.ts +++ b/server/src/nest/packing/packing.service.ts @@ -3,8 +3,8 @@ import type { TrekWsPayload, TrekWsTripEventName } from '@trek/shared'; import { RealtimeService } from '../realtime/realtime.service'; import { PermissionsService } from '../permissions/permissions.service'; import { verifyTripAccess } from '../../services/tripAccess'; -import { avatarUrl } from '../../services/avatarUrl'; -import type { UpdateConflict } from '../../services/conflictResult'; +import { avatarUrl } from '../common/avatarUrl'; +import type { UpdateConflict } from '../common/conflictResult'; import type { User } from '../../types'; import { DatabaseService } from '../database/database.service'; diff --git a/server/src/nest/places/places.controller.ts b/server/src/nest/places/places.controller.ts index e1b3cb0ff..79761a493 100644 --- a/server/src/nest/places/places.controller.ts +++ b/server/src/nest/places/places.controller.ts @@ -20,12 +20,12 @@ import { hexColorSchema } from '@trek/shared'; import { readEnv } from '../../app-config'; import type { User } from '../../types'; import { PlacesService } from './places.service'; -import { isUpdateConflict } from '../../services/conflictResult'; +import { isUpdateConflict } from '../common/conflictResult'; import { JwtAuthGuard } from '../auth/jwt-auth.guard'; import { CurrentUser } from '../auth/current-user.decorator'; import { PLACE_IMAGE_UPLOAD } from '../common/place-image-upload'; import { placeImageUrl } from '../../services/placeImage'; -import { isDemoEmail } from '../../services/demo'; +import { isDemoEmail } from '../common/demo'; import { PlaceBulkDeleteDto, PlaceBulkUpdateDto, diff --git a/server/src/nest/places/places.service.ts b/server/src/nest/places/places.service.ts index 160b99543..5b6d45129 100644 --- a/server/src/nest/places/places.service.ts +++ b/server/src/nest/places/places.service.ts @@ -19,7 +19,7 @@ import { resolveCategoryIdForFolder, } from '../../services/kmlImport'; import { searchUnsplashPhotos, getUnsplashKey } from '../../services/unsplashService'; -import { type UpdateConflict, isUpdateConflict } from '../../services/conflictResult'; +import { type UpdateConflict, isUpdateConflict } from '../common/conflictResult'; import { reclaimPlaceImage } from '../../services/placeImage'; import { onPlaceCreated, onPlaceUpdated, onPlaceDeleted } from '../../services/journeyService'; import { diff --git a/server/src/nest/plugins/host/plugin-host-deps.factory.ts b/server/src/nest/plugins/host/plugin-host-deps.factory.ts index a92c7b0f0..7a322af33 100644 --- a/server/src/nest/plugins/host/plugin-host-deps.factory.ts +++ b/server/src/nest/plugins/host/plugin-host-deps.factory.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import type { TrekWsPayload, TrekWsTripEventName } from '@trek/shared'; import { readEnv } from '../../../app-config'; import { RealtimeService } from '../../realtime/realtime.service'; -import { isUpdateConflict } from '../../../services/conflictResult'; +import { isUpdateConflict } from '../../common/conflictResult'; import { getWeather } from '../../../services/weatherService'; import { BLOCKED_EXTENSIONS, filesDir } from '../../files/files.constants'; import { joinTripAsMember } from '../../../services/tripMembership'; @@ -17,7 +17,7 @@ import { PermissionsService } from '../../permissions/permissions.service'; import { TripsService, NotFoundError, ValidationError } from '../../trips/trips.service'; import { PlacesService, type PlaceCreateInput, type PlaceUpdateInput } from '../../places/places.service'; import { AddonsService } from '../../addons/addons.service'; -import { isDemoEmail } from '../../../services/demo'; +import { isDemoEmail } from '../../common/demo'; import { ADDON_IDS } from '../../../addons'; import { listJourneys, listEntries as listJournalEntriesSvc, createEntry as createJournalEntrySvc, updateEntry as updateJournalEntrySvc, deleteEntry as deleteJournalEntrySvc, createJourney as createJourneySvc, deleteJourney as deleteJourneySvc, onPlaceCreated, onPlaceUpdated, onPlaceDeleted } from '../../../services/journeyService'; import { AtlasService } from '../../atlas/atlas.service'; diff --git a/server/src/nest/plugins/plugin-oauth.service.ts b/server/src/nest/plugins/plugin-oauth.service.ts index bba838a46..3bca14715 100644 --- a/server/src/nest/plugins/plugin-oauth.service.ts +++ b/server/src/nest/plugins/plugin-oauth.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import crypto from 'node:crypto'; import { DatabaseService } from '../database/database.service'; -import { encrypt_api_key, decrypt_api_key } from '../../services/apiKeyCrypto'; +import { encrypt_api_key, decrypt_api_key } from '../common/crypto/apiKeyCrypto'; import { getAppUrl } from '../../app-config'; import { isPrivateIp } from './install/safe-fetch'; import { safeFetchLlm } from '../../utils/ssrfGuard'; diff --git a/server/src/nest/plugins/plugin-runtime.service.ts b/server/src/nest/plugins/plugin-runtime.service.ts index aeeb84f1a..3be09f5c2 100644 --- a/server/src/nest/plugins/plugin-runtime.service.ts +++ b/server/src/nest/plugins/plugin-runtime.service.ts @@ -9,7 +9,7 @@ import { readUserSettingsDecrypted, hasRequiredUserSettings } from './plugins.se import { PLUGIN_CHANNEL_EVENTS } from './install/manifest'; import { stripEmoji } from './text-sanitize'; import { applyStagedPluginTrees, setStagedRestoreApplier } from './plugin-backup'; -import { decrypt_api_key } from '../../services/apiKeyCrypto'; +import { decrypt_api_key } from '../common/crypto/apiKeyCrypto'; import { PluginSupervisor, type PluginRouteInfo } from './supervisor/plugin-supervisor'; import fs from 'node:fs'; import path from 'node:path'; diff --git a/server/src/nest/plugins/plugins.service.ts b/server/src/nest/plugins/plugins.service.ts index 5544ca49a..b19e355b7 100644 --- a/server/src/nest/plugins/plugins.service.ts +++ b/server/src/nest/plugins/plugins.service.ts @@ -3,7 +3,7 @@ import { db } from '../../db/database'; import { DatabaseService } from '../database/database.service'; import { pluginsEnabled } from './kill-switch'; import { devLinkEnabled } from './dev-link'; -import { maybe_encrypt_api_key, decrypt_api_key } from '../../services/apiKeyCrypto'; +import { maybe_encrypt_api_key, decrypt_api_key } from '../common/crypto/apiKeyCrypto'; import { readAudit } from './host/plugin-audit'; import { keyFingerprint } from './signature-status'; import { pluginBudgetUsage } from './host/plugin-host-state'; diff --git a/server/src/nest/reservations/reservations.service.ts b/server/src/nest/reservations/reservations.service.ts index 1c4867122..99c55c9c2 100644 --- a/server/src/nest/reservations/reservations.service.ts +++ b/server/src/nest/reservations/reservations.service.ts @@ -4,7 +4,7 @@ import type { TrekWsPayload, TrekWsTripEventName } from '@trek/shared'; import { RealtimeService } from '../realtime/realtime.service'; import { PermissionsService } from '../permissions/permissions.service'; import { verifyTripAccess } from '../../services/tripAccess'; -import { avatarUrl } from '../../services/avatarUrl'; +import { avatarUrl } from '../common/avatarUrl'; import type { Reservation, User } from '../../types'; import { BudgetService } from '../budget/budget.service'; import { typeToCostCategory } from '@trek/shared'; diff --git a/server/src/nest/settings/settings.service.ts b/server/src/nest/settings/settings.service.ts index bab2f165e..acd8c9140 100644 --- a/server/src/nest/settings/settings.service.ts +++ b/server/src/nest/settings/settings.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@nestjs/common'; import { DatabaseService } from '../database/database.service'; -import { decrypt_api_key, maybe_encrypt_api_key } from '../../services/apiKeyCrypto'; +import { decrypt_api_key, maybe_encrypt_api_key } from '../common/crypto/apiKeyCrypto'; import { MASKED_SETTING_VALUE, normalizeAppearance } from '@trek/shared'; const ENCRYPTED_SETTING_KEYS = new Set(['webhook_url', 'ntfy_token', 'mapbox_access_token', 'llm_api_key']); diff --git a/server/src/nest/transit/transit-itinerary.helpers.ts b/server/src/nest/transit/transit-itinerary.helpers.ts index b3a0e44e6..bb75fe3b2 100644 --- a/server/src/nest/transit/transit-itinerary.helpers.ts +++ b/server/src/nest/transit/transit-itinerary.helpers.ts @@ -9,7 +9,7 @@ */ import { haversineKm } from '../../services/distanceService'; import type { EndpointInput } from '../reservations/reservations.service'; -import { localParts, resolveTimeZone } from '../../services/timezoneService'; +import { localParts, resolveTimeZone } from '../common/timezoneService'; import { deriveTransitStats, type TransitItinerary, type TransitLeg } from './transit.helpers'; import { z } from 'zod'; diff --git a/server/src/nest/trips/trips.controller.ts b/server/src/nest/trips/trips.controller.ts index 3033e0d74..51c2694c6 100644 --- a/server/src/nest/trips/trips.controller.ts +++ b/server/src/nest/trips/trips.controller.ts @@ -30,7 +30,7 @@ import { CurrentUser } from '../auth/current-user.decorator'; import { getClientIp } from '../audit/client-ip'; import { logInfo } from '../audit/audit-log.logger'; import { AuditService } from '../audit/audit.service'; -import { isDemoEmail } from '../../services/demo'; +import { isDemoEmail } from '../common/demo'; import { NotFoundError, ValidationError } from './trips.service'; import { TripCreateDto, TripUpdateDto, TripCopyDto, TripAddMemberDto, TripTransferOwnershipDto, TripCreateGuestDto, TripRenameGuestDto } from './trips.dto'; import { saveUnsplashCover, isUnsplashCoverUrl } from '../../services/unsplashService'; diff --git a/server/src/nest/trips/trips.service.ts b/server/src/nest/trips/trips.service.ts index b28812a96..2ddf230dd 100644 --- a/server/src/nest/trips/trips.service.ts +++ b/server/src/nest/trips/trips.service.ts @@ -7,10 +7,10 @@ import type { TrekWsPayload, TrekWsTripEventName } from '@trek/shared'; import { RealtimeService } from '../realtime/realtime.service'; import { PermissionsService } from '../permissions/permissions.service'; import type { Trip, User } from '../../types'; -import { avatarUrl } from '../../services/avatarUrl'; +import { avatarUrl } from '../common/avatarUrl'; import { erasePluginUserData } from '../../services/userCleanupService'; import { emitUserDeleted } from '../../plugin-user-lifecycle'; -import { resolveTimeZone } from '../../services/timezoneService'; +import { resolveTimeZone } from '../common/timezoneService'; import { PlacesService } from '../places/places.service'; import { DaysService, addDays } from '../days/days.service'; import { PackingService } from '../packing/packing.service'; diff --git a/server/src/services/airtrail/airtrailMapper.ts b/server/src/services/airtrail/airtrailMapper.ts index ede21172d..4a9c32df2 100644 --- a/server/src/services/airtrail/airtrailMapper.ts +++ b/server/src/services/airtrail/airtrailMapper.ts @@ -1,4 +1,4 @@ -import { localParts } from '../timezoneService'; +import { localParts } from '../../nest/common/timezoneService'; import type { AirtrailAirport, AirtrailFlightRaw, AirtrailNamedCode } from './airtrailClient'; import type { AirtrailFlight } from '@trek/shared'; diff --git a/server/src/services/airtrail/airtrailService.ts b/server/src/services/airtrail/airtrailService.ts index b8d2ebafd..4f5ab4194 100644 --- a/server/src/services/airtrail/airtrailService.ts +++ b/server/src/services/airtrail/airtrailService.ts @@ -1,6 +1,6 @@ import type { AirtrailFlight } from '@trek/shared'; import { db } from '../../db/database'; -import { maybe_encrypt_api_key, decrypt_api_key } from '../apiKeyCrypto'; +import { maybe_encrypt_api_key, decrypt_api_key } from '../../nest/common/crypto/apiKeyCrypto'; import { checkSsrf } from '../../utils/ssrfGuard'; import { writeAudit } from '../../nest/audit/audit.bridge'; import { AirtrailAuthError, AirtrailCreds, AirtrailRequestError, listFlights } from './airtrailClient'; diff --git a/server/src/services/journeyService.ts b/server/src/services/journeyService.ts index 23428b607..c845c37fd 100644 --- a/server/src/services/journeyService.ts +++ b/server/src/services/journeyService.ts @@ -1,5 +1,5 @@ import { db, canAccessTrip } from '../db/database'; -import { avatarUrl } from './avatarUrl'; +import { avatarUrl } from '../nest/common/avatarUrl'; import type { Journey, JourneyEntry, JourneyPhoto, JourneyContributor } from '../types'; import { broadcastToUser } from '../websocket'; import { diff --git a/server/src/services/llmConfig.ts b/server/src/services/llmConfig.ts index a34960bb0..6cb290b50 100644 --- a/server/src/services/llmConfig.ts +++ b/server/src/services/llmConfig.ts @@ -1,4 +1,4 @@ -import { maybe_encrypt_api_key, decrypt_api_key } from './apiKeyCrypto'; +import { maybe_encrypt_api_key, decrypt_api_key } from '../nest/common/crypto/apiKeyCrypto'; /** * Shared types + helpers for the `llm_parsing` addon configuration. diff --git a/server/src/services/memories/helpersService.ts b/server/src/services/memories/helpersService.ts index 7a8a16a62..6ce0dd412 100644 --- a/server/src/services/memories/helpersService.ts +++ b/server/src/services/memories/helpersService.ts @@ -3,7 +3,7 @@ import { Readable } from 'node:stream'; import { Response } from 'express'; import { canAccessTrip, db } from "../../db/database"; import { safeFetch, SsrfBlockedError, type SafeFetchOptions } from '../../utils/ssrfGuard'; -import { decrypt_api_key } from '../apiKeyCrypto'; +import { decrypt_api_key } from '../../nest/common/crypto/apiKeyCrypto'; // helpers for handling return types diff --git a/server/src/services/memories/immichService.ts b/server/src/services/memories/immichService.ts index 9e797e1b0..717d3c830 100644 --- a/server/src/services/memories/immichService.ts +++ b/server/src/services/memories/immichService.ts @@ -1,6 +1,6 @@ import { Response } from 'express'; import { db } from '../../db/database'; -import { maybe_encrypt_api_key, decrypt_api_key } from '../apiKeyCrypto'; +import { maybe_encrypt_api_key, decrypt_api_key } from '../../nest/common/crypto/apiKeyCrypto'; import { checkSsrf, safeFetch } from '../../utils/ssrfGuard'; import { writeAudit } from '../../nest/audit/audit.bridge'; import { addTripPhotos} from './unifiedService'; diff --git a/server/src/services/memories/photoResolverService.ts b/server/src/services/memories/photoResolverService.ts index 6d5c8222c..05750cdfa 100644 --- a/server/src/services/memories/photoResolverService.ts +++ b/server/src/services/memories/photoResolverService.ts @@ -7,7 +7,7 @@ import { streamImmichAsset, fetchImmichThumbnailBytes, getAssetInfo as getImmich import { streamSynologyAsset, fetchSynologyThumbnailBytes, getSynologyAssetInfo } from './synologyService'; import type { ServiceResult, AssetInfo } from './helpersService'; import { fail, success } from './helpersService'; -import { encrypt_api_key, decrypt_api_key } from '../apiKeyCrypto'; +import { encrypt_api_key, decrypt_api_key } from '../../nest/common/crypto/apiKeyCrypto'; import * as photoCache from './trekPhotoCache'; import { ensureLocalThumbnail } from './thumbnailService'; diff --git a/server/src/services/memories/synologyService.ts b/server/src/services/memories/synologyService.ts index f0972ee5c..39dbf1636 100644 --- a/server/src/services/memories/synologyService.ts +++ b/server/src/services/memories/synologyService.ts @@ -1,7 +1,7 @@ import { Response } from 'express'; import { db } from '../../db/database'; -import { decrypt_api_key, encrypt_api_key, maybe_encrypt_api_key } from '../apiKeyCrypto'; +import { decrypt_api_key, encrypt_api_key, maybe_encrypt_api_key } from '../../nest/common/crypto/apiKeyCrypto'; import { safeFetch, SsrfBlockedError, checkSsrf } from '../../utils/ssrfGuard'; import { addTripPhotos } from './unifiedService'; import { diff --git a/server/src/services/memories/unifiedService.ts b/server/src/services/memories/unifiedService.ts index 821223288..668ed1a0e 100644 --- a/server/src/services/memories/unifiedService.ts +++ b/server/src/services/memories/unifiedService.ts @@ -9,7 +9,7 @@ import { Selection, } from './helpersService'; import { getOrCreateTrekPhoto, deleteTrekPhotoIfOrphan } from './photoResolverService'; -import { encrypt_api_key } from '../apiKeyCrypto'; +import { encrypt_api_key } from '../../nest/common/crypto/apiKeyCrypto'; function _providers(): Array<{id: string; enabled: boolean}> { diff --git a/server/src/services/notifications.ts b/server/src/services/notifications.ts index d31dc5313..e0eb63fc8 100644 --- a/server/src/services/notifications.ts +++ b/server/src/services/notifications.ts @@ -1,7 +1,7 @@ import { getAppUrl, readEnv } from '../app-config'; import { db } from '../db/database'; import { checkSsrf, createPinnedDispatcher } from '../utils/ssrfGuard'; -import { decrypt_api_key } from './apiKeyCrypto'; +import { decrypt_api_key } from '../nest/common/crypto/apiKeyCrypto'; import { logInfo, logDebug, logError } from '../nest/audit/audit-log.logger'; // ── Types ────────────────────────────────────────────────────────────────── diff --git a/server/src/services/unsplashService.ts b/server/src/services/unsplashService.ts index d1062b0a7..c5b2ae31c 100644 --- a/server/src/services/unsplashService.ts +++ b/server/src/services/unsplashService.ts @@ -4,7 +4,7 @@ import { v4 as uuidv4 } from 'uuid'; import { readEnv } from '../app-config'; import { safeFetch } from '../utils/ssrfGuard'; import { db } from '../db/database'; -import { decrypt_api_key } from './apiKeyCrypto'; +import { decrypt_api_key } from '../nest/common/crypto/apiKeyCrypto'; interface UnsplashSearchResponse { results?: { diff --git a/server/tests/e2e/files.e2e.test.ts b/server/tests/e2e/files.e2e.test.ts index 7690e20f1..f323012ab 100644 --- a/server/tests/e2e/files.e2e.test.ts +++ b/server/tests/e2e/files.e2e.test.ts @@ -45,7 +45,7 @@ vi.mock('../../src/db/database', () => ({ db, canAccessTrip, isOwner: vi.fn(() => true), getPlaceWithTags: vi.fn(), closeDb: () => {}, reinitialize: () => {}, })); vi.mock('../../src/websocket', () => ({ broadcast: vi.fn() })); -vi.mock('../../src/services/demo', () => ({ isDemoEmail: vi.fn(() => false) })); +vi.mock('../../src/nest/common/demo', () => ({ isDemoEmail: vi.fn(() => false) })); import { PermissionsService } from '../../src/nest/permissions/permissions.service'; diff --git a/server/tests/e2e/trips.e2e.test.ts b/server/tests/e2e/trips.e2e.test.ts index 8fccce0a1..6e435161a 100644 --- a/server/tests/e2e/trips.e2e.test.ts +++ b/server/tests/e2e/trips.e2e.test.ts @@ -108,7 +108,7 @@ vi.mock('../../src/nest/notifications/notifications.bridge', () => ({ send: vi.f // The audit domain is DI-native now: writeAudit runs for real against the temp // db's audit_log table; only the file logger is silenced. vi.mock('../../src/nest/audit/audit-log.logger', () => ({ LOG_LEVEL: 'error', logInfo: vi.fn(), logDebug: vi.fn(), logError: vi.fn(), logWarn: vi.fn() })); -vi.mock('../../src/services/demo', () => ({ isDemoEmail: vi.fn(() => false) })); +vi.mock('../../src/nest/common/demo', () => ({ isDemoEmail: vi.fn(() => false) })); import { PermissionsService } from '../../src/nest/permissions/permissions.service'; diff --git a/server/tests/helpers/factories.ts b/server/tests/helpers/factories.ts index 7acb2c521..a2f3704f8 100644 --- a/server/tests/helpers/factories.ts +++ b/server/tests/helpers/factories.ts @@ -6,8 +6,8 @@ import Database from 'better-sqlite3'; import bcrypt from 'bcryptjs'; -import { encryptMfaSecret } from '../../src/services/mfaCrypto'; -import { encrypt_api_key } from '../../src/services/apiKeyCrypto'; +import { encryptMfaSecret } from '../../src/nest/common/crypto/mfaCrypto'; +import { encrypt_api_key } from '../../src/nest/common/crypto/apiKeyCrypto'; let _userSeq = 0; let _tripSeq = 0; diff --git a/server/tests/integration/memories-synology.test.ts b/server/tests/integration/memories-synology.test.ts index cff8e932d..befa14368 100644 --- a/server/tests/integration/memories-synology.test.ts +++ b/server/tests/integration/memories-synology.test.ts @@ -704,7 +704,7 @@ describe('Synology auth checks', () => { // ── Album sync ──────────────────────────────────────────────────────────────── import { addAlbumLink } from '../helpers/factories'; -import { encrypt_api_key } from '../../src/services/apiKeyCrypto'; +import { encrypt_api_key } from '../../src/nest/common/crypto/apiKeyCrypto'; describe('Synology syncSynologyAlbumLink', () => { it('SYNO-050 — POST sync happy path: trip owner with album link saves photos to DB', async () => { @@ -1187,7 +1187,7 @@ describe('Synology SSRF blocked error handling', () => { // ── Passphrase persistence fixes ───────────────────────────────────────────── import { getOrCreateTrekPhoto, deleteTrekPhotoIfOrphan } from '../../src/services/memories/photoResolverService'; -import { decrypt_api_key } from '../../src/services/apiKeyCrypto'; +import { decrypt_api_key } from '../../src/nest/common/crypto/apiKeyCrypto'; describe('trek_photos passphrase healing (SYNO-090)', () => { it('SYNO-090 — getOrCreateTrekPhoto overwrites an existing bad passphrase when a new one is supplied', () => { diff --git a/server/tests/unit/nest/admin.service.test.ts b/server/tests/unit/nest/admin.service.test.ts index f295bb5b8..03731278f 100644 --- a/server/tests/unit/nest/admin.service.test.ts +++ b/server/tests/unit/nest/admin.service.test.ts @@ -35,7 +35,7 @@ vi.mock('../../../src/config', () => ({ ENCRYPTION_KEY: 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2', updateJwtSecret: () => {}, })); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ encrypt_api_key: (v: string) => v, decrypt_api_key: (v: string) => v, maybe_encrypt_api_key: (v: string) => v, diff --git a/server/tests/unit/nest/auth-guard.test.ts b/server/tests/unit/nest/auth-guard.test.ts index 372971cb8..646b2f665 100644 --- a/server/tests/unit/nest/auth-guard.test.ts +++ b/server/tests/unit/nest/auth-guard.test.ts @@ -3,7 +3,7 @@ import { HttpException } from '@nestjs/common'; import type { Request } from 'express'; vi.mock('../../../src/middleware/auth', () => ({ extractToken: vi.fn(), verifyJwtAndLoadUser: vi.fn() })); -vi.mock('../../../src/services/cookie', () => ({ setAuthCookie: vi.fn() })); +vi.mock('../../../src/nest/common/cookie', () => ({ setAuthCookie: vi.fn() })); vi.mock('../../../src/nest/audit/client-ip', () => ({ getClientIp: vi.fn(() => '1.2.3.4') })); vi.mock('../../../src/nest/audit/audit-log.logger', () => ({ LOG_LEVEL: 'error', logInfo: vi.fn(), logDebug: vi.fn(), logError: vi.fn(), logWarn: vi.fn() })); @@ -35,7 +35,7 @@ import { CurrentUser } from '../../../src/nest/auth/current-user.decorator'; import { extractToken, verifyJwtAndLoadUser } from '../../../src/middleware/auth'; import type { AuthService } from '../../../src/nest/auth/auth.service'; import type { PasskeyService } from '../../../src/nest/auth/passkey.service'; -import { setAuthCookie } from '../../../src/services/cookie'; +import { setAuthCookie } from '../../../src/nest/common/cookie'; import type { AuditService } from '../../../src/nest/audit/audit.service'; import type { User } from '../../../src/types'; diff --git a/server/tests/unit/nest/auth.controller.test.ts b/server/tests/unit/nest/auth.controller.test.ts index 467922802..a78817865 100644 --- a/server/tests/unit/nest/auth.controller.test.ts +++ b/server/tests/unit/nest/auth.controller.test.ts @@ -4,14 +4,14 @@ import type { Request, Response } from 'express'; vi.mock('../../../src/nest/audit/client-ip', () => ({ getClientIp: vi.fn(() => '1.2.3.4') })); vi.mock('../../../src/nest/audit/audit-log.logger', () => ({ LOG_LEVEL: 'error', logInfo: vi.fn(), logDebug: vi.fn(), logError: vi.fn(), logWarn: vi.fn() })); -vi.mock('../../../src/services/demo', () => ({ isDemoEmail: vi.fn(() => false) })); +vi.mock('../../../src/nest/common/demo', () => ({ isDemoEmail: vi.fn(() => false) })); import { AuthPublicController } from '../../../src/nest/auth/auth-public.controller'; import { AuthController } from '../../../src/nest/auth/auth.controller'; import { RateLimitService } from '../../../src/nest/common/rate-limit.service'; import type { AuthService } from '../../../src/nest/auth/auth.service'; import type { AuditService } from '../../../src/nest/audit/audit.service'; -import { isDemoEmail } from '../../../src/services/demo'; +import { isDemoEmail } from '../../../src/nest/common/demo'; import type { User } from '../../../src/types'; const user = { id: 1, username: 'u', role: 'user', email: 'u@example.test' } as User; diff --git a/server/tests/unit/nest/auth.helpers.test.ts b/server/tests/unit/nest/auth.helpers.test.ts index 6f9aeecbc..3ca74b2e2 100644 --- a/server/tests/unit/nest/auth.helpers.test.ts +++ b/server/tests/unit/nest/auth.helpers.test.ts @@ -10,7 +10,7 @@ import { describe, it, expect, vi } from 'vitest'; vi.mock('../../../src/config', () => ({ JWT_SECRET: 'test-secret', ENCRYPTION_KEY: '0'.repeat(64) })); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ decrypt_api_key: vi.fn((v) => v), maybe_encrypt_api_key: vi.fn((v) => v), encrypt_api_key: vi.fn((v) => v), @@ -25,7 +25,7 @@ import { generateBackupCodes, parseBackupCodeHashes, } from '../../../src/nest/auth/auth.helpers'; -import { avatarUrl } from '../../../src/services/avatarUrl'; +import { avatarUrl } from '../../../src/nest/common/avatarUrl'; import type { User } from '../../../src/types'; // ── utcSuffix ──────────────────────────────────────────────────────────────── diff --git a/server/tests/unit/nest/auth.service.test.ts b/server/tests/unit/nest/auth.service.test.ts index 2ade03f20..1f9a4dd63 100644 --- a/server/tests/unit/nest/auth.service.test.ts +++ b/server/tests/unit/nest/auth.service.test.ts @@ -43,11 +43,11 @@ vi.mock('../../../src/config', () => ({ SESSION_DURATION_REMEMBER_SECONDS: 2592000, updateJwtSecret: () => {}, })); -vi.mock('../../../src/services/mfaCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/mfaCrypto', () => ({ encryptMfaSecret: vi.fn((s) => `enc:${s}`), decryptMfaSecret: vi.fn((s: string) => s.replace('enc:', '')), })); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ decrypt_api_key: vi.fn((v) => v), maybe_encrypt_api_key: vi.fn((v) => v), mask_stored_api_key: vi.fn((v: string | null | undefined) => (v ? '••••••••' : null)), diff --git a/server/tests/unit/nest/collab.service.test.ts b/server/tests/unit/nest/collab.service.test.ts index e1e225994..85b0f2f6d 100644 --- a/server/tests/unit/nest/collab.service.test.ts +++ b/server/tests/unit/nest/collab.service.test.ts @@ -57,7 +57,7 @@ import { createTables } from '../../../src/db/schema'; import { runMigrations } from '../../../src/db/migrations'; import { resetTestDb } from '../../helpers/test-db'; import { createUser, createTrip } from '../../helpers/factories'; -import { avatarUrl } from '../../../src/services/avatarUrl'; +import { avatarUrl } from '../../../src/nest/common/avatarUrl'; import { DatabaseService } from '../../../src/nest/database/database.service'; import { PermissionsService } from '../../../src/nest/permissions/permissions.service'; import { CollabService } from '../../../src/nest/collab/collab.service'; diff --git a/server/tests/unit/nest/files.controller.test.ts b/server/tests/unit/nest/files.controller.test.ts index ffdc15cb2..32009764c 100644 --- a/server/tests/unit/nest/files.controller.test.ts +++ b/server/tests/unit/nest/files.controller.test.ts @@ -5,14 +5,14 @@ import os from 'os'; import path from 'path'; import fs from 'fs'; -vi.mock('../../../src/services/demo', () => ({ isDemoEmail: vi.fn(() => false) })); +vi.mock('../../../src/nest/common/demo', () => ({ isDemoEmail: vi.fn(() => false) })); import { FilesController } from '../../../src/nest/files/files.controller'; import { FilesDownloadController } from '../../../src/nest/files/files-download.controller'; import { PhotosController } from '../../../src/nest/photos/photos.controller'; import type { FilesService } from '../../../src/nest/files/files.service'; import type { PhotosService } from '../../../src/nest/photos/photos.service'; -import { isDemoEmail } from '../../../src/services/demo'; +import { isDemoEmail } from '../../../src/nest/common/demo'; import type { User } from '../../../src/types'; const user = { id: 1, username: 'u', role: 'user', email: 'u@example.test' } as User; diff --git a/server/tests/unit/nest/maps.service.test.ts b/server/tests/unit/nest/maps.service.test.ts index d9b55f9b9..266098f8c 100644 --- a/server/tests/unit/nest/maps.service.test.ts +++ b/server/tests/unit/nest/maps.service.test.ts @@ -79,7 +79,7 @@ vi.mock('../../../src/utils/ssrfGuard', () => { }; }); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ decrypt_api_key: (v: string | null) => v, })); diff --git a/server/tests/unit/nest/notifications.service.test.ts b/server/tests/unit/nest/notifications.service.test.ts index a19e57f19..fc455ba93 100644 --- a/server/tests/unit/nest/notifications.service.test.ts +++ b/server/tests/unit/nest/notifications.service.test.ts @@ -31,7 +31,7 @@ vi.mock('../../../src/config', () => ({ ENCRYPTION_KEY: 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2', updateJwtSecret: () => {}, })); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ decrypt_api_key: (v: string | null) => v, maybe_encrypt_api_key: (v: string) => v, encrypt_api_key: (v: string) => v, diff --git a/server/tests/unit/nest/oidc.service.test.ts b/server/tests/unit/nest/oidc.service.test.ts index ca723e8e1..0da50481d 100644 --- a/server/tests/unit/nest/oidc.service.test.ts +++ b/server/tests/unit/nest/oidc.service.test.ts @@ -51,11 +51,11 @@ vi.mock('../../../src/config', () => ({ // as auth.service.test.ts) — services/tripMembership is deliberately NOT // mocked: OIDC-SVC-045 asserts the real trip_members row a trip-bound invite // creates. -vi.mock('../../../src/services/mfaCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/mfaCrypto', () => ({ encryptMfaSecret: vi.fn((s) => `enc:${s}`), decryptMfaSecret: vi.fn((s: string) => s.replace('enc:', '')), })); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ decrypt_api_key: vi.fn((v) => v), maybe_encrypt_api_key: vi.fn((v) => v), mask_stored_api_key: vi.fn((v: string | null | undefined) => (v ? '••••••••' : null)), @@ -78,8 +78,8 @@ vi.mock('../../../src/app-config', async (importOriginal) => { }); const { setAuthCookieMock } = vi.hoisted(() => ({ setAuthCookieMock: vi.fn() })); -vi.mock('../../../src/services/cookie', async (importOriginal) => { - const actual = await importOriginal(); +vi.mock('../../../src/nest/common/cookie', async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, setAuthCookie: setAuthCookieMock }; }); diff --git a/server/tests/unit/nest/passkey.service.test.ts b/server/tests/unit/nest/passkey.service.test.ts index 20000ccea..8630480b1 100644 --- a/server/tests/unit/nest/passkey.service.test.ts +++ b/server/tests/unit/nest/passkey.service.test.ts @@ -43,11 +43,11 @@ vi.mock('../../../src/config', () => ({ // Construction insurance for the injected AuthService's import graph (same set // as oidc.service.test.ts / auth.service.test.ts). -vi.mock('../../../src/services/mfaCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/mfaCrypto', () => ({ encryptMfaSecret: vi.fn((s) => `enc:${s}`), decryptMfaSecret: vi.fn((s: string) => s.replace('enc:', '')), })); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ decrypt_api_key: vi.fn((v) => v), maybe_encrypt_api_key: vi.fn((v) => v), mask_stored_api_key: vi.fn((v: string | null | undefined) => (v ? '••••••••' : null)), diff --git a/server/tests/unit/nest/settings.service.test.ts b/server/tests/unit/nest/settings.service.test.ts index e01280c52..efc704c16 100644 --- a/server/tests/unit/nest/settings.service.test.ts +++ b/server/tests/unit/nest/settings.service.test.ts @@ -35,7 +35,7 @@ vi.mock('../../../src/config', () => ({ })); // Passthrough crypto — value comes back unchanged for most tests -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ maybe_encrypt_api_key: (v: string) => v, decrypt_api_key: (v: string) => v, })); diff --git a/server/tests/unit/nest/trips.controller.test.ts b/server/tests/unit/nest/trips.controller.test.ts index 63fa47824..916159dc0 100644 --- a/server/tests/unit/nest/trips.controller.test.ts +++ b/server/tests/unit/nest/trips.controller.test.ts @@ -5,7 +5,7 @@ import type { Request } from 'express'; vi.mock('../../../src/nest/audit/client-ip', () => ({ getClientIp: vi.fn(() => '1.2.3.4') })); vi.mock('../../../src/nest/audit/audit-log.logger', () => ({ LOG_LEVEL: 'error', logInfo: vi.fn(), logDebug: vi.fn(), logError: vi.fn(), logWarn: vi.fn() })); const { isDemoEmail } = vi.hoisted(() => ({ isDemoEmail: vi.fn(() => false) })); -vi.mock('../../../src/services/demo', () => ({ isDemoEmail })); +vi.mock('../../../src/nest/common/demo', () => ({ isDemoEmail })); // Mock the Unsplash cover internalisation so the controller test never hits the // network; isUnsplashCoverUrl keeps its real (host-based) logic. vi.mock('../../../src/services/unsplashService', () => ({ diff --git a/server/tests/unit/plugins/plugin-host-deps.factory.test.ts b/server/tests/unit/plugins/plugin-host-deps.factory.test.ts index 64f3db383..bd1e794a6 100644 --- a/server/tests/unit/plugins/plugin-host-deps.factory.test.ts +++ b/server/tests/unit/plugins/plugin-host-deps.factory.test.ts @@ -148,7 +148,7 @@ const packingStub = { deleteBag: vi.fn((_tid: number | string, bagId: string) => Number(bagId) !== 404), setBagMembers: vi.fn((_tid: number | string, bagId: string, userIds: number[]) => (Number(bagId) === 404 ? null : userIds.map((u) => ({ user_id: u })))), } as unknown as PackingService; -vi.mock('../../../src/services/conflictResult', () => ({ isUpdateConflict: (r: unknown) => !!(r as { conflict?: boolean })?.conflict })); +vi.mock('../../../src/nest/common/conflictResult', () => ({ isUpdateConflict: (r: unknown) => !!(r as { conflict?: boolean })?.conflict })); vi.mock('../../../src/services/weatherService', () => ({ getWeather: vi.fn(async (lat: string, lng: string) => ({ lat, lng, temp: 20 })) })); const categoriesStub = { list: vi.fn(() => [{ id: 1, name: 'Food' }]) } as unknown as CategoriesService; const tagsStub = { diff --git a/server/tests/unit/plugins/plugin-oauth.service.test.ts b/server/tests/unit/plugins/plugin-oauth.service.test.ts index 267d00401..d7f814459 100644 --- a/server/tests/unit/plugins/plugin-oauth.service.test.ts +++ b/server/tests/unit/plugins/plugin-oauth.service.test.ts @@ -6,7 +6,7 @@ */ import { describe, it, expect, beforeEach, vi } from 'vitest'; -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ encrypt_api_key: (v: unknown) => (typeof v === 'string' ? `enc:${v}` : v), decrypt_api_key: (v: unknown) => (typeof v === 'string' && v.startsWith('enc:') ? v.slice(4) : v), })); diff --git a/server/tests/unit/plugins/plugin-user-settings.test.ts b/server/tests/unit/plugins/plugin-user-settings.test.ts index 8d1920e9a..e1e43732c 100644 --- a/server/tests/unit/plugins/plugin-user-settings.test.ts +++ b/server/tests/unit/plugins/plugin-user-settings.test.ts @@ -8,7 +8,7 @@ import { describe, it, expect, beforeEach, vi } from 'vitest'; // Reversible crypto stub so we can assert encrypt-at-rest without a real key env. -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ maybe_encrypt_api_key: (v: unknown) => (typeof v === 'string' ? `enc:${v}` : v), decrypt_api_key: (v: unknown) => (typeof v === 'string' && v.startsWith('enc:') ? v.slice(4) : v), })); diff --git a/server/tests/unit/services/apiKeyCrypto.test.ts b/server/tests/unit/services/apiKeyCrypto.test.ts index 40357ee58..8434ffb57 100644 --- a/server/tests/unit/services/apiKeyCrypto.test.ts +++ b/server/tests/unit/services/apiKeyCrypto.test.ts @@ -7,7 +7,7 @@ vi.mock('../../../src/config', () => ({ updateJwtSecret: () => {}, })); -import { encrypt_api_key, decrypt_api_key, maybe_encrypt_api_key } from '../../../src/services/apiKeyCrypto'; +import { encrypt_api_key, decrypt_api_key, maybe_encrypt_api_key } from '../../../src/nest/common/crypto/apiKeyCrypto'; describe('apiKeyCrypto', () => { const PLAINTEXT_KEY = 'my-secret-api-key-12345'; diff --git a/server/tests/unit/services/avatarUrl.test.ts b/server/tests/unit/services/avatarUrl.test.ts index 5a4e1c21f..bdc9b46c6 100644 --- a/server/tests/unit/services/avatarUrl.test.ts +++ b/server/tests/unit/services/avatarUrl.test.ts @@ -4,7 +4,7 @@ * an OIDC `picture` claim (#1399); the helper resolves both to a renderable src. */ import { describe, it, expect } from 'vitest'; -import { avatarUrl } from '../../../src/services/avatarUrl'; +import { avatarUrl } from '../../../src/nest/common/avatarUrl'; describe('avatarUrl', () => { it('AVATAR-URL-001: prefixes an uploaded file name with the avatars path', () => { diff --git a/server/tests/unit/services/channelOverride.test.ts b/server/tests/unit/services/channelOverride.test.ts index ba5896be3..71092dbf8 100644 --- a/server/tests/unit/services/channelOverride.test.ts +++ b/server/tests/unit/services/channelOverride.test.ts @@ -16,7 +16,7 @@ const { testDb, dbMock } = vi.hoisted(() => { }); vi.mock('../../../src/db/database', () => dbMock); vi.mock('../../../src/config', () => ({ JWT_SECRET: 'x'.repeat(40), ENCRYPTION_KEY: 'a'.repeat(64), updateJwtSecret: () => {} })); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ decrypt_api_key: (v: string) => v, maybe_encrypt_api_key: (v: string) => v, encrypt_api_key: (v: string) => v })); +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ decrypt_api_key: (v: string) => v, maybe_encrypt_api_key: (v: string) => v, encrypt_api_key: (v: string) => v })); const { sendMailMock } = vi.hoisted(() => ({ sendMailMock: vi.fn().mockResolvedValue({ accepted: ['a@b.c'] }) })); vi.mock('nodemailer', () => ({ default: { createTransport: vi.fn(() => ({ sendMail: sendMailMock, verify: vi.fn() })) } })); vi.stubGlobal('fetch', vi.fn()); diff --git a/server/tests/unit/services/conflictUpdate.test.ts b/server/tests/unit/services/conflictUpdate.test.ts index a7ad359f8..3e3bcd93b 100644 --- a/server/tests/unit/services/conflictUpdate.test.ts +++ b/server/tests/unit/services/conflictUpdate.test.ts @@ -38,7 +38,7 @@ import { createTables } from '../../../src/db/schema'; import { runMigrations } from '../../../src/db/migrations'; import { resetTestDb } from '../../helpers/test-db'; import { createUser, createTrip } from '../../helpers/factories'; -import { isUpdateConflict } from '../../../src/services/conflictResult'; +import { isUpdateConflict } from '../../../src/nest/common/conflictResult'; import { DatabaseService } from '../../../src/nest/database/database.service'; import { PackingService } from '../../../src/nest/packing/packing.service'; import { PlacesService } from '../../../src/nest/places/places.service'; diff --git a/server/tests/unit/services/cookie.test.ts b/server/tests/unit/services/cookie.test.ts index 97823f718..494f111c7 100644 --- a/server/tests/unit/services/cookie.test.ts +++ b/server/tests/unit/services/cookie.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { cookieOptions } from '../../../src/services/cookie'; +import { cookieOptions } from '../../../src/nest/common/cookie'; import { SESSION_DURATION_MS, SESSION_DURATION_REMEMBER_MS } from '../../../src/config'; describe('cookieOptions', () => { diff --git a/server/tests/unit/services/mfaCrypto.test.ts b/server/tests/unit/services/mfaCrypto.test.ts index 03b5c4266..a19dedc8b 100644 --- a/server/tests/unit/services/mfaCrypto.test.ts +++ b/server/tests/unit/services/mfaCrypto.test.ts @@ -7,7 +7,7 @@ vi.mock('../../../src/config', () => ({ updateJwtSecret: () => {}, })); -import { encryptMfaSecret, decryptMfaSecret } from '../../../src/services/mfaCrypto'; +import { encryptMfaSecret, decryptMfaSecret } from '../../../src/nest/common/crypto/mfaCrypto'; describe('mfaCrypto', () => { const TOTP_SECRET = 'JBSWY3DPEHPK3PXP'; // typical base32 TOTP secret diff --git a/server/tests/unit/services/notificationPreferencesService.test.ts b/server/tests/unit/services/notificationPreferencesService.test.ts index ae8a058de..51d591b45 100644 --- a/server/tests/unit/services/notificationPreferencesService.test.ts +++ b/server/tests/unit/services/notificationPreferencesService.test.ts @@ -26,7 +26,7 @@ vi.mock('../../../src/config', () => ({ ENCRYPTION_KEY: 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2', updateJwtSecret: () => {}, })); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ decrypt_api_key: (v: string | null) => v, maybe_encrypt_api_key: (v: string) => v, encrypt_api_key: (v: string) => v, diff --git a/server/tests/unit/services/notifications.test.ts b/server/tests/unit/services/notifications.test.ts index c115b7a91..716597c5d 100644 --- a/server/tests/unit/services/notifications.test.ts +++ b/server/tests/unit/services/notifications.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi, afterEach, afterAll, beforeEach } from 'vites vi.mock('../../../src/db/database', () => ({ db: { prepare: () => ({ get: vi.fn(() => undefined), all: vi.fn(() => []) }) }, })); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ decrypt_api_key: vi.fn((v) => v), maybe_encrypt_api_key: vi.fn((v) => v), })); diff --git a/server/tests/unit/services/oauthService.test.ts b/server/tests/unit/services/oauthService.test.ts index 7020cd62f..0b97c9759 100644 --- a/server/tests/unit/services/oauthService.test.ts +++ b/server/tests/unit/services/oauthService.test.ts @@ -29,7 +29,7 @@ vi.mock('../../../src/config', () => ({ ENCRYPTION_KEY: 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2', updateJwtSecret: () => {}, })); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ encrypt_api_key: (v: string) => v, decrypt_api_key: (v: string) => v, maybe_encrypt_api_key: (v: string) => v, diff --git a/server/tests/unit/services/passwordPolicy.test.ts b/server/tests/unit/services/passwordPolicy.test.ts index 65b5471a1..6f5eff3f7 100644 --- a/server/tests/unit/services/passwordPolicy.test.ts +++ b/server/tests/unit/services/passwordPolicy.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest'; -import { validatePassword } from '../../../src/services/passwordPolicy'; +import { validatePassword } from '../../../src/nest/common/passwordPolicy'; describe('validatePassword', () => { // AUTH-006 — Registration with weak password diff --git a/server/tests/unit/services/timezoneService.test.ts b/server/tests/unit/services/timezoneService.test.ts index fff57e6a1..29a31ef19 100644 --- a/server/tests/unit/services/timezoneService.test.ts +++ b/server/tests/unit/services/timezoneService.test.ts @@ -1,4 +1,4 @@ -import { localParts, resolveTimeZone } from '../../../src/services/timezoneService'; +import { localParts, resolveTimeZone } from '../../../src/nest/common/timezoneService'; import { describe, expect, it } from 'vitest'; diff --git a/server/tests/unit/services/unsplashService.test.ts b/server/tests/unit/services/unsplashService.test.ts index bf4c90879..ab734187b 100644 --- a/server/tests/unit/services/unsplashService.test.ts +++ b/server/tests/unit/services/unsplashService.test.ts @@ -11,7 +11,7 @@ vi.mock('../../../src/utils/ssrfGuard', () => ({ safeFetch })); vi.mock('../../../src/db/database', () => ({ db: { prepare: () => ({ get: mockDbGet, all: vi.fn(() => []), run: vi.fn() }) }, })); -vi.mock('../../../src/services/apiKeyCrypto', () => ({ decrypt_api_key: (v: string | null) => v })); +vi.mock('../../../src/nest/common/crypto/apiKeyCrypto', () => ({ decrypt_api_key: (v: string | null) => v })); import { searchUnsplashPhotos, getUnsplashKey, saveUnsplashCover, isUnsplashCoverUrl } from '../../../src/services/unsplashService';