@eclipse-glsp/server-mcp 2.7.0-next.9
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/LICENSE +642 -0
- package/README.md +57 -0
- package/lib/index.d.ts +23 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +41 -0
- package/lib/index.js.map +1 -0
- package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.d.ts +43 -0
- package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.d.ts.map +1 -0
- package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.js +96 -0
- package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.js.map +1 -0
- package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.d.ts +43 -0
- package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.d.ts.map +1 -0
- package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.js +95 -0
- package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.js.map +1 -0
- package/lib/prompts/index.d.ts +18 -0
- package/lib/prompts/index.d.ts.map +1 -0
- package/lib/prompts/index.js +34 -0
- package/lib/prompts/index.js.map +1 -0
- package/lib/resources/handlers/diagram-png-mcp-resource-handler.d.ts +81 -0
- package/lib/resources/handlers/diagram-png-mcp-resource-handler.d.ts.map +1 -0
- package/lib/resources/handlers/diagram-png-mcp-resource-handler.js +174 -0
- package/lib/resources/handlers/diagram-png-mcp-resource-handler.js.map +1 -0
- package/lib/resources/handlers/diagram-svg-mcp-resource-handler.d.ts +52 -0
- package/lib/resources/handlers/diagram-svg-mcp-resource-handler.d.ts.map +1 -0
- package/lib/resources/handlers/diagram-svg-mcp-resource-handler.js +96 -0
- package/lib/resources/handlers/diagram-svg-mcp-resource-handler.js.map +1 -0
- package/lib/resources/index.d.ts +20 -0
- package/lib/resources/index.d.ts.map +1 -0
- package/lib/resources/index.js +36 -0
- package/lib/resources/index.js.map +1 -0
- package/lib/resources/services/element-types-provider.d.ts +65 -0
- package/lib/resources/services/element-types-provider.d.ts.map +1 -0
- package/lib/resources/services/element-types-provider.js +81 -0
- package/lib/resources/services/element-types-provider.js.map +1 -0
- package/lib/resources/services/mcp-model-serializer.d.ts +78 -0
- package/lib/resources/services/mcp-model-serializer.d.ts.map +1 -0
- package/lib/resources/services/mcp-model-serializer.js +188 -0
- package/lib/resources/services/mcp-model-serializer.js.map +1 -0
- package/lib/server/glsp-mcp-server.d.ts +82 -0
- package/lib/server/glsp-mcp-server.d.ts.map +1 -0
- package/lib/server/glsp-mcp-server.js +140 -0
- package/lib/server/glsp-mcp-server.js.map +1 -0
- package/lib/server/index.d.ts +37 -0
- package/lib/server/index.d.ts.map +1 -0
- package/lib/server/index.js +57 -0
- package/lib/server/index.js.map +1 -0
- package/lib/server/lru-event-store.d.ts +53 -0
- package/lib/server/lru-event-store.d.ts.map +1 -0
- package/lib/server/lru-event-store.js +100 -0
- package/lib/server/lru-event-store.js.map +1 -0
- package/lib/server/mcp-diagram-handler-dispatcher.d.ts +144 -0
- package/lib/server/mcp-diagram-handler-dispatcher.d.ts.map +1 -0
- package/lib/server/mcp-diagram-handler-dispatcher.js +382 -0
- package/lib/server/mcp-diagram-handler-dispatcher.js.map +1 -0
- package/lib/server/mcp-diagram-module.d.ts +123 -0
- package/lib/server/mcp-diagram-module.d.ts.map +1 -0
- package/lib/server/mcp-diagram-module.js +186 -0
- package/lib/server/mcp-diagram-module.js.map +1 -0
- package/lib/server/mcp-diagram-prompt-handler-registry.d.ts +33 -0
- package/lib/server/mcp-diagram-prompt-handler-registry.d.ts.map +1 -0
- package/lib/server/mcp-diagram-prompt-handler-registry.js +76 -0
- package/lib/server/mcp-diagram-prompt-handler-registry.js.map +1 -0
- package/lib/server/mcp-diagram-resource-handler-registry.d.ts +35 -0
- package/lib/server/mcp-diagram-resource-handler-registry.d.ts.map +1 -0
- package/lib/server/mcp-diagram-resource-handler-registry.js +94 -0
- package/lib/server/mcp-diagram-resource-handler-registry.js.map +1 -0
- package/lib/server/mcp-diagram-tool-handler-registry.d.ts +57 -0
- package/lib/server/mcp-diagram-tool-handler-registry.d.ts.map +1 -0
- package/lib/server/mcp-diagram-tool-handler-registry.js +111 -0
- package/lib/server/mcp-diagram-tool-handler-registry.js.map +1 -0
- package/lib/server/mcp-handler-shared.d.ts +142 -0
- package/lib/server/mcp-handler-shared.d.ts.map +1 -0
- package/lib/server/mcp-handler-shared.js +199 -0
- package/lib/server/mcp-handler-shared.js.map +1 -0
- package/lib/server/mcp-http-transport.d.ts +93 -0
- package/lib/server/mcp-http-transport.d.ts.map +1 -0
- package/lib/server/mcp-http-transport.js +350 -0
- package/lib/server/mcp-http-transport.js.map +1 -0
- package/lib/server/mcp-id-alias-service.d.ts +70 -0
- package/lib/server/mcp-id-alias-service.d.ts.map +1 -0
- package/lib/server/mcp-id-alias-service.js +85 -0
- package/lib/server/mcp-id-alias-service.js.map +1 -0
- package/lib/server/mcp-input-schemas.d.ts +73 -0
- package/lib/server/mcp-input-schemas.d.ts.map +1 -0
- package/lib/server/mcp-input-schemas.js +67 -0
- package/lib/server/mcp-input-schemas.js.map +1 -0
- package/lib/server/mcp-label-provider.d.ts +45 -0
- package/lib/server/mcp-label-provider.d.ts.map +1 -0
- package/lib/server/mcp-label-provider.js +42 -0
- package/lib/server/mcp-label-provider.js.map +1 -0
- package/lib/server/mcp-log-level-registry.d.ts +54 -0
- package/lib/server/mcp-log-level-registry.d.ts.map +1 -0
- package/lib/server/mcp-log-level-registry.js +80 -0
- package/lib/server/mcp-log-level-registry.js.map +1 -0
- package/lib/server/mcp-logger.d.ts +59 -0
- package/lib/server/mcp-logger.d.ts.map +1 -0
- package/lib/server/mcp-logger.js +104 -0
- package/lib/server/mcp-logger.js.map +1 -0
- package/lib/server/mcp-mime-types.d.ts +28 -0
- package/lib/server/mcp-mime-types.d.ts.map +1 -0
- package/lib/server/mcp-mime-types.js +18 -0
- package/lib/server/mcp-mime-types.js.map +1 -0
- package/lib/server/mcp-options.d.ts +39 -0
- package/lib/server/mcp-options.d.ts.map +1 -0
- package/lib/server/mcp-options.js +53 -0
- package/lib/server/mcp-options.js.map +1 -0
- package/lib/server/mcp-progress-reporter.d.ts +48 -0
- package/lib/server/mcp-progress-reporter.d.ts.map +1 -0
- package/lib/server/mcp-progress-reporter.js +66 -0
- package/lib/server/mcp-progress-reporter.js.map +1 -0
- package/lib/server/mcp-prompt-handler.d.ts +120 -0
- package/lib/server/mcp-prompt-handler.d.ts.map +1 -0
- package/lib/server/mcp-prompt-handler.js +131 -0
- package/lib/server/mcp-prompt-handler.js.map +1 -0
- package/lib/server/mcp-request-context.d.ts +37 -0
- package/lib/server/mcp-request-context.d.ts.map +1 -0
- package/lib/server/mcp-request-context.js +37 -0
- package/lib/server/mcp-request-context.js.map +1 -0
- package/lib/server/mcp-resource-handler.d.ts +212 -0
- package/lib/server/mcp-resource-handler.d.ts.map +1 -0
- package/lib/server/mcp-resource-handler.js +298 -0
- package/lib/server/mcp-resource-handler.js.map +1 -0
- package/lib/server/mcp-server-launcher.d.ts +143 -0
- package/lib/server/mcp-server-launcher.d.ts.map +1 -0
- package/lib/server/mcp-server-launcher.js +355 -0
- package/lib/server/mcp-server-launcher.js.map +1 -0
- package/lib/server/mcp-server-module.d.ts +143 -0
- package/lib/server/mcp-server-module.d.ts.map +1 -0
- package/lib/server/mcp-server-module.js +249 -0
- package/lib/server/mcp-server-module.js.map +1 -0
- package/lib/server/mcp-session.d.ts +44 -0
- package/lib/server/mcp-session.d.ts.map +1 -0
- package/lib/server/mcp-session.js +18 -0
- package/lib/server/mcp-session.js.map +1 -0
- package/lib/server/mcp-tool-handler.d.ts +259 -0
- package/lib/server/mcp-tool-handler.d.ts.map +1 -0
- package/lib/server/mcp-tool-handler.js +355 -0
- package/lib/server/mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/count-elements-mcp-tool-handler.d.ts +46 -0
- package/lib/tools/handlers/count-elements-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/count-elements-mcp-tool-handler.js +76 -0
- package/lib/tools/handlers/count-elements-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/create-edges-mcp-tool-handler.d.ts +112 -0
- package/lib/tools/handlers/create-edges-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/create-edges-mcp-tool-handler.js +190 -0
- package/lib/tools/handlers/create-edges-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/create-nodes-mcp-tool-handler.d.ts +81 -0
- package/lib/tools/handlers/create-nodes-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/create-nodes-mcp-tool-handler.js +123 -0
- package/lib/tools/handlers/create-nodes-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/delete-elements-mcp-tool-handler.d.ts +52 -0
- package/lib/tools/handlers/delete-elements-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/delete-elements-mcp-tool-handler.js +73 -0
- package/lib/tools/handlers/delete-elements-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/diagram-model-mcp-tool-handler.d.ts +59 -0
- package/lib/tools/handlers/diagram-model-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/diagram-model-mcp-tool-handler.js +78 -0
- package/lib/tools/handlers/diagram-model-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/element-types-mcp-tool-handler.d.ts +97 -0
- package/lib/tools/handlers/element-types-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/element-types-mcp-tool-handler.js +155 -0
- package/lib/tools/handlers/element-types-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/get-selection-mcp-tool-handler.d.ts +43 -0
- package/lib/tools/handlers/get-selection-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/get-selection-mcp-tool-handler.js +68 -0
- package/lib/tools/handlers/get-selection-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.d.ts +43 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.js +71 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/modify-edges-mcp-tool-handler.d.ts +78 -0
- package/lib/tools/handlers/modify-edges-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/modify-edges-mcp-tool-handler.js +136 -0
- package/lib/tools/handlers/modify-edges-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/modify-nodes-mcp-tool-handler.d.ts +92 -0
- package/lib/tools/handlers/modify-nodes-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/modify-nodes-mcp-tool-handler.js +125 -0
- package/lib/tools/handlers/modify-nodes-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/query-elements-mcp-tool-handler.d.ts +102 -0
- package/lib/tools/handlers/query-elements-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/query-elements-mcp-tool-handler.js +158 -0
- package/lib/tools/handlers/query-elements-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.d.ts +45 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.js +73 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/save-model-mcp-tool-handler.d.ts +55 -0
- package/lib/tools/handlers/save-model-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/save-model-mcp-tool-handler.js +91 -0
- package/lib/tools/handlers/save-model-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/session-info-mcp-tool-handler.d.ts +65 -0
- package/lib/tools/handlers/session-info-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/session-info-mcp-tool-handler.js +108 -0
- package/lib/tools/handlers/session-info-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/set-selection-mcp-tool-handler.d.ts +60 -0
- package/lib/tools/handlers/set-selection-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/set-selection-mcp-tool-handler.js +103 -0
- package/lib/tools/handlers/set-selection-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/set-view-mcp-tool-handler.d.ts +110 -0
- package/lib/tools/handlers/set-view-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/set-view-mcp-tool-handler.js +142 -0
- package/lib/tools/handlers/set-view-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.d.ts +45 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.js +74 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/validate-diagram-mcp-tool-handler.d.ts +66 -0
- package/lib/tools/handlers/validate-diagram-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/validate-diagram-mcp-tool-handler.js +0 -0
- package/lib/tools/handlers/validate-diagram-mcp-tool-handler.js.map +1 -0
- package/lib/tools/index.d.ts +34 -0
- package/lib/tools/index.d.ts.map +1 -0
- package/lib/tools/index.js +50 -0
- package/lib/tools/index.js.map +1 -0
- package/lib/util/index.d.ts +18 -0
- package/lib/util/index.d.ts.map +1 -0
- package/lib/util/index.js +34 -0
- package/lib/util/index.js.map +1 -0
- package/lib/util/markdown-util.d.ts +20 -0
- package/lib/util/markdown-util.d.ts.map +1 -0
- package/lib/util/markdown-util.js +45 -0
- package/lib/util/markdown-util.js.map +1 -0
- package/lib/util/mcp-util.d.ts +22 -0
- package/lib/util/mcp-util.d.ts.map +1 -0
- package/lib/util/mcp-util.js +29 -0
- package/lib/util/mcp-util.js.map +1 -0
- package/package.json +63 -0
- package/src/index.ts +24 -0
- package/src/prompts/handlers/describe-diagram-mcp-prompt-handler.ts +89 -0
- package/src/prompts/handlers/suggest-improvements-mcp-prompt-handler.ts +86 -0
- package/src/prompts/index.ts +18 -0
- package/src/resources/handlers/diagram-png-mcp-resource-handler.ts +181 -0
- package/src/resources/handlers/diagram-svg-mcp-resource-handler.ts +89 -0
- package/src/resources/index.ts +20 -0
- package/src/resources/services/element-types-provider.ts +105 -0
- package/src/resources/services/mcp-model-serializer.ts +211 -0
- package/src/server/glsp-mcp-server.spec.ts +73 -0
- package/src/server/glsp-mcp-server.ts +196 -0
- package/src/server/index.ts +42 -0
- package/src/server/lru-event-store.spec.ts +121 -0
- package/src/server/lru-event-store.ts +112 -0
- package/src/server/mcp-diagram-handler-dispatcher.spec.ts +231 -0
- package/src/server/mcp-diagram-handler-dispatcher.ts +459 -0
- package/src/server/mcp-diagram-module.ts +248 -0
- package/src/server/mcp-diagram-prompt-handler-registry.ts +59 -0
- package/src/server/mcp-diagram-resource-handler-registry.ts +73 -0
- package/src/server/mcp-diagram-tool-handler-registry.ts +97 -0
- package/src/server/mcp-handler-shared.spec.ts +53 -0
- package/src/server/mcp-handler-shared.ts +247 -0
- package/src/server/mcp-http-transport-e2e.spec.ts +151 -0
- package/src/server/mcp-http-transport.spec.ts +385 -0
- package/src/server/mcp-http-transport.ts +368 -0
- package/src/server/mcp-id-alias-service.spec.ts +106 -0
- package/src/server/mcp-id-alias-service.ts +104 -0
- package/src/server/mcp-input-schemas.ts +82 -0
- package/src/server/mcp-label-provider.ts +52 -0
- package/src/server/mcp-log-level-registry.spec.ts +75 -0
- package/src/server/mcp-log-level-registry.ts +90 -0
- package/src/server/mcp-logger.spec.ts +227 -0
- package/src/server/mcp-logger.ts +91 -0
- package/src/server/mcp-mime-types.ts +31 -0
- package/src/server/mcp-options.ts +43 -0
- package/src/server/mcp-progress-reporter.spec.ts +93 -0
- package/src/server/mcp-progress-reporter.ts +67 -0
- package/src/server/mcp-prompt-handler.ts +157 -0
- package/src/server/mcp-request-context.ts +39 -0
- package/src/server/mcp-resource-handler.ts +389 -0
- package/src/server/mcp-server-launcher.spec.ts +173 -0
- package/src/server/mcp-server-launcher.ts +369 -0
- package/src/server/mcp-server-module.ts +287 -0
- package/src/server/mcp-session.ts +45 -0
- package/src/server/mcp-tool-handler.spec.ts +182 -0
- package/src/server/mcp-tool-handler.ts +431 -0
- package/src/server/raw-http.spec.ts +59 -0
- package/src/tools/handlers/count-elements-mcp-tool-handler.spec.ts +99 -0
- package/src/tools/handlers/count-elements-mcp-tool-handler.ts +66 -0
- package/src/tools/handlers/create-edges-mcp-tool-handler.spec.ts +196 -0
- package/src/tools/handlers/create-edges-mcp-tool-handler.ts +205 -0
- package/src/tools/handlers/create-nodes-mcp-tool-handler.spec.ts +197 -0
- package/src/tools/handlers/create-nodes-mcp-tool-handler.ts +131 -0
- package/src/tools/handlers/delete-elements-mcp-tool-handler.ts +73 -0
- package/src/tools/handlers/diagram-model-mcp-tool-handler.ts +66 -0
- package/src/tools/handlers/element-types-mcp-tool-handler.ts +151 -0
- package/src/tools/handlers/get-selection-mcp-tool-handler.ts +54 -0
- package/src/tools/handlers/layout-mcp-tool-handler.ts +56 -0
- package/src/tools/handlers/modify-edges-mcp-tool-handler.ts +148 -0
- package/src/tools/handlers/modify-nodes-mcp-tool-handler.ts +140 -0
- package/src/tools/handlers/query-elements-mcp-tool-handler.spec.ts +210 -0
- package/src/tools/handlers/query-elements-mcp-tool-handler.ts +161 -0
- package/src/tools/handlers/redo-mcp-tool-handler.ts +62 -0
- package/src/tools/handlers/save-model-mcp-tool-handler.ts +71 -0
- package/src/tools/handlers/session-info-mcp-tool-handler.spec.ts +152 -0
- package/src/tools/handlers/session-info-mcp-tool-handler.ts +97 -0
- package/src/tools/handlers/set-selection-mcp-tool-handler.spec.ts +118 -0
- package/src/tools/handlers/set-selection-mcp-tool-handler.ts +90 -0
- package/src/tools/handlers/set-view-mcp-tool-handler.ts +162 -0
- package/src/tools/handlers/undo-mcp-tool-handler.ts +61 -0
- package/src/tools/handlers/validate-diagram-mcp-tool-handler.ts +0 -0
- package/src/tools/index.ts +34 -0
- package/src/tools/tool-annotations.spec.ts +141 -0
- package/src/util/index.ts +18 -0
- package/src/util/markdown-util.ts +44 -0
- package/src/util/mcp-util.ts +25 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { Disposable, Logger, McpServerOptions } from '@eclipse-glsp/server';
|
|
18
|
+
import {
|
|
19
|
+
McpServer,
|
|
20
|
+
RegisteredPrompt,
|
|
21
|
+
RegisteredResource,
|
|
22
|
+
RegisteredResourceTemplate,
|
|
23
|
+
RegisteredTool
|
|
24
|
+
} from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
25
|
+
import { EmptyResultSchema, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
26
|
+
import { injectable, unmanaged } from 'inversify';
|
|
27
|
+
|
|
28
|
+
export const GLSPMcpServer = Symbol('GLSPMcpServer');
|
|
29
|
+
|
|
30
|
+
/** Either a static resource or a templated resource registration. */
|
|
31
|
+
export type GLSPMcpResource = RegisteredResource | RegisteredResourceTemplate;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Cadence for server-initiated `ping` requests on the standalone SSE GET stream. Shorter than
|
|
35
|
+
* typical client-side SSE read timeouts (e.g. undici's 5-min `bodyTimeout`) so the stream stays
|
|
36
|
+
* alive across chat-idle periods.
|
|
37
|
+
*/
|
|
38
|
+
const KEEP_ALIVE_INTERVAL_MS = 30_000;
|
|
39
|
+
|
|
40
|
+
/** Per-ping timeout — short, since a ping with no SSE GET stream open will never resolve. */
|
|
41
|
+
const KEEP_ALIVE_PING_TIMEOUT_MS = 5_000;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Curated, per-session view onto the underlying MCP server. Handlers see this during
|
|
45
|
+
* registration; the launcher disposes it on session-close and on server shutdown.
|
|
46
|
+
*/
|
|
47
|
+
export interface GLSPMcpServer
|
|
48
|
+
extends Pick<McpServer, 'registerPrompt' | 'registerResource' | 'registerTool' | 'sendLoggingMessage' | 'isConnected' | 'connect'>,
|
|
49
|
+
Disposable {
|
|
50
|
+
readonly options: McpServerOptions;
|
|
51
|
+
|
|
52
|
+
/** Register a tool. Wraps the SDK's {@link McpServer.registerTool} and updates the local log. */
|
|
53
|
+
readonly registerTool: McpServer['registerTool'];
|
|
54
|
+
/** Register a resource. Wraps the SDK's {@link McpServer.registerResource} and updates the local log. */
|
|
55
|
+
readonly registerResource: McpServer['registerResource'];
|
|
56
|
+
/** Register a prompt. Wraps the SDK's {@link McpServer.registerPrompt} and updates the local log. */
|
|
57
|
+
readonly registerPrompt: McpServer['registerPrompt'];
|
|
58
|
+
/** Send an LLM-facing log message via the MCP `logging/message` notification. */
|
|
59
|
+
sendLoggingMessage: McpServer['sendLoggingMessage'];
|
|
60
|
+
/** True iff a transport is currently connected. */
|
|
61
|
+
isConnected: McpServer['isConnected'];
|
|
62
|
+
/** Attach the supplied transport. */
|
|
63
|
+
connect: McpServer['connect'];
|
|
64
|
+
|
|
65
|
+
listTools(): RegisteredTool[];
|
|
66
|
+
/** True iff a tool with this exact `name` has been registered on this server instance. */
|
|
67
|
+
hasTool(name: string): boolean;
|
|
68
|
+
listResources(): GLSPMcpResource[];
|
|
69
|
+
listPrompts(): RegisteredPrompt[];
|
|
70
|
+
/** Sends an MCP `ping` and resolves on empty result, rejects on transport timeout. */
|
|
71
|
+
ping(): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Escape hatch to the underlying SDK `McpServer` for advanced APIs not covered by the
|
|
74
|
+
* stable surface. The returned value is the SDK type, not a stable GLSP surface.
|
|
75
|
+
*/
|
|
76
|
+
getRawServer(): McpServer;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const GLSPMcpServerFactory = Symbol('GLSPMcpServerFactory');
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Factory that produces a {@link GLSPMcpServer} per MCP client session.
|
|
83
|
+
* Bound to {@link DefaultGLSPMcpServer} by default; rebind to swap the
|
|
84
|
+
* implementation across all sessions.
|
|
85
|
+
*/
|
|
86
|
+
export type GLSPMcpServerFactory = (mcpServer: McpServer, options: McpServerOptions) => GLSPMcpServer;
|
|
87
|
+
|
|
88
|
+
@injectable()
|
|
89
|
+
export class DefaultGLSPMcpServer implements GLSPMcpServer {
|
|
90
|
+
protected readonly tools = new Map<string, RegisteredTool>();
|
|
91
|
+
protected readonly resources = new Map<string, GLSPMcpResource>();
|
|
92
|
+
protected readonly prompts = new Map<string, RegisteredPrompt>();
|
|
93
|
+
protected keepAliveTimer?: NodeJS.Timeout;
|
|
94
|
+
|
|
95
|
+
readonly registerTool: McpServer['registerTool'];
|
|
96
|
+
readonly registerResource: McpServer['registerResource'];
|
|
97
|
+
readonly registerPrompt: McpServer['registerPrompt'];
|
|
98
|
+
|
|
99
|
+
constructor(
|
|
100
|
+
@unmanaged() protected readonly mcpServer: McpServer,
|
|
101
|
+
@unmanaged() readonly options: McpServerOptions,
|
|
102
|
+
@unmanaged() protected readonly logger: Logger
|
|
103
|
+
) {
|
|
104
|
+
// `register*` need an interception layer so the local registration log stays in
|
|
105
|
+
// sync; the Proxy preserves the SDK's generic signatures (which a wrapped method
|
|
106
|
+
// using `Parameters<>` would collapse, breaking adopter autocomplete on
|
|
107
|
+
// `inputSchema → handler arg shape`).
|
|
108
|
+
const { tools, resources, prompts } = this;
|
|
109
|
+
this.registerTool = new Proxy(mcpServer.registerTool.bind(mcpServer), {
|
|
110
|
+
apply(target, thisArg, args) {
|
|
111
|
+
const registered = Reflect.apply(target, thisArg, args);
|
|
112
|
+
if (typeof args[0] === 'string') {
|
|
113
|
+
tools.set(args[0], registered);
|
|
114
|
+
}
|
|
115
|
+
return registered;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
this.registerResource = new Proxy(mcpServer.registerResource.bind(mcpServer), {
|
|
119
|
+
apply(target, thisArg, args) {
|
|
120
|
+
const registered = Reflect.apply(target, thisArg, args);
|
|
121
|
+
if (typeof args[0] === 'string') {
|
|
122
|
+
resources.set(args[0], registered);
|
|
123
|
+
}
|
|
124
|
+
return registered;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
this.registerPrompt = new Proxy(mcpServer.registerPrompt.bind(mcpServer), {
|
|
128
|
+
apply(target, thisArg, args) {
|
|
129
|
+
const registered = Reflect.apply(target, thisArg, args);
|
|
130
|
+
if (typeof args[0] === 'string') {
|
|
131
|
+
prompts.set(args[0], registered);
|
|
132
|
+
}
|
|
133
|
+
return registered;
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
sendLoggingMessage(...args: Parameters<McpServer['sendLoggingMessage']>): ReturnType<McpServer['sendLoggingMessage']> {
|
|
139
|
+
return this.mcpServer.sendLoggingMessage(...args);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async connect(...args: Parameters<McpServer['connect']>): ReturnType<McpServer['connect']> {
|
|
143
|
+
await this.mcpServer.connect(...args);
|
|
144
|
+
// Suppress the expected `RequestTimeout` when no SSE GET stream is open; surface other
|
|
145
|
+
// failures via debug. `unref` so a forgotten timer can't pin the process.
|
|
146
|
+
this.keepAliveTimer = setInterval(
|
|
147
|
+
() =>
|
|
148
|
+
this.ping().catch(err => {
|
|
149
|
+
if (!(err instanceof McpError) || err.code !== ErrorCode.RequestTimeout) {
|
|
150
|
+
this.logger.debug('MCP keep-alive ping failed:', err);
|
|
151
|
+
}
|
|
152
|
+
}),
|
|
153
|
+
KEEP_ALIVE_INTERVAL_MS
|
|
154
|
+
);
|
|
155
|
+
this.keepAliveTimer.unref();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
isConnected(): boolean {
|
|
159
|
+
return this.mcpServer.isConnected();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async ping(): Promise<void> {
|
|
163
|
+
// Bypass `Server.ping()` to pass a per-request timeout; SDK's no-arg wrapper uses the
|
|
164
|
+
// 60s default, which leaves keep-alive pings dangling for a full minute when no SSE GET
|
|
165
|
+
// stream is open.
|
|
166
|
+
await this.mcpServer.server.request({ method: 'ping' }, EmptyResultSchema, { timeout: KEEP_ALIVE_PING_TIMEOUT_MS });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
listTools(): RegisteredTool[] {
|
|
170
|
+
return [...this.tools.values()];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
hasTool(name: string): boolean {
|
|
174
|
+
return this.tools.has(name);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
listResources(): GLSPMcpResource[] {
|
|
178
|
+
return [...this.resources.values()];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
listPrompts(): RegisteredPrompt[] {
|
|
182
|
+
return [...this.prompts.values()];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
getRawServer(): McpServer {
|
|
186
|
+
return this.mcpServer;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
dispose(): void {
|
|
190
|
+
if (this.keepAliveTimer) {
|
|
191
|
+
clearInterval(this.keepAliveTimer);
|
|
192
|
+
this.keepAliveTimer = undefined;
|
|
193
|
+
}
|
|
194
|
+
this.mcpServer.close();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
export * from './glsp-mcp-server';
|
|
18
|
+
export * from './mcp-diagram-handler-dispatcher';
|
|
19
|
+
export * from './mcp-diagram-prompt-handler-registry';
|
|
20
|
+
export * from './mcp-diagram-resource-handler-registry';
|
|
21
|
+
export * from './mcp-diagram-tool-handler-registry';
|
|
22
|
+
export * from './mcp-handler-shared';
|
|
23
|
+
export * from './mcp-http-transport';
|
|
24
|
+
export * from './mcp-id-alias-service';
|
|
25
|
+
export * from './mcp-input-schemas';
|
|
26
|
+
export * from './mcp-label-provider';
|
|
27
|
+
export * from './mcp-log-level-registry';
|
|
28
|
+
export * from './mcp-logger';
|
|
29
|
+
export * from './mcp-mime-types';
|
|
30
|
+
export * from './mcp-options';
|
|
31
|
+
export * from './mcp-progress-reporter';
|
|
32
|
+
export * from './mcp-prompt-handler';
|
|
33
|
+
export * from './mcp-request-context';
|
|
34
|
+
export * from './mcp-resource-handler';
|
|
35
|
+
export * from './mcp-server-launcher';
|
|
36
|
+
export * from './mcp-session';
|
|
37
|
+
export * from './mcp-tool-handler';
|
|
38
|
+
|
|
39
|
+
// `mcp-diagram-module` and `mcp-server-module` are intentionally not re-exported here —
|
|
40
|
+
// they import handler classes from `../resources` / `../tools`, which would create a circular
|
|
41
|
+
// import chain through this barrel. They are re-exported from the package root (`src/index.ts`)
|
|
42
|
+
// after the handler barrels finish initializing.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { Logger } from '@eclipse-glsp/server';
|
|
18
|
+
import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
|
|
19
|
+
import { expect } from 'chai';
|
|
20
|
+
import { LruEventStore } from './lru-event-store';
|
|
21
|
+
|
|
22
|
+
function jsonRpc(id: number): JSONRPCMessage {
|
|
23
|
+
return { jsonrpc: '2.0', id, result: { value: id } };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe('LruEventStore', () => {
|
|
27
|
+
it('rejects an invalid limit (< 1)', () => {
|
|
28
|
+
expect(() => new LruEventStore(0)).to.throw(/limit must be >= 1/);
|
|
29
|
+
expect(() => new LruEventStore(-5)).to.throw(/limit must be >= 1/);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('storeEvent returns a streamId-prefixed event id', async () => {
|
|
33
|
+
const store = new LruEventStore();
|
|
34
|
+
const id = await store.storeEvent('stream-A', jsonRpc(1));
|
|
35
|
+
expect(id.split('_')[0]).to.equal('stream-A');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('evicts the oldest event once the cap is exceeded', async () => {
|
|
39
|
+
const store = new LruEventStore(3);
|
|
40
|
+
const id1 = await store.storeEvent('s', jsonRpc(1));
|
|
41
|
+
const id2 = await store.storeEvent('s', jsonRpc(2));
|
|
42
|
+
await store.storeEvent('s', jsonRpc(3));
|
|
43
|
+
|
|
44
|
+
expect(store.size).to.equal(3);
|
|
45
|
+
|
|
46
|
+
// Adding a 4th event evicts the oldest (id1).
|
|
47
|
+
const id4 = await store.storeEvent('s', jsonRpc(4));
|
|
48
|
+
expect(store.size).to.equal(3);
|
|
49
|
+
|
|
50
|
+
// Replay since id1 → can't find it (evicted) → returns ''.
|
|
51
|
+
const replayed: string[] = [];
|
|
52
|
+
const streamId = await store.replayEventsAfter(id1, {
|
|
53
|
+
send: async eventId => {
|
|
54
|
+
replayed.push(eventId);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
expect(streamId).to.equal(''); // id1 has been evicted
|
|
58
|
+
expect(replayed).to.have.lengthOf(0);
|
|
59
|
+
|
|
60
|
+
// Replay since id2 still works — id3 (still in store) and id4 are sent in order.
|
|
61
|
+
const replayedFromId2: string[] = [];
|
|
62
|
+
await store.replayEventsAfter(id2, {
|
|
63
|
+
send: async eventId => {
|
|
64
|
+
replayedFromId2.push(eventId);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
expect(replayedFromId2).to.have.lengthOf(2);
|
|
68
|
+
expect(replayedFromId2[1]).to.equal(id4);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('replays only events from the same stream after the lastEventId', async () => {
|
|
72
|
+
const store = new LruEventStore();
|
|
73
|
+
const a1 = await store.storeEvent('A', jsonRpc(1));
|
|
74
|
+
await store.storeEvent('B', jsonRpc(2)); // different stream — must be skipped
|
|
75
|
+
const a3 = await store.storeEvent('A', jsonRpc(3));
|
|
76
|
+
const a4 = await store.storeEvent('A', jsonRpc(4));
|
|
77
|
+
|
|
78
|
+
const replayed: Array<{ id: string; msg: JSONRPCMessage }> = [];
|
|
79
|
+
const streamId = await store.replayEventsAfter(a1, {
|
|
80
|
+
send: async (id, msg) => {
|
|
81
|
+
replayed.push({ id, msg });
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
expect(streamId).to.equal('A');
|
|
86
|
+
expect(replayed.map(e => e.id)).to.deep.equal([a3, a4]);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('returns "" when lastEventId is unknown', async () => {
|
|
90
|
+
const store = new LruEventStore();
|
|
91
|
+
await store.storeEvent('A', jsonRpc(1));
|
|
92
|
+
|
|
93
|
+
const streamId = await store.replayEventsAfter('A_999_xxx', {
|
|
94
|
+
send: async () => {
|
|
95
|
+
throw new Error('should not be called');
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
expect(streamId).to.equal('');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('logs a cap-eviction warn when replaying an evicted last-event-id', async () => {
|
|
103
|
+
const warns: string[] = [];
|
|
104
|
+
const logger = { warn: (message: string) => warns.push(message) } as unknown as Logger;
|
|
105
|
+
const store = new LruEventStore(2, logger);
|
|
106
|
+
const evictedId = await store.storeEvent('s', jsonRpc(1));
|
|
107
|
+
await store.storeEvent('s', jsonRpc(2));
|
|
108
|
+
await store.storeEvent('s', jsonRpc(3));
|
|
109
|
+
|
|
110
|
+
const streamId = await store.replayEventsAfter(evictedId, {
|
|
111
|
+
send: async () => {
|
|
112
|
+
throw new Error('should not be called');
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
expect(streamId).to.equal('');
|
|
117
|
+
expect(warns).to.have.lengthOf(1);
|
|
118
|
+
expect(warns[0]).to.match(/Replay miss/);
|
|
119
|
+
expect(warns[0]).to.include('Cap is 2');
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { Logger } from '@eclipse-glsp/server';
|
|
18
|
+
import { EventId, EventStore, StreamId } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
19
|
+
import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* In-memory `EventStore` with a bounded LRU cap, replacing the SDK's `InMemoryEventStore`
|
|
23
|
+
* (which is unbounded and explicitly intended only for examples).
|
|
24
|
+
*
|
|
25
|
+
* Resumability via `Last-Event-ID` requires that historical events stay reachable. Without a
|
|
26
|
+
* cap, the underlying `Map` grows linearly with `MCP message volume × server uptime` — fine
|
|
27
|
+
* for local-dev, a slow leak for daemonised / multi-user / CI deployments.
|
|
28
|
+
*
|
|
29
|
+
* Eviction shape: insert-order LRU. JS `Map` already preserves insertion order, so newer
|
|
30
|
+
* events sit at the tail and `keys().next()` returns the oldest. On overflow we delete the
|
|
31
|
+
* oldest — no timer, no periodic sweep, no `dispose()` plumbing required. The cap must be
|
|
32
|
+
* comfortably larger than the worst-case in-flight event count (per-client × concurrent-clients
|
|
33
|
+
* × disconnect-window), or a client reconnecting with a stale `Last-Event-ID` will find its
|
|
34
|
+
* resume point already evicted.
|
|
35
|
+
*
|
|
36
|
+
* The event-id format mirrors the SDK's example impl (`<streamId>_<timestamp>_<random>`) so
|
|
37
|
+
* `replayEventsAfter` can extract the stream id with the same `split('_')[0]` trick.
|
|
38
|
+
*/
|
|
39
|
+
export class LruEventStore implements EventStore {
|
|
40
|
+
static readonly DEFAULT_LIMIT = 10_000;
|
|
41
|
+
|
|
42
|
+
protected readonly events = new Map<EventId, { streamId: StreamId; message: JSONRPCMessage }>();
|
|
43
|
+
protected readonly limit: number;
|
|
44
|
+
protected readonly logger?: Logger;
|
|
45
|
+
|
|
46
|
+
constructor(limit: number = LruEventStore.DEFAULT_LIMIT, logger?: Logger) {
|
|
47
|
+
if (limit < 1) {
|
|
48
|
+
throw new Error(`LruEventStore limit must be >= 1, got ${limit}`);
|
|
49
|
+
}
|
|
50
|
+
this.limit = limit;
|
|
51
|
+
this.logger = logger;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Current event count. Exposed for tests. */
|
|
55
|
+
get size(): number {
|
|
56
|
+
return this.events.size;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async storeEvent(streamId: StreamId, message: JSONRPCMessage): Promise<EventId> {
|
|
60
|
+
// Format: `<streamId>_<unixMs>_<8-char-base36-random>`. The leading `streamId` lets
|
|
61
|
+
// `replayEventsAfter` recover the stream via `split('_')[0]` without a side table; the
|
|
62
|
+
// timestamp + random suffix make ids globally unique across concurrent emits.
|
|
63
|
+
const eventId = `${streamId}_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
|
|
64
|
+
this.events.set(eventId, { streamId, message });
|
|
65
|
+
if (this.events.size > this.limit) {
|
|
66
|
+
const oldest = this.events.keys().next().value;
|
|
67
|
+
if (oldest !== undefined) {
|
|
68
|
+
this.events.delete(oldest);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return eventId;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async replayEventsAfter(
|
|
75
|
+
lastEventId: EventId,
|
|
76
|
+
{ send }: { send: (eventId: EventId, message: JSONRPCMessage) => Promise<void> }
|
|
77
|
+
): Promise<StreamId> {
|
|
78
|
+
if (!lastEventId) {
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
if (!this.events.has(lastEventId)) {
|
|
82
|
+
// Cap-eviction race: warn so adopters can tune `eventStoreLimit` upward.
|
|
83
|
+
this.logger?.warn(
|
|
84
|
+
`[LruEventStore] Replay miss for last-event-id '${lastEventId}'. ` +
|
|
85
|
+
`Cap is ${this.limit}; consider increasing \`eventStoreLimit\` if this fires under normal load.`
|
|
86
|
+
);
|
|
87
|
+
return '';
|
|
88
|
+
}
|
|
89
|
+
const streamId = lastEventId.split('_')[0];
|
|
90
|
+
if (!streamId) {
|
|
91
|
+
return '';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Map iteration is insertion-order — equivalent to the SDK example's `localeCompare`
|
|
95
|
+
// sort under our id format, but cheaper and not dependent on the lexicographic-vs-
|
|
96
|
+
// chronological coincidence of the timestamp segment.
|
|
97
|
+
let foundLast = false;
|
|
98
|
+
for (const [eventId, { streamId: evtStreamId, message }] of this.events) {
|
|
99
|
+
if (evtStreamId !== streamId) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (eventId === lastEventId) {
|
|
103
|
+
foundLast = true;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (foundLast) {
|
|
107
|
+
await send(eventId, message);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return streamId;
|
|
111
|
+
}
|
|
112
|
+
}
|