@hydranium/glsp-client-theia 1.0.0-next.23 → 1.0.0-next.232
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 +59 -24
- package/lib/browser/action-dispatcher.d.ts +1 -1
- package/lib/browser/action-dispatcher.d.ts.map +1 -1
- package/lib/browser/action-dispatcher.js +1 -1
- package/lib/browser/action-dispatcher.js.map +1 -1
- package/lib/browser/client-contribution.d.ts +83 -25
- package/lib/browser/client-contribution.d.ts.map +1 -1
- package/lib/browser/client-contribution.js +225 -53
- package/lib/browser/client-contribution.js.map +1 -1
- package/lib/browser/diagram-loader.d.ts +16 -7
- package/lib/browser/diagram-loader.d.ts.map +1 -1
- package/lib/browser/diagram-loader.js +18 -10
- package/lib/browser/diagram-loader.js.map +1 -1
- package/lib/browser/diagram-only-marker-manager.d.ts.map +1 -1
- package/lib/browser/diagram-only-marker-manager.js.map +1 -1
- package/lib/browser/diagram-widget.d.ts +42 -24
- package/lib/browser/diagram-widget.d.ts.map +1 -1
- package/lib/browser/diagram-widget.js +74 -24
- package/lib/browser/diagram-widget.js.map +1 -1
- package/lib/browser/glsp-client-theia-module.d.ts +1 -1
- package/lib/browser/glsp-client-theia-module.d.ts.map +1 -1
- package/lib/browser/glsp-client-theia-module.js +3 -1
- package/lib/browser/glsp-client-theia-module.js.map +1 -1
- package/lib/browser/glsp-client.d.ts +17 -0
- package/lib/browser/glsp-client.d.ts.map +1 -0
- package/lib/browser/glsp-client.js +23 -0
- package/lib/browser/glsp-client.js.map +1 -0
- package/lib/browser/glsp-diagram-manager.d.ts +61 -0
- package/lib/browser/glsp-diagram-manager.d.ts.map +1 -1
- package/lib/browser/glsp-diagram-manager.js +126 -0
- package/lib/browser/glsp-diagram-manager.js.map +1 -1
- package/lib/browser/glsp-message-service.d.ts +8 -0
- package/lib/browser/glsp-message-service.d.ts.map +1 -1
- package/lib/browser/glsp-message-service.js +8 -0
- package/lib/browser/glsp-message-service.js.map +1 -1
- package/lib/browser/glsp-saveable.d.ts +66 -0
- package/lib/browser/glsp-saveable.d.ts.map +1 -0
- package/lib/browser/glsp-saveable.js +109 -0
- package/lib/browser/glsp-saveable.js.map +1 -0
- package/lib/browser/glsp-theia-frontend-module.d.ts.map +1 -1
- package/lib/browser/glsp-theia-frontend-module.js +4 -1
- package/lib/browser/glsp-theia-frontend-module.js.map +1 -1
- package/lib/browser/hidden-bounds-updater.d.ts +3 -5
- package/lib/browser/hidden-bounds-updater.d.ts.map +1 -1
- package/lib/browser/hidden-bounds-updater.js +8 -4
- package/lib/browser/hidden-bounds-updater.js.map +1 -1
- package/lib/browser/hydranium-glsp-diagram-configuration.d.ts.map +1 -1
- package/lib/browser/hydranium-glsp-diagram-configuration.js.map +1 -1
- package/lib/browser/index.d.ts +5 -0
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +4 -0
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/status-overlay.d.ts +23 -0
- package/lib/browser/status-overlay.d.ts.map +1 -0
- package/lib/browser/status-overlay.js +52 -0
- package/lib/browser/status-overlay.js.map +1 -0
- package/lib/browser/window-session.d.ts +57 -0
- package/lib/browser/window-session.d.ts.map +1 -0
- package/lib/browser/window-session.js +102 -0
- package/lib/browser/window-session.js.map +1 -0
- package/lib/node/connection-container-module.js.map +1 -1
- package/lib/node/glsp-server-connection-handler.d.ts +12 -11
- package/lib/node/glsp-server-connection-handler.d.ts.map +1 -1
- package/lib/node/glsp-server-connection-handler.js +12 -15
- package/lib/node/glsp-server-connection-handler.js.map +1 -1
- package/lib/testing/bind-recorder.js.map +1 -1
- package/package.json +34 -41
- package/src/browser/action-dispatcher.ts +1 -1
- package/src/browser/client-contribution.ts +250 -54
- package/src/browser/diagram-loader.ts +19 -12
- package/src/browser/diagram-widget.ts +79 -27
- package/src/browser/glsp-client-theia-module.ts +4 -2
- package/src/browser/glsp-client.ts +20 -0
- package/src/browser/glsp-diagram-manager.ts +140 -2
- package/src/browser/glsp-message-service.ts +8 -0
- package/src/browser/glsp-saveable.ts +110 -0
- package/src/browser/glsp-theia-frontend-module.ts +4 -1
- package/src/browser/hidden-bounds-updater.ts +6 -7
- package/src/browser/index.ts +9 -0
- package/src/browser/status-overlay.ts +43 -0
- package/src/browser/window-session.ts +114 -0
- package/src/node/glsp-server-connection-handler.ts +13 -15
- package/style/diagram-loading.css +2 -5
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, 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 StatusAction, StatusOverlay } from '@eclipse-glsp/client';
|
|
11
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* GLSP's status overlay, kept on the page.
|
|
15
|
+
*
|
|
16
|
+
* It inserts its element into the diagram's base div when the diagram starts,
|
|
17
|
+
* and sprotty's first render then replaces that div with its own, so the element
|
|
18
|
+
* is left detached and no status it shows is ever seen. This puts the element
|
|
19
|
+
* back into the current base div before it shows anything.
|
|
20
|
+
*/
|
|
21
|
+
@injectable()
|
|
22
|
+
export class HydraniumStatusOverlay extends StatusOverlay {
|
|
23
|
+
override handle(action: StatusAction): void {
|
|
24
|
+
this.reattach();
|
|
25
|
+
super.handle(action);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override show(...args: Parameters<StatusOverlay['show']>): void {
|
|
29
|
+
super.show(...args);
|
|
30
|
+
this.reattach();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
protected reattach(): void {
|
|
34
|
+
const container = this.containerElement as HTMLElement | undefined;
|
|
35
|
+
if (!container || container.isConnected) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const parent = this.getParentContainer();
|
|
39
|
+
if (parent) {
|
|
40
|
+
this.insertContainerIntoParent(container, parent);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, 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 { randomUuid } from '@hydranium/protocol';
|
|
11
|
+
// Not the `@theia/core/lib/browser` barrel, which touches DOM globals at load.
|
|
12
|
+
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application-contribution';
|
|
13
|
+
import { injectable, type interfaces } from '@theia/core/shared/inversify';
|
|
14
|
+
|
|
15
|
+
/** The `sessionStorage` key of the window's {@link WindowSession}. */
|
|
16
|
+
export const WINDOW_SESSION_KEY = 'hydranium.glsp.windowSession';
|
|
17
|
+
/** Holds the id of the window session the last page in the tab left, for the next page to take up. */
|
|
18
|
+
export const RELEASED_WINDOW_SESSION_KEY = 'hydranium.glsp.releasedWindowSession';
|
|
19
|
+
|
|
20
|
+
/** The window's part of every diagram client id it opens, and the token its diagrams resume with. */
|
|
21
|
+
export interface WindowSession {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly resumeToken: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isWindowSession(value: unknown): value is WindowSession {
|
|
27
|
+
return (
|
|
28
|
+
typeof value === 'object' &&
|
|
29
|
+
value !== null &&
|
|
30
|
+
typeof (value as WindowSession).id === 'string' &&
|
|
31
|
+
typeof (value as WindowSession).resumeToken === 'string'
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const WindowSessionService = Symbol('WindowSessionService');
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The page's window session: the one the last page in this tab left, so a
|
|
39
|
+
* reload resumes its diagrams, and a new one otherwise.
|
|
40
|
+
*
|
|
41
|
+
* A reload only has a session to resume on a server that outlives the page; a
|
|
42
|
+
* server started per frontend, as a Theia plugin host's is, is new after one.
|
|
43
|
+
*/
|
|
44
|
+
export interface WindowSessionService {
|
|
45
|
+
current(): WindowSession;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Keeps the window session in `sessionStorage` and hands it on only as the page
|
|
50
|
+
* leaves. A duplicated tab copies `sessionStorage` while the original page is
|
|
51
|
+
* still live, so the copy finds no released session and draws its own; taking
|
|
52
|
+
* the original's would end the original's diagram sessions. Where
|
|
53
|
+
* `sessionStorage` is unavailable the session lasts for the page, and a reload
|
|
54
|
+
* resumes nothing.
|
|
55
|
+
*
|
|
56
|
+
* Claimed as the frontend starts, not with the first diagram: until then the
|
|
57
|
+
* released mark stays, and a tab duplicated meanwhile would take it too. A page
|
|
58
|
+
* restored from the back-forward cache takes the mark back, since Theia
|
|
59
|
+
* before 1.75 leaves it live without a reload.
|
|
60
|
+
*/
|
|
61
|
+
@injectable()
|
|
62
|
+
export class DefaultWindowSessionService implements WindowSessionService, FrontendApplicationContribution {
|
|
63
|
+
protected session?: WindowSession;
|
|
64
|
+
|
|
65
|
+
initialize(): void {
|
|
66
|
+
this.current();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
current(): WindowSession {
|
|
70
|
+
this.session ??= this.claim();
|
|
71
|
+
return this.session;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
protected claim(): WindowSession {
|
|
75
|
+
const created: WindowSession = { id: randomUuid(), resumeToken: randomUuid() };
|
|
76
|
+
try {
|
|
77
|
+
const storage = globalThis.sessionStorage;
|
|
78
|
+
const stored = this.parse(storage.getItem(WINDOW_SESSION_KEY));
|
|
79
|
+
const session = stored && storage.getItem(RELEASED_WINDOW_SESSION_KEY) === stored.id ? stored : created;
|
|
80
|
+
storage.setItem(WINDOW_SESSION_KEY, JSON.stringify(session));
|
|
81
|
+
storage.removeItem(RELEASED_WINDOW_SESSION_KEY);
|
|
82
|
+
globalThis.addEventListener?.('pagehide', () => storage.setItem(RELEASED_WINDOW_SESSION_KEY, session.id));
|
|
83
|
+
globalThis.addEventListener?.('pageshow', event => {
|
|
84
|
+
if ((event as PageTransitionEvent).persisted) {
|
|
85
|
+
storage.removeItem(RELEASED_WINDOW_SESSION_KEY);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
return session;
|
|
89
|
+
} catch {
|
|
90
|
+
return created;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
protected parse(text: string | null): WindowSession | undefined {
|
|
95
|
+
try {
|
|
96
|
+
const value: unknown = text ? JSON.parse(text) : undefined;
|
|
97
|
+
return isWindowSession(value) ? value : undefined;
|
|
98
|
+
} catch {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Bind {@link WindowSessionService} once per container, and claim it as the
|
|
106
|
+
* frontend starts. An adopter rebinds {@link WindowSessionService}.
|
|
107
|
+
*/
|
|
108
|
+
export function bindWindowSessionService(bind: interfaces.Bind, isBound: interfaces.IsBound): void {
|
|
109
|
+
if (!isBound(WindowSessionService)) {
|
|
110
|
+
bind(DefaultWindowSessionService).toSelf().inSingletonScope();
|
|
111
|
+
bind(WindowSessionService).toService(DefaultWindowSessionService);
|
|
112
|
+
bind(FrontendApplicationContribution).toService(WindowSessionService);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
|
|
10
10
|
import { GLSPContribution } from '@eclipse-glsp/theia-integration/lib/common';
|
|
11
|
-
import {
|
|
12
|
-
import { AbstractSocketForwardingConnectionHandler } from '@hydranium/client-theia/lib/node';
|
|
13
|
-
import { type Channel, type Disposable } from '@theia/core';
|
|
11
|
+
import { AbstractSocketForwardingConnectionHandler } from '@hydranium/client-theia/node';
|
|
14
12
|
import { injectable, unmanaged } from '@theia/core/shared/inversify';
|
|
15
13
|
import type * as net from 'net';
|
|
16
14
|
|
|
@@ -21,6 +19,8 @@ import type * as net from 'net';
|
|
|
21
19
|
export interface GlspServerConnectionHandlerOptions {
|
|
22
20
|
readonly languageContributionId: string;
|
|
23
21
|
readonly portCommand: string;
|
|
22
|
+
/** Name of the server in this handler's log lines. */
|
|
23
|
+
readonly serverName?: string;
|
|
24
24
|
readonly findPortTimeout?: number;
|
|
25
25
|
readonly findPortAttempts?: number;
|
|
26
26
|
readonly connectTimeoutMs?: number;
|
|
@@ -38,15 +38,13 @@ export interface GlspServerConnectionHandlerOptions {
|
|
|
38
38
|
/**
|
|
39
39
|
* Bridges a Theia browser-frontend channel to a GLSP server's TCP socket.
|
|
40
40
|
*
|
|
41
|
-
* The port
|
|
42
|
-
* on the cross-head
|
|
43
|
-
*
|
|
41
|
+
* The port discovery, the buffer-and-replay race fix, the connect orchestration
|
|
42
|
+
* and the byte forwarder live on the cross-head
|
|
43
|
+
* {@link AbstractSocketForwardingConnectionHandler} base; this subclass supplies
|
|
44
|
+
* only the GLSP specifics — the per-language servicePath
|
|
44
45
|
* (`GLSPContribution.servicePath + '/' + languageContributionId`), the port
|
|
45
|
-
* command, the log labels
|
|
46
|
-
*
|
|
47
|
-
* language ids or command names subclass with a one-line `super({...})` call.
|
|
48
|
-
* Sibling of `@hydranium/data-client-theia`'s `DataServerConnectionHandler`,
|
|
49
|
-
* which subclasses the same base with its own GLSP-free forwarder.
|
|
46
|
+
* command, the log labels. Adopters with different language ids or command
|
|
47
|
+
* names subclass with a one-line `super({...})` call.
|
|
50
48
|
*/
|
|
51
49
|
@injectable()
|
|
52
50
|
export class GlspServerConnectionHandler extends AbstractSocketForwardingConnectionHandler {
|
|
@@ -55,7 +53,7 @@ export class GlspServerConnectionHandler extends AbstractSocketForwardingConnect
|
|
|
55
53
|
path: GLSPContribution.servicePath + '/' + options.languageContributionId,
|
|
56
54
|
portCommand: options.portCommand,
|
|
57
55
|
logComponent: 'GLSP',
|
|
58
|
-
serverName: '
|
|
56
|
+
serverName: options.serverName ?? 'Diagram Server',
|
|
59
57
|
findPortTimeout: options.findPortTimeout,
|
|
60
58
|
findPortAttempts: options.findPortAttempts,
|
|
61
59
|
connectTimeoutMs: options.connectTimeoutMs,
|
|
@@ -63,7 +61,7 @@ export class GlspServerConnectionHandler extends AbstractSocketForwardingConnect
|
|
|
63
61
|
});
|
|
64
62
|
}
|
|
65
63
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
64
|
+
/** Logged only: the frontend contribution reports the failed start, and a
|
|
65
|
+
* second notification would duplicate it. */
|
|
66
|
+
protected override reportConnectFailure(): void {}
|
|
69
67
|
}
|
|
@@ -49,11 +49,8 @@
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
/* Failure state:
|
|
53
|
-
|
|
54
|
-
The spinner goes (nothing is pending any more) and the text takes the error
|
|
55
|
-
colour. A load that failed and WAS reported never reaches this state — the
|
|
56
|
-
overlay is removed and GLSP's own status overlay shows it instead. */
|
|
52
|
+
/* Failure state: the spinner goes, since nothing is pending any more, and the
|
|
53
|
+
text takes the error colour. */
|
|
57
54
|
.hydranium-diagram-loading-failed .hydranium-diagram-loading-spinner {
|
|
58
55
|
display: none;
|
|
59
56
|
}
|