Files
Dune/tests/admin-room-creation-client.test.ts
T
Quintine 238de3860d Add recoverable administrator room removal and restoration
Preserve room JSON, seats, credentials and messages while removed rooms deny ordinary reads and writes. Add deliberate room-scoped controls, removed-directory filters, persistent player notices and live-authorized atomic version/revision audit receipts. Retain uncertain room/seat requests and hidden recovery drafts through removal; restore the prior pause/join settings without reviving revoked credentials.

Fix AI readiness after a joining human or human faction change so real lobby starts remain legal.

Verified types, lint, 5314 offline tests, 52 HTTP tests and build. Fourteen authenticated HTTP groups and independent privacy/persistence review passed. Desktop/mobile browser QA confirmed a saved removal after a lost response and refresh, one audit on exact retry, persistent notices and recovery draft continuity. All 1,945 baseline rooms, 4,121 seats and related records preserved. Positive authenticated production admin acceptance remains pending authorized QA operator access; full admin and rules gates remain open.
2026-09-22 12:01:22 +10:00

78 lines
5.4 KiB
TypeScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { clearAdminRoomCreation, completeAdminRoomCreation, newAdminRoomCreationRequest, readAdminRoomCreation, saveAdminRoomCreation, validAdminRoomCreationResult } from '../lib/admin-room-creation-client';
import type { AdminRoomCreationResult } from '../lib/admin-room-creation';
const fields = () => ({ name: ' Host QA ', faction: 'atreides' as const, advanced: true, techTokens: true, strongholdCards: true,
bots: [{ faction: 'fremen' as const, difficulty: 'Easy' as const }, { faction: 'guild' as const, difficulty: 'Hard' as const }], reason: ' Dedicated QA lobby ' });
function storage() {
const values = new Map<string, string>();
return { values, getItem: (key: string) => values.get(key) ?? null, setItem: (key: string, value: string) => { values.set(key, value); }, removeItem: (key: string) => { values.delete(key); } };
}
const receipt = (operationId: string): AdminRoomCreationResult => ({ operationId, code: 'ABCD2345', hostId: crypto.randomUUID(), replayed: true, hostAccess: true });
void test('a removed room confirmation cannot erase its only creation proof before restoration', () => {
const tab = storage(), input = newAdminRoomCreationRequest(fields());
saveAdminRoomCreation(tab, 'a', input);
const result = { ...receipt(input.operationId), hostAccess: false, roomRemoved: true as const };
assert.equal(validAdminRoomCreationResult(result), true);
assert.equal(validAdminRoomCreationResult({ ...result, hostAccess: true }), false);
assert.equal(validAdminRoomCreationResult({ ...result, roomRemoved: false }), false);
assert.throws(() => completeAdminRoomCreation(tab, 'a', input, result), /temporarily removed/);
assert.deepEqual(readAdminRoomCreation(tab, 'a'), { kind: 'pending', input });
const restored = receipt(input.operationId);
completeAdminRoomCreation(tab, 'a', input, restored);
assert.deepEqual(readAdminRoomCreation(tab, 'a'), { kind: 'completed', result: restored });
});
void test('creation retry preserves one exact private host proof and roster order in its original administrator scope', () => {
const tab = storage(), input = newAdminRoomCreationRequest(fields());
assert.equal(input.name, 'Host QA'); assert.equal(input.reason, 'Dedicated QA lobby');
assert.match(input.sessionToken, /^[0-9a-f]{64}$/);
saveAdminRoomCreation(tab, 'operator-a', input);
assert.deepEqual(readAdminRoomCreation(tab, 'operator-a'), { kind: 'pending', input });
assert.equal(readAdminRoomCreation(tab, 'operator-b'), null);
assert.throws(() => saveAdminRoomCreation(tab, 'operator-a', newAdminRoomCreationRequest(fields())), /Resolve the saved/);
assert.throws(() => saveAdminRoomCreation(tab, 'operator-a', { ...input, bots: [...input.bots].reverse() }), /Resolve the saved/);
saveAdminRoomCreation(tab, 'operator-a', input);
assert.deepEqual(readAdminRoomCreation(tab, 'operator-a'), { kind: 'pending', input });
});
void test('only a matching valid receipt replaces the private retry proof with safe completed-room metadata', () => {
const tab = storage(), input = newAdminRoomCreationRequest(fields());
saveAdminRoomCreation(tab, 'a', input);
assert.throws(() => completeAdminRoomCreation(tab, 'a', input, receipt(crypto.randomUUID())), /did not confirm/);
assert.equal(readAdminRoomCreation(tab, 'a')?.kind, 'pending');
const result = receipt(input.operationId);
completeAdminRoomCreation(tab, 'a', input, result);
assert.deepEqual(readAdminRoomCreation(tab, 'a'), { kind: 'completed', result });
const raw = [...tab.values.values()].join('');
assert.equal(raw.includes(input.sessionToken), false);
assert.equal(raw.includes(input.reason), false);
assert.throws(() => saveAdminRoomCreation(tab, 'a', newAdminRoomCreationRequest(fields())), /Resolve the saved/);
clearAdminRoomCreation(tab, 'a');
assert.equal(readAdminRoomCreation(tab, 'a'), null);
});
void test('unavailable, corrupt or replaced tab storage never silently authorizes a different creation', () => {
const tab = storage(), input = newAdminRoomCreationRequest(fields());
assert.throws(() => saveAdminRoomCreation({ ...tab, setItem() {} }, 'a', input), /could not be saved/);
saveAdminRoomCreation(tab, 'a', input);
const key = [...tab.values.keys()][0];
tab.values.set(key, '{broken');
assert.throws(() => readAdminRoomCreation(tab, 'a'), /unreadable/);
assert.throws(() => saveAdminRoomCreation(tab, 'a', input), /unreadable/);
assert.equal(tab.values.get(key), '{broken');
tab.values.set(key, JSON.stringify({ kind: 'pending', input: newAdminRoomCreationRequest(fields()) }));
assert.throws(() => completeAdminRoomCreation(tab, 'a', input, receipt(input.operationId)), /record changed/);
});
void test('revoked host receipts remain readable without claiming access and malformed/secret-bearing results cannot clear proof', () => {
const result = { ...receipt(crypto.randomUUID()), hostAccess: false };
assert.equal(validAdminRoomCreationResult(result), true);
for (const invalid of [null, [], { ...result, hostAccess: undefined }, { ...result, code: result.code + '\n' }, { ...result, hostId: 'not-an-id' }, { ...result, sessionToken: 'private' }])
assert.equal(validAdminRoomCreationResult(invalid), false);
assert.throws(() => newAdminRoomCreationRequest({ ...fields(), strongholdCards: true, advanced: false }));
assert.throws(() => newAdminRoomCreationRequest({ ...fields(), bots: [{ faction: 'atreides', difficulty: 'Easy' }] }));
});