* feat(places): hand a trip back as GPX TREK reads GPX but never wrote it, so a planned trip could not reach the offline map or the handheld it was planned for. The importer already fixes the mapping: a wpt is a place, a rte or trk is a place with route_geometry, so writing is that reversed. Days have no import counterpart and become routes of their stops in order, which is the part that puts a plan on a device. XMLBuilder comes from the same fast-xml-parser the importer parses with, so nothing new is pulled in. * feat(dayplan): a GPX button beside PDF and ICS Scopes are worded by what someone wants on their device rather than by the GPX element: the whole trip, just the places for an offline map, just the days to follow a plan. An empty trip says so instead of reporting a failed download. * feat(mobile): GPX in the export sheet, which is no longer calendar-only The sheet held the PDF export next to the calendar entries and was still called Export Calendar; with GPX beside them the name was simply wrong. * i18n(dayplan): translate the GPX export into all locales * docs(map): document the GPX export * fix(dayplan): drop the GPX tooltip and centre both export menus The tooltip sat under the cursor exactly where the menu opens, so hovering the button produced both at once. The label lives on as an aria-label. Both menus now open centred under their button instead of hanging off its right edge.
@trek/shared
Single source of truth for TREK's API contracts, expressed as Zod schemas and consumed by both the server (request validation + inferred DTO types) and the client (typed requests/responses).
This package is part of the incremental NestJS + React 19 migration (see the "Brownfield Rewrite" board). It is intentionally dormant until modules start importing it — adding it changes nothing for users.
Rules
- One folder per domain:
src/<domain>/<domain>.schema.ts(+.spec.ts). - Domain-agnostic building blocks live in
src/common/. - A route is only considered migrated once its contract lives here.
- Schemas are the source of truth; server DTOs and client types are inferred from them
(
z.infer<typeof schema>), never hand-duplicated.
Consumption (dev)
Both apps resolve @trek/shared to this package's TypeScript source:
- Server (
tsx): viapathsinserver/tsconfig.json. - Client (
vite): viaresolve.aliasinclient/vite.config.ts(+pathsfor the type-checker).
Production packaging (Docker / workspace wiring) is introduced in card F2, when the server first depends on this package at runtime. Until then prod builds are untouched.
Not yet here
The canonical error envelope is finalised in card F5 (it must match TREK's current Express error responses byte-for-byte), so it is deliberately not invented in F1.