@fluxstack/live 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -296,11 +296,229 @@ interface IRoomPubSubAdapter {
296
296
  publishStateChange(roomId: string, updates: any): Promise<void>;
297
297
  }
298
298
 
299
+ interface LiveRoomManagerInterface {
300
+ joinRoom<TState = any>(componentId: string, roomId: string, ws: any, initialState?: TState, options?: {
301
+ deepDiff?: boolean;
302
+ deepDiffDepth?: number;
303
+ serverOnlyState?: boolean;
304
+ }, joinContext?: {
305
+ userId?: string;
306
+ payload?: any;
307
+ }): {
308
+ state: TState;
309
+ rejected?: false;
310
+ } | {
311
+ rejected: true;
312
+ reason: string;
313
+ };
314
+ leaveRoom(componentId: string, roomId: string, leaveReason?: 'leave' | 'disconnect' | 'cleanup'): void;
315
+ cleanupComponent(componentId: string): void;
316
+ emitToRoom(roomId: string, event: string, data: any, excludeComponentId?: string): number;
317
+ setRoomState(roomId: string, updates: any, excludeComponentId?: string): void;
318
+ getRoomState<TState = any>(roomId: string): TState;
319
+ isInRoom(componentId: string, roomId: string): boolean;
320
+ getComponentRooms(componentId: string): string[];
321
+ getMemberCount?(roomId: string): number;
322
+ getRoomInstance?(roomId: string): LiveRoom<any, any, any> | undefined;
323
+ getStats(): any;
324
+ }
325
+ interface LiveComponentContext {
326
+ roomEvents: RoomEventBus;
327
+ roomManager: LiveRoomManagerInterface;
328
+ }
329
+ /**
330
+ * Set the global Live Component context.
331
+ * Called once by LiveServer.start() before any components are mounted.
332
+ */
333
+ declare function setLiveComponentContext(ctx: LiveComponentContext): void;
334
+ /**
335
+ * Get the global Live Component context.
336
+ * Throws if LiveServer.start() hasn't been called yet.
337
+ */
338
+ declare function getLiveComponentContext(): LiveComponentContext;
339
+
340
+ declare const BINARY_ROOM_EVENT = 2;
341
+ declare const BINARY_ROOM_STATE = 3;
342
+ interface RoomCodec {
343
+ encode(data: unknown): Uint8Array;
344
+ decode(buf: Uint8Array): unknown;
345
+ }
346
+ declare const msgpackCodec: RoomCodec;
347
+ declare const jsonCodec: RoomCodec;
348
+ type RoomCodecOption = 'msgpack' | 'json' | RoomCodec;
349
+ declare function resolveCodec(option?: RoomCodecOption): RoomCodec;
350
+ /**
351
+ * Build a binary room frame.
352
+ * Format: [frameType:u8][compIdLen:u8][compId:utf8][roomIdLen:u8][roomId:utf8][eventLen:u16BE][event:utf8][payload]
353
+ */
354
+ declare function buildRoomFrame(frameType: number, componentId: string, roomId: string, event: string, payload: Uint8Array): Uint8Array;
355
+ /**
356
+ * Build frame tail (roomId + event + payload) that is shared across all members.
357
+ * Per-member: prepend [frameType:u8][compIdLen:u8][compId:utf8].
358
+ */
359
+ declare function buildRoomFrameTail(roomId: string, event: string, payload: Uint8Array): Uint8Array;
360
+ /**
361
+ * Prepend per-member header to a shared tail.
362
+ * Header: [frameType:u8][compIdLen:u8][compId:utf8]
363
+ */
364
+ declare function prependMemberHeader(frameType: number, componentId: string, tail: Uint8Array): Uint8Array;
365
+ /**
366
+ * Parse a binary room frame header (client-side).
367
+ * Returns parsed fields and the payload offset.
368
+ */
369
+ declare function parseRoomFrame(buf: Uint8Array): {
370
+ frameType: number;
371
+ componentId: string;
372
+ roomId: string;
373
+ event: string;
374
+ payload: Uint8Array;
375
+ } | null;
376
+
377
+ interface RoomJoinContext {
378
+ componentId: string;
379
+ userId?: string;
380
+ payload?: any;
381
+ }
382
+ interface RoomLeaveContext {
383
+ componentId: string;
384
+ userId?: string;
385
+ reason: 'leave' | 'disconnect' | 'cleanup';
386
+ }
387
+ interface RoomEventContext {
388
+ componentId: string;
389
+ userId?: string;
390
+ }
391
+ interface LiveRoomOptions {
392
+ /** Enable deep diff for room state. Default: true */
393
+ deepDiff?: boolean;
394
+ /** Max recursion depth for deep diff. Default: 3 */
395
+ deepDiffDepth?: number;
396
+ /** Max number of members allowed. Undefined = unlimited */
397
+ maxMembers?: number;
398
+ /**
399
+ * Wire codec for room messages. Default: 'msgpack' (binary).
400
+ * - 'msgpack' — Built-in MessagePack encoder (zero deps, ~30% smaller, ~2-3x faster)
401
+ * - 'json' — Standard JSON (text-based, larger but human-readable)
402
+ * - Custom RoomCodec object with encode/decode methods
403
+ */
404
+ codec?: RoomCodecOption;
405
+ }
406
+ /**
407
+ * Base class for typed rooms with lifecycle hooks and public/private state.
408
+ *
409
+ * @typeParam TState - Public state synced to all connected clients
410
+ * @typeParam TMeta - Private server-only metadata (never broadcasted)
411
+ * @typeParam TEvents - Event map for typed emit/on
412
+ */
413
+ declare abstract class LiveRoom<TState extends Record<string, any> = Record<string, any>, TMeta extends Record<string, any> = Record<string, any>, TEvents extends Record<string, any> = Record<string, any>> {
414
+ /** Unique room type name. Used as prefix in compound room IDs (e.g. "chat:lobby"). */
415
+ static roomName: string;
416
+ /** Initial public state template. Cloned per room instance. */
417
+ static defaultState: Record<string, any>;
418
+ /** Initial private metadata template. Cloned per room instance. */
419
+ static defaultMeta: Record<string, any>;
420
+ /** Room-level options */
421
+ static $options?: LiveRoomOptions;
422
+ /** The unique room instance identifier (e.g. "chat:lobby") */
423
+ readonly id: string;
424
+ /** Public state — synced to all connected clients via setState(). */
425
+ state: TState;
426
+ /** Private metadata — NEVER leaves the server. Mutate directly. */
427
+ meta: TMeta;
428
+ /** @internal Type brand for client-side event inference.
429
+ * No runtime value. Usage: `$room<CounterRoom>('id').on(...)` */
430
+ readonly $events: TEvents;
431
+ /** @internal Reference to the room manager for broadcasting */
432
+ protected readonly _manager: LiveRoomManagerInterface;
433
+ constructor(id: string, manager: LiveRoomManagerInterface);
434
+ /**
435
+ * Update public state and broadcast changes to all room members.
436
+ * Uses deep diff by default — only changed fields are sent over the wire.
437
+ */
438
+ setState(updates: Partial<TState>): void;
439
+ /**
440
+ * Emit a typed event to all members in this room.
441
+ * @returns Number of members notified
442
+ */
443
+ emit<K extends keyof TEvents & string>(event: K, data: TEvents[K]): number;
444
+ /** Get current member count */
445
+ get memberCount(): number;
446
+ /**
447
+ * Called when a component attempts to join this room.
448
+ * Return false to reject the join.
449
+ */
450
+ onJoin(_ctx: RoomJoinContext): void | false | Promise<void | false>;
451
+ /**
452
+ * Called after a component leaves this room.
453
+ */
454
+ onLeave(_ctx: RoomLeaveContext): void | Promise<void>;
455
+ /**
456
+ * Called when an event is emitted to this room.
457
+ * Can intercept/validate events before broadcasting.
458
+ */
459
+ onEvent(_event: string, _data: any, _ctx: RoomEventContext): void | Promise<void>;
460
+ /**
461
+ * Called once when the room is first created (first member joins).
462
+ */
463
+ onCreate(): void | Promise<void>;
464
+ /**
465
+ * Called when the last member leaves and the room is about to be destroyed.
466
+ * Return false to keep the room alive (e.g., persist state).
467
+ */
468
+ onDestroy(): void | false | Promise<void | false>;
469
+ }
470
+ /** Extract the public state type from a LiveRoom subclass */
471
+ type InferRoomState<R> = R extends LiveRoom<infer S, any, any> ? S : Record<string, any>;
472
+ /** Extract the private meta type from a LiveRoom subclass */
473
+ type InferRoomMeta<R> = R extends LiveRoom<any, infer M, any> ? M : Record<string, any>;
474
+ /** Extract the events type from a LiveRoom subclass */
475
+ type InferRoomEvents<R> = R extends LiveRoom<any, any, infer E> ? E : Record<string, any>;
476
+ /** LiveRoom class constructor type */
477
+ type LiveRoomClass<R extends LiveRoom = LiveRoom> = {
478
+ new (id: string, manager: LiveRoomManagerInterface): R;
479
+ roomName: string;
480
+ defaultState: Record<string, any>;
481
+ defaultMeta: Record<string, any>;
482
+ $options?: LiveRoomOptions;
483
+ };
484
+
485
+ declare class RoomRegistry {
486
+ private rooms;
487
+ /**
488
+ * Register a LiveRoom subclass.
489
+ * @throws If the class doesn't define a static roomName
490
+ */
491
+ register(roomClass: LiveRoomClass): void;
492
+ /**
493
+ * Get a registered room class by name.
494
+ */
495
+ get(name: string): LiveRoomClass | undefined;
496
+ /**
497
+ * Check if a room class is registered.
498
+ */
499
+ has(name: string): boolean;
500
+ /**
501
+ * Resolve a compound room ID (e.g. "chat:lobby") to its registered class.
502
+ * Returns undefined if the prefix doesn't match any registered room.
503
+ */
504
+ resolveFromId(roomId: string): LiveRoomClass | undefined;
505
+ /**
506
+ * Get all registered room names.
507
+ */
508
+ getRegisteredNames(): string[];
509
+ /**
510
+ * Check if a value is a LiveRoom subclass.
511
+ */
512
+ static isLiveRoomClass(cls: unknown): cls is LiveRoomClass;
513
+ }
514
+
299
515
  declare class LiveRoomManager {
300
516
  private roomEvents;
301
517
  private pubsub?;
302
518
  private rooms;
303
519
  private componentRooms;
520
+ /** Room registry for LiveRoom class lookup. Set by LiveServer. */
521
+ roomRegistry?: RoomRegistry;
304
522
  /**
305
523
  * @param roomEvents - Local server-side event bus
306
524
  * @param pubsub - Optional cross-instance pub/sub adapter (e.g. Redis).
@@ -309,28 +527,44 @@ declare class LiveRoomManager {
309
527
  */
310
528
  constructor(roomEvents: RoomEventBus, pubsub?: IRoomPubSubAdapter | undefined);
311
529
  /**
312
- * Component joins a room
530
+ * Component joins a room.
531
+ * @param options.deepDiff - Enable/disable deep diff for this room's state. Default: true
532
+ * @param joinContext - Optional context for LiveRoom lifecycle hooks (userId, payload)
313
533
  */
314
- joinRoom<TState = any>(componentId: string, roomId: string, ws: GenericWebSocket, initialState?: TState): {
534
+ joinRoom<TState = any>(componentId: string, roomId: string, ws: GenericWebSocket, initialState?: TState, options?: {
535
+ deepDiff?: boolean;
536
+ deepDiffDepth?: number;
537
+ serverOnlyState?: boolean;
538
+ }, joinContext?: {
539
+ userId?: string;
540
+ payload?: any;
541
+ }): {
315
542
  state: TState;
543
+ rejected?: false;
544
+ } | {
545
+ rejected: true;
546
+ reason: string;
316
547
  };
317
548
  /**
318
549
  * Component leaves a room
550
+ * @param leaveReason - Why the component is leaving. Default: 'leave'
319
551
  */
320
- leaveRoom(componentId: string, roomId: string): void;
552
+ leaveRoom(componentId: string, roomId: string, leaveReason?: 'leave' | 'disconnect' | 'cleanup'): void;
321
553
  /**
322
554
  * Component disconnects - leave all rooms.
323
- * Batches removals: removes member from all rooms first,
555
+ * Batches removals: calls onLeave hooks, removes member from all rooms,
324
556
  * then sends leave notifications in bulk.
325
557
  */
326
558
  cleanupComponent(componentId: string): void;
327
559
  /**
328
- * Emit event to all members in a room
560
+ * Emit event to all members in a room.
561
+ * For LiveRoom-backed rooms, calls onEvent() hook before broadcasting.
329
562
  */
330
563
  emitToRoom(roomId: string, event: string, data: any, excludeComponentId?: string): number;
331
564
  /**
332
565
  * Update room state.
333
- * Mutates state in-place with Object.assign to avoid full-object spread.
566
+ * When deepDiff is enabled (default), deep-diffs plain objects to send only changed fields.
567
+ * When disabled, uses shallow diff (reference equality) like classic behavior.
334
568
  */
335
569
  setRoomState(roomId: string, updates: any, excludeComponentId?: string): void;
336
570
  /**
@@ -339,17 +573,35 @@ declare class LiveRoomManager {
339
573
  getRoomState<TState = any>(roomId: string): TState;
340
574
  /**
341
575
  * Broadcast to all members in a room.
342
- * Serializes the message ONCE and sends the same string to all members.
576
+ *
577
+ * When the room has a binary codec (LiveRoom-backed), builds a binary frame
578
+ * once (encode payload + frame tail), then prepends per-member componentId header.
579
+ *
580
+ * When no codec (legacy rooms), uses JSON with serialize-once optimization:
581
+ * builds the JSON string template once, then inserts each member's componentId.
343
582
  */
344
583
  private broadcastToRoom;
345
584
  /**
346
585
  * Check if component is in a room
347
586
  */
348
587
  isInRoom(componentId: string, roomId: string): boolean;
588
+ /**
589
+ * Check if room state is server-only (no client writes)
590
+ */
591
+ isServerOnlyState(roomId: string): boolean;
349
592
  /**
350
593
  * Get rooms for a component
351
594
  */
352
595
  getComponentRooms(componentId: string): string[];
596
+ /**
597
+ * Get member count for a room
598
+ */
599
+ getMemberCount(roomId: string): number;
600
+ /**
601
+ * Get the LiveRoom instance for a room (if backed by a typed room class).
602
+ * Used by ComponentRoomProxy to expose custom methods.
603
+ */
604
+ getRoomInstance(roomId: string): LiveRoom<any, any, any> | undefined;
353
605
  /**
354
606
  * Get statistics
355
607
  */
@@ -363,80 +615,6 @@ declare class LiveRoomManager {
363
615
  };
364
616
  }
365
617
 
366
- type DebugEventType = 'COMPONENT_MOUNT' | 'COMPONENT_UNMOUNT' | 'COMPONENT_REHYDRATE' | 'STATE_CHANGE' | 'ACTION_CALL' | 'ACTION_RESULT' | 'ACTION_ERROR' | 'ROOM_JOIN' | 'ROOM_LEAVE' | 'ROOM_EMIT' | 'ROOM_EVENT_RECEIVED' | 'WS_CONNECT' | 'WS_DISCONNECT' | 'ERROR' | 'LOG';
367
- interface DebugEvent {
368
- id: string;
369
- timestamp: number;
370
- type: DebugEventType;
371
- componentId: string | null;
372
- componentName: string | null;
373
- data: Record<string, unknown>;
374
- }
375
- interface ComponentSnapshot {
376
- componentId: string;
377
- componentName: string;
378
- /** Developer-defined label for easier identification in the debugger */
379
- debugLabel?: string;
380
- state: Record<string, unknown>;
381
- rooms: string[];
382
- mountedAt: number;
383
- lastActivity: number;
384
- actionCount: number;
385
- stateChangeCount: number;
386
- errorCount: number;
387
- }
388
- interface DebugSnapshot {
389
- components: ComponentSnapshot[];
390
- connections: number;
391
- uptime: number;
392
- totalEvents: number;
393
- }
394
- interface DebugWsMessage {
395
- type: 'DEBUG_EVENT' | 'DEBUG_SNAPSHOT' | 'DEBUG_WELCOME' | 'DEBUG_DISABLED';
396
- event?: DebugEvent;
397
- snapshot?: DebugSnapshot;
398
- enabled?: boolean;
399
- timestamp: number;
400
- }
401
- declare class LiveDebugger {
402
- private events;
403
- private componentSnapshots;
404
- private debugClients;
405
- private _enabled;
406
- private startTime;
407
- private eventCounter;
408
- constructor(enabled?: boolean);
409
- get enabled(): boolean;
410
- set enabled(value: boolean);
411
- emit(type: DebugEventType | string, componentId: string | null, componentName: string | null, data?: Record<string, unknown>): void;
412
- trackComponentMount(componentId: string, componentName: string, initialState: Record<string, unknown>, room?: string, debugLabel?: string): void;
413
- trackComponentUnmount(componentId: string): void;
414
- trackStateChange(componentId: string, delta: Record<string, unknown>, fullState: Record<string, unknown>, source?: 'proxy' | 'setState' | 'rehydrate'): void;
415
- trackActionCall(componentId: string, action: string, payload: unknown): void;
416
- trackActionResult(componentId: string, action: string, result: unknown, duration: number): void;
417
- trackActionError(componentId: string, action: string, error: string, duration: number): void;
418
- trackRoomJoin(componentId: string, roomId: string): void;
419
- trackRoomLeave(componentId: string, roomId: string): void;
420
- trackRoomEmit(componentId: string, roomId: string, event: string, data: unknown): void;
421
- trackConnection(connectionId: string): void;
422
- trackDisconnection(connectionId: string, componentCount: number): void;
423
- trackError(componentId: string | null, error: string, context?: Record<string, unknown>): void;
424
- registerDebugClient(ws: GenericWebSocket): void;
425
- unregisterDebugClient(ws: GenericWebSocket): void;
426
- getSnapshot(): DebugSnapshot;
427
- getComponentState(componentId: string): ComponentSnapshot | null;
428
- getEvents(filter?: {
429
- componentId?: string;
430
- type?: DebugEventType;
431
- limit?: number;
432
- }): DebugEvent[];
433
- clearEvents(): void;
434
- private broadcastEvent;
435
- private sanitizeData;
436
- private sanitizeState;
437
- private updateSnapshot;
438
- }
439
-
440
618
  declare class LiveAuthManager {
441
619
  private providers;
442
620
  private defaultProviderName?;
@@ -953,46 +1131,19 @@ declare class WebSocketConnectionManager extends EventEmitter {
953
1131
  shutdown(): void;
954
1132
  }
955
1133
 
956
- interface LiveRoomManagerInterface {
957
- joinRoom<TState = any>(componentId: string, roomId: string, ws: any, initialState?: TState): {
958
- state: TState;
959
- };
960
- leaveRoom(componentId: string, roomId: string): void;
961
- cleanupComponent(componentId: string): void;
962
- emitToRoom(roomId: string, event: string, data: any, excludeComponentId?: string): number;
963
- setRoomState(roomId: string, updates: any, excludeComponentId?: string): void;
964
- getRoomState<TState = any>(roomId: string): TState;
965
- isInRoom(componentId: string, roomId: string): boolean;
966
- getComponentRooms(componentId: string): string[];
967
- getStats(): any;
968
- }
969
- interface LiveDebuggerInterface {
970
- enabled: boolean;
971
- trackStateChange(componentId: string, delta: Record<string, unknown>, fullState: Record<string, unknown>, source?: string): void;
972
- trackActionCall(componentId: string, action: string, payload: unknown): void;
973
- trackActionResult(componentId: string, action: string, result: unknown, duration: number): void;
974
- trackActionError(componentId: string, action: string, error: string, duration: number): void;
975
- trackRoomEmit(componentId: string, roomId: string, event: string, data: unknown): void;
976
- }
977
- interface LiveComponentContext {
978
- roomEvents: RoomEventBus;
979
- roomManager: LiveRoomManagerInterface;
980
- debugger?: LiveDebuggerInterface;
981
- }
982
- /**
983
- * Set the global Live Component context.
984
- * Called once by LiveServer.start() before any components are mounted.
985
- */
986
- declare function setLiveComponentContext(ctx: LiveComponentContext): void;
987
- /**
988
- * Get the global Live Component context.
989
- * Throws if LiveServer.start() hasn't been called yet.
990
- */
991
- declare function getLiveComponentContext(): LiveComponentContext;
992
-
993
1134
  /** Symbol key for singleton emit override */
994
1135
  declare const EMIT_OVERRIDE_KEY: unique symbol;
995
1136
 
1137
+ interface ComponentOptions {
1138
+ /** Enable deep diff for plain objects in setState(). Default: false */
1139
+ deepDiff?: boolean;
1140
+ /** Enable deep diff for room state updates. Default: true */
1141
+ roomDeepDiff?: boolean;
1142
+ /** Max recursion depth for deep diff (component + room). Default: 3 */
1143
+ deepDiffDepth?: number;
1144
+ /** When true, room state can only be set from server-side code. Client ROOM_STATE_SET is rejected. Default: false */
1145
+ serverOnlyRoomState?: boolean;
1146
+ }
996
1147
  declare abstract class LiveComponent<TState = ComponentState, TPrivate extends Record<string, any> = Record<string, any>> {
997
1148
  /** Component name for registry lookup - must be defined in subclasses */
998
1149
  static componentName: string;
@@ -1052,6 +1203,13 @@ declare abstract class LiveComponent<TState = ComponentState, TPrivate extends R
1052
1203
  * All clients share the same state.
1053
1204
  */
1054
1205
  static singleton?: boolean;
1206
+ /**
1207
+ * Component behavior options.
1208
+ *
1209
+ * @example
1210
+ * static $options = { deepDiff: true }
1211
+ */
1212
+ static $options?: ComponentOptions;
1055
1213
  readonly id: string;
1056
1214
  state: TState;
1057
1215
  protected ws: GenericWebSocket;
@@ -1073,7 +1231,30 @@ declare abstract class LiveComponent<TState = ComponentState, TPrivate extends R
1073
1231
  userId?: string;
1074
1232
  });
1075
1233
  get $private(): TPrivate;
1076
- get $room(): ServerRoomProxy;
1234
+ /**
1235
+ * Unified room accessor.
1236
+ *
1237
+ * Usage:
1238
+ * - `this.$room` — default room handle (legacy)
1239
+ * - `this.$room('roomId')` — untyped room handle (legacy)
1240
+ * - `this.$room(ChatRoom, 'lobby')` — typed handle with custom methods
1241
+ */
1242
+ get $room(): ServerRoomProxy & {
1243
+ <R extends LiveRoom<any, any, any>>(roomClass: LiveRoomClass<R>, instanceId: string): R & {
1244
+ readonly id: string;
1245
+ join: (payload?: any) => {
1246
+ rejected?: false;
1247
+ } | {
1248
+ rejected: true;
1249
+ reason: string;
1250
+ };
1251
+ leave: () => void;
1252
+ emit: R['emit'];
1253
+ on: <K extends string>(event: K, handler: (data: any) => void) => () => void;
1254
+ setState: (updates: Partial<R['state']>) => void;
1255
+ readonly memberCount: number;
1256
+ };
1257
+ };
1077
1258
  /**
1078
1259
  * List of room IDs this component is participating in.
1079
1260
  * Cached — invalidated on join/leave.
@@ -1238,7 +1419,6 @@ interface StateMigration {
1238
1419
  }
1239
1420
  interface ComponentRegistryDeps {
1240
1421
  authManager: LiveAuthManager;
1241
- debugger: LiveDebugger;
1242
1422
  stateSignature: StateSignatureManager;
1243
1423
  performanceMonitor: PerformanceMonitor;
1244
1424
  cluster?: IClusterAdapter;
@@ -1255,7 +1435,6 @@ declare class ComponentRegistry {
1255
1435
  private remoteSingletons;
1256
1436
  private cluster?;
1257
1437
  private authManager;
1258
- private debugger;
1259
1438
  private stateSignature;
1260
1439
  private performanceMonitor;
1261
1440
  constructor(deps: ComponentRegistryDeps);
@@ -1403,11 +1582,12 @@ interface LiveServerOptions {
1403
1582
  * component state is mirrored to a shared store (Redis), and actions on
1404
1583
  * remote singletons are forwarded to the owner instance. */
1405
1584
  cluster?: IClusterAdapter;
1585
+ /** LiveRoom classes to register. These define typed rooms with lifecycle hooks. */
1586
+ rooms?: LiveRoomClass[];
1406
1587
  }
1407
1588
  declare class LiveServer {
1408
1589
  readonly roomEvents: RoomEventBus;
1409
1590
  readonly roomManager: LiveRoomManager;
1410
- readonly debugger: LiveDebugger;
1411
1591
  readonly authManager: LiveAuthManager;
1412
1592
  readonly stateSignature: StateSignatureManager;
1413
1593
  readonly performanceMonitor: PerformanceMonitor;
@@ -1415,6 +1595,7 @@ declare class LiveServer {
1415
1595
  readonly connectionManager: WebSocketConnectionManager;
1416
1596
  readonly registry: ComponentRegistry;
1417
1597
  readonly rateLimiter: RateLimiterRegistry;
1598
+ readonly roomRegistry: RoomRegistry;
1418
1599
  private transport;
1419
1600
  private options;
1420
1601
  constructor(options: LiveServerOptions);
@@ -1422,6 +1603,11 @@ declare class LiveServer {
1422
1603
  * Register an auth provider.
1423
1604
  */
1424
1605
  useAuth(provider: LiveAuthProvider): this;
1606
+ /**
1607
+ * Register a LiveRoom class.
1608
+ * Can be called before start() to register room types dynamically.
1609
+ */
1610
+ useRoom(roomClass: LiveRoomClass): this;
1425
1611
  /**
1426
1612
  * Start the LiveServer: register WS + HTTP handlers on the transport.
1427
1613
  */
@@ -1452,6 +1638,11 @@ interface PendingMessage {
1452
1638
  * Messages are batched per-WS and sent as a JSON array.
1453
1639
  */
1454
1640
  declare function queueWsMessage(ws: GenericWebSocket, message: PendingMessage): void;
1641
+ /**
1642
+ * Send a binary message immediately (bypass batching).
1643
+ * Binary frames are never batched — they are self-framing.
1644
+ */
1645
+ declare function sendBinaryImmediate(ws: GenericWebSocket, data: Uint8Array): void;
1455
1646
  /**
1456
1647
  * Send a message immediately (bypass batching).
1457
1648
  * Used for ACTION_RESPONSE and other request-response patterns
@@ -1594,12 +1785,10 @@ declare function registerComponentLogging(componentId: string, config: LiveLogCo
1594
1785
  declare function unregisterComponentLogging(componentId: string): void;
1595
1786
  /**
1596
1787
  * Log a message gated by the component's logging config.
1597
- * Always forwarded to the Live Debugger when active.
1598
1788
  */
1599
1789
  declare function liveLog(category: LiveLogCategory, componentId: string | null, message: string, ...args: unknown[]): void;
1600
1790
  /**
1601
1791
  * Warn-level log gated by config.
1602
- * Always forwarded to the Live Debugger when active.
1603
1792
  */
1604
1793
  declare function liveWarn(category: LiveLogCategory, componentId: string | null, message: string, ...args: unknown[]): void;
1605
1794
 
@@ -1665,4 +1854,4 @@ interface UseTypedLiveComponentReturn<T extends LiveComponent<any>> {
1665
1854
  };
1666
1855
  }
1667
1856
 
1668
- export { ANONYMOUS_CONTEXT, type ActionNames, type ActionPayload, type ActionReturn, type ActiveUpload, AnonymousContext, AuthenticatedContext, type BinaryChunkHeader, type BroadcastMessage, type ClusterActionRequest, type ClusterActionResponse, type ClusterComponentState, type ClusterDeltaHandler, type ClusterSingletonClaim, type ClusterSingletonOwner, type ComponentDefinition, type ComponentMetadata, type ComponentMetrics, type ComponentPerformanceMetrics, ComponentRegistry, type ComponentSnapshot, type ComponentState, type ConnectionConfig, type ConnectionHealth, type ConnectionMetrics, ConnectionRateLimiter, DEFAULT_CHUNK_SIZE, DEFAULT_WS_PATH, type DebugEvent, type DebugEventType, type DebugSnapshot, type DebugWsMessage, EMIT_OVERRIDE_KEY, type EventHandler, type ExtractActions, type FileChunkData, type FileUploadChunkMessage, type FileUploadCompleteMessage, type FileUploadCompleteResponse, type FileUploadConfig, FileUploadManager, type FileUploadProgressResponse, type FileUploadStartMessage, type FluxStackWSData, type FluxStackWebSocket, type GenericWebSocket, type HttpRequest, type HttpResponse, type HttpRouteDefinition, type HybridComponentOptions, type HybridState, type IClusterAdapter, type IRoomPubSubAdapter, type IRoomStorageAdapter, InMemoryRoomAdapter, type InferComponentState, type InferPrivateState, type LiveActionAuth, type LiveActionAuthMap, type LiveAuthContext, type LiveAuthCredentials, LiveAuthManager, type LiveAuthProvider, type LiveAuthResult, type LiveAuthUser, LiveComponent, type LiveComponentAuth, type LiveComponentContext, type LiveComponentInstance, LiveDebugger, type LiveLogCategory, type LiveLogConfig, type LiveMessage, LiveRoomManager, LiveServer, type LiveServerOptions, type LiveTransport, type LiveWSData, PROTOCOL_VERSION, type PerformanceAlert, type PerformanceConfig, PerformanceMonitor, RateLimiterRegistry, RoomEventBus, type RoomInfo, type RoomMessage, type RoomStateData, RoomStateManager, type RoomSubscription, type ServerRoomHandle, type ServerRoomProxy, type SignedState, type StateMigration, type StateSignatureConfig, StateSignatureManager, type TypedCall, type TypedCallAndWait, type TypedSetValue, type UseTypedLiveComponentReturn, type WebSocketConfig, WebSocketConnectionManager, type WebSocketMessage, type WebSocketResponse, createTypedRoomEventBus, createTypedRoomState, decodeBinaryChunk, encodeBinaryChunk, getLiveComponentContext, liveLog, liveWarn, queueWsMessage, registerComponentLogging, sendImmediate, setLiveComponentContext, unregisterComponentLogging };
1857
+ export { ANONYMOUS_CONTEXT, type ActionNames, type ActionPayload, type ActionReturn, type ActiveUpload, AnonymousContext, AuthenticatedContext, BINARY_ROOM_EVENT, BINARY_ROOM_STATE, type BinaryChunkHeader, type BroadcastMessage, type ClusterActionRequest, type ClusterActionResponse, type ClusterComponentState, type ClusterDeltaHandler, type ClusterSingletonClaim, type ClusterSingletonOwner, type ComponentDefinition, type ComponentMetadata, type ComponentMetrics, type ComponentPerformanceMetrics, ComponentRegistry, type ComponentState, type ConnectionConfig, type ConnectionHealth, type ConnectionMetrics, ConnectionRateLimiter, DEFAULT_CHUNK_SIZE, DEFAULT_WS_PATH, EMIT_OVERRIDE_KEY, type EventHandler, type ExtractActions, type FileChunkData, type FileUploadChunkMessage, type FileUploadCompleteMessage, type FileUploadCompleteResponse, type FileUploadConfig, FileUploadManager, type FileUploadProgressResponse, type FileUploadStartMessage, type FluxStackWSData, type FluxStackWebSocket, type GenericWebSocket, type HttpRequest, type HttpResponse, type HttpRouteDefinition, type HybridComponentOptions, type HybridState, type IClusterAdapter, type IRoomPubSubAdapter, type IRoomStorageAdapter, InMemoryRoomAdapter, type InferComponentState, type InferPrivateState, type InferRoomEvents, type InferRoomMeta, type InferRoomState, type LiveActionAuth, type LiveActionAuthMap, type LiveAuthContext, type LiveAuthCredentials, LiveAuthManager, type LiveAuthProvider, type LiveAuthResult, type LiveAuthUser, LiveComponent, type LiveComponentAuth, type LiveComponentContext, type LiveComponentInstance, type LiveLogCategory, type LiveLogConfig, type LiveMessage, LiveRoom, type LiveRoomClass, LiveRoomManager, type LiveRoomManagerInterface, type LiveRoomOptions, LiveServer, type LiveServerOptions, type LiveTransport, type LiveWSData, PROTOCOL_VERSION, type PerformanceAlert, type PerformanceConfig, PerformanceMonitor, RateLimiterRegistry, type RoomCodec, type RoomCodecOption, RoomEventBus, type RoomEventContext, type RoomInfo, type RoomJoinContext, type RoomLeaveContext, type RoomMessage, RoomRegistry, type RoomStateData, RoomStateManager, type RoomSubscription, type ServerRoomHandle, type ServerRoomProxy, type SignedState, type StateMigration, type StateSignatureConfig, StateSignatureManager, type TypedCall, type TypedCallAndWait, type TypedSetValue, type UseTypedLiveComponentReturn, type WebSocketConfig, WebSocketConnectionManager, type WebSocketMessage, type WebSocketResponse, buildRoomFrame, buildRoomFrameTail, createTypedRoomEventBus, createTypedRoomState, decodeBinaryChunk, encodeBinaryChunk, getLiveComponentContext, jsonCodec, liveLog, liveWarn, msgpackCodec, parseRoomFrame, prependMemberHeader, queueWsMessage, registerComponentLogging, resolveCodec, sendBinaryImmediate, sendImmediate, setLiveComponentContext, unregisterComponentLogging };