FluxyChat

Rooms

Rooms

One Durable Object per room. Attach, options, and the room bag.

A room is one Durable Object plus D1. Chat, presence, occupancy, typing, locks, and cursors share the JSON WebSocket. Yjs uses a second binary connection on the same /ws/room/:id route.

Hosted is beta. Pin @fluxy-chat/sdk (see status and limits).

Get a room

import { FluxyChatClient } from "@fluxy-chat/sdk";

const client = new FluxyChatClient({
  baseUrl: workerUrl,
  token: memberJwt,
  userId: "ada",
});

const room = await client.rooms.get("lobby");
await room.attach();

client.room("lobby") is the same object, without waiting. await room.attach() resolves when the socket is attached, or rejects on suspended / failed. rooms.get rejects if you request the same id with different options (unable to get room; options differ). rooms.release("lobby") detaches and drops the cache. client.close() / rooms.dispose() tears down every tracked room.

useChat({ roomId }) still connects as a side effect. For attach-on-purpose, use useChat({ roomId, autoConnect: false }) and call attach(), or wrap with FluxyRoomProvider.

What is on the bag

FieldJob
messagesSend, history, edit, delete, message reactions
presenceEnter, leave, update. Leave does not close the socket
occupancySocket count vs unique members
typingEphemeral keystroke / stop
reactionsRoom-level bursts (room_reaction), not message emoji
cursorsBatched pointer + last-position map
locksExclusive lock on the Room DO
locationsUI locus (uiLocation), not GPS
membersRoster + leaver TTL
objectsShared JSON bag (derived / derived_set)
statusAttach lifecycle
onDiscontinuityResume hole you could not fill

React hooks with the same names live on FluxyRoomProvider: useMessages, usePresence, useOccupancy, useTyping, useLocks, useCursors, useMembers, useRoomStatus.

Dedicated pages: Message history, Message replies, Share media, UI kit.

Options

const room = await client.rooms.get("lobby", {
  occupancy: { enableEvents: true },
  messages: { rawMessageReactions: false },
});

Occupancy events default on (same socket, not a second channel). Set enableEvents: false if you only want occupancy.get(). Raw message reactions default off.

On this page