@msaki/jsonrpc 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ # Changesets
2
+
3
+ Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4
+ with multi-package repos, or single-package repos to help you version and publish your code. You can
5
+ find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6
+
7
+ We have a quick list of common questions to get you started engaging with this project in
8
+ [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@changesets/config@3.1.2/schema.json",
3
+ "changelog": "@changesets/cli/changelog",
4
+ "commit": false,
5
+ "fixed": [],
6
+ "linked": [],
7
+ "access": "public",
8
+ "baseBranch": "main",
9
+ "updateInternalDependencies": "patch",
10
+ "ignore": []
11
+ }
@@ -0,0 +1,5 @@
1
+ ---
2
+ "@msaki/jsonrpc": patch
3
+ ---
4
+
5
+ add changeset and build process
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # jsonrpc
2
+
3
+ ## Usage
4
+
5
+ ```sh
6
+ import { JsonRpcServer } from "@msaki/jsonrpc";
7
+
8
+ const server = new JsonRpcServer()
9
+
10
+ server.register("add", ([a,b]: [number, number]) => a + b)
11
+ server.register("ping", () => "pong")
12
+
13
+ Bun.serve({
14
+ port: 4444,
15
+ async fetch(req) {
16
+ if (req.method !== "POST") {
17
+ return new Response("JSON-RPC only", { status: 405 })
18
+ }
19
+ const payload = await req.json();
20
+ const response = await server.handle(payload);
21
+ if (!response) {
22
+ return new Response(null, { status: 204 })
23
+ }
24
+ return Response.json(response);
25
+ }
26
+ })
27
+
28
+ console.log("JSON-RPC sever on http://localhost:4444")
29
+ ```
@@ -0,0 +1,47 @@
1
+ type JsonRpcId = string | number | null;
2
+ interface JsonRpcRequest {
3
+ jsonrpc: "2.0";
4
+ method: string;
5
+ params?: unknown;
6
+ id?: JsonRpcId;
7
+ }
8
+ interface JsonRpcSuccess {
9
+ jsonrpc: "2.0";
10
+ result: unknown;
11
+ id: JsonRpcId;
12
+ }
13
+ interface JsonRpcErrorObject {
14
+ code: number;
15
+ message: string;
16
+ data?: unknown;
17
+ }
18
+ interface JsonRpcError {
19
+ jsonrpc: "2.0";
20
+ error: JsonRpcErrorObject;
21
+ id: JsonRpcId;
22
+ }
23
+ type JsonRpcResponse = JsonRpcSuccess | JsonRpcError;
24
+
25
+ declare const INVALID_REQUEST = -32600;
26
+ declare const METHOD_NOT_FOUND = -32601;
27
+ declare const INVALID_PARAMS = -32602;
28
+ declare const INTERNAL_ERROR = -32603;
29
+ declare const PARSE_ERROR = -32700;
30
+ declare const REQUEST_ABORTED = -32800;
31
+ type Handler = (params: any) => any | Promise<any>;
32
+ declare class JsonRpcServer {
33
+ private methods;
34
+ register(method: string, handler: Handler): void;
35
+ handle(raw: unknown): Promise<JsonRpcResponse | JsonRpcResponse[] | null>;
36
+ private error;
37
+ }
38
+
39
+ declare class JsonRpcClient {
40
+ private send;
41
+ private id;
42
+ constructor(send: (req: JsonRpcRequest) => Promise<JsonRpcResponse>);
43
+ call<T = unknown>(method: string, params?: unknown): Promise<T>;
44
+ notify(method: string, params?: unknown): Promise<JsonRpcResponse>;
45
+ }
46
+
47
+ export { type Handler, INTERNAL_ERROR, INVALID_PARAMS, INVALID_REQUEST, JsonRpcClient, type JsonRpcError, type JsonRpcErrorObject, type JsonRpcId, type JsonRpcRequest, type JsonRpcResponse, JsonRpcServer, type JsonRpcSuccess, METHOD_NOT_FOUND, PARSE_ERROR, REQUEST_ABORTED };
@@ -0,0 +1,47 @@
1
+ type JsonRpcId = string | number | null;
2
+ interface JsonRpcRequest {
3
+ jsonrpc: "2.0";
4
+ method: string;
5
+ params?: unknown;
6
+ id?: JsonRpcId;
7
+ }
8
+ interface JsonRpcSuccess {
9
+ jsonrpc: "2.0";
10
+ result: unknown;
11
+ id: JsonRpcId;
12
+ }
13
+ interface JsonRpcErrorObject {
14
+ code: number;
15
+ message: string;
16
+ data?: unknown;
17
+ }
18
+ interface JsonRpcError {
19
+ jsonrpc: "2.0";
20
+ error: JsonRpcErrorObject;
21
+ id: JsonRpcId;
22
+ }
23
+ type JsonRpcResponse = JsonRpcSuccess | JsonRpcError;
24
+
25
+ declare const INVALID_REQUEST = -32600;
26
+ declare const METHOD_NOT_FOUND = -32601;
27
+ declare const INVALID_PARAMS = -32602;
28
+ declare const INTERNAL_ERROR = -32603;
29
+ declare const PARSE_ERROR = -32700;
30
+ declare const REQUEST_ABORTED = -32800;
31
+ type Handler = (params: any) => any | Promise<any>;
32
+ declare class JsonRpcServer {
33
+ private methods;
34
+ register(method: string, handler: Handler): void;
35
+ handle(raw: unknown): Promise<JsonRpcResponse | JsonRpcResponse[] | null>;
36
+ private error;
37
+ }
38
+
39
+ declare class JsonRpcClient {
40
+ private send;
41
+ private id;
42
+ constructor(send: (req: JsonRpcRequest) => Promise<JsonRpcResponse>);
43
+ call<T = unknown>(method: string, params?: unknown): Promise<T>;
44
+ notify(method: string, params?: unknown): Promise<JsonRpcResponse>;
45
+ }
46
+
47
+ export { type Handler, INTERNAL_ERROR, INVALID_PARAMS, INVALID_REQUEST, JsonRpcClient, type JsonRpcError, type JsonRpcErrorObject, type JsonRpcId, type JsonRpcRequest, type JsonRpcResponse, JsonRpcServer, type JsonRpcSuccess, METHOD_NOT_FOUND, PARSE_ERROR, REQUEST_ABORTED };
package/dist/index.js ADDED
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ INTERNAL_ERROR: () => INTERNAL_ERROR,
24
+ INVALID_PARAMS: () => INVALID_PARAMS,
25
+ INVALID_REQUEST: () => INVALID_REQUEST,
26
+ JsonRpcClient: () => JsonRpcClient,
27
+ JsonRpcServer: () => JsonRpcServer,
28
+ METHOD_NOT_FOUND: () => METHOD_NOT_FOUND,
29
+ PARSE_ERROR: () => PARSE_ERROR,
30
+ REQUEST_ABORTED: () => REQUEST_ABORTED
31
+ });
32
+ module.exports = __toCommonJS(index_exports);
33
+
34
+ // src/server.ts
35
+ var INVALID_REQUEST = -32600;
36
+ var METHOD_NOT_FOUND = -32601;
37
+ var INVALID_PARAMS = -32602;
38
+ var INTERNAL_ERROR = -32603;
39
+ var PARSE_ERROR = -32700;
40
+ var REQUEST_ABORTED = -32800;
41
+ var JsonRpcServer = class {
42
+ methods = /* @__PURE__ */ new Map();
43
+ register(method, handler) {
44
+ this.methods.set(method, handler);
45
+ }
46
+ async handle(raw) {
47
+ if (Array.isArray(raw)) {
48
+ if (raw.length === 0) {
49
+ return this.error(null, INVALID_REQUEST, "Invalid request");
50
+ }
51
+ const responses = await Promise.all(
52
+ raw.map((item) => this.handle(item))
53
+ );
54
+ const filtered = responses.filter(
55
+ (r) => r !== null
56
+ );
57
+ return filtered.length > 0 ? filtered : null;
58
+ }
59
+ let req = raw;
60
+ if (typeof req !== "object" || req === null || req.jsonrpc !== "2.0" || typeof req.method !== "string") {
61
+ return this.error(null, INVALID_REQUEST, "Invalid request");
62
+ }
63
+ const id = typeof req?.id === "string" || typeof req?.id === "number" || req?.id === null ? req.id : null;
64
+ const handler = this.methods.get(req.method);
65
+ if (!handler) {
66
+ return id === null ? null : this.error(req.id, METHOD_NOT_FOUND, "Method not found");
67
+ }
68
+ try {
69
+ const result = await handler(req.params);
70
+ if (req.id === void 0) return null;
71
+ return {
72
+ jsonrpc: "2.0",
73
+ result,
74
+ id: req.id
75
+ };
76
+ } catch (err) {
77
+ return this.error(
78
+ req.id ?? null,
79
+ INTERNAL_ERROR,
80
+ "Internal error",
81
+ err instanceof Error ? err.message : err
82
+ );
83
+ }
84
+ }
85
+ error(id, code, message, data) {
86
+ return {
87
+ jsonrpc: "2.0",
88
+ error: { code, message, data },
89
+ id: id ?? null
90
+ };
91
+ }
92
+ };
93
+
94
+ // src/client.ts
95
+ var JsonRpcClient = class {
96
+ constructor(send) {
97
+ this.send = send;
98
+ }
99
+ id = 0;
100
+ async call(method, params) {
101
+ const request = {
102
+ jsonrpc: "2.0",
103
+ method,
104
+ params,
105
+ id: ++this.id
106
+ };
107
+ const response = await this.send(request);
108
+ if ("error" in response) {
109
+ const e = response.error;
110
+ throw new Error(`RPC error ${e.code} ${e.message}`);
111
+ }
112
+ return response.result;
113
+ }
114
+ notify(method, params) {
115
+ const request = {
116
+ jsonrpc: "2.0",
117
+ method,
118
+ params
119
+ };
120
+ return this.send(request);
121
+ }
122
+ };
123
+ // Annotate the CommonJS export names for ESM import in node:
124
+ 0 && (module.exports = {
125
+ INTERNAL_ERROR,
126
+ INVALID_PARAMS,
127
+ INVALID_REQUEST,
128
+ JsonRpcClient,
129
+ JsonRpcServer,
130
+ METHOD_NOT_FOUND,
131
+ PARSE_ERROR,
132
+ REQUEST_ABORTED
133
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,99 @@
1
+ // src/server.ts
2
+ var INVALID_REQUEST = -32600;
3
+ var METHOD_NOT_FOUND = -32601;
4
+ var INVALID_PARAMS = -32602;
5
+ var INTERNAL_ERROR = -32603;
6
+ var PARSE_ERROR = -32700;
7
+ var REQUEST_ABORTED = -32800;
8
+ var JsonRpcServer = class {
9
+ methods = /* @__PURE__ */ new Map();
10
+ register(method, handler) {
11
+ this.methods.set(method, handler);
12
+ }
13
+ async handle(raw) {
14
+ if (Array.isArray(raw)) {
15
+ if (raw.length === 0) {
16
+ return this.error(null, INVALID_REQUEST, "Invalid request");
17
+ }
18
+ const responses = await Promise.all(
19
+ raw.map((item) => this.handle(item))
20
+ );
21
+ const filtered = responses.filter(
22
+ (r) => r !== null
23
+ );
24
+ return filtered.length > 0 ? filtered : null;
25
+ }
26
+ let req = raw;
27
+ if (typeof req !== "object" || req === null || req.jsonrpc !== "2.0" || typeof req.method !== "string") {
28
+ return this.error(null, INVALID_REQUEST, "Invalid request");
29
+ }
30
+ const id = typeof req?.id === "string" || typeof req?.id === "number" || req?.id === null ? req.id : null;
31
+ const handler = this.methods.get(req.method);
32
+ if (!handler) {
33
+ return id === null ? null : this.error(req.id, METHOD_NOT_FOUND, "Method not found");
34
+ }
35
+ try {
36
+ const result = await handler(req.params);
37
+ if (req.id === void 0) return null;
38
+ return {
39
+ jsonrpc: "2.0",
40
+ result,
41
+ id: req.id
42
+ };
43
+ } catch (err) {
44
+ return this.error(
45
+ req.id ?? null,
46
+ INTERNAL_ERROR,
47
+ "Internal error",
48
+ err instanceof Error ? err.message : err
49
+ );
50
+ }
51
+ }
52
+ error(id, code, message, data) {
53
+ return {
54
+ jsonrpc: "2.0",
55
+ error: { code, message, data },
56
+ id: id ?? null
57
+ };
58
+ }
59
+ };
60
+
61
+ // src/client.ts
62
+ var JsonRpcClient = class {
63
+ constructor(send) {
64
+ this.send = send;
65
+ }
66
+ id = 0;
67
+ async call(method, params) {
68
+ const request = {
69
+ jsonrpc: "2.0",
70
+ method,
71
+ params,
72
+ id: ++this.id
73
+ };
74
+ const response = await this.send(request);
75
+ if ("error" in response) {
76
+ const e = response.error;
77
+ throw new Error(`RPC error ${e.code} ${e.message}`);
78
+ }
79
+ return response.result;
80
+ }
81
+ notify(method, params) {
82
+ const request = {
83
+ jsonrpc: "2.0",
84
+ method,
85
+ params
86
+ };
87
+ return this.send(request);
88
+ }
89
+ };
90
+ export {
91
+ INTERNAL_ERROR,
92
+ INVALID_PARAMS,
93
+ INVALID_REQUEST,
94
+ JsonRpcClient,
95
+ JsonRpcServer,
96
+ METHOD_NOT_FOUND,
97
+ PARSE_ERROR,
98
+ REQUEST_ABORTED
99
+ };
package/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./src/types"
2
+ export * from "./src/server";
3
+ export * from "./src/client";
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@msaki/jsonrpc",
3
+ "author": "Meek Msaki",
4
+ "version": "0.0.1",
5
+ "license": "MIT",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.mjs",
8
+ "types": "dist/index.d.ts",
9
+ "scripts": {
10
+ "build": "tsup index.ts --format cjs,esm --dts",
11
+ "publish": "bun run build && changeset publish",
12
+ "lint": "tsc"
13
+ },
14
+ "devDependencies": {
15
+ "@changesets/cli": "^2.29.8",
16
+ "@types/bun": "latest",
17
+ "tsup": "^8.5.1"
18
+ },
19
+ "peerDependencies": {
20
+ "typescript": "^5"
21
+ }
22
+ }
package/src/client.ts ADDED
@@ -0,0 +1,33 @@
1
+ import type { JsonRpcRequest, JsonRpcResponse } from "./types";
2
+
3
+ export class JsonRpcClient {
4
+ private id = 0
5
+
6
+ constructor(
7
+ private send: (req: JsonRpcRequest) => Promise<JsonRpcResponse>
8
+ ) {}
9
+
10
+ async call<T = unknown>(method: string, params?: unknown): Promise<T> {
11
+ const request: JsonRpcRequest = {
12
+ jsonrpc: "2.0",
13
+ method,
14
+ params,
15
+ id: ++this.id,
16
+ }
17
+ const response = await this.send(request);
18
+ if ("error" in response) {
19
+ const e = response.error
20
+ throw new Error(`RPC error ${e.code} ${e.message}`)
21
+ }
22
+ return response.result as T
23
+ }
24
+
25
+ notify(method: string, params?: unknown) {
26
+ const request: JsonRpcRequest = {
27
+ jsonrpc: "2.0",
28
+ method,
29
+ params
30
+ }
31
+ return this.send(request)
32
+ }
33
+ }
package/src/server.ts ADDED
@@ -0,0 +1,88 @@
1
+ import type { JsonRpcResponse, JsonRpcRequest } from "./types";
2
+
3
+ export const INVALID_REQUEST = -32600;
4
+ export const METHOD_NOT_FOUND = -32601;
5
+ export const INVALID_PARAMS = -32602; // unused
6
+ export const INTERNAL_ERROR = -32603;
7
+ export const PARSE_ERROR = -32700; // unused
8
+ export const REQUEST_ABORTED = -32800; // unused
9
+
10
+ export type Handler = (params: any) => any | Promise<any>
11
+
12
+ export class JsonRpcServer {
13
+ private methods = new Map<string, Handler>()
14
+
15
+ register(method: string, handler: Handler) {
16
+ this.methods.set(method, handler)
17
+ }
18
+
19
+ async handle(
20
+ raw: unknown,
21
+ ): Promise<JsonRpcResponse | JsonRpcResponse[] | null> {
22
+ // handle batch
23
+ if (Array.isArray(raw)) {
24
+ if (raw.length === 0) {
25
+ return this.error(null, INVALID_REQUEST, "Invalid request")
26
+ }
27
+ const responses = await Promise.all(
28
+ raw.map(item => this.handle(item))
29
+ )
30
+ const filtered = responses.filter(
31
+ (r): r is JsonRpcResponse => r !== null
32
+ )
33
+ return filtered.length > 0 ? filtered : null
34
+ }
35
+
36
+ // handle single response
37
+ let req = raw as Partial<JsonRpcRequest>
38
+
39
+ if (
40
+ typeof req !== "object" ||
41
+ req === null ||
42
+ req.jsonrpc !== "2.0" ||
43
+ typeof req.method !== "string"
44
+ ) {
45
+ return this.error(null, INVALID_REQUEST, "Invalid request")
46
+ }
47
+
48
+ const id =
49
+ typeof (req as any)?.id === "string" ||
50
+ typeof (req as any)?.id === "number" ||
51
+ (req as any)?.id === null ? (req as any).id : null
52
+
53
+ const handler = this.methods.get(req.method)
54
+ if (!handler) {
55
+ return id === null ? null : this.error(req.id, METHOD_NOT_FOUND, "Method not found")
56
+ }
57
+
58
+ try {
59
+ const result = await handler(req.params)
60
+ if (req.id === undefined) return null // notification
61
+ return {
62
+ jsonrpc: "2.0",
63
+ result,
64
+ id: req.id
65
+ }
66
+ } catch (err) {
67
+ return this.error(
68
+ req.id ?? null,
69
+ INTERNAL_ERROR,
70
+ "Internal error",
71
+ err instanceof Error ? err.message : err
72
+ )
73
+ }
74
+ }
75
+
76
+ private error(
77
+ id: JsonRpcRequest["id"],
78
+ code: number,
79
+ message: string,
80
+ data?: unknown
81
+ ): JsonRpcResponse {
82
+ return {
83
+ jsonrpc: "2.0",
84
+ error: { code, message, data },
85
+ id: id ?? null
86
+ }
87
+ }
88
+ }
package/src/types.ts ADDED
@@ -0,0 +1,28 @@
1
+ export type JsonRpcId = string | number | null
2
+
3
+ export interface JsonRpcRequest {
4
+ jsonrpc: "2.0"
5
+ method: string
6
+ params?: unknown
7
+ id?: JsonRpcId
8
+ }
9
+
10
+ export interface JsonRpcSuccess {
11
+ jsonrpc: "2.0"
12
+ result: unknown
13
+ id: JsonRpcId
14
+ }
15
+
16
+ export interface JsonRpcErrorObject {
17
+ code: number
18
+ message: string
19
+ data?: unknown
20
+ }
21
+
22
+ export interface JsonRpcError {
23
+ jsonrpc: "2.0"
24
+ error: JsonRpcErrorObject
25
+ id: JsonRpcId
26
+ }
27
+
28
+ export type JsonRpcResponse = JsonRpcSuccess | JsonRpcError
package/tsconfig.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Environment setup & latest features
4
+ "lib": [
5
+ "ESNext"
6
+ ],
7
+ "target": "ESNext",
8
+ "module": "Preserve",
9
+ "moduleDetection": "force",
10
+ "jsx": "react-jsx",
11
+ "allowJs": true,
12
+ // Bundler mode
13
+ "moduleResolution": "bundler",
14
+ "allowImportingTsExtensions": true,
15
+ "verbatimModuleSyntax": true,
16
+ "noEmit": true,
17
+ // Best practices
18
+ "strict": true,
19
+ "skipLibCheck": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "noUncheckedIndexedAccess": true,
22
+ "noImplicitOverride": true,
23
+ // Some stricter flags (disabled by default)
24
+ "noUnusedLocals": false,
25
+ "noUnusedParameters": false,
26
+ "noPropertyAccessFromIndexSignature": false
27
+ }
28
+ }