Socket
Real-time socket connection to the Ovok backend - SocketProvider, useSocket hook, and AI event listener
- Stable unknown
- Release candidate since 1.16.1-rc.3
- Development since 1.16.1-dev.2111+9796905
The Socket module wraps a socket.io-client connection to the Ovok backend and exposes
the live Socket instance through React context. It connects when the native next
client has a session, disconnects on sign-out, and reconnects the same socket when
network access returns.
This is the channel real-time SDK features (AI streaming, server-pushed logs, presence) ride on. Most apps only need it if they consume one of those features; REST traffic uses the native Ovok client.
Exports
// from @ovok/native/socket
export { SocketProvider } from "./components/socket-provider";
export { SocketContext } from "./contexts/socket-context";
export type { SocketContextType } from "./types/socket-context-type";
export type { SocketLogPayload } from "./types/socket-log-payload";
export { useAiEventListener } from "./hooks/use-ai-event-listener";
export { useSocket } from "./hooks/use-socket";Source: src/modules/socket/index.ts.
<SocketProvider>
Wrap your app (inside OvokProvider so the client + access token are available) to open the socket connection.
Props
import type { SocketLogPayload } from "@ovok/native/socket";
type SocketProviderProps = React.PropsWithChildren<{
onError?: (error: Error) => void;
onConnectionError?: (error: Error) => void;
onPing?: (latency: number) => void;
onConnect?: () => void;
onDisconnect?: () => void;
onLogs?: (message: SocketLogPayload) => void;
}>;| Prop | When it fires |
|---|---|
onConnect | Socket transport opened and authenticated with the bearer token. |
onDisconnect | Socket transport closed (network change, manual disconnect, idle timeout). |
onError | error event from the socket — typically protocol-level failures. |
onConnectionError | connect_error event — the handshake or authentication failed. Both onError and onConnectionError flip internal state back to disconnected. |
onPing | Socket.IO ping event latency/value supplied by the client transport. |
onLogs | Server-pushed log line. SocketLogPayload = { message: string; level: 'info' | 'warn' | 'error' }. |
SocketProvider reads the native client's baseUrl and active session access token from OvokProvider, so it must be a descendant of that provider. The connection URL is ${baseUrl}events.
Reconnection
SocketProvider registers a NetInfo listener. When the network goes offline it calls
socket.disconnect(). When the network returns it reconnects that socket with its
listeners intact. An account switch closes the previous socket before connecting with
the new token. Default socket.io-client options are 5 reconnection attempts with
1s → 5s delay.
useSocket()
Read the live socket + connection state from context.
type SocketContextType = {
socket: ReturnType<typeof io> | null;
isConnected: boolean;
};
const { socket, isConnected } = useSocket();Throws if called outside <SocketProvider>. Returned socket is null without a session; gate connected operations on isConnected.
useAiEventListener()
Subscribe to AI events streamed over the socket (currently the /ai/session/message channel).
type MessageEvent = {
content: string;
mode: "user" | "assistant";
reference: string;
sender: string;
sentAt: string;
session: string;
};
const { subscribe } = useAiEventListener();Use:
import { useAiEventListener } from "@ovok/native/socket";
function ChatView() {
const { subscribe } = useAiEventListener();
const [messages, setMessages] = React.useState<MessageEvent[]>([]);
React.useEffect(() => {
const unsubscribe = subscribe("message", (event) => {
setMessages((prev) => [...prev, event as MessageEvent]);
});
return () => unsubscribe?.();
}, [subscribe]);
return <ChatList messages={messages} />;
}subscribe(type, callback) returns an unsubscribe function. Multiple subscribers per event type are supported; each receives every event independently.
Full integration example
import { OvokProvider } from "@ovok/core/next/react";
import {
ThemeProvider as OvokThemeProvider,
DEFAULT_COLORS,
} from "@ovok/native";
import { Ovok } from "@ovok/native/next";
import { SocketProvider } from "@ovok/native/socket";
import * as SecureStore from "expo-secure-store";
const client = new Ovok({
baseUrl: "https://api.ovok.com/",
tenantCode: "your-tenant",
secureStore: SecureStore,
});
function App() {
return (
<OvokThemeProvider theme={{ colors: DEFAULT_COLORS, dark: false }}>
<OvokProvider client={client}>
<SocketProvider
onConnect={() => console.log("socket up")}
onDisconnect={() => console.log("socket down")}
onConnectionError={(e) => console.error("handshake failed", e)}
onLogs={(payload) => console.log(`[${payload.level}]`, payload.message)}
>
<YourAppRoot />
</SocketProvider>
</OvokProvider>
</OvokThemeProvider>
);
}When to mount it
- Mount once at the root, inside
OvokProvider. MultipleSocketProviderinstances create multiple sockets, which counts against the backend's per-user connection limit. - Mount only if you consume AI events, server-pushed logs, or another socket-only feature. REST traffic via
useFhirSearch/client.createdoes not need a socket. - Mount before any consumer of
useSocketoruseAiEventListenerin the tree — these throw if called outside.
Related
- OvokProvider documentation — the FHIR client + auth wrapper this depends on
Last updated on