Skip to content

Commit

Permalink
push v0.1.20
Browse files Browse the repository at this point in the history
  • Loading branch information
silesky committed Jan 2, 2022
1 parent cd6ddb7 commit fed32c0
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 105 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.1.18",
"version": "0.1.20",
"license": "MIT",
"main": "dist/index.js",
"module": "dist/jsonrpc-ts-client.esm.js",
Expand All @@ -15,7 +15,8 @@
"start": "dts watch",
"build": "dts build --tsconfig ./tsconfig.prod.json",
"test": "dts test",
"test:debug": "DEBUG=jsonrpc-ts-client npm test",
"t:watch": "dts test --watch",
"t:debug": "DEBUG=jsonrpc-ts-client npm test",
"lint": "npm run tsc:check && eslint .",
"prepare": "npm run build",
"tsc:check": "tsc --noEmit"
Expand Down Expand Up @@ -49,4 +50,4 @@
"typescript": "^4.5.4",
"uuid": "^8.3.2"
}
}
}
78 changes: 44 additions & 34 deletions src/client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import axios, { AxiosError, AxiosInstance, AxiosResponse } from "axios";
import Debug from "debug";
import {
assertJsonRpcReply,
assertJsonRpcReplyBatch,
Expand All @@ -10,22 +9,26 @@ import {
} from "./utils/jsonrpc";
import { Either } from "./utils/either";
import { GetElementByIndex, MapEither } from "./utils/ts";
import { debug } from "./utils/debug";

/* run via npm test DEBUG=jsonrpc-ts-client etc */
const debug = Debug("jsonrpc-ts-client");

export interface JsonRpcCreateConfig {
export interface JsonRpcConfigOptions {
url: string;
headers?: Record<string, string>;
idGeneratorFn?: () => string;
}

export class ApiClientConfig {
url: string;
headers?: Record<string, string>;

idGeneratorFn?: () => string;
// intentionally separate the final configuration from the arguments used for its instantiation, since these could easily deviate.
export class JsonRpcConfig implements JsonRpcConfigOptions {
url: JsonRpcConfigOptions["url"];
headers?: JsonRpcConfigOptions["headers"];
idGeneratorFn?: JsonRpcConfigOptions["idGeneratorFn"];

constructor(opts: JsonRpcConfigOptions) {
this.url = opts.url;
this.headers = opts.headers;
this.idGeneratorFn = opts.idGeneratorFn;
this.validate();
}
/**
* Asserts that the current object is valid; this is useful in non-typescript environments.
*/
Expand All @@ -40,18 +43,12 @@ export class ApiClientConfig {
* Allows the user to do ad-hock updates to the configration.
* Merge a set of arbitrary overrides with the current configuration, and validate.
*/
public merge(o: Partial<JsonRpcCreateConfig>) {
public merge(o: Partial<JsonRpcConfigOptions>) {
o.url && (this.url = o.url);
o.idGeneratorFn && (this.idGeneratorFn = o.idGeneratorFn);
o.headers && (o.headers = this.headers);
this.validate();
}

constructor(opts: JsonRpcCreateConfig) {
this.url = opts.url;
this.headers = opts.headers;
this.idGeneratorFn = opts.idGeneratorFn;
}
}

export interface JsonRpcClientCallOptions {
Expand All @@ -60,34 +57,34 @@ export interface JsonRpcClientCallOptions {
id?: string;
}

type JsonRpcApi = {
export interface JsonRpcApiContract {
[methodName: string]: (params: any) => any;
};
}

type EmptyObject = Record<string, never>;

type GetParamsFromContract<
Api extends JsonRpcApi,
Api extends JsonRpcApiContract,
Method extends keyof Api
> = Parameters<Api[Method]>[0];

type GetResponseFromContract<
Api extends JsonRpcApi,
Api extends JsonRpcApiContract,
Method extends keyof Api
> = ReturnType<Api[Method]>;

type GetAllCalls<Api extends JsonRpcApi> = {
type GetAllCalls<Api extends JsonRpcApiContract> = {
[Method in keyof Api]: Call<Api, Method>;
}[keyof Api];

type Call<Api extends JsonRpcApi, Method extends keyof Api> = {
type Call<Api extends JsonRpcApiContract, Method extends keyof Api> = {
method: Method;
params?: GetParamsFromContract<Api, Method>;
id?: string;
};

type GetAllResponses<
Api extends JsonRpcApi,
Api extends JsonRpcApiContract,
Calls extends readonly Call<any, any>[]
> = {
[Index in keyof Calls]: Either<
Expand All @@ -101,19 +98,32 @@ type GetAllResponses<
/**
* Instantiate this class to make requests to a JSON-RPC endpoint (or endpoints).
*/
export class JsonRpcClient<Api extends JsonRpcApi = EmptyObject> {
export class JsonRpcClient<Api extends JsonRpcApiContract = EmptyObject> {
#client: AxiosInstance;
config: ApiClientConfig;
config: JsonRpcConfig;

constructor(
// Intentionally re-defining some options-inline for better intellisense.
config:
| {
url: string;
headers?: Record<string, string>;
idGeneratorFn?: () => string;
}
| JsonRpcConfig
) {
this.config =
config instanceof JsonRpcConfig ? config : new JsonRpcConfig(config);

this.config.validate();

constructor(opts: JsonRpcCreateConfig) {
this.config = new ApiClientConfig(opts);
this.#client = this.#buildAxiosClient(this.config);
}

/**
* Create a new axios client.
*/
#buildAxiosClient(config: ApiClientConfig) {
#buildAxiosClient(config: JsonRpcConfig) {
return axios.create({
baseURL: config.url,
headers: config.headers,
Expand All @@ -125,21 +135,21 @@ export class JsonRpcClient<Api extends JsonRpcApi = EmptyObject> {
method: M,
params: GetParamsFromContract<Api, M>,
id?: string,
configOverrides?: Partial<JsonRpcCreateConfig>
configOverrides?: Partial<JsonRpcConfigOptions>
): Promise<Either<JsonRpcError, GetResponseFromContract<Api, M>>>;

async exec<M extends keyof Api = any>(
method: GetParamsFromContract<Api, M> extends undefined ? M : never,
params?: undefined,
id?: string,
configOverrides?: Partial<JsonRpcCreateConfig>
configOverrides?: Partial<JsonRpcConfigOptions>
): Promise<Either<JsonRpcError, GetResponseFromContract<Api, M>>>;

async exec<Response>(
method: Api extends EmptyObject ? string : never, // maybe add a branded type??
params?: JsonRpcParams,
id?: string,
configOverrides?: Partial<JsonRpcCreateConfig>
configOverrides?: Partial<JsonRpcConfigOptions>
): Promise<Either<JsonRpcError, Response>>;

/**
Expand All @@ -156,7 +166,7 @@ export class JsonRpcClient<Api extends JsonRpcApi = EmptyObject> {
method: string,
params?: JsonRpcParams,
id?: string,
configOverrides?: Partial<JsonRpcCreateConfig>
configOverrides?: Partial<JsonRpcConfigOptions>
) {
try {
if (configOverrides) {
Expand Down Expand Up @@ -201,7 +211,7 @@ export class JsonRpcClient<Api extends JsonRpcApi = EmptyObject> {
): Promise<GetAllResponses<Api, Calls>>;

async execBatch<Result extends unknown[]>(
calls: Call<JsonRpcApi, string>[]
calls: Call<JsonRpcApiContract, string>[]
): Promise<MapEither<Result>>;

async execBatch(calls: Call<any, any>[]): Promise<unknown[]> {
Expand Down
13 changes: 7 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
export { JsonRpcClient as default } from "./client";

export {
ApiClientConfig,
JsonRpcClient,
JsonRpcCreateConfig,
JsonRpcConfig,
JsonRpcClient, // re-export client in case users do not want to use named arguments
JsonRpcConfigOptions,
JsonRpcClientCallOptions,
JsonRpcApiContract,
} from "./client";

export { JsonRpcClient as default } from "./client";

export {
export type {
InvalidJsonRpcResponseError,
JsonRpcCall,
JsonRpcError,
Expand Down
4 changes: 4 additions & 0 deletions src/utils/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Debug from "debug";

/* run via npm test DEBUG=jsonrpc-ts-client etc */
export const debug = Debug("jsonrpc-ts-client");
2 changes: 1 addition & 1 deletion src/utils/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export type MapEither<T extends [...any[]]> = {
[Index in keyof T]: Either<JsonRpcError, GetElementByIndex<T, Index>>;
} & {};

export type Compute<T> = { [P in keyof T]: T[P] } & {};
export type InterfaceToType<T> = { [P in keyof T]: T[P] } & {};
Loading

0 comments on commit fed32c0

Please sign in to comment.