@k13engineering/yajrpc 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,255 @@
1
+ import { coerceJrpcMessage } from "./coerce.js";
2
+ /*import type { TJsonRpcError, TJsonRpcMandatoryId, TJsonRpcMessage, TJsonRpcParameters, TRequestResponse, TRequestResponseValue, TRequestResult } from "./types.ts";*/
3
+
4
+ /*type TPendingRequestHandle = {
5
+ resolve: (args: TRequestResult) => void;
6
+ };*/
7
+
8
+ /*type TRequestHandlerResponse = {
9
+ result: TRequestResponseValue;
10
+ error: undefined;
11
+ } | {
12
+ result: undefined;
13
+ error: TJsonRpcError;
14
+ } | {
15
+ result: undefined;
16
+ error: undefined;
17
+ };*/
18
+
19
+ /*type TRequestHandler = (args: { method: string, params: TJsonRpcParameters | undefined }) => Promise<TRequestHandlerResponse>;*/
20
+ /*type TNotificationHandler = (args: { method: string, params: TJsonRpcParameters | undefined }) => void;*/
21
+
22
+ /*type TNotifyMethod = (args: { method: string, params: TJsonRpcParameters }) => void;*/
23
+ /*type TRequestMethod = (args: { method: string, params: TJsonRpcParameters, timeoutMs?: number }) => Promise<TRequestResult>;*/
24
+
25
+ const createJrpc = ({
26
+ sendMessage,
27
+ handleRequest,
28
+ handleNotification
29
+ }/*: {
30
+ sendMessage: (args: { message: TJsonRpcMessage }) => void;
31
+ handleRequest: TRequestHandler;
32
+ handleNotification: TNotificationHandler;
33
+ }*/) => {
34
+
35
+ let closed = false;
36
+
37
+ const receivedRequest = ({
38
+ id,
39
+ method,
40
+ params
41
+ }/*: {
42
+ id: TJsonRpcMandatoryId,
43
+ method: string,
44
+ params: TJsonRpcParameters | undefined
45
+ }*/)/*: { error: Error | undefined }*/ => {
46
+
47
+ handleRequest({ method, params }).then((response) => {
48
+
49
+ if (response.error !== undefined) {
50
+ sendMessage({
51
+ message: {
52
+ jsonrpc: "2.0",
53
+ id,
54
+ error: response.error
55
+ }
56
+ });
57
+ return;
58
+ }
59
+
60
+ if (response.result !== undefined) {
61
+ sendMessage({
62
+ message: {
63
+ jsonrpc: "2.0",
64
+ result: response.result,
65
+ id
66
+ }
67
+ });
68
+ return;
69
+ }
70
+
71
+ // send nothing if we neither have a result nor an error
72
+ // this is a valid case
73
+ });
74
+
75
+ return {
76
+ error: undefined
77
+ };
78
+ };
79
+
80
+ let pendingRequests/*: Record<string, TPendingRequestHandle>*/ = {};
81
+
82
+ const receivedResponse = ({ id, response }/*: { id: TJsonRpcMandatoryId, response: TRequestResponse }*/)/*: { error: Error | undefined }*/ => {
83
+ const pendingRequest = pendingRequests[id];
84
+ if (pendingRequest === undefined) {
85
+ return {
86
+ error: Error("received response for non-pending id")
87
+ };
88
+ }
89
+
90
+ pendingRequest.resolve({
91
+ response,
92
+ error: undefined
93
+ });
94
+
95
+ return {
96
+ error: undefined
97
+ };
98
+ };
99
+
100
+ // eslint-disable-next-line complexity
101
+ const receivedMessage = ({ message }/*: { message: unknown }*/)/*: { error: Error | undefined }*/ => {
102
+ if (closed) {
103
+ throw Error("connection closed");
104
+ }
105
+
106
+ const { error: coerceError, jrpcMessage } = coerceJrpcMessage({ message });
107
+ if (coerceError !== undefined) {
108
+ return {
109
+ error: coerceError
110
+ };
111
+ }
112
+
113
+ if (jrpcMessage.id === null) {
114
+ return {
115
+ error: Error("this library does not support null ids")
116
+ };
117
+ }
118
+
119
+ if (jrpcMessage.id === undefined) {
120
+ handleNotification({
121
+ method: jrpcMessage.method,
122
+ params: jrpcMessage.params
123
+ });
124
+
125
+ return { error: undefined };
126
+ }
127
+
128
+ if (jrpcMessage.result !== undefined) {
129
+ return receivedResponse({
130
+ id: jrpcMessage.id,
131
+ response: {
132
+ result: jrpcMessage.result,
133
+ error: undefined
134
+ }
135
+ });
136
+ }
137
+
138
+ if (jrpcMessage.error !== undefined) {
139
+ return receivedResponse({
140
+ id: jrpcMessage.id,
141
+ response: {
142
+ result: undefined,
143
+ error: jrpcMessage.error
144
+ }
145
+ });
146
+ }
147
+
148
+ return receivedRequest({
149
+ id: jrpcMessage.id,
150
+ method: jrpcMessage.method,
151
+ params: jrpcMessage.params
152
+ });
153
+ };
154
+
155
+ const close = () => {
156
+ if (closed) {
157
+ throw Error("connection already closed");
158
+ }
159
+
160
+ Object.keys(pendingRequests).forEach((id) => {
161
+ const pendingRequest = pendingRequests[id];
162
+ pendingRequest.resolve({
163
+ error: Error("connection closed"),
164
+ response: undefined
165
+ });
166
+ });
167
+
168
+ closed = true;
169
+ };
170
+
171
+ let requestIdCounter = 0;
172
+
173
+ const request/*: TRequestMethod*/ = ({
174
+ method,
175
+ params,
176
+ timeoutMs
177
+ })/*: Promise<TRequestResult>*/ => {
178
+
179
+ const requestId = requestIdCounter;
180
+ requestIdCounter += 1;
181
+
182
+ let timeoutHandle/*: NodeJS.Timeout | undefined*/ = undefined;
183
+ if (timeoutMs !== undefined) {
184
+ timeoutHandle = setTimeout(() => {
185
+ const pendingRequest = pendingRequests[requestId];
186
+ pendingRequest.resolve({
187
+ error: Error("timeout"),
188
+ response: undefined
189
+ });
190
+ }, timeoutMs);
191
+ }
192
+
193
+ sendMessage({
194
+ message: {
195
+ jsonrpc: "2.0",
196
+ method,
197
+ params,
198
+ id: requestId
199
+ }
200
+ });
201
+
202
+ return new Promise((resolve) => {
203
+ pendingRequests = {
204
+ ...pendingRequests,
205
+ [requestId]: {
206
+ resolve: (result) => {
207
+ // remove the request from the pending requests
208
+ const { [requestId]: requestToDrop, ...otherPendingRequests } = pendingRequests;
209
+ pendingRequests = otherPendingRequests;
210
+
211
+ // clear the timeout
212
+ clearTimeout(timeoutHandle);
213
+
214
+ resolve(result);
215
+ },
216
+ timeoutHandle
217
+ }
218
+ };
219
+ });
220
+ };
221
+
222
+ const notify/*: TNotifyMethod*/ = ({ method, params }) => {
223
+ sendMessage({
224
+ message: {
225
+ jsonrpc: "2.0",
226
+ method,
227
+ params
228
+ }
229
+ });
230
+ };
231
+
232
+ return {
233
+ receivedMessage,
234
+ request,
235
+ notify,
236
+ close
237
+ };
238
+ };
239
+
240
+ /*type TJrpc = ReturnType<typeof createJrpc>;*/
241
+
242
+ export {
243
+ createJrpc
244
+ };
245
+
246
+ /*export type {
247
+ TJsonRpcMessage,
248
+ TRequestResponse,
249
+ TRequestResult,
250
+ TJrpc,
251
+ TRequestHandler,
252
+ TNotificationHandler,
253
+ TRequestMethod,
254
+ TNotifyMethod
255
+ };*/
@@ -0,0 +1,68 @@
1
+ type TJsonRpcParameterValue = Exclude<unknown, undefined>;
2
+ type TRequestResponseValue = NonNullable<unknown> | null;
3
+ type TJsonRpcParameters = Array<TJsonRpcParameterValue> | Record<string, TJsonRpcParameterValue>;
4
+ type TJsonRpcOptionalId = string | number | null;
5
+ type TJsonRpcMandatoryId = string | number;
6
+ type TJsonRpcError = {
7
+ code: number;
8
+ message: string;
9
+ data?: unknown;
10
+ };
11
+ type TJsonRpcRequest = {
12
+ jsonrpc: "2.0";
13
+ id: TJsonRpcOptionalId;
14
+ method: string;
15
+ params?: TJsonRpcParameters;
16
+ result?: undefined;
17
+ error?: undefined;
18
+ };
19
+ type TJsonRpcNotification = {
20
+ jsonrpc: "2.0";
21
+ id?: undefined;
22
+ method: string;
23
+ params?: TJsonRpcParameters;
24
+ result?: undefined;
25
+ error?: undefined;
26
+ };
27
+ type TJsonRpcSuccessResponse = {
28
+ jsonrpc: "2.0";
29
+ id: TJsonRpcMandatoryId;
30
+ method?: undefined;
31
+ params?: undefined;
32
+ result: TRequestResponseValue;
33
+ error?: undefined;
34
+ };
35
+ type TJsonRpcErrorResponse = {
36
+ jsonrpc: "2.0";
37
+ id: TJsonRpcOptionalId;
38
+ method?: undefined;
39
+ params?: undefined;
40
+ result?: undefined;
41
+ error: TJsonRpcError;
42
+ };
43
+ type TJsonRpcResponse = TJsonRpcSuccessResponse | TJsonRpcErrorResponse;
44
+ type TJsonRpcMessage = TJsonRpcRequest | TJsonRpcNotification | TJsonRpcResponse;
45
+ type TRequestErrorResponse = {
46
+ result?: never;
47
+ error: {
48
+ code: number;
49
+ message: string;
50
+ data?: unknown;
51
+ };
52
+ ignore?: never;
53
+ };
54
+ type TRequestResponse = {
55
+ error: TJsonRpcError;
56
+ result: undefined;
57
+ } | {
58
+ error: undefined;
59
+ result: TRequestResponseValue;
60
+ };
61
+ type TRequestResult = {
62
+ error: Error;
63
+ response: undefined;
64
+ } | {
65
+ error: undefined;
66
+ response: TRequestResponse;
67
+ };
68
+ export type { TJsonRpcRequest, TJsonRpcResponse, TJsonRpcNotification, TJsonRpcSuccessResponse, TJsonRpcErrorResponse, TJsonRpcMessage, TJsonRpcParameters, TJsonRpcOptionalId, TJsonRpcMandatoryId, TRequestResponse, TRequestResult, TRequestErrorResponse, TRequestResponseValue, TJsonRpcError, };
@@ -0,0 +1,98 @@
1
+ /* c8 ignore start */
2
+ /*type TJsonRpcParameterValue = Exclude<unknown, undefined>;*/
3
+ /*type TRequestResponseValue = NonNullable<unknown> | null;*/
4
+
5
+ /*type TJsonRpcParameters = Array<TJsonRpcParameterValue> | Record<string, TJsonRpcParameterValue>;*/
6
+
7
+ /*type TJsonRpcOptionalId = string | number | null;*/
8
+ /*type TJsonRpcMandatoryId = string | number;*/
9
+
10
+ /*type TJsonRpcError = {
11
+ code: number;
12
+ message: string;
13
+ data?: unknown;
14
+ };*/
15
+
16
+ /*type TJsonRpcRequest = {
17
+ jsonrpc: "2.0";
18
+ id: TJsonRpcOptionalId;
19
+ method: string;
20
+ params?: TJsonRpcParameters;
21
+ result?: undefined;
22
+ error?: undefined;
23
+ };*/
24
+
25
+ /*type TJsonRpcNotification = {
26
+ jsonrpc: "2.0";
27
+ id?: undefined;
28
+ method: string;
29
+ params?: TJsonRpcParameters;
30
+ result?: undefined;
31
+ error?: undefined;
32
+ };*/
33
+
34
+ /*type TJsonRpcSuccessResponse = {
35
+ jsonrpc: "2.0";
36
+ id: TJsonRpcMandatoryId;
37
+ method?: undefined;
38
+ params?: undefined;
39
+ result: TRequestResponseValue;
40
+ error?: undefined;
41
+ };*/
42
+
43
+ /*type TJsonRpcErrorResponse = {
44
+ jsonrpc: "2.0";
45
+ id: TJsonRpcOptionalId;
46
+ method?: undefined;
47
+ params?: undefined;
48
+ result?: undefined;
49
+ error: TJsonRpcError;
50
+ };*/
51
+
52
+ /*type TJsonRpcResponse = TJsonRpcSuccessResponse | TJsonRpcErrorResponse;*/
53
+
54
+ /*type TJsonRpcMessage = TJsonRpcRequest | TJsonRpcNotification | TJsonRpcResponse;*/
55
+
56
+ /*type TRequestErrorResponse = {
57
+ result?: never;
58
+ error: {
59
+ code: number;
60
+ message: string;
61
+ data?: unknown;
62
+ };
63
+ ignore?: never;
64
+ };*/
65
+
66
+ /*type TRequestResponse = {
67
+ error: TJsonRpcError;
68
+ result: undefined;
69
+ } | {
70
+ error: undefined;
71
+ result: TRequestResponseValue;
72
+ };*/
73
+
74
+ /*type TRequestResult = {
75
+ error: Error;
76
+ response: undefined;
77
+ } | {
78
+ error: undefined;
79
+ response: TRequestResponse;
80
+ };*/
81
+
82
+ /*export type {
83
+ TJsonRpcRequest,
84
+ TJsonRpcResponse,
85
+ TJsonRpcNotification,
86
+ TJsonRpcSuccessResponse,
87
+ TJsonRpcErrorResponse,
88
+ TJsonRpcMessage,
89
+ TJsonRpcParameters,
90
+ TJsonRpcOptionalId,
91
+ TJsonRpcMandatoryId,
92
+ TRequestResponse,
93
+ TRequestResult,
94
+ TRequestErrorResponse,
95
+ TRequestResponseValue,
96
+ TJsonRpcError,
97
+ };*/
98
+ /* c8 ignore end */
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "version": "0.0.1",
3
+ "name": "@k13engineering/yajrpc",
4
+ "type": "module",
5
+ "description": "Boilerplate project",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "main": "dist/lib/index.js",
10
+ "scripts": {
11
+ "build": "rm -rf dist/ && deno-node-build --root . --out dist/ --entry lib/index.ts",
12
+ "type-check": "tsc --noEmit",
13
+ "test": "c8 --reporter lcov --reporter html --reporter text --all --src lib/ --exclude lib/snippets/ --exclude test/ mocha test/**/*.ts",
14
+ "lint": "eslint .",
15
+ "update-deps": "npm-check-updates -u"
16
+ },
17
+ "devDependencies": {
18
+ "@eslint/js": "^9.39.2",
19
+ "@k13engineering/releasetool": "^0.0.5",
20
+ "@types/mocha": "^10.0.10",
21
+ "@types/node": "^25.0.10",
22
+ "c8": "^10.1.3",
23
+ "deno-node": "^0.0.12",
24
+ "mocha": "^11.7.5",
25
+ "npm-check-updates": "^19.3.1",
26
+ "typescript": "^5.9.3",
27
+ "typescript-eslint": "^8.53.1"
28
+ },
29
+ "dependencies": {},
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/k13-engineering/yajrpc.git"
36
+ },
37
+ "keywords": [
38
+ "node",
39
+ "jrpc"
40
+ ],
41
+ "author": "Simon Kadisch",
42
+ "license": "LGPL 2.1",
43
+ "bugs": {
44
+ "url": "https://github.com/k13-engineering/yajrpc/issues"
45
+ },
46
+ "homepage": "https://github.com/k13-engineering/yajrpc#readme"
47
+ }