/** * RPC Client Plugin for OpenSpeed * Provides end-to-end type safety between frontend and backend (similar to tRPC/Eden) */ import type { Context } from '../context.js'; export type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; export interface RouteHandler { (ctx: Context): any; } export type InferInput = T extends (ctx: infer C) => any ? C extends Context & { body: infer B; } ? B : never : never; export type InferOutput = T extends (...args: any[]) => infer R ? R extends Promise ? P extends { body: infer B; } ? B extends string ? any : B : any : R extends { body: infer B; } ? B extends string ? any : B : any : never; export interface RPCRoute { method: Method; path: string; handler: RouteHandler; } export interface RPCApp { routes: Map; get(path: string, handler: RouteHandler): this; post(path: string, handler: RouteHandler): this; put(path: string, handler: RouteHandler): this; patch(path: string, handler: RouteHandler): this; delete(path: string, handler: RouteHandler): this; } export interface RPCClientOptions { baseUrl?: string; headers?: Record; fetch?: typeof fetch; onRequest?: (req: Request) => void | Promise; onResponse?: (res: Response) => void | Promise; onError?: (error: Error) => void | Promise; } export interface RPCResponse { data?: T; error?: { message: string; status: number; details?: any; }; status: number; headers: Headers; } export type QueryParams = Record; export interface RequestOptions { params?: Record; query?: QueryParams; body?: TBody; headers?: Record; } /** * Create RPC client from app type */ export declare function createClient(options?: RPCClientOptions): RPCClient; export type RPCClient = { [K in keyof TApp['routes']]: { get(options?: RequestOptions): Promise>; post(options?: RequestOptions): Promise>; put(options?: RequestOptions): Promise>; patch(options?: RequestOptions): Promise>; delete(options?: RequestOptions): Promise>; }; }; /** * Helper to extract routes from app for type inference */ export declare function treaty(baseUrl: string, options?: Omit): RPCClient; /** * Batch request helper */ export declare function batch[]>(...requests: T): Promise<{ [K in keyof T]: Awaited; }>; /** * RPC middleware for server-side route collection */ export interface RPCPluginOptions { enableIntrospection?: boolean; prefix?: string; } export declare function rpc(options?: RPCPluginOptions): (ctx: Context, next: () => Promise) => Promise; /** * Type-safe route definition helper */ export declare function defineRoute(handler: (ctx: Context & { body: TInput; }) => TOutput | Promise): RouteHandler; /** * Create typed API contract */ export declare function createContract>(): T; /** * Utility for creating webhooks/subscriptions */ export declare class RPCSubscription { private url; private options; private listeners; private ws?; constructor(url: string, options?: RPCClientOptions); subscribe(callback: (data: T) => void): () => void; private connect; private disconnect; send(data: T): void; } /** * Example usage: * * // Server-side * import { Openspeed } from 'openspeed'; * import { rpc, defineRoute } from 'openspeed/plugins/rpc'; * * const app = Openspeed(); * app.use(rpc()); * * app.post('/api/user', defineRoute<{ name: string }, { id: string }>((ctx) => { * const { name } = ctx.body; * return ctx.json({ id: '123', name }); * })); * * export type App = typeof app; * * // Client-side * import { treaty } from 'openspeed/plugins/rpc'; * import type { App } from './server'; * * const api = treaty('http://localhost:3000'); * * const { data, error } = await api['/api/user'].post({ * body: { name: 'John' } // Type-safe! * }); * * if (data) { * console.log(data.id); // Type-safe! * } */ //# sourceMappingURL=rpc.d.ts.map