@lspeasy/client 3.0.0 → 3.0.2
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.
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Capability validation for client requests
|
|
3
3
|
*
|
|
4
|
-
* Ensures clients only send requests/notifications that the server supports
|
|
4
|
+
* Ensures clients only send requests/notifications that the server supports,
|
|
5
|
+
* and only register handlers for methods the client declared support for.
|
|
5
6
|
*/
|
|
6
7
|
import type { ClientCapabilities, ServerCapabilities } from '@lspeasy/core';
|
|
7
8
|
import type { Logger } from '@lspeasy/core';
|
|
@@ -14,25 +15,8 @@ export declare class CapabilityGuard {
|
|
|
14
15
|
private readonly logger;
|
|
15
16
|
private readonly strict;
|
|
16
17
|
constructor(capabilities: Partial<ServerCapabilities>, logger: Logger, strict?: boolean);
|
|
17
|
-
/**
|
|
18
|
-
* Check if a request can be sent to the server
|
|
19
|
-
*
|
|
20
|
-
* @param method - LSP method name
|
|
21
|
-
* @returns true if allowed, false otherwise
|
|
22
|
-
* @throws Error if strict mode enabled and server capability not declared
|
|
23
|
-
*/
|
|
24
18
|
canSendRequest(method: string): boolean;
|
|
25
|
-
/**
|
|
26
|
-
* Check if a notification can be sent to the server
|
|
27
|
-
*
|
|
28
|
-
* @param method - LSP method name
|
|
29
|
-
* @returns true if allowed, false otherwise
|
|
30
|
-
* @throws Error if strict mode enabled and server capability not declared
|
|
31
|
-
*/
|
|
32
19
|
canSendNotification(method: string): boolean;
|
|
33
|
-
/**
|
|
34
|
-
* Get list of capabilities the server declared
|
|
35
|
-
*/
|
|
36
20
|
getServerCapabilities(): Partial<ServerCapabilities>;
|
|
37
21
|
}
|
|
38
22
|
/**
|
|
@@ -44,19 +28,7 @@ export declare class ClientCapabilityGuard {
|
|
|
44
28
|
private readonly logger;
|
|
45
29
|
private readonly strict;
|
|
46
30
|
constructor(capabilities: Partial<ClientCapabilities>, logger: Logger, strict?: boolean);
|
|
47
|
-
/**
|
|
48
|
-
* Check if handler registration is allowed for this method
|
|
49
|
-
*
|
|
50
|
-
* @param method - LSP method name
|
|
51
|
-
* @returns true if allowed, false otherwise
|
|
52
|
-
* @throws Error if strict mode enabled and client capability not declared
|
|
53
|
-
*/
|
|
54
31
|
canRegisterHandler(method: string): boolean;
|
|
55
|
-
/**
|
|
56
|
-
* Get list of capabilities the client declared
|
|
57
|
-
*/
|
|
58
32
|
getClientCapabilities(): Partial<ClientCapabilities>;
|
|
59
|
-
private isRequestAllowed;
|
|
60
|
-
private isNotificationAllowed;
|
|
61
33
|
}
|
|
62
34
|
//# sourceMappingURL=capability-guard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capability-guard.d.ts","sourceRoot":"","sources":["../src/capability-guard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"capability-guard.d.ts","sourceRoot":"","sources":["../src/capability-guard.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAa5C;;;GAGG;AACH,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHzB,YACmB,YAAY,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACzC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,OAAe,EACtC;IAEJ,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAWtC;IAED,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAW3C;IAED,qBAAqB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAEnD;CACF;AAED;;;GAGG;AACH,qBAAa,qBAAqB;IAE9B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHzB,YACmB,YAAY,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACzC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,OAAe,EACtC;IAEJ,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAgB1C;IAED,qBAAqB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAEnD;CACF"}
|
package/dist/capability-guard.js
CHANGED
|
@@ -1,34 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Capability validation for client requests
|
|
3
3
|
*
|
|
4
|
-
* Ensures clients only send requests/notifications that the server supports
|
|
4
|
+
* Ensures clients only send requests/notifications that the server supports,
|
|
5
|
+
* and only register handlers for methods the client declared support for.
|
|
5
6
|
*/
|
|
6
|
-
import {
|
|
7
|
-
function buildMethodSets(capabilityKey) {
|
|
8
|
-
const all = new Set();
|
|
9
|
-
const alwaysAllowed = new Set();
|
|
10
|
-
for (const namespaceDefinitions of Object.values(LSPRequest)) {
|
|
11
|
-
for (const definition of Object.values(namespaceDefinitions)) {
|
|
12
|
-
const entry = definition;
|
|
13
|
-
all.add(entry.Method);
|
|
14
|
-
if (!entry[capabilityKey]) {
|
|
15
|
-
alwaysAllowed.add(entry.Method);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
for (const namespaceDefinitions of Object.values(LSPNotification)) {
|
|
20
|
-
for (const definition of Object.values(namespaceDefinitions)) {
|
|
21
|
-
const entry = definition;
|
|
22
|
-
all.add(entry.Method);
|
|
23
|
-
if (!entry[capabilityKey]) {
|
|
24
|
-
alwaysAllowed.add(entry.Method);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return { all, alwaysAllowed };
|
|
29
|
-
}
|
|
30
|
-
const SERVER_METHODS = buildMethodSets('ServerCapability');
|
|
31
|
-
const CLIENT_METHODS = buildMethodSets('ClientCapability');
|
|
7
|
+
import { SERVER_METHODS, CLIENT_METHODS, checkMethod, getClientCapabilityForNotificationMethod, getClientCapabilityForRequestMethod, hasServerCapability, hasClientCapability, getCapabilityForNotificationMethod, getCapabilityForRequestMethod } from '@lspeasy/core';
|
|
32
8
|
/**
|
|
33
9
|
* Validates that a request/notification can be sent based on
|
|
34
10
|
* declared server capabilities
|
|
@@ -42,103 +18,30 @@ export class CapabilityGuard {
|
|
|
42
18
|
this.logger = logger;
|
|
43
19
|
this.strict = strict;
|
|
44
20
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Check if a request can be sent to the server
|
|
47
|
-
*
|
|
48
|
-
* @param method - LSP method name
|
|
49
|
-
* @returns true if allowed, false otherwise
|
|
50
|
-
* @throws Error if strict mode enabled and server capability not declared
|
|
51
|
-
*/
|
|
52
21
|
canSendRequest(method) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
// Check if server supports this request method
|
|
66
|
-
const capabilityKey = getCapabilityForRequestMethod(method);
|
|
67
|
-
if (!capabilityKey) {
|
|
68
|
-
// Unknown method - allow in non-strict mode with warning
|
|
69
|
-
if (!this.strict) {
|
|
70
|
-
this.logger.debug(`Unknown request method ${method}, allowing in non-strict mode`);
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
const error = `Cannot send request for unknown method: ${method}`;
|
|
74
|
-
this.logger.error(error);
|
|
75
|
-
throw new Error(error);
|
|
76
|
-
}
|
|
77
|
-
// Methods marked as 'alwaysOn' don't require explicit capabilities
|
|
78
|
-
if (capabilityKey === 'alwaysOn') {
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
// Check if server declared this capability
|
|
82
|
-
if (!hasServerCapability(this.capabilities, capabilityKey)) {
|
|
83
|
-
const error = `Cannot send request ${method}: server capability '${capabilityKey}' not declared`;
|
|
84
|
-
this.logger.warn(error);
|
|
85
|
-
if (this.strict) {
|
|
86
|
-
throw new Error(error);
|
|
87
|
-
}
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
return true;
|
|
22
|
+
return checkMethod({
|
|
23
|
+
method,
|
|
24
|
+
methodSets: SERVER_METHODS,
|
|
25
|
+
getCapabilityKey: (m) => getCapabilityForRequestMethod(m),
|
|
26
|
+
hasCapability: (key) => hasServerCapability(this.capabilities, key),
|
|
27
|
+
actionLabel: 'send request',
|
|
28
|
+
capabilityLabel: 'server capability',
|
|
29
|
+
logger: this.logger,
|
|
30
|
+
strict: this.strict
|
|
31
|
+
});
|
|
91
32
|
}
|
|
92
|
-
/**
|
|
93
|
-
* Check if a notification can be sent to the server
|
|
94
|
-
*
|
|
95
|
-
* @param method - LSP method name
|
|
96
|
-
* @returns true if allowed, false otherwise
|
|
97
|
-
* @throws Error if strict mode enabled and server capability not declared
|
|
98
|
-
*/
|
|
99
33
|
canSendNotification(method) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
// Check if server supports this notification method
|
|
113
|
-
const capabilityKey = getCapabilityForNotificationMethod(method);
|
|
114
|
-
if (!capabilityKey) {
|
|
115
|
-
// Unknown method - allow in non-strict mode with warning
|
|
116
|
-
if (!this.strict) {
|
|
117
|
-
this.logger.debug(`Unknown notification method ${method}, allowing in non-strict mode`);
|
|
118
|
-
return true;
|
|
119
|
-
}
|
|
120
|
-
const error = `Cannot send notification for unknown method: ${method}`;
|
|
121
|
-
this.logger.error(error);
|
|
122
|
-
throw new Error(error);
|
|
123
|
-
}
|
|
124
|
-
// Methods marked as 'alwaysOn' don't require explicit capabilities
|
|
125
|
-
if (capabilityKey === 'alwaysOn') {
|
|
126
|
-
return true;
|
|
127
|
-
}
|
|
128
|
-
// Check if server declared this capability
|
|
129
|
-
if (!hasServerCapability(this.capabilities, capabilityKey)) {
|
|
130
|
-
const error = `Cannot send notification ${method}: server capability '${capabilityKey}' not declared`;
|
|
131
|
-
this.logger.warn(error);
|
|
132
|
-
if (this.strict) {
|
|
133
|
-
throw new Error(error);
|
|
134
|
-
}
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
return true;
|
|
34
|
+
return checkMethod({
|
|
35
|
+
method,
|
|
36
|
+
methodSets: SERVER_METHODS,
|
|
37
|
+
getCapabilityKey: (m) => getCapabilityForNotificationMethod(m),
|
|
38
|
+
hasCapability: (key) => hasServerCapability(this.capabilities, key),
|
|
39
|
+
actionLabel: 'send notification',
|
|
40
|
+
capabilityLabel: 'server capability',
|
|
41
|
+
logger: this.logger,
|
|
42
|
+
strict: this.strict
|
|
43
|
+
});
|
|
138
44
|
}
|
|
139
|
-
/**
|
|
140
|
-
* Get list of capabilities the server declared
|
|
141
|
-
*/
|
|
142
45
|
getServerCapabilities() {
|
|
143
46
|
return { ...this.capabilities };
|
|
144
47
|
}
|
|
@@ -156,75 +59,23 @@ export class ClientCapabilityGuard {
|
|
|
156
59
|
this.logger = logger;
|
|
157
60
|
this.strict = strict;
|
|
158
61
|
}
|
|
159
|
-
/**
|
|
160
|
-
* Check if handler registration is allowed for this method
|
|
161
|
-
*
|
|
162
|
-
* @param method - LSP method name
|
|
163
|
-
* @returns true if allowed, false otherwise
|
|
164
|
-
* @throws Error if strict mode enabled and client capability not declared
|
|
165
|
-
*/
|
|
166
62
|
canRegisterHandler(method) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (!capabilityKey) {
|
|
181
|
-
const notificationCapability = getClientCapabilityForNotificationMethod(method);
|
|
182
|
-
if (!notificationCapability) {
|
|
183
|
-
if (!this.strict) {
|
|
184
|
-
this.logger.debug(`Unknown method ${method}, allowing in non-strict mode`);
|
|
185
|
-
return true;
|
|
186
|
-
}
|
|
187
|
-
const error = `Cannot register handler for unknown method: ${method}`;
|
|
188
|
-
this.logger.error(error);
|
|
189
|
-
throw new Error(error);
|
|
190
|
-
}
|
|
191
|
-
return this.isNotificationAllowed(method, notificationCapability);
|
|
192
|
-
}
|
|
193
|
-
return this.isRequestAllowed(method, capabilityKey);
|
|
63
|
+
return checkMethod({
|
|
64
|
+
method,
|
|
65
|
+
methodSets: CLIENT_METHODS,
|
|
66
|
+
getCapabilityKey: (m) => {
|
|
67
|
+
return (getClientCapabilityForRequestMethod(m) ??
|
|
68
|
+
getClientCapabilityForNotificationMethod(m));
|
|
69
|
+
},
|
|
70
|
+
hasCapability: (key) => hasClientCapability(this.capabilities, key),
|
|
71
|
+
actionLabel: 'register handler',
|
|
72
|
+
capabilityLabel: 'client capability',
|
|
73
|
+
logger: this.logger,
|
|
74
|
+
strict: this.strict
|
|
75
|
+
});
|
|
194
76
|
}
|
|
195
|
-
/**
|
|
196
|
-
* Get list of capabilities the client declared
|
|
197
|
-
*/
|
|
198
77
|
getClientCapabilities() {
|
|
199
78
|
return { ...this.capabilities };
|
|
200
79
|
}
|
|
201
|
-
isRequestAllowed(method, capabilityKey) {
|
|
202
|
-
if (capabilityKey === 'alwaysOn') {
|
|
203
|
-
return true;
|
|
204
|
-
}
|
|
205
|
-
if (!hasClientCapability(this.capabilities, capabilityKey)) {
|
|
206
|
-
const error = `Cannot register handler for ${method}: client capability '${capabilityKey}' not declared`;
|
|
207
|
-
this.logger.warn(error);
|
|
208
|
-
if (this.strict) {
|
|
209
|
-
throw new Error(error);
|
|
210
|
-
}
|
|
211
|
-
return false;
|
|
212
|
-
}
|
|
213
|
-
return true;
|
|
214
|
-
}
|
|
215
|
-
isNotificationAllowed(method, capabilityKey) {
|
|
216
|
-
if (capabilityKey === 'alwaysOn') {
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
219
|
-
if (!hasClientCapability(this.capabilities, capabilityKey)) {
|
|
220
|
-
const error = `Cannot register handler for ${method}: client capability '${capabilityKey}' not declared`;
|
|
221
|
-
this.logger.warn(error);
|
|
222
|
-
if (this.strict) {
|
|
223
|
-
throw new Error(error);
|
|
224
|
-
}
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
return true;
|
|
228
|
-
}
|
|
229
80
|
}
|
|
230
81
|
//# sourceMappingURL=capability-guard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capability-guard.js","sourceRoot":"","sources":["../src/capability-guard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"capability-guard.js","sourceRoot":"","sources":["../src/capability-guard.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EACL,cAAc,EACd,cAAc,EACd,WAAW,EACX,wCAAwC,EACxC,mCAAmC,EACnC,mBAAmB,EACnB,mBAAmB,EACnB,kCAAkC,EAClC,6BAA6B,EAC9B,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,MAAM,OAAO,eAAe;IAEP,YAAY;IACZ,MAAM;IACN,MAAM;IAHzB,YACmB,YAAyC,EACzC,MAAc,EACd,MAAM,GAAY,KAAK,EACxC;4BAHiB,YAAY;sBACZ,MAAM;sBACN,MAAM;IACtB,CAAC;IAEJ,cAAc,CAAC,MAAc,EAAW;QACtC,OAAO,WAAW,CAAC;YACjB,MAAM;YACN,UAAU,EAAE,cAAc;YAC1B,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,6BAA6B,CAAC,CAAQ,CAAC;YAChE,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,YAAY,EAAE,GAAU,CAAC;YAC1E,WAAW,EAAE,cAAc;YAC3B,eAAe,EAAE,mBAAmB;YACpC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;IAAA,CACJ;IAED,mBAAmB,CAAC,MAAc,EAAW;QAC3C,OAAO,WAAW,CAAC;YACjB,MAAM;YACN,UAAU,EAAE,cAAc;YAC1B,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,kCAAkC,CAAC,CAAQ,CAAC;YACrE,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,YAAY,EAAE,GAAU,CAAC;YAC1E,WAAW,EAAE,mBAAmB;YAChC,eAAe,EAAE,mBAAmB;YACpC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;IAAA,CACJ;IAED,qBAAqB,GAAgC;QACnD,OAAO,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;IAAA,CACjC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,qBAAqB;IAEb,YAAY;IACZ,MAAM;IACN,MAAM;IAHzB,YACmB,YAAyC,EACzC,MAAc,EACd,MAAM,GAAY,KAAK,EACxC;4BAHiB,YAAY;sBACZ,MAAM;sBACN,MAAM;IACtB,CAAC;IAEJ,kBAAkB,CAAC,MAAc,EAAW;QAC1C,OAAO,WAAW,CAAC;YACjB,MAAM;YACN,UAAU,EAAE,cAAc;YAC1B,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;gBACvB,OAAO,CACL,mCAAmC,CAAC,CAAQ,CAAC;oBAC7C,wCAAwC,CAAC,CAAQ,CAAC,CACnD,CAAC;YAAA,CACH;YACD,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,YAAY,EAAE,GAAU,CAAC;YAC1E,WAAW,EAAE,kBAAkB;YAC/B,eAAe,EAAE,mBAAmB;YACpC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;IAAA,CACJ;IAED,qBAAqB,GAAgC;QACnD,OAAO,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;IAAA,CACjC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lspeasy/client",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Connect to LSP servers with typed client API",
|
|
5
|
+
"private": false,
|
|
5
6
|
"keywords": [
|
|
6
7
|
"lsp",
|
|
7
8
|
"language-server-protocol",
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
"access": "public"
|
|
37
38
|
},
|
|
38
39
|
"dependencies": {
|
|
39
|
-
"@lspeasy/core": "2.1.
|
|
40
|
+
"@lspeasy/core": "2.1.2"
|
|
40
41
|
},
|
|
41
42
|
"optionalDependencies": {
|
|
42
43
|
"zod": "^4.3.6"
|
|
@@ -51,7 +52,7 @@
|
|
|
51
52
|
},
|
|
52
53
|
"scripts": {
|
|
53
54
|
"build": "tsgo --build",
|
|
54
|
-
"clean": "rm -rf dist
|
|
55
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
55
56
|
"dev": "tsgo --build --watch",
|
|
56
57
|
"type-check": "tsgo --noEmit"
|
|
57
58
|
}
|