Skip to content

Commit c800e2e

Browse files
committed
Allow options to be proxied to send method
1 parent b61039e commit c800e2e

File tree

2 files changed

+112
-60
lines changed

2 files changed

+112
-60
lines changed

src/index.spec.ts

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import * as t from "io-ts";
2-
import { createServer, parse, createClient, RpcError } from "./index";
32
import { isLeft, isRight } from "fp-ts/lib/Either";
3+
import {
4+
createServer,
5+
parse,
6+
createClient,
7+
RpcError,
8+
Resolvers
9+
} from "./index";
410

511
describe("json rpc", () => {
612
const methods = {
@@ -14,11 +20,12 @@ describe("json rpc", () => {
1420
}
1521
};
1622

17-
const server = createServer(methods, {
23+
const resolvers: Resolvers<typeof methods> = {
1824
hello: _ => "Hello World!",
1925
echo: ({ arg }) => arg
20-
});
26+
};
2127

28+
const server = createServer(methods, resolvers);
2229
const client = createClient(methods, x => server(x, undefined));
2330

2431
describe("parse", () => {
@@ -271,6 +278,28 @@ describe("json rpc", () => {
271278
}
272279
});
273280
});
281+
282+
describe("without type checking", () => {
283+
const server = createServer(methods, resolvers, {
284+
encode: false,
285+
decode: false
286+
});
287+
288+
it("should succeed", async () => {
289+
const result = await server({
290+
jsonrpc: "2.0",
291+
id: 1,
292+
method: "hello",
293+
params: {}
294+
});
295+
296+
expect(result).toEqual({
297+
jsonrpc: "2.0",
298+
id: 1,
299+
result: "Hello World!"
300+
});
301+
});
302+
});
274303
});
275304
});
276305

@@ -300,42 +329,69 @@ describe("json rpc", () => {
300329
})
301330
).rejects.toBeInstanceOf(RpcError);
302331
});
332+
333+
describe("without type checking", () => {
334+
const client = createClient(methods, x => server(x), {
335+
encode: false,
336+
decode: false
337+
});
338+
339+
it("should succeed", async () => {
340+
const result = await client({ method: "hello", params: {} });
341+
342+
expect(result).toEqual("Hello World!");
343+
});
344+
});
345+
346+
describe("with send options", () => {
347+
const client = createClient(methods, (_, options: string) =>
348+
Promise.resolve({ result: options })
349+
);
350+
351+
it("should accept options", async () => {
352+
const result = await client({ method: "hello", params: {} }, "Test");
353+
354+
expect(result).toEqual("Test");
355+
});
356+
});
303357
});
304358

305-
describe("batch", () => {
306-
it("should make a batch request", async () => {
307-
const result = await client.batch(
359+
describe("many", () => {
360+
it("should make a many request", async () => {
361+
const result = await client.many([
308362
{ method: "hello", params: {} },
309363
{ method: "echo", params: { arg: "test" } }
310-
);
364+
]);
311365

312366
expect(result).toEqual(["Hello World!", "test"]);
313367
});
314368

315-
it("should make a batch notification request", async () => {
316-
const result = await client.batch(
369+
it("should make a many notification request", async () => {
370+
const result = await client.many([
317371
{ method: "hello", params: {}, async: true },
318372
{ method: "echo", params: { arg: "test" }, async: true }
319-
);
373+
]);
320374

321375
expect(result).toEqual([undefined, undefined]);
322376
});
323377

324-
it("should handle mixed batch responses", async () => {
325-
const result = await client.batch(
378+
it("should handle mixed many responses", async () => {
379+
const result = await client.many([
326380
{ method: "hello", params: {}, async: true },
327381
{ method: "echo", params: { arg: "test" } },
328382
{ method: "hello", params: {}, async: true }
329-
);
383+
]);
330384

331385
expect(result).toEqual([undefined, "test", undefined]);
332386
});
333387

334388
it("should return rpc errors", async () => {
335-
const result = await client.batch({
336-
method: "echo",
337-
params: {} as any
338-
});
389+
const result = await client.many([
390+
{
391+
method: "echo",
392+
params: {} as any
393+
}
394+
]);
339395

340396
expect(result.length).toEqual(1);
341397
expect(result[0]).toBeInstanceOf(RpcError);

src/index.ts

Lines changed: 39 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,11 @@ export interface ClientOptions {
272272
/**
273273
* Create a JSON RPC request client.
274274
*/
275-
export function createClient<T extends Methods>(
275+
export function createClient<T extends Methods, U = void>(
276276
methods: T,
277277
send: (
278-
rpc: JsonRpcRequest<string, unknown> | JsonRpcRequest<string, unknown>[]
278+
data: JsonRpcRequest<string, unknown> | JsonRpcRequest<string, unknown>[],
279+
options: U
279280
) => Promise<unknown>,
280281
options: ClientOptions = {}
281282
) {
@@ -303,61 +304,59 @@ export function createClient<T extends Methods>(
303304

304305
const { result, error } = body as Record<string, any>;
305306

306-
if (result) {
307-
const output =
308-
options.decode === false
309-
? either.right(result)
310-
: response.decode(result);
311-
312-
if (either.isLeft(output)) {
313-
return new RpcError(
314-
PathReporter.report(output).join("; "),
315-
-2,
316-
output.left
317-
);
318-
}
319-
320-
return output.right;
307+
if (result === undefined && error === undefined) {
308+
return new RpcError("Invalid response", -1, undefined);
321309
}
322310

323-
if (
324-
error === null ||
325-
typeof error !== "object" ||
326-
Array.isArray(error)
327-
) {
328-
return new RpcError("Invalid response", -1, undefined);
311+
if (error !== undefined) {
312+
return new RpcError(
313+
String(error?.message || "Error"),
314+
Number(error?.code) || 0,
315+
error?.data
316+
);
317+
}
318+
319+
const output =
320+
options.decode === false
321+
? either.right(result)
322+
: response.decode(result);
323+
324+
if (either.isLeft(output)) {
325+
return new RpcError(
326+
PathReporter.report(output).join("; "),
327+
-2,
328+
output.left
329+
);
329330
}
330331

331-
return new RpcError(
332-
String(error.message || "Error"),
333-
Number(error.code) || 0,
334-
error.data
335-
);
332+
return output.right;
336333
}
337334
};
338335
}
339336

340-
async function rpcClient<U extends ClientMethods<T>>(
341-
payload: U
337+
async function rpcClient<P extends ClientMethods<T>>(
338+
payload: P,
339+
options: U
342340
): Promise<
343-
U["async"] extends true ? undefined : TypeOf<T[U["method"]]["response"]>
341+
P["async"] extends true ? undefined : TypeOf<T[P["method"]]["response"]>
344342
> {
345343
const { params, id, method, process } = prepare(payload);
346-
const data = await send({ jsonrpc, method, params, id });
344+
const data = await send({ jsonrpc, method, params, id }, options);
347345
const response = process(data) as any;
348346
if (response instanceof RpcError) throw response; // Throw RPC errors.
349347
return response;
350348
}
351349

352-
rpcClient.many = async <U extends ClientMethods<T>[]>(
353-
payload: U
350+
rpcClient.many = async <P extends ClientMethods<T>[]>(
351+
payload: P,
352+
options: U
354353
): Promise<
355354
{
356-
[K in keyof U]: U[K] extends ClientMethods<T>
357-
? U[K]["async"] extends true
355+
[K in keyof P]: P[K] extends ClientMethods<T>
356+
? P[K]["async"] extends true
358357
? undefined
359-
: TypeOf<T[U[K]["method"]]["response"]> | RpcError
360-
: U[K];
358+
: TypeOf<T[P[K]["method"]]["response"]> | RpcError
359+
: P[K];
361360
}
362361
> => {
363362
const items = payload.map(prepare);
@@ -370,7 +369,8 @@ export function createClient<T extends Methods>(
370369
params,
371370
id
372371
})
373-
)
372+
),
373+
options
374374
);
375375

376376
if (!Array.isArray(data)) {
@@ -382,9 +382,5 @@ export function createClient<T extends Methods>(
382382
return items.map(item => item.process(lookup.get(item.id))) as any;
383383
};
384384

385-
rpcClient.batch = async <U extends ClientMethods<T>[]>(...payload: U) => {
386-
return rpcClient.many(payload);
387-
};
388-
389385
return rpcClient;
390386
}

0 commit comments

Comments
 (0)