@emeryld/rrroutes-client 2.6.2 → 2.6.4

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.
@@ -0,0 +1,5 @@
1
+ import type { EventMap, SocketConnectionConfigOutput } from '@emeryld/rrroutes-contract';
2
+ import * as React from 'react';
3
+ import { SocketClient } from './socket.client.core';
4
+ export declare const SocketCtx: React.Context<SocketClient<any, SocketConnectionConfigOutput> | null>;
5
+ export declare function useSocketClient<T extends EventMap, C extends SocketConnectionConfigOutput>(): SocketClient<T, C>;
@@ -0,0 +1,18 @@
1
+ import type { EventMap, Payload, SocketConnectionConfigOutput, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
2
+ import type { ClientCtx, ServerEnvelope } from './socket.client.core';
3
+ type Rooms = string[] | string | undefined;
4
+ export type UseSocketConnectionArgs<T extends EventMap, K extends keyof T & string, C extends SocketConnectionConfigOutput> = {
5
+ event: K;
6
+ rooms?: Rooms;
7
+ onMessage: (payload: Payload<T, K>, meta?: {
8
+ envelope: ServerEnvelope<T, K>;
9
+ ctx: ClientCtx;
10
+ }) => void;
11
+ onCleanup?: () => void;
12
+ autoJoin?: boolean;
13
+ autoLeave?: boolean;
14
+ joinMeta: SocketSchemaOutput<C['joinMetaMessage']>;
15
+ leaveMeta: SocketSchemaOutput<C['leaveMetaMessage']>;
16
+ };
17
+ export declare function useSocketConnection<T extends EventMap, K extends keyof T & string, C extends SocketConnectionConfigOutput>(args: UseSocketConnectionArgs<T, K, C>): void;
18
+ export {};
@@ -1,71 +1,4 @@
1
- import { EventMap, Payload, SocketConnectionConfigOutput, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
2
- import * as React from 'react';
3
- import { Socket } from 'socket.io-client';
4
- import { ClientCtx, ServerEnvelope, SocketClient, SocketClientOptions } from './socket.client.index';
5
- /** === Provider-side debug === */
6
- type HookDebugReason = 'init' | 'change';
7
- type HookDebugValue = string | number | boolean | null | undefined;
8
- export type SocketProviderDebugEvent = {
9
- type: 'resolve';
10
- phase: 'start' | 'ok' | 'error' | 'socketMissing' | 'cancelled';
11
- err?: string;
12
- } | {
13
- type: 'client';
14
- phase: 'init' | 'destroy';
15
- missing?: boolean;
16
- } | {
17
- type: 'render';
18
- hasClient: boolean;
19
- } | {
20
- type: 'hook';
21
- phase: 'resolve_effect' | 'client_memo' | 'destroy_effect';
22
- reason: HookDebugReason;
23
- changes: Array<{
24
- dependency: string;
25
- previous: HookDebugValue;
26
- next: HookDebugValue;
27
- }>;
28
- };
29
- export type SocketProviderDebugOptions = {
30
- verbose?: boolean;
31
- logger?: (e: SocketProviderDebugEvent) => void;
32
- } & {
33
- [P in SocketProviderDebugEvent['type']]?: boolean;
34
- };
35
- /** === Types for runtime socket injection === */
36
- type BaseOptions<T extends EventMap, C extends SocketConnectionConfigOutput> = Omit<SocketClientOptions<T, C>, 'socket'>;
37
- type ProviderRuntimeSocket = {
38
- socket: Socket | null;
39
- } | {
40
- getSocket: () => Socket | Promise<Socket>;
41
- };
42
- export declare function buildSocketProvider<T extends EventMap, C extends SocketConnectionConfigOutput>(args: {
43
- events: T;
44
- options: Omit<BaseOptions<T, C>, 'debug'> & {
45
- debug: BaseOptions<T, C>['debug'] & SocketProviderDebugOptions;
46
- };
47
- }): {
48
- SocketProvider: (props: React.PropsWithChildren<ProviderRuntimeSocket & {
49
- fallback?: React.ReactNode;
50
- destroyLeaveMeta: SocketSchemaOutput<C["leaveMetaMessage"]>;
51
- }>) => import("react/jsx-runtime").JSX.Element;
52
- useSocketClient: () => SocketClient<T, C>;
53
- useSocketConnection: <K extends keyof T & string>(p: Parameters<typeof useSocketConnection<T, K, C>>[0]) => void;
54
- };
55
- export declare function useSocketClient<T extends EventMap, C extends SocketConnectionConfigOutput>(): SocketClient<T, C>;
56
- type Rooms = string[] | string | undefined;
57
- export type UseSocketConnectionArgs<T extends EventMap, K extends keyof T & string, C extends SocketConnectionConfigOutput> = {
58
- event: K;
59
- rooms?: Rooms;
60
- onMessage: (payload: Payload<T, K>, meta?: {
61
- envelope: ServerEnvelope<T, K>;
62
- ctx: ClientCtx;
63
- }) => void;
64
- onCleanup?: () => void;
65
- autoJoin?: boolean;
66
- autoLeave?: boolean;
67
- joinMeta: SocketSchemaOutput<C['joinMetaMessage']>;
68
- leaveMeta: SocketSchemaOutput<C['leaveMetaMessage']>;
69
- };
70
- export declare function useSocketConnection<T extends EventMap, K extends keyof T & string, C extends SocketConnectionConfigOutput>(args: UseSocketConnectionArgs<T, K, C>): void;
71
- export {};
1
+ export { buildSocketProvider } from './socket.client.context.provider';
2
+ export { useSocketClient } from './socket.client.context.client';
3
+ export { useSocketConnection, type UseSocketConnectionArgs, } from './socket.client.context.connection';
4
+ export type { SocketProviderDebugEvent, SocketProviderDebugOptions, } from './socket.client.context.debug';
@@ -0,0 +1,50 @@
1
+ import type * as React from 'react';
2
+ type HookDebugReason = 'init' | 'change';
3
+ type HookDebugValue = string | number | boolean | null | undefined;
4
+ export type SocketProviderDebugEvent = {
5
+ type: 'resolve';
6
+ phase: 'start' | 'ok' | 'error' | 'socketMissing' | 'cancelled';
7
+ err?: string;
8
+ } | {
9
+ type: 'client';
10
+ phase: 'init' | 'destroy';
11
+ missing?: boolean;
12
+ } | {
13
+ type: 'render';
14
+ hasClient: boolean;
15
+ } | {
16
+ type: 'hook';
17
+ phase: 'resolve_effect' | 'client_memo' | 'destroy_effect';
18
+ reason: HookDebugReason;
19
+ changes: Array<{
20
+ dependency: string;
21
+ previous: HookDebugValue;
22
+ next: HookDebugValue;
23
+ }>;
24
+ };
25
+ export type SocketProviderDebugOptions = {
26
+ verbose?: boolean;
27
+ logger?: (e: SocketProviderDebugEvent) => void;
28
+ } & {
29
+ [P in SocketProviderDebugEvent['type']]?: boolean;
30
+ };
31
+ export type HookDebugSnapshot = Record<string, unknown>;
32
+ type HookIdentifier = Extract<SocketProviderDebugEvent, {
33
+ type: 'hook';
34
+ }>['phase'];
35
+ export declare function dbg(dbgOpts: SocketProviderDebugOptions | undefined, e: SocketProviderDebugEvent): void;
36
+ export declare function describeSocketLike(value: {
37
+ id?: string;
38
+ connected?: boolean;
39
+ recovered?: boolean;
40
+ } | null): HookDebugValue;
41
+ export declare function summarizeEvents(events: unknown): HookDebugValue;
42
+ export declare function summarizeBaseOptions(options: unknown): HookDebugValue;
43
+ export declare function summarizeMeta(meta: unknown, label: string): HookDebugValue;
44
+ export declare function trackHookTrigger({ ref, hook, providerDebug, snapshot, }: {
45
+ ref: React.MutableRefObject<HookDebugSnapshot | null>;
46
+ hook: HookIdentifier;
47
+ providerDebug?: SocketProviderDebugOptions;
48
+ snapshot: HookDebugSnapshot;
49
+ }): void;
50
+ export {};
@@ -0,0 +1,26 @@
1
+ import type { EventMap, SocketConnectionConfigOutput, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
2
+ import * as React from 'react';
3
+ import type { Socket } from 'socket.io-client';
4
+ import { SocketClient, type SocketClientOptions } from './socket.client.core';
5
+ import { type UseSocketConnectionArgs } from './socket.client.context.connection';
6
+ import { SocketProviderDebugOptions } from './socket.client.context.debug';
7
+ type BaseOptions<T extends EventMap, C extends SocketConnectionConfigOutput> = Omit<SocketClientOptions<T, C>, 'socket'>;
8
+ type ProviderRuntimeSocket = {
9
+ socket: Socket | null;
10
+ } | {
11
+ getSocket: () => Socket | Promise<Socket>;
12
+ };
13
+ export declare function buildSocketProvider<T extends EventMap, C extends SocketConnectionConfigOutput>(args: {
14
+ events: T;
15
+ options: Omit<BaseOptions<T, C>, 'debug'> & {
16
+ debug: BaseOptions<T, C>['debug'] & SocketProviderDebugOptions;
17
+ };
18
+ }): {
19
+ SocketProvider: (props: React.PropsWithChildren<ProviderRuntimeSocket & {
20
+ fallback?: React.ReactNode;
21
+ destroyLeaveMeta: SocketSchemaOutput<C["leaveMetaMessage"]>;
22
+ }>) => import("react/jsx-runtime").JSX.Element;
23
+ useSocketClient: () => SocketClient<T, C>;
24
+ useSocketConnection: <K extends keyof T & string>(p: UseSocketConnectionArgs<T, K, C>) => void;
25
+ };
26
+ export {};
@@ -0,0 +1,116 @@
1
+ import type { EventMap, Payload, SocketConnectionConfigOutput, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
2
+ import { SocketClientDebugEvent } from './socket.client.debug';
3
+ import type { MaybeSocket, SysEventMap } from './socket.client.sys';
4
+ export type ServerEnvelope<T extends EventMap, K extends keyof T & string> = {
5
+ eventName: K;
6
+ sentAt: string | Date;
7
+ sentTo: string[];
8
+ data?: Payload<T, K>;
9
+ metadata?: Record<string, unknown>;
10
+ rooms: string[];
11
+ };
12
+ export type ClientCtx = {
13
+ receivedAt: Date;
14
+ latencyMs?: number;
15
+ nsp?: string;
16
+ socketId?: string;
17
+ socket?: MaybeSocket;
18
+ reply?: (data?: unknown) => void;
19
+ };
20
+ export type ClientStatsSnapshot = {
21
+ roomsCount: number;
22
+ totalHandlers: number;
23
+ rooms: {
24
+ room: string;
25
+ count: number;
26
+ }[];
27
+ handlers: {
28
+ event: string;
29
+ handlers: number;
30
+ }[];
31
+ };
32
+ export type SocketClientDebugOptions<K extends string = string> = {
33
+ verbose?: boolean;
34
+ only?: K[];
35
+ logger?: (e: SocketClientDebugEvent<K>) => void;
36
+ } & {
37
+ [P in SocketClientDebugEvent['type']]?: boolean;
38
+ };
39
+ /** === Heartbeat config (now only timing + optional onPong) === */
40
+ export type HeartbeatClientOptions = {
41
+ /** Interval between pings. Default 15_000. */
42
+ intervalMs?: number;
43
+ /** Give up waiting for pong after this many ms. Default 7_500. */
44
+ timeoutMs?: number;
45
+ };
46
+ export type SocketClientOptions<T extends EventMap = EventMap, C extends SocketConnectionConfigOutput = SocketConnectionConfigOutput> = {
47
+ /** Inject an existing socket.io-client Socket. Can be null while bootstrapping. */
48
+ socket: MaybeSocket;
49
+ config: C;
50
+ environment?: 'development' | 'production';
51
+ debug?: SocketClientDebugOptions<keyof T & string>;
52
+ heartbeat?: HeartbeatClientOptions;
53
+ sys: SysEventMap<T, C>;
54
+ };
55
+ export declare class SocketClient<T extends EventMap, C extends SocketConnectionConfigOutput = SocketConnectionConfigOutput> {
56
+ readonly socket: MaybeSocket;
57
+ private readonly events;
58
+ private readonly environment;
59
+ private readonly debug;
60
+ private readonly config;
61
+ private readonly sysEvents;
62
+ private readonly roomJoinSchema;
63
+ private readonly roomLeaveSchema;
64
+ private readonly hb;
65
+ private hbTimer;
66
+ /** keep references so we can .off() later */
67
+ private readonly onConnect;
68
+ private readonly onReconnect;
69
+ private readonly onDisconnect;
70
+ private readonly onConnectError;
71
+ private readonly onPong;
72
+ private readonly roomCounts;
73
+ private readonly handlerMap;
74
+ private snapshotSocketConfig;
75
+ private logSocketConfigSnapshot;
76
+ private getValidationDetails;
77
+ private getVerboseDetails;
78
+ private getNamespace;
79
+ constructor(events: T, opts: SocketClientOptions<T, C>);
80
+ private getSysEvent;
81
+ private dbg;
82
+ /** internal stats snapshot */
83
+ stats(): ClientStatsSnapshot;
84
+ private toArray;
85
+ private rollbackJoinIncrement;
86
+ private rollbackLeaveDecrement;
87
+ /**
88
+ * Public: start the heartbeat loop manually.
89
+ *
90
+ * This is called by the default 'sys:connect' handler, but you can also
91
+ * call it yourself from any sysHandler to change when heartbeats start.
92
+ */
93
+ startHeartbeat(): void;
94
+ /**
95
+ * Public: stop the heartbeat loop.
96
+ *
97
+ * This is called by the default 'sys:disconnect' handler, but you can also
98
+ * call it yourself from any sysHandler to fully control heartbeat lifecycle.
99
+ */
100
+ stopHeartbeat(reason?: string): void;
101
+ emit<K extends keyof T & string>(event: K, payload: Payload<T, K>, metadata?: Record<string, unknown>): void;
102
+ joinRooms(rooms: string[] | string, meta: SocketSchemaOutput<C['joinMetaMessage']>): Promise<() => Promise<void>>;
103
+ leaveRooms(rooms: string[] | string, meta: SocketSchemaOutput<C['leaveMetaMessage']>): Promise<void>;
104
+ on<K extends keyof T & string>(event: K, handler: (payload: Payload<T, K>, meta?: {
105
+ envelope: ServerEnvelope<T, K>;
106
+ ctx: ClientCtx;
107
+ }) => void): () => void;
108
+ /**
109
+ * Remove all listeners, stop timers, and leave rooms.
110
+ * Call when disposing the client instance.
111
+ */
112
+ destroy(leaveMeta: SocketSchemaOutput<C['leaveMetaMessage']>): Promise<void>;
113
+ /** Pass-throughs. Managing connection is the caller’s responsibility. */
114
+ disconnect(): void;
115
+ connect(): void;
116
+ }
@@ -1,119 +1,4 @@
1
- import type { EventMap, Payload, SocketConnectionConfigOutput, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
2
- import { SocketClientDebugEvent } from './socket.client.debug';
3
- import type { MaybeSocket, SysEventMap } from './socket.client.sys';
4
- export type ServerEnvelope<T extends EventMap, K extends keyof T & string> = {
5
- eventName: K;
6
- sentAt: string | Date;
7
- sentTo: string[];
8
- data?: Payload<T, K>;
9
- metadata?: Record<string, unknown>;
10
- rooms: string[];
11
- };
12
- export type ClientCtx = {
13
- receivedAt: Date;
14
- latencyMs?: number;
15
- nsp?: string;
16
- socketId?: string;
17
- socket?: MaybeSocket;
18
- reply?: (data?: unknown) => void;
19
- };
20
- export type ClientStatsSnapshot = {
21
- roomsCount: number;
22
- totalHandlers: number;
23
- rooms: {
24
- room: string;
25
- count: number;
26
- }[];
27
- handlers: {
28
- event: string;
29
- handlers: number;
30
- }[];
31
- };
32
- export type SocketClientDebugOptions<K extends string = string> = {
33
- verbose?: boolean;
34
- only?: K[];
35
- logger?: (e: SocketClientDebugEvent<K>) => void;
36
- } & {
37
- [P in SocketClientDebugEvent['type']]?: boolean;
38
- };
39
- /** === Heartbeat config (now only timing + optional onPong) === */
40
- export type HeartbeatClientOptions = {
41
- /** Interval between pings. Default 15_000. */
42
- intervalMs?: number;
43
- /** Give up waiting for pong after this many ms. Default 7_500. */
44
- timeoutMs?: number;
45
- };
46
- export type SocketClientOptions<T extends EventMap = EventMap, C extends SocketConnectionConfigOutput = SocketConnectionConfigOutput> = {
47
- /** Inject an existing socket.io-client Socket. Can be null while bootstrapping. */
48
- socket: MaybeSocket;
49
- config: C;
50
- environment?: 'development' | 'production';
51
- debug?: SocketClientDebugOptions<keyof T & string>;
52
- heartbeat?: HeartbeatClientOptions;
53
- sys: SysEventMap<T, C>;
54
- };
55
- export declare class SocketClient<T extends EventMap, C extends SocketConnectionConfigOutput = SocketConnectionConfigOutput> {
56
- readonly socket: MaybeSocket;
57
- private readonly events;
58
- private readonly environment;
59
- private readonly debug;
60
- private readonly config;
61
- private readonly sysEvents;
62
- private readonly roomJoinSchema;
63
- private readonly roomLeaveSchema;
64
- private readonly hb;
65
- private hbTimer;
66
- /** keep references so we can .off() later */
67
- private readonly onConnect;
68
- private readonly onReconnect;
69
- private readonly onDisconnect;
70
- private readonly onConnectError;
71
- private readonly onPong;
72
- private readonly roomCounts;
73
- private readonly handlerMap;
74
- private snapshotSocketConfig;
75
- private logSocketConfigSnapshot;
76
- private getValidationDetails;
77
- private getVerboseDetails;
78
- private getNamespace;
79
- constructor(events: T, opts: SocketClientOptions<T, C>);
80
- private getSysEvent;
81
- private dbg;
82
- /** internal stats snapshot */
83
- stats(): ClientStatsSnapshot;
84
- private toArray;
85
- private rollbackJoinIncrement;
86
- private rollbackLeaveDecrement;
87
- /**
88
- * Public: start the heartbeat loop manually.
89
- *
90
- * This is called by the default 'sys:connect' handler, but you can also
91
- * call it yourself from any sysHandler to change when heartbeats start.
92
- */
93
- startHeartbeat(): void;
94
- /**
95
- * Public: stop the heartbeat loop.
96
- *
97
- * This is called by the default 'sys:disconnect' handler, but you can also
98
- * call it yourself from any sysHandler to fully control heartbeat lifecycle.
99
- */
100
- stopHeartbeat(reason?: string): void;
101
- emit<K extends keyof T & string>(event: K, payload: Payload<T, K>, metadata?: Record<string, unknown>): void;
102
- joinRooms(rooms: string[] | string, meta: SocketSchemaOutput<C['joinMetaMessage']>): Promise<() => Promise<void>>;
103
- leaveRooms(rooms: string[] | string, meta: SocketSchemaOutput<C['leaveMetaMessage']>): Promise<void>;
104
- on<K extends keyof T & string>(event: K, handler: (payload: Payload<T, K>, meta?: {
105
- envelope: ServerEnvelope<T, K>;
106
- ctx: ClientCtx;
107
- }) => void): () => void;
108
- /**
109
- * Remove all listeners, stop timers, and leave rooms.
110
- * Call when disposing the client instance.
111
- */
112
- destroy(leaveMeta: SocketSchemaOutput<C['leaveMetaMessage']>): Promise<void>;
113
- /** Pass-throughs. Managing connection is the caller’s responsibility. */
114
- disconnect(): void;
115
- connect(): void;
116
- }
1
+ export * from './socket.client.core';
117
2
  export * from './socket.client.context';
118
3
  export * from './socket.client.sys';
119
4
  export * from './socketedRoute/socket.client.helper';
@@ -1,7 +1,7 @@
1
1
  import type { Socket } from 'socket.io-client';
2
2
  import { z } from 'zod';
3
3
  import type { EventMap, SocketConnectionConfigOutput, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
4
- import { SocketClient } from './socket.client.index';
4
+ import type { SocketClient } from './socket.client.core';
5
5
  export type MaybeSocket = Socket | null;
6
6
  export type SysEventMap<T extends EventMap, C extends SocketConnectionConfigOutput = SocketConnectionConfigOutput> = {
7
7
  'sys:connect': (args: {
@@ -1,70 +1,2 @@
1
- import type { AnyLeafLowProfile, EventMap, InferOutput, Payload, SocketConnectionConfigOutput, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
2
- import type { BuiltInfinite, BuiltQuery, DataShape, InfiniteUseEndpointResultFor, QueryUseEndpointResultFor, UseEndpointArgs } from '../../routesV3.client.types';
3
- import type { ClientCtx, ServerEnvelope, SocketClient } from '../socket.client.index';
4
- type RoomsInput = string | string[] | undefined | null;
5
- type HookDebugReason = 'init' | 'change';
6
- type HookDebugValue = string | number | boolean | null | undefined;
7
- export type SocketedRouteDebugEvent = {
8
- type: 'client';
9
- phase: 'ready' | 'missing';
10
- err?: string;
11
- } | {
12
- type: 'render';
13
- renderCount: number;
14
- hasClient: boolean;
15
- argsKey: string;
16
- rooms: string[];
17
- roomsKey: string;
18
- joinMetaKey: string;
19
- leaveMetaKey: string;
20
- } | {
21
- type: 'hook';
22
- phase: 'endpoint_on_receive_effect' | 'derive_rooms_effect' | 'join_rooms_effect' | 'apply_socket_effect';
23
- reason: HookDebugReason;
24
- changes: Array<{
25
- dependency: string;
26
- previous: HookDebugValue;
27
- next: HookDebugValue;
28
- }>;
29
- } | {
30
- type: 'room';
31
- phase: 'join_attempt' | 'join_skip' | 'join_error' | 'leave_attempt' | 'leave_skip' | 'leave_error';
32
- rooms: string[];
33
- reason?: string;
34
- err?: string;
35
- };
36
- export type SocketedRouteDebugOptions = {
37
- logger?: (event: SocketedRouteDebugEvent) => void;
38
- } & {
39
- [P in SocketedRouteDebugEvent['type']]?: boolean;
40
- };
41
- type SocketedBuilt<L extends AnyLeafLowProfile> = L['cfg']['feed'] extends true ? BuiltInfinite<L> : BuiltQuery<L>;
42
- type SocketedRouteResult<L extends AnyLeafLowProfile> = (L['cfg']['feed'] extends true ? InfiniteUseEndpointResultFor<L> : QueryUseEndpointResultFor<L>) & {
43
- rooms: string[];
44
- };
45
- export type SocketedRouteOptions<L extends AnyLeafLowProfile, Events extends EventMap, C extends SocketConnectionConfigOutput> = {
46
- built: SocketedBuilt<L>;
47
- toRooms: (data: InferOutput<L>) => {
48
- rooms: RoomsInput;
49
- joinMeta: SocketSchemaOutput<C['joinMetaMessage']>;
50
- leaveMeta: SocketSchemaOutput<C['leaveMetaMessage']>;
51
- };
52
- applySocket: {
53
- [K in keyof Events & string]?: (prev: DataShape<L> | undefined, payload: Payload<Events, K>, meta: {
54
- envelope?: ServerEnvelope<Events, keyof Events & string>;
55
- ctx?: ClientCtx;
56
- args: UseEndpointArgs<L>;
57
- }) => DataShape<L> | undefined;
58
- };
59
- useSocketClient: () => SocketClient<Events, C>;
60
- debug?: SocketedRouteDebugOptions;
61
- };
62
- /**
63
- * Compose a GET endpoint with socket wiring:
64
- * - joins/leaves rooms derived from the endpoint data
65
- * - subscribes to a socket event and applies messages to the cache
66
- */
67
- export declare function buildSocketedRoute<L extends AnyLeafLowProfile, Events extends EventMap, C extends SocketConnectionConfigOutput>(options: SocketedRouteOptions<L, Events, C>): Omit<SocketedBuilt<L>, "useEndpoint"> & {
68
- useEndpoint: (...useArgs: UseEndpointArgs<L>) => SocketedRouteResult<L>;
69
- };
70
- export {};
1
+ export type { SocketedRouteDebugEvent, SocketedRouteDebugOptions, } from './socket.client.helper.debug';
2
+ export { buildSocketedRoute, type SocketedRouteOptions, } from './socket.client.helper.route';
@@ -0,0 +1,54 @@
1
+ export type HookDebugReason = 'init' | 'change';
2
+ export type HookDebugValue = string | number | boolean | null | undefined;
3
+ export type SocketedRouteDebugEvent = {
4
+ type: 'client';
5
+ phase: 'ready' | 'missing';
6
+ err?: string;
7
+ } | {
8
+ type: 'render';
9
+ renderCount: number;
10
+ hasClient: boolean;
11
+ argsKey: string;
12
+ rooms: string[];
13
+ roomsKey: string;
14
+ joinMetaKey: string;
15
+ leaveMetaKey: string;
16
+ } | {
17
+ type: 'hook';
18
+ phase: 'endpoint_on_receive_effect' | 'derive_rooms_effect' | 'join_rooms_effect' | 'apply_socket_effect';
19
+ reason: HookDebugReason;
20
+ changes: Array<{
21
+ dependency: string;
22
+ previous: HookDebugValue;
23
+ next: HookDebugValue;
24
+ }>;
25
+ } | {
26
+ type: 'room';
27
+ phase: 'join_attempt' | 'join_skip' | 'join_error' | 'leave_attempt' | 'leave_skip' | 'leave_error';
28
+ rooms: string[];
29
+ reason?: string;
30
+ err?: string;
31
+ };
32
+ export type SocketedRouteDebugOptions = {
33
+ logger?: (event: SocketedRouteDebugEvent) => void;
34
+ } & {
35
+ [P in SocketedRouteDebugEvent['type']]?: boolean;
36
+ };
37
+ export type HookDebugSnapshot = Record<string, unknown>;
38
+ type HookIdentifier = Extract<SocketedRouteDebugEvent, {
39
+ type: 'hook';
40
+ }>['phase'];
41
+ export declare function describeObjectReference(value: unknown): string | null;
42
+ export declare function safeJsonKey(value: unknown): string;
43
+ export declare function isSameObjectReference(prev: unknown, next: unknown): boolean;
44
+ export declare function shouldWarnSocketMutationGuard(): boolean;
45
+ export declare function dbg(debug: SocketedRouteDebugOptions | undefined, event: SocketedRouteDebugEvent): void;
46
+ export declare function trackHookTrigger({ ref, phase, debug, snapshot, }: {
47
+ ref: {
48
+ current: HookDebugSnapshot | null;
49
+ };
50
+ phase: HookIdentifier;
51
+ debug?: SocketedRouteDebugOptions;
52
+ snapshot: HookDebugSnapshot;
53
+ }): void;
54
+ export {};
@@ -0,0 +1,17 @@
1
+ import type { AnyLeafLowProfile, InferOutput, SocketConnectionConfigOutput, SocketSchemaOutput } from '@emeryld/rrroutes-contract';
2
+ import type { DataShape } from '../../routesV3.client.types';
3
+ export type RoomsInput = string | string[] | undefined | null;
4
+ export type RoomState<C extends SocketConnectionConfigOutput> = {
5
+ rooms: string[];
6
+ joinMeta?: SocketSchemaOutput<C['joinMetaMessage']>;
7
+ leaveMeta?: SocketSchemaOutput<C['leaveMetaMessage']>;
8
+ };
9
+ export type ToRoomsResult<C extends SocketConnectionConfigOutput> = {
10
+ rooms: RoomsInput;
11
+ joinMeta: SocketSchemaOutput<C['joinMetaMessage']>;
12
+ leaveMeta: SocketSchemaOutput<C['leaveMetaMessage']>;
13
+ };
14
+ export type ToRoomsMapper<L extends AnyLeafLowProfile, C extends SocketConnectionConfigOutput> = (data: InferOutput<L>) => ToRoomsResult<C>;
15
+ export declare function roomStateEqual<C extends SocketConnectionConfigOutput>(prev: RoomState<C>, next: RoomState<C>): boolean;
16
+ export declare function mergeRoomState<L extends AnyLeafLowProfile, C extends SocketConnectionConfigOutput>(prev: RoomState<C>, toRoomsResult: ToRoomsResult<C>): RoomState<C>;
17
+ export declare function roomsFromData<L extends AnyLeafLowProfile, C extends SocketConnectionConfigOutput>(data: DataShape<L> | undefined, toRooms: ToRoomsMapper<L, C>): RoomState<C>;
@@ -0,0 +1,31 @@
1
+ import type { AnyLeafLowProfile, EventMap, Payload, SocketConnectionConfigOutput } from '@emeryld/rrroutes-contract';
2
+ import type { BuiltInfinite, BuiltQuery, DataShape, InfiniteUseEndpointResultFor, QueryUseEndpointResultFor, UseEndpointArgs } from '../../routesV3.client.types';
3
+ import type { ClientCtx, ServerEnvelope, SocketClient } from '../socket.client.core';
4
+ import { type SocketedRouteDebugOptions } from './socket.client.helper.debug';
5
+ import { type ToRoomsMapper } from './socket.client.helper.rooms';
6
+ type SocketedBuilt<L extends AnyLeafLowProfile> = L['cfg']['feed'] extends true ? BuiltInfinite<L> : BuiltQuery<L>;
7
+ type SocketedRouteResult<L extends AnyLeafLowProfile> = (L['cfg']['feed'] extends true ? InfiniteUseEndpointResultFor<L> : QueryUseEndpointResultFor<L>) & {
8
+ rooms: string[];
9
+ };
10
+ export type SocketedRouteOptions<L extends AnyLeafLowProfile, Events extends EventMap, C extends SocketConnectionConfigOutput> = {
11
+ built: SocketedBuilt<L>;
12
+ toRooms: ToRoomsMapper<L, C>;
13
+ applySocket: {
14
+ [K in keyof Events & string]?: (prev: DataShape<L> | undefined, payload: Payload<Events, K>, meta: {
15
+ envelope?: ServerEnvelope<Events, keyof Events & string>;
16
+ ctx?: ClientCtx;
17
+ args: UseEndpointArgs<L>;
18
+ }) => DataShape<L> | undefined | null;
19
+ };
20
+ useSocketClient: () => SocketClient<Events, C>;
21
+ debug?: SocketedRouteDebugOptions;
22
+ };
23
+ /**
24
+ * Compose a GET endpoint with socket wiring:
25
+ * - joins/leaves rooms derived from the endpoint data
26
+ * - subscribes to a socket event and applies messages to the cache
27
+ */
28
+ export declare function buildSocketedRoute<L extends AnyLeafLowProfile, Events extends EventMap, C extends SocketConnectionConfigOutput>(options: SocketedRouteOptions<L, Events, C>): Omit<SocketedBuilt<L>, "useEndpoint"> & {
29
+ useEndpoint: (...useArgs: UseEndpointArgs<L>) => SocketedRouteResult<L>;
30
+ };
31
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emeryld/rrroutes-client",
3
- "version": "2.6.2",
3
+ "version": "2.6.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -19,7 +19,7 @@
19
19
  "dist"
20
20
  ],
21
21
  "dependencies": {
22
- "@emeryld/rrroutes-contract": "^2.5.13",
22
+ "@emeryld/rrroutes-contract": "^2.6.0",
23
23
  "zod": "^4.3.6"
24
24
  },
25
25
  "peerDependencies": {