Skip to content

feat: refresh long-lived tabs after a new build is deployed - #1040

Open
lucamzanon wants to merge 6 commits into
bulwarkmail:mainfrom
lucamzanon:feat/build-refresh
Open

lucamzanon wants to merge 6 commits into
bulwarkmail:mainfrom
lucamzanon:feat/build-refresh

Conversation

@lucamzanon

@lucamzanon lucamzanon commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Long-lived tabs never notice a deploy: Bulwark talks to the JMAP server directly, so a tab can sit on the inbox for days without ever asking Next.js for a page, and keeps running the JavaScript it loaded before the upgrade. Users then report "the new feature isn't there" until they happen to reload.

This adds a small self-refresh mechanism:

  • next.config.ts bakes NEXT_PUBLIC_BUILD_STAMP (short commit + build timestamp, unique even for rebuilds of the same commit) into both bundles.
  • GET /api/system/build returns the stamp of the build serving the request (Cache-Control: no-store, no other information).
  • components/build-refresh.tsx, mounted in the locale layout, compares the two every 5 minutes and whenever the tab becomes visible or comes back online (rate-limited to once a minute). On a mismatch a hidden tab reloads silently, so the user comes back to the current build; a visible tab keeps its state and shows a top banner with a reload button, and reloads by itself as soon as it goes to the background.
  • New i18n namespace build_refresh (title, reload) in all locales, English text where not translated.

Tests: components/__tests__/build-refresh.test.tsx covers same build (silent), visible tab (banner, then reload once hidden), hidden-tab reload and re-check on visibility, and the no-stamp case. tsc and translation tests pass.

Bulwark talks to the mail server directly, so a tab can sit on the
inbox for days without asking Next.js for a page and never notices a
deploy. Every build now bakes a unique stamp; /api/system/build
returns the server's. The client polls it every 5 minutes and on
visibility/online changes: a hidden tab reloads silently, a visible
one gets a banner with a reload button.
Lite is a static bundle: there is no /api/system/build to ask and no
server build to follow, and its verifier rejects a client chunk that
names an undocumented server endpoint. The banner is not mounted under
Lite, and the stamp lookup answers "unknown" there.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant