1- import type { EventHandler , EventHandlerRequest , Middleware } from "../types/handler.ts" ;
1+ import type {
2+ EventHandler ,
3+ EventHandlerObject ,
4+ EventHandlerRequest ,
5+ Middleware ,
6+ } from "../types/handler.ts" ;
7+ import type { Hooks as WebSocketHooks , Peer as WebSocketPeer } from "crossws" ;
28import type { H3Event } from "../event.ts" ;
39import { defineHandler } from "../handler.ts" ;
410import { defineWebSocketHandler } from "./ws.ts" ;
511import { HTTPError } from "../error.ts" ;
6-
7- import type { Hooks as WebSocketHooks , Peer as WebSocketPeer } from "crossws" ;
12+ import { HTTPResponse } from "../response.ts" ;
813
914/**
1015 * JSON-RPC 2.0 Interfaces based on the specification.
@@ -39,16 +44,8 @@ export interface JsonRpcError {
3944 * JSON-RPC 2.0 Response object.
4045 */
4146export type JsonRpcResponse < O = unknown > =
42- | {
43- jsonrpc : "2.0" ;
44- id : string | number | null ;
45- result : O ;
46- }
47- | {
48- jsonrpc : "2.0" ;
49- id : string | number | null ;
50- error : JsonRpcError ;
51- } ;
47+ | { jsonrpc : "2.0" ; id : string | number | null ; result : O }
48+ | { jsonrpc : "2.0" ; id : string | number | null ; error : JsonRpcError } ;
5249
5350/**
5451 * A function that handles a JSON-RPC method call.
@@ -68,25 +65,10 @@ export type JsonRpcWebSocketMethod<
6865 I extends JsonRpcParams | undefined = JsonRpcParams | undefined ,
6966> = ( data : JsonRpcRequest < I > , peer : WebSocketPeer ) => O | Promise < O > ;
7067
71- /**
72- * Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.
73- */
74- const PARSE_ERROR = - 32_700 ;
75-
76- /**
77- * The JSON sent is not a valid Request object.
78- */
79- const INVALID_REQUEST = - 32_600 ;
80- /**
81- * The method does not exist / is not available.
82- */
83-
84- const METHOD_NOT_FOUND = - 32_601 ;
85-
86- /**
87- * Invalid method parameter(s).
88- */
89- const INVALID_PARAMS = - 32_602 ;
68+ const PARSE_ERROR = - 32_700 ; // Invalid JSON was received by the server.
69+ const INVALID_REQUEST = - 32_600 ; // The JSON sent is not a valid Request object.
70+ const METHOD_NOT_FOUND = - 32_601 ; // The method does not exist / is not available.
71+ const INVALID_PARAMS = - 32_602 ; // Invalid method parameter(s).
9072
9173/**
9274 * Creates an H3 event handler that implements the JSON-RPC 2.0 specification.
@@ -97,51 +79,37 @@ const INVALID_PARAMS = -32_602;
9779 *
9880 * @example
9981 * app.post("/rpc", defineJsonRpcHandler({
100- * echo: ({ params }, event) => {
101- * return `Received \`${params}\` on path \`${event.url.pathname}\``;
102- * },
103- * sum: ({ params }, event) => {
104- * return params.a + params.b;
82+ * methods: {
83+ * echo: ({ params }, event) => {
84+ * return `Received \`${params}\` on path \`${event.url.pathname}\``;
85+ * },
86+ * sum: ({ params }, event) => {
87+ * return params.a + params.b;
88+ * },
10589 * },
10690 * }));
10791 */
10892export function defineJsonRpcHandler < RequestT extends EventHandlerRequest = EventHandlerRequest > (
109- methods : Record < string , JsonRpcMethod > ,
110- middleware ?: Middleware [ ] ,
93+ opts : Omit < EventHandlerObject < RequestT > , "handler" | "fetch" > & {
94+ methods : Record < string , JsonRpcMethod > ;
95+ } = { } as any ,
11196) : EventHandler < RequestT > {
112- const methodMap = createMethodMap ( methods ) ;
113-
97+ const methodMap = createMethodMap ( opts . methods ) ;
11498 const handler = async ( event : H3Event ) => {
11599 // JSON-RPC requests MUST be POST.
116100 if ( event . req . method !== "POST" ) {
117- throw new HTTPError ( {
118- status : 405 ,
119- message : "Method Not Allowed" ,
120- } ) ;
101+ throw new HTTPError ( { status : 405 } ) ;
121102 }
122-
123103 let body : unknown ;
124104 try {
125105 body = await event . req . json ( ) ;
126106 } catch {
127107 return createJsonRpcError ( null , PARSE_ERROR , "Parse error" ) ;
128108 }
129-
130109 const result = await processJsonRpcBody ( body , methodMap , event ) ;
131-
132- if ( result === undefined ) {
133- event . res . status = 202 ;
134- return "" ;
135- }
136-
137- event . res . headers . set ( "Content-Type" , "application/json" ) ;
138- return result ;
110+ return result === undefined ? new HTTPResponse ( "" , { status : 202 } ) : result ;
139111 } ;
140-
141- return defineHandler < RequestT > ( {
142- handler,
143- middleware,
144- } ) ;
112+ return defineHandler < RequestT > ( { ...opts , handler } ) ;
145113}
146114
147115/**
@@ -151,25 +119,27 @@ export function defineJsonRpcHandler<RequestT extends EventHandlerRequest = Even
151119 * connections for bi-directional messaging. Each incoming WebSocket text message
152120 * is processed as a JSON-RPC request, and responses are sent back to the peer.
153121 *
154- * @param methods A map of RPC method names to their handler functions.
155- * @param options Optional configuration including additional WebSocket hooks.
122+ * @param opts Options including methods map and optional WebSocket hooks.
156123 * @returns An H3 EventHandler that upgrades to a WebSocket connection.
157124 *
158125 * @example
159126 * app.get("/rpc/ws", defineJsonRpcWebSocketHandler({
160- * echo: ({ params }) => {
161- * return `Received: ${Array.isArray(params) ? params[0] : params?.message}`;
162- * },
163- * sum: ({ params }) => {
164- * return params.a + params.b;
127+ * methods: {
128+ * echo: ({ params }) => {
129+ * return `Received: ${Array.isArray(params) ? params[0] : params?.message}`;
130+ * },
131+ * sum: ({ params }) => {
132+ * return params.a + params.b;
133+ * },
165134 * },
166135 * }));
167136 *
168137 * @example
169138 * // With additional WebSocket hooks
170139 * app.get("/rpc/ws", defineJsonRpcWebSocketHandler({
171- * greet: ({ params }) => `Hello, ${params.name}!`,
172- * }, {
140+ * methods: {
141+ * greet: ({ params }) => `Hello, ${params.name}!`,
142+ * },
173143 * hooks: {
174144 * open(peer) {
175145 * console.log(`Peer connected: ${peer.id}`);
@@ -180,19 +150,13 @@ export function defineJsonRpcHandler<RequestT extends EventHandlerRequest = Even
180150 * },
181151 * }));
182152 */
183- export function defineJsonRpcWebSocketHandler (
184- methods : Record < string , JsonRpcWebSocketMethod > ,
185- options ?: {
186- hooks ?: Partial < Omit < WebSocketHooks , "message" > > ;
187- } ,
188- ) : EventHandler {
189- const methodMap = createMethodMap ( methods ) ;
190-
153+ export function defineJsonRpcWebSocketHandler ( opts : {
154+ methods : Record < string , JsonRpcWebSocketMethod > ;
155+ hooks ?: Partial < Omit < WebSocketHooks , "message" > > ;
156+ } ) : EventHandler {
157+ const methodMap = createMethodMap ( opts . methods ) ;
191158 return defineWebSocketHandler ( {
192- upgrade : options ?. hooks ?. upgrade ,
193- open : options ?. hooks ?. open ,
194- close : options ?. hooks ?. close ,
195- error : options ?. hooks ?. error ,
159+ ...opts . hooks ,
196160 async message ( peer , message ) {
197161 let body : unknown ;
198162 try {
@@ -201,9 +165,7 @@ export function defineJsonRpcWebSocketHandler(
201165 peer . send ( JSON . stringify ( createJsonRpcError ( null , PARSE_ERROR , "Parse error" ) ) ) ;
202166 return ;
203167 }
204-
205168 const result = await processJsonRpcBody ( body , methodMap , peer ) ;
206-
207169 if ( result !== undefined ) {
208170 peer . send ( JSON . stringify ( result ) ) ;
209171 }
0 commit comments