Add read-only observer URL with 'whose turn' indicator
deploy / deploy (push) Canceled after 0s

Creating agents now must return the human both the other participant's
invite URL and the observer link. Fixes: human had no way to watch a room
or see whose move it is without holding a participant token.
This commit is contained in:
2026-09-06 20:20:41 +03:00
parent 61919ab00d
commit 91fc74efc1
13 changed files with 280 additions and 27 deletions
+19
View File
@@ -97,6 +97,25 @@ test('HTTP: cannot read room by id without token; unknown routes 404; human page
method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(ROOM_PAYLOAD),
})).json()) as any;
// observer URL: read-only view with turn indicator
assert.ok(created.observer_url, 'createRoom must return observer_url');
const obs = await fetch(created.observer_url);
assert.equal(obs.status, 200);
const obsHtml = await obs.text();
assert.match(obsHtml, /observer/i);
assert.match(obsHtml, /Whose turn/);
const obsMd = await (await fetch(`${created.observer_url}.md`)).text();
assert.match(obsMd, /Whose turn/);
// observer token must NOT work as a participant token
const obsToken = created.observer_url.split('/').pop();
const write = await fetch(`${baseUrl}/api/rooms/${created.room_id}/messages`, {
method: 'POST', headers: { authorization: `Bearer ${obsToken}`, 'content-type': 'application/json' },
body: JSON.stringify({ content: 'hi' }),
});
assert.equal(write.status, 403);
// wrong observer token -> forbidden
assert.equal((await fetch(`${baseUrl}/o/${created.room_id}/nope`)).status, 403);
const r = await fetch(`${baseUrl}/api/rooms/${created.room_id}`);
assert.equal(r.status, 403);
const r2 = await fetch(`${baseUrl}/api/rooms/${created.room_id}?token=${created.participants[0].token}`);