Add account based multiplayer hosting and bug report retention

This commit is contained in:
2026-10-10 16:24:34 +05:00
parent 9af71c85c2
commit fc6da6756d
33 changed files with 1538 additions and 102 deletions

View File

@@ -65,6 +65,107 @@ try {
])
).rows[0].room;
}
await db.query(
"insert into public.profiles(id,display_name) values($1,'Account host')",
[account],
);
const secondAccount = (
await db.query(
"insert into auth.users values(gen_random_uuid()) returning id",
)
).rows[0].id;
await db.query(
"insert into public.profiles(id,display_name) values($1,'Account friend')",
[secondAccount],
);
const accountRoom = async () =>
(
await db.query(
"select public.create_map_room($1,'normal','Forged host',4,$2,$3) as id",
[dataset, secret(1), account],
)
).rows[0].id;
await assert.rejects(
db.query(
"select public.create_map_room($1,'normal','Guest host',4,$2,null)",
[dataset, secret(4)],
),
/Log in to create/,
);
const identityRoom = await accountRoom();
const identityHost = (await act(identityRoom, 1)).players[0];
assert.equal(
identityHost.name,
"Account host",
"SQL ignores a forged host nickname",
);
assert.equal(
(
await db.query(
"select account_id from public.multiplayer_players where id=$1",
[identityHost.id],
)
).rows[0].account_id,
account,
"host linked atomically",
);
await act(identityRoom, 2, "join", { name: "Guest first" });
await db.query(
"select public.join_multiplayer_room($1,$2,$3,'Forged friend')",
[identityRoom, secret(3), secondAccount],
);
let identityView = await act(identityRoom, 3);
assert.equal(
identityView.players.find((p) => p.id === identityView.you).name,
"Account friend",
"signed-in join ignores a forged nickname",
);
await act(identityRoom, 1, "leave");
identityView = await act(identityRoom, 3);
assert.equal(
identityView.hostId,
identityView.you,
"host transfer skips a guest for an account",
);
await act(identityRoom, 3, "leave");
assert.equal(
(await act(identityRoom, 2)).status,
"closed",
"guest-only party closes when host leaves",
);
const guestOnly = await accountRoom();
await db.query(
"select public.join_multiplayer_room($1,$2,null,'Guest custom nickname')",
[guestOnly, secret(2)],
);
const guestView = await act(guestOnly, 2);
assert.equal(
guestView.players.find((p) => p.id === guestView.you)?.name,
"Guest custom nickname",
);
const cleanupEvent = (
await db.query("select public.publish_discord_party($1,$2) as id", [
guestOnly,
secret(1),
])
).rows[0].id;
await db.query(
"update public.discord_announcements set state='sent',channel_id='123456789012345678',message_id='123456789012345679' where id=$1",
[cleanupEvent],
);
await act(guestOnly, 1, "leave");
assert.ok(
(
await db.query(
"select closed_at from public.discord_announcements where id=$1",
[cleanupEvent],
)
).rows[0].closed_at,
"guest-only host departure also queues Discord cleanup",
);
console.log(
"Multiplayer SQL account identity: forged names rejected, guest joins retained, authenticated transfer and guest-only closure verified.",
);
for (const cap of [1, 17, null])
await assert.rejects(create(cap), /Choose between 2 and 16 players/);
const room = await create();
@@ -255,6 +356,15 @@ try {
await assert.rejects(chat(capacity, 16), /Chat permission/);
assert.equal((await act(capacity, 16)).you, null);
await act(capacity, 17, "join", { name: "Replacement" });
const nextHost = (await act(capacity, 2)).you;
await db.query(
"insert into public.profiles(id,display_name) values($1,'Next host') on conflict(id) do nothing",
[account],
);
await db.query(
"update public.multiplayer_players set account_id=$1 where id=$2",
[account, nextHost],
);
await act(capacity, 1, "leave");
await assert.rejects(
chat(capacity, 1, "Left", randomUUID()),