Files
WRNexusJS/packages/realtime/src/client.ts
T
Clintchiz 2c960fc1dc
Quality / quality (ubuntu-latest) (push) Failing after 9m49s
Quality / quality (windows-latest) (push) Canceled after 0s
refactor: migrate legacy wire namespace to wrn
2026-08-12 18:51:15 +05:30

58 lines
1.8 KiB
TypeScript

import { assertRealtimeRoomName, type RealtimeMessage } from "./messages.ts";
export interface BrowserRoomConnection {
readonly name: string;
send(message: unknown): BrowserRoomConnection;
on(
type: string | ((message: unknown) => void),
callback?: (message: unknown) => void,
): BrowserRoomConnection;
close(): void;
}
export interface WrnexusRealtimeWindow extends Window {
wrn?: {
room?: (name: string, query?: string) => BrowserRoomConnection;
};
}
const QUERY_KEY = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
export function roomQuery(
params: Record<string, string | number | boolean | null | undefined>,
): string {
const query = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (!QUERY_KEY.test(key)) throw new TypeError(`Invalid realtime query key: ${key}`);
if (value !== undefined && value !== null) query.set(key, String(value));
}
const result = query.toString();
if (result.length > 2_048) throw new RangeError("Realtime room query exceeds 2048 characters.");
return result;
}
export function connectRoom(
name: string,
options: {
query?: Record<string, string | number | boolean | null | undefined>;
window?: WrnexusRealtimeWindow;
} = {},
): BrowserRoomConnection {
const roomName = assertRealtimeRoomName(name);
const target = options.window ?? (globalThis as unknown as WrnexusRealtimeWindow);
const factory = target.wrn?.room;
if (!factory) {
throw new Error(
"WRN-REALTIME-CLIENT-NOT-READY: add a RealtimeRoom/data-room component before calling connectRoom().",
);
}
return factory(roomName, options.query ? roomQuery(options.query) : undefined);
}
export function sendRoomMessage<T>(
room: BrowserRoomConnection,
message: RealtimeMessage<T> | T,
): BrowserRoomConnection {
return room.send(message);
}