From 3fdae4704176764866cfb083e0c6ba812ae29847 Mon Sep 17 00:00:00 2001 From: Maurice Date: Sat, 10 Oct 2026 21:52:09 +0200 Subject: [PATCH] chore: drop the exports the reworked server modules left without an importer knip found them once the server lanes and the client ratchets met: re-exports and helpers that moved into place-import, nest-rpc and auth-core but kept an export nothing reads, the demo-denied helper the central MCP gate replaced, and two settings keys only the selector uses. @OptionalAuth stays exported as the documented opt-out and is marked @public. The baselines for knip and the unused en keys drop to the merged tree. --- client/scripts/i18n-unused-baseline.json | 3 --- knip.jsonc | 6 ++++-- scripts/ci/knip-baseline.json | 15 ++------------- scripts/lib/eslint-warnings.mjs | 2 +- scripts/lib/format.mjs | 2 +- server/src/mcp/tools/_shared.ts | 1 - server/src/nest-mcp/index.ts | 3 --- server/src/nest-mcp/types.ts | 2 +- server/src/nest-rpc/rpc-kit/types.ts | 4 +--- server/src/nest/auth-core/public.decorator.ts | 1 + server/src/nest/maps/maps.service.ts | 2 +- server/src/nest/maps/places-provider.selector.ts | 4 ++-- .../src/nest/permissions/permissions.service.ts | 2 +- server/src/nest/place-import/gpx.codec.ts | 2 +- server/src/nest/place-import/kml.codec.ts | 8 +++----- .../src/nest/place-import/place-import.service.ts | 2 +- .../nest/place-import/providers/gpx.provider.ts | 2 +- server/src/nest/places/places.helpers.ts | 8 +------- server/src/nest/plugins/mcp-tool-schema.ts | 4 ++-- .../eslint-rules/restricted-imports-xml.test.ts | 5 ++--- 20 files changed, 26 insertions(+), 52 deletions(-) diff --git a/client/scripts/i18n-unused-baseline.json b/client/scripts/i18n-unused-baseline.json index 5e9965342..cdcb629d9 100644 --- a/client/scripts/i18n-unused-baseline.json +++ b/client/scripts/i18n-unused-baseline.json @@ -26,16 +26,13 @@ "packing.ts": 6, "pdf.ts": 1, "perm.ts": 4, - "photos.ts": 22, "places.ts": 10, "planner.ts": 53, - "register.ts": 20, "reservations.ts": 21, "roadtrip.ts": 38, "settings.ts": 40, "share.ts": 7, "shared.ts": 2, - "stats.ts": 8, "storage.ts": 16, "system_notice.ts": 32, "todo.ts": 4, diff --git a/knip.jsonc b/knip.jsonc index c79a82181..a54be7a67 100644 --- a/knip.jsonc +++ b/knip.jsonc @@ -15,8 +15,10 @@ "entry": ["scripts/ci/*.mjs", "scripts/*.{cjs,mts}"], "project": ["scripts/**/*.{mjs,cjs,mts}"], // An optional peer of tsdown, which loads shared/tsdown.config.ts through - // it; nothing imports it by name. - "ignoreDependencies": ["unrun"] + // it; nothing imports it by name. eslint and prettier are the workspaces' + // own copies: the shared scripts/lib takes them handed in, and its tests + // import the hoisted ones the server and shared declare. + "ignoreDependencies": ["unrun", "eslint", "prettier"] }, "client": { // The app, its scripts, the Playwright specs and the server launcher diff --git a/scripts/ci/knip-baseline.json b/scripts/ci/knip-baseline.json index a9e2ab069..a88760a49 100644 --- a/scripts/ci/knip-baseline.json +++ b/scripts/ci/knip-baseline.json @@ -1,7 +1,4 @@ { - "devDependencies": { - "server/package.json": 3 - }, "duplicates": { "client/src/api/client.ts": 1, "client/src/components/Map/VectorBasemap.tsx": 1, @@ -79,11 +76,9 @@ "server/src/mcp/nest-mcp-policy.ts": 1, "server/src/mcp/scopes.ts": 3, "server/src/mcp/tools/_shared.ts": 8, - "server/src/nest-mcp/index.ts": 1, "server/src/nest/accommodations/night-seat.ts": 1, "server/src/nest/app-config/index.ts": 6, "server/src/nest/auth/auth.helpers.ts": 1, - "server/src/nest/auth/public.decorator.ts": 1, "server/src/nest/backup/backup-archive.ts": 1, "server/src/nest/backup/backup.impl.ts": 3, "server/src/nest/budget/budget.service.ts": 1, @@ -100,7 +95,6 @@ "server/src/nest/llm-parse/image-input.ts": 2, "server/src/nest/llm-parse/llm-config.ts": 1, "server/src/nest/llm-parse/llm-prompt.ts": 1, - "server/src/nest/maps/maps.service.ts": 2, "server/src/nest/maps/providers/amap.provider.ts": 2, "server/src/nest/maps/providers/places-provider.ts": 1, "server/src/nest/notifications/channel-registry.ts": 1, @@ -109,7 +103,6 @@ "server/src/nest/oauth/oauth.helpers.ts": 1, "server/src/nest/place-enrichment/place-enrichment.service.ts": 1, "server/src/nest/place-shadow/place-shadow.service.ts": 1, - "server/src/nest/places/kml-import.helpers.ts": 1, "server/src/nest/places/places.helpers.ts": 1, "server/src/nest/plugins/contributions/plugin-search.helpers.ts": 2, "server/src/nest/plugins/host/plugin-data.service.ts": 1, @@ -121,7 +114,6 @@ "server/src/nest/route-usage/route-usage.service.ts": 1, "server/src/nest/share/share.service.ts": 1, "server/src/nest/storage/storage-stats.service.ts": 1, - "server/src/nest/transit/transit-provider.ts": 2, "shared/src/roadtrip/accessSpur.ts": 3 }, "types": { @@ -207,7 +199,7 @@ "server/src/db/repositories/UserSessions.repository.ts": 1, "server/src/db/repositories/_shared/rows.ts": 1, "server/src/mcp/nest-mcp-policy.ts": 1, - "server/src/nest-mcp/index.ts": 13, + "server/src/nest-mcp/index.ts": 12, "server/src/nest-mcp/types.ts": 4, "server/src/nest/booking-import/kitinerary.types.ts": 6, "server/src/nest/collab/collab.service.ts": 1, @@ -219,9 +211,7 @@ "server/src/nest/maps/trek-places.client.ts": 1, "server/src/nest/memories/memories.helpers.ts": 1, "server/src/nest/notifications/notifications.service.ts": 1, - "server/src/nest/places/places.helpers.ts": 1, "server/src/nest/plugins/contributions/map-layers.controller.ts": 1, - "server/src/nest/plugins/host/rpc-kit/types.ts": 2, "server/src/nest/plugins/install/manifest.ts": 7, "server/src/nest/plugins/plugins.service.ts": 1, "server/src/nest/plugins/protocol/envelope.ts": 2, @@ -233,8 +223,7 @@ "server/src/nest/vacay/vacay.service.ts": 4, "server/src/nest/weather/weather.impl.ts": 1, "server/src/shutdown.ts": 1, - "server/src/systemNotices/types.ts": 7, - "server/src/types.ts": 14 + "server/src/systemNotices/types.ts": 7 }, "unlisted": { "client/src/components/Map/MapView.tsx": 1, diff --git a/scripts/lib/eslint-warnings.mjs b/scripts/lib/eslint-warnings.mjs index ee74c89e4..a60b62970 100644 --- a/scripts/lib/eslint-warnings.mjs +++ b/scripts/lib/eslint-warnings.mjs @@ -27,7 +27,7 @@ import { * inline disable must not be the cheap way under the ratchet, and an inline * rule config, which silences without a trace, fails outright (see tally). */ -export const AREAS = ['src', 'tests', 'suppressed']; +const AREAS = ['src', 'tests', 'suppressed']; const areaOf = (key) => (key.startsWith('tests/') || TEST_FILE.test(key) ? 'tests' : 'src'); diff --git a/scripts/lib/format.mjs b/scripts/lib/format.mjs index 679c8fae9..5397aee58 100644 --- a/scripts/lib/format.mjs +++ b/scripts/lib/format.mjs @@ -38,7 +38,7 @@ export async function isFormatted(prettier, path) { } /** The files under root/ that accepts takes and Prettier would rewrite, keyed by their path from root. */ -export async function unformatted({ prettier, root, dirs, accepts }) { +async function unformatted({ prettier, root, dirs, accepts }) { const found = []; for (const path of listFiles(root, dirs, accepts)) { if (!(await isFormatted(prettier, path))) found.push(toKey(root, path)); diff --git a/server/src/mcp/tools/_shared.ts b/server/src/mcp/tools/_shared.ts index 9b6a7922f..c4f989385 100644 --- a/server/src/mcp/tools/_shared.ts +++ b/server/src/mcp/tools/_shared.ts @@ -6,7 +6,6 @@ import { errorResult } from '../../nest-mcp'; // the impure guards (hasTripPermission/isAdminUser/safeBroadcast) moved onto // the injectable McpToolGuardsService (src/nest/mcp-shared/). export { - demoDenied, errorResult, ok, TOOL_ANNOTATIONS_DELETE, diff --git a/server/src/nest-mcp/index.ts b/server/src/nest-mcp/index.ts index 284d7dce3..63a4458c5 100644 --- a/server/src/nest-mcp/index.ts +++ b/server/src/nest-mcp/index.ts @@ -16,8 +16,6 @@ export { McpModule } from './mcp.module'; export { McpRegistry, type McpRegistryOptions } from './registry'; export { createTestRegistry } from './testing'; export { - MCP_MODULE_OPTIONS, - MCP_TOOL_GATE, type McpAccess, type McpAccessGroup, type McpAccessGroupRegistry, @@ -37,7 +35,6 @@ export { type McpModuleOptions, type McpRegistryListing, type McpToolGate, - type McpToolGateProvider, type McpZodSchema, type PromptArgsShape, type PromptOptions, diff --git a/server/src/nest-mcp/types.ts b/server/src/nest-mcp/types.ts index 1e6334952..398ff41d7 100644 --- a/server/src/nest-mcp/types.ts +++ b/server/src/nest-mcp/types.ts @@ -284,7 +284,7 @@ export type McpErrorMapper = (err: unknown) => unknown; * needs, resolved from the container like any other provider. A gate that * reads the database has to come from DI, and `forRoot` options are static. */ -export interface McpToolGateProvider { +interface McpToolGateProvider { /** Modules exporting what `inject` names, unless those providers are global. */ imports?: NonNullable; inject?: InjectionToken[]; diff --git a/server/src/nest-rpc/rpc-kit/types.ts b/server/src/nest-rpc/rpc-kit/types.ts index e1734504c..00a2846a6 100644 --- a/server/src/nest-rpc/rpc-kit/types.ts +++ b/server/src/nest-rpc/rpc-kit/types.ts @@ -32,13 +32,11 @@ export interface PluginRpcContext { } /** What a plugin may do to its declared dependencies. */ -export interface PluginRpcPeers { +interface PluginRpcPeers { call(targetId: string, fn: string, args: unknown, actingUserId: number | undefined): Promise; emit(event: string, payload: unknown): Promise; } -export type PluginRpcHandler = (params: Record, ctx: PluginRpcContext) => unknown; - /** * What a decorator records. `methodName` is the name of the decorated class method, * `method` the wire name it answers to; they are deliberately independent. diff --git a/server/src/nest/auth-core/public.decorator.ts b/server/src/nest/auth-core/public.decorator.ts index cb3611c67..75f762e8a 100644 --- a/server/src/nest/auth-core/public.decorator.ts +++ b/server/src/nest/auth-core/public.decorator.ts @@ -30,4 +30,5 @@ export const Public = (reason: string) => SetMetadata(IS_PUBLIC, { reason }); * aside when there is no user, so making a route optional-auth newly enrols its * mutations in idempotency replay. */ +/** @public The documented opt-out for a route that reads a session when there is one; no route needs it today. */ export const OptionalAuth = (reason: string) => SetMetadata(OPTIONAL_AUTH, { reason }); diff --git a/server/src/nest/maps/maps.service.ts b/server/src/nest/maps/maps.service.ts index ac0f76a84..1cb37295e 100644 --- a/server/src/nest/maps/maps.service.ts +++ b/server/src/nest/maps/maps.service.ts @@ -35,7 +35,7 @@ export { readBrandIdentity, readWikiIdentity, type WikiIdentity } from './provid export { withPhotoFetchSlot } from './photo-fetch-slot'; export type { BrandLogo, CommonsCandidate } from './providers/wikimedia.client'; export { GOOGLE_SHORT_HOSTS, isGoogleMapsHost } from '../common/google-maps-hosts'; -export { PLACES_PROVIDER_SETTING, PLACES_GOOGLE_ONLY_SETTING, type KeyedProvider } from './places-provider.selector'; +export { type KeyedProvider } from './places-provider.selector'; // Places near a point (#976): cached longer than the POI boxes, because the // likely caller is an import asking the same photo location again, and Google diff --git a/server/src/nest/maps/places-provider.selector.ts b/server/src/nest/maps/places-provider.selector.ts index 54a845f40..070a4a603 100644 --- a/server/src/nest/maps/places-provider.selector.ts +++ b/server/src/nest/maps/places-provider.selector.ts @@ -31,13 +31,13 @@ import { isOutsideChina } from '@trek/shared'; * admin can say which one should answer. Absent, which is every install that * predates Amap, means `auto`, which keeps Google. */ -export const PLACES_PROVIDER_SETTING = 'places_provider'; +const PLACES_PROVIDER_SETTING = 'places_provider'; /** * The admin switch that hands search and suggestions to Google alone. Off, the * index and OpenStreetMap answer first and Google is only asked when they find * nothing, which is what every install has had since 4.3.0. */ -export const PLACES_GOOGLE_ONLY_SETTING = 'places_google_only'; +const PLACES_GOOGLE_ONLY_SETTING = 'places_google_only'; /** * Whoever holds the keyed slot beside the index for one request: Google's diff --git a/server/src/nest/permissions/permissions.service.ts b/server/src/nest/permissions/permissions.service.ts index f4ea1ec4d..bac4461ab 100644 --- a/server/src/nest/permissions/permissions.service.ts +++ b/server/src/nest/permissions/permissions.service.ts @@ -12,7 +12,7 @@ import { PERMISSION_ACTIONS, evaluatePermission, type PermissionAction, type Per // @trek/shared, so the admin screen and the client read the same table the // server enforces. Re-exported here for the server code that imported them. export { PERMISSION_ACTIONS }; -export type { PermissionAction, PermissionLevel }; +export type { PermissionLevel }; const ACTIONS_MAP = new Map(PERMISSION_ACTIONS.map((a) => [a.key, a])); diff --git a/server/src/nest/place-import/gpx.codec.ts b/server/src/nest/place-import/gpx.codec.ts index 87704e708..54933176d 100644 --- a/server/src/nest/place-import/gpx.codec.ts +++ b/server/src/nest/place-import/gpx.codec.ts @@ -56,7 +56,7 @@ export function createGpxParser(mode: GpxReadMode): XMLParser { export const gpxGeometryParser = createGpxParser('geometry'); export const gpxTextParser = createGpxParser('text'); -export const GPX_NAMESPACE = 'http://www.topografix.com/GPX/1/1'; +const GPX_NAMESPACE = 'http://www.topografix.com/GPX/1/1'; /** Coordinates are written with 7 decimals, ~11 mm, which is past what any consumer * device resolves and keeps the file from carrying float noise. */ diff --git a/server/src/nest/place-import/kml.codec.ts b/server/src/nest/place-import/kml.codec.ts index 146be85f8..74ce14eb0 100644 --- a/server/src/nest/place-import/kml.codec.ts +++ b/server/src/nest/place-import/kml.codec.ts @@ -16,7 +16,7 @@ import { XMLParser, XMLValidator } from 'fast-xml-parser'; import unzipper from 'unzipper'; import { TextDecoder } from 'util'; -export type { KmlImportSummary, ParsedKmlPlacemark } from './place-import.types'; +export type { ParsedKmlPlacemark } from './place-import.types'; export interface KmlPlacemarkNode { placemark: any; @@ -111,9 +111,7 @@ export function sanitizeKmlDescription(value: unknown): string | null { return decoded || null; } -export function parseKmlLineStringCoordinates( - value: unknown, -): Array<{ lat: number; lng: number; ele: number | null }> | null { +function parseKmlLineStringCoordinates(value: unknown): Array<{ lat: number; lng: number; ele: number | null }> | null { const coordinates = asTrimmedString(value); if (!coordinates) return null; @@ -148,7 +146,7 @@ export function parseKmlPointCoordinates(value: unknown): { lat: number; lng: nu return { lat, lng }; } -export function createKmlImportSummary(totalPlacemarks: number): KmlImportSummary { +function createKmlImportSummary(totalPlacemarks: number): KmlImportSummary { return { totalPlacemarks, createdCount: 0, diff --git a/server/src/nest/place-import/place-import.service.ts b/server/src/nest/place-import/place-import.service.ts index a5488e1aa..b821a65aa 100644 --- a/server/src/nest/place-import/place-import.service.ts +++ b/server/src/nest/place-import/place-import.service.ts @@ -20,7 +20,7 @@ import type { CollectionGpxExport, CollectionGpxReadResult } from '@trek/shared' // The directions-link reading is also what the road trip planner reads a // shared route with, and what the import routes dispatch on. -export { isDirectionsUrl, parseDirectionsUrl, MAX_DIR_WAYPOINTS, type DirWaypoint } from './directions-url.helpers'; +export { isDirectionsUrl, parseDirectionsUrl, MAX_DIR_WAYPOINTS } from './directions-url.helpers'; export type { GpxExportDay, GpxExportInput, GpxExportOptions, GpxExportPlace } from './providers/gpx.provider'; export type { ExportedCollectionFile } from './providers/collection-gpx.provider'; diff --git a/server/src/nest/place-import/providers/gpx.provider.ts b/server/src/nest/place-import/providers/gpx.provider.ts index 9e4925cdb..28b6d4c71 100644 --- a/server/src/nest/place-import/providers/gpx.provider.ts +++ b/server/src/nest/place-import/providers/gpx.provider.ts @@ -166,7 +166,7 @@ export function gpxFilename(tripTitle: string): string { * anything. Waypoints become places, each route and each track becomes one * place carrying its geometry. */ -export function prepareGpxRows(fileBuffer: Buffer, opts: GpxImportOptions = {}): PreparedGpxPlace[] { +function prepareGpxRows(fileBuffer: Buffer, opts: GpxImportOptions = {}): PreparedGpxPlace[] { const { importWaypoints = true, importRoutes = true, importTracks = true, defaultName } = opts; const parsed = gpxGeometryParser.parse(fileBuffer.toString('utf-8')); diff --git a/server/src/nest/places/places.helpers.ts b/server/src/nest/places/places.helpers.ts index 244f3fde4..f3831c157 100644 --- a/server/src/nest/places/places.helpers.ts +++ b/server/src/nest/places/places.helpers.ts @@ -18,7 +18,7 @@ import { externalIdsOf, normalizePlaceName, placeMatchStrategies, type PlaceMatc // while the values themselves live in @trek/shared with the rule that uses them. export { COORD_DEDUP_TOLERANCE, externalIdsOf } from '@trek/shared'; -export type { GpxImportOptions, KmlImportOptions, ListImportError } from '../place-import/place-import.types'; +export type { GpxImportOptions, KmlImportOptions } from '../place-import/place-import.types'; /** * Escape the LIKE metacharacters in a user-supplied search term so `%` and `_` @@ -36,12 +36,6 @@ export interface ListImportOptions { lang?: string; } -export interface PlaceWithCategory extends Place { - category_name: string | null; - category_color: string | null; - category_icon: string | null; -} - export interface PlaceImportResult { places: PlaceWithTags[]; count: number; diff --git a/server/src/nest/plugins/mcp-tool-schema.ts b/server/src/nest/plugins/mcp-tool-schema.ts index 3f4494753..b903d03d9 100644 --- a/server/src/nest/plugins/mcp-tool-schema.ts +++ b/server/src/nest/plugins/mcp-tool-schema.ts @@ -13,14 +13,14 @@ * because that is what an assistant reliably surfaces. */ import type { McpZodSchema } from '../../nest-mcp'; -import { MCP_TOOLS_MAX, TOOL_NAME_RE } from './protocol/manifest-rules'; +import { MCP_TOOLS_MAX } from './protocol/manifest-rules'; import { sanitiseAssistantText } from './text-sanitize'; import { z } from 'zod'; // The per-plugin cap and the tool-name pattern are manifest rules: they live in // protocol/manifest-rules.ts, which gen-plugin-facts writes into the SDK. -export { MCP_TOOLS_MAX, TOOL_NAME_RE }; +export { MCP_TOOLS_MAX }; /** * Tools all plugins together may advertise. diff --git a/server/tests/unit/eslint-rules/restricted-imports-xml.test.ts b/server/tests/unit/eslint-rules/restricted-imports-xml.test.ts index 12b91c588..cc76f5433 100644 --- a/server/tests/unit/eslint-rules/restricted-imports-xml.test.ts +++ b/server/tests/unit/eslint-rules/restricted-imports-xml.test.ts @@ -1,7 +1,6 @@ -import tsParser from '@typescript-eslint/parser'; - import { ESLint, Linter } from 'eslint'; import path from 'path'; +import tseslint from 'typescript-eslint'; import { describe, expect, it } from 'vitest'; // fast-xml-parser is allowed in place-import's codecs and the WebDAV client @@ -29,7 +28,7 @@ async function flags(file: string, source: string): Promise { [ { files: ['**/*.ts'], - languageOptions: { parser: tsParser }, + languageOptions: { parser: tseslint.parser }, rules: { 'no-restricted-imports': ['error', ...(options as object[])] }, }, ],