The access token is stored with the instance id it was given for, and a
page reads it only for its own instance: a tab still open on the old
backend after BACKEND_URL changed no longer sends the new server's
token there. The API client hands every 401 to reportAccessDenied(),
which now also sends a page without a token for its instance to sign-in,
while one that holds its token back until the instance is checked keeps
it.
A closed tab's adopted edits carry `yields`: replayed, they change only
what is still as that tab saw it, so they never replace progress this
tab or another device saved since. The flag survives the journal.
The sync spec's fake server and memory storage move to a test-helpers
file to keep the spec under its line limit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ServerStorageStatusService.accessToken() returns the stored token only
while server mode runs on an instance this start verified. The API
client, the HttpClient interceptor and PwaService's raw fetch calls use
it, so after an offline start from a remembered instance no request
(including the /instance reachability check) carries the token to
whatever answers at that address, and a 401 then does not clear it.
- Sign-in remembers the server along with the token; when storage refuses
either, it reports SIGN_IN_STORAGE instead of reloading into a start
that would drop the token.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- User-state entries carry a content tag; PUT/DELETE accept If-Match or
If-None-Match: * and answer 412 with the current value and tag. The PWA
sends each edit on the tag it read and replays it (before → after) on
the server's value after a conflict, so another device's change to the
same playlist's favorites or positions is kept instead of overwritten.
- The access token goes only to the backend URL (same origin and path),
never to another host or a sibling path.
- Deleting a playlist (or all) first drops its queued user-data edits and
waits for writes in flight, so none recreates deleted data.
- The migration copy writes on the tags it read.
- The write queue moves out of ServerUserDataStorage into
UserDataWriteQueue.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Moved playback positions are matched by content type and Xtream id and
name the server playlist.
- Page-hide writes report whether the server took them; refused ones go
back into the queue. Re-reads run one at a time.
- The access guard's 401 carries WWW-Authenticate: Bearer
realm="iptvnator"; the interceptor and PwaService's raw fetches turn it
into sign-in, so a token changed on the server is noticed on provider
calls too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The session plugs the HTTP document store into PlaylistStorageBackend,
hydrates synced user data before the first read (bounded to 3 s), retries
while offline, flushes on hide, and routes to sign-in when the server
answers 401. The interceptor adds the access token to HttpClient calls to
the backend.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>