mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-12 23:31:02 +00:00
80183bc986
POST /api/routing/valhalla/route, /trace_attributes and /height ask the Valhalla at TREK_VALHALLA_URL (default https://valhalla.liketrek.com) for a signed-in user. The body is held to the shared contract (64 KB, at most 20 locations), every question counts against 120 a minute per user, and the installation key goes along only to a host TREK_SERVICES_HOSTS lists. Valhalla's answer is passed on as it came, refusals included. The road trip router asks the same relay when the routing choice lands on the TREK services, so the MCP road trip, city walk and hike tools share its limits, and hands a question it cannot answer to FOSSGIS.
284 lines
21 KiB
TypeScript
284 lines
21 KiB
TypeScript
import swc from 'unplugin-swc';
|
||
import { defineConfig } from 'vitest/config';
|
||
|
||
export default defineConfig({
|
||
// SWC transform so NestJS decorator metadata is emitted in tests
|
||
// (vitest's default esbuild does not emit it -> type-based DI would break).
|
||
plugins: [
|
||
swc.vite({
|
||
// unplugin-swc's default filter is /\.m?[jt]sx?$/ — anchored at the end of the
|
||
// id, so anything carrying a query string skips the SWC transform. The istanbul
|
||
// provider's uncovered-file pass asks vite for every never-imported source as
|
||
// `<file>.ts?cache=<n>&vitest-uncovered-coverage=true`; with the default filter
|
||
// those ids come back as raw TypeScript and babel's instrumenter (no TS or
|
||
// decorator plugins) dies on the first `as const`/`interface`/`@Global()`.
|
||
// Match the same extensions with an optional query so those ids are transformed
|
||
// exactly like the imported ones.
|
||
include: /\.[cm]?[jt]sx?(\?.*)?$/,
|
||
jsc: {
|
||
parser: { syntax: 'typescript', decorators: true },
|
||
transform: { legacyDecorator: true, decoratorMetadata: true },
|
||
keepClassNames: true,
|
||
},
|
||
}),
|
||
],
|
||
test: {
|
||
root: '.',
|
||
include: ['tests/**/*.test.ts'],
|
||
globals: true,
|
||
// Migrates one database for the whole run and snapshots it; workers open a
|
||
// copy instead of replaying 242 migrations per file. See tests/global-setup.ts.
|
||
globalSetup: ['tests/global-setup.ts'],
|
||
setupFiles: ['tests/setup.ts', 'tests/setup.console-noise.ts'],
|
||
testTimeout: 15000,
|
||
hookTimeout: 15000,
|
||
pool: 'forks',
|
||
// Console output is kept for failing tests and dropped for passing ones: a
|
||
// green run used to print every e2e boot and every migrator line (~100k
|
||
// lines) and a red one buried its failure in them. `default` prints one line
|
||
// per file and the full detail only for failures; on CI the github-actions
|
||
// reporter adds inline annotations on the PR.
|
||
silent: 'passed-only',
|
||
reporters: process.env.CI ? ['default', 'github-actions'] : ['default'],
|
||
coverage: {
|
||
// Vite 8 + Vitest 4 made the sourcemap-based `v8` provider under-report branch
|
||
// coverage on the SWC/decorator-transformed output (it dropped to ~68% even
|
||
// though every test passes). `istanbul` instruments the source directly, so
|
||
// coverage is measured independently of the transform pipeline.
|
||
provider: 'istanbul',
|
||
// Serialises report processing: three identical runs otherwise gave 13/6/6
|
||
// threshold errors (files like platform/api-docs.ts flipping between 0% and
|
||
// 100%) because the default concurrency processes per-file coverage results
|
||
// out of order against istanbul's shared state.
|
||
processingConcurrency: 1,
|
||
// json-summary is what the per-domain ratchet below is derived from: the text
|
||
// reporter prints one row per DIRECTORY, not a recursive total, so reading the
|
||
// thresholds off it silently understates any domain with subdirectories.
|
||
reporter: ['lcov', 'text', 'json-summary'],
|
||
reportsDirectory: './coverage',
|
||
include: ['src/**/*.ts'],
|
||
// The plugin child bootstrap runs in a forked subprocess via tsx, so the
|
||
// parent's instrumentation can't measure it; it's exercised end-to-end by
|
||
// the supervisor integration test instead. Everything else in the plugin
|
||
// module runs in-process and is unit-tested.
|
||
exclude: ['src/nest/plugins/runtime/plugin-host-entry.ts'],
|
||
// Coverage gate scoped to the new NestJS code only — the legacy codebase is
|
||
// intentionally ungated.
|
||
//
|
||
// The bar is PER DOMAIN and works as a ratchet: each entry is that domain's
|
||
// measured coverage at the time it was set, minus one point of slack. Regenerate
|
||
// with `node scripts/coverage-thresholds.mjs` after a run that RAISED coverage. A single
|
||
// repo-wide 80% let a well-covered domain subsidise a thin one, so a domain could
|
||
// lose ten points and the build stayed green. Now it cannot: the only way past a
|
||
// number here is to raise it, which makes the ratchet visible in the diff.
|
||
//
|
||
// Raise an entry when you improve a domain. Never lower one to make a build pass —
|
||
// that is the whole point of the mechanism.
|
||
//
|
||
// Regenerate from a LINUX run if you can: CI runs on Linux, and a few branches are
|
||
// platform-specific (the drive-letter half of the backup zip-slip guard is only
|
||
// reachable on win32). Numbers taken on Windows can therefore sit a hair above what
|
||
// CI measures, which shows up as a threshold failure that reproduces nowhere local.
|
||
//
|
||
// A file matched by a glob below is EXCLUDED from the catch-all, so the last entry
|
||
// only covers what sits directly under src/nest (app.module.ts and the like).
|
||
thresholds: {
|
||
'src/nest/accommodations/**/*.ts': { statements: 92, branches: 87, functions: 99, lines: 97 },
|
||
'src/nest/addons/**/*.ts': { statements: 99, branches: 89, functions: 99, lines: 99 },
|
||
'src/nest/admin/**/*.ts': { statements: 86, branches: 70, functions: 89, lines: 88 },
|
||
// New domains in this change, unmeasured: pinned at the 80 floor. Regenerate
|
||
// with scripts/coverage-thresholds.mjs after the first full run.
|
||
'src/nest/ai-connections/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
'src/nest/airports/**/*.ts': { statements: 68, branches: 60, functions: 93, lines: 73 },
|
||
'src/nest/app-config/**/*.ts': { statements: 79, branches: 100, functions: 65, lines: 71 },
|
||
'src/nest/assignments/**/*.ts': { statements: 90, branches: 80, functions: 97, lines: 96 },
|
||
'src/nest/assistant/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
'src/nest/atlas/**/*.ts': { statements: 92, branches: 82, functions: 96, lines: 94 },
|
||
'src/nest/audit/**/*.ts': { statements: 93, branches: 80, functions: 99, lines: 96 },
|
||
'src/nest/auth/**/*.ts': { statements: 93, branches: 85, functions: 95, lines: 96 },
|
||
'src/nest/auth-core/**/*.ts': { statements: 89, branches: 83, functions: 94, lines: 89 },
|
||
'src/nest/backup/**/*.ts': { statements: 97, branches: 93, functions: 99, lines: 98 },
|
||
'src/nest/booking-import/**/*.ts': { statements: 50, branches: 28, functions: 64, lines: 53 },
|
||
'src/nest/budget/**/*.ts': { statements: 91, branches: 77, functions: 97, lines: 95 },
|
||
'src/nest/calendar/**/*.ts': { statements: 96, branches: 93, functions: 99, lines: 99 },
|
||
'src/nest/categories/**/*.ts': { statements: 99, branches: 80, functions: 99, lines: 99 },
|
||
'src/nest/collab/**/*.ts': { statements: 92, branches: 85, functions: 95, lines: 97 },
|
||
'src/nest/collections/**/*.ts': { statements: 86, branches: 75, functions: 95, lines: 95 },
|
||
'src/nest/common/**/*.ts': { statements: 95, branches: 89, functions: 99, lines: 97 },
|
||
'src/nest/config/**/*.ts': { statements: 99, branches: 100, functions: 99, lines: 99 },
|
||
'src/nest/database/**/*.ts': { statements: 99, branches: 100, functions: 99, lines: 99 },
|
||
'src/nest/day-notes/**/*.ts': { statements: 92, branches: 83, functions: 99, lines: 99 },
|
||
'src/nest/days/**/*.ts': { statements: 92, branches: 82, functions: 98, lines: 97 },
|
||
'src/nest/doc-sync/**/*.ts': { statements: 91, branches: 79, functions: 96, lines: 95 },
|
||
'src/nest/feeds/**/*.ts': { statements: 91, branches: 83, functions: 83, lines: 91 },
|
||
// New domain in this change, unmeasured: pinned at the 80 floor so it
|
||
// has its own entry rather than hiding in the catch-all. Regenerate with
|
||
// scripts/coverage-thresholds.mjs after the first full run.
|
||
'src/nest/ferratas/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
'src/nest/files/**/*.ts': { statements: 97, branches: 95, functions: 99, lines: 98 },
|
||
'src/nest/geo/**/*.ts': { statements: 99, branches: 95, functions: 99, lines: 99 },
|
||
// google-quota, managed, mcp-shared, mcp-transport, public-api,
|
||
// receipt-scan, route-usage, scheduling, school-holidays, tokens and tours
|
||
// sat on the 80 catch-all until 2026-10-08. Each is pinned one point under
|
||
// what the unit, integration and e2e suites that load it measure, as the
|
||
// script prints it: a subset a full run can only measure higher. managed holds an empty
|
||
// module and nothing to count. mcp-shared and route-usage measure below
|
||
// the 80 floor on branches and functions and are pinned where they are.
|
||
// tests/unit/coverage-thresholds.test.ts fails on a domain without an entry.
|
||
'src/nest/google-quota/**/*.ts': { statements: 99, branches: 99, functions: 99, lines: 99 },
|
||
'src/nest/health/**/*.ts': { statements: 99, branches: 65, functions: 99, lines: 99 },
|
||
'src/nest/help/**/*.ts': { statements: 81, branches: 70, functions: 99, lines: 86 },
|
||
'src/nest/integrations/**/*.ts': { statements: 78, branches: 68, functions: 78, lines: 80 },
|
||
'src/nest/journey/**/*.ts': { statements: 91, branches: 84, functions: 88, lines: 93 },
|
||
// New domain in this change (JRN-01), unmeasured: pinned at the 80 floor
|
||
// like ferratas until the first full run regenerates it.
|
||
'src/nest/journey-recordings/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
'src/nest/llm-parse/**/*.ts': { statements: 91, branches: 85, functions: 85, lines: 94 },
|
||
'src/nest/managed/**/*.ts': { statements: 100, branches: 100, functions: 100, lines: 100 },
|
||
'src/nest/maps/**/*.ts': { statements: 93, branches: 86, functions: 97, lines: 96 },
|
||
'src/nest/mcp-shared/**/*.ts': { statements: 84, branches: 59, functions: 99, lines: 88 },
|
||
'src/nest/mcp-transport/**/*.ts': { statements: 89, branches: 79, functions: 87, lines: 90 },
|
||
'src/nest/memories/**/*.ts': { statements: 92, branches: 83, functions: 97, lines: 94 },
|
||
'src/nest/notifications/**/*.ts': { statements: 83, branches: 72, functions: 85, lines: 87 },
|
||
'src/nest/oauth/**/*.ts': { statements: 96, branches: 95, functions: 97, lines: 97 },
|
||
'src/nest/oidc/**/*.ts': { statements: 88, branches: 83, functions: 91, lines: 92 },
|
||
// The Overpass client the ferratas and the tours share, moved out of ferratas in this
|
||
// change with its tests: pinned at the 80 floor until a full run measures it.
|
||
'src/nest/overpass/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
'src/nest/packing/**/*.ts': { statements: 92, branches: 83, functions: 99, lines: 97 },
|
||
'src/nest/paddle-obstacles/**/*.ts': { statements: 96, branches: 92, functions: 94, lines: 97 },
|
||
// PAD-11, new in this change: measured by its unit and e2e suites, one point of slack.
|
||
'src/nest/paddle-routing/**/*.ts': { statements: 94, branches: 83, functions: 96, lines: 97 },
|
||
'src/nest/permissions/**/*.ts': { statements: 97, branches: 92, functions: 99, lines: 97 },
|
||
'src/nest/photos/**/*.ts': { statements: 96, branches: 92, functions: 92, lines: 96 },
|
||
// Landed on dev without an entry, so it sat on the 80 catch-all while
|
||
// measuring 99.5/99.0/97.4/100 — the gap the per-domain ratchet exists to
|
||
// close. Set with a few points of slack against the Linux/Windows drift.
|
||
'src/nest/place-enrichment/**/*.ts': { statements: 96, branches: 95, functions: 94, lines: 97 },
|
||
// New domain: the file and list readers that moved out of places/ and
|
||
// collections/. On the floor until a full CI run measures it; raise it
|
||
// with scripts/coverage-thresholds.mjs then, never lower it.
|
||
'src/nest/place-import/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
'src/nest/place-photos/**/*.ts': { statements: 87, branches: 79, functions: 72, lines: 89 },
|
||
// New domain in this change. Measured over its own suites at
|
||
// 98.3/89.8/96.2/100, and pinned well under that on purpose: the
|
||
// subset run does not load the controller the way the full run does,
|
||
// so the real figure is not this one. Regenerate with
|
||
// scripts/coverage-thresholds.mjs after a full run. What matters now is
|
||
// that it is off the 80 catch-all, where a new domain could shed twenty
|
||
// points without anything noticing.
|
||
'src/nest/place-shadow/**/*.ts': { statements: 90, branches: 80, functions: 90, lines: 95 },
|
||
'src/nest/places/**/*.ts': { statements: 91, branches: 82, functions: 96, lines: 94 },
|
||
'src/nest/platform/**/*.ts': { statements: 99, branches: 99, functions: 99, lines: 99 },
|
||
'src/nest/plugins/**/*.ts': { statements: 86, branches: 81, functions: 78, lines: 89 },
|
||
'src/nest/public-api/**/*.ts': { statements: 97, branches: 86, functions: 99, lines: 99 },
|
||
'src/nest/query-helpers/**/*.ts': { statements: 90, branches: 75, functions: 99, lines: 92 },
|
||
'src/nest/realtime/**/*.ts': { statements: 99, branches: 100, functions: 99, lines: 99 },
|
||
'src/nest/receipt-scan/**/*.ts': { statements: 99, branches: 99, functions: 99, lines: 99 },
|
||
'src/nest/reservation-import/**/*.ts': { statements: 61, branches: 55, functions: 41, lines: 61 },
|
||
'src/nest/reservations/**/*.ts': { statements: 92, branches: 83, functions: 96, lines: 96 },
|
||
// New domain in this change. Measured over its own suites at
|
||
// 94.0/81.1/100/99.1 and pinned under that: the subset run does not
|
||
// load the controller the way the full run does, so the real figure is
|
||
// not this one. Regenerate with scripts/coverage-thresholds.mjs after a
|
||
// full run. What matters now is that it carries its own floor instead of
|
||
// hiding in the 80 catch-all, where 557 new lines could shed twenty
|
||
// points against the headroom of the domains beside them.
|
||
'src/nest/roadtrip/**/*.ts': { statements: 88, branches: 80, functions: 95, lines: 95 },
|
||
'src/nest/route-usage/**/*.ts': { statements: 84, branches: 66, functions: 77, lines: 83 },
|
||
// New domain in this change, unmeasured: on the 80 floor until the first
|
||
// full CI run, then raised with scripts/coverage-thresholds.mjs, never lowered.
|
||
'src/nest/routing-relay/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
'src/nest/scheduling/**/*.ts': { statements: 99, branches: 92, functions: 99, lines: 99 },
|
||
'src/nest/school-holidays/**/*.ts': { statements: 97, branches: 95, functions: 99, lines: 97 },
|
||
// New domain in this change, unmeasured: on the 80 floor until the first
|
||
// full CI run, then raised with scripts/coverage-thresholds.mjs, never lowered.
|
||
'src/nest/service-identity/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
// New domain in this change, unmeasured: pinned at the 80 floor so it
|
||
// has its own entry rather than hiding in the catch-all. Its suites
|
||
// cover every branch they can reach; regenerate with
|
||
// scripts/coverage-thresholds.mjs after the first full run.
|
||
'src/nest/sessions/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
'src/nest/settings/**/*.ts': { statements: 87, branches: 71, functions: 99, lines: 88 },
|
||
'src/nest/share/**/*.ts': { statements: 97, branches: 87, functions: 99, lines: 99 },
|
||
// The piste router, new in this change and not measured yet: on the floor until the first full CI
|
||
// run, then raised with scripts/coverage-thresholds.mjs (the spec aims at 90), never lowered.
|
||
'src/nest/ski-routing/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
'src/nest/storage/**/*.ts': { statements: 94, branches: 84, functions: 97, lines: 94 },
|
||
'src/nest/system-notices/**/*.ts': { statements: 99, branches: 99, functions: 99, lines: 99 },
|
||
'src/nest/tags/**/*.ts': { statements: 97, branches: 89, functions: 99, lines: 99 },
|
||
'src/nest/todo/**/*.ts': { statements: 90, branches: 82, functions: 99, lines: 99 },
|
||
'src/nest/tokens/**/*.ts': { statements: 99, branches: 97, functions: 99, lines: 99 },
|
||
'src/nest/tours/**/*.ts': { statements: 95, branches: 92, functions: 99, lines: 97 },
|
||
'src/nest/transit/**/*.ts': { statements: 92, branches: 83, functions: 97, lines: 94 },
|
||
'src/nest/trip-invite/**/*.ts': { statements: 91, branches: 93, functions: 93, lines: 89 },
|
||
'src/nest/trip-membership/**/*.ts': { statements: 99, branches: 86, functions: 99, lines: 99 },
|
||
'src/nest/trip-members/**/*.ts': { statements: 95, branches: 91, functions: 99, lines: 95 },
|
||
'src/nest/trip-read-model/**/*.ts': { statements: 97, branches: 96, functions: 99, lines: 97 },
|
||
'src/nest/trips/**/*.ts': { statements: 95, branches: 86, functions: 95, lines: 96 },
|
||
'src/nest/unsplash/**/*.ts': { statements: 99, branches: 88, functions: 99, lines: 99 },
|
||
'src/nest/vacay/**/*.ts': { statements: 82, branches: 66, functions: 90, lines: 86 },
|
||
'src/nest/wanderer/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
'src/nest/weather/**/*.ts': { statements: 93, branches: 78, functions: 91, lines: 97 },
|
||
'src/nest/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
|
||
// Outside the container. Coverage MEASURES src/**, but until now only
|
||
// src/nest/** was gated, so the boot path, the scheduler, the MCP
|
||
// handler and the migrations sat under no floor at all — which is
|
||
// exactly where the worst finding of the last audit lived (a swallowed
|
||
// EADDRINUSE that no test could have caught). These entries pin what is
|
||
// measured today so it cannot slide; they are floors to raise, not
|
||
// targets that have been met.
|
||
//
|
||
// src/demo/** is deliberately absent: it measures 0%, and a floor of
|
||
// zero asserts nothing. It needs tests before it needs a threshold.
|
||
'src/app-config/**/*.ts': { statements: 99, branches: 95, functions: 99, lines: 99 },
|
||
// Hand-maintained (scripts/coverage-thresholds.mjs only emits src/nest/* lines): floor(measured) - 1 after Plan 2.
|
||
'src/db/**/*.ts': { statements: 84, branches: 42, functions: 95, lines: 87 },
|
||
'src/db/dialect/**/*.ts': { statements: 99, branches: 99, functions: 99, lines: 99 },
|
||
// Branches re-pinned at floor(measured) - 1 once Plans 3a–4 had grown the
|
||
// folder from the Plan 2 handful to 136 repositories (89.83% measured,
|
||
// identical locally and on CI); the 99 was set before any of them existed.
|
||
'src/db/repositories/**/*.ts': { statements: 99, branches: 88, functions: 99, lines: 99 },
|
||
'src/db/types/**/*.ts': { statements: 93, branches: 99, functions: 99, lines: 93 },
|
||
'src/mcp/**/*.ts': { statements: 58, branches: 43, functions: 63, lines: 60 },
|
||
'src/middleware/**/*.ts': { statements: 91, branches: 89, functions: 87, lines: 94 },
|
||
// The folded-in nest-mcp decorator/registry layer keeps the 80% floor
|
||
// its own workspace gate enforced (tests/unit/nest-mcp/).
|
||
'src/nest-mcp/**/*.ts': { statements: 80, branches: 80, functions: 80, lines: 80 },
|
||
// The plugin RPC kit (rpc-kit, rpc-params, rpc-errors, PluginGuards), moved
|
||
// out of src/nest/plugins with its tests (tests/unit/nest-rpc/).
|
||
'src/nest-rpc/**/*.ts': { statements: 92, branches: 85, functions: 95, lines: 94 },
|
||
'src/systemNotices/**/*.ts': { statements: 84, branches: 67, functions: 93, lines: 85 },
|
||
'src/utils/**/*.ts': { statements: 92, branches: 87, functions: 89, lines: 96 },
|
||
// index.ts, bootstrap.ts, scheduler.ts, config.ts, websocket.ts and the
|
||
// small top-level modules beside them.
|
||
'src/*.ts': { statements: 39, branches: 36, functions: 36, lines: 42 },
|
||
},
|
||
},
|
||
},
|
||
resolve: {
|
||
alias: {
|
||
// MCP SDK's exports map uses extension-less wildcard targets that neither
|
||
// Node nor Vite can resolve. Point directly at the CJS dist files.
|
||
// Paths are relative to the monorepo root (packages are hoisted there).
|
||
'@modelcontextprotocol/sdk/server/mcp': new URL(
|
||
'../node_modules/@modelcontextprotocol/sdk/dist/cjs/server/mcp.js',
|
||
import.meta.url,
|
||
).pathname,
|
||
'@modelcontextprotocol/sdk/server/streamableHttp': new URL(
|
||
'../node_modules/@modelcontextprotocol/sdk/dist/cjs/server/streamableHttp.js',
|
||
import.meta.url,
|
||
).pathname,
|
||
'@modelcontextprotocol/sdk/inMemory': new URL(
|
||
'../node_modules/@modelcontextprotocol/sdk/dist/cjs/inMemory.js',
|
||
import.meta.url,
|
||
).pathname,
|
||
'@modelcontextprotocol/sdk/client/index': new URL(
|
||
'../node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.js',
|
||
import.meta.url,
|
||
).pathname,
|
||
},
|
||
},
|
||
});
|