or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

authentication.mdclient-runtime.mddatabase.mde2e-testing.mdindex.mdrealtime.mdrouting.mdsynced-state.mdturnstile.mdvite-plugin.mdworker-runtime.md
tile.json

routing.mddocs/

Routing

The Routing system provides composable route definitions with pattern matching, middleware, layouts, and type-safe link generation for both server and client environments.

Capabilities

Route Definition

Defines a single route with pattern matching and handler.

/**
 * Defines a route with pattern matching
 * @param path - URL pattern (supports parameters like "/users/:id")
 * @param handler - Route handler function or React component
 * @returns Route definition
 */
function route<Path, T>(
  path: Path,
  handler: RouteHandler<T> | MethodHandlers<T>
): RouteDefinition<NormalizePath<Path>, T>;

type NormalizePath<Path> = Path;

type RouteHandler<T> =
  | React.ComponentType
  | ((context?: T) => Response | React.ReactElement | Promise<Response | React.ReactElement>)
  | MethodHandlers<T>;

interface MethodHandlers<T> {
  GET?: (context?: T) => Response | React.ReactElement | Promise<Response | React.ReactElement>;
  POST?: (context?: T) => Response | Promise<Response>;
  PUT?: (context?: T) => Response | Promise<Response>;
  PATCH?: (context?: T) => Response | Promise<Response>;
  DELETE?: (context?: T) => Response | Promise<Response>;
  HEAD?: (context?: T) => Response | Promise<Response>;
  OPTIONS?: (context?: T) => Response | Promise<Response>;
}

interface RouteDefinition<Path, T> {
  path: Path;
  handler: RouteHandler<T>;
}

Usage Examples:

import { route } from 'rwsdk/router';

// Simple component route
route('/', HomePage);

// Function handler returning Response
route('/api/hello', () => new Response('Hello, World!'));

// Async handler with JSX
route('/users/:id', async () => {
  const user = await getUser();
  return <UserProfile user={user} />;
});

// HTTP method-specific handlers
route('/api/users', {
  GET: async () => {
    const users = await getUsers();
    return Response.json(users);
  },
  POST: async () => {
    const user = await createUser();
    return Response.json(user, { status: 201 });
  },
});

Index Route

Defines the root route (equivalent to route('/', handler)).

/**
 * Defines the root route
 * @param handler - Route handler
 * @returns Route definition
 */
function index<T>(handler: RouteHandler<T>): RouteDefinition<"/", T>;

Route Array Definition

Defines multiple routes at once.

/**
 * Defines an array of routes
 * @param routes - Array of route definitions
 * @returns Object with routes array and handle function
 */
function defineRoutes<T>(routes: readonly Route<T>[]): {
  routes: Route<T>[];
  handle: (request: Request, env: any, ctx: ExecutionContext) => Response | Promise<Response>;
};

type Route<T> = RouteDefinition<any, T> | Route<T>[];

Route Prefixing

Adds a common prefix to a group of routes.

/**
 * Prefixes a group of routes
 * @param prefixPath - Common path prefix (e.g., "/api")
 * @param routes - Routes to prefix
 * @returns Prefixed route group
 */
function prefix<Prefix, T, Routes>(
  prefixPath: Prefix,
  routes: Routes
): PrefixedRouteArray<Prefix, Routes>;

type PrefixedRouteArray<Prefix, Routes> = Route<any>[];

Usage Example:

import { prefix, route } from 'rwsdk/router';

const apiRoutes = prefix('/api', [
  route('/users', getUsers),
  route('/posts', getPosts),
]);
// Results in: /api/users, /api/posts

Layout Wrapper

Wraps routes with a layout component that receives children and context.

/**
 * Wraps routes with a layout component
 * @param LayoutComponent - Layout component receiving children and context
 * @param routes - Routes to wrap
 * @returns Wrapped route group
 */
function layout<T, Routes>(
  LayoutComponent: React.ComponentType<LayoutProps<T>>,
  routes: Routes
): Route<T>;

interface LayoutProps<T = any> {
  children: React.ReactNode;
  context?: T;
}

Usage Example:

import { layout, route } from 'rwsdk/router';

function AppLayout({ children }) {
  return (
    <div>
      <nav>Navigation</nav>
      <main>{children}</main>
    </div>
  );
}

const routes = layout(AppLayout, [
  route('/', HomePage),
  route('/about', AboutPage),
]);

Document Wrapper

Wraps routes with a Document component for HTML structure.

/**
 * Wraps routes with a Document component
 * @param Document - Document component for HTML structure
 * @param routes - Routes to wrap
 * @param options - Optional rendering options
 * @returns Wrapped route group
 */
function render<T, Routes>(
  Document: React.ComponentType<DocumentProps<T>>,
  routes: Routes,
  options?: RenderOptions
): RenderedRoutes<T, Routes>;

interface DocumentProps<T = any> {
  children: React.ReactNode;
  context?: T;
}

interface RenderOptions {
  /** Whether to include RSC payload (default: true) */
  rscPayload?: boolean;
  /** Whether to use SSR (default: true) */
  ssr?: boolean;
}

type RenderedRoutes<T, Routes> = Route<T>;

Usage Example:

import { render, route } from 'rwsdk/router';

function Document({ children }) {
  return (
    <html>
      <head>
        <title>My App</title>
      </head>
      <body>{children}</body>
    </html>
  );
}

const app = render(Document, [
  route('/', HomePage),
  route('/about', AboutPage),
]);

Pattern Matching

Matches route patterns against request paths.

/**
 * Matches a route pattern against a request path
 * @param routePath - Route pattern (e.g., "/users/:id")
 * @param requestPath - Actual request path (e.g., "/users/123")
 * @returns Match result with params or null
 */
function matchPath<T>(
  routePath: string,
  requestPath: string
): T["params"] | null;

Handler Utilities

Utility functions for route handlers.

/**
 * Checks if a value is a client reference
 * @param value - Value to check
 * @returns True if value is a client reference
 */
function isClientReference(value: any): boolean;

Type-Safe Link Generation

Creates type-safe link builders from route definitions.

/**
 * Defines a type-safe link builder from routes
 * @returns Link builder function
 */
function defineLinks<App>(): AppLink<App>;
function defineLinks<T>(routes: T): LinkFunction<T[number]>;

/**
 * Creates a link function for an app
 * @returns Link generation function
 */
function linkFor<App>(): AppLink<App>;

/**
 * Creates links from app definition
 * @param app - Optional app definition
 * @returns Link builder
 */
function createLinks<App>(app?: App): AppLink<App>;

type AppLink<App> = {
  [K in AppRoutePaths<App>]: (params?: Record<string, string>) => string;
};

type AppRoutePaths<App> = string;

type LinkFunction<Paths> = (path: Paths, params?: Record<string, string>) => string;

Usage Example:

import { defineApp, route, defineLinks } from 'rwsdk/router';

const app = defineApp([
  route('/', HomePage),
  route('/users/:id', UserPage),
  route('/posts/:slug', PostPage),
]);

const links = createLinks(app);

// Type-safe link generation
const userLink = links['/users/:id']({ id: '123' });
// Result: "/users/123"

const postLink = links['/posts/:slug']({ slug: 'hello-world' });
// Result: "/posts/hello-world"

Route Patterns

Route patterns support parameter extraction:

  • Static: /about, /api/users
  • Parameters: /users/:id, /posts/:slug
  • Multiple parameters: /blog/:year/:month/:slug
  • Wildcard: /files/*

Composing Routes

Routes can be composed and nested in various ways:

import { defineApp, route, prefix, layout, render } from 'rwsdk/router';

function RootLayout({ children }) {
  return <div className="root">{children}</div>;
}

function AdminLayout({ children }) {
  return (
    <div className="admin">
      <aside>Admin Menu</aside>
      <main>{children}</main>
    </div>
  );
}

function Document({ children }) {
  return (
    <html>
      <body>{children}</body>
    </html>
  );
}

const app = defineApp([
  render(Document, [
    layout(RootLayout, [
      route('/', HomePage),
      route('/about', AboutPage),
      prefix('/admin', [
        layout(AdminLayout, [
          route('/', AdminDashboard),
          route('/users', AdminUsers),
        ]),
      ]),
    ]),
  ]),
]);

Client-Side Routing

On the client, use a subset of routing functions:

// Client-side routing (from rwsdk/router on client)
function defineLinks(routes?: any): LinkBuilder;
function linkFor<App>(): (path: string, params?: Record<string, string>) => string;

Types

type MethodVerb = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";

type RouteMiddleware<T> = (
  handler: RouteHandler<T>,
  context: T
) => RouteHandler<T>;