From 3e4f43137355455f014e38ba9c9c7ac61c8b1c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 1 Oct 2026 00:48:46 +0200 Subject: [PATCH 1/2] =?UTF-8?q?chore(release):=20v1.39.6=20=E2=80=94=20a?= =?UTF-8?q?=20critical=20framework=20fix,=20a=20workout=20token,=20a=20lab?= =?UTF-8?q?=20scan=20that=20keeps=20every=20reading,=20and=20an=20instant?= =?UTF-8?q?=20restore=20preview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 43 +++++++++++++++++++++++++++++++++++++++++++ docs/api/openapi.yaml | 2 +- package.json | 2 +- public/sw.js | 2 +- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0a18cb1b..ee6a16aa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,48 @@ # Changelog +## [1.39.6] — 2026-10-01 + +A critical security fix for the web framework, a workout token for devices +and bridges, a lab scan that no longer drops incomplete readings, and a +restore preview that appears at once. A full-history import can no longer +run beside its own retry, and the nightly clean-up steps around a restore. + +### Security + +- **Next.js 16.3.6.** Fixes a critical advisory against 16.2.0 to 16.3.5. + The floors of fast-uri (3.1.8), ip-address (10.7.1) and dompurify + (3.4.16) are raised for newer advisories; development-only copies of + @grpc/grpc-js, brace-expansion and undici 7 too. + +### Added + +- **Workout token.** Settings → API → Workout tokens mints a token with the + `workouts:write` scope (`POST /api/tokens/workouts`, recent confirmation + required, at most ten live tokens). It reaches `POST /api/workouts/batch` + only; workouts written with it carry the source `EXTERNAL`, and a body + that names a source is refused with 422. (#1054) + +### Fixed + +- **Lab scan review.** Saving is all or nothing over the selected readings; + incomplete ones are marked with a summary and focus on the first, instead + of being left out silently. (#1055) +- **Restore preview.** The counts a backup holds are stored with it + (migration 0364) and the preview answers from them; older backups are + read once and then stored. The query no longer retries, and only a real + schema failure is reported as one. (#1031) +- **Dashboard quick-add** follows the server's `intakeActionable` and no + longer offers an ended course. (#1040) +- **Dense glucose inside 90 days** is bucketed per local hour for the series + when the window holds more than 10 000 readings; statistics cover every + reading. The doctor report keeps glucose raw inside 90 days. +- **Full-history import lane.** Admission jobs expire after 16 hours instead + of pg-boss's default 15 minutes, each run holds an advisory lock on its + kind and account so a retry cannot run beside it, and the Google Health + import stops at its job budget as incomplete. (#1023) +- **Tombstone purge** deletes per account under the restore lock and leaves + an account being restored for the next night. (#1031) + ## [1.39.5] — 2026-09-28 A server with a per-minute heart-rate history stays inside its memory: the diff --git a/docs/api/openapi.yaml b/docs/api/openapi.yaml index 60b72dce6..20072acf6 100644 --- a/docs/api/openapi.yaml +++ b/docs/api/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: HealthLog API - version: 1.39.5 + version: 1.39.6 description: >- Self-hosted personal-health-tracking PWA — public API surface for the iOS native client and external ingest. diff --git a/package.json b/package.json index f9dc6e7a7..7dafc625f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "healthlog", - "version": "1.39.5", + "version": "1.39.6", "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", diff --git a/public/sw.js b/public/sw.js index d63ea1462..aee0ab404 100644 --- a/public/sw.js +++ b/public/sw.js @@ -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.39.5"; + /* @sw-version-fallback */ "v1.39.6"; 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/*` From 8ea9322c8efc2ef9c319933dba1f0b1db50062ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 1 Oct 2026 00:50:18 +0200 Subject: [PATCH 2/2] docs(changelog): say which charts the 1.39.5 pulse buckets reach --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee6a16aa8..745666dcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,7 +64,7 @@ right after a start. counted the import as unfinished and started over on every retry and start. It may now run to 10 000 pages. (#1023) - **Dense pulse inside 90 days.** A pulse window with more than 10 000 - readings is bucketed per local hour for charts (mean with low and high, + readings is bucketed per local hour in the series route (the iPhone app's charts and API clients) (mean with low and high, `hour:` ids), read per day for the doctor report, and the resting-pulse estimate on the insights page is computed per day in the database. Sparse pulse data stays raw. (#1023)