@lspeasy/core 1.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.
Files changed (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +550 -0
  3. package/dist/index.d.ts +44 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +32 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/jsonrpc/framing.d.ts +32 -0
  8. package/dist/jsonrpc/framing.d.ts.map +1 -0
  9. package/dist/jsonrpc/framing.js +96 -0
  10. package/dist/jsonrpc/framing.js.map +1 -0
  11. package/dist/jsonrpc/messages.d.ts +64 -0
  12. package/dist/jsonrpc/messages.d.ts.map +1 -0
  13. package/dist/jsonrpc/messages.js +23 -0
  14. package/dist/jsonrpc/messages.js.map +1 -0
  15. package/dist/jsonrpc/reader.d.ts +44 -0
  16. package/dist/jsonrpc/reader.d.ts.map +1 -0
  17. package/dist/jsonrpc/reader.js +107 -0
  18. package/dist/jsonrpc/reader.js.map +1 -0
  19. package/dist/jsonrpc/schemas.d.ts +103 -0
  20. package/dist/jsonrpc/schemas.d.ts.map +1 -0
  21. package/dist/jsonrpc/schemas.js +66 -0
  22. package/dist/jsonrpc/schemas.js.map +1 -0
  23. package/dist/jsonrpc/writer.d.ts +43 -0
  24. package/dist/jsonrpc/writer.d.ts.map +1 -0
  25. package/dist/jsonrpc/writer.js +110 -0
  26. package/dist/jsonrpc/writer.js.map +1 -0
  27. package/dist/middleware/compose.d.ts +3 -0
  28. package/dist/middleware/compose.d.ts.map +1 -0
  29. package/dist/middleware/compose.js +16 -0
  30. package/dist/middleware/compose.js.map +1 -0
  31. package/dist/middleware/index.d.ts +6 -0
  32. package/dist/middleware/index.d.ts.map +1 -0
  33. package/dist/middleware/index.js +5 -0
  34. package/dist/middleware/index.js.map +1 -0
  35. package/dist/middleware/pipeline.d.ts +5 -0
  36. package/dist/middleware/pipeline.d.ts.map +1 -0
  37. package/dist/middleware/pipeline.js +54 -0
  38. package/dist/middleware/pipeline.js.map +1 -0
  39. package/dist/middleware/scoped.d.ts +9 -0
  40. package/dist/middleware/scoped.d.ts.map +1 -0
  41. package/dist/middleware/scoped.js +20 -0
  42. package/dist/middleware/scoped.js.map +1 -0
  43. package/dist/middleware/typed.d.ts +3 -0
  44. package/dist/middleware/typed.d.ts.map +1 -0
  45. package/dist/middleware/typed.js +18 -0
  46. package/dist/middleware/typed.js.map +1 -0
  47. package/dist/middleware/types.d.ts +45 -0
  48. package/dist/middleware/types.d.ts.map +1 -0
  49. package/dist/middleware/types.js +2 -0
  50. package/dist/middleware/types.js.map +1 -0
  51. package/dist/protocol/capabilities.d.ts +93 -0
  52. package/dist/protocol/capabilities.d.ts.map +1 -0
  53. package/dist/protocol/capabilities.js +143 -0
  54. package/dist/protocol/capabilities.js.map +1 -0
  55. package/dist/protocol/capability-methods.d.ts +270 -0
  56. package/dist/protocol/capability-methods.d.ts.map +1 -0
  57. package/dist/protocol/capability-methods.js +14 -0
  58. package/dist/protocol/capability-methods.js.map +1 -0
  59. package/dist/protocol/enums.d.ts +336 -0
  60. package/dist/protocol/enums.d.ts.map +1 -0
  61. package/dist/protocol/enums.js +417 -0
  62. package/dist/protocol/enums.js.map +1 -0
  63. package/dist/protocol/infer.d.ts +112 -0
  64. package/dist/protocol/infer.d.ts.map +1 -0
  65. package/dist/protocol/infer.js +58 -0
  66. package/dist/protocol/infer.js.map +1 -0
  67. package/dist/protocol/namespaces.d.ts +1432 -0
  68. package/dist/protocol/namespaces.d.ts.map +1 -0
  69. package/dist/protocol/namespaces.js +570 -0
  70. package/dist/protocol/namespaces.js.map +1 -0
  71. package/dist/protocol/partial.d.ts +29 -0
  72. package/dist/protocol/partial.d.ts.map +1 -0
  73. package/dist/protocol/partial.js +24 -0
  74. package/dist/protocol/partial.js.map +1 -0
  75. package/dist/protocol/progress.d.ts +32 -0
  76. package/dist/protocol/progress.d.ts.map +1 -0
  77. package/dist/protocol/progress.js +60 -0
  78. package/dist/protocol/progress.js.map +1 -0
  79. package/dist/protocol/schemas.d.ts +534 -0
  80. package/dist/protocol/schemas.d.ts.map +1 -0
  81. package/dist/protocol/schemas.js +271 -0
  82. package/dist/protocol/schemas.js.map +1 -0
  83. package/dist/protocol/types.d.ts +19 -0
  84. package/dist/protocol/types.d.ts.map +1 -0
  85. package/dist/protocol/types.js +8 -0
  86. package/dist/protocol/types.js.map +1 -0
  87. package/dist/protocol/watching.d.ts +29 -0
  88. package/dist/protocol/watching.d.ts.map +1 -0
  89. package/dist/protocol/watching.js +36 -0
  90. package/dist/protocol/watching.js.map +1 -0
  91. package/dist/protocol/workspace.d.ts +24 -0
  92. package/dist/protocol/workspace.d.ts.map +1 -0
  93. package/dist/protocol/workspace.js +26 -0
  94. package/dist/protocol/workspace.js.map +1 -0
  95. package/dist/transport/events.d.ts +27 -0
  96. package/dist/transport/events.d.ts.map +1 -0
  97. package/dist/transport/events.js +34 -0
  98. package/dist/transport/events.js.map +1 -0
  99. package/dist/transport/stdio.d.ts +55 -0
  100. package/dist/transport/stdio.d.ts.map +1 -0
  101. package/dist/transport/stdio.js +147 -0
  102. package/dist/transport/stdio.js.map +1 -0
  103. package/dist/transport/transport.d.ts +38 -0
  104. package/dist/transport/transport.d.ts.map +1 -0
  105. package/dist/transport/transport.js +5 -0
  106. package/dist/transport/transport.js.map +1 -0
  107. package/dist/transport/websocket.d.ts +142 -0
  108. package/dist/transport/websocket.d.ts.map +1 -0
  109. package/dist/transport/websocket.js +324 -0
  110. package/dist/transport/websocket.js.map +1 -0
  111. package/dist/utils/cancellation.d.ts +47 -0
  112. package/dist/utils/cancellation.d.ts.map +1 -0
  113. package/dist/utils/cancellation.js +77 -0
  114. package/dist/utils/cancellation.js.map +1 -0
  115. package/dist/utils/disposable-event-emitter.d.ts +26 -0
  116. package/dist/utils/disposable-event-emitter.d.ts.map +1 -0
  117. package/dist/utils/disposable-event-emitter.js +62 -0
  118. package/dist/utils/disposable-event-emitter.js.map +1 -0
  119. package/dist/utils/disposable.d.ts +34 -0
  120. package/dist/utils/disposable.d.ts.map +1 -0
  121. package/dist/utils/disposable.js +55 -0
  122. package/dist/utils/disposable.js.map +1 -0
  123. package/dist/utils/document.d.ts +20 -0
  124. package/dist/utils/document.d.ts.map +1 -0
  125. package/dist/utils/document.js +54 -0
  126. package/dist/utils/document.js.map +1 -0
  127. package/dist/utils/errors.d.ts +69 -0
  128. package/dist/utils/errors.d.ts.map +1 -0
  129. package/dist/utils/errors.js +104 -0
  130. package/dist/utils/errors.js.map +1 -0
  131. package/dist/utils/handler-registry.d.ts +35 -0
  132. package/dist/utils/handler-registry.d.ts.map +1 -0
  133. package/dist/utils/handler-registry.js +68 -0
  134. package/dist/utils/handler-registry.js.map +1 -0
  135. package/dist/utils/index.d.ts +5 -0
  136. package/dist/utils/index.d.ts.map +1 -0
  137. package/dist/utils/index.js +4 -0
  138. package/dist/utils/index.js.map +1 -0
  139. package/dist/utils/internal.d.ts +3 -0
  140. package/dist/utils/internal.d.ts.map +1 -0
  141. package/dist/utils/internal.js +3 -0
  142. package/dist/utils/internal.js.map +1 -0
  143. package/dist/utils/logger.d.ts +47 -0
  144. package/dist/utils/logger.d.ts.map +1 -0
  145. package/dist/utils/logger.js +61 -0
  146. package/dist/utils/logger.js.map +1 -0
  147. package/dist/utils/pending-request-tracker.d.ts +36 -0
  148. package/dist/utils/pending-request-tracker.d.ts.map +1 -0
  149. package/dist/utils/pending-request-tracker.js +93 -0
  150. package/dist/utils/pending-request-tracker.js.map +1 -0
  151. package/dist/utils/transport-attachment.d.ts +34 -0
  152. package/dist/utils/transport-attachment.d.ts.map +1 -0
  153. package/dist/utils/transport-attachment.js +48 -0
  154. package/dist/utils/transport-attachment.js.map +1 -0
  155. package/package.json +87 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Pradeep Mouli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,550 @@
1
+ # @lspeasy/core
2
+
3
+ Core transport layer and utilities for the lspeasy Language Server Protocol SDK.
4
+
5
+ ## Overview
6
+
7
+ `@lspeasy/core` provides the foundational building blocks for LSP communication:
8
+
9
+ - **Transport Interface**: Abstract transport layer for message exchange
10
+ - **StdioTransport**: Standard input/output transport implementation
11
+ - **WebSocketTransport**: WebSocket transport with automatic reconnection
12
+ - **Middleware Pipeline**: Composable JSON-RPC interception with method scoping and typing
13
+ - **JSON-RPC 2.0**: Message framing, parsing, and serialization
14
+ - **Type-Safe Enums**: Enums for all LSP kind types with extensibility support
15
+ - **Cancellation**: Token-based cancellation support
16
+ - **Utilities**: Event emitters, disposables, logging, and document sync helpers
17
+
18
+ ## Middleware API
19
+
20
+ Middleware is exported from `@lspeasy/core/middleware`.
21
+
22
+ ```typescript
23
+ import {
24
+ composeMiddleware,
25
+ createScopedMiddleware,
26
+ createTypedMiddleware,
27
+ type Middleware
28
+ } from '@lspeasy/core/middleware';
29
+
30
+ const logging: Middleware = async (context, next) => {
31
+ console.log(`${context.direction} ${context.messageType} ${context.method}`);
32
+ await next();
33
+ };
34
+
35
+ const scoped = createScopedMiddleware(
36
+ { methods: /^textDocument\//, direction: 'clientToServer', messageType: ['request'] },
37
+ async (context, next) => {
38
+ context.metadata.startedAt = Date.now();
39
+ await next();
40
+ }
41
+ );
42
+
43
+ const typed = createTypedMiddleware('textDocument/hover', async (context, next) => {
44
+ console.log(context.params?.position);
45
+ await next();
46
+ });
47
+
48
+ export const middleware = composeMiddleware(logging, scoped, typed);
49
+ ```
50
+
51
+ ## Native WebSocket Support
52
+
53
+ - `createWebSocketClient()` and `WebSocketTransport` use native `globalThis.WebSocket` when available.
54
+ - Node.js `>= 22.4` is recommended for native WebSocket client support.
55
+ - For older Node.js versions, install `ws` as an optional peer dependency.
56
+ - WebSocket server mode (`WebSocketServer`) still requires `ws`.
57
+
58
+ ## Document Change Helpers
59
+
60
+ Use document helpers from `@lspeasy/core/utils` to create typed didChange payloads.
61
+
62
+ ```typescript
63
+ import {
64
+ DocumentVersionTracker,
65
+ createIncrementalDidChangeParams,
66
+ createFullDidChangeParams
67
+ } from '@lspeasy/core/utils';
68
+
69
+ const tracker = new DocumentVersionTracker();
70
+ tracker.open('file:///demo.ts', 0);
71
+
72
+ const incremental = createIncrementalDidChangeParams(
73
+ 'file:///demo.ts',
74
+ [
75
+ {
76
+ range: {
77
+ start: { line: 0, character: 0 },
78
+ end: { line: 0, character: 5 }
79
+ },
80
+ text: 'const'
81
+ }
82
+ ],
83
+ { tracker }
84
+ );
85
+
86
+ const full = createFullDidChangeParams('file:///demo.ts', 'const value = 1;', {
87
+ tracker
88
+ });
89
+ ```
90
+
91
+ ## Installation
92
+
93
+ ```bash
94
+ npm install @lspeasy/core
95
+ # or
96
+ pnpm add @lspeasy/core
97
+ # or
98
+ yarn add @lspeasy/core
99
+ ```
100
+
101
+ ## Quick Start
102
+
103
+ ### Type-Safe LSP Enums
104
+
105
+ The SDK exports enums for all LSP kind types, providing type safety and IDE autocomplete:
106
+
107
+ ```typescript
108
+ import {
109
+ CompletionItemKind,
110
+ SymbolKind,
111
+ DiagnosticSeverity,
112
+ CodeActionKind,
113
+ FoldingRangeKind
114
+ } from '@lspeasy/core/protocol/enums';
115
+
116
+ // Use enums instead of magic numbers
117
+ const completion = {
118
+ label: 'myFunction',
119
+ kind: CompletionItemKind.Function // Instead of: kind: 2
120
+ };
121
+
122
+ // String-based kinds support both enums and custom values
123
+ const codeAction = {
124
+ title: 'Quick fix',
125
+ kind: CodeActionKind.QuickFix // Or custom: 'refactor.extract.helper'
126
+ };
127
+ ```
128
+
129
+ ### Using StdioTransport
130
+
131
+ ```typescript
132
+ import { StdioTransport } from '@lspeasy/core';
133
+
134
+ // Create transport for stdio communication
135
+ const transport = new StdioTransport();
136
+
137
+ // Listen for messages
138
+ transport.onMessage((message) => {
139
+ console.log('Received:', message);
140
+ });
141
+
142
+ // Send a message
143
+ await transport.send({
144
+ jsonrpc: '2.0',
145
+ method: 'initialize',
146
+ id: 1,
147
+ params: { /* ... */ }
148
+ });
149
+
150
+ // Clean up
151
+ await transport.close();
152
+ ```
153
+
154
+ ### Using WebSocketTransport
155
+
156
+ ```typescript
157
+ import { WebSocketTransport } from '@lspeasy/core';
158
+
159
+ // Client mode with automatic reconnection
160
+ const transport = new WebSocketTransport({
161
+ url: 'ws://localhost:3000',
162
+ enableReconnect: true,
163
+ maxReconnectAttempts: 5,
164
+ reconnectDelay: 1000,
165
+ maxReconnectDelay: 30000,
166
+ reconnectBackoffMultiplier: 2
167
+ });
168
+
169
+ // Subscribe to events
170
+ transport.onMessage((message) => {
171
+ console.log('Received:', message);
172
+ });
173
+
174
+ transport.onError((error) => {
175
+ console.error('Transport error:', error);
176
+ });
177
+
178
+ transport.onClose(() => {
179
+ console.log('Connection closed');
180
+ });
181
+
182
+ // Send messages
183
+ await transport.send({
184
+ jsonrpc: '2.0',
185
+ method: 'textDocument/hover',
186
+ id: 2,
187
+ params: { /* ... */ }
188
+ });
189
+ ```
190
+
191
+ If running on Node.js < 22.4 and using client mode, install `ws`:
192
+
193
+ ```bash
194
+ pnpm add ws
195
+ ```
196
+
197
+ ### Server Mode WebSocket
198
+
199
+ ```typescript
200
+ import { WebSocketTransport } from '@lspeasy/core';
201
+ import { WebSocketServer } from 'ws';
202
+
203
+ const wss = new WebSocketServer({ port: 3000 });
204
+
205
+ wss.on('connection', (ws) => {
206
+ // Wrap existing WebSocket connection
207
+ const transport = new WebSocketTransport({
208
+ socket: ws
209
+ });
210
+
211
+ transport.onMessage((message) => {
212
+ // Handle LSP messages
213
+ });
214
+ });
215
+ ```
216
+
217
+ ## Transport Interface
218
+
219
+ All transports implement the `Transport` interface:
220
+
221
+ ```typescript
222
+ interface Transport {
223
+ // Send a JSON-RPC message
224
+ send(message: JSONRPCMessage): Promise<void>;
225
+
226
+ // Subscribe to incoming messages
227
+ onMessage(handler: (message: JSONRPCMessage) => void): Disposable;
228
+
229
+ // Subscribe to errors
230
+ onError(handler: (error: Error) => void): Disposable;
231
+
232
+ // Subscribe to connection close
233
+ onClose(handler: () => void): Disposable;
234
+
235
+ // Close the transport
236
+ close(): Promise<void>;
237
+ }
238
+ ```
239
+
240
+ ### Creating Custom Transports
241
+
242
+ You can implement custom transports for any communication protocol:
243
+
244
+ ```typescript
245
+ import { Transport, Disposable, JSONRPCMessage } from '@lspeasy/core';
246
+ import EventEmitter from 'events';
247
+
248
+ class HTTPPollingTransport implements Transport {
249
+ private events = new EventEmitter();
250
+ private pollInterval: NodeJS.Timeout | null = null;
251
+
252
+ constructor(private url: string) {
253
+ this.startPolling();
254
+ }
255
+
256
+ async send(message: JSONRPCMessage): Promise<void> {
257
+ await fetch(`${this.url}/send`, {
258
+ method: 'POST',
259
+ headers: { 'Content-Type': 'application/json' },
260
+ body: JSON.stringify(message)
261
+ });
262
+ }
263
+
264
+ onMessage(handler: (message: JSONRPCMessage) => void): Disposable {
265
+ this.events.on('message', handler);
266
+ return {
267
+ dispose: () => this.events.off('message', handler)
268
+ };
269
+ }
270
+
271
+ onError(handler: (error: Error) => void): Disposable {
272
+ this.events.on('error', handler);
273
+ return {
274
+ dispose: () => this.events.off('error', handler)
275
+ };
276
+ }
277
+
278
+ onClose(handler: () => void): Disposable {
279
+ this.events.on('close', handler);
280
+ return {
281
+ dispose: () => this.events.off('close', handler)
282
+ };
283
+ }
284
+
285
+ async close(): Promise<void> {
286
+ if (this.pollInterval) {
287
+ clearInterval(this.pollInterval);
288
+ this.pollInterval = null;
289
+ }
290
+ this.events.emit('close');
291
+ }
292
+
293
+ private startPolling(): void {
294
+ this.pollInterval = setInterval(async () => {
295
+ try {
296
+ const response = await fetch(`${this.url}/poll`);
297
+ const messages = await response.json();
298
+ for (const message of messages) {
299
+ this.events.emit('message', message);
300
+ }
301
+ } catch (error) {
302
+ this.events.emit('error', error);
303
+ }
304
+ }, 100);
305
+ }
306
+ }
307
+ ```
308
+
309
+ ## JSON-RPC Message Utilities
310
+
311
+ ### Parsing and Serialization
312
+
313
+ ```typescript
314
+ import { parseMessages, serializeMessage } from '@lspeasy/core';
315
+
316
+ // Parse HTTP-style headers + JSON content
317
+ const input = 'Content-Length: 59\r\n\r\n{"jsonrpc":"2.0","method":"initialize","id":1,"params":{}}';
318
+ const messages = parseMessages(input);
319
+ // messages = [{ jsonrpc: '2.0', method: 'initialize', id: 1, params: {} }]
320
+
321
+ // Serialize back to wire format
322
+ const output = serializeMessage(messages[0]);
323
+ // output = 'Content-Length: 59\r\n\r\n{"jsonrpc":"2.0","method":"initialize","id":1,"params":{}}'
324
+ ```
325
+
326
+ ### Creating Messages
327
+
328
+ ```typescript
329
+ // JSON-RPC 2.0 request message
330
+ const request = {
331
+ jsonrpc: '2.0',
332
+ id: 1,
333
+ method: 'textDocument/hover',
334
+ params: { /* params */ },
335
+ };
336
+
337
+ // JSON-RPC 2.0 notification message (no id)
338
+ const notification = {
339
+ jsonrpc: '2.0',
340
+ method: 'textDocument/didChange',
341
+ params: { /* params */ },
342
+ };
343
+
344
+ // Successful response message
345
+ const response = {
346
+ jsonrpc: '2.0',
347
+ id: 1,
348
+ result: { /* result */ },
349
+ };
350
+
351
+ // Error response message
352
+ const errorResponse = {
353
+ jsonrpc: '2.0',
354
+ id: 1,
355
+ error: {
356
+ code: -32601,
357
+ message: 'Method not found',
358
+ // optional: data: { ... },
359
+ },
360
+ };
361
+ ```
362
+
363
+ ## Cancellation
364
+
365
+ ### CancellationToken
366
+
367
+ ```typescript
368
+ import { CancellationTokenSource } from '@lspeasy/core';
369
+
370
+ const source = new CancellationTokenSource();
371
+ const token = source.token;
372
+
373
+ // Subscribe to cancellation
374
+ token.onCancellationRequested(() => {
375
+ console.log('Operation cancelled');
376
+ });
377
+
378
+ // Check if cancelled
379
+ if (token.isCancellationRequested) {
380
+ return;
381
+ }
382
+
383
+ // Cancel the operation
384
+ source.cancel();
385
+
386
+ // Clean up
387
+ source.dispose();
388
+ ```
389
+
390
+ ### Using with Async Operations
391
+
392
+ ```typescript
393
+ async function longRunningTask(token: CancellationToken): Promise<void> {
394
+ for (let i = 0; i < 100; i++) {
395
+ if (token.isCancellationRequested) {
396
+ throw new Error('Operation cancelled');
397
+ }
398
+ await doWork();
399
+ }
400
+ }
401
+
402
+ const source = new CancellationTokenSource();
403
+ longRunningTask(source.token).catch(console.error);
404
+
405
+ // Cancel after 5 seconds
406
+ setTimeout(() => source.cancel(), 5000);
407
+ ```
408
+
409
+ ## Logging
410
+
411
+ ```typescript
412
+ import { ConsoleLogger, LogLevel } from '@lspeasy/core';
413
+
414
+ // Create logger
415
+ const logger = new ConsoleLogger('MyServer', LogLevel.Debug);
416
+
417
+ // Log at different levels
418
+ logger.error('Error message', new Error('Something failed'));
419
+ logger.warn('Warning message');
420
+ logger.info('Info message');
421
+ logger.debug('Debug message');
422
+ ```
423
+
424
+ ## Error Codes
425
+
426
+ Standard JSON-RPC 2.0 error codes:
427
+
428
+ ```typescript
429
+ enum ErrorCode {
430
+ ParseError = -32700,
431
+ InvalidRequest = -32600,
432
+ MethodNotFound = -32601,
433
+ InvalidParams = -32602,
434
+ InternalError = -32603
435
+ }
436
+ ```
437
+
438
+ ## Best Practices
439
+
440
+ ### Resource Management
441
+
442
+ Always clean up resources using the Disposable pattern:
443
+
444
+ ```typescript
445
+ const disposables: Disposable[] = [];
446
+
447
+ disposables.push(transport.onMessage(handleMessage));
448
+ disposables.push(transport.onError(handleError));
449
+ disposables.push(transport.onClose(handleClose));
450
+
451
+ // Later, dispose all
452
+ disposables.forEach(d => d.dispose());
453
+ ```
454
+
455
+ ### Error Handling
456
+
457
+ Wrap transport operations in try/catch:
458
+
459
+ ```typescript
460
+ try {
461
+ await transport.send(message);
462
+ } catch (error) {
463
+ logger.error('Failed to send message', error as Error);
464
+ // Handle error (reconnect, retry, etc.)
465
+ }
466
+ ```
467
+
468
+ ### WebSocket Reconnection
469
+
470
+ Configure reconnection parameters based on your use case:
471
+
472
+ ```typescript
473
+ // Aggressive reconnection for interactive apps
474
+ const transport = new WebSocketTransport({
475
+ url: 'ws://localhost:3000',
476
+ enableReconnect: true,
477
+ maxReconnectAttempts: 10,
478
+ reconnectDelay: 500,
479
+ maxReconnectDelay: 5000,
480
+ reconnectBackoffMultiplier: 1.5
481
+ });
482
+
483
+ // Conservative reconnection for batch processing
484
+ const transport = new WebSocketTransport({
485
+ url: 'ws://localhost:3000',
486
+ enableReconnect: true,
487
+ maxReconnectAttempts: 3,
488
+ reconnectDelay: 5000,
489
+ maxReconnectDelay: 30000,
490
+ reconnectBackoffMultiplier: 2
491
+ });
492
+ ```
493
+
494
+ ## Testing
495
+
496
+ Use mock transports for testing:
497
+
498
+ ```typescript
499
+ import { Transport, Disposable, JSONRPCMessage } from '@lspeasy/core';
500
+ import EventEmitter from 'events';
501
+
502
+ class MockTransport implements Transport {
503
+ private events = new EventEmitter();
504
+ public sentMessages: JSONRPCMessage[] = [];
505
+
506
+ async send(message: JSONRPCMessage): Promise<void> {
507
+ this.sentMessages.push(message);
508
+ }
509
+
510
+ onMessage(handler: (message: JSONRPCMessage) => void): Disposable {
511
+ this.events.on('message', handler);
512
+ return { dispose: () => this.events.off('message', handler) };
513
+ }
514
+
515
+ onError(handler: (error: Error) => void): Disposable {
516
+ this.events.on('error', handler);
517
+ return { dispose: () => this.events.off('error', handler) };
518
+ }
519
+
520
+ onClose(handler: () => void): Disposable {
521
+ this.events.on('close', handler);
522
+ return { dispose: () => this.events.off('close', handler) };
523
+ }
524
+
525
+ async close(): Promise<void> {
526
+ this.events.emit('close');
527
+ }
528
+
529
+ // Test helpers
530
+ simulateMessage(message: JSONRPCMessage): void {
531
+ this.events.emit('message', message);
532
+ }
533
+
534
+ simulateError(error: Error): void {
535
+ this.events.emit('error', error);
536
+ }
537
+ }
538
+ ```
539
+
540
+ ## API Reference
541
+
542
+ See [API.md](../../docs/API.md) for complete API documentation.
543
+
544
+ ## Architecture
545
+
546
+ See [ARCHITECTURE.md](../../docs/ARCHITECTURE.md) for system architecture details.
547
+
548
+ ## License
549
+
550
+ MIT
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @lspeasy/core - Core types, transports, and utilities for LSP SDK
3
+ */
4
+ export type { BaseMessage, RequestMessage, NotificationMessage, SuccessResponseMessage, ErrorResponseMessage, ResponseMessage, Message } from './jsonrpc/messages.js';
5
+ export type { ResponseError as ResponseErrorInterface } from './jsonrpc/messages.js';
6
+ export { isRequestMessage, isNotificationMessage, isResponseMessage, isSuccessResponse, isErrorResponse } from './jsonrpc/messages.js';
7
+ export { parseMessage, serializeMessage } from './jsonrpc/framing.js';
8
+ export { MessageReader } from './jsonrpc/reader.js';
9
+ export { MessageWriter } from './jsonrpc/writer.js';
10
+ export { requestMessageSchema, notificationMessageSchema, responseErrorSchema, successResponseMessageSchema, errorResponseMessageSchema, responseMessageSchema, messageSchema } from './jsonrpc/schemas.js';
11
+ export type { Transport } from './transport/transport.js';
12
+ export { StdioTransport } from './transport/stdio.js';
13
+ export type { StdioTransportOptions } from './transport/stdio.js';
14
+ export { WebSocketTransport } from './transport/websocket.js';
15
+ export type { WebSocketTransportOptions } from './transport/websocket.js';
16
+ export { createWebSocketClient } from './transport/websocket.js';
17
+ export { TransportEventEmitter } from './transport/events.js';
18
+ export type { Middleware, MiddlewareContext, MiddlewareDirection, MiddlewareMessage, MiddlewareMessageType, MiddlewareNext, MiddlewareResult, MethodFilter, ScopedMiddleware, TypedMiddleware, TypedMiddlewareContext, TypedParams, TypedResult, LSPMethod } from './middleware/index.js';
19
+ export { composeMiddleware, executeMiddlewarePipeline, createScopedMiddleware, createTypedMiddleware } from './middleware/index.js';
20
+ export type { Disposable } from './utils/disposable.js';
21
+ export { DisposableStore } from './utils/disposable.js';
22
+ export type { CancellationToken } from './utils/cancellation.js';
23
+ export { CancellationTokenSource, CancellationToken as CancellationTokenNone } from './utils/cancellation.js';
24
+ export type { Logger } from './utils/logger.js';
25
+ export { LogLevel, ConsoleLogger, NullLogger } from './utils/logger.js';
26
+ export { JSONRPCErrorCode, ErrorMessage, ResponseError } from './utils/errors.js';
27
+ export { DocumentVersionTracker, createFullDidChangeParams, createIncrementalDidChangeParams } from './utils/document.js';
28
+ export type { IncrementalChange, VersionSource } from './utils/document.js';
29
+ export type * from './protocol/types.js';
30
+ export { LSPRequest, LSPNotification } from './protocol/namespaces.js';
31
+ export * from './protocol/infer.js';
32
+ export * from './protocol/capability-methods.js';
33
+ export type { Client, Server } from './protocol/capability-methods.js';
34
+ export { PositionSchema, RangeSchema, TextDocumentIdentifierSchema, HoverParamsSchema, HoverSchema, CompletionParamsSchema, CompletionItemSchema, CompletionListSchema, DefinitionParamsSchema, ReferenceParamsSchema, DocumentSymbolParamsSchema, DocumentSymbolSchema, InitializeParamsSchema, DidOpenTextDocumentParamsSchema, DidChangeTextDocumentParamsSchema, DidCloseTextDocumentParamsSchema, DidSaveTextDocumentParamsSchema, LSPSchemas, getSchemaForMethod } from './protocol/schemas.js';
35
+ export type { WorkspaceFolder, WorkspaceFoldersChangeEvent, WorkspaceEdit, ApplyWorkspaceEditParams, ApplyWorkspaceEditResult, DidChangeWorkspaceFoldersParams } from './protocol/workspace.js';
36
+ export { createWorkspaceFolder, createWorkspaceFoldersChangeEvent, FileChangeTypes as WorkspaceFileChangeTypes } from './protocol/workspace.js';
37
+ export type { DidChangeWatchedFilesParams, FileEvent, FileChangeType, FileSystemWatcher, WatchKind } from './protocol/watching.js';
38
+ export { WatchKinds, createFileEvent, createFileSystemWatcher, createDidChangeWatchedFilesParams } from './protocol/watching.js';
39
+ export type { ProgressToken, WorkDoneProgressBegin, WorkDoneProgressReport, WorkDoneProgressEnd, WorkDoneProgressParams, WorkDoneProgressOptions, WorkDoneProgressCreateParams, WorkDoneProgressValue } from './protocol/progress.js';
40
+ export { createProgressBegin, createProgressReport, createProgressEnd, createProgressCreateParams, createProgressToken } from './protocol/progress.js';
41
+ export type { PartialResultParams } from './protocol/partial.js';
42
+ export { createPartialResultParams, hasPartialResultToken, getPartialResultToken } from './protocol/partial.js';
43
+ export * from './protocol/capabilities.js';
44
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @lspeasy/core - Core types, transports, and utilities for LSP SDK
3
+ */
4
+ export { isRequestMessage, isNotificationMessage, isResponseMessage, isSuccessResponse, isErrorResponse } from './jsonrpc/messages.js';
5
+ export { parseMessage, serializeMessage } from './jsonrpc/framing.js';
6
+ export { MessageReader } from './jsonrpc/reader.js';
7
+ export { MessageWriter } from './jsonrpc/writer.js';
8
+ export { requestMessageSchema, notificationMessageSchema, responseErrorSchema, successResponseMessageSchema, errorResponseMessageSchema, responseMessageSchema, messageSchema } from './jsonrpc/schemas.js';
9
+ export { StdioTransport } from './transport/stdio.js';
10
+ export { WebSocketTransport } from './transport/websocket.js';
11
+ export { createWebSocketClient } from './transport/websocket.js';
12
+ export { TransportEventEmitter } from './transport/events.js';
13
+ export { composeMiddleware, executeMiddlewarePipeline, createScopedMiddleware, createTypedMiddleware } from './middleware/index.js';
14
+ export { DisposableStore } from './utils/disposable.js';
15
+ export { CancellationTokenSource, CancellationToken as CancellationTokenNone } from './utils/cancellation.js';
16
+ export { LogLevel, ConsoleLogger, NullLogger } from './utils/logger.js';
17
+ export { JSONRPCErrorCode, ErrorMessage, ResponseError } from './utils/errors.js';
18
+ export { DocumentVersionTracker, createFullDidChangeParams, createIncrementalDidChangeParams } from './utils/document.js';
19
+ // LSP protocol types and constants (overloaded with same name - type and const)
20
+ // Note: Single export statement exports both the type and const with same name
21
+ export { LSPRequest, LSPNotification } from './protocol/namespaces.js';
22
+ export * from './protocol/infer.js';
23
+ // Capability-conditional method interfaces (hand-written type transformations)
24
+ export * from './protocol/capability-methods.js';
25
+ // LSP protocol schemas
26
+ export { PositionSchema, RangeSchema, TextDocumentIdentifierSchema, HoverParamsSchema, HoverSchema, CompletionParamsSchema, CompletionItemSchema, CompletionListSchema, DefinitionParamsSchema, ReferenceParamsSchema, DocumentSymbolParamsSchema, DocumentSymbolSchema, InitializeParamsSchema, DidOpenTextDocumentParamsSchema, DidChangeTextDocumentParamsSchema, DidCloseTextDocumentParamsSchema, DidSaveTextDocumentParamsSchema, LSPSchemas, getSchemaForMethod } from './protocol/schemas.js';
27
+ export { createWorkspaceFolder, createWorkspaceFoldersChangeEvent, FileChangeTypes as WorkspaceFileChangeTypes } from './protocol/workspace.js';
28
+ export { WatchKinds, createFileEvent, createFileSystemWatcher, createDidChangeWatchedFilesParams } from './protocol/watching.js';
29
+ export { createProgressBegin, createProgressReport, createProgressEnd, createProgressCreateParams, createProgressToken } from './protocol/progress.js';
30
+ export { createPartialResultParams, hasPartialResultToken, getPartialResultToken } from './protocol/partial.js';
31
+ export * from './protocol/capabilities.js';
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgBH,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,4BAA4B,EAC5B,0BAA0B,EAC1B,qBAAqB,EACrB,aAAa,EACd,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAmB9D,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACtB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EACL,uBAAuB,EACvB,iBAAiB,IAAI,qBAAqB,EAC3C,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,gCAAgC,EACjC,MAAM,qBAAqB,CAAC;AAM7B,gFAAgF;AAChF,+EAA+E;AAC/E,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACvE,cAAc,qBAAqB,CAAC;AAEpC,+EAA+E;AAC/E,cAAc,kCAAkC,CAAC;AAGjD,uBAAuB;AACvB,OAAO,EACL,cAAc,EACd,WAAW,EACX,4BAA4B,EAC5B,iBAAiB,EACjB,WAAW,EACX,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,0BAA0B,EAC1B,oBAAoB,EACpB,sBAAsB,EACtB,+BAA+B,EAC/B,iCAAiC,EACjC,gCAAgC,EAChC,+BAA+B,EAC/B,UAAU,EACV,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAW/B,OAAO,EACL,qBAAqB,EACrB,iCAAiC,EACjC,eAAe,IAAI,wBAAwB,EAC5C,MAAM,yBAAyB,CAAC;AASjC,OAAO,EACL,UAAU,EACV,eAAe,EACf,uBAAuB,EACvB,iCAAiC,EAClC,MAAM,wBAAwB,CAAC;AAYhC,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,0BAA0B,EAC1B,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,EACtB,MAAM,uBAAuB,CAAC;AAE/B,cAAc,4BAA4B,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * JSON-RPC 2.0 message framing with Content-Length headers
3
+ * Pattern: MCP SDK's parseMessage with header parsing
4
+ */
5
+ import type { Message } from './messages.js';
6
+ /**
7
+ * Header constants
8
+ */
9
+ export declare const CONTENT_LENGTH_HEADER = "Content-Length";
10
+ export declare const CONTENT_TYPE_HEADER = "Content-Type";
11
+ export declare const DEFAULT_CONTENT_TYPE = "application/vscode-jsonrpc; charset=utf-8";
12
+ /**
13
+ * Parse headers from buffer
14
+ * Format: "Header-Name: value\r\n"
15
+ */
16
+ export declare function parseHeaders(buffer: Buffer): {
17
+ headers: Map<string, string>;
18
+ bodyStart: number;
19
+ } | null;
20
+ /**
21
+ * Parse a complete message from buffer
22
+ * Returns { message, bytesRead } or null if incomplete
23
+ */
24
+ export declare function parseMessage(buffer: Buffer): {
25
+ message: Message;
26
+ bytesRead: number;
27
+ } | null;
28
+ /**
29
+ * Serialize a message to buffer with headers
30
+ */
31
+ export declare function serializeMessage(message: Message): Buffer;
32
+ //# sourceMappingURL=framing.d.ts.map