feat(settings): add a colophon, with a link to the source

Production notes at the foot of Settings: where this came from, what it
was built with, what it is set in, and what it stores where.

The schema version is real, read from the dataset rather than written
into the copy, because it is the number that matters when someone opens a
backup and wonders what will read it.

The build stamp is new plumbing, and small: build.ts already computed a
`version` for the service worker, so the app bundle now gets the same
value. Read through a try/catch accessor, never a `typeof process` guard
(AGENTS.md §2) — and genuinely absent in development, which is the normal
case and reads as "development" rather than as an error. A caller's own
BUILD_VERSION is printed as given; only build.ts's default timestamp is
translated, because "1788379707862" tells a reader nothing and
"2026-09-02" tells them what they wanted. ISO, not a locale format: this
string ends up in bug reports and should not vary by who reads it.

rel="noreferrer" on the link is deliberate rather than boilerplate. An
app whose whole position is that the data never leaves the browser should
not hand this page's URL to another origin on the way out.

No licence is claimed for the app: there is no LICENSE file in the
repository, and asserting one in the UI would be worse than saying
nothing. The font licences are committed beside the files, so those are
named.

Verified: both build paths inline the value and leave no bare process.env
reference in the bundle (BUILD_VERSION=v1.4.0-test appears literally, the
default appears as a timestamp), and the section was read in both themes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5 committed 2026-09-02 22:09:14 +02:00
1 parent a73cff13a3
commit 61e7093c36
6 files changed
+162 -1

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
/**
* The build stamp shown in the colophon.
*
* `build.ts` already computes a version for the service worker; this exposes
* the same value to the app bundle. It is genuinely absent in development,
* which is the normal case rather than an error.
*/
/**
* try/catch, NOT a `typeof process` guard — see AGENTS.md §2. Bun inlines the
* literal only when the variable is set; unset, the bare reference reaches the
* browser and throws before the app boots, and a `typeof` guard would survive
* inlining and discard the inlined value.
*/
export function readBuildVersionEnv(): string | undefined {
try {
return process.env.BUN_PUBLIC_BUILD_VERSION;
} catch {
return undefined;
}
}
/** A millisecond epoch, which is what build.ts falls back to. */
const EPOCH_MS = /^\d{10,}$/;
/**
* `BUILD_VERSION` may be anything the person building chose — a git sha, a tag,
* a release number — so an unrecognised value is printed as given rather than
* reformatted into something it is not. The one shape worth translating is
* build.ts's own default, a `Date.now()` timestamp, because "1756809600000"
* tells a reader nothing and "2026-09-02" tells them what they wanted to know.
*
* ISO rather than a locale format: this string appears in bug reports against
* the linked repository, and it should not vary by who is reading it.
*/
export function describeBuild(raw: string | undefined): string {
if (!raw) return "development";
if (EPOCH_MS.test(raw)) {
const at = new Date(Number(raw));
if (!Number.isNaN(at.getTime())) return at.toISOString().slice(0, 10);
}
return raw;
}
export const BUILD_VERSION = describeBuild(readBuildVersionEnv());