@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 +314 -125
- package/dist/index.js +1026 -393
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
|
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 };
|