Repository navigation
Conversation
Interrail holders can now pick their pass in the header. Every train in the SNCF feed counts for them, since each takes a pass-holder reservation, and every result says that no open data tells whether a pass-holder seat is left. The data-refresh script now also writes public/data/interrail.json: the whole feed in a compact format that stores each service once with a bitmask of the dates it runs, so the full feed stays a small static file. Switching between a MAX pass and Interrail opens the page again on the other snapshot; the worker, the boot preload and the copy (11 locales) follow the pass. Refs #81
davd-gzl
force-pushed
the
interrail-pass
branch
from
October 5, 2026 06:40
945594a to
62fa586
Compare
MAX JEUNE / MAX SENIOR read train-api's max-jeune file and Interrail its interrail file. When train-api is off, slow (8 s) or unreachable, the app reads its own snapshot as before. The worker reads the same source as the page. The test servers strip the train-api meta so the gates run on the bundled snapshot.
davd-gzl
marked this pull request as ready for review
October 5, 2026 07:15
…p the prerender off it - Skip train-api when it is over 36 h old or every date has passed, unless the snapshot is out of reach too - Bound the train-api wait to the server's answer, not the download - Service worker: train-api timetables are network-first with an offline copy (they share the site's origin, so they were cached as static assets) - Prerender blocks off-server requests and checks the train-api meta survives
The test needs more than 30 destinations from Paris, and a blind today+5 days can land on a day with far fewer free MAX seats. That made the daily Pages deploy fail since 10 October.
davd-gzl
force-pushed
the
interrail-pass
branch
from
October 12, 2026 07:48
f458219 to
f3f73d1
Compare
… and plane How does it work? now lists the rules of each pass: MAX JEUNE (16 to 27) and MAX SENIOR (60+), the booking window and daily limits, who can buy Interrail (residents of the 33 countries, Eurail for everyone else) and the special case for people living in France. An exact trip shows one line comparing its CO2 by train with driving alone and flying, using ADEME factors over the straight-line distance (src/util/eco.ts). Refs #92
This was referenced Oct 12, 2026
The other pass's timetable now loads while the page stays up: the current results dim under a Loading pill until the new search is ready, and each timetable loads once per visit, so switching back is instant.
# Conflicts: # README.md # index.html
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Before: the app only shows SNCF trains with a free MAX seat, read from its own daily snapshot, so an Interrail holder can't see the TGV INOUI, Intercités, night and international trains they can actually take.
After: the header's pass picker offers MAX JEUNE, MAX SENIOR and Interrail. Timetables come from train-api (refreshed daily), with the app's own snapshots as the fallback. Interrail shows every train in the SNCF feed, international stops included, and every result page says that no open data tells whether a pass-holder seat is left. "How does it work?" now says who can use each pass and how, including the special case for people living in France, and an exact trip shows its CO₂ by train against driving and flying.
Covers the "pass as a choice" and "app on the API, falling back to the static snapshot" checkboxes of #81.
Screenshots
Taken from this branch's build against the live train-api, for Monday 19 October.
Try it
Then open http://localhost:5173/?card=interrail&mode=from&from=PARIS%20(intramuros) and switch passes in the header. For the CO₂ line, open an exact trip: http://localhost:5173/?card=interrail&mode=od&from=PARIS%20(intramuros)&to=TOULOUSE%20MATABIAU.
How
index.htmlnames train-api in<meta name="train-api">.loadDatasetreads<base>/sncf/<pass>/all.json(MAX JEUNE and MAX SENIOR both readmax-jeune; Interrail readsinterrail) andindex.jsonfor freshness. It falls back to the bundled snapshot when train-api is off, slow (8 s) or unreachable, and then to the sample fixture. The CSP allowsoffware-apps.github.io. The search worker reads the same source as the page, so its cache dump always describes the page's trains.src/data/compact.ts): each service stored once, with a bitmask of the dates it runs. The full SNCF feed (358,954 trains) comes to 1.3 MB.fetch-datastill writestgvmax.jsonand now alsointerrail.json, so the app keeps working without train-api (constitution §5).INTERRAIL_PROFILEtreats every running train as bookable, drops the MAX-only international exclusions and setsseatKnown: false.profileForCardmaps the pass to its profile.main.ts, the worker and thetheme.jspreload pick the pass fromcard=in the link, or else the saved pass. Switching between a MAX pass and Interrail loads the other timetable while the page stays up: the current results dim under a Loading pill until the new ones are ready, and each timetable loads once per visit, so switching back is instant. Switching between the two MAX passes re-runs straight away.t()reads<key>_irwhen the seat is unknown. There are new keys for the pass name, its how-to line and the seat notice. Booking still opens SNCF Connect, which sells pass-holder reservations.src/util/eco.ts, numbers formatted for the locale). The README's "Supported passes" table now gives the same rules, with the CO₂ comparison under it.docs/user-flows.md,README.md,llms.txtandapi.jsonare updated.Checks
tsc,npm test(234 passed, including train-api and fallback tests intests/interrail.test.tsand the CO₂ figures intests/eco.test.ts),npm run build,npm run verifyandnpm run test:e2e(25/25, including a pass switch that checks the page never reloads) all pass. The new notice and CO₂ line wrap without cutting text at 390 px in English, French and German. With train-api unreachable, the app falls back tointerrail.jsonwith no CSP errors.Refs #81, refs #92