timescale.info
Sign inSign up

How OpenChronology was built

Every merged pull request of openchronology/timeline-app, its first week of commits and its releases; and before them the 2020 PureScript editor, from snapshots of its deleted repositories in the Wayback Machine. Written to this server through the HTTP API.

327 moments · 2020-03-09T00:15:08Z CE – 2026-11-02T20:11:21Z CE · by @athan · @athan

#117 · Give downloads a page of their own

  • timeline-app
  • pull request

Closes #111. ## The page `/download` replaces the header's Download dropdown, which linked to GitHub assets. - **Your system first.** The page reads the browser's `User-Agent` and `Sec-CH-UA-Platform` on the server, so there's no flicker on load. - It shows "Desktop app for Windows/macOS/Linux" with a large **Download for …** button and the alternatives beside it. - On macOS, Apple silicon is the main button, with Intel next to it and a hint on how to tell which Mac you have. - On phones, tablets and Chromebooks, it offers the website and the offline file instead. - **Desktop.** A card for each operating system lists every file with its size; your system's card comes first and is marked *Your system*. A card for the offline browser file follows. - **Server.** Debian 13 and Ubuntu 24.04 each have a one-line command to copy, with a **Copy** button: ``` curl -fLO https://github.com/openchronology/timeline-app/releases/…/openchronology-server-debian13-amd64.deb && sudo apt install ./openchronology-server-debian13-amd64.deb ``` `apt install ./…deb` also installs PostgreSQL, which is why apt is used rather than `dpkg`. - Each server card also has a direct `.deb` link. - A Linux browser that names its distribution (Firefox on Ubuntu does) puts that card first. - Docker Compose covers other systems. - The section ends with a note that more server platforms will be added. - **Verify and build:** the SHA-256 checksums, the source archives, and all releases. ## Release data - The buttons come from GitHub releases. `platform/lib/latest-release.js` reads `api.github.com/repos/openchronology/timeline-app/releases/latest` on the server, with a 3 s timeout. That gives the version, release date, release-notes link, and each asset's address and size. - The result is cached for 10 minutes, or 1 minute after a failure, which keeps well inside GitHub's unauthenticated rate limit. - **Fallback:** if there's no release (the case today) or GitHub can't be reached, links use the fixed `releases/latest/download/ ` addresses. - Only `https://` asset addresses are used. - `RELEASES_API_URL` overrides the API address, for mirrors and tests. ## Adding platforms `platform/lib/releases.js` lists the desktop files, the offline file and the server packages. `test/releases.test.mjs` checks them against the release workflow's own lists (`scripts/desktop/packages.mjs`, `scripts/server-targets.mjs`), so the page can't drift from what's attached to a release. A new server platform is one entry in `SERVERS`. ## Tests - **Unit tests** cover: - asset names matching the workflow; - system detection for Windows, macOS, Linux, Android, iOS, ChromeOS and client hints; - Ubuntu and Debian detection; - links, sizes and install commands with and without a release, and non-HTTPS assets being ignored. - `test/next-platform.mjs`, against a mock GitHub API: - the header link; - for a Windows browser: the version, the primary Windows button with the release's exact link and size, and fallback links for files the release lacks; - for Ubuntu: its card first, and the one-liner with the release's address; - for a phone: the browser option; - in the browser part: navigating from the header, the Copy button, and no horizontal overflow. - Passes in Chromium, Firefox and WebKit. - `test/next-postgres.mjs` points at an unreachable API and checks the fallback links. - Screenshots at desktop and phone widths looked right. ## Also: the stored-windows test's other flake The first CI run failed Firefox's `viewport-store-browser` again ("the first view was not kept after hiding the page"), even with #114's fix. On a one-CPU container it failed 2 runs in 15. **Cause:** this time nothing was lost. The stored windows were identical before and after hiding. The test expected the first view (0 to 20) to be stored in exactly the window −5 to 25. But going to bounds animates through the views in between, so on a slow machine the view is covered by a window fetched on the way (such as −10 to 30), and…

Sources

Open #117 · Give downloads a page of their own in the timeline