React Router Framework Mode

Load Cavuno data in React Router route modules, actions, and native error boundaries.

React Router Framework Mode is the current full-stack successor to Remix. Put public reads in route loaders, mutations in actions, and session cookies in the application’s server boundary. Translate Cavuno not-found errors into native 404 responses so the route error boundary owns the page.

Create a stateless server client

ts
import { createBoardClient } from '@cavuno/board';
export const board = createBoardClient({
board: process.env.PUBLIC_CAVUNO_BOARD!,
auth: { storage: 'nostore' },
});

Load a job directory

tsx
import type { Route } from './+types/jobs';
import { useLoaderData } from 'react-router';
import { board } from '~/lib/cavuno.server';
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const page = Math.max(1, Number(url.searchParams.get('page') ?? '1'));
const limit = 20;
return board.jobs.list({
query: url.searchParams.get('query') ?? undefined,
limit,
offset: (page - 1) * limit,
});
}
export default function JobsRoute() {
const jobs = useLoaderData<typeof loader>();
return <JobList jobs={jobs.data} />;
}

Map a missing job to the route boundary

ts
import { isNotFound } from '@cavuno/board';
export async function loader({ params }: Route.LoaderArgs) {
try {
return await board.jobs.retrieve(params.jobSlug);
} catch (error) {
if (isNotFound(error)) {
throw new Response('Job not found', { status: 404 });
}
throw error;
}
}

Let the route’s ErrorBoundary render the 404. Do not turn all SDK errors into null; authorization, validation, rate limiting, and upstream failures need different recovery paths.

Keep actions private

Read the application’s httpOnly session cookie inside the action, parse it with @cavuno/board/server, and pass its access token in the trailing fetch options. Return validation errors from the action; redirect after successful mutations. Do not serialize the session into loader data.

Verify the React Router boundary

  1. Open the jobs route and confirm its loader runs on the intended server boundary.
  2. Open an invalid job slug and confirm the route error boundary renders a 404 response.
  3. Submit an authenticated action as two users and confirm each request receives only its own data.
  4. Inspect loader data and HTML for bearer or refresh tokens.
  5. Build using every rendering mode you plan to deploy—SSR, static, or SPA—and verify the same route explicitly.

Continue with SSR sessions before adding authenticated routes.