@gtkx/mcp 1.3.0 → 1.5.0
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/README.md +5 -4
- package/dist/app-router.d.ts +3 -5
- package/dist/app-router.d.ts.map +1 -1
- package/dist/app-router.js +21 -34
- package/dist/app-router.js.map +1 -1
- package/dist/connection-registry.d.ts +3 -4
- package/dist/connection-registry.d.ts.map +1 -1
- package/dist/connection-registry.js +5 -16
- package/dist/connection-registry.js.map +1 -1
- package/dist/internal.d.ts +3 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/protocol/errors.d.ts +6 -7
- package/dist/protocol/errors.d.ts.map +1 -1
- package/dist/protocol/errors.js +12 -8
- package/dist/protocol/errors.js.map +1 -1
- package/dist/protocol/schemas.d.ts +1 -19
- package/dist/protocol/schemas.d.ts.map +1 -1
- package/dist/protocol/schemas.js +1 -16
- package/dist/protocol/schemas.js.map +1 -1
- package/dist/socket-server.js +1 -1
- package/dist/socket-server.js.map +1 -1
- package/dist/transport.d.ts +18 -39
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +78 -127
- package/dist/transport.js.map +1 -1
- package/package.json +6 -6
- package/src/app-router.ts +34 -44
- package/src/connection-registry.ts +6 -22
- package/src/internal.ts +2 -3
- package/src/protocol/errors.ts +20 -10
- package/src/protocol/schemas.ts +0 -41
- package/src/socket-server.ts +1 -1
- package/src/transport.ts +106 -171
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Socket } from "node:net";
|
|
2
|
-
import
|
|
2
|
+
import { methodNotFoundError } from "./protocol/errors.js";
|
|
3
3
|
import {
|
|
4
4
|
type AppConnections,
|
|
5
5
|
connectionDisconnectionEvent,
|
|
6
6
|
connectionErrorEvent,
|
|
7
|
-
|
|
7
|
+
type ConnectionRequestHandler,
|
|
8
8
|
ProtocolConnection,
|
|
9
9
|
} from "./transport.js";
|
|
10
10
|
|
|
@@ -12,6 +12,8 @@ class ConnectionRegistry extends EventTarget implements AppConnections {
|
|
|
12
12
|
private connections: Map<string, ProtocolConnection> = new Map();
|
|
13
13
|
private sockets: Map<string, Socket> = new Map();
|
|
14
14
|
|
|
15
|
+
onRequest: ConnectionRequestHandler = (_connection, request) => Promise.reject(methodNotFoundError(request.method));
|
|
16
|
+
|
|
15
17
|
register(socket: Socket): ProtocolConnection {
|
|
16
18
|
const connection = ProtocolConnection.fromSocket(socket, {
|
|
17
19
|
onClose: () => {
|
|
@@ -24,30 +26,12 @@ class ConnectionRegistry extends EventTarget implements AppConnections {
|
|
|
24
26
|
|
|
25
27
|
this.connections.set(connection.id, connection);
|
|
26
28
|
this.sockets.set(connection.id, socket);
|
|
27
|
-
connection.
|
|
28
|
-
|
|
29
|
-
connection.on("invalid", ({ id: badId, error }) => {
|
|
30
|
-
connection.write({ id: badId, error: error.toErrorObject() });
|
|
31
|
-
});
|
|
29
|
+
connection.fallbackRequestHandler = (request) => this.onRequest(connection, request);
|
|
32
30
|
|
|
33
31
|
return connection;
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
const connection = this.connections.get(connectionId);
|
|
38
|
-
|
|
39
|
-
if (!connection) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
connection.write(message);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
dispose(reason: string): void {
|
|
47
|
-
for (const connection of this.connections.values()) {
|
|
48
|
-
connection.rejectPending(new Error(reason));
|
|
49
|
-
}
|
|
50
|
-
|
|
34
|
+
dispose(): void {
|
|
51
35
|
for (const socket of this.sockets.values()) {
|
|
52
36
|
socket.destroy();
|
|
53
37
|
}
|
package/src/internal.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export {
|
|
2
|
-
ErrorCode,
|
|
3
2
|
invalidRequestError,
|
|
3
|
+
isConnectionClosedError,
|
|
4
4
|
methodNotFoundError,
|
|
5
|
-
ProtocolError,
|
|
6
5
|
propertyNotFoundError,
|
|
7
6
|
widgetNotFoundError,
|
|
8
7
|
} from "./protocol/errors.js";
|
|
@@ -11,7 +10,6 @@ export {
|
|
|
11
10
|
DEFAULT_SUBTREE_DEPTH,
|
|
12
11
|
MAX_SUBTREE_WIDGETS,
|
|
13
12
|
type ParamsSchema,
|
|
14
|
-
type Request,
|
|
15
13
|
type SerializedProperty,
|
|
16
14
|
type SerializedWidget,
|
|
17
15
|
type ServerInitiatedMethod,
|
|
@@ -19,3 +17,4 @@ export {
|
|
|
19
17
|
ServerRequestParamsSchemas,
|
|
20
18
|
} from "./protocol/schemas.js";
|
|
21
19
|
export { ProtocolConnection } from "./transport.js";
|
|
20
|
+
export type { JSONRPCRequest, Result } from "@modelcontextprotocol/sdk/types.js";
|
package/src/protocol/errors.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { McpError, ErrorCode as SdkErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
|
|
1
3
|
type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
2
4
|
|
|
3
5
|
const ErrorCode = {
|
|
@@ -12,6 +14,9 @@ const ErrorCode = {
|
|
|
12
14
|
PROPERTY_NOT_FOUND: 1008,
|
|
13
15
|
} as const;
|
|
14
16
|
|
|
17
|
+
const CONNECTION_CLOSED_CODE: number = SdkErrorCode.ConnectionClosed;
|
|
18
|
+
const REQUEST_TIMEOUT_CODE: number = SdkErrorCode.RequestTimeout;
|
|
19
|
+
|
|
15
20
|
function isErrorCode(code: number): code is ErrorCode {
|
|
16
21
|
return (Object.values(ErrorCode) as number[]).includes(code);
|
|
17
22
|
}
|
|
@@ -64,6 +69,17 @@ function methodNotFoundError(method: string): ProtocolError {
|
|
|
64
69
|
return new ProtocolError(ErrorCode.METHOD_NOT_FOUND, `Method '${method}' not found`, { method });
|
|
65
70
|
}
|
|
66
71
|
|
|
72
|
+
function isConnectionClosedError(value: unknown): boolean {
|
|
73
|
+
return value instanceof McpError && value.code === CONNECTION_CLOSED_CODE;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function protocolErrorFrom(error: McpError): ProtocolError {
|
|
77
|
+
const prefix = `MCP error ${String(error.code)}: `;
|
|
78
|
+
const message = error.message.startsWith(prefix) ? error.message.slice(prefix.length) : error.message;
|
|
79
|
+
|
|
80
|
+
return new ProtocolError(isErrorCode(error.code) ? error.code : ErrorCode.INTERNAL_ERROR, message, error.data);
|
|
81
|
+
}
|
|
82
|
+
|
|
67
83
|
class ProtocolError extends Error {
|
|
68
84
|
code: ErrorCode;
|
|
69
85
|
data?: unknown;
|
|
@@ -74,19 +90,12 @@ class ProtocolError extends Error {
|
|
|
74
90
|
this.data = data;
|
|
75
91
|
this.name = "ProtocolError";
|
|
76
92
|
}
|
|
77
|
-
|
|
78
|
-
toErrorObject(): { code: number; message: string; data?: unknown } {
|
|
79
|
-
return {
|
|
80
|
-
code: this.code,
|
|
81
|
-
message: this.message,
|
|
82
|
-
...(this.data !== undefined && { data: this.data }),
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
93
|
}
|
|
86
94
|
|
|
87
95
|
export {
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
CONNECTION_CLOSED_CODE,
|
|
97
|
+
isConnectionClosedError,
|
|
98
|
+
REQUEST_TIMEOUT_CODE,
|
|
90
99
|
noAppConnectedError,
|
|
91
100
|
appNotFoundError,
|
|
92
101
|
connectionWriteFailedError,
|
|
@@ -96,4 +105,5 @@ export {
|
|
|
96
105
|
invalidRequestError,
|
|
97
106
|
methodNotFoundError,
|
|
98
107
|
ProtocolError,
|
|
108
|
+
protocolErrorFrom,
|
|
99
109
|
};
|
package/src/protocol/schemas.ts
CHANGED
|
@@ -2,9 +2,6 @@ import { tmpdir } from "node:os";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
|
-
type Request = z.infer<typeof RequestSchema>;
|
|
6
|
-
type Response = z.infer<typeof ResponseSchema>;
|
|
7
|
-
|
|
8
5
|
type SerializedWidget = {
|
|
9
6
|
id: string;
|
|
10
7
|
type: string;
|
|
@@ -37,39 +34,6 @@ type ServerRequestParams<Method extends keyof typeof ServerRequestParamsSchemas>
|
|
|
37
34
|
|
|
38
35
|
type ParamsSchema<Output> = z.ZodType<Output>;
|
|
39
36
|
type ServerInitiatedMethod = keyof typeof ServerRequestParamsSchemas;
|
|
40
|
-
type Message = Request | Response;
|
|
41
|
-
|
|
42
|
-
const RequestSchema: z.ZodObject<
|
|
43
|
-
{
|
|
44
|
-
id: z.ZodString;
|
|
45
|
-
method: z.ZodString;
|
|
46
|
-
params: z.ZodOptional<z.ZodUnknown>;
|
|
47
|
-
}
|
|
48
|
-
> = z.object({
|
|
49
|
-
id: z.string(),
|
|
50
|
-
method: z.string(),
|
|
51
|
-
params: z.unknown().optional(),
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const ErrorSchema: z.ZodObject<
|
|
55
|
-
{ code: z.ZodNumber; message: z.ZodString; data: z.ZodOptional<z.ZodUnknown> }
|
|
56
|
-
> = z.object({
|
|
57
|
-
code: z.number(),
|
|
58
|
-
message: z.string(),
|
|
59
|
-
data: z.unknown().optional(),
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const ResponseSchema: z.ZodObject<
|
|
63
|
-
{
|
|
64
|
-
id: z.ZodString;
|
|
65
|
-
result: z.ZodOptional<z.ZodUnknown>;
|
|
66
|
-
error: z.ZodOptional<typeof ErrorSchema>;
|
|
67
|
-
}
|
|
68
|
-
> = z.object({
|
|
69
|
-
id: z.string(),
|
|
70
|
-
result: z.unknown().optional(),
|
|
71
|
-
error: ErrorSchema.optional(),
|
|
72
|
-
});
|
|
73
37
|
|
|
74
38
|
const RegisterParamsSchema: z.ZodObject<
|
|
75
39
|
{
|
|
@@ -175,8 +139,6 @@ function getRuntimeDir(): string {
|
|
|
175
139
|
export {
|
|
176
140
|
DEFAULT_SUBTREE_DEPTH,
|
|
177
141
|
MAX_SUBTREE_WIDGETS,
|
|
178
|
-
RequestSchema,
|
|
179
|
-
ResponseSchema,
|
|
180
142
|
RegisterParamsSchema,
|
|
181
143
|
widgetIdParams,
|
|
182
144
|
widgetPropsParams,
|
|
@@ -187,13 +149,10 @@ export {
|
|
|
187
149
|
screenshotParams,
|
|
188
150
|
ServerRequestParamsSchemas,
|
|
189
151
|
DEFAULT_SOCKET_PATH,
|
|
190
|
-
type Request,
|
|
191
|
-
type Response,
|
|
192
152
|
type SerializedWidget,
|
|
193
153
|
type SerializedProperty,
|
|
194
154
|
type AppInfo,
|
|
195
155
|
type ServerRequestParams,
|
|
196
156
|
type ParamsSchema,
|
|
197
157
|
type ServerInitiatedMethod,
|
|
198
|
-
type Message,
|
|
199
158
|
};
|
package/src/socket-server.ts
CHANGED
package/src/transport.ts
CHANGED
|
@@ -1,30 +1,36 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-empty-function -- the app link negotiates no MCP capabilities */
|
|
2
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
1
3
|
import type { Socket } from "node:net";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
type
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
};
|
|
4
|
+
import { normalizeError } from "@gtkx/utils";
|
|
5
|
+
import { Protocol } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
6
|
+
import { ReadBuffer, serializeMessage } from "@modelcontextprotocol/sdk/shared/stdio.js";
|
|
7
|
+
import {
|
|
8
|
+
ErrorCode,
|
|
9
|
+
type JSONRPCMessage,
|
|
10
|
+
type JSONRPCRequest,
|
|
11
|
+
McpError,
|
|
12
|
+
type Notification,
|
|
13
|
+
type Request,
|
|
14
|
+
type Result,
|
|
15
|
+
ResultSchema,
|
|
16
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
16
17
|
|
|
17
18
|
type ConnectionEvent = CustomEvent<ProtocolConnection>;
|
|
18
|
-
type ConnectionRequestEvent = CustomEvent<{ connection: ProtocolConnection; request: Request }>;
|
|
19
19
|
type ConnectionErrorEvent = CustomEvent<Error>;
|
|
20
|
+
type ConnectionRequestHandler = (connection: ProtocolConnection, request: JSONRPCRequest) => Promise<Result>;
|
|
21
|
+
type RequestParams = Request["params"];
|
|
22
|
+
|
|
23
|
+
type ConnectionOptions = {
|
|
24
|
+
onClose: () => void;
|
|
25
|
+
onError: (error: Error) => void;
|
|
26
|
+
};
|
|
20
27
|
|
|
21
28
|
type AppConnections = {
|
|
22
|
-
|
|
29
|
+
onRequest: ConnectionRequestHandler;
|
|
23
30
|
} & EventTarget;
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
32
|
+
const MAX_MESSAGE_BYTES = 64 * 1024 * 1024;
|
|
33
|
+
const MAX_PENDING_WRITE_BYTES = 8 * 1024 * 1024;
|
|
28
34
|
|
|
29
35
|
function connectionDisconnectionEvent(connection: ProtocolConnection): ConnectionEvent {
|
|
30
36
|
return new CustomEvent("disconnection", { detail: connection });
|
|
@@ -34,208 +40,137 @@ function connectionErrorEvent(error: Error): ConnectionErrorEvent {
|
|
|
34
40
|
return new CustomEvent("error", { detail: error });
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
class
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
this.name = "ConnectionClosedError";
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
class ProtocolConnection extends EventTarget {
|
|
45
|
-
static fromSocket(
|
|
46
|
-
socket: Socket,
|
|
47
|
-
options: {
|
|
48
|
-
onClose?: () => void;
|
|
49
|
-
onError?: (error: Error) => void;
|
|
50
|
-
} = {},
|
|
51
|
-
): ProtocolConnection {
|
|
52
|
-
const connection = new ProtocolConnection(socket);
|
|
53
|
-
|
|
54
|
-
socket.on("data", (data: Buffer) => {
|
|
55
|
-
connection.feed(data);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
socket.on("close", () => {
|
|
59
|
-
connection.rejectPending(new Error("Connection closed"));
|
|
60
|
-
options.onClose?.();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
if (options.onError) {
|
|
64
|
-
socket.on("error", options.onError);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return connection;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private buffer = "";
|
|
71
|
-
private pending: Map<string, PendingRequest> = new Map();
|
|
72
|
-
private writer: Duplex;
|
|
73
|
-
|
|
74
|
-
id: string = crypto.randomUUID();
|
|
75
|
-
|
|
76
|
-
constructor(writer: Duplex) {
|
|
77
|
-
super();
|
|
78
|
-
this.writer = writer;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
private notify<K extends keyof ProtocolConnectionEvents>(type: K, detail: ProtocolConnectionEvents[K]): void {
|
|
82
|
-
this.dispatchEvent(new CustomEvent(type, { detail }));
|
|
83
|
-
}
|
|
43
|
+
class SocketTransport implements Transport {
|
|
44
|
+
private readonly readBuffer: ReadBuffer = new ReadBuffer({ maxBufferSize: MAX_MESSAGE_BYTES });
|
|
45
|
+
private readonly socket: Socket;
|
|
84
46
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
47
|
+
onclose?: () => void;
|
|
48
|
+
onerror?: (error: Error) => void;
|
|
49
|
+
onmessage?: (message: JSONRPCMessage) => void;
|
|
89
50
|
|
|
90
|
-
|
|
91
|
-
this.
|
|
92
|
-
reject(new ConnectionClosedError());
|
|
51
|
+
constructor(socket: Socket) {
|
|
52
|
+
this.socket = socket;
|
|
93
53
|
}
|
|
94
54
|
|
|
95
|
-
private
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (typeof message.method === "string") {
|
|
99
|
-
const requestResult = RequestSchema.safeParse(parsed);
|
|
55
|
+
private read(): void {
|
|
56
|
+
for (;;) {
|
|
57
|
+
let message: JSONRPCMessage | null;
|
|
100
58
|
|
|
101
|
-
|
|
102
|
-
|
|
59
|
+
try {
|
|
60
|
+
message = this.readBuffer.readMessage();
|
|
61
|
+
} catch (error) {
|
|
62
|
+
this.onerror?.(normalizeError(error));
|
|
63
|
+
continue;
|
|
103
64
|
}
|
|
104
65
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const responseResult = ResponseSchema.safeParse(parsed);
|
|
66
|
+
if (message === null) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
111
69
|
|
|
112
|
-
|
|
113
|
-
return false;
|
|
70
|
+
this.onmessage?.(message);
|
|
114
71
|
}
|
|
72
|
+
}
|
|
115
73
|
|
|
116
|
-
|
|
74
|
+
private drop(reason: string): Promise<void> {
|
|
75
|
+
const error = new McpError(ErrorCode.ConnectionClosed, reason);
|
|
76
|
+
this.onerror?.(error);
|
|
77
|
+
this.socket.destroy();
|
|
117
78
|
|
|
118
|
-
return
|
|
79
|
+
return Promise.reject(error);
|
|
119
80
|
}
|
|
120
81
|
|
|
121
|
-
private
|
|
122
|
-
let parsed: unknown;
|
|
123
|
-
|
|
82
|
+
private receive(chunk: Buffer): void {
|
|
124
83
|
try {
|
|
125
|
-
|
|
126
|
-
} catch {
|
|
127
|
-
this.
|
|
128
|
-
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
84
|
+
this.readBuffer.append(chunk);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
this.onerror?.(normalizeError(error));
|
|
87
|
+
this.socket.destroy();
|
|
131
88
|
|
|
132
|
-
if (this.dispatchParsed(parsed)) {
|
|
133
89
|
return;
|
|
134
90
|
}
|
|
135
91
|
|
|
136
|
-
|
|
137
|
-
const id = typeof message.id === "string" ? message.id : "unknown";
|
|
138
|
-
this.notify("invalid", { id, error: invalidRequestError("Invalid message format") });
|
|
92
|
+
this.read();
|
|
139
93
|
}
|
|
140
94
|
|
|
141
|
-
|
|
142
|
-
|
|
95
|
+
start(): Promise<void> {
|
|
96
|
+
this.socket.on("data", (chunk: Buffer) => {
|
|
97
|
+
this.receive(chunk);
|
|
98
|
+
});
|
|
143
99
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
100
|
+
this.socket.on("close", () => {
|
|
101
|
+
this.onclose?.();
|
|
102
|
+
});
|
|
147
103
|
|
|
148
|
-
|
|
149
|
-
|
|
104
|
+
this.socket.on("error", (error) => {
|
|
105
|
+
this.onerror?.(error);
|
|
106
|
+
});
|
|
150
107
|
|
|
151
|
-
|
|
152
|
-
|
|
108
|
+
return Promise.resolve();
|
|
109
|
+
}
|
|
153
110
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
);
|
|
157
|
-
} else {
|
|
158
|
-
entry.resolve(response.result);
|
|
111
|
+
send(message: JSONRPCMessage): Promise<void> {
|
|
112
|
+
if (!this.socket.writable) {
|
|
113
|
+
return Promise.reject(new McpError(ErrorCode.ConnectionClosed, "Connection stream is not writable"));
|
|
159
114
|
}
|
|
160
|
-
}
|
|
161
115
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
): void {
|
|
166
|
-
this.addEventListener(type, (event) => {
|
|
167
|
-
listener((event as CustomEvent<ProtocolConnectionEvents[K]>).detail);
|
|
168
|
-
});
|
|
169
|
-
}
|
|
116
|
+
if (this.socket.writableLength > MAX_PENDING_WRITE_BYTES) {
|
|
117
|
+
return this.drop("Connection stream is not draining");
|
|
118
|
+
}
|
|
170
119
|
|
|
171
|
-
|
|
172
|
-
this.buffer += typeof data === "string" ? data : data.toString();
|
|
173
|
-
let newlineIndex = this.buffer.indexOf("\n");
|
|
120
|
+
this.socket.write(serializeMessage(message));
|
|
174
121
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
this.buffer = this.buffer.slice(newlineIndex + 1);
|
|
122
|
+
return Promise.resolve();
|
|
123
|
+
}
|
|
178
124
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
125
|
+
close(): Promise<void> {
|
|
126
|
+
this.socket.destroy();
|
|
182
127
|
|
|
183
|
-
|
|
184
|
-
}
|
|
128
|
+
return Promise.resolve();
|
|
185
129
|
}
|
|
130
|
+
}
|
|
186
131
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
132
|
+
class ProtocolConnection extends Protocol<Request, Notification, Result> {
|
|
133
|
+
static fromSocket(socket: Socket, options: ConnectionOptions): ProtocolConnection {
|
|
134
|
+
const connection = Object.assign(new ProtocolConnection(), {
|
|
135
|
+
onclose: options.onClose,
|
|
136
|
+
onerror: options.onError,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
void connection.connect(new SocketTransport(socket));
|
|
191
140
|
|
|
192
|
-
|
|
141
|
+
return connection;
|
|
193
142
|
}
|
|
194
143
|
|
|
195
|
-
|
|
196
|
-
return new Promise<T>((resolve, reject) => {
|
|
197
|
-
if (!this.writer.writable) {
|
|
198
|
-
reject(new ConnectionClosedError());
|
|
144
|
+
id: string = crypto.randomUUID();
|
|
199
145
|
|
|
200
|
-
|
|
201
|
-
}
|
|
146
|
+
protected assertCapabilityForMethod(): void {}
|
|
202
147
|
|
|
203
|
-
|
|
148
|
+
protected assertNotificationCapability(): void {}
|
|
204
149
|
|
|
205
|
-
|
|
206
|
-
this.pending.delete(id);
|
|
207
|
-
reject(requestTimeoutError(timeout));
|
|
208
|
-
}, timeout);
|
|
150
|
+
protected assertRequestHandlerCapability(): void {}
|
|
209
151
|
|
|
210
|
-
|
|
211
|
-
resolve: resolve as (result: unknown) => void,
|
|
212
|
-
reject,
|
|
213
|
-
timeout: timeoutHandle,
|
|
214
|
-
});
|
|
152
|
+
protected assertTaskCapability(): void {}
|
|
215
153
|
|
|
216
|
-
|
|
217
|
-
this.rejectWhenClosed(id, timeoutHandle, reject);
|
|
218
|
-
});
|
|
219
|
-
}
|
|
154
|
+
protected assertTaskHandlerCapability(): void {}
|
|
220
155
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
156
|
+
async send<T>(method: string, params?: RequestParams, timeout?: number): Promise<T> {
|
|
157
|
+
const result = await this.request(
|
|
158
|
+
{ method, ...(params !== undefined && { params }) },
|
|
159
|
+
ResultSchema,
|
|
160
|
+
{ ...(timeout !== undefined && { timeout }) },
|
|
161
|
+
);
|
|
226
162
|
|
|
227
|
-
|
|
163
|
+
return result as T;
|
|
228
164
|
}
|
|
229
165
|
}
|
|
230
166
|
|
|
231
167
|
export {
|
|
232
|
-
ConnectionClosedError,
|
|
233
168
|
connectionDisconnectionEvent,
|
|
234
169
|
connectionErrorEvent,
|
|
235
|
-
connectionRequestEvent,
|
|
236
170
|
ProtocolConnection,
|
|
237
171
|
type AppConnections,
|
|
238
172
|
type ConnectionEvent,
|
|
239
173
|
type ConnectionErrorEvent,
|
|
240
|
-
type
|
|
174
|
+
type ConnectionRequestHandler,
|
|
175
|
+
type RequestParams,
|
|
241
176
|
};
|