mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-14 00:01:03 +00:00
5fe3dea4cccf9a8d21bc5e7dc7fb64d9ffaf8e45
63 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f7bad3c5b3 |
docs(wiki): the mail import's deferred folder, recipients, limits and sender hint
Describes TREK/deferred, which header names the address, the webhook's 401 and 429 answers and where the sender hint can show at all. The variables table leaves an empty default blank instead of a dash. |
||
|
|
7d3ed21a03 |
feat(mail-ingest): the transport settings in the admin form, each overridable from the environment
The IMAP box, the webhook secret and the address template join the admin settings form (masked, encrypted, held by the operator on a managed install), and MAIL_INGEST_* variables override them through the mailIngestConfig token. The audit row masks every masked key, and key rotation covers the new secrets. |
||
|
|
2d95bf6744 |
docs(wiki): live flight status and FLIGHT_LIVE_ENABLED
The transport page explains what TREK follows, where it shows and what open data cannot give; the environment page documents the switch and what leaves the server. |
||
|
|
354e30a075 |
fix(ci): wallet passes pass the server gates
- TREK_WALLET_PASS_URL read as a secret to the env check (the word PASS); it is TREK_WALLET_SIGNER_URL now, everywhere it is documented - findPassContext compared the TEXT accommodation_id with an integer id, which Postgres refuses; it compares them as numbers now, as both databases accept - the wallet-pass service test takes its subject from createTestModule instead of building it by hand, and no longer names the DOM-only BodyInit type - Reservations.repository.ts is formatted, so it leaves the format baseline - the wallet button test reads the translated texts the render helper gives |
||
|
|
37a4e84360 |
feat: Apple Wallet passes for bookings
"Add to Apple Wallet" on a booking in the iOS app turns it into a TREK pass: a boarding pass from and to for flights, trains, buses and boats, check-in and check-out for a stay, pickup and drop-off for a car, the time for anything else, with the confirmation code as a QR code. Wallet brings it up on the lock screen around its time and place: times carry the offset of the endpoint's zone (looked up from the coordinates where the endpoint has none), stays and restaurants their place's coordinates. The labels come from the booking forms' own strings, so nothing new to translate on the pass. Only liketrek holds the Pass Type ID certificate, so the server sends the pass's texts to the TREK services' signer (TREK_WALLET_PASS_URL, push.liketrek.com) once per tap; it stores nothing, and TREK_SERVICES=off turns it off with the other services. Texts are cleaned of links and shortened here, the answer must be a .pkpass within 512 KB, and a user gets 20 passes a minute. - New wallet-pass domain: GET /api/trips/:tripId/reservations/:id/wallet-pass behind the trip guard, the booking checked to belong to the trip; trip title and place come from the reservations domain (findPassContext) - MWalletButton in the transport and booking sheets, only where the app binary has the wallet feature; undated bookings and failures are told apart - TREK_WALLET_PASS_URL in .env.example, compose, Helm and the wiki |
||
|
|
18dc121132 |
wiki: sharing place details with the TREK Places API
What is sent and when, what never is, how values are checked before anyone sees them, and where an admin switches it off or takes it back. The new TREK_PLACES_CONTRIBUTE variable is listed with the compose file and the chart. |
||
|
|
70f27085b9 |
feat(i18n): bring the Hebrew locale up to date with dev and list it in the docs
Translate the 55 keys dev added since the branch was cut (TREK services allowance, Valhalla routing service, PDF routing progress, overview distances, Unsplash key hint, tour day limit) and drop the two reservation toasts dev removed, so he matches en key for key again. Refresh the two admin strings and the Valhalla hint whose English changed. Check he in the placeholder spec and the RTL test, and count 28 languages with Hebrew in the README and the Languages, Environment Variables, Contributing and Help Center wiki pages. |
||
|
|
c4c63ffd62 |
docs(transit): describe the empty-result fallback between transit providers
Admin settings, transport, environment and MCP pages still said Transitous is the only fallback and that Google is billed only when picked. Document that an empty plan asks the other backend, that the Google fallback uses only an instance key within the daily limit, and mention it in the search_transit_routes tool description. |
||
|
|
b98e530ffc | wiki: describe the address search, the merged result list and the routing of the TREK services | ||
|
|
80183bc986 |
feat(server): relay Valhalla routing to the TREK services with the installation key
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. |
||
|
|
250a7d4eb7 | docs(wiki): describe the Photon address search and TREK_PHOTON_URL | ||
|
|
afacf00c9f |
docs: document TREK_SERVICES, TREK_SERVICES_KEY and the daily allowance
docker-compose.yml and the Helm chart name the switch and the key (the key in the Secret, never the ConfigMap), and the wiki explains the installation key, what it carries, where it goes and the admin view of the allowance. |
||
|
|
0ca9f7241a | Add PLACES_API_BASE, TREK_DB_FILE and an AI Assistant note to the variable reference and list the assistant connections in the key rotation page | ||
|
|
9373667084 | feat: support importing Google lists from a configured data URL base | ||
|
|
d924dcf99d |
fix(tours): keep the Places layers off the search breaker and keep partial way answers
The ways and routes layers now count failures on a breaker of their own, so busy or slow layer answers no longer send place search to the fallback for a minute, and a layer's 404 no longer clears the count of search failures. When a later batch of /v1/ways fails, the batches that answered are kept and only the ids still open go to the Overpass mirrors. The wiki, the compose file and the chart now say that the way ids of a planned tour and the horse routes box go to the TREK Places API. |
||
|
|
3c823e07f4 |
fix(tours): search along a tour through the places index along the line, and name what could not be searched (PLN-02, CW-05)
The search along a tour found nothing. It asked the places index for all kinds of a stretch at once, above the 100 rows and 200 characters of terms the index takes, so the index refused and every stretch went to the public Overpass mirrors, which do not answer from this server. Now the index is asked in small circles strung along the line, one request per kind and circle within its limits, and an empty circle counts as an answer, so a city walk lists its sights, museums, parks, cafes, restaurants and markets in well under a second. The kinds the index does not know (viewpoints, huts, drinking water, toilets and the like) are asked of Overpass along the whole line at the same time, one query per stretch of up to 50 km, three at a time, each with a short deadline of its own; a line past 400 km is searched along its start and says so. When the index answers no circle at all, its kinds go to Overpass beside the others instead of after them. A kind no source could be searched for is named in a calm notice above the list instead of reporting nothing found, and the reason is written to the log. Unnamed taps, toilets, shelters, picnic spots, viewpoints, summits, slipways and repair stands stay in the list and on the map under the name of their kind; an unnamed garden, cafe or memorial is left out. The places nearest the line are kept when there are more than sixty, listed from the start, with the opening hours the source has. A walk's parks are parks and gardens only, and its museums are museums and galleries only, no longer the beaches, summits, theatres and cinemas of the map's explore buttons; a water park the index files under parks is not one of them. The index also answers markets and summits. The explore buttons keep their single request, and a search of several kinds that would exceed the index limits is asked one kind at a time instead of being refused. The MCP tool search_tour_pois and its wiki row describe the walk kinds and the new unavailable list, and the OVERPASS_TIMEOUT_MS row says the search along a tour keeps its own shorter deadline. |
||
|
|
f901982903 |
fix(llm-parse): LLM_MAX_OUTPUT_TOKENS sets the answer cap, a cut-off answer says so
The OpenAI-compatible client always asked for 4096 tokens, and a document whose bookings needed more came back as "no reservations" with nothing that pointed at the cap. LLM_MAX_OUTPUT_TOKENS now sets the cap for every provider; unset keeps 4096 and 8192 so a small local model's context still fits. A finish_reason of "length" is reported like Anthropic's max_tokens stop, naming the limit and the variable that raises it. Closes #2677 |
||
|
|
1ea72dca97 |
fix(config): trim whitespace around NODE_ENV, LOG_LEVEL and DEFAULT_LANGUAGE once at boot
NODE_ENV="production " passed the boot check but matched none of the
exact production comparisons, so the web UI was never served and every
page answered {"error":"Cannot GET /"}, while the banner showed a clean
"production". The boot import now trims these three variables in
process.env before anything else reads them, so Express, the plugin
children and readEnv() agree, and reports each change as a process
warning. Casing stays as it was. A padded "test" is only reported, so an
instance cannot switch to an in-memory database after an update. The
banner prints NODE_ENV as set instead of lowercasing it.
Refs #2565
|
||
|
|
558203213c |
fix(server): keep idle connections open longer than Traefik's upstream timeout
The 65 s default sat above nginx's 60 s but below the 90 s Traefik keeps an idle upstream connection, so a default Traefik deployment could still reuse a socket Node had just closed and answer that request with a 502. 95 s clears both, and the headers timeout one second above it stays well under Node's 300 s request timeout and the 290000 cap the schema accepts. Also moves the stray RawEnv import in boot-derive.ts up to the other import. |
||
|
|
5cb87a4df5 |
feat(server): add last-resort error handlers, a draining readiness probe and proxy keep-alive
Three small gaps in how the process behaves at its edges: - An unhandled rejection or uncaught exception crashed the process with the stack on stderr only. index.ts now logs it to trek.log and runs the same orderly shutdown a SIGTERM gets, exiting with 1; a second fatal error during that shutdown exits at once. - /api/health/ready kept answering 200 while a SIGTERM was draining the process, so an orchestrator sent traffic for another probe period. A shutdown now marks the new ReadinessService first (and Nest's own shutdown hook marks it too), and the probe answers 503 from then on. - Node closes an idle keep-alive connection after 5 seconds while reverse proxies keep upstream connections for about a minute, which shows up as intermittent 502s. The server now keeps them for 65 seconds, configurable through HTTP_KEEP_ALIVE_TIMEOUT_MS (owned by the httpConfig token), with the headers timeout one second above. |
||
|
|
ff3615fdf0 |
feat(db): copy the database before a boot migrates it
Migrations only go forward, and since #2610 an older image refuses a database a newer one migrated. Going back after a bad update therefore needs a copy from before it, and the only copies were backups the admin takes by hand or auto-backup, which is off by default. The first boot on 4.4 migrates every 4.3.x install through the legacy baseline and the new migrations without either. Before applying pending migrations to a file database that holds anything, the boot now writes a VACUUM INTO copy next to it, named pre-migrate-<schema>-<time>.db (legacy-<schema_version> for an install the positional runner left, otherwise the last recorded migration), and keeps the newest TREK_DB_PRE_MIGRATE_SNAPSHOT_KEEP (3). The copy is written under a temporary name and renamed, so a crash never leaves a truncated file that looks good. If it cannot be written the boot refuses before anything is migrated; TREK_DB_PRE_MIGRATE_SNAPSHOT=false is the documented way past that. The newer-database refusal names the copy taken right before the newer release migrated past this one. A fresh install, a restart with nothing pending, an in-memory database and a restore's re-bootstrap (the archive is the copy) take none, and NODE_ENV=test leaves it off unless a suite sets the switch. |
||
|
|
05b53d024e | docs(wiki): bring every page up to the next release; admin settings, user defaults and notifications get pages of their own | ||
|
|
5138358d7b |
feat(net): the SSRF-guarded requests go through HTTP_PROXY / HTTPS_PROXY too
Place photos, link previews, webhooks and the integrations fetch through the guard's own dispatcher and so ignored the outbound proxy, which left a server that can only reach the internet through one without them. They now read HTTP_PROXY, HTTPS_PROXY and NO_PROXY themselves and connect through the proxy, after the guard has vetted the target. The Helm chart passes the three variables through. (#1754) |
||
|
|
885896aba2 |
feat(files): FILE_UPLOAD_LIMIT_MB sets the upload limit for files and notes
The 50 MB limit for files, booking attachments and note attachments becomes FILE_UPLOAD_LIMIT_MB, 50 by default. The server hands it to the client through the app config, so the upload dialogs refuse a file over it up front and say what the limit is; on desktop a file over it no longer vanishes without a word. (#1364) |
||
|
|
1fee38e8f7 |
feat(oidc): OIDC_USERNAME_CLAIM picks the claim a new account's username comes from
Providers like Pocket ID send the full name in 'name', which became 'JaneDoe'. OIDC_USERNAME_CLAIM=preferred_username builds the username from that claim instead. Unset, or with the claim empty, the old order applies (name, preferred_username, the email's local part), and it is only read when an account is created. (#1677) |
||
|
|
8fd46c4c18 |
feat: quality of life sweep from the feature discussions
Small requests from the discussions, each built end to end: planner and map (cycling mode, date first headings, clear a day, stay times per day, off-route stops, map lock, compact unplanned markers, pending stays, cable car, transit quick picks), places (location filter, category from OSM, open in maps, geo: link, image from an attachment, enrichment on file import, places near a pin, place name language, Amap first in China), lists and costs (packed counter, inherited sharing, Markdown to-dos, payment notes, bookings CSV, my plan PDF), sharing (unplanned places, travel only, without photos), journey (photo zoom, drafts, photo order, trip suggestion, day jump), atlas (region counter, region bucket list, places per country), vacay half company holidays, studio copy and paste plus the book's own layouts, and RESTORE_FROM_BACKUP for a first start restore. |
||
|
|
650451bdf7 |
feat(notifications): Web Push delivers notifications to every device, even with TREK closed
A fourth built-in channel next to email, webhook and ntfy. Browsers register per device, the server encrypts per RFC 8291 and signs per RFC 8292 with node:crypto and sends only to known push services through the SSRF guard. The event matrix decides per category what arrives by push; admins switch the channel on under Notifications. VAPID keys come from the environment or are generated once, only while neither stored row exists, and kept encrypted. A pair that does not decrypt or match is never overwritten and never swapped for another one: push stays off with an error in the log and every device stays registered until the key is fixed. The subject is VAPID_SUBJECT, then an https APP_URL, then the project URL. Only chat messages collapse into one notification per trip, and a replacement still alerts. A 403 removes a device only after three failures in a row; 404 and 410 remove it at once. Password change, reset and an admin setting a password drop the user's devices with the other credentials. The request log redacts subscriptions and endpoints, boot errors print *** for every secret variable, and logout forgets the device with a plain fetch so an expired session cannot redirect midway. Addresses discussion #894. |
||
|
|
bb5c5dcfc1 |
docs: TREK ships 27 languages now
Azerbaijani, Estonian, Slovak and Thai joined; the README and the wiki still counted 23. |
||
|
|
b7f777024a |
feat(i18n): bring the Thai translation up to date with dev
Translates the keys dev gained since the branch was cut, the help center above all, and drops the six keys dev no longer has. Registers th everywhere a language is listed: notification emails, the rate-limit message, the placeholder check and the wiki. The two tests that counted the languages by hand now derive the count from SUPPORTED_LANGUAGES. |
||
|
|
3c036ea25d |
feat(i18n): bring the Slovak translation up to date with dev
Translates the keys dev gained since the branch was cut, the help center above all, and drops the six keys dev no longer has. Registers sk everywhere a language is listed: notification emails, the rate-limit message, the placeholder check and the wiki. The two tests that counted the languages by hand now derive the count from SUPPORTED_LANGUAGES. |
||
|
|
ffa085aef7 |
feat(i18n): bring the Estonian translation up to date with dev
Translates the keys dev gained since the branch was cut, the help center above all, and drops the six keys dev no longer has. Registers et everywhere a language is listed: notification emails, the rate-limit message, the placeholder check and the wiki. The two tests that counted the languages by hand now derive the count from SUPPORTED_LANGUAGES. |
||
|
|
33aa1cd52e |
feat(i18n): bring the Azerbaijani translation up to date with dev
Translates the keys dev gained since the branch was cut, the help center above all, and drops the six keys dev no longer has. Registers az everywhere a language is listed: notification emails, the rate-limit message, the placeholder check and the wiki. The two tests that counted the languages by hand now derive the count from SUPPORTED_LANGUAGES. |
||
|
|
8906b66bc8 |
feat(settings): set the Google Maps key through PLACES_API_KEY
The server already put PLACES_API_KEY ahead of the key saved in the admin panel, but nothing said so: the variable was in no template and the admin field kept showing a stored value that no search used. GET /me/settings now answers env_keys, the variable behind each key the environment sets (Google, Unsplash, Amap), and null for that key's value. The admin field turns read-only and names the variable, Test still probes the key a search resolves to, and a save leaves those names out so the stored fallback survives. The variable is documented in .env.example, docker-compose.yml, the Helm chart (as a secret) and the wiki. Addresses discussion #1881. |
||
|
|
ed18c37903 |
fix: the findings of the final 4.3.0 audit
Every file the release touches was read once more, and what survived an independent check against the code is fixed here, with a test for each. Data and credentials - A document sync connection edited to a new address no longer carries the stored token along: a blank form under another origin is refused, the same rule the probe route already had. Dawarich and AirTrail testConnection send the stored key only to the host it was stored for. - The key rotation script now covers document_connections.secrets and trip_document_links.webhook_secret, which it had skipped. - Turning a booked night into a pause in the road trip popup asks first and says that the booking and its expense go with it. Deleting a place says the same when a night is booked there, on the desktop and on the phone. - A moved version marker over unchanged bytes no longer replaces the TREK file and its attachments; a real revision carries the attachments over. Planner - A drop in the day plan names the row it lands ahead of in the full day, so a hidden hotel stop no longer shifts it one slot early; the store sorts before it splices. Via re-anchoring, the booked-night guard and the sidebar's day membership read the stored day, the index space the server uses. - A hotel stop placed mid-day re-pins the road trip vias of that day, and the booking session receives the new stop order too. The Public API and the iCal feed list a booked hotel once. A plugin can no longer write a stay against another trip's day. Road trip and map - The route overview paces its requests to the public routers and retries a rate limit, and it says which legs it could not route instead of quietly reporting a shorter trip. A click on a via handle no longer drops a second via; handles hide when zooming out. Read-only members cannot edit the driving limits. The phone shows a way back when no day is picked and prints the night drive departure in the chosen clock format. Integrations and search - Google transit keeps conventional trains when the train chip is on. TREK_PLACES_ENABLED=false stops the details and enrichment calls too, and accepts the whole boolean family. A caller-supplied description no longer lands in the instance-wide enrichment cache. Nominatim searches carry a timeout. An OSM place id is checked for shape before it reaches Overpass. - Dawarich puts a stay on the trip whose dates hold it, the Atlas hand-off knows what the Atlas already shows, and a host change with a new key clears the old instance's state. - Document sync: a webhook address pasted by hand works on the token alone, deleting a connection unregisters its subscriptions, Nextcloud under a sub-path connects, Synology answers a name collision before uploading and verifies a move into the bin, Paperless titles are capped at 128 characters, a DNS failure reads as unreachable rather than as a policy verdict, videos from the store are accepted like uploads, and remote_missing has a way out. Conflict buttons only for the owner, a refused choice is reported, a refused credential gets a Reconnect button, disconnecting asks first on the desktop as it does on the phone, and the folder picker no longer spins forever. Release - The server holds the release notice back from a bundle that cannot draw it, so the previous shell served from the service worker cache after an update no longer shows bare keys and no longer lets a click use the notice up. - Import into an existing list gets the same body limit as a new list. Chat images say when the limit is reached and the new controls are translated. The transit backend switch reports a failed save. The Helm chart carries the Amap credentials in its Secret; the shipped templates document the Places API and Amap variables and the Overpass default. The wiki follows. |
||
|
|
44c92052a3 |
docs(wiki): bring the pages in line with 4.3.0
Every page was read against the code on dev. What changed: - Pages that described 4.2 behaviour: satellite view on the vector maps, the mobile journal timeline, Collab with its fifth tab, the Review badge, clustered pins on the share page, the Leaflet preset list, the strict guard on fe80::/10, the invite link tools and their scopes, the Public API scope rules, the permission count in the plugin SDK. - Features of this release that no page mentioned: videos in a journal entry, receipts on an expense, the Google transit backend, routing counters, the rating on a place, the navigation menu, car stops, the manual school holiday catalogue and its MCP tools, the Dawarich panel in the Atlas, the release notes modal, plugin frames going fullscreen, the corridor call into the search provider hook. - Statements that sent an admin the wrong way: DEFAULT_LANGUAGE is not in the Helm ConfigMap, env.PORT cannot be changed on the chart alone, the rotation script does not cover the document sync credentials, event handlers cannot broadcast, there is no per user MFA reset in the admin panel, the demo user can edit, an unparsable APP_URL stops the server. - Updating gets a section for 4.3.0: the TREK Places API as the new default, the new variables, the Overpass timeout, SSO sessions on an OIDC only instance, the migration that puts booked nights on the drive. |
||
|
|
7cfec6452d |
fix(ssrf): let a listed link-local address through, such as a rootless Podman host gateway
A rootless Podman container reaches its host through 169.254.1.2, and an identity provider behind that address failed the OIDC login with "Requests to link-local / cloud-metadata addresses are not allowed", with no setting to change it. ALLOW_LINK_LOCAL_IPS names single link-local IPv4 addresses that may be reached after all. The admin-configured lane (OIDC, AI parsing, plugin OAuth, routing engines) reaches a listed address directly; the guard on user-supplied URLs treats it as internal, so it also needs ALLOW_INTERNAL_NETWORK there. 169.254.169.0/24 and 169.254.170.0/24, where clouds serve instance metadata and credentials, cannot be listed, and an entry that is not one link-local IPv4 aborts startup. Unset, nothing changes. Closes #2400 |
||
|
|
58f6a49f32 |
docs(wiki): document road trip, document sync, the TREK Places API and Dawarich
The 4.3.0 features had no pages, or pages that described an earlier state. Three new pages and a rewrite: - Road-Trip: the addon from enabling it to the phone tab, stays and a stop's End as the time you leave, pinned times and the backward schedule, daily travel times, the three driving limits, search along the route, via points, other ways and what avoiding tolls needs, following a track, the warning layer, MCP tools and troubleshooting. - Document-Sync: switching stores on, binding a trip, what each store asks for and binds, direction and delete rules, conflicts, the mass-delete guard, renames and restores, what needs a look, limits, private addresses, and the MCP tools. - TREK-Places-API: what the index is, where TREK asks it, what leaves the instance, switching it off or pointing it at a copy of your own, and what happens when it is down. - Dawarich: brought up to date with suggestions, the journal fold, recorded routes, Atlas proposals and the wish list. Places and search, documents, the addon and admin overviews, MCP tools, environment variables, internal network access, the sidebar and home link the new pages, and the in-app help picks them up from the sidebar. |
||
|
|
61a8a2765b |
fix(geo): read the Nominatim override the way the schema validates it
Follow-up to #2379. NOMINATIM_URL arrives from a compose file or a ConfigMap with whatever whitespace was typed around it. The schema validates the trimmed string and calls a blank one unset, the derivation did neither, so " " passed startup as "use the default" and then became the base URL that cannot be fetched, and a padded value lost every geocoding call the same way. It trims now, which is also what the places client next door does with its own override. The chart could not pass the variable at all: the ConfigMap is an allowlist and an unknown key is dropped without a word, which is exactly the locked-down cluster the override exists for. The docs said what to set and not what it costs. They now say that it replaces the public service with no fallback, that the endpoint has to speak the Nominatim API, and that the one-per-second spacing stays either way, so nobody stands up their own instance expecting it to run faster. Test IDs follow the file again. |
||
|
|
c0195557d4 | feat(geo): support overriding Nominatim endpoint via env | ||
|
|
3e8ab22836 |
docs(maps): Amap beside the TREK index
The index and OpenStreetMap answer every search; the provider choice only decides who fills the keyed slot next to them. Rows carry a source mark, a place keeps its Amap id, and the journey map shares the shifted projection. |
||
|
|
57eac32f9f |
feat(map): amap as map api provider and display template
|
||
|
|
94914295d1 |
fix(llm): let a model refuse temperature, and say which extractor is installed
Two reports, both about an import that fails without saying why. #2262 — temperature: 0 sat in the shared request body, so it went out on every attempt including both retries. Reasoning models (the gpt-5 family) reject any explicit temperature, and the json_object retry fires on any 400, so the import spent two doomed requests and could not succeed at all. The parameter is now dropped once a server has explicitly said it will not take it. Not as a third link in the chain, though. A gpt-5 rejects max_tokens AND temperature, the API names one parameter per response, and it may name either first — a chain of one-shot ifs converges on only one of the two orders. The retries are a loop over what the server actually said instead: each remedy applies at most once and they compose. Detection is a phrase, not the bare word, because dropping temperature costs the deterministic sampling that small local models depend on, and an unfamiliar wording still falls through to the json_object retry exactly as before. NuExtract and Ollama are untouched: the first attempt always carries temperature, and it is the only one they ever see. #2261 — the bundled extractor is Debian trixie's 24.12.3, roughly eighteen months behind upstream, and the reporter is right that this is invisible: a stale extractor, a mistyped KITINERARY_EXTRACTOR_PATH and a genuinely unsupported provider all look the same from the UI, which is nothing imported and no reason given. The version now appears in the startup log and in a new admin-only GET /api/admin/system-info, and LOG_LEVEL=debug passes the extractor's raw stderr through — the JS ERROR and Invalid-result-type lines the filter drops are the only evidence that a vendor script is missing or failing. Capped at 200 lines, and opt-in because those lines can carry document fragments. Not bumping the package: the filter the reporter needs first ships in KDE Gear 26.08 and no Debian suite carries it, and sid's 26.04.3 wants KF6 6.22 and Qt6 6.10.2 against trixie's 6.6 and 6.8.2 — a partial upgrade of Qt6, KF6 and libc6 from unstable into the production image, on two architectures, that still would not fix the reported carrier. It comes for free with the base-image move after Debian 14. |
||
|
|
53c246e8e5 |
docs(wiki): the AI parsing addon now reads one environment variable
Three shipped sentences became false with LLM_TIMEOUT_MS: two claiming the addon needs no environment variables (one of them in the very file the variable was added to), and one naming the old five-minute ceiling that the deleted constant used to set. |
||
|
|
dba4434ef6 |
fix(llm-parse): one configurable ceiling for a model call, and undici honours it
The timeout for a model call was spelled three times and adjustable nowhere: 120s in the Anthropic client, 300s in the OpenAI-compatible one, 300s in the Ollama one. None of them was the ceiling that actually applied, either — every one of those calls goes through the pinned undici dispatcher, and an undici Agent stops waiting for response headers after five minutes by default, so a client constant set above that never got the chance to fire. - LLM_TIMEOUT_MS (default 900000) replaces the three constants and is passed to the dispatcher as headersTimeout/bodyTimeout, so the abort signal and undici are governed by the same setting. The default is deliberately generous: heavier parsing work should fit without a code change, and an admin who would rather fail fast can lower it. - The ceiling stays on the model lane. safeFetchAdminConfigured is also the OIDC lane (discovery, token, userinfo, JWKS) and the plugin OAuth token exchange, and that one sends no AbortSignal of its own, so it keeps undici's five minutes rather than inheriting a model setting. - The derived value is floored: the schema accepts any positive number and undici rejects a fractional headersTimeout. |
||
|
|
bc10fba389 |
feat(plugins): TREK_PLUGINS_IGNORE_TREK_RANGE turns the version gate into a warning (#2226)
* feat(plugins): TREK_PLUGINS_IGNORE_TREK_RANGE turns the version gate into a warning A plugin whose author has not updated its `trek` range for the running TREK can now be installed, updated and activated when the operator sets TREK_PLUGINS_IGNORE_TREK_RANGE to a truthy value. Every gate (registry picker, post-extraction re-check, sideload, dev-link, activation) warns instead of refusing; a missing range is tolerated the same way; "install latest" takes the newest published version. The plugin-API version gate is not lifted and the Discover compatibility verdict stays truthful. The admin is warned at every step: each bypass is logged, install/upload/link/ update responses carry a `trekRangeBypassed` marker, and both admin panels show a "Version checks off" pill, an "Install anyway" confirm dialog before a registry install, the same notice after a path that could not ask first, and a persistent chip on the row while the plugin runs outside its range. Nine new i18n keys in every locale; wiki pages updated (Environment-Variables, Admin-Plugins, Plugin-Development, Security-Hardening). * refactor(plugins): one useRangeBypass hook behind both admin shells SonarQube flagged PR 2226 at 10.8% duplicated new code: the range-bypass logic had been added to the desktop and phone plugin panels as identical copies. The marker/warning types, the row chip, the "Install anyway" offer, the dialog copy and the confirm-or-notice state now live in useRangeBypass (next to useInstanceSettings, the existing shared-logic precedent); each panel keeps only its own dialog/sheet markup. * docs(claude): record the SonarQube gate rules and the no-English-placeholder i18n rule The CI SonarCloud gate (Sonar way, on new code: >=80% coverage, <=3% duplication, A ratings, hotspots reviewed) was only discoverable by waiting 20-25 minutes for the workflow. The root CLAUDE.md now states the conditions, the desktop/mobile shell-mirror duplication trap and its shared-hook fix, and how to check a PR with the sonarqube MCP first; client and server CLAUDE.md point at it. shared/CLAUDE.md says every locale needs a real translation — parity cannot tell an English placeholder from a translation. * docs(claude): keep CLAUDE.md to commands, invariants, gates and philosophy Verified every concrete claim in the five CLAUDE.md files against the code and fixed the stale ones: the websocket server is the Nest realtime gateway, MCP tools live in <domain>.mcp.ts files, the client "native shell" section described code that was never written, offline maps also prefetch vector basemaps, plus several renamed files and wrong table names. Then trimmed everything that drifts on its own: dates, migration history, counts, and inventories of stores, slices, domains, sync files and CLI commands. What stays is the commands, the invariants with the file that enforces each one, what CI actually runs, the reference implementations to copy, and the rules for new code. Each file now opens with that rule. |
||
|
|
ad2119efd6 |
docs(wiki): correct what reading each page whole turned up (#2036)
The last pass reviewed diffs, so it never saw a new paragraph contradicting an older one on the same page, or a long-standing claim nobody had checked. Plugin authors were told ctx.config carries their per-user secrets and that definePlugin takes a permissions key — neither is true, and both fail silently. FORCE_HTTPS was said to need TRUST_PROXY, which it does not. |
||
|
|
7da0080557 |
docs(wiki): bring the wiki in line with 4.0.0 (#2034)
* docs(wiki): correct the install and operations pages for 4.0.0 Quick Start passed docker an empty ENCRYPTION_KEY: an assignment prefix is not expanded on the same command line, so the server silently generated its own key instead of taking the one the page told you to set. The tag examples pinned to the 3.x line, the documented tmpfs size did not match the shipped compose file, and several .env values were described as reaching the container when compose never interpolates them. * docs(wiki): match the MCP reference to the registered surface The scope table was missing the whole Collections group and the totals said 27 scopes across 13 groups where the code registers 29 across 14. The Cloudflare link on the setup page pointed at an anchor on its own page instead of the heading on Troubleshooting. * docs(wiki): correct the plugin and admin pages Three links to Plugin-Development carried a .md suffix, which does not resolve on the wiki. The admin pages described tabs, permissions and storage behaviour that had moved on. * docs(wiki): bring the feature pages back in line with the app Costs still documented the old panel, where categories could be added, renamed, reordered and deleted; they are fixed now and the panel is a day-grouped ledger with settlements. Trip sharing, journeys, maps, packing, reservations and the account pages had all drifted in the same way. * docs(wiki): cover the pages the first pass did not reach The MCP catalog listed 168 of the 201 registered tools; the settlement tools and rate_place were missing here and the Collections family from the addon page. Several resource rows claimed a trips:* scope where the handler asks for trips:read. * docs(wiki): tighten the corrections a review picked apart The audit-log resource is the row id, not the credential id; an admin password reset does not bump password_version the way the page implied; and a few of the new paragraphs described behaviour more confidently than the code supports. * docs(wiki): fix what a last read-through caught Costs shows every figure in your display currency, not the trip's, and an expense with no payer still counts against the members it is split between. Studio's cutoff is a 1024px viewport rather than phones alone, and the Integrations tab is gated on the providers an admin has configured. * docs(wiki): the last few the review caught A passkey satisfies the MFA policy everywhere except the WebSocket handshake, which still asks for TOTP, so a passkey-only account under that policy gets no live updates. Mobile optimizes a day from two places, not three. The ctx.db row carried an unescaped pipe that split the table, and the Backups table linked with a wiki link whose pipe did the same. |
||
|
|
38f3cb3101 |
fix(server): the second pass over this branch's own fixes
An adversarial review of what had already landed here turned up three that
were wrong, and they are the reason for this commit.
The CSP change removed 'unsafe-eval', which is not leftover: heic-to's
libheif build initialises embind through new Function(), and without it every
iPhone .heic upload fails in the browser. 'wasm-unsafe-eval' alone was tried
once already and was not enough (
|
||
|
|
305b113d5f |
Feat/storage driver (#1949)
* feat(storage): storage key validation, driver contract suite, LocalDriver * feat(storage): MirrorDriver composite backend * feat(server): add TREK_UPLOADS_DIR env var for the uploads root * feat(storage): settings-backed registry, StorageService facade, module wiring * test(storage): pin src/nest/storage coverage thresholds * feat(storage): multer upload options factory * refactor(files): spool trip-file uploads through storage * refactor(collab): spool note attachments through storage; normalize files/ prefix * refactor(journey): spool journey media uploads through storage * refactor(trips): spool trip cover upload through storage * refactor(places): spool place-image and collection uploads through storage * refactor(auth): spool avatar upload through storage * fix(server): consolidate allowed_file_types onto AllowedFileTypesService * fix(storage): default defParamCharset to utf8 in the upload factory * test(db): re-point the trailing-migration guard at the trip_files prefix strip * fix(storage): age-gate the boot spool sweep * test(files): key FILE-P02 residue checks on upload size * test(storage): raise src/nest/storage coverage pin * refactor(platform): serve /uploads routes through storage * refactor(files): serve trip-file downloads through storage * refactor(memories): serve photo bytes through storage * refactor(maps): stream place-photo bytes through storage * refactor(share): stream shared place-photo bytes through storage * refactor(journey): serve public journey assets through storage * fix(share): answer place-photo cache miss with 204 like the maps proxy * test(server): close serving-swap gaps surfaced by the full tier * test(storage): raise src/nest/storage branches pin * refactor(place-photos): route place-photo cache through storage * refactor(places): reclaim place images and collection covers through storage * refactor(trips): trip covers through storage * refactor(auth): avatar reclaim through storage * refactor(collab): note-file deletion through storage * refactor(files): trash deletion through storage * refactor(memories): trek photo cache internals through storage * refactor(memories): thumbnail service category-addressed * refactor(memories): immich upload reads through storage; drop uploads-root * refactor(journey): photo deletion through storage * fix(memories): reclaim orphaned trek photo cache objects in the ttl sweep * feat(journey): journey-thumbs orphan sweep and delete-site derived-artifact reclaim * test(server): close slice-4 gaps surfaced by the full tier * test(coverage): raise slice-4 domain pins * refactor(backup): list, existence and delete through storage * refactor(backup): download through storage sendToResponse * refactor(backup): create backup through per-category storage enumeration * refactor(backup): restore and upload-restore through storage * refactor(backup): auto-backup retention through storage * refactor(server): boot dir-creation to driver init * test(server): close slice-5 gaps surfaced by the coverage tier * test(coverage): raise slice-5 backup pin * test(server): resolve async backupFileExists mocks for the tests typecheck * test(server): pin ranged-read stat and zero-byte roundtrip in the storage driver contract * feat(server): TREK_S3_* env wiring — schema, s3 namespace, all-or-nothing boot rule * feat(server): S3 driver core — aws-lite client seam, stat/delete, driver-owned deadlines * refactor(server): type the aws-lite S3 client via s3-types reference * feat(server): S3 driver getStream and list — ranged full-object stat, iterator pagination * feat(server): S3 driver put — bounded-peek routing, Upload inactivity deadline * fix(server): S3 driver Upload monitoring — Transform interposition, stream cleanup * feat(server): env-declared s3-main storage backend; settings-declared s3 rejected * test(server): env-gated S3 driver contract suite against MinIO * fix(server): S3 driver zero-byte put — work around aws4 duplicate Content-Length signing defect * fix(server): scope the zero-byte put workaround to buffered bodies; bind test MinIO to localhost * ci(server): MinIO-backed S3 driver contract job * ci(server): align s3-contract shim comment and MinIO bind with references * docs: S3 storage backend configuration and off-box backup mirroring * docs: restore README formatting, keep S3 additions only * ci(server): make live-MinIO contract runs manual-only (AIStor licensing) MinIO's community line is discontinued entirely; the maintained successor, AIStor, requires a license key that can't safely live in a shared CI runner. The s3-contract CI job is removed; live-provider contract runs against MinIO/AIStor are now a manual, license-gated procedure documented in docker-compose.minio-test.yml's header. * chore(server): final-review polish — stale CI refs, dockerignore key, boundary pins, zero-byte tempfile contract case * expose admin ui * feat(shared): storage backend type registry, wire schemas, category relocation * feat(server): accept settings-declared s3 backends — shared-schema options, decrypt-at-build, registry preview() * feat(server): remove TREK_S3_*/TREK_UPLOADS_DIR — tombstone boot rule, built-in override as the relocation path * feat(server): deriveSecurity.encryptionKeySet and storage secret plumbing (gate, encrypt, unmask, mask, redact) * chore(server): drop storage-secrets import that only Task 8's probe helper will use * feat(server): seed-once storage-config.json boot import — fail closed on any invalid seed * feat(server): registry snapshot() — effective storage config with provenance * feat(server): api/admin/storage GET/PUT — masked secrets, preview-gated saves, wired reload, audits * feat(server): api/admin/storage/test — per-target ephemeral probes, mirror targets probed individually * test(server): e2e coverage for api/admin/storage — guards, managed refusal, envelope, probes * test(server): give e2e harness DBs the app_settings table the storage registry reads at boot * test(coverage): raise pins after the storage admin-config slice * fix(server): final-review polish — encryption-gate wording, all-field sentinel guard, README/e2e notes * test(server): storage slice-1 review follow-ups — mirror s3-replica probe decrypt, all-encrypted seed without key, test-route 401 * feat(i18n): storage admin domain + tab label in every locale * feat(client): adminApi storage endpoints — getStorage, updateStorage, testStorageBackend * feat(client): storage admin draft-document helpers + relative-time util * feat(client): schema-driven storage BackendForm — fields by kind, mask echo, encryption banner * feat(client): admin storage panel — backends list, category map, health strip, one-PUT save * feat(client): storage tab on the admin page * feat(client): storage admin panel and section on the phone shell * fix(client): block renaming a storage backend onto an existing name * feat(server): allow mirrors on any storage category — lift the backups-only rule * feat(i18n): replicas-on-primary mirror strings in every locale * feat(client): mirror fold/synthesize model helpers for replicas-on-primary * feat(client): BackendForm mirror-targets composer; raw mirror type hidden * feat(client): desktop storage panel folds mirrors into their primaries * feat(client): phone storage panel folds mirrors into their primaries * fix(client): strip removed backends from remaining mirror replicas — no phantom refs * feat(storage): retire photos as a configurable category — served-only via the ServedCategory seam * feat(i18n): descriptive storage category names and descriptions in every locale * feat(client): descriptive category names, descriptions and id badges in the storage panel * docs(storage): fix stale nine-category comments after the eight-category shrink * docs: storage configuration via the admin UI and seed file — README + compose * docs(wiki): Admin Storage page and storage cross-links * docs(server): storage domain blueprint entry; TREK_PLACE_PHOTO_DIR tombstone clarifier * refactor(server): drop the storage env-var tombstones — the variables never shipped * docs: storage config is simply new in v4 — drop the removed-variables story * feat(shared): backfill-status and usage wire schemas on the storage admin state * feat(server): MirrorDriver.backfill — prefix-scoped, size-compared, cancellable replica catch-up * feat(server): one-at-a-time storage backfill jobs + the storage events bridge * feat(server): storage usage scan — nightly cron, on-demand service, persisted with computedAt * feat(server): replica_failure admin notifications — events bridge, hourly debounce, channel registration * feat(i18n): replica-failure notification text in every locale * feat(server): storage backfill and stats-refresh admin endpoints * feat(client): adminApi backfill and stats-refresh endpoints * feat(i18n): storage sync and usage strings in every locale * feat(client): desktop storage panel — sync now, usage display, backfill polling * feat(client): phone storage panel — sync now, usage display, backfill polling * fix(client): per-category usage line on the phone storage panel * docs: sync now, usage stats and replica-failure notifications * test(server): admin scope now includes replica_failure, not just version_available Commit |
||
|
|
5f4fa30416 |
docs: say where the outbound proxy switch actually lives
The variables only take effect when Node runs with NODE_USE_ENV_PROXY=1, and that is set in the image. This page also covers Helm, Unraid and source installs, where nothing sets it, so following it there changed nothing. Also recommend NO_PROXY. Without it the proxy sees every request TREK makes to itself, including the container health check. |