chore(release): v1.38.11 — sign out everywhere means everywhere

Version anchors, the OpenAPI document, the changelog entry, and the
README sentence that still declared immunization records out of scope
while the vaccination record has shipped since v1.37.3.
This commit is contained in:
Marc-André Bombeck committed 2026-09-08 20:23:30 +02:00
1 parent 076c2f9c5d
commit e0cf6c2403
5 files changed
+56 -4

No files matched your search

+52
View File
@@ -1,5 +1,57 @@
# Changelog
## [1.38.11] — 2026-09-08
"Sign out everywhere" now means everywhere, a refresh cannot outrun a
revocation, and the idempotency cache can no longer answer for a credential
the route has not seen.
### Fixed
- **"Sign out everywhere" signs out the other phones, not the one pressing
it.** A native login is two rows: a refresh token and the access token it is
paired with, and the Bearer check consults only the second. Revoking the
refresh tokens alone, which is what the button did, left every other device
working until its access token ran out, up to a day on the default policy.
Worse, a phone pressing the button described itself to the server as a
browser session, so the exception meant to spare the caller matched nothing
and the phone revoked its own refresh token: it was the one device signed
out, at its next rotation. Both ends are fixed. The button revokes the paired
access tokens of every other device inside the same transaction, and a
Bearer caller is named by its access token so its own login is the one kept.
Long-lived API tokens from the settings page are untouched, as before.
- **A refresh that overlaps a revocation loses.** Rotation read the presented
refresh token as live, minted a new pair, and only then marked the old row
consumed with a condition that checked "not yet used" but not "not yet
revoked". A sign-out-everywhere or a credential rotation landing in that
window was overtaken: the update still matched, and the pair minted a moment
after the family ended was the one live login left. The condition now
includes the revocation, the pair minted inside the window is retired, and
the client hears `revoked`, which it answers with a fresh sign-in, rather
than `already_used`, which it would retry. Pinned by an integration test that
revokes the family from inside the window against real Postgres.
- **The idempotency cache is keyed by the authority a request carries.** A
retry that replays a cached response runs before the route's own permission
check, by design, so what the cache could answer had to match what the route
would allow. Two gaps: a delegate whose grant had been replaced by a narrower
one, or whose scope had been edited in place, still matched the cell they
filled under the wider grant, because the replay checked only that a live
grant existed; and a narrow-scoped API token of the same account could read
a cell filled by a wildcard credential on a route outside its scope.
Delegated cells now fold the grant's identity, level and scope into the key,
and a narrow token's cells are keyed by the token, so any change of authority
lands a retry in a fresh cell where the route decides. Cookie sessions and
wildcard tokens acting on their own record are keyed byte-for-byte as before;
no client changes.
### Changed
- **README: immunizations are in.** The record list still said immunization
records were deliberately out of scope; the vaccination record has shipped
since v1.37.3.
## [1.38.10] — 2026-09-06
The nightly off-host backup streams and fits a small container, and a
+1 -1
View File
@@ -36,7 +36,7 @@ Try the [live demo](https://demo.healthlog.dev) to see a working install — sig
- **Every vital on one timeline.** Weight, blood pressure, pulse, glucose, body composition, sleep, SpO₂, respiratory rate, mood, and cycle tracking — charted with trends, moving averages, and clinical reference ranges (ESH 2023, ADA 2024), overridable with the targets your clinician set.
- **Clinical signals, opt-in and additive.** Validated self-checks for mental wellbeing and sleep (WHO-5, PHQ-9, GAD-7, Sleep Condition Indicator — official questionnaire wording, calm crisis-resource handling), grip strength, a 0–10 pain score, waist and body measurements, and a longevity lab panel — each added through one signal registry, so a new signal wires into charts, correlations, the coach, the FHIR map, and the API at once.
- **Records, structured.** Allergies and family history as encrypted structured records that flow into the doctor report, plus lab values you key in or scan from a printed report — OCR extracts the stated values, units, and dates for you to review and confirm before anything is saved. HealthLog transcribes what a report says; it never interprets or diagnoses from it. (Immunization records are deliberately out of scope.)
- **Records, structured.** Allergies and family history as encrypted structured records that flow into the doctor report, plus lab values you key in or scan from a printed report — OCR extracts the stated values, units, and dates for you to review and confirm before anything is saved. HealthLog transcribes what a report says; it never interprets or diagnoses from it. A vaccination record keeps a lifetime immunization log, doses grouped under the disease they protect against, and prints in the doctor report.
- **A document vault for the paper trail.** An opt-in module stores every letter, report, and scan encrypted at rest — PDFs and photos preview inline, Office and text files stay download-only, and nothing user-uploaded can ever execute in the app. One searchable timeline with type, condition, and year filters, drag-and-drop and paste-to-upload, bulk filing, undo-able delete with a 30-day grace, and per-file/per-account limits the operator tunes.
- **Context that explains the numbers.** An opt-in environmental module folds weather, daylight, and temperature in as influence signals (winter darkness against mood, heat against blood pressure) using a home location you set, so a pattern has somewhere to point.
- **Your devices, one server.** Withings, WHOOP, Oura and Polar sync over OAuth2, Google Health connects Fitbit and Pixel Watch through your own Google Cloud client, Nightscout streams CGM glucose, an Apple Health `export.zip` folds your full history in, and the native iOS app streams HealthKit live. A per-metric source priority decides which reading is canonical when wearables overlap.
+1 -1
View File
@@ -1,7 +1,7 @@
openapi: 3.1.0
info:
title: HealthLog API
version: 1.38.10
version: 1.38.11
description: >-
Self-hosted personal-health-tracking PWA — public API surface for the iOS native client and external ingest.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "healthlog",
"version": "1.38.10",
"version": "1.38.11",
"description": "Self-hosted personal-health-tracking PWA with Withings integration, AI insights, and doctor-report PDF export.",
"license": "PolyForm-Noncommercial-1.0.0",
"homepage": "https://healthlog.dev",
+1 -1
View File
@@ -36,7 +36,7 @@ try {
// v1.4.38.4 → v1.4.42. Do not hand-edit; bump `package.json` and rebuild.
const CACHE_VERSION =
(typeof self !== "undefined" && self.__APP_VERSION__) ||
/* @sw-version-fallback */ "v1.38.10";
/* @sw-version-fallback */ "v1.38.11";
const STATIC_CACHE = `healthlog-static-${CACHE_VERSION}`;
const PAGE_CACHE = `healthlog-pages-${CACHE_VERSION}`;
// v1.18.6 — read-only data cache for a curated allowlist of safe GET `/api/*`