export interface RpcParameterContract { name: string; type: string; optional: boolean; } export interface RpcManifestContract { function: string; parameters?: RpcParameterContract[]; returnType?: string; } export interface RpcRequestPayload { component: string; function: string; args: unknown[]; } export interface RpcContext { request: Request; user?: unknown; traceId: string; } export interface RpcHandlerOptions { resolve(component: string): Promise<{ functions: Record any>; manifest?: RpcManifestContract[]; } | null>; authenticate?: (request: Request) => Promise | unknown; authorize?: (context: RpcContext, payload: RpcRequestPayload) => Promise | boolean; validateCsrf?: (request: Request) => Promise | boolean; validateInput?: ( payload: RpcRequestPayload, manifestEntry: RpcManifestContract, ) => Promise | unknown[]; validateOutput?: ( value: unknown, manifestEntry: RpcManifestContract, ) => Promise | unknown; } function json(body: unknown, status = 200): Response { return new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json; charset=utf-8", "cache-control": "no-store", }, }); } function error( code: string, message: string, status: number, traceId: string, details?: unknown, ): Response { return json( { ok: false, error: { code, message, traceId, ...(details === undefined ? {} : { details }) } }, status, ); } function validName(value: unknown): value is string { return typeof value === "string" && /^[A-Za-z_$][\w$]*$/.test(value); } function removePromise(type: string): string { const match = /^Promise\s*<([\s\S]+)>$/.exec(type.trim()); return match?.[1]?.trim() ?? type.trim(); } function splitUnion(type: string): string[] { const parts: string[] = []; let depth = 0; let quote = ""; let start = 0; for (let index = 0; index < type.length; index++) { const char = type[index]!; if (quote) { if (char === "\\") index++; else if (char === quote) quote = ""; continue; } if (char === '"' || char === "'") quote = char; else if ("<([{".includes(char)) depth++; else if (">)]}".includes(char)) depth = Math.max(0, depth - 1); else if (char === "|" && depth === 0) { parts.push(type.slice(start, index).trim()); start = index + 1; } } parts.push(type.slice(start).trim()); return parts.filter(Boolean); } function matchesRuntimeType(value: unknown, rawType: string): boolean { const type = removePromise(rawType).trim(); if (!type || ["unknown", "any", "never"].includes(type)) return true; const union = splitUnion(type); if (union.length > 1) return union.some((part) => matchesRuntimeType(value, part)); if (type === "undefined" || type === "void") return value === undefined; if (type === "null") return value === null; if (/^"[\s\S]*"$|^'[\s\S]*'$/.test(type)) return value === type.slice(1, -1); if (/^-?\d+(?:\.\d+)?$/.test(type)) return value === Number(type); if (type === "true") return value === true; if (type === "false") return value === false; if (type === "string") return typeof value === "string"; if (type === "number") return typeof value === "number" && Number.isFinite(value); if (type === "boolean") return typeof value === "boolean"; if (type === "bigint") return typeof value === "bigint"; if (type === "Date") return value instanceof Date || (typeof value === "string" && !Number.isNaN(Date.parse(value))); if (type.endsWith("[]")) return ( Array.isArray(value) && value.every((item) => matchesRuntimeType(item, type.slice(0, -2))) ); if (/^(?:Readonly)?Array\s*)?$/.test(type)) return value !== null && typeof value === "object"; return true; } function validateArguments(payload: RpcRequestPayload, manifest: RpcManifestContract): unknown[] { const parameters = manifest.parameters ?? []; const required = parameters.filter((parameter) => !parameter.optional).length; if (payload.args.length < required || payload.args.length > parameters.length) { throw new TypeError( `WRN-RPC-INPUT: ${manifest.function} expects ${required === parameters.length ? required : `${required}-${parameters.length}`} arguments, received ${payload.args.length}.`, ); } parameters.forEach((parameter, index) => { const value = payload.args[index]; if (value === undefined && parameter.optional) return; if (!matchesRuntimeType(value, parameter.type)) { throw new TypeError( `WRN-RPC-INPUT: argument '${parameter.name}' expected ${parameter.type}.`, ); } }); return payload.args; } function validateReturn(value: unknown, manifest: RpcManifestContract): unknown { const type = manifest.returnType ?? "unknown"; if (!matchesRuntimeType(value, type)) { throw new TypeError( `WRN-RPC-OUTPUT: ${manifest.function} returned a value incompatible with ${type}.`, ); } return value; } export function createRpcHandler( options: RpcHandlerOptions, ): (request: Request) => Promise { return async (request) => { const traceId = request.headers.get("x-request-id") || crypto.randomUUID(); if (request.method !== "POST") return error("WRN-RPC-METHOD", "RPC requires POST", 405, traceId); if (options.validateCsrf && !(await options.validateCsrf(request))) { return error("WRN-RPC-CSRF", "CSRF validation failed", 403, traceId); } let payload: RpcRequestPayload; try { payload = (await request.json()) as RpcRequestPayload; } catch { return error("WRN-RPC-JSON", "Invalid JSON request", 400, traceId); } if ( !validName(payload.component) || !validName(payload.function) || !Array.isArray(payload.args) ) { return error("WRN-RPC-PAYLOAD", "Invalid RPC payload", 400, traceId); } const resolved = await options.resolve(payload.component); if (!resolved) return error( "WRN-RPC-COMPONENT", `Unknown RPC component '${payload.component}'`, 404, traceId, ); const manifestEntry = resolved.manifest?.find((entry) => entry.function === payload.function); if (!manifestEntry) { return error( "WRN-RPC-FUNCTION", `Server function '${payload.function}' is not remotely exposed`, 404, traceId, ); } const fn = resolved.functions[payload.function]; if (typeof fn !== "function") { return error( "WRN-RPC-FUNCTION", `Server function '${payload.function}' is not available`, 404, traceId, ); } const user = options.authenticate ? await options.authenticate(request) : undefined; const context: RpcContext = { request, user, traceId }; if (options.authorize && !(await options.authorize(context, payload))) { return error("WRN-RPC-AUTHZ", "Not authorized", 403, traceId); } try { const args = options.validateInput ? await options.validateInput(payload, manifestEntry) : validateArguments(payload, manifestEntry); const value = await fn(...args, context); const validated = options.validateOutput ? await options.validateOutput(value, manifestEntry) : validateReturn(value, manifestEntry); return json({ ok: true, value: validated, traceId }); } catch (cause) { const message = cause instanceof Error ? cause.message : String(cause); const code = message.startsWith("WRN-RPC-INPUT") ? "WRN-RPC-INPUT" : message.startsWith("WRN-RPC-OUTPUT") ? "WRN-RPC-OUTPUT" : "WRN-RPC-EXECUTION"; return error(code, message, code === "WRN-RPC-EXECUTION" ? 500 : 400, traceId); } }; }