UNPKG

@firtoz/socka

Version:

Standard Schema–first WebSocket RPC for TypeScript — Bun, Hono, Node ws, Cloudflare Workers, Durable Objects

112 lines (106 loc) • 5.42 kB
import { DependencyList, RefObject, ReactNode, ReactElement } from 'react'; import { S as SockaContractBound, b as InferSockaPushHandlers, d as InferSockaSend, c as InferSockaPushPayload } from '../socka-report-error-BALZPjd1.js'; import { SockaSessionOptions, SockaSession, SockaConnectionStatus } from '../client/index.js'; import '@standard-schema/spec'; /** Options for {@link useSocka}. */ type UseSockaOptions<TContract extends SockaContractBound> = SockaSessionOptions<TContract>; /** * Connects a {@link SockaSession} in an effect: rejects all pending calls and closes * the socket on cleanup or when `deps` change. */ declare function useSocka<TContract extends SockaContractBound>(options: UseSockaOptions<TContract>, deps: DependencyList): { ready: boolean; sessionRef: RefObject<SockaSession<TContract> | null>; status: SockaConnectionStatus; reconnecting: boolean; reconnectAttempt: number; }; type UseSockaSessionOptions<TContract extends SockaContractBound> = Omit<UseSockaOptions<TContract>, "contract" | "pushHandlers"> & { pushHandlers?: Partial<InferSockaPushHandlers<TContract>>; }; /** * Builds the same typed `send` object as {@link useSockaSession} from a live session ref. * Used by {@link useSockaSessionContext} so consumers do not open extra connections. */ declare function createSockaSendProxyFromSession<TContract extends SockaContractBound>(contract: TContract, sessionRef: RefObject<SockaSession<TContract> | null>): InferSockaSend<TContract>; /** * ```tsx * const { ready, send } = useSockaSession(myContract, { url }, deps); * await send.echo({ message: "hi" }); * ``` */ declare function useSockaSession<TContract extends SockaContractBound>(contract: TContract, options: UseSockaSessionOptions<TContract>, deps: DependencyList): { ready: boolean; send: InferSockaSend<TContract>; sessionRef: RefObject<SockaSession<TContract> | null>; status: SockaConnectionStatus; reconnecting: boolean; reconnectAttempt: number; }; type SockaPresenceOptions<TContract extends SockaContractBound, TUser extends { userId: string; }, KJoin extends keyof TContract["pushes"] & string, KLeave extends keyof TContract["pushes"] & string> = { snapshot: () => Promise<{ selfUserId: string; users: TUser[]; }>; joinPush: KJoin; leavePush: KLeave; mapJoinUser: (p: InferSockaPushPayload<TContract, KJoin>) => TUser; mapLeaveUserId: (p: InferSockaPushPayload<TContract, KLeave>) => string; /** Optional display order after each update (e.g. by `displayName`). */ sortUsers?: (a: TUser, b: TUser) => number; }; /** * Loads a presence snapshot RPC once, then merges **`joinPush`** / **`leavePush`** deltas. * Pass the same **`deps`** you use for {@link useSocka} when room identity changes. * Options are read from a ref so you do not need to memoize the **`options`** object. */ declare function useSockaPresence<TContract extends SockaContractBound, TUser extends { userId: string; }, KJoin extends keyof TContract["pushes"] & string, KLeave extends keyof TContract["pushes"] & string>(sessionRef: RefObject<SockaSession<TContract> | null>, ready: boolean, options: SockaPresenceOptions<TContract, TUser, KJoin, KLeave>, deps: DependencyList): { users: TUser[]; selfUserId: string | undefined; loading: boolean; }; type AnySockaContract = SockaContractBound; /** * Session slice stored on React context by {@link SockaSessionProvider}. The typed * `send` object is built in {@link useSockaSessionContext} (same as {@link useSockaSession}) * so children do not open duplicate WebSockets. */ type SockaSessionContextValue<TContract extends SockaContractBound = AnySockaContract> = { readonly contract: TContract; readonly ready: boolean; readonly sessionRef: RefObject<SockaSession<TContract> | null>; readonly status: SockaConnectionStatus; readonly reconnecting: boolean; readonly reconnectAttempt: number; }; type SockaSessionProviderProps<TContract extends SockaContractBound> = { readonly contract: TContract; readonly deps: DependencyList; readonly children: ReactNode; } & UseSockaSessionOptions<TContract>; /** * Owns a single {@link SockaSession} / WebSocket and exposes it to descendants via * {@link useSockaSessionContext}. Mount once per connection (e.g. layout); avoid * calling {@link useSockaSession} in every leaf—use the context hook instead. */ declare function SockaSessionProvider<TContract extends SockaContractBound>(props: SockaSessionProviderProps<TContract>): ReactElement; declare namespace SockaSessionProvider { var displayName: string; } /** * Reads the socka session from the nearest {@link SockaSessionProvider}. * Pass the **same** `contract` reference as the provider for typing and validation. */ declare function useSockaSessionContext<TContract extends SockaContractBound>(contract: TContract): { ready: boolean; send: InferSockaSend<TContract>; sessionRef: RefObject<SockaSession<TContract> | null>; status: SockaConnectionStatus; reconnecting: boolean; reconnectAttempt: number; }; export { type SockaPresenceOptions, type SockaSessionContextValue, SockaSessionProvider, type SockaSessionProviderProps, type UseSockaOptions, type UseSockaSessionOptions, createSockaSendProxyFromSession, useSocka, useSockaPresence, useSockaSession, useSockaSessionContext };