Tutorial 06

Harden realtime for production

Treat socket connections like long-lived sessions with explicit auth, controlled errors, and a Node runtime.

Outcome

You will read the session in src/hooks.socket.ts, return only the user data handlers need, and deploy on a long-running Node process.

1

Socket hook

Create socket locals in hooks.socket.ts

The socket hook runs when a browser opens or refreshes the realtime connection. Read the session there and return only the values your .socket.ts files need.

Protected rooms start in the socket hook

Private tenant rooms need user data that came from the server. src/hooks.socket.ts is where the session cookie becomes locals.user for the rest of the connection.

Terms

Previously: The Rooms page added a tenant room that reads locals.user.tenantId. This step shows the hook that creates locals.user before that room code runs.

Code focus: This example keeps only the values .socket.ts files need. Do not pass raw session blobs into every handler.

Lives in

src/hooks.socket.ts

creates per-connection values for .socket.ts files Room contracts read locals.user, but they should not duplicate session-cookie lookup code. Keep that lookup in the socket hook.

Route map

src/hooks.socket.ts <- resolve locals.user

src/routes/rooms/[roomId]/chat.socket.ts <- read locals.user

typescript src/hooks.socket.ts · socket locals from session
import { handleSocket } from 'liverpc/server';

export const handle = handleSocket(async ({ cookies }) => {
  const sessionId = cookies.get('session');
  const session = sessionId ? await getSession(sessionId) : undefined;

  return {
    locals: {
      // Socket handlers read locals.user, never browser-supplied identity.
      user: session?.user
    }
  };
});

Result: Every connection now gets user data from one server-side hook before protected rooms or handlers run.

Checkpoint

Connect without a session cookie and confirm protected rooms reject access on the server.

2

Runtime

Deploy as a long-running Node server

Deploy this package version as adapter-node output or a custom Node server. Static, edge, and short-lived serverless output cannot keep Socket.IO connections open.

Socket.IO needs a process that keeps connections open

The adapter wrapper attaches Socket.IO to the SvelteKit Node server. Run that server as a long-lived process so browser connections stay attached after the first request.

Terms

Code focus: Use this shape in your process manager, container command, or platform start command.

Lives in

build output from adapter-node

production command for the built app This is deployment setup, not route code. The process owns both SvelteKit HTTP requests and Socket.IO connections.

Route map

svelte.config.js <- adapter wrapper

build/ <- Node server output

node build <- long-lived process

bash production command · build and run Node server
# Build the SvelteKit Node app.
pnpm build

# Run the long-lived process that owns Socket.IO.
HOST=0.0.0.0 PORT=3000 node build

Result: The app now runs in the runtime mode LiveRPC expects for this version.

Checkpoint

Open the production URL and keep a browser tab connected through a deploy restart test.

Run the safe realtime lab