Hosted rooms: the hub's side
CI / test (push) Successful in 1m5s

Rooms made on the website (hosted_room, migration 0005), the REST routes in
docs/hosted-rooms.md, and the realtime room.* protocol: joining with the
capacity, adult and linked-account rules, seats, numbered messages with
forged senders dropped and a rate limit, closing. The Rooms page lists them,
with a form to make one and the owner's edit and close.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
dhkatzandClaude Opus 5.5 committed 2026-10-30 03:21:21 -07:00
1 parent 0c67232425
commit 2a1fc94df6
18 files changed
+3138 -52

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
// The fields of a hosted room, for making one and for editing it.
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { Textarea } from "@/components/ui/textarea";
import type { HostedRoom } from "@/lib/api";
export function RoomFields({ room, canAdult }: { room?: HostedRoom; canAdult: boolean }) {
return (
<>
<Field>
<FieldLabel htmlFor="name">Name</FieldLabel>
<Input id="name" name="name" defaultValue={room?.name} required maxLength={64} className="max-w-md" />
</Field>
<Field>
<FieldLabel htmlFor="description">Description</FieldLabel>
<Textarea id="description" name="description" defaultValue={room?.description} maxLength={512} rows={3} />
</Field>
<div className="grid gap-4 sm:grid-cols-3">
<Field>
<FieldLabel htmlFor="roomPid">Room shell</FieldLabel>
<Input
id="roomPid"
name="roomPid"
type="number"
inputMode="numeric"
min={1}
required
defaultValue={room?.roomPid}
placeholder="Product ID"
/>
<FieldDescription>An IMVU room product&apos;s ID, from its shop page.</FieldDescription>
</Field>
<Field>
<FieldLabel htmlFor="rating">Rating</FieldLabel>
<NativeSelect id="rating" name="rating" defaultValue={room?.rating ?? "general"} className="w-full">
<NativeSelectOption value="general">General</NativeSelectOption>
<NativeSelectOption value="adult" disabled={!canAdult && room?.rating !== "adult"}>
Adult
</NativeSelectOption>
</NativeSelect>
{!canAdult && <FieldDescription>Adult needs an age-verified account.</FieldDescription>}
</Field>
<Field>
<FieldLabel htmlFor="maxUsers">Max people</FieldLabel>
<Input
id="maxUsers"
name="maxUsers"
type="number"
inputMode="numeric"
min={2}
max={30}
required
defaultValue={room?.maxUsers ?? 10}
/>
</Field>
</div>
</>
);
}