import { ExtractRoomClientMessages, InferState, NormalizeRoomType } from "@colyseus/shared-types"; import { Room, RoomAvailable, SeatReservation } from "@colyseus/sdk"; import { ArraySchema, MapSchema, Schema } from "@colyseus/schema"; import { DependencyList, ReactNode } from "react"; //#region src/schema/createSnapshot.d.ts /** * Remove function properties from a type. */ type OmitFunctions = Omit; /** * Recursively applies `readonly` to all properties of a type. */ type DeepReadonly = T extends (infer R)[] ? ReadonlyArray> : T extends Record ? { readonly [K in keyof T]: DeepReadonly } : T; /** * Transforms a Colyseus Schema type into an immutable, plain JavaScript type. * * - `ArraySchema` becomes `readonly T[]` * - `MapSchema` becomes `Readonly>` * - `Schema` subclasses become plain objects with only data properties * - Primitives remain unchanged * * @template T - The Colyseus Schema type to snapshot */ type Snapshot = DeepReadonly ? Snapshot[] : T extends MapSchema ? Record> : T extends Schema ? { [K in keyof OmitFunctions]: Snapshot[K]> } : T>; //#endregion //#region src/schema/useRoomState.d.ts /** * React hook that provides immutable snapshots of Colyseus room state * with structural sharing to minimize re-renders. * * This hook subscribes to state changes from the room's Colyseus decoder * and produces plain JavaScript snapshots of the state. Unchanged portions * of the state tree maintain referential equality between renders, enabling * efficient React component updates. * * @template State - The root Schema type of the room state * @template U - The selected portion of state (defaults to full state) * * @param room - The Colyseus room instance whose state should be snapshotted * @param selector - Optional function to select a portion of the state * * @returns The snapshotted, immutable state * * @example * ```tsx * // Use the full state * const state = useRoomState(room); * * // Use with a selector to only subscribe to part of the state * const players = useRoomState(room, (s) => s.players); * ``` */ declare function useRoomState(selector: (state: InferState) => U): Snapshot | undefined; declare function useRoomState, U = State>(room: Room | null | undefined, selector?: (state: State) => U): Snapshot | undefined; //#endregion //#region src/room/useRoom.d.ts /** * Return type of the useRoom hook. */ interface UseRoomResult { /** The connected Room instance, or undefined while connecting or on error. */ room: Room | undefined; /** The error if connection failed, or undefined. */ error: Error | undefined; /** True while the connection promise is pending. */ isConnecting: boolean; } /** * React hook that manages the lifecycle of a Colyseus room connection. * * Connects to a room by calling the provided callback, handles cleanup * on unmount, and supports reconnection when dependencies change. * Properly handles React StrictMode's double mount/unmount cycle * without creating duplicate connections. * * @template T - The Room type parameter (room definition type) * @template State - The Room state type parameter * * @param callback - A function returning Promise>, or a falsy * value to skip connection. Covers all Colyseus matchmaking methods: * joinOrCreate, join, create, joinById, consumeSeatReservation. * @param deps - Optional dependency array. When any value changes, * the old room is left and a new connection is established. * Defaults to [] (connect once). * * @returns An object containing room, error, and isConnecting. * * @example * ```tsx * // joinOrCreate * const { room } = useRoom(() => client.joinOrCreate("game_room", options), [roomName]); * * // joinById * const { room } = useRoom(() => client.joinById(roomId, options), [roomId]); * * // consumeSeatReservation * const { room } = useRoom(() => client.consumeSeatReservation(reservation), [reservation]); * * // Compose with useRoomState for state snapshots * const state = useRoomState(room); * * // Conditional connection * const { room } = useRoom(isReady ? () => client.joinOrCreate("game") : null, [isReady]); * ``` */ declare function useRoom>(callback: (() => Promise>) | null | undefined | false, deps?: DependencyList): UseRoomResult; //#endregion //#region src/room/useRoomMessage.d.ts declare function useRoomMessage>>(room: Room | null | undefined, type: MessageType, callback: (payload: ExtractRoomClientMessages>[MessageType]) => void): void; declare function useRoomMessage(room: Room | null | undefined, type: "*", callback: (messageType: string | number, payload: any) => void): void; declare function useRoomMessage(room: Room | null | undefined, type: [keyof ExtractRoomClientMessages>] extends [never] ? (string | number) : never, callback: (payload: Payload) => void): void; //#endregion //#region src/context/createRoomContext.d.ts interface RoomProviderProps { connect: (() => Promise>) | null | undefined | false; deps?: DependencyList; children: ReactNode; } /** * Creates a set of hooks and a Provider for sharing a Colyseus room * across React reconciler boundaries (e.g. DOM + React Three Fiber). * * Uses a closure-scoped external store (not React Context), so hooks * work in any reconciler tree that imports them. * * @template T - A Room definition type or a Schema state type. * When a Schema type is passed, it is used directly as the state. * When a Room definition type is passed, the state is inferred via `InferState`. * * @example * ```tsx * const { RoomProvider, useRoom, useRoomState } = createRoomContext(); * * // Wrap your app * client.joinOrCreate("my_room")}> * * * * // In any component (DOM or R3F): * const { room } = useRoom(); * const players = useRoomState((s) => s.players); * room.send("action", data); * ``` */ declare function createRoomContext>(): { RoomProvider: ({ connect, deps, children }: RoomProviderProps) => ReactNode; useRoom: () => UseRoomResult; useRoomState: (selector?: (state: State) => U) => Snapshot | undefined; useRoomMessage: { >>(type: MessageType, callback: (payload: ExtractRoomClientMessages>[MessageType]) => void): void; (type: "*", callback: (messageType: string | number, payload: any) => void): void; (type: [keyof ExtractRoomClientMessages>] extends [never] ? (string | number) : never, callback: (payload: Payload) => void): void; }; }; //#endregion //#region src/room/useLobbyRoom.d.ts interface UseLobbyRoomResult { rooms: RoomAvailable[]; room: Room | undefined; error: Error | undefined; isConnecting: boolean; } declare function useLobbyRoom(callback: (() => Promise) | null | undefined | false, deps?: DependencyList): UseLobbyRoomResult; //#endregion //#region src/context/createLobbyContext.d.ts interface LobbyProviderProps { connect: (() => Promise) | null | undefined | false; deps?: DependencyList; children: ReactNode; } /** * Creates a LobbyProvider and useLobby hook for sharing lobby room data * (available rooms + metadata) globally across your app. * * Uses a closure-scoped external store (not React Context), so the hook * works in any reconciler tree that imports it. * * This is useful when you need lobby metadata available persistently * alongside an active game room — not just on a lobby screen. * * @template Metadata - The type of room metadata * * @example * ```tsx * const { LobbyProvider, useLobby } = createLobbyContext(); * * // Wrap your app (can nest with RoomProvider) * client.joinLobby()}> * client.joinOrCreate("game")}> * * * * * // In any component: * const { rooms } = useLobby(); * rooms.map(r => r.metadata.displayName) * ``` */ declare function createLobbyContext(): { LobbyProvider: ({ connect, deps, children }: LobbyProviderProps) => ReactNode; useLobby: () => UseLobbyRoomResult; }; //#endregion //#region src/room/useQueueRoom.d.ts /** * Return type of the useQueueRoom hook. */ interface UseQueueRoomResult> { /** The match room after the seat has been consumed, undefined otherwise. */ room: Room | undefined; /** The queue room while waiting. Undefined before connection and after match is joined. */ queue: Room | undefined; /** Number of clients in the current matchmaking group. */ clients: number; /** The seat reservation, once received from the queue. */ seat: SeatReservation | undefined; /** Connection or matchmaking error. */ error: Error | undefined; /** True while connected to the queue and waiting for a match. */ isWaiting: boolean; } /** * React hook that manages the lifecycle of a Colyseus QueueRoom, * automatically consuming the seat reservation when a match is found. * * Handles connecting to the queue room, tracking group size, * receiving the seat reservation, sending "confirm", and consuming * the seat to join the match room. Cleans up both rooms on unmount. * * @template T - The match Room type parameter * @template State - The match Room state type parameter * * @param connect - A function returning a promise to the queue room, * or a falsy value to skip connection. * @param consume - A function that consumes a seat reservation and * returns a promise to the match room. * @param deps - Optional dependency array. When any value changes, * the queue is left and re-joined. * * @example * ```tsx * const { room, clients, isWaiting, error } = useQueueRoom( * () => client.joinOrCreate("queue", { rank: 1200 }), * (reservation) => client.consumeSeatReservation(reservation), * [rank] * ); * * if (error) return
Error: {error.message}
; * if (room) return ; * if (isWaiting) return
Waiting... {clients} players in group
; * return
Connecting...
; * ``` */ declare function useQueueRoom>(connect: (() => Promise) | null | undefined | false, consume: (reservation: SeatReservation) => Promise>, deps?: DependencyList): UseQueueRoomResult; //#endregion export { type Snapshot, type UseLobbyRoomResult, type UseQueueRoomResult, type UseRoomResult, createLobbyContext, createRoomContext, useLobbyRoom, useQueueRoom, useRoom, useRoomMessage, useRoomState };