@hydranium/glsp-server 1.0.0-next.31 → 1.0.0-next.315
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -88
- package/lib/browser/start-glsp-server-in-worker.d.ts +43 -42
- package/lib/browser/start-glsp-server-in-worker.d.ts.map +1 -1
- package/lib/browser/start-glsp-server-in-worker.js +62 -13
- package/lib/browser/start-glsp-server-in-worker.js.map +1 -1
- package/lib/command/diagram-edit-dropped-error.d.ts +31 -0
- package/lib/command/diagram-edit-dropped-error.d.ts.map +1 -0
- package/lib/command/diagram-edit-dropped-error.js +48 -0
- package/lib/command/diagram-edit-dropped-error.js.map +1 -0
- package/lib/command/hydranium-glsp-command-stack.d.ts +33 -0
- package/lib/command/hydranium-glsp-command-stack.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-command-stack.js +63 -0
- package/lib/command/hydranium-glsp-command-stack.js.map +1 -0
- package/lib/command/hydranium-glsp-operation-action-handler.d.ts +64 -0
- package/lib/command/hydranium-glsp-operation-action-handler.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-operation-action-handler.js +142 -0
- package/lib/command/hydranium-glsp-operation-action-handler.js.map +1 -0
- package/lib/command/hydranium-glsp-operation-command.d.ts +250 -0
- package/lib/command/hydranium-glsp-operation-command.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-operation-command.js +491 -0
- package/lib/command/hydranium-glsp-operation-command.js.map +1 -0
- package/lib/command/hydranium-glsp-recording-command.d.ts +26 -87
- package/lib/command/hydranium-glsp-recording-command.d.ts.map +1 -1
- package/lib/command/hydranium-glsp-recording-command.js +40 -117
- package/lib/command/hydranium-glsp-recording-command.js.map +1 -1
- package/lib/command/hydranium-glsp-undo-redo-action-handler.d.ts +23 -0
- package/lib/command/hydranium-glsp-undo-redo-action-handler.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-undo-redo-action-handler.js +41 -0
- package/lib/command/hydranium-glsp-undo-redo-action-handler.js.map +1 -0
- package/lib/command/index.d.ts +5 -0
- package/lib/command/index.d.ts.map +1 -1
- package/lib/command/index.js +5 -0
- package/lib/command/index.js.map +1 -1
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts +1 -1
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts.map +1 -1
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js +2 -2
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js.map +1 -1
- package/lib/dispatcher/server-action-dispatcher.d.ts +25 -24
- package/lib/dispatcher/server-action-dispatcher.d.ts.map +1 -1
- package/lib/dispatcher/server-action-dispatcher.js +38 -26
- package/lib/dispatcher/server-action-dispatcher.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts +35 -59
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts.map +1 -1
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.js +60 -71
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.js.map +1 -1
- package/lib/launcher/drop-notifications-to-gone-client.d.ts +23 -0
- package/lib/launcher/drop-notifications-to-gone-client.d.ts.map +1 -0
- package/lib/launcher/drop-notifications-to-gone-client.js +43 -0
- package/lib/launcher/drop-notifications-to-gone-client.js.map +1 -0
- package/lib/launcher/glsp-app-module.d.ts +1 -2
- package/lib/launcher/glsp-app-module.d.ts.map +1 -1
- package/lib/launcher/glsp-app-module.js.map +1 -1
- package/lib/launcher/glsp-connection-logger.d.ts +19 -0
- package/lib/launcher/glsp-connection-logger.d.ts.map +1 -0
- package/lib/launcher/glsp-connection-logger.js +24 -0
- package/lib/launcher/glsp-connection-logger.js.map +1 -0
- package/lib/launcher/glsp-server-overrides.d.ts +10 -8
- package/lib/launcher/glsp-server-overrides.d.ts.map +1 -1
- package/lib/launcher/glsp-server-overrides.js +25 -11
- package/lib/launcher/glsp-server-overrides.js.map +1 -1
- package/lib/launcher/hydranium-glsp-server.d.ts +60 -15
- package/lib/launcher/hydranium-glsp-server.d.ts.map +1 -1
- package/lib/launcher/hydranium-glsp-server.js +145 -22
- package/lib/launcher/hydranium-glsp-server.js.map +1 -1
- package/lib/launcher/index.d.ts +2 -0
- package/lib/launcher/index.d.ts.map +1 -1
- package/lib/launcher/index.js +5 -4
- package/lib/launcher/index.js.map +1 -1
- package/lib/logging/glsp-client-logger.d.ts +10 -6
- package/lib/logging/glsp-client-logger.d.ts.map +1 -1
- package/lib/logging/glsp-client-logger.js +14 -7
- package/lib/logging/glsp-client-logger.js.map +1 -1
- package/lib/messages/index.d.ts +11 -6
- package/lib/messages/index.d.ts.map +1 -1
- package/lib/messages/index.js +11 -6
- package/lib/messages/index.js.map +1 -1
- package/lib/node/start-glsp-server.d.ts +50 -15
- package/lib/node/start-glsp-server.d.ts.map +1 -1
- package/lib/node/start-glsp-server.js +97 -30
- package/lib/node/start-glsp-server.js.map +1 -1
- package/lib/state/abstract-hydranium-glsp-state.d.ts +326 -102
- package/lib/state/abstract-hydranium-glsp-state.d.ts.map +1 -1
- package/lib/state/abstract-hydranium-glsp-state.js +529 -139
- package/lib/state/abstract-hydranium-glsp-state.js.map +1 -1
- package/lib/state/diagram-status.d.ts +38 -0
- package/lib/state/diagram-status.d.ts.map +1 -0
- package/lib/state/diagram-status.js +27 -0
- package/lib/state/diagram-status.js.map +1 -0
- package/lib/state/full-text-hydranium-glsp-state.d.ts +22 -9
- package/lib/state/full-text-hydranium-glsp-state.d.ts.map +1 -1
- package/lib/state/full-text-hydranium-glsp-state.js +45 -18
- package/lib/state/full-text-hydranium-glsp-state.js.map +1 -1
- package/lib/state/hydranium-glsp-index.d.ts +40 -29
- package/lib/state/hydranium-glsp-index.d.ts.map +1 -1
- package/lib/state/hydranium-glsp-index.js +82 -45
- package/lib/state/hydranium-glsp-index.js.map +1 -1
- package/lib/state/hydranium-shared-core-services.d.ts +16 -29
- package/lib/state/hydranium-shared-core-services.d.ts.map +1 -1
- package/lib/state/hydranium-shared-core-services.js +15 -28
- package/lib/state/hydranium-shared-core-services.js.map +1 -1
- package/lib/state/index.d.ts +1 -0
- package/lib/state/index.d.ts.map +1 -1
- package/lib/state/index.js +1 -0
- package/lib/state/index.js.map +1 -1
- package/lib/state/model-ready-timeout-error.d.ts.map +1 -1
- package/lib/state/model-ready-timeout-error.js.map +1 -1
- package/lib/state/reconcile-source-model-write.d.ts +13 -27
- package/lib/state/reconcile-source-model-write.d.ts.map +1 -1
- package/lib/state/reconcile-source-model-write.js +44 -32
- package/lib/state/reconcile-source-model-write.js.map +1 -1
- package/lib/state/reconciling-multi-document-glsp-state.d.ts +125 -69
- package/lib/state/reconciling-multi-document-glsp-state.d.ts.map +1 -1
- package/lib/state/reconciling-multi-document-glsp-state.js +242 -100
- package/lib/state/reconciling-multi-document-glsp-state.js.map +1 -1
- package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts +36 -28
- package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts.map +1 -1
- package/lib/state/reconciling-transfer-hydranium-glsp-state.js +59 -42
- package/lib/state/reconciling-transfer-hydranium-glsp-state.js.map +1 -1
- package/lib/status/diagram-status-reporter.d.ts +44 -0
- package/lib/status/diagram-status-reporter.d.ts.map +1 -0
- package/lib/status/diagram-status-reporter.js +88 -0
- package/lib/status/diagram-status-reporter.js.map +1 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.d.ts +27 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.d.ts.map +1 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.js +52 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.js.map +1 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.d.ts +27 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.d.ts.map +1 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.js +53 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.js.map +1 -0
- package/lib/status/index.d.ts +12 -0
- package/lib/status/index.d.ts.map +1 -0
- package/lib/status/index.js +12 -0
- package/lib/status/index.js.map +1 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.d.ts +30 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.d.ts.map +1 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.js +47 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.js.map +1 -0
- package/lib/storage/hydranium-glsp-storage.d.ts +324 -143
- package/lib/storage/hydranium-glsp-storage.d.ts.map +1 -1
- package/lib/storage/hydranium-glsp-storage.js +569 -213
- package/lib/storage/hydranium-glsp-storage.js.map +1 -1
- package/lib/storage/index.d.ts +2 -1
- package/lib/storage/index.d.ts.map +1 -1
- package/lib/storage/index.js +2 -1
- package/lib/storage/index.js.map +1 -1
- package/lib/storage/save-delivery-policy.d.ts +51 -0
- package/lib/storage/save-delivery-policy.d.ts.map +1 -0
- package/lib/storage/{save-conflict-policy.js → save-delivery-policy.js} +7 -8
- package/lib/storage/save-delivery-policy.js.map +1 -0
- package/lib/submission/hydranium-glsp-submission-handler.d.ts +44 -4
- package/lib/submission/hydranium-glsp-submission-handler.d.ts.map +1 -1
- package/lib/submission/hydranium-glsp-submission-handler.js +82 -6
- package/lib/submission/hydranium-glsp-submission-handler.js.map +1 -1
- package/lib/testing/glsp-harness.d.ts +34 -7
- package/lib/testing/glsp-harness.d.ts.map +1 -1
- package/lib/testing/glsp-harness.js +47 -19
- package/lib/testing/glsp-harness.js.map +1 -1
- package/lib/validation/diagnostic-markers.d.ts +3 -3
- package/lib/validation/diagnostic-markers.d.ts.map +1 -1
- package/lib/validation/diagnostic-markers.js +1 -1
- package/lib/validation/diagnostic-markers.js.map +1 -1
- package/lib/validation/hydranium-glsp-model-validator.d.ts +1 -2
- package/lib/validation/hydranium-glsp-model-validator.d.ts.map +1 -1
- package/lib/validation/hydranium-glsp-model-validator.js +1 -1
- package/lib/validation/hydranium-glsp-model-validator.js.map +1 -1
- package/package.json +31 -52
- package/src/browser/start-glsp-server-in-worker.ts +79 -51
- package/src/command/diagram-edit-dropped-error.ts +51 -0
- package/src/command/hydranium-glsp-command-stack.ts +47 -0
- package/src/command/hydranium-glsp-operation-action-handler.ts +141 -0
- package/src/command/hydranium-glsp-operation-command.ts +602 -0
- package/src/command/hydranium-glsp-recording-command.ts +40 -121
- package/src/command/hydranium-glsp-undo-redo-action-handler.ts +29 -0
- package/src/command/index.ts +10 -0
- package/src/computed-bounds/hydranium-glsp-computed-bounds-action-handler.ts +2 -2
- package/src/dispatcher/server-action-dispatcher.ts +39 -31
- package/src/index.ts +1 -0
- package/src/launcher/abstract-hydranium-glsp-diagram-module.ts +79 -91
- package/src/launcher/drop-notifications-to-gone-client.ts +47 -0
- package/src/launcher/glsp-app-module.ts +1 -2
- package/src/launcher/glsp-connection-logger.ts +27 -0
- package/src/launcher/glsp-server-overrides.ts +27 -11
- package/src/launcher/hydranium-glsp-server.ts +153 -23
- package/src/launcher/index.ts +5 -4
- package/src/logging/glsp-client-logger.ts +16 -9
- package/src/messages/index.ts +16 -6
- package/src/node/start-glsp-server.ts +133 -40
- package/src/state/abstract-hydranium-glsp-state.ts +609 -154
- package/src/state/diagram-status.ts +41 -0
- package/src/state/full-text-hydranium-glsp-state.ts +46 -18
- package/src/state/hydranium-glsp-index.ts +85 -41
- package/src/state/hydranium-shared-core-services.ts +16 -29
- package/src/state/index.ts +1 -0
- package/src/state/reconcile-source-model-write.ts +51 -53
- package/src/state/reconciling-multi-document-glsp-state.ts +276 -102
- package/src/state/reconciling-transfer-hydranium-glsp-state.ts +67 -45
- package/src/status/diagram-status-reporter.ts +106 -0
- package/src/status/hydranium-glsp-request-model-action-handler.ts +43 -0
- package/src/status/hydranium-glsp-set-edit-mode-action-handler.ts +38 -0
- package/src/status/index.ts +12 -0
- package/src/storage/hydranium-glsp-request-save-model-action-handler.ts +40 -0
- package/src/storage/hydranium-glsp-storage.ts +647 -223
- package/src/storage/index.ts +2 -1
- package/src/storage/save-delivery-policy.ts +49 -0
- package/src/submission/hydranium-glsp-submission-handler.ts +91 -5
- package/src/testing/glsp-harness.ts +67 -25
- package/src/validation/diagnostic-markers.ts +3 -3
- package/src/validation/hydranium-glsp-model-validator.ts +4 -5
- package/lib/storage/save-conflict-policy.d.ts +0 -56
- package/lib/storage/save-conflict-policy.d.ts.map +0 -1
- package/lib/storage/save-conflict-policy.js.map +0 -1
- package/src/storage/save-conflict-policy.ts +0 -52
|
@@ -0,0 +1,27 @@
|
|
|
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 MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import type { Logger as GlspLogger } from '@eclipse-glsp/server';
|
|
11
|
+
import type { Logger as ConnectionLogger } from 'vscode-jsonrpc';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A GLSP logger in the shape a `vscode-jsonrpc` connection logs to. A launcher
|
|
15
|
+
* that overrides `createConnection` passes it over its injected `logger`, or
|
|
16
|
+
* the connection logs to `console` or nowhere instead of the adopter's logger.
|
|
17
|
+
* GLSP's logger has no `log`; the connection's `log` lines go to `info`, the
|
|
18
|
+
* threshold the framework's own `Logger.log` emits at.
|
|
19
|
+
*/
|
|
20
|
+
export function createGlspConnectionLogger(logger: GlspLogger): ConnectionLogger {
|
|
21
|
+
return {
|
|
22
|
+
error: message => logger.error(message),
|
|
23
|
+
warn: message => logger.warn(message),
|
|
24
|
+
info: message => logger.info(message),
|
|
25
|
+
log: message => logger.info(message)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
|
|
10
|
-
import { GLSPServer } from '@eclipse-glsp/server';
|
|
10
|
+
import { DefaultGLSPServer, GLSPServer, LoggerFactory } from '@eclipse-glsp/server';
|
|
11
11
|
import { ContainerModule } from 'inversify';
|
|
12
12
|
import { HydraniumGlspServer } from './hydranium-glsp-server.js';
|
|
13
13
|
|
|
@@ -18,15 +18,17 @@ import { HydraniumGlspServer } from './hydranium-glsp-server.js';
|
|
|
18
18
|
*
|
|
19
19
|
* **The tier matters, and the app container cannot stand in for it.** GLSP's
|
|
20
20
|
* launcher creates the server container as a child and loads the adopter's
|
|
21
|
-
* `ServerModule` into it
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* reach this symbol.
|
|
21
|
+
* `ServerModule` into it. The framework's server is a singleton of that
|
|
22
|
+
* container; bound in the app container, every connected application would
|
|
23
|
+
* share one server.
|
|
25
24
|
*
|
|
26
|
-
* **
|
|
27
|
-
* `GLSPServer
|
|
28
|
-
*
|
|
29
|
-
*
|
|
25
|
+
* **An adopter's server is kept when it extends {@link HydraniumGlspServer}.**
|
|
26
|
+
* Any other `GLSPServer` the adopter's `ServerModule` binds, upstream's default
|
|
27
|
+
* included, is replaced when the container first creates it, so a server that
|
|
28
|
+
* extends upstream's directly is discarded, with a warning naming its class.
|
|
29
|
+
* The replacement happens on activation because `rebind` would replace an
|
|
30
|
+
* adopter's subclass as well; the discarded server is constructed once and
|
|
31
|
+
* never used.
|
|
30
32
|
*
|
|
31
33
|
* Keeping this out of the adopter's hands is the point: an adopter passes their
|
|
32
34
|
* own `ServerModule` in, so anything they must add themselves is a fix the
|
|
@@ -40,7 +42,21 @@ import { HydraniumGlspServer } from './hydranium-glsp-server.js';
|
|
|
40
42
|
* a further adopter subclass moves it again.
|
|
41
43
|
*/
|
|
42
44
|
export function createGlspServerOverrides(): ContainerModule {
|
|
43
|
-
return new ContainerModule((
|
|
44
|
-
|
|
45
|
+
return new ContainerModule((bind, _unbind, _isBound, _rebind, _unbindAsync, onActivation) => {
|
|
46
|
+
bind(HydraniumGlspServer).toSelf().inSingletonScope();
|
|
47
|
+
onActivation<GLSPServer>(GLSPServer, (context, server) => {
|
|
48
|
+
if (server instanceof HydraniumGlspServer) {
|
|
49
|
+
return server;
|
|
50
|
+
}
|
|
51
|
+
if (server.constructor !== DefaultGLSPServer) {
|
|
52
|
+
context.container
|
|
53
|
+
.get<LoggerFactory>(LoggerFactory)('HydraniumGlspServer')
|
|
54
|
+
.warn(
|
|
55
|
+
`Replacing the bound GLSP server ${server.constructor.name} with HydraniumGlspServer; ` +
|
|
56
|
+
'extend HydraniumGlspServer to keep its behaviour.'
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return context.container.get(HydraniumGlspServer);
|
|
60
|
+
});
|
|
45
61
|
});
|
|
46
62
|
}
|
|
@@ -8,42 +8,122 @@
|
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
|
+
type ActionMessage,
|
|
12
|
+
ClientAction,
|
|
11
13
|
type ClientSession,
|
|
12
14
|
DefaultGLSPServer,
|
|
13
15
|
GLSPServerError,
|
|
16
|
+
type InitializeClientSessionParameters,
|
|
17
|
+
MessageAction,
|
|
14
18
|
RejectAction,
|
|
15
|
-
|
|
16
|
-
type ResponseAction
|
|
19
|
+
RequestAction,
|
|
20
|
+
type ResponseAction,
|
|
21
|
+
SourceModelStorage
|
|
17
22
|
} from '@eclipse-glsp/server';
|
|
23
|
+
import { describeErrorWithStack, RequestSaveModelAction } from '@hydranium/protocol';
|
|
18
24
|
import { injectable } from 'inversify';
|
|
25
|
+
import { logActionFailure } from '../command/diagram-edit-dropped-error.js';
|
|
26
|
+
import { HydraniumGlspStorage } from '../storage/hydranium-glsp-storage.js';
|
|
19
27
|
|
|
20
28
|
/**
|
|
21
29
|
* The GLSP server the framework binds in place of upstream's
|
|
22
30
|
* {@link DefaultGLSPServer}, so a failed REQUEST reaches its reader with the
|
|
23
|
-
* text the thrower wrote
|
|
31
|
+
* text the thrower wrote, and a diagram whose connection ends keeps its unsaved
|
|
32
|
+
* text for the release grace (see {@link shutdown}).
|
|
24
33
|
*
|
|
25
34
|
* **What breaks without it.** Upstream projects a failing request's detail as
|
|
26
35
|
* `error.cause?.toString()` whenever the error is a {@link GLSPServerError},
|
|
27
36
|
* and that one value feeds both the server log and the client's
|
|
28
37
|
* {@link RejectAction}. A {@link GLSPServerError} carrying no `cause` therefore
|
|
29
|
-
* reaches
|
|
30
|
-
* while a plain `Error` survives,
|
|
31
|
-
* itself. The typed error is the trap,
|
|
38
|
+
* reaches its readers as `undefined` — the log line and the client's
|
|
39
|
+
* action-dispatcher warning both print it — while a plain `Error` survives,
|
|
40
|
+
* because the other branch reads the error itself. The typed error is the trap,
|
|
41
|
+
* and it is the one upstream's own
|
|
32
42
|
* `getOrThrow` helper raises: that helper's signature cannot pass a `cause`, so
|
|
33
43
|
* an adopter using the sanctioned helper has no fix available on their side.
|
|
34
44
|
* Restating the cause at each throw site is the alternative, and it costs
|
|
35
45
|
* every adopter a rule they must know and cannot apply to `getOrThrow`.
|
|
36
46
|
*
|
|
37
|
-
* Only the REQUEST path needs this.
|
|
38
|
-
*
|
|
47
|
+
* Only the REQUEST path needs this. A non-request action fails through
|
|
48
|
+
* {@link handleProcessError}, which reads `message` directly; it and
|
|
49
|
+
* {@link process} are lifted for their logging only.
|
|
39
50
|
*
|
|
40
|
-
*
|
|
41
|
-
* {@link DefaultGLSPServer}
|
|
42
|
-
*
|
|
43
|
-
* server
|
|
51
|
+
* An adopter who binds their own GLSP server extends this class rather than
|
|
52
|
+
* {@link DefaultGLSPServer}: the framework's server-container override keeps a
|
|
53
|
+
* server that extends this one and replaces any other, so a subclass of
|
|
54
|
+
* upstream's server is discarded, and with it both behaviours.
|
|
44
55
|
*/
|
|
45
56
|
@injectable()
|
|
46
57
|
export class HydraniumGlspServer extends DefaultGLSPServer {
|
|
58
|
+
/**
|
|
59
|
+
* End each diagram's client session as lost rather than closed, before
|
|
60
|
+
* upstream disposes the sessions, so its unsaved text waits out the release
|
|
61
|
+
* grace for the client to reconnect. A shutdown is how the client's
|
|
62
|
+
* connection ending reaches the server; a client that stops on purpose
|
|
63
|
+
* shuts the server down the same way, and its diagrams are held as well.
|
|
64
|
+
*/
|
|
65
|
+
override shutdown(): void {
|
|
66
|
+
for (const session of this.clientSessions.values()) {
|
|
67
|
+
const storage = session.container.isBound(SourceModelStorage) ? session.container.get(SourceModelStorage) : undefined;
|
|
68
|
+
if (storage instanceof HydraniumGlspStorage) {
|
|
69
|
+
storage.dispose('lost');
|
|
70
|
+
} else if (storage) {
|
|
71
|
+
this.logger.debug(`Shutdown leaves ending ${session.id} to its storage, which is not a HydraniumGlspStorage`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
super.shutdown();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* End a session the id still has before initializing it again. A model
|
|
79
|
+
* source initializes once, so a second initialize under one id is a new
|
|
80
|
+
* widget, a reopened tab whose closed predecessor's dispose never arrived;
|
|
81
|
+
* upstream would hand it that stale session.
|
|
82
|
+
*/
|
|
83
|
+
override async initializeClientSession(params: InitializeClientSessionParameters): Promise<void> {
|
|
84
|
+
if (!this.clientSessions.has(params.clientSessionId)) {
|
|
85
|
+
return super.initializeClientSession(params);
|
|
86
|
+
}
|
|
87
|
+
this.logger.debug(`Client session ${params.clientSessionId} initialized again before its dispose arrived; ending the old one`);
|
|
88
|
+
// Not awaited before the initialize: both drop and set the session before
|
|
89
|
+
// their first await, and the model request that follows is read without
|
|
90
|
+
// waiting for this one to settle.
|
|
91
|
+
const disposed = this.disposeClientSession({ clientSessionId: params.clientSessionId });
|
|
92
|
+
const initialized = super.initializeClientSession(params);
|
|
93
|
+
await Promise.all([disposed, initialized]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Lifted from `@eclipse-glsp/server` 2.7.0's {@link DefaultGLSPServer.process}:
|
|
98
|
+
* each action is logged at `debug` rather than `info`, and an action that
|
|
99
|
+
* fails once its session has ended, which disposing the session's dispatcher
|
|
100
|
+
* does to every action it holds, is logged at `debug` and told to no client,
|
|
101
|
+
* since the one that sent it has gone. The accompanying test pins upstream's
|
|
102
|
+
* source.
|
|
103
|
+
*/
|
|
104
|
+
override process(message: ActionMessage): void {
|
|
105
|
+
this.validateServerInitialized();
|
|
106
|
+
this.logger.debug(`process [action=${message.action.kind}, clientId=${message.clientId}]`);
|
|
107
|
+
const clientSessionId = message.clientId;
|
|
108
|
+
const clientSession = this.clientSessions.get(clientSessionId);
|
|
109
|
+
if (!clientSession) {
|
|
110
|
+
throw new Error(`No client session has been initialized for client id: ${clientSessionId}`);
|
|
111
|
+
}
|
|
112
|
+
const action = message.action;
|
|
113
|
+
ClientAction.mark(action);
|
|
114
|
+
if (RequestAction.is(action)) {
|
|
115
|
+
void this.handleClientRequest(clientSession, action, message.clientId);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
clientSession.actionDispatcher.dispatch(action).catch((error: unknown) => {
|
|
119
|
+
if (this.clientSessions.get(clientSessionId) === clientSession) {
|
|
120
|
+
void this.handleProcessError(message, error);
|
|
121
|
+
} else {
|
|
122
|
+
this.logger.debug(`Action '${action.kind}' ended with its session: ${describeErrorWithStack(error)}`);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
47
127
|
/**
|
|
48
128
|
* The detail projected into the client's {@link RejectAction} and the server
|
|
49
129
|
* log when a request fails.
|
|
@@ -61,11 +141,40 @@ export class HydraniumGlspServer extends DefaultGLSPServer {
|
|
|
61
141
|
}
|
|
62
142
|
|
|
63
143
|
/**
|
|
64
|
-
* Lifted
|
|
144
|
+
* Lifted from `@eclipse-glsp/server` 2.7.0's
|
|
145
|
+
* {@link DefaultGLSPServer.handleProcessError}, logging the failure once
|
|
146
|
+
* with {@link logActionFailure} where upstream logs the action and the
|
|
147
|
+
* reason as two lines.
|
|
148
|
+
*
|
|
149
|
+
* The notification is upstream's, text and all, and this body does not
|
|
150
|
+
* track upstream: the accompanying test pins upstream's source as it does
|
|
151
|
+
* for {@link handleClientRequest}.
|
|
152
|
+
*/
|
|
153
|
+
protected override handleProcessError(message: ActionMessage, reason: unknown): void {
|
|
154
|
+
const kind = message.action.kind;
|
|
155
|
+
logActionFailure(this.logger, message.action, reason);
|
|
156
|
+
let errorMsg = `Could not process action: '${kind}`;
|
|
157
|
+
let details = stringifyAsUpstream(reason);
|
|
158
|
+
if (reason instanceof GLSPServerError) {
|
|
159
|
+
details = stringifyAsUpstream(reason.cause);
|
|
160
|
+
errorMsg = reason.message;
|
|
161
|
+
}
|
|
162
|
+
this.sendToClient({ clientId: message.clientId, action: MessageAction.create(errorMsg, { severity: 'ERROR', details }) });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Lifted from `@eclipse-glsp/server` 2.7.0's
|
|
65
167
|
* {@link DefaultGLSPServer.handleClientRequest}, with the detail computation
|
|
66
|
-
* delegated to {@link requestFailureDetail}
|
|
67
|
-
*
|
|
68
|
-
*
|
|
168
|
+
* delegated to {@link requestFailureDetail}, the failure logged once with
|
|
169
|
+
* its stack, a request that fails once its session has ended logged at
|
|
170
|
+
* `debug` and answered to no client, as {@link process} treats an action,
|
|
171
|
+
* and one addition: a failed {@link RequestSaveModelAction} also
|
|
172
|
+
* raises the error notification a failed `SaveModelAction` raises, through
|
|
173
|
+
* {@link handleProcessError}, which then logs it instead. A rejection
|
|
174
|
+
* reaches only the client's log, and a Theia host only logs a rejected save,
|
|
175
|
+
* so without it a save that failed would tell the user nothing. Nothing else
|
|
176
|
+
* here — the timeout branch, the response dispatch, the nested send-failure
|
|
177
|
+
* handling — relates to either.
|
|
69
178
|
*
|
|
70
179
|
* **This body does not track upstream.** A release that changes request
|
|
71
180
|
* handling would silently not apply, on the path every request takes. There
|
|
@@ -88,17 +197,38 @@ export class HydraniumGlspServer extends DefaultGLSPServer {
|
|
|
88
197
|
this.sendResponseToClient(clientId, response);
|
|
89
198
|
}
|
|
90
199
|
} catch (error: unknown) {
|
|
200
|
+
if (this.clientSessions.get(clientSession.id) !== clientSession) {
|
|
201
|
+
this.logger.debug(`Request '${action.kind}' (${action.requestId}) ended with its session: ${describeErrorWithStack(error)}`);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
91
204
|
const detail = this.requestFailureDetail(error);
|
|
92
|
-
|
|
205
|
+
const isSave = action.kind === RequestSaveModelAction.KIND;
|
|
206
|
+
if (!isSave) {
|
|
207
|
+
this.logger.error(`Failed to handle request '${action.kind}' (${action.requestId}): ${describeErrorWithStack(error)}`);
|
|
208
|
+
}
|
|
209
|
+
// Inside the guard: `process` does not await this method, so a throw
|
|
210
|
+
// here would be an unhandled rejection.
|
|
93
211
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
212
|
+
try {
|
|
213
|
+
const reject = RejectAction.create(`Failed to handle request '${action.kind}' (${action.requestId})`, {
|
|
214
|
+
responseId: action.requestId,
|
|
215
|
+
detail
|
|
216
|
+
});
|
|
217
|
+
this.sendResponseToClient(clientId, reject);
|
|
218
|
+
} finally {
|
|
219
|
+
// Also when the reject could not be sent, since this logs the save's failure.
|
|
220
|
+
if (isSave) {
|
|
221
|
+
this.handleProcessError({ clientId, action }, error);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
99
224
|
} catch (sendError: unknown) {
|
|
100
|
-
this.logger.error(`Failed to send rejection for request '${action.requestId}'
|
|
225
|
+
this.logger.error(`Failed to send rejection for request '${action.requestId}': ${describeErrorWithStack(sendError)}`);
|
|
101
226
|
}
|
|
102
227
|
}
|
|
103
228
|
}
|
|
104
229
|
}
|
|
230
|
+
|
|
231
|
+
/** `value?.toString?.()`, as upstream projects a reason into a notification's details. */
|
|
232
|
+
function stringifyAsUpstream(value: unknown): string | undefined {
|
|
233
|
+
return (value as { toString?: () => string } | null | undefined)?.toString?.();
|
|
234
|
+
}
|
package/src/launcher/index.ts
CHANGED
|
@@ -13,10 +13,11 @@ export * from './abstract-hydranium-glsp-diagram-module.js';
|
|
|
13
13
|
// rather than upstream's — the server-container override discards a subclass of
|
|
14
14
|
// `DefaultGLSPServer`.
|
|
15
15
|
export * from './hydranium-glsp-server.js';
|
|
16
|
+
export * from './drop-notifications-to-gone-client.js';
|
|
17
|
+
export * from './glsp-connection-logger.js';
|
|
16
18
|
// The socket bringup lives in `@hydranium/glsp-server/node` and the worker
|
|
17
19
|
// bringup in `@hydranium/glsp-server/browser`, not here: each pulls the
|
|
18
20
|
// upstream build for its platform, which the portable `.` entry must stay free
|
|
19
|
-
// of.
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
// the launcher rather than its internals.
|
|
21
|
+
// of. The container overrides those two bringups share stay unexported, reached
|
|
22
|
+
// by relative import: an adopter composing a container by hand wants the
|
|
23
|
+
// launcher rather than its internals.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { type Logger as GlspLogger, LogLevel } from '@eclipse-glsp/server';
|
|
11
11
|
import { LspLogger, type LspLoggerOptions, type ServerSharedServices } from '@hydranium/core';
|
|
12
|
-
import { Logger, type LogThreshold } from '@hydranium/protocol';
|
|
12
|
+
import { describeErrorWithStack, LEVEL_ORDER, Logger, type LogThreshold } from '@hydranium/protocol';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Options accepted by {@link GlspClientLogger}. Extends
|
|
@@ -19,11 +19,11 @@ import { Logger, type LogThreshold } from '@hydranium/protocol';
|
|
|
19
19
|
export interface GlspClientLoggerOptions extends LspLoggerOptions {
|
|
20
20
|
/**
|
|
21
21
|
* Per-instance NARROWING of the framework threshold. Omit it — the default
|
|
22
|
-
* tracks
|
|
22
|
+
* tracks the framework thresholds live, which is what makes one
|
|
23
23
|
* `HYDRANIUM_LOG_LEVEL` / one LSP setting govern GLSP output too.
|
|
24
24
|
*
|
|
25
25
|
* It can only narrow, never widen, and that is not a policy choice:
|
|
26
|
-
* `AbstractLogger.send` gates every emission on
|
|
26
|
+
* `AbstractLogger.send` gates every emission on `Logger.isLevelEnabled`
|
|
27
27
|
* before it reaches the output channel, so a value more verbose than the
|
|
28
28
|
* global is silently ineffective. Set it only to make ONE component quieter
|
|
29
29
|
* than the rest.
|
|
@@ -66,8 +66,8 @@ export function glspLogLevelOf(threshold: LogThreshold): LogLevel {
|
|
|
66
66
|
* GLSP-specific concerns layered on top of {@link LspLogger}:
|
|
67
67
|
*
|
|
68
68
|
* - A {@link logLevel} field, because GLSP's `Logger` contract declares one.
|
|
69
|
-
* **It tracks the framework's
|
|
70
|
-
*
|
|
69
|
+
* **It tracks the framework's thresholds by default**, resolving them
|
|
70
|
+
* through {@link glspLogLevelOf} on every read — so
|
|
71
71
|
* `HYDRANIUM_LOG_LEVEL`, the LSP log-level setting and the Theia preference
|
|
72
72
|
* all reach GLSP output without a second knob. Assigning the field (or
|
|
73
73
|
* passing `logLevel`) pins an explicit per-instance NARROWING; see
|
|
@@ -104,9 +104,16 @@ export class GlspClientLogger extends LspLogger implements GlspLogger {
|
|
|
104
104
|
this.logLevelOverride = options.logLevel;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
/**
|
|
107
|
+
/**
|
|
108
|
+
* GLSP's `Logger.logLevel` contract; unless pinned, the more verbose of
|
|
109
|
+
* `Logger.getLevel()` and `Logger.getFileLevel()`. The process threshold
|
|
110
|
+
* alone drops GLSP lines a log file with its own threshold asks for.
|
|
111
|
+
*/
|
|
108
112
|
get logLevel(): LogLevel {
|
|
109
|
-
|
|
113
|
+
const level = Logger.getLevel();
|
|
114
|
+
const fileLevel = Logger.getFileLevel();
|
|
115
|
+
const widest = fileLevel && LEVEL_ORDER[fileLevel] > LEVEL_ORDER[level] ? fileLevel : level;
|
|
116
|
+
return this.logLevelOverride ?? glspLogLevelOf(widest);
|
|
110
117
|
}
|
|
111
118
|
|
|
112
119
|
set logLevel(level: LogLevel) {
|
|
@@ -156,10 +163,10 @@ export class GlspClientLogger extends LspLogger implements GlspLogger {
|
|
|
156
163
|
return params.length === 0 ? message : `${message} ${params.map(p => this.formatParam(p)).join(',\n')}`;
|
|
157
164
|
}
|
|
158
165
|
|
|
159
|
-
/** Format a single param: errors →
|
|
166
|
+
/** Format a single param: errors → their stack and causes; everything else → JSON.stringify(p, undefined, 4). */
|
|
160
167
|
protected formatParam(param: unknown): string {
|
|
161
168
|
if (param instanceof Error) {
|
|
162
|
-
return
|
|
169
|
+
return describeErrorWithStack(param);
|
|
163
170
|
}
|
|
164
171
|
try {
|
|
165
172
|
return JSON.stringify(param, undefined, 4);
|
package/src/messages/index.ts
CHANGED
|
@@ -10,11 +10,21 @@
|
|
|
10
10
|
/**
|
|
11
11
|
* Every user-facing message `@hydranium/glsp-server` raises.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* the
|
|
13
|
+
* **Each one is rendered AT ITS RAISE SITE**, through the shared
|
|
14
|
+
* `MessageRenderer`, because GLSP's action protocol carries no slot for an
|
|
15
|
+
* identity on any of its actions — so the identity is gone the moment a raise
|
|
16
|
+
* site formats its text, and there is nothing at the error boundary to render
|
|
17
|
+
* from. That makes this head the one place where a new message can ship
|
|
18
|
+
* unrendered without any single chokepoint noticing, which is why the package's
|
|
19
|
+
* own test suite scans for a declaration reached by `.format()` instead.
|
|
20
|
+
*
|
|
21
|
+
* The barrel is also how an adopter rendering their own diagram chrome
|
|
22
|
+
* discovers the codes exist.
|
|
18
23
|
*/
|
|
19
24
|
|
|
20
|
-
export {
|
|
25
|
+
export {
|
|
26
|
+
DIAGRAM_READONLY_PARSE_ERROR,
|
|
27
|
+
DIAGRAM_SESSION_REFUSED,
|
|
28
|
+
SAVE_TARGET_UNKNOWN,
|
|
29
|
+
SOURCE_URI_MISSING
|
|
30
|
+
} from '../storage/hydranium-glsp-storage.js';
|