roon-mcp 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/README.md +61 -11
- package/dist/PlaybackService.d.ts +16 -0
- package/dist/PlaybackService.js +59 -2
- package/dist/PlaybackService.js.map +1 -1
- package/dist/PlaybackService.test.js +63 -0
- package/dist/PlaybackService.test.js.map +1 -1
- package/dist/RoonClient.d.ts +21 -0
- package/dist/RoonClient.js +35 -0
- package/dist/RoonClient.js.map +1 -1
- package/dist/RoonMcpServer.d.ts +3 -1
- package/dist/RoonMcpServer.js +215 -39
- package/dist/RoonMcpServer.js.map +1 -1
- package/dist/SearchService.d.ts +12 -0
- package/dist/SearchService.js +63 -1
- package/dist/SearchService.js.map +1 -1
- package/dist/SearchService.test.js +79 -4
- package/dist/SearchService.test.js.map +1 -1
- package/dist/TransportService.d.ts +73 -0
- package/dist/TransportService.js +248 -0
- package/dist/TransportService.js.map +1 -0
- package/dist/TransportService.test.d.ts +1 -0
- package/dist/TransportService.test.js +331 -0
- package/dist/TransportService.test.js.map +1 -0
- package/dist/ZoneService.d.ts +1 -0
- package/dist/ZoneService.js +9 -0
- package/dist/ZoneService.js.map +1 -1
- package/dist/ZoneService.test.js +1 -0
- package/dist/ZoneService.test.js.map +1 -1
- package/dist/ZoneSubscription.d.ts +67 -0
- package/dist/ZoneSubscription.js +187 -0
- package/dist/ZoneSubscription.js.map +1 -0
- package/dist/ZoneSubscription.test.d.ts +1 -0
- package/dist/ZoneSubscription.test.js +185 -0
- package/dist/ZoneSubscription.test.js.map +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +39 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import { TransportService } from "./TransportService.js";
|
|
4
|
+
import { RoonMcpError } from "./types.js";
|
|
5
|
+
import { ZoneService } from "./ZoneService.js";
|
|
6
|
+
import { ZoneSubscription } from "./ZoneSubscription.js";
|
|
7
|
+
function zone(partial) {
|
|
8
|
+
return {
|
|
9
|
+
display_name: partial.zone_id,
|
|
10
|
+
state: "stopped",
|
|
11
|
+
outputs: [{ output_id: `o:${partial.zone_id}`, zone_id: partial.zone_id, display_name: partial.zone_id }],
|
|
12
|
+
...partial,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** Builds a TransportService backed by a stub RoonClient with the given zones. */
|
|
16
|
+
function serviceWith(zones, defaultZone) {
|
|
17
|
+
const controlCalls = [];
|
|
18
|
+
const volumeCalls = [];
|
|
19
|
+
const muteCalls = [];
|
|
20
|
+
const stub = {
|
|
21
|
+
waitForCore: async () => undefined,
|
|
22
|
+
getTransport: () => ({
|
|
23
|
+
get_zones: (cb) => cb(false, { zones }),
|
|
24
|
+
subscribe_zones: () => { },
|
|
25
|
+
control: (zoneOrOutput, control, cb) => {
|
|
26
|
+
controlCalls.push({ zone: zoneOrOutput, control });
|
|
27
|
+
cb?.(false);
|
|
28
|
+
},
|
|
29
|
+
change_volume: (output, how, value, cb) => {
|
|
30
|
+
const outputId = typeof output === "string" ? output : output.output_id;
|
|
31
|
+
volumeCalls.push({ outputId, how, value });
|
|
32
|
+
cb?.(false);
|
|
33
|
+
},
|
|
34
|
+
mute: (output, how, cb) => {
|
|
35
|
+
const outputId = typeof output === "string" ? output : output.output_id;
|
|
36
|
+
muteCalls.push({ outputId, how });
|
|
37
|
+
cb?.(false);
|
|
38
|
+
},
|
|
39
|
+
}),
|
|
40
|
+
getActiveSubscription: () => undefined,
|
|
41
|
+
};
|
|
42
|
+
const zoneSvc = new ZoneService(stub, undefined, defaultZone);
|
|
43
|
+
const svc = new TransportService(stub, zoneSvc);
|
|
44
|
+
return { svc, controlCalls, volumeCalls, muteCalls };
|
|
45
|
+
}
|
|
46
|
+
test("getNowPlaying returns a structured snapshot of a playing zone", async () => {
|
|
47
|
+
const { svc } = serviceWith([
|
|
48
|
+
zone({
|
|
49
|
+
zone_id: "z1",
|
|
50
|
+
display_name: "Office",
|
|
51
|
+
state: "playing",
|
|
52
|
+
now_playing: {
|
|
53
|
+
three_line: { line1: "A Walk", line2: "Tycho", line3: "Dive" },
|
|
54
|
+
seek_position: 42,
|
|
55
|
+
length: 240,
|
|
56
|
+
image_key: "img:1",
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
]);
|
|
60
|
+
const info = await svc.getNowPlaying();
|
|
61
|
+
assert.deepEqual(info, {
|
|
62
|
+
zoneId: "z1",
|
|
63
|
+
displayName: "Office",
|
|
64
|
+
state: "playing",
|
|
65
|
+
title: "A Walk",
|
|
66
|
+
artist: "Tycho",
|
|
67
|
+
album: "Dive",
|
|
68
|
+
imageKey: "img:1",
|
|
69
|
+
lengthSec: 240,
|
|
70
|
+
seekPositionSec: 42,
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
test("getNowPlaying falls back through three/two/one line displays", async () => {
|
|
74
|
+
// Two-line only — `album` should be undefined.
|
|
75
|
+
const two = await serviceWith([
|
|
76
|
+
zone({
|
|
77
|
+
zone_id: "z1",
|
|
78
|
+
state: "playing",
|
|
79
|
+
now_playing: { two_line: { line1: "Strobe", line2: "deadmau5" } },
|
|
80
|
+
}),
|
|
81
|
+
]).svc.getNowPlaying();
|
|
82
|
+
assert.deepEqual(two, {
|
|
83
|
+
zoneId: "z1",
|
|
84
|
+
displayName: "z1",
|
|
85
|
+
state: "playing",
|
|
86
|
+
title: "Strobe",
|
|
87
|
+
artist: "deadmau5",
|
|
88
|
+
album: undefined,
|
|
89
|
+
imageKey: undefined,
|
|
90
|
+
lengthSec: undefined,
|
|
91
|
+
seekPositionSec: undefined,
|
|
92
|
+
});
|
|
93
|
+
// One-line only — both `artist` and `album` should be undefined.
|
|
94
|
+
const one = await serviceWith([
|
|
95
|
+
zone({
|
|
96
|
+
zone_id: "z2",
|
|
97
|
+
state: "playing",
|
|
98
|
+
now_playing: { one_line: { line1: "Track 1" } },
|
|
99
|
+
}),
|
|
100
|
+
]).svc.getNowPlaying();
|
|
101
|
+
assert.equal(one?.title, "Track 1");
|
|
102
|
+
assert.equal(one?.artist, undefined);
|
|
103
|
+
assert.equal(one?.album, undefined);
|
|
104
|
+
});
|
|
105
|
+
test("getNowPlaying reports the zone state when nothing is playing", async () => {
|
|
106
|
+
const { svc } = serviceWith([zone({ zone_id: "z1", state: "stopped" })]);
|
|
107
|
+
const info = await svc.getNowPlaying();
|
|
108
|
+
// Zone exists, so the snapshot is returned with `title` undefined to signal
|
|
109
|
+
// "no track" (rather than throwing or returning null).
|
|
110
|
+
assert.equal(info?.state, "stopped");
|
|
111
|
+
assert.equal(info?.title, undefined);
|
|
112
|
+
assert.equal(info?.artist, undefined);
|
|
113
|
+
});
|
|
114
|
+
test("getNowPlaying rejects an unknown zone id with ZONE_NOT_FOUND", async () => {
|
|
115
|
+
const { svc } = serviceWith([zone({ zone_id: "z1" })]);
|
|
116
|
+
await assert.rejects(svc.getNowPlaying("nope"), (e) => e instanceof RoonMcpError && e.code === "ZONE_NOT_FOUND");
|
|
117
|
+
});
|
|
118
|
+
test("control rejects an unknown action with BROWSE_FAILED", async () => {
|
|
119
|
+
const { svc } = serviceWith([zone({ zone_id: "z1", state: "playing" })]);
|
|
120
|
+
await assert.rejects(svc.control(undefined, "rewind"), (e) => e instanceof RoonMcpError && e.code === "BROWSE_FAILED" && /unknown action/i.test(e.message));
|
|
121
|
+
});
|
|
122
|
+
test("control('pause') issues transport.control(zoneId, 'pause')", async () => {
|
|
123
|
+
const { svc, controlCalls } = serviceWith([
|
|
124
|
+
zone({ zone_id: "z1", state: "playing", is_pause_allowed: true }),
|
|
125
|
+
]);
|
|
126
|
+
const out = await svc.control("z1", "pause");
|
|
127
|
+
assert.equal(out.ok, true);
|
|
128
|
+
assert.equal(out.zoneId, "z1");
|
|
129
|
+
assert.equal(out.action, "pause");
|
|
130
|
+
assert.deepEqual(controlCalls, [{ zone: "z1", control: "pause" }]);
|
|
131
|
+
});
|
|
132
|
+
test("control('resume') maps to Roon's 'play' verb", async () => {
|
|
133
|
+
const { svc, controlCalls } = serviceWith([
|
|
134
|
+
zone({ zone_id: "z1", state: "paused", is_play_allowed: true }),
|
|
135
|
+
]);
|
|
136
|
+
await svc.control("z1", "resume");
|
|
137
|
+
assert.deepEqual(controlCalls, [{ zone: "z1", control: "play" }]);
|
|
138
|
+
});
|
|
139
|
+
test("control('next') is refused when is_next_allowed is false", async () => {
|
|
140
|
+
const { svc, controlCalls } = serviceWith([
|
|
141
|
+
zone({ zone_id: "z1", state: "playing", is_next_allowed: false }),
|
|
142
|
+
]);
|
|
143
|
+
await assert.rejects(svc.control("z1", "next"), (e) => e instanceof RoonMcpError && e.code === "BROWSE_FAILED");
|
|
144
|
+
assert.deepEqual(controlCalls, []);
|
|
145
|
+
});
|
|
146
|
+
test("control('stop') bypasses the allowed-flag check", async () => {
|
|
147
|
+
// Roon doesn't expose is_stop_allowed; `stop` should never be refused.
|
|
148
|
+
const { svc, controlCalls } = serviceWith([
|
|
149
|
+
zone({ zone_id: "z1", state: "playing" }),
|
|
150
|
+
]);
|
|
151
|
+
await svc.control("z1", "stop");
|
|
152
|
+
assert.deepEqual(controlCalls, [{ zone: "z1", control: "stop" }]);
|
|
153
|
+
});
|
|
154
|
+
test("control resolves an omitted zoneId via ZoneService", async () => {
|
|
155
|
+
const { svc, controlCalls } = serviceWith([
|
|
156
|
+
zone({ zone_id: "z1", state: "playing", is_pause_allowed: true }),
|
|
157
|
+
]);
|
|
158
|
+
await svc.control(undefined, "pause");
|
|
159
|
+
assert.deepEqual(controlCalls, [{ zone: "z1", control: "pause" }]);
|
|
160
|
+
});
|
|
161
|
+
test("setVolume rejects out-of-range levels", async () => {
|
|
162
|
+
const { svc } = serviceWith([zone({ zone_id: "z1" })]);
|
|
163
|
+
for (const bad of [-1, 101, Number.NaN]) {
|
|
164
|
+
await assert.rejects(svc.setVolume("z1", bad), (e) => e instanceof RoonMcpError && e.code === "BROWSE_FAILED");
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
test("setVolume rescales 0..100 to each output's native min/max", async () => {
|
|
168
|
+
// Output with 0..60 numeric range and a step of 5 → 50% maps to 30.
|
|
169
|
+
const { svc, volumeCalls } = serviceWith([
|
|
170
|
+
zone({
|
|
171
|
+
zone_id: "z1",
|
|
172
|
+
outputs: [
|
|
173
|
+
{
|
|
174
|
+
output_id: "o1",
|
|
175
|
+
zone_id: "z1",
|
|
176
|
+
display_name: "Office",
|
|
177
|
+
volume: { min: 0, max: 60, step: 5 },
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
}),
|
|
181
|
+
]);
|
|
182
|
+
const out = await svc.setVolume("z1", 50);
|
|
183
|
+
assert.equal(out.applied.length, 1);
|
|
184
|
+
assert.deepEqual(volumeCalls, [{ outputId: "o1", how: "absolute", value: 30 }]);
|
|
185
|
+
});
|
|
186
|
+
test("setVolume fans out across multiple outputs in a grouped zone", async () => {
|
|
187
|
+
const { svc, volumeCalls } = serviceWith([
|
|
188
|
+
zone({
|
|
189
|
+
zone_id: "z1",
|
|
190
|
+
outputs: [
|
|
191
|
+
{ output_id: "o1", zone_id: "z1", display_name: "L", volume: { min: 0, max: 100 } },
|
|
192
|
+
{ output_id: "o2", zone_id: "z1", display_name: "R", volume: { min: 0, max: 100 } },
|
|
193
|
+
],
|
|
194
|
+
}),
|
|
195
|
+
]);
|
|
196
|
+
const out = await svc.setVolume("z1", 25);
|
|
197
|
+
assert.equal(out.applied.length, 2);
|
|
198
|
+
assert.deepEqual(volumeCalls.sort((a, b) => a.outputId.localeCompare(b.outputId)), [
|
|
199
|
+
{ outputId: "o1", how: "absolute", value: 25 },
|
|
200
|
+
{ outputId: "o2", how: "absolute", value: 25 },
|
|
201
|
+
]);
|
|
202
|
+
});
|
|
203
|
+
test("setVolume skips incremental outputs and applies to the rest", async () => {
|
|
204
|
+
const { svc, volumeCalls } = serviceWith([
|
|
205
|
+
zone({
|
|
206
|
+
zone_id: "z1",
|
|
207
|
+
outputs: [
|
|
208
|
+
{ output_id: "o1", zone_id: "z1", display_name: "Speaker", volume: { min: 0, max: 100 } },
|
|
209
|
+
// No min/max — incremental IR-blaster style.
|
|
210
|
+
{ output_id: "o2", zone_id: "z1", display_name: "IR", volume: { type: "incremental" } },
|
|
211
|
+
],
|
|
212
|
+
}),
|
|
213
|
+
]);
|
|
214
|
+
const out = await svc.setVolume("z1", 50);
|
|
215
|
+
assert.deepEqual(out.applied, ["o1"]);
|
|
216
|
+
assert.deepEqual(out.skipped, ["o2"]);
|
|
217
|
+
assert.equal(volumeCalls.length, 1);
|
|
218
|
+
});
|
|
219
|
+
test("setVolume throws when every output is incremental", async () => {
|
|
220
|
+
const { svc } = serviceWith([
|
|
221
|
+
zone({
|
|
222
|
+
zone_id: "z1",
|
|
223
|
+
outputs: [
|
|
224
|
+
{ output_id: "o1", zone_id: "z1", display_name: "IR", volume: { type: "incremental" } },
|
|
225
|
+
],
|
|
226
|
+
}),
|
|
227
|
+
]);
|
|
228
|
+
await assert.rejects(svc.setVolume("z1", 50), (e) => e instanceof RoonMcpError &&
|
|
229
|
+
e.code === "BROWSE_FAILED" &&
|
|
230
|
+
/incremental/i.test(e.message));
|
|
231
|
+
});
|
|
232
|
+
test("mute fans out to every output with the requested how", async () => {
|
|
233
|
+
const { svc, muteCalls } = serviceWith([
|
|
234
|
+
zone({
|
|
235
|
+
zone_id: "z1",
|
|
236
|
+
outputs: [
|
|
237
|
+
{ output_id: "o1", zone_id: "z1", display_name: "L" },
|
|
238
|
+
{ output_id: "o2", zone_id: "z1", display_name: "R" },
|
|
239
|
+
],
|
|
240
|
+
}),
|
|
241
|
+
]);
|
|
242
|
+
const out = await svc.mute("z1", true);
|
|
243
|
+
assert.equal(out.muted, true);
|
|
244
|
+
assert.deepEqual(muteCalls.sort((a, b) => a.outputId.localeCompare(b.outputId)), [
|
|
245
|
+
{ outputId: "o1", how: "mute" },
|
|
246
|
+
{ outputId: "o2", how: "mute" },
|
|
247
|
+
]);
|
|
248
|
+
await svc.mute("z1", false);
|
|
249
|
+
assert.equal(muteCalls.length, 4);
|
|
250
|
+
assert.deepEqual(muteCalls.slice(2), [
|
|
251
|
+
{ outputId: "o1", how: "unmute" },
|
|
252
|
+
{ outputId: "o2", how: "unmute" },
|
|
253
|
+
]);
|
|
254
|
+
});
|
|
255
|
+
/**
|
|
256
|
+
* A subscription-backed transport stub. The `subscribe_zones` callback is
|
|
257
|
+
* captured so the test can drive `Changed` events. The `get_zones` RPC is
|
|
258
|
+
* kept so a cold-start fallback still works.
|
|
259
|
+
*/
|
|
260
|
+
function serviceWithSubscription(initial) {
|
|
261
|
+
const controlCalls = [];
|
|
262
|
+
let cb;
|
|
263
|
+
let getZonesCalls = 0;
|
|
264
|
+
const transport = {
|
|
265
|
+
get_zones: (cb2) => {
|
|
266
|
+
getZonesCalls++;
|
|
267
|
+
cb2(false, { zones: initial });
|
|
268
|
+
},
|
|
269
|
+
subscribe_zones: (callback) => {
|
|
270
|
+
cb = callback;
|
|
271
|
+
},
|
|
272
|
+
control: (zoneOrOutput, control, cb3) => {
|
|
273
|
+
controlCalls.push({ zone: zoneOrOutput, control });
|
|
274
|
+
cb3?.(false);
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
const sub = new ZoneSubscription(transport, "core-1");
|
|
278
|
+
sub.start();
|
|
279
|
+
// Pre-load the cache so reads don't hit the cold-start fallback path.
|
|
280
|
+
cb?.("Subscribed", { zones: initial });
|
|
281
|
+
const stub = {
|
|
282
|
+
waitForCore: async () => undefined,
|
|
283
|
+
getTransport: () => transport,
|
|
284
|
+
getActiveSubscription: () => sub,
|
|
285
|
+
};
|
|
286
|
+
const zones = new ZoneService(stub);
|
|
287
|
+
const svc = new TransportService(stub, zones);
|
|
288
|
+
return { svc, controlCalls, push: (r, b) => cb?.(r, b) };
|
|
289
|
+
}
|
|
290
|
+
test("control waits for the post-action snapshot when the subscription pushes a Changed event", async () => {
|
|
291
|
+
// Reproduces issue #1 for `control_playback`: after `next` the zone's
|
|
292
|
+
// `state` is still the pre-action one until Roon pushes a Changed event.
|
|
293
|
+
const { svc, push } = serviceWithSubscription([
|
|
294
|
+
zone({
|
|
295
|
+
zone_id: "z1",
|
|
296
|
+
state: "playing",
|
|
297
|
+
is_next_allowed: true,
|
|
298
|
+
now_playing: { two_line: { line1: "Old Track" } },
|
|
299
|
+
}),
|
|
300
|
+
]);
|
|
301
|
+
// Fire the action and the matching Changed event concurrently. The
|
|
302
|
+
// service should observe the new state when the action resolves.
|
|
303
|
+
const out = await Promise.all([
|
|
304
|
+
svc.control("z1", "next"),
|
|
305
|
+
// Simulate Roon pushing the new track on the next event loop turn.
|
|
306
|
+
new Promise((r) => setTimeout(() => {
|
|
307
|
+
push("Changed", {
|
|
308
|
+
zones_changed: [
|
|
309
|
+
zone({
|
|
310
|
+
zone_id: "z1",
|
|
311
|
+
state: "playing",
|
|
312
|
+
is_next_allowed: true,
|
|
313
|
+
now_playing: { two_line: { line1: "New Track" } },
|
|
314
|
+
}),
|
|
315
|
+
],
|
|
316
|
+
});
|
|
317
|
+
r();
|
|
318
|
+
}, 5)),
|
|
319
|
+
]).then(([res]) => res);
|
|
320
|
+
assert.equal(out.state, "playing");
|
|
321
|
+
});
|
|
322
|
+
test("control falls back to the latest snapshot when no Changed event arrives", async () => {
|
|
323
|
+
// No subscription pushes anything; the service should still return
|
|
324
|
+
// promptly with the current snapshot, not hang.
|
|
325
|
+
const { svc } = serviceWithSubscription([
|
|
326
|
+
zone({ zone_id: "z1", state: "paused", is_play_allowed: true }),
|
|
327
|
+
]);
|
|
328
|
+
const out = await svc.control("z1", "resume");
|
|
329
|
+
assert.equal(out.state, "paused");
|
|
330
|
+
});
|
|
331
|
+
//# sourceMappingURL=TransportService.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TransportService.test.js","sourceRoot":"","sources":["../src/TransportService.test.ts"],"names":[],"mappings":"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"}
|
package/dist/ZoneService.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ export declare class ZoneService {
|
|
|
41
41
|
nowPlayingFor(idOrOutput: string): Promise<string | undefined>;
|
|
42
42
|
private findRawZone;
|
|
43
43
|
private getZonesBody;
|
|
44
|
+
private fallbackGetZones;
|
|
44
45
|
/**
|
|
45
46
|
* Resolve a single zone, applying the plan's resolution rules:
|
|
46
47
|
* 1. Exact, then fuzzy, name match when a preferred name is given.
|
package/dist/ZoneService.js
CHANGED
|
@@ -91,6 +91,15 @@ export class ZoneService {
|
|
|
91
91
|
async getZonesBody() {
|
|
92
92
|
await this.roon.waitForCore();
|
|
93
93
|
const transport = this.roon.getTransport();
|
|
94
|
+
const sub = this.roon.getActiveSubscription();
|
|
95
|
+
if (sub) {
|
|
96
|
+
// Prefer the cache kept current by Roon's `subscribe_zones` events;
|
|
97
|
+
// fall back to a one-shot `get_zones` only on cold start (cache empty).
|
|
98
|
+
return sub.getSnapshot(() => this.fallbackGetZones(transport));
|
|
99
|
+
}
|
|
100
|
+
return this.fallbackGetZones(transport);
|
|
101
|
+
}
|
|
102
|
+
fallbackGetZones(transport) {
|
|
94
103
|
return this.logger.call("get_zones", {}, () => new Promise((resolve, reject) => {
|
|
95
104
|
transport.get_zones((error, result) => {
|
|
96
105
|
if (error) {
|
package/dist/ZoneService.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZoneService.js","sourceRoot":"","sources":["../src/ZoneService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ZoneService.js","sourceRoot":"","sources":["../src/ZoneService.ts"],"names":[],"mappings":"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"}
|
package/dist/ZoneService.test.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZoneService.test.js","sourceRoot":"","sources":["../src/ZoneService.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAKjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAiB,MAAM,YAAY,CAAC;AAEzD,SAAS,IAAI,CAAC,OAAmD;IAC/D,OAAO;QACL,YAAY,EAAE,OAAO,CAAC,OAAO;QAC7B,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QACzG,GAAG,OAAO;KACX,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,SAAS,WAAW,CAAC,KAAoB,EAAE,WAAoB;IAC7D,MAAM,IAAI,GAAG;QACX,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS;QAClC,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;YACnB,SAAS,EAAE,CAAC,EAAgD,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC;YACrF,eAAe,EAAE,GAAG,EAAE,GAAE,CAAC;SAC1B,CAAC;
|
|
1
|
+
{"version":3,"file":"ZoneService.test.js","sourceRoot":"","sources":["../src/ZoneService.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { GetZonesBody, RoonApiTransport } from "node-roon-api-transport";
|
|
2
|
+
/**
|
|
3
|
+
* Default upper bound (ms) for {@link ZoneSubscription.waitForZoneChange}.
|
|
4
|
+
* Kept short so a slow Core never turns a `play_now` call into a multi-second
|
|
5
|
+
* hang; the result still returns the latest snapshot on timeout.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_ZONE_CHANGE_TIMEOUT_MS = 2000;
|
|
8
|
+
/**
|
|
9
|
+
* A snapshot fingerprint used to detect a meaningful state change for a zone.
|
|
10
|
+
* Compares state plus the now_playing identity (title/artist/album), so a
|
|
11
|
+
* high-frequency `seek_position` tick doesn't satisfy a wait.
|
|
12
|
+
*/
|
|
13
|
+
export interface ZoneFingerprint {
|
|
14
|
+
state: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
artist?: string;
|
|
17
|
+
album?: string;
|
|
18
|
+
}
|
|
19
|
+
/** Build a fingerprint for the named zone in the given snapshot. */
|
|
20
|
+
export declare function fingerprintFor(body: GetZonesBody, idOrOutput: string): ZoneFingerprint | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Wraps `RoonApiTransport.subscribe_zones` and keeps the latest full snapshot
|
|
23
|
+
* in memory. Reads (via {@link getSnapshot}) hit the cache when fresh and fall
|
|
24
|
+
* back to a one-shot `get_zones` request otherwise. Waiters
|
|
25
|
+
* ({@link waitForZoneChange}) subscribe to in-memory change notifications and
|
|
26
|
+
* resolve as soon as the named zone's fingerprint moves — typically well
|
|
27
|
+
* before a `get_zones` round-trip would.
|
|
28
|
+
*/
|
|
29
|
+
export declare class ZoneSubscription {
|
|
30
|
+
private readonly transport;
|
|
31
|
+
private readonly coreId;
|
|
32
|
+
private snapshot;
|
|
33
|
+
private waiters;
|
|
34
|
+
constructor(transport: RoonApiTransport, coreId: string);
|
|
35
|
+
/** Subscribe and start receiving zone updates from the Core. */
|
|
36
|
+
start(): void;
|
|
37
|
+
/** Drop the cache and any pending waiters. Called on Core unpair. */
|
|
38
|
+
stop(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Return the latest zone snapshot, falling back to a one-shot `get_zones`
|
|
41
|
+
* request when no `Subscribed` event has landed yet (cold start, reconnect).
|
|
42
|
+
* The fallback is wrapped in the supplied logger so a stderr line still
|
|
43
|
+
* records the read.
|
|
44
|
+
*/
|
|
45
|
+
getSnapshot(fallback: () => Promise<GetZonesBody>): Promise<GetZonesBody>;
|
|
46
|
+
/**
|
|
47
|
+
* Resolve with the next snapshot whose fingerprint for `idOrOutput` differs
|
|
48
|
+
* from `before`, or with the latest snapshot once `timeoutMs` has elapsed
|
|
49
|
+
* (whichever comes first). The pre-action snapshot should be taken via
|
|
50
|
+
* {@link fingerprintFor} right before the Roon action runs.
|
|
51
|
+
*/
|
|
52
|
+
waitForZoneChange(idOrOutput: string, before: ZoneFingerprint, timeoutMs?: number): Promise<GetZonesBody>;
|
|
53
|
+
private notifyWaiters;
|
|
54
|
+
private removeWaiter;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Registry that pairs a {@link ZoneSubscription} with each paired Core. Roon
|
|
58
|
+
* can pair with multiple Cores over a session (only one is ever paired at a
|
|
59
|
+
* time on a single extension), so this is keyed by `core_id`. The current
|
|
60
|
+
* subscription is exposed via {@link forCore} for read services.
|
|
61
|
+
*/
|
|
62
|
+
export declare class ZoneSubscriptionRegistry {
|
|
63
|
+
private readonly byCore;
|
|
64
|
+
startFor(coreId: string, transport: RoonApiTransport): ZoneSubscription;
|
|
65
|
+
stopFor(coreId: string): void;
|
|
66
|
+
forCore(coreId: string | undefined): ZoneSubscription | undefined;
|
|
67
|
+
}
|