fix(spotify): device-scope Rust Connect control + ignore foreign-device poll state (multi-bot) [corner-case R4-4]

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
saopig1andClaude Opus 4.8 committed 2026-07-04 13:50:28 +08:00
1 parent ec0a027a1e
commit 1a3ccd0e38
5 files changed
+176 -13

No files matched your search

+36
View File
@@ -141,6 +141,16 @@ describe("SpotifyConnectApi mutating calls", () => {
});
});
it("resume(id) forwards device_id param", async () => {
const http = makeHttp();
const api = new SpotifyConnectApi(token(), { http });
await api.resume("dev-1");
expect(http.put).toHaveBeenCalledWith("/v1/me/player/play", undefined, {
headers: { Authorization: "Bearer tok123" },
params: { device_id: "dev-1" },
});
});
it("seek() PUTs /v1/me/player/seek?position_ms=", async () => {
const http = makeHttp();
const api = new SpotifyConnectApi(token(), { http });
@@ -326,6 +336,32 @@ describe("SpotifyConnectApi.getPlaybackState", () => {
});
});
// R4-4 (multi-bot): the account-wide /v1/me/player response names the single
// ACTIVE Connect device. Expose it as activeDeviceId so the Rust backend can
// tell "our device" from a foreign device another bot stole the session with.
it("maps device.id -> activeDeviceId", async () => {
const http = makeHttp({
get: vi.fn().mockResolvedValue({
status: 200,
data: {
is_playing: true,
progress_ms: 1000,
item: { uri: "spotify:track:abc", duration_ms: 200000 },
device: { id: "dev-1", name: "TS Bot", is_active: true },
},
}),
});
const api = new SpotifyConnectApi(token(), { http });
const state = await api.getPlaybackState();
expect(state).toEqual({
isPlaying: true,
progressMs: 1000,
trackUri: "spotify:track:abc",
durationMs: 200000,
activeDeviceId: "dev-1",
});
});
it("returns null on 204 (no active device)", async () => {
const http = makeHttp({ get: vi.fn().mockResolvedValue({ status: 204, data: "" }) });
const api = new SpotifyConnectApi(token(), { http });