rwsdk
Version:
Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime
162 lines (161 loc) • 6.01 kB
TypeScript
import React from "react";
import { RequestInfo } from "../requestInfo/types";
import type { DocumentProps, LayoutProps } from "./types.js";
export type RouteMiddleware<T extends RequestInfo = RequestInfo> = (requestInfo: T) => MaybePromise<React.JSX.Element | Response | void>;
type RouteFunction<T extends RequestInfo = RequestInfo> = (requestInfo: T) => MaybePromise<Response>;
type MaybePromise<T> = T | Promise<T>;
type RouteComponent<T extends RequestInfo = RequestInfo> = (requestInfo: T) => MaybePromise<React.JSX.Element | Response | void>;
type RouteHandler<T extends RequestInfo = RequestInfo> = RouteFunction<T> | RouteComponent<T> | readonly [...RouteMiddleware<T>[], RouteFunction<T> | RouteComponent<T>];
declare const METHOD_VERBS: readonly ["delete", "get", "head", "patch", "post", "put"];
export type MethodVerb = (typeof METHOD_VERBS)[number];
export type MethodHandlers<T extends RequestInfo = RequestInfo> = {
[K in MethodVerb]?: RouteHandler<T>;
} & {
config?: {
disable405?: true;
disableOptions?: true;
};
custom?: {
[method: string]: RouteHandler<T>;
};
};
export type Route<T extends RequestInfo = RequestInfo> = RouteMiddleware<T> | RouteDefinition<T> | Array<Route<T>>;
export type RouteDefinition<T extends RequestInfo = RequestInfo> = {
path: string;
handler: RouteHandler<T> | MethodHandlers<T>;
layouts?: React.FC<LayoutProps<T>>[];
};
export declare function matchPath<T extends RequestInfo = RequestInfo>(routePath: string, requestPath: string): T["params"] | null;
export declare function defineRoutes<T extends RequestInfo = RequestInfo>(routes: Route<T>[]): {
routes: Route<T>[];
handle: ({ request, renderPage, getRequestInfo, onError, runWithRequestInfoOverrides, rscActionHandler, }: {
request: Request;
renderPage: (requestInfo: T, Page: React.FC, onError: (error: unknown) => void) => Promise<Response>;
getRequestInfo: () => T;
onError: (error: unknown) => void;
runWithRequestInfoOverrides: <Result>(overrides: Partial<T>, fn: () => Promise<Result>) => Promise<Result>;
rscActionHandler: (request: Request) => Promise<unknown>;
}) => Response | Promise<Response>;
};
/**
* Defines a route handler for a path pattern.
*
* Supports three types of path patterns:
* - Static: /about, /contact
* - Parameters: /users/:id, /posts/:postId/edit
* - Wildcards: /files/*, /api/*\/download
*
* @example
* // Static route
* route("/about", () => <AboutPage />)
*
* @example
* // Route with parameters
* route("/users/:id", ({ params }) => {
* return <UserProfile userId={params.id} />
* })
*
* @example
* // Route with wildcards
* route("/files/*", ({ params }) => {
* const filePath = params.$0
* return <FileViewer path={filePath} />
* })
*
* @example
* // Method-based routing
* route("/api/users", {
* get: () => Response.json(users),
* post: ({ request }) => Response.json({ status: "created" }, { status: 201 }),
* delete: () => new Response(null, { status: 204 }),
* })
*
* @example
* // Route with middleware array
* route("/admin", [isAuthenticated, isAdmin, () => <AdminDashboard />])
*/
export declare function route<T extends RequestInfo = RequestInfo>(path: string, handler: RouteHandler<T> | MethodHandlers<T>): RouteDefinition<T>;
/**
* Defines a route handler for the root path "/".
*
* @example
* // Homepage
* index(() => <HomePage />)
*
* @example
* // With middleware
* index([logRequest, () => <HomePage />])
*/
export declare function index<T extends RequestInfo = RequestInfo>(handler: RouteHandler<T>): RouteDefinition<T>;
/**
* Prefixes a group of routes with a path.
*
* @example
* // Organize blog routes under /blog
* const blogRoutes = [
* route("/", () => <BlogIndex />),
* route("/post/:id", ({ params }) => <BlogPost id={params.id} />),
* route("/admin", [isAuthenticated, () => <BlogAdmin />]),
* ]
*
* // In worker.tsx
* defineApp([
* render(Document, [
* route("/", () => <HomePage />),
* prefix("/blog", blogRoutes),
* ]),
* ])
*/
export declare function prefix<T extends RequestInfo = RequestInfo>(prefixPath: string, routes: Route<T>[]): Route<T>[];
export declare const wrapHandlerToThrowResponses: <T extends RequestInfo = RequestInfo>(handler: RouteFunction<T> | RouteComponent<T>) => RouteHandler<T>;
/**
* Wraps routes with a layout component.
*
* @example
* // Define a layout component
* function BlogLayout({ children }: { children: React.ReactNode }) {
* return (
* <div>
* <nav>Blog Navigation</nav>
* <main>{children}</main>
* </div>
* )
* }
*
* // Apply layout to routes
* const blogRoutes = layout(BlogLayout, [
* route("/", () => <BlogIndex />),
* route("/post/:id", ({ params }) => <BlogPost id={params.id} />),
* ])
*/
export declare function layout<T extends RequestInfo = RequestInfo>(LayoutComponent: React.FC<LayoutProps<T>>, routes: Route<T>[]): Route<T>[];
/**
* Wraps routes with a Document component and configures rendering options.
*
* @param options.rscPayload - Toggle the RSC payload that's appended to the Document. Disabling this will mean that interactivity no longer works.
* @param options.ssr - Disable sever side rendering for all these routes. This only allow client side rendering, which requires `rscPayload` to be enabled.
*
* @example
* // Basic usage
* defineApp([
* render(Document, [
* route("/", () => <HomePage />),
* route("/about", () => <AboutPage />),
* ]),
* ])
*
* @example
* // With custom rendering options
* render(Document, [
* route("/", () => <HomePage />),
* ], {
* rscPayload: true,
* ssr: true,
* })
*/
export declare function render<T extends RequestInfo = RequestInfo>(Document: React.FC<DocumentProps<T>>, routes: Route<T>[], options?: {
rscPayload?: boolean;
ssr?: boolean;
}): Route<T>[];
export declare const isClientReference: (value: any) => boolean;
export {};