@k13engineering/yajrpc 0.0.2 → 0.0.4
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.
- package/dist/lib/coerce.js +9 -1
- package/dist/lib/definitions/combined.d.ts +37 -0
- package/dist/lib/definitions/combined.js +102 -0
- package/dist/lib/definitions/notification.d.ts +32 -0
- package/dist/lib/definitions/notification.js +95 -0
- package/dist/lib/definitions/parser.d.ts +16 -0
- package/dist/lib/definitions/parser.js +17 -0
- package/dist/lib/definitions/requests.d.ts +39 -0
- package/dist/lib/definitions/requests.js +134 -0
- package/dist/lib/index.d.ts +8 -47
- package/dist/lib/index.js +12 -248
- package/dist/lib/jrpc.d.ts +20 -0
- package/dist/lib/jrpc.js +248 -0
- package/dist/lib/types.d.ts +28 -1
- package/dist/lib/types.js +28 -0
- package/dist/lib/websocket.d.ts +35 -0
- package/dist/lib/websocket.js +202 -0
- package/package.json +2 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { createJrpc } from "./index.js";
|
|
2
|
+
/*import type { TJsonRpcMessage, TNotificationHandler, TRequestHandler } from "./jrpc.ts";*/
|
|
3
|
+
|
|
4
|
+
/*type TMessageParseResult = {
|
|
5
|
+
error: Error;
|
|
6
|
+
message: undefined;
|
|
7
|
+
} | {
|
|
8
|
+
error: undefined;
|
|
9
|
+
message: unknown;
|
|
10
|
+
};*/
|
|
11
|
+
|
|
12
|
+
/*type TWebSocketMessageParser = {
|
|
13
|
+
parse: (args: { data: string | Uint8Array }) => TMessageParseResult;
|
|
14
|
+
format: (args: { message: unknown }) => string | Uint8Array;
|
|
15
|
+
};*/
|
|
16
|
+
|
|
17
|
+
const createWebSocketJrpc = ({
|
|
18
|
+
socket,
|
|
19
|
+
|
|
20
|
+
parser,
|
|
21
|
+
|
|
22
|
+
handleRequest,
|
|
23
|
+
handleNotification,
|
|
24
|
+
|
|
25
|
+
onConnectionError,
|
|
26
|
+
onRemoteClose
|
|
27
|
+
}/*: {
|
|
28
|
+
socket: WebSocket,
|
|
29
|
+
|
|
30
|
+
parser: TWebSocketMessageParser;
|
|
31
|
+
|
|
32
|
+
handleRequest: TRequestHandler;
|
|
33
|
+
handleNotification: TNotificationHandler;
|
|
34
|
+
|
|
35
|
+
onConnectionError: (args: { error: Error }) => void;
|
|
36
|
+
onRemoteClose: () => void;
|
|
37
|
+
}*/) => {
|
|
38
|
+
|
|
39
|
+
let closedByUs = false;
|
|
40
|
+
let connectionError/*: Error | undefined*/ = undefined;
|
|
41
|
+
socket.binaryType = "arraybuffer";
|
|
42
|
+
|
|
43
|
+
let sendQueue/*: (string | Uint8Array)[]*/ = [];
|
|
44
|
+
|
|
45
|
+
const maybeSendNext = () => {
|
|
46
|
+
if (socket.readyState !== WebSocket.OPEN) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
sendQueue.forEach((data) => {
|
|
51
|
+
socket.send(data);
|
|
52
|
+
});
|
|
53
|
+
sendQueue = [];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const sendOrQueueRawMessage = ({ data }/*: { data: string | Uint8Array }*/) => {
|
|
57
|
+
sendQueue.push(data);
|
|
58
|
+
maybeSendNext();
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const sendMessage = ({ message }/*: { message: TJsonRpcMessage }*/) => {
|
|
62
|
+
const encoded = parser.format({ message });
|
|
63
|
+
sendOrQueueRawMessage({ data: encoded });
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const jrpc = createJrpc({
|
|
67
|
+
sendMessage,
|
|
68
|
+
handleRequest,
|
|
69
|
+
handleNotification
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const dataFromMessageEvent = ({ messageEvent }/*: { messageEvent: MessageEvent }*/)/*: string | Uint8Array*/ => {
|
|
73
|
+
if (typeof messageEvent.data === "string") {
|
|
74
|
+
return messageEvent.data;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (messageEvent.data instanceof ArrayBuffer) {
|
|
78
|
+
return new Uint8Array(messageEvent.data);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
throw Error("unsupported WebSocket data type");
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
socket.addEventListener("message", (event) => {
|
|
85
|
+
|
|
86
|
+
if (closedByUs) {
|
|
87
|
+
throw Error("WebSocket was closed by us, but received a message from remote");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const data = dataFromMessageEvent({ messageEvent: event });
|
|
91
|
+
|
|
92
|
+
const { error: parseError, message } = parser.parse({ data });
|
|
93
|
+
if (parseError !== undefined) {
|
|
94
|
+
closedByUs = true;
|
|
95
|
+
socket.close();
|
|
96
|
+
onConnectionError({
|
|
97
|
+
error: Error("failed to parse WebSocket message", { cause: parseError })
|
|
98
|
+
});
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const { error: jrpcError } = jrpc.receivedMessage({ message });
|
|
103
|
+
if (jrpcError !== undefined) {
|
|
104
|
+
closedByUs = true;
|
|
105
|
+
socket.close();
|
|
106
|
+
onConnectionError({
|
|
107
|
+
error: Error("failed to handle JRPC message", { cause: jrpcError })
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
socket.addEventListener("close", () => {
|
|
114
|
+
sendQueue = [];
|
|
115
|
+
jrpc.close();
|
|
116
|
+
|
|
117
|
+
if (closedByUs) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (connectionError !== undefined) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
onRemoteClose();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
socket.addEventListener("error", () => {
|
|
129
|
+
if (closedByUs) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const error = Error("WebSocket connection error");
|
|
134
|
+
connectionError = error;
|
|
135
|
+
|
|
136
|
+
onConnectionError({ error });
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const close = () => {
|
|
140
|
+
closedByUs = true;
|
|
141
|
+
socket.close();
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const bufferedAmount = () => {
|
|
145
|
+
return socket.bufferedAmount;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
request: jrpc.request,
|
|
150
|
+
notify: jrpc.notify,
|
|
151
|
+
|
|
152
|
+
bufferedAmount,
|
|
153
|
+
|
|
154
|
+
close
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/*type TWebsocketJrpcHandle = ReturnType<typeof createWebSocketJrpc>;*/
|
|
159
|
+
|
|
160
|
+
const createJsonParser = ()/*: TWebSocketMessageParser*/ => {
|
|
161
|
+
|
|
162
|
+
const parse/*: TWebSocketMessageParser["parse"]*/ = ({ data }) => {
|
|
163
|
+
|
|
164
|
+
if (typeof data === "string") {
|
|
165
|
+
try {
|
|
166
|
+
const message = JSON.parse(data);
|
|
167
|
+
return {
|
|
168
|
+
error: undefined,
|
|
169
|
+
message
|
|
170
|
+
};
|
|
171
|
+
} catch (err) {
|
|
172
|
+
return {
|
|
173
|
+
error: err /*as Error*/,
|
|
174
|
+
message: undefined
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
error: Error("unsupported WebSocket data type"),
|
|
181
|
+
message: undefined
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const format/*: TWebSocketMessageParser["format"]*/ = ({ message }) => {
|
|
186
|
+
return JSON.stringify(message);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
parse,
|
|
191
|
+
format
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export {
|
|
196
|
+
createWebSocketJrpc,
|
|
197
|
+
createJsonParser
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/*export type {
|
|
201
|
+
TWebsocketJrpcHandle,
|
|
202
|
+
};*/
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.0.
|
|
2
|
+
"version": "0.0.4",
|
|
3
3
|
"name": "@k13engineering/yajrpc",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Boilerplate project",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"@types/node": "^25.0.10",
|
|
16
16
|
"c8": "^10.1.3",
|
|
17
17
|
"deno-node": "^0.0.12",
|
|
18
|
+
"isomorphic-ws": "^5.0.0",
|
|
18
19
|
"mocha": "^11.7.5",
|
|
19
20
|
"npm-check-updates": "^19.3.1",
|
|
20
21
|
"typescript": "^5.9.3",
|