Skip to content

feat(live-activity): honour the streamer's liveActivityPush flag - #671

Open
RonenMars wants to merge 2 commits into
mainfrom
feat/live-activity-push-flag
Open

feat(live-activity): honour the streamer's liveActivityPush flag#671
RonenMars wants to merge 2 commits into
mainfrom
feat/live-activity-push-flag

Conversation

@RonenMars

Copy link
Copy Markdown
Owner

The client half starts a Live Activity locally from session_update frames, independently of whether the server can push to it.
Against a server with liveActivityPush off that produces the worst version of the feature: a Lock Screen card that only updates while you are already looking at the phone, then freezes the moment the app backgrounds and expires silently at iOS's ~8h cap.

Both reconcilers now return early unless the server opted in.
Android's ongoing notification is included — it renders the same feature, so one flag has to govern both.

Why the lookup is synchronous

reconcile() runs on every session_update frame and cannot await an HTTP round-trip per frame, so isLiveActivityEnabled(serverId) answers from a per-server cache and kicks the fetch off in the background.

  • Unknown reads as off, matching the streamer's registry default and erring toward not drawing a surface we may have to tear down a moment later.
  • One request per server: a burst of frames collapses into a single in-flight lookup.
  • A failed lookup is not cached, so one dropped request cannot pin the feature off until the app restarts. The next frame retries.

The one behaviour change worth flagging

A server too old to serve GET /api/config/feature-flags reads as off rather than being grandfathered on.
An old streamer is precisely one where the push half cannot exist, so "on" there would guarantee the degraded local-only path — the exact thing this flag exists to stop.
It also keeps the upgrade direction sane: grandfathering would mean upgrading your streamer removes a visible feature.

Because that is the only path where surfaces stop appearing without anyone choosing it, it logs liveActivity.legacyServer with the serverId.
From the phone the absence looks identical to a server that answered false, and that log line is what separates "upgrade the streamer" from "check the flag".

Server side

Requires RonenMars/threadbase-streamer#545, which adds the flag and gates the server half.
Until that lands, every server 404s the endpoint and reads as off.

Verified state

tsc --noEmit clean, eslint clean on all changed files.
Full unit suite: 1006 passed, 106 suites, 0 failed.

New coverage: 7 cases for the gate module (unknown-then-resolved, explicit off, legacy 404 + its log, per-server independence, request collapsing, retry-after-failure), plus reconcile-level on/off cases for both platforms.
The iOS suite had never exercised reconcile() at all — only the pure helpers — so those two cases are new ground.

The client half starts a Live Activity locally from session_update frames, independently of whether the server can push to it.
On a server with liveActivityPush off that produces the worst version of the feature: a Lock Screen card that only updates while you are already looking at the phone, then freezes on backgrounding and expires silently after ~8h.
Both reconcilers now return early unless the server opted in — Android's ongoing notification included, since it renders the same feature.

The lookup is synchronous against a per-server cache because reconcile() runs on every frame and cannot await an HTTP round-trip.
Unknown reads as off, one request per server, and a failed lookup is not cached so a dropped request does not pin the feature off until the app restarts.
A server too old to serve the endpoint reads as off and logs liveActivity.legacyServer, since that is the only path where surfaces stop appearing without anyone choosing it.
…ration suite

The liveActivityPush gate short-circuits reconcile() before any decision, so seven cases in LiveActivity.reconcile.test.tsx asserted against a reconciler that had already returned.
They exercise the reconciler's behaviour, not whether the server opted in, so the gate is mocked on for the suite the same way the unit suites do it.

Adds the missing off-case: an opened turn posts nothing when the flag is off.
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