From e8c425bb4b4c9adab87b56a88d6e8d9e1b884edb Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sun, 6 Sep 2026 06:53:29 -0700 Subject: [PATCH 1/3] fix(site): keep a refusal a browser would not store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit readPreference fell back to the in-memory answer only when localStorage threw. A browser can let the read succeed and refuse the write — Safari's private mode and a full quota both do — and there the stored value came back null, so an explicit "Do not allow" was read as no answer at all: the banner stayed up and, outside a prior-consent country, the tag loaded anyway. The answer given on this page now governs it whenever storage has none of its own, however storage failed to keep it. Claude-Session: https://claude.ai/code/session_013MqwrF5NA179khDtEQdib5 --- site/src/components/Analytics.astro | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/site/src/components/Analytics.astro b/site/src/components/Analytics.astro index 9e40de7..ea9a88c 100644 --- a/site/src/components/Analytics.astro +++ b/site/src/components/Analytics.astro @@ -121,12 +121,17 @@ const enabled = Boolean(measurementId) && import.meta.env.PROD; function readPreference() { try { var stored = window.localStorage.getItem(STORAGE_KEY); - return stored === "granted" || stored === "denied" ? stored : null; + if (stored === "granted" || stored === "denied") return stored; } catch (_) { // A locked-down browser throws on access rather than returning - // null. The in-memory answer still governs this page. - return memoryPreference; + // null. } + // Storage had no answer, or would not give one. Either way the + // choice made on this page still governs it: a browser can let the + // read succeed and refuse the write — Safari's private mode and a + // full quota both do — and reading back null there would discard an + // explicit refusal and start measuring anyway. + return memoryPreference; } function writePreference(preference) { From 1af0090a03e2f2e759f57420bd0794ac3008b0e8 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sun, 6 Sep 2026 06:58:11 -0700 Subject: [PATCH 2/3] fix(site): make a withdrawal reach the tabs already open This file has claimed since it was written that every other open tab is told about the change and acts on it. Nothing did. The storage listener lived inside subscribe, whose only caller is the privacy page's control, and that subscriber redraws its own status text rather than re-applying the preference. So a reader with a documentation page open who went to /privacy and denied kept being measured in the tab they left behind, until it happened to reload. Applying the preference on the storage event is what makes the claim true. Claude-Session: https://claude.ai/code/session_013MqwrF5NA179khDtEQdib5 --- site/src/components/Analytics.astro | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/site/src/components/Analytics.astro b/site/src/components/Analytics.astro index ea9a88c..baab1d3 100644 --- a/site/src/components/Analytics.astro +++ b/site/src/components/Analytics.astro @@ -314,6 +314,17 @@ const enabled = Boolean(measurementId) && import.meta.env.PROD; }, }; + // Every other open tab is told about the change and acts on it, which + // this file has claimed from the start and nothing did. The listener + // above reaches only subscribers, and the only subscriber is the + // privacy page's control, which redraws its own text. So a reader with + // a docs page open who went to /privacy and denied kept being measured + // in the tab they left behind until it happened to reload. Applying + // the preference here is what makes the claim true. + window.addEventListener("storage", function (event) { + if (event.key === STORAGE_KEY || event.key === null) apply(); + }); + function ready(run) { if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", run, { once: true }); From 966a51b4b03666621811c2e597c72cbc46f3e24f Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sun, 6 Sep 2026 07:03:22 -0700 Subject: [PATCH 3/3] Revert "fix(site): make a withdrawal reach the tabs already open" This reverts commit 1af0090a03e2f2e759f57420bd0794ac3008b0e8. --- site/src/components/Analytics.astro | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/site/src/components/Analytics.astro b/site/src/components/Analytics.astro index baab1d3..ea9a88c 100644 --- a/site/src/components/Analytics.astro +++ b/site/src/components/Analytics.astro @@ -314,17 +314,6 @@ const enabled = Boolean(measurementId) && import.meta.env.PROD; }, }; - // Every other open tab is told about the change and acts on it, which - // this file has claimed from the start and nothing did. The listener - // above reaches only subscribers, and the only subscriber is the - // privacy page's control, which redraws its own text. So a reader with - // a docs page open who went to /privacy and denied kept being measured - // in the tab they left behind until it happened to reload. Applying - // the preference here is what makes the claim true. - window.addEventListener("storage", function (event) { - if (event.key === STORAGE_KEY || event.key === null) apply(); - }); - function ready(run) { if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", run, { once: true });