cross_tab 0.2.1 copy "cross_tab: ^0.2.1" to clipboard
cross_tab: ^0.2.1 copied to clipboard

Coordinate the browser tabs of a Flutter Web app: send typed messages between them, know how many are open, and elect exactly one to do the work.

0.2.1 #

No code changes. This release exists because the package was almost impossible to install.

sdk: ^3.13.0 meant Dart 3.13, which only ships with Flutter 3.47 — released three weeks ago. Anyone on an older SDK hit a version-solve failure before they could try it. The floor is now ^3.5.0 / Flutter 3.24, and it is tested: the library resolves and type-checks against Flutter 3.16.9 / Dart 3.2.6, so the declared range is narrower than the verified one.

0.2.0 #

An audit of every package in this repo found five defects here, including two that produced the one thing leader election exists to prevent: two leaders.

Fixed #

  • A backgrounded tab was pruned as dead while it still believed it led. Browsers throttle a hidden tab's timers to about a minute, so it stopped beating, everyone else dropped it after three missed beats and elected a new leader — while the hidden tab, running its own throttled clock, still thought it was in charge. Two tabs then did the leader's work. The channel now beats on visibilitychange and skips one prune round after becoming visible, since everyone's clocks were throttled together.
  • A brand new tab crowned itself before hearing from anyone. _electedLeader() had no path that returned null despite the nullable return type, so a tab reported isLeader true on its first presence event — before it could know whether it was joining a crowd. Leadership is now null ("electing") for one heartbeat unless a peer speaks up first, and a tab that really is alone picks it up a beat later.
  • presence could drop a listener's own demotion. It was an async* generator whose yield current prelude suspended before anything subscribed to the controller, so events in that window went nowhere. It subscribes eagerly now and replays the current state through onListen — which also makes it genuinely broadcast.
  • The payload contract was documented backwards. TabMessage.data claimed to be "exactly as the sender passed it"; the envelope is JSON-encoded, so a DateTime never survives and a nested map arrives as Map<String, dynamic>. The docs now say so, and send refuses a non-encodable value with an ArgumentError naming the type instead of failing deep inside the encoder.
  • send after close threw on web and did nothing off-web. The stub now matches, so the mistake surfaces in a VM test rather than only in a browser.

0.1.3 #

  • Screenshots on pub.dev, generated by tool/shoot.sh rather than captured by hand, so they can be regenerated when the demo changes.
  • The example now bundles Material icons. It never had uses-material-design: true, so every icon in it rendered as an empty box — which nothing warns about at build time; the giveaway is an empty FontManifest.json.
  • Fixed a key placement in the example: the ValueKey was on the panel rather than on the Expanded wrapping it, so closing one tab tore down and rebuilt all the others with new ids. Flutter matches children by position and key together, and an unkeyed Expanded that shifts takes its subtree with it.

0.1.2 #

Actually fixes the README's opening example.

0.1.1 said it had fixed this and had not. The edit was made in the working tree and never staged, so that release changed only the version and the changelog — the broken snippet went out again, now with a note claiming it was gone. Verifying that a fix landed is part of the fix, and skipping it turned a small error into a false claim.

The opening example read if (p.isLeader) startPolling() else stopPolling();, which is missing the semicolon before else and does not compile.

0.1.1 #

  • Fixes the README's opening example, which did not compile. It read if (p.isLeader) startPolling() else stopPolling(); — missing the semicolon before else — so the first thing anyone copied out of this package was a syntax error. The corrected snippet was checked through the analyser rather than by eye.

0.1.0 #

Initial release: cross-tab coordination for Flutter Web.

  • CrossTab.open(name) joins every tab of your app sharing that name.
  • Leader election. Exactly one tab is elected to do work that must happen once — polling, a socket, a notification — and leadership moves when that tab closes. The oldest tab leads, with the id as a tiebreak so tabs opened in the same microsecond still reach the same answer.
  • Presence. count, tabs, leader, isLeader, emitted on change and on subscription. A closed tab says goodbye so the others react immediately; a crashed one is dropped after three missed heartbeats.
  • Messages with a sender id, carrying structure rather than strings. A tab never hears its own.
  • Off the web the package still compiles and behaves as the single instance it is: one tab, always the leader. That is the truthful answer, and it means leader logic needs no if (kIsWeb) around it.

Verified in a real browser: flutter test --platform chrome exercises four tabs agreeing on one leader, the oldest winning, and leadership passing on close — using two BroadcastChannel objects in one document, which see each other exactly as separate tabs do.

0
likes
160
points
301
downloads
screenshot

Documentation

Documentation
API reference

Publisher

verified publisherjumyn.com

Weekly Downloads

Coordinate the browser tabs of a Flutter Web app: send typed messages between them, know how many are open, and elect exactly one to do the work.

Repository (GitHub)
View/report issues

Topics

#web #broadcastchannel #tabs #leader-election #browser

License

MIT (license)

Dependencies

flutter, web

More

Packages that depend on cross_tab