Tutorial 03
Use the generated client like a remote function
Import the sibling chat.socket.ts file from +page.svelte and use the typed browser client it becomes.
Outcome
You will render room messages in Svelte and keep listener and emit types tied to chat.socket.ts.
Page usage
Import the contract directly in +page.svelte
The page imports ./chat.socket and calls chat(). That returns the browser client with listeners, emits, joins, connection state, and cleanup helpers.
The import starts as server code and becomes browser code
chat.socket.ts is server code. In +page.svelte, LiveRPC replaces the import with a generated browser client before the page reaches the browser.
Previously: The Contract page created chat.socket.ts with toClient.message, rooms.chat, and fromClient.send.
Code focus: This shows the browser side of the same route: create the channel, listen for server messages, and emit typed input.
Lives in
src/routes/rooms/[roomId]/+page.svelte
browser page for the same route · This page renders the chat room and imports ./chat.socket from the same route folder. The socket connection opens only after the page registers a listener or sends an event.
Route map
src/routes/rooms/[roomId]/
+page.svelte
chat.socket.ts <- realtime contract
src/hooks.socket.ts
<script lang="ts">
import { chat } from './chat.socket';
type Message = {
id: string;
roomId: string;
text: string;
sentAt: string;
};
const room = chat();
let text = $state('');
let messages = $state<Message[]>([]);
// The listener payload is inferred from toClient.message.
room.on.message((message) => {
messages = [message, ...messages];
});
async function send() {
// The emit payload is inferred from fromClient.send.
await room.emit.send({ text });
text = '';
}
</script>
<form onsubmit={(event) => { event.preventDefault(); void send(); }}>
<input bind:value={text} aria-label="Message" />
<button type="submit">Send</button>
</form>Result: The browser page can now listen and send through typed methods while LiveRPC owns the Socket.IO client setup.
Checkpoint
Load the page in two tabs. Sending from one tab should render in both tabs for the active route room.
Refresh
Reconnect after auth or cookie changes
When a login action changes cookies, reconnect active realtime clients so src/hooks.socket.ts can read the new cookie values.
Refresh reruns the socket hook
The page should not send user ids to chat.socket.ts. It calls refreshRealtime(), LiveRPC reconnects, and src/hooks.socket.ts returns fresh socket locals from the new cookies.
Code focus: This helper is separate from chat.socket.ts because it reacts to auth state, not room behavior.
Lives in
src/routes/login/+page.svelte or your login action caller
browser code that runs after login completes · Call refreshRealtime after the login action changes cookies. Do it from the login flow because the chat contract should only read the finished connection state.
Route map
src/routes/login/+page.svelte <- call refreshRealtime()
src/hooks.socket.ts <- re-resolves locals
import { refreshRealtime } from 'liverpc/client';
await submitLogin(formData);
// Reconnect active channels so hooks.socket.ts reruns with new cookies.
await refreshRealtime();Result: Existing realtime channels reconnect and handlers that read locals.user see the newly authenticated session.
Checkpoint
After login, trigger a realtime action that reads locals.user. It should use the user from the new session cookie.