UNPKG

rwsdk

Version:

Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime

89 lines (88 loc) 3.4 kB
import { requestInfo } from "./requestInfo/worker"; function createServerFunction(fns, mainFn, options) { const wrapped = async (...args) => { const { request, ctx } = requestInfo; // Execute interruptors for (const fn of fns) { const result = await fn({ request, ctx, args }); if (result instanceof Response) { // We can't easily return a Response from a server action function // because the return type is expected to be TResult. // However, if the interruptor returns a Response, it usually means "stop and return this HTTP response". // In the RSC context, throwing a Response is a common pattern to short-circuit. throw result; } } return mainFn(...args); }; wrapped.method = options?.method ?? "POST"; // Default to POST if not specified, though user said serverQuery defaults to GET? // User said: "export const getProject = serverQuery(...) // Defaults to GET" // So serverQuery defaults to GET, serverAction defaults to POST? return wrapped; } /** * Wrap a function to be used as a server query. * * - **Method**: Defaults to `GET`. can be changed via `options`. * - **Behavior**: When called from the client, it returns data-only and does **not** rehydrate or re-render the React page. * - **Location**: Must be defined in a file with `"use server"`. We recommend `queries.ts` colocated with components. * - **Middleware**: You can pass an array of functions as the first argument to act as interruptors (e.g. for auth). * * @example * ```ts * // getters.ts * "use server" * * export const getUser = serverQuery(async (id: string) => { * return db.user.findUnique({ where: { id } }) * }) * ``` */ export function serverQuery(fnsOrFn, options) { let fns = []; let mainFn; if (Array.isArray(fnsOrFn)) { fns = fnsOrFn.slice(0, -1); mainFn = fnsOrFn[fnsOrFn.length - 1]; } else { mainFn = fnsOrFn; } const method = options?.method ?? "GET"; // Default to GET for query const wrapped = createServerFunction(fns, mainFn, { ...options, method }); wrapped.method = method; return wrapped; } /** * Wrap a function to be used as a server action. * * - **Method**: Defaults to `POST`. can be changed via `options`. * - **Behavior**: When called from the client, it **will** rehydrate and re-render the React page with the new server state. * - **Location**: Must be defined in a file with `"use server"`. We recommend `actions.ts` colocated with components. * - **Middleware**: You can pass an array of functions as the first argument to act as interruptors (e.g. for auth). * * @example * ```ts * // actions.ts * "use server" * * export const updateUser = serverAction(async (id: string, data: any) => { * return db.user.update({ where: { id }, data }) * }) * ``` */ export function serverAction(fnsOrFn, options) { let fns = []; let mainFn; if (Array.isArray(fnsOrFn)) { fns = fnsOrFn.slice(0, -1); mainFn = fnsOrFn[fnsOrFn.length - 1]; } else { mainFn = fnsOrFn; } const method = options?.method ?? "POST"; // Default to POST for action const wrapped = createServerFunction(fns, mainFn, { ...options, method }); wrapped.method = method; return wrapped; }