mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-25 17:18:33 +01:00
feat(tavern): unified global chat with persistent history in the tavern
The tavern used ephemeral, room-scoped chat with no backlog, so entering it showed a blank log. Wire it to the shared global chat provider instead: - TavernManager takes a globalChatProvider (the lobby's chat provider) and publishes tavern messages to the 'global' scope, so tavern + lobby share ONE conversation that persists to Postgres and (when NOSTR_CHAT_ENABLED) fans out over relay.smirk.cash. Falls back to the old tavern-scoped ephemeral provider when none is injected. - On join, the tavern sends the recent global backlog (chat_history) to the joiner so history shows immediately. - tavern.html: render chat_history on join and accept global-scope broadcasts (not just this room's), so lobby<->tavern messages flow both ways. Tests: +3 (join sends backlog, chat routes to global scope, legacy fallback stays tavern-scoped). Suite 55 suites / 394 tests green.
This commit is contained in:
@@ -227,5 +227,51 @@ describe('TavernManager', () => {
|
||||
mgr.shutdown();
|
||||
expect(mgr._tickInterval).toBeNull();
|
||||
});
|
||||
|
||||
describe('global chat wiring', () => {
|
||||
function makeGlobalProvider() {
|
||||
return {
|
||||
published: [],
|
||||
publish(msg) { this.published.push(msg); return Promise.resolve(); },
|
||||
getHistory() { return Promise.resolve([{ username: 'bob', message: 'gm all' }]); }
|
||||
};
|
||||
}
|
||||
|
||||
test('join sends the global chat backlog to the joiner', async () => {
|
||||
const io = makeFakeIo();
|
||||
const gcp = makeGlobalProvider();
|
||||
const mgr = new TavernManager({ io, globalChatProvider: gcp });
|
||||
const s = makeFakeSocket('a', io);
|
||||
await mgr.join(s, { name: 'Alice' });
|
||||
await new Promise(r => setImmediate(r)); // let the history promise resolve
|
||||
const hist = s.emitted.find(e => e.event === 'chat_history');
|
||||
expect(hist).toBeDefined();
|
||||
expect(hist.payload.messages[0].message).toBe('gm all');
|
||||
});
|
||||
|
||||
test('chat routes to the GLOBAL scope through the shared provider', async () => {
|
||||
const io = makeFakeIo();
|
||||
const gcp = makeGlobalProvider();
|
||||
const mgr = new TavernManager({ io, globalChatProvider: gcp });
|
||||
const s = makeFakeSocket('a', io);
|
||||
await mgr.join(s, { name: 'Alice' });
|
||||
mgr.chat(s, { text: 'hello world' });
|
||||
const sent = gcp.published.find(m => m.text && m.text.indexOf('hello') !== -1);
|
||||
expect(sent).toBeDefined();
|
||||
expect(sent.scope).toBe('global');
|
||||
});
|
||||
|
||||
test('without a global provider, chat stays tavern-scoped (legacy behavior)', async () => {
|
||||
const io = makeFakeIo();
|
||||
const mgr = new TavernManager({ io }); // no globalChatProvider
|
||||
const s = makeFakeSocket('a', io);
|
||||
await mgr.join(s, { name: 'Alice' });
|
||||
io.emitted.length = 0;
|
||||
mgr.chat(s, { text: 'local only' });
|
||||
const bc = io.emitted.find(e => e.event === 'chat_broadcast');
|
||||
expect(bc).toBeDefined();
|
||||
expect(bc.channel).toBe('tavern:main'); // room-scoped, not global
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user