watchparty/client/src
Nicolas daab755ce9
All checks were successful
Publier l'image Docker / test (push) Successful in 25s
Publier l'image Docker / publish (push) Successful in 18s
Device detection: confirm before disconnecting another device
Asked for directly: "same account, same device already in the party"
should never need a confirmation, "same account, a genuinely different
device" should ask before disconnecting it instead of silently
overwriting. There was no concept of "device" at all before this -
party.members is keyed by userId only.

- client/src/deviceId.ts (new): a UUID kept in localStorage (not
  sessionStorage) - that's what makes "device" mean "browser", not
  "tab". Falls back to an in-memory id if storage is unavailable.
- server/src/types.ts, client/src/api/party.ts: "join" now carries
  {partyId, deviceId, force?} instead of just {partyId}; new
  PartyMember.deviceId and "deviceConflict" server->client event (sent
  only to the joining socket, never broadcast).
- server/src/realtime/SocketGateway.ts: the "join" handler now tells
  three cases apart - no existing connection or the same deviceId
  reconnecting (attach silently, booting any stale connection for that
  same device first), a different deviceId with no force (emit
  deviceConflict and stop - the socket stays connected but inert), or
  force:true (the confirmed takeover - boot the old connection, take
  the slot).
- server/src/services/PartyService.ts: join() is now idempotent -
  returns the existing member instead of always building a fresh one.
  This was itself a real bug independent of the guard below: the REST
  "Rejoindre" route calls this every time regardless of membership, so
  a re-click/reload/retry used to silently reset connection/isPaused/
  deviceId.
- server/src/realtime/SocketGateway.ts: "leave"/"disconnect" now also
  check party.members.get(userId)?.connection === socket before acting
  - generalizes the earlier stale-connection crash fix to the new
  reality where a member can have more than one connection attempt in
  flight (the superseded one's own eventual "disconnect" must not be
  read as a real leave).
- client/src/views/player/Player.ts, client/src/musicBar/MusicBar.ts:
  onDeviceConflict wired to a plain confirm() - yes calls the new
  PartyConnection.confirmDeviceTakeover() (re-sends "join" with
  force:true), no backs out (navigate home for video, leaveMusicParty
  for music).
- Deliberately does NOT change the home page's live party list itself
  (still just "Rejoindre" either way) - LobbyPartyDto is one snapshot
  shared by the whole "lobby" room with no per-viewer membership info,
  and giving it that is a real protocol change on its own. For video
  the conflict check above already is the meaningful moment (you can't
  be looking at the home page from inside your own party on the same
  tab - the player is a full-screen takeover), so this doesn't cost
  the feature much: Rejoindre reaches the check immediately, same
  device reconnects silently, a different device asks first. See
  docs/architecture.md for the fuller reasoning.
- server/test/socketGateway.test.ts, server/test/partyService.test.ts:
  new tests for the conflict/takeover/reconnect paths and join()'s
  idempotency; the earlier stale-connection crash regression test
  updated to reach the same shared-slot shape through a real device
  takeover instead of a raw PartyService.join() call (which no longer
  reproduces it now that join() is idempotent).

Verified: full typecheck+test+build on both projects (39/39 server
tests passing); confirmed the "leave"/"disconnect" guard is load-
bearing by temporarily reverting it and watching the new takeover test
fail, then restoring it; deviceId.ts's localStorage persistence
checked against the real compiled bundle in a real browser (survives
a reload, stable across calls).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 17:32:21 +02:00
..
api Device detection: confirm before disconnecting another device 2026-09-14 17:32:21 +02:00
musicBar Device detection: confirm before disconnecting another device 2026-09-14 17:32:21 +02:00
shell Fix settings menu visibility bug; make the music player a persistent bar 2026-09-14 10:43:12 +02:00
styles Fix settings menu visibility bug; make the music player a persistent bar 2026-09-14 10:43:12 +02:00
views Device detection: confirm before disconnecting another device 2026-09-14 17:32:21 +02:00
app.ts Rewrite server + client in TypeScript, service-oriented server architecture 2026-09-14 09:38:14 +02:00
deviceId.ts Device detection: confirm before disconnecting another device 2026-09-14 17:32:21 +02:00
global.d.ts Fix subtitle selection timing out: hls.js's default timeouts too tight 2026-09-14 13:11:06 +02:00
index.html Rewrite server + client in TypeScript, service-oriented server architecture 2026-09-14 09:38:14 +02:00
router.ts Rewrite server + client in TypeScript, service-oriented server architecture 2026-09-14 09:38:14 +02:00
tiles.css Music bar: refresh vote count on join/leave, progress bar; catalog search 2026-09-14 16:44:23 +02:00
tiles.ts Music bar: refresh vote count on join/leave, progress bar; catalog search 2026-09-14 16:44:23 +02:00
types.ts Replace avatar-click with a request toolbar; add "request resume" 2026-09-14 17:09:01 +02:00