Skip to content

fix(platform-web): broadcast broadcasted writes and resets while the signal is not observed - #247

Merged
dangreen merged 1 commit into
mainfrom
fix/broadcasted-unobserved-writes
Sep 8, 2026
Merged

fix(platform-web): broadcast broadcasted writes and resets while the signal is not observed#247
dangreen merged 1 commit into
mainfrom
fix/broadcasted-unobserved-writes

Conversation

@dangreen

@dangreen dangreen commented Sep 8, 2026

Copy link
Copy Markdown
Member

Why

BroadcastChannelStorage opened its channel only in sub, and syncedStored subscribes to the storage when the signal gets its first subscriber. set posted through this.#channel?.postMessage(...), so a write from a tab that did not observe the signal itself was silently dropped. del was a no-op, so $signal(undefined) never reached other tabs either. Probe in the browser runner, tab A writes and tab B listens:

no subscriber in writer tab:   target = "idle"     <- 'logout' lost
with subscriber in writer tab: target = "logout"
after $a(undefined):           target = "logout"   <- reset lost

The docs example, a logout button calling $authEvent('logout'), is exactly the first case: the tab with the button has no reason to observe $authEvent. The existing spec masked it by attaching an effect to the source signal before writing.

What

  • #open(key) creates the channel lazily with ??= and holds the single typeof BroadcastChannel check. set and sub share it; unsubscribing still closes and clears the channel, and the next write opens a fresh one.
  • del posts null, which the subscription handler already maps to the default value.
  • Tests: should post messages while the signal is not observed and should broadcast a reset.

Size

The lazy channel and the reset cost bytes in the only bundle of the package. The limit is re-pinned on the 0.05 kB step:

bundle before after limit
All publics (Gzip) 3399 B 3416 B 3.4 kB → 3.45 kB
All publics (Brotli) 3027 B 3039 B 3.05 kB

Checks

  • oxlint, tsc --noEmit, vitest run (60 tests, browser mode) and size-limit in packages/platform-web pass.

…e signal is not observed

The `BroadcastChannel` behind `broadcasted` was opened only by the storage subscription, which `syncedStored` starts with the first subscriber of the signal, and writes posted into that channel through optional chaining. A tab that wrote to the signal without observing it, the logout button case from the docs, posted nothing, and other tabs never heard about it. Resetting the signal to `undefined` went through the no-op `del`, so other tabs kept the old value. The channel is now opened lazily by the first write or subscription and reused by both, and a reset posts `null`, which subscribers already turn into the default value. The `platform-web` size limit is re-pinned for the extra 17 B gzipped.
@codecov

codecov Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.29%. Comparing base (82d45cf) to head (ab8db7f).

Files with missing lines Patch % Lines
packages/platform-web/src/broadcast.ts 60.00% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #247      +/-   ##
==========================================
- Coverage   83.32%   83.29%   -0.03%     
==========================================
  Files          98       98              
  Lines        2554     2556       +2     
  Branches      550      551       +1     
==========================================
+ Hits         2128     2129       +1     
  Misses        314      314              
- Partials      112      113       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dangreen
dangreen merged commit 2696386 into main Sep 8, 2026
8 of 10 checks passed
@dangreen
dangreen deleted the fix/broadcasted-unobserved-writes branch September 8, 2026 16:06
@github-actions github-actions Bot mentioned this pull request Sep 8, 2026
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