import { type InferState, type InferInput, type NormalizeRoomType, type ExtractRoomMessages, type ExtractRoomClientMessages, type ExtractMessageType, type ExtractResponseType } from '@colyseus/shared-types'; import { Schema } from '@colyseus/schema'; import type { InputHandle, InputOptions } from './input/InputHandle.ts'; export { type InputHandle, type InputOptions } from './input/InputHandle.ts'; import { Packr } from 'msgpackr'; import { Connection } from './Connection.ts'; import { Serializer } from './serializer/Serializer.ts'; import { SchemaConstructor, SchemaSerializer } from './serializer/SchemaSerializer.ts'; import { type RoomClock } from './RoomClock.ts'; import { type ReconnectionOptions } from './Reconnection.ts'; import { type RequestOptions } from './RoomRequest.ts'; export type InferSerializer = [State] extends [Schema] ? SchemaSerializer : Serializer; export declare class Room> { #private; roomId: string; sessionId: string; reconnectionToken: string; name: string; connection: Connection; onStateChange: { once: (cb: (state: State) => void) => void; remove: (cb: (state: State) => void) => void; invoke: (state: State) => void; invokeAsync: (state: State) => Promise; clear: () => void; } & ((this: any, cb: (state: State) => void) => import("./core/signal.ts").EventEmitter<(state: State) => void>); onError: { once: (cb: (code: number, message?: string) => void) => void; remove: (cb: (code: number, message?: string) => void) => void; invoke: (code: number, message?: string) => void; invokeAsync: (code: number, message?: string) => Promise; clear: () => void; } & ((this: any, cb: (code: number, message?: string) => void) => import("./core/signal.ts").EventEmitter<(code: number, message?: string) => void>); onLeave: { once: (cb: (code: number, reason?: string) => void) => void; remove: (cb: (code: number, reason?: string) => void) => void; invoke: (code: number, reason?: string) => void; invokeAsync: (code: number, reason?: string) => Promise; clear: () => void; } & ((this: any, cb: (code: number, reason?: string) => void) => import("./core/signal.ts").EventEmitter<(code: number, reason?: string) => void>); onReconnect: { once: (cb: () => void) => void; remove: (cb: () => void) => void; invoke: () => void; invokeAsync: () => Promise; clear: () => void; } & ((this: any, cb: () => void) => import("./core/signal.ts").EventEmitter<() => void>); onDrop: { once: (cb: (code: number, reason?: string) => void) => void; remove: (cb: (code: number, reason?: string) => void) => void; invoke: (code: number, reason?: string) => void; invokeAsync: (code: number, reason?: string) => Promise; clear: () => void; } & ((this: any, cb: (code: number, reason?: string) => void) => import("./core/signal.ts").EventEmitter<(code: number, reason?: string) => void>); protected onJoin: { once: (cb: (...args: any[]) => void | Promise) => void; remove: (cb: (...args: any[]) => void | Promise) => void; invoke: (...args: any[]) => void; invokeAsync: (...args: any[]) => Promise; clear: () => void; } & ((this: any, cb: (...args: any[]) => void | Promise) => import("./core/signal.ts").EventEmitter<(...args: any[]) => void | Promise>); serializerId: string; serializer: InferSerializer; reconnection: ReconnectionOptions; protected joinedAtTime: number; /** * Server-time + RTT estimator, driven by the {@link ProtocolModifier.TIMED} * prefix that servers emit when `defineInput()` was called. * * PRESENCE CONTRACT: `clock` is never `undefined` and always satisfies * {@link RoomClock} — every member, including `renderNow()`, is callable * with no optional chaining and no fallback. * * - Defaults to a shared frozen {@link NULL_CLOCK} so `room.clock.serverNow()` * always works. The shim returns the client's own `performance.now()` and * reports `0` for RTT. Rooms that never call `defineInput()` keep this * stub for the whole session — zero allocation cost for chat / lobby / * turn-based rooms. * - After handshake on an input room, a default {@link RoomClockImpl} is * instantiated. Users can swap their own implementation in via * `room.clock = new MyClock()` between `await joinOrCreate(...)` and * the first state message (any state-message arrival is on a future * microtask, so a synchronous swap is race-free). A custom clock with no * slew state of its own satisfies the `renderNow` guarantee by aliasing: * `renderNow() { return this.serverNow(); }`. */ clock: RoomClock; protected onMessageHandlers: import("./core/nanoevents.ts").Emitter; protected packr: Packr; protected sharedBuffer: Uint8Array; /** * Default time (ms) a `room.request()` / `room.send(..., callback)` waits * for a reply before rejecting. Class-level default — tune globally via * `Room.defaultRequestTimeout = ms`; override per-call with the `timeout` option. */ static defaultRequestTimeout: number; constructor(name: string, rootSchema?: SchemaConstructor); connect(endpoint: string, options?: any, headers?: any): void; leave(consented?: boolean): Promise; onMessage>>(message: MessageType, callback: (payload: ExtractRoomClientMessages>[MessageType]) => void): () => void; onMessage(type: "*", callback: (messageType: string | number, payload: Payload) => void): () => void; onMessage(type: [keyof ExtractRoomClientMessages>] extends [never] ? (string | number) : never, callback: (payload: Payload) => void): () => void; ping(callback: (ms: number) => void): void; send>>(messageType: MessageType, payload?: ExtractMessageType>[MessageType]>): void; send>>(messageType: MessageType, payload: ExtractMessageType>[MessageType]>, callback: (response: ExtractResponseType>[MessageType]>, error?: Error) => void): void; send(messageType: [keyof ExtractRoomMessages>] extends [never] ? (string | number) : never, payload?: Payload): void; send(messageType: [keyof ExtractRoomMessages>] extends [never] ? (string | number) : never, payload: Payload, callback: (response: Response, error?: Error) => void): void; /** * Send a message and await the server's reply. The server answers by * returning a value from its matching `onMessage(type, ...)` handler. * * Rejects if the handler throws, if no handler is registered, if the * connection closes first, or if no reply arrives within `timeout` * (defaults to {@link Room.defaultRequestTimeout}). * * @example * ```typescript * const profile = await room.request("get-profile", { id: 42 }); * ``` */ request>>(messageType: MessageType, payload?: ExtractMessageType>[MessageType]>, options?: RequestOptions): Promise>[MessageType]>>; request(messageType: [keyof ExtractRoomMessages>] extends [never] ? (string | number) : never, payload?: Payload, options?: RequestOptions): Promise; sendUnreliable(type: string | number, message?: T): void; sendBytes(type: string | number, bytes: Uint8Array): void; /** * Get the per-room input handle. Lazily created on first call and cached; * subsequent calls return the same handle (options on later calls are * ignored — a warning fires once if they differ from the handle's config). * * Schema discovery, in order: * 1. `options.type` — explicit constructor (overrides everything). * 2. Server-sent reflection from the JOIN handshake — populated when the * server room called `defineInput()`. The synthesized class has the * same fields as the server's input schema; `instanceof YourInput` * won't pass on it. * * Throws if neither source has produced a constructor. * * Inputs are always delta-encoded; every `send()` transmits one input * (a body-less frame when nothing changed). For rollback netcode, prefer * `{ mode: "unreliable", historySize: 4 }`: tiny per-tick payloads, * redundancy across drops, idempotent under reordering. * * @example * ```typescript * const room = await client.joinOrCreate("fps"); * const input = room.input({ mode: "unreliable" }); // type from server * // each simulation tick: * input.data.seq++; * input.data.vx = vx; * input.data.vy = vy; * input.send(); * ``` */ input] extends [never] ? any : InferInput)>(options?: InputOptions): InputHandle; get state(): State; removeAllListeners(): void; protected onMessageCallback(event: MessageEvent): void; private dispatchMessage; private destroy; private getMessageHandlerKey; private handleReconnection; private retryReconnection; }