@hydranium/data-client-theia 1.0.0-next.25 → 1.0.0-next.251
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 +57 -101
- package/lib/browser/channel-connection.d.ts +8 -8
- package/lib/browser/channel-connection.d.ts.map +1 -1
- package/lib/browser/channel-connection.js +1 -1
- package/lib/browser/channel-connection.js.map +1 -1
- package/lib/browser/channel-data-port.d.ts +89 -0
- package/lib/browser/channel-data-port.d.ts.map +1 -0
- package/lib/browser/channel-data-port.js +190 -0
- package/lib/browser/channel-data-port.js.map +1 -0
- package/lib/browser/data-session-stop-contribution.d.ts +76 -0
- package/lib/browser/data-session-stop-contribution.d.ts.map +1 -0
- package/lib/browser/data-session-stop-contribution.js +146 -0
- package/lib/browser/data-session-stop-contribution.js.map +1 -0
- package/lib/browser/host-diagnostics-frontend.js +1 -1
- package/lib/browser/host-diagnostics-frontend.js.map +1 -1
- package/lib/browser/index.d.ts +2 -3
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +2 -3
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/workspace-gate.js.map +1 -1
- package/lib/common/emitter-data-client.d.ts +13 -1
- package/lib/common/emitter-data-client.d.ts.map +1 -1
- package/lib/common/emitter-data-client.js +18 -0
- package/lib/common/emitter-data-client.js.map +1 -1
- package/lib/node/connection-container-module.d.ts +5 -4
- package/lib/node/connection-container-module.d.ts.map +1 -1
- package/lib/node/connection-container-module.js +5 -4
- package/lib/node/connection-container-module.js.map +1 -1
- package/lib/node/data-server-connection-handler.d.ts +10 -10
- package/lib/node/data-server-connection-handler.d.ts.map +1 -1
- package/lib/node/data-server-connection-handler.js +9 -13
- package/lib/node/data-server-connection-handler.js.map +1 -1
- package/lib/node/host-diagnostics-server.d.ts.map +1 -1
- package/lib/node/host-diagnostics-server.js +1 -1
- package/lib/node/host-diagnostics-server.js.map +1 -1
- package/lib/node/index.d.ts +0 -1
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +0 -1
- package/lib/node/index.js.map +1 -1
- package/package.json +25 -39
- package/src/browser/channel-connection.ts +8 -8
- package/src/browser/channel-data-port.ts +184 -0
- package/src/browser/data-session-stop-contribution.ts +151 -0
- package/src/browser/host-diagnostics-frontend.ts +1 -1
- package/src/browser/index.ts +2 -3
- package/src/common/emitter-data-client.ts +27 -0
- package/src/node/connection-container-module.ts +5 -4
- package/src/node/data-server-connection-handler.ts +11 -14
- package/src/node/host-diagnostics-server.ts +1 -1
- package/src/node/index.ts +0 -1
- package/lib/browser/data-service-frontend.d.ts +0 -154
- package/lib/browser/data-service-frontend.d.ts.map +0 -1
- package/lib/browser/data-service-frontend.js +0 -169
- package/lib/browser/data-service-frontend.js.map +0 -1
- package/lib/browser/diagnostics-data-service-frontend.d.ts +0 -35
- package/lib/browser/diagnostics-data-service-frontend.d.ts.map +0 -1
- package/lib/browser/diagnostics-data-service-frontend.js +0 -54
- package/lib/browser/diagnostics-data-service-frontend.js.map +0 -1
- package/lib/browser/references-data-service-frontend.d.ts +0 -45
- package/lib/browser/references-data-service-frontend.d.ts.map +0 -1
- package/lib/browser/references-data-service-frontend.js +0 -55
- package/lib/browser/references-data-service-frontend.js.map +0 -1
- package/lib/node/socket-channel-forwarder.d.ts +0 -34
- package/lib/node/socket-channel-forwarder.d.ts.map +0 -1
- package/lib/node/socket-channel-forwarder.js +0 -68
- package/lib/node/socket-channel-forwarder.js.map +0 -1
- package/src/browser/data-service-frontend.ts +0 -208
- package/src/browser/diagnostics-data-service-frontend.ts +0 -70
- package/src/browser/references-data-service-frontend.ts +0 -70
- package/src/node/socket-channel-forwarder.ts +0 -69
package/README.md
CHANGED
|
@@ -1,57 +1,20 @@
|
|
|
1
1
|
# `@hydranium/data-client-theia`
|
|
2
2
|
|
|
3
|
-
Theia
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
over a channel that the Theia backend relays byte-for-byte onto the server's
|
|
9
|
-
socket. This package is both halves of that arrangement: the browser-side
|
|
10
|
-
connection and typed-frontend bases, and the backend-side connection handler and
|
|
11
|
-
forwarder. Install it if a Theia application needs form editors, trees, or
|
|
12
|
-
code-gen driven from the live AST rather than from LSP text edits.
|
|
3
|
+
The Theia connection for the
|
|
4
|
+
[Hydranium](https://github.com/eclipse-emfcloud/hydranium) data head, the
|
|
5
|
+
companion of `@hydranium/data-server`. Install it when forms, trees or views in
|
|
6
|
+
a Theia application work on the live model rather than on text. It builds on
|
|
7
|
+
`@hydranium/client-theia`.
|
|
13
8
|
|
|
14
9
|
## What it gives you
|
|
15
10
|
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
escalating per consecutive loss and resetting after
|
|
24
|
-
`RECONNECT_ESCALATION_RESET_MS`.
|
|
25
|
-
- **`AbstractDataServiceFrontend`** — base for a frontend that owns the
|
|
26
|
-
data-server connection: the workspace-gated connect, the typed server proxy,
|
|
27
|
-
the inbound client binding, and a lazy idempotent init gate (`ensureConnected`).
|
|
28
|
-
You supply the connection seams (`connectionProvider`, `servicePath`,
|
|
29
|
-
`methodNamespace`, `client`, `clientMethods`); progress UI and domain caching
|
|
30
|
-
layer on top.
|
|
31
|
-
- **`AbstractDiagnosticsDataServiceFrontend`** and
|
|
32
|
-
**`AbstractReferencesDataServiceFrontend`** — the same base specialised for the
|
|
33
|
-
two protocol fragments an adopter most often keeps: each diagnostics
|
|
34
|
-
(`dumpServerState`, `writeHeapSnapshot`, `dumpPodMemory`, the profiling and
|
|
35
|
-
latency calls) and each reference method is implemented as a readiness-gated
|
|
36
|
-
pass-through, so you do not hand-write identical one-line bodies. They are
|
|
37
|
-
deliberately independent bases rather than chained.
|
|
38
|
-
- **`EmitterDataClient`** (on `./common`, not `./browser`) — the default
|
|
39
|
-
client-side implementation of the data protocol's inbound notifications,
|
|
40
|
-
fanning each one out to a Theia `Event`: `onDidUpdateDocument`,
|
|
41
|
-
`onDidSaveDocument`, `onDidChangeProjects`. Bind an instance as the
|
|
42
|
-
`localTarget` of the frontend's RPC proxy. It sits on the common tier because
|
|
43
|
-
its only runtime dependency is `@theia/core`'s root entry, which is Theia's own
|
|
44
|
-
common tier, so a backend or a plain-Node consumer can bind it too.
|
|
45
|
-
- **`whenWorkspaceOpen`** — resolves once Theia reports a workspace root. The data
|
|
46
|
-
server only starts once the LSP launches for a workspace, so connecting earlier
|
|
47
|
-
would hang in port discovery; pass this as `whenReady`.
|
|
48
|
-
- **Backend (`./node`)** — `DataServerConnectionHandler` (the socket bridge, with
|
|
49
|
-
its own GLSP-free `SocketChannelForwarder`),
|
|
50
|
-
`createDataServerConnectionContainerModule(...handlers)` for the
|
|
51
|
-
frontend-scoped module boilerplate, and `HostDiagnosticsServer` with
|
|
52
|
-
`createHostDiagnosticsBackendModule()` — which, paired with the browser-side
|
|
53
|
-
`bindHostDiagnostics`, lights up the "Backend" diagnostics commands in
|
|
54
|
-
`@hydranium/client-theia`'s contribution.
|
|
11
|
+
- A data connection in the Theia frontend: you subclass `ChannelDataPort`, and
|
|
12
|
+
the connection and sessions from `@hydranium/protocol` run over it.
|
|
13
|
+
- A connection that waits for a workspace, and reconnects on its own when the
|
|
14
|
+
channel is lost, a restarted server included.
|
|
15
|
+
- Sessions that end with the page, and a page held while one of them saves.
|
|
16
|
+
- The backend handler that relays the channel to the data server's socket.
|
|
17
|
+
- Diagnostics commands for the Theia backend process, beside the server's.
|
|
55
18
|
|
|
56
19
|
## Install
|
|
57
20
|
|
|
@@ -59,68 +22,61 @@ code-gen driven from the live AST rather than from LSP text edits.
|
|
|
59
22
|
npm install @hydranium/data-client-theia
|
|
60
23
|
```
|
|
61
24
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
| `@
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
| `@theia/core` | `^1.70.0` |
|
|
71
|
-
| `@theia/workspace` | `^1.70.0` |
|
|
72
|
-
| `inversify` | `^6.0.0` |
|
|
73
|
-
| `vscode-jsonrpc` | `9.0.1` |
|
|
74
|
-
|
|
75
|
-
`@hydranium/core` is reached only from the `./node` tier (the host-diagnostics
|
|
76
|
-
service), so a frontend-only consumer never loads it.
|
|
25
|
+
| Peer | Range |
|
|
26
|
+
| ------------------------- | ------------- |
|
|
27
|
+
| `@hydranium/client-theia` | `^1.0.0-next` |
|
|
28
|
+
| `@hydranium/protocol` | `^1.0.0-next` |
|
|
29
|
+
| `@theia/core` | `^1.70.0` |
|
|
30
|
+
| `@theia/workspace` | `^1.70.0` |
|
|
31
|
+
| `inversify` | `^6.0.0` |
|
|
32
|
+
| `vscode-jsonrpc` | `^9.0.0` |
|
|
77
33
|
|
|
78
34
|
## Wiring
|
|
79
35
|
|
|
80
|
-
This package declares no `theiaExtensions
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
- the
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
`
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
36
|
+
This package declares no `theiaExtensions`; your own Theia extension declares
|
|
37
|
+
them and binds from here.
|
|
38
|
+
|
|
39
|
+
- In a frontend module, subclass `ChannelDataPort` with a `servicePath` and
|
|
40
|
+
bind it in singleton scope. Call `bindDataConnection` for the connection
|
|
41
|
+
over it.
|
|
42
|
+
- In the same frontend, call `bindChannelLogger` from
|
|
43
|
+
`@hydranium/client-theia`, and its `bindEditorDiskSync`, since a data server
|
|
44
|
+
save writes a file an editor can have open.
|
|
45
|
+
- For the backend diagnostics commands, call `bindHostDiagnostics` in the
|
|
46
|
+
frontend and export `createHostDiagnosticsBackendModule()` from a backend
|
|
47
|
+
module.
|
|
48
|
+
- In the backend, export
|
|
49
|
+
`createDataServerConnectionContainerModule(MyHandler)`, where `MyHandler`
|
|
50
|
+
extends `DataServerConnectionHandler` and names your server's port command.
|
|
51
|
+
|
|
52
|
+
Give each frontend channel its own `servicePath`. Theia refuses a second
|
|
53
|
+
channel on a path already open, silently: the frontend hangs with nothing in
|
|
54
|
+
the log. For several participants on one channel, use sessions instead.
|
|
55
|
+
|
|
56
|
+
For the whole setup, see *Host in Theia* in
|
|
57
|
+
[Adopting Hydranium](https://github.com/eclipse-emfcloud/hydranium/blob/main/docs/ADOPTING.md).
|
|
99
58
|
|
|
100
59
|
## Entry points
|
|
101
60
|
|
|
102
|
-
| Subpath |
|
|
103
|
-
| ----------- |
|
|
104
|
-
| `.` | Nothing
|
|
105
|
-
| `./common` |
|
|
106
|
-
| `./browser` |
|
|
107
|
-
| `./node` |
|
|
61
|
+
| Subpath | Use it for | Runs in |
|
|
62
|
+
| ----------- | ------------------------------------------------------------- | --------------- |
|
|
63
|
+
| `.` | Nothing; import a subpath | browser-neutral |
|
|
64
|
+
| `./common` | The data server's notifications as Theia events, on any side | browser-neutral |
|
|
65
|
+
| `./browser` | The port, the connection binding and the diagnostics proxy | Theia frontend |
|
|
66
|
+
| `./node` | The connection handler and the backend modules | Theia backend |
|
|
108
67
|
|
|
109
|
-
|
|
110
|
-
`
|
|
111
|
-
|
|
112
|
-
transitive ones included; `./node` is deliberately outside that gate. Also
|
|
113
|
-
worth reading: [what "gated neutral" does and does not promise](../../docs/concepts/browser-hosting.md#a-note-on-what-gated-neutral-does-and-does-not-promise).
|
|
68
|
+
The subpaths need a TypeScript `moduleResolution` that reads `exports`
|
|
69
|
+
(`NodeNext` or `Bundler`); see *Requirements* in
|
|
70
|
+
[Adopting Hydranium](https://github.com/eclipse-emfcloud/hydranium/blob/main/docs/ADOPTING.md).
|
|
114
71
|
|
|
115
72
|
## Status
|
|
116
73
|
|
|
117
|
-
Alpha
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
[repository README](../../README.md) for current status and known limitations.
|
|
74
|
+
Alpha: every release is a prerelease that may break the API, so pin an exact
|
|
75
|
+
version. Guides and known limitations:
|
|
76
|
+
[Adopting Hydranium](https://github.com/eclipse-emfcloud/hydranium/blob/main/docs/ADOPTING.md).
|
|
121
77
|
|
|
122
78
|
## License
|
|
123
79
|
|
|
124
|
-
`MIT` — see this package's [`LICENSE`](./LICENSE)
|
|
125
|
-
|
|
126
|
-
|
|
80
|
+
`MIT` — see this package's [`LICENSE`](./LICENSE), and the repository
|
|
81
|
+
[`NOTICE.md`](https://github.com/eclipse-emfcloud/hydranium/blob/main/NOTICE.md)
|
|
82
|
+
for third-party notices.
|
|
@@ -21,7 +21,7 @@ import { type Logger, type MessageConnection } from 'vscode-jsonrpc/browser';
|
|
|
21
21
|
* Mirrors `@eclipse-glsp/theia-integration`'s `createChannelConnection`, but
|
|
22
22
|
* lives here so the data-server head carries no GLSP dependency.
|
|
23
23
|
*/
|
|
24
|
-
export declare function createChannelConnection(channel: Channel, logger
|
|
24
|
+
export declare function createChannelConnection(channel: Channel, logger: Logger): MessageConnection;
|
|
25
25
|
/** Options for {@link openChannelConnection}. */
|
|
26
26
|
export interface OpenChannelConnectionOptions {
|
|
27
27
|
/**
|
|
@@ -32,8 +32,8 @@ export interface OpenChannelConnectionOptions {
|
|
|
32
32
|
* publishes the port) exists.
|
|
33
33
|
*/
|
|
34
34
|
whenReady?: Promise<void>;
|
|
35
|
-
/**
|
|
36
|
-
logger
|
|
35
|
+
/** Where the connection logs its protocol faults; without one they leave no trace. */
|
|
36
|
+
logger: Logger;
|
|
37
37
|
/**
|
|
38
38
|
* Re-establish the connection whenever the live one is lost, by RE-OPENING
|
|
39
39
|
* the channel on `path` — not merely by rebuilding over a channel Theia hands
|
|
@@ -107,8 +107,8 @@ export interface ChannelConnectionHandle {
|
|
|
107
107
|
/**
|
|
108
108
|
* The current connection. Read it per use rather than caching it: after a
|
|
109
109
|
* reconnect this returns a NEW promise, and a cached one resolves to the
|
|
110
|
-
* dead connection forever. The same reasoning makes
|
|
111
|
-
*
|
|
110
|
+
* dead connection forever. The same reasoning makes `RpcConnection` rebuild
|
|
111
|
+
* its proxy per generation rather than hold one.
|
|
112
112
|
*/
|
|
113
113
|
readonly current: Promise<MessageConnection>;
|
|
114
114
|
/**
|
|
@@ -120,10 +120,10 @@ export interface ChannelConnectionHandle {
|
|
|
120
120
|
*
|
|
121
121
|
* **This is the event a consumer wants, not {@link onDidReconnect}.** Anything
|
|
122
122
|
* derived from a connection — an `createRpcProxy`, a readiness gate, a
|
|
123
|
-
* `
|
|
123
|
+
* `DataConnection` generation — is dead from this moment, and a consumer that
|
|
124
124
|
* waits for the replacement to be live instead keeps sending into the dead one
|
|
125
125
|
* for the whole gap. A `DataPort` implementation translates this into the
|
|
126
|
-
* port's own `onDispose`, which is what makes `
|
|
126
|
+
* port's own `onDispose`, which is what makes `DataConnection` drop its
|
|
127
127
|
* generation.
|
|
128
128
|
*
|
|
129
129
|
* Never fires when {@link OpenChannelConnectionOptions.reconnect} is off.
|
|
@@ -170,5 +170,5 @@ export interface ChannelConnectionHandle {
|
|
|
170
170
|
* so the consumer's request is left unsettled: a hang with a clean log, not an
|
|
171
171
|
* error. Owning the re-open here means owning it exclusively.
|
|
172
172
|
*/
|
|
173
|
-
export declare function openChannelConnection(connectionProvider: ServiceConnectionProvider, path: string, options
|
|
173
|
+
export declare function openChannelConnection(connectionProvider: ServiceConnectionProvider, path: string, options: OpenChannelConnectionOptions): ChannelConnectionHandle;
|
|
174
174
|
//# sourceMappingURL=channel-connection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-connection.d.ts","sourceRoot":"","sources":["../../src/browser/channel-connection.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,OAAO,EAAiC,KAAK,KAAK,EAAwB,MAAM,aAAa,CAAC;AAC5G,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAEzE,OAAO,EAMJ,KAAK,MAAM,EAEX,KAAK,iBAAiB,EAQxB,MAAM,wBAAwB,CAAC;AAkEhC;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"channel-connection.d.ts","sourceRoot":"","sources":["../../src/browser/channel-connection.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,OAAO,EAAiC,KAAK,KAAK,EAAwB,MAAM,aAAa,CAAC;AAC5G,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAEzE,OAAO,EAMJ,KAAK,MAAM,EAEX,KAAK,iBAAiB,EAQxB,MAAM,wBAAwB,CAAC;AAkEhC;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAI3F;AAED,iDAAiD;AACjD,MAAM,WAAW,4BAA4B;IAC1C;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAA2C,CAAC;AAElG,iFAAiF;AACjF,eAAO,MAAM,6BAA6B,QAAS,CAAC;AAEpD;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAE7C;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,mBAAmB,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAE1C;;;;;;;OAOG;IACH,QAAQ,CAAC,cAAc,EAAE,KAAK,CAAC,iBAAiB,CAAC,CAAC;IAElD;;;;;;OAMG;IACH,OAAO,IAAI,IAAI,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CAClC,kBAAkB,EAAE,yBAAyB,EAC7C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,4BAA4B,GACrC,uBAAuB,CA4IzB"}
|
|
@@ -126,7 +126,7 @@ exports.RECONNECT_ESCALATION_RESET_MS = 30_000;
|
|
|
126
126
|
* so the consumer's request is left unsettled: a hang with a clean log, not an
|
|
127
127
|
* error. Owning the re-open here means owning it exclusively.
|
|
128
128
|
*/
|
|
129
|
-
function openChannelConnection(connectionProvider, path, options
|
|
129
|
+
function openChannelConnection(connectionProvider, path, options) {
|
|
130
130
|
const reconnect = options.reconnect ?? true;
|
|
131
131
|
const reconnectDelays = options.reconnectDelays ?? exports.DEFAULT_RECONNECT_DELAYS;
|
|
132
132
|
const reconnectEmitter = new core_1.Emitter();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-connection.js","sourceRoot":"","sources":["../../src/browser/channel-connection.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF
|
|
1
|
+
{"version":3,"file":"channel-connection.js","sourceRoot":"","sources":["../../src/browser/channel-connection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
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
|
+
import { ChannelLogger, ConnectionReporter, type ConnectionAttempt, type ConnectionTarget } from '@hydranium/client-theia/browser';
|
|
10
|
+
import { type DataPort, type ResolvedMessage, type RpcConnectionLifecycle } from '@hydranium/protocol';
|
|
11
|
+
import { Emitter, MessageService, type Event } from '@theia/core';
|
|
12
|
+
import { type ServiceConnectionProvider } from '@theia/core/lib/browser';
|
|
13
|
+
import { WorkspaceService } from '@theia/workspace/lib/browser';
|
|
14
|
+
import type { MessageConnection } from 'vscode-jsonrpc';
|
|
15
|
+
import { type ChannelConnectionHandle } from './channel-connection';
|
|
16
|
+
/**
|
|
17
|
+
* A {@link DataPort} over a Theia frontend channel.
|
|
18
|
+
*
|
|
19
|
+
* Subclasses supply {@link servicePath}; everything above the port —
|
|
20
|
+
* `DataConnection`, its sessions, and whatever model a widget drives — is
|
|
21
|
+
* host-neutral and shared with the VS Code and browser shells.
|
|
22
|
+
*
|
|
23
|
+
* Bind one per service path and in singleton scope. Theia keys a frontend
|
|
24
|
+
* channel by its path and refuses a second on a path already open, and the
|
|
25
|
+
* throw escapes the `openChannelConnection` the loser is awaiting, leaving that
|
|
26
|
+
* promise unsettled rather than rejected.
|
|
27
|
+
*/
|
|
28
|
+
export declare abstract class ChannelDataPort implements DataPort {
|
|
29
|
+
protected readonly connectionProvider: ServiceConnectionProvider;
|
|
30
|
+
protected readonly workspaceService: WorkspaceService;
|
|
31
|
+
protected readonly messageService: MessageService;
|
|
32
|
+
protected readonly connectionReporter: ConnectionReporter;
|
|
33
|
+
readonly logger: ChannelLogger;
|
|
34
|
+
/** Frontend service path the backend forwarder for this head is registered under. */
|
|
35
|
+
protected abstract readonly servicePath: string;
|
|
36
|
+
/**
|
|
37
|
+
* Re-open the channel when the current connection is lost. Default `true` —
|
|
38
|
+
* re-opening is the only thing that recovers a restarted language server,
|
|
39
|
+
* which binds new ephemeral ports. Turn it off for a frontend that tears
|
|
40
|
+
* itself down on transport loss instead.
|
|
41
|
+
*/
|
|
42
|
+
protected readonly reconnectOnConnectionLoss: boolean;
|
|
43
|
+
protected readonly disposeEmitter: Emitter<void>;
|
|
44
|
+
readonly onDispose: Event<void>;
|
|
45
|
+
protected handle?: ChannelConnectionHandle;
|
|
46
|
+
/** Set by {@link dispose}, after which {@link connect} rejects. */
|
|
47
|
+
protected disposed: boolean;
|
|
48
|
+
/** How long a connection may take before it is reported as failed; it keeps trying after. */
|
|
49
|
+
protected readonly connectFailureNoticeMs: number;
|
|
50
|
+
protected attempt?: ConnectionAttempt;
|
|
51
|
+
protected attemptTimer?: ReturnType<typeof setTimeout>;
|
|
52
|
+
/** Set once {@link connectionLifecycle} reports, which then owns the connection failures. */
|
|
53
|
+
protected reportsConnections: boolean;
|
|
54
|
+
/** Reports each connection generation through the {@link ConnectionReporter}. */
|
|
55
|
+
readonly connectionLifecycle: RpcConnectionLifecycle;
|
|
56
|
+
/**
|
|
57
|
+
* Open the workspace-gated channel and hand back its listening connection.
|
|
58
|
+
*
|
|
59
|
+
* Gated because the backend forwarder discovers the head's port by executing
|
|
60
|
+
* a command the language server answers, and the language server only
|
|
61
|
+
* launches once there is a workspace to launch it for. Asking earlier polls
|
|
62
|
+
* a command nobody has registered.
|
|
63
|
+
*
|
|
64
|
+
* Rejects once the port is disposed: the consumer reconnects when the
|
|
65
|
+
* dispose fires {@link onDispose}, and a channel opened then is closed by
|
|
66
|
+
* nothing.
|
|
67
|
+
*/
|
|
68
|
+
connect(): Promise<MessageConnection>;
|
|
69
|
+
/**
|
|
70
|
+
* Surface a transport or write failure as a Theia notification.
|
|
71
|
+
*
|
|
72
|
+
* Swallowing it is the failure this exists to prevent: a dead connection and
|
|
73
|
+
* an empty document are indistinguishable in a widget.
|
|
74
|
+
*
|
|
75
|
+
* `reported` is already a complete sentence with the detail interpolated, so
|
|
76
|
+
* wrapping it in a sentence of the host's own would nest one owner's clause
|
|
77
|
+
* inside another's and leave no translator in control of the whole.
|
|
78
|
+
*/
|
|
79
|
+
reportError(_error: unknown, reported: ResolvedMessage): void;
|
|
80
|
+
/** End the current attempt through `settle`, or cancel it. */
|
|
81
|
+
protected settleAttempt(settle?: (attempt: ConnectionAttempt) => void): void;
|
|
82
|
+
protected get connectionTarget(): ConnectionTarget;
|
|
83
|
+
/** One object per port: the reporter keys what it has shown on it. */
|
|
84
|
+
protected cachedConnectionTarget?: ConnectionTarget;
|
|
85
|
+
protected unreachableMessage(): string;
|
|
86
|
+
protected connectTimeoutMessage(): string;
|
|
87
|
+
dispose(): void;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=channel-data-port.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-data-port.d.ts","sourceRoot":"","sources":["../../src/browser/channel-data-port.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnI,OAAO,EAIJ,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC7B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,cAAc,EAAO,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAGzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,KAAK,uBAAuB,EAAyB,MAAM,sBAAsB,CAAC;AAG3F;;;;;;;;;;;GAWG;AACH,8BACsB,eAAgB,YAAW,QAAQ;IACpB,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAG,yBAAyB,CAAC;IAC1E,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAG,gBAAgB,CAAC;IACzD,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAG,cAAc,CAAC;IAC/C,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAG,kBAAkB,CAAC;IAChE,QAAQ,CAAC,MAAM,EAAG,aAAa,CAAC;IAEvD,qFAAqF;IACrF,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAEhD;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,yBAAyB,EAAE,OAAO,CAAQ;IAE7D,SAAS,CAAC,QAAQ,CAAC,cAAc,gBAAuB;IACxD,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAA6B;IAE5D,SAAS,CAAC,MAAM,CAAC,EAAE,uBAAuB,CAAC;IAC3C,mEAAmE;IACnE,SAAS,CAAC,QAAQ,UAAS;IAE3B,6FAA6F;IAC7F,SAAS,CAAC,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAU;IAC3D,SAAS,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IACtC,SAAS,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;IACvD,6FAA6F;IAC7F,SAAS,CAAC,kBAAkB,UAAS;IAErC,iFAAiF;IACjF,QAAQ,CAAC,mBAAmB,EAAE,sBAAsB,CAclD;IAEF;;;;;;;;;;;OAWG;IACH,OAAO,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAoBpC;IAED;;;;;;;;;OASG;IACH,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI,CAS5D;IAED,8DAA8D;IAC9D,SAAS,CAAC,aAAa,CAAC,MAAM,GAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAqC,GAAG,IAAI,CAO3G;IAED,SAAS,KAAK,gBAAgB,IAAI,gBAAgB,CAKjD;IACD,sEAAsE;IACtE,SAAS,CAAC,sBAAsB,CAAC,EAAE,gBAAgB,CAAC;IAEpD,SAAS,CAAC,kBAAkB,IAAI,MAAM,CAErC;IAED,SAAS,CAAC,qBAAqB,IAAI,MAAM,CAMxC;IAED,OAAO,IAAI,IAAI,CAOd;CACH"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
11
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
12
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
13
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
14
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
15
|
+
};
|
|
16
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
17
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.ChannelDataPort = void 0;
|
|
21
|
+
const browser_1 = require("@hydranium/client-theia/browser");
|
|
22
|
+
const protocol_1 = require("@hydranium/protocol");
|
|
23
|
+
const core_1 = require("@theia/core");
|
|
24
|
+
const service_connection_provider_1 = require("@theia/core/lib/browser/messaging/service-connection-provider");
|
|
25
|
+
const inversify_1 = require("@theia/core/shared/inversify");
|
|
26
|
+
const browser_2 = require("@theia/workspace/lib/browser");
|
|
27
|
+
const channel_connection_1 = require("./channel-connection");
|
|
28
|
+
const workspace_gate_1 = require("./workspace-gate");
|
|
29
|
+
/**
|
|
30
|
+
* A {@link DataPort} over a Theia frontend channel.
|
|
31
|
+
*
|
|
32
|
+
* Subclasses supply {@link servicePath}; everything above the port —
|
|
33
|
+
* `DataConnection`, its sessions, and whatever model a widget drives — is
|
|
34
|
+
* host-neutral and shared with the VS Code and browser shells.
|
|
35
|
+
*
|
|
36
|
+
* Bind one per service path and in singleton scope. Theia keys a frontend
|
|
37
|
+
* channel by its path and refuses a second on a path already open, and the
|
|
38
|
+
* throw escapes the `openChannelConnection` the loser is awaiting, leaving that
|
|
39
|
+
* promise unsettled rather than rejected.
|
|
40
|
+
*/
|
|
41
|
+
let ChannelDataPort = class ChannelDataPort {
|
|
42
|
+
connectionProvider;
|
|
43
|
+
workspaceService;
|
|
44
|
+
messageService;
|
|
45
|
+
connectionReporter;
|
|
46
|
+
logger;
|
|
47
|
+
/**
|
|
48
|
+
* Re-open the channel when the current connection is lost. Default `true` —
|
|
49
|
+
* re-opening is the only thing that recovers a restarted language server,
|
|
50
|
+
* which binds new ephemeral ports. Turn it off for a frontend that tears
|
|
51
|
+
* itself down on transport loss instead.
|
|
52
|
+
*/
|
|
53
|
+
reconnectOnConnectionLoss = true;
|
|
54
|
+
disposeEmitter = new core_1.Emitter();
|
|
55
|
+
onDispose = this.disposeEmitter.event;
|
|
56
|
+
handle;
|
|
57
|
+
/** Set by {@link dispose}, after which {@link connect} rejects. */
|
|
58
|
+
disposed = false;
|
|
59
|
+
/** How long a connection may take before it is reported as failed; it keeps trying after. */
|
|
60
|
+
connectFailureNoticeMs = 30_000;
|
|
61
|
+
attempt;
|
|
62
|
+
attemptTimer;
|
|
63
|
+
/** Set once {@link connectionLifecycle} reports, which then owns the connection failures. */
|
|
64
|
+
reportsConnections = false;
|
|
65
|
+
/** Reports each connection generation through the {@link ConnectionReporter}. */
|
|
66
|
+
connectionLifecycle = {
|
|
67
|
+
onConnecting: () => {
|
|
68
|
+
this.reportsConnections = true;
|
|
69
|
+
this.settleAttempt();
|
|
70
|
+
const attempt = this.connectionReporter.connecting(this.connectionTarget);
|
|
71
|
+
this.attempt = attempt;
|
|
72
|
+
this.attemptTimer = setTimeout(() => {
|
|
73
|
+
attempt.failed(this.connectTimeoutMessage());
|
|
74
|
+
// The generation keeps waiting; a follow-up attempt reports it connecting.
|
|
75
|
+
this.attempt = this.connectionReporter.connecting(this.connectionTarget);
|
|
76
|
+
}, this.connectFailureNoticeMs);
|
|
77
|
+
},
|
|
78
|
+
onReady: () => this.settleAttempt(attempt => attempt.connected()),
|
|
79
|
+
onFailed: () => this.settleAttempt(attempt => attempt.failed(this.unreachableMessage()))
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Open the workspace-gated channel and hand back its listening connection.
|
|
83
|
+
*
|
|
84
|
+
* Gated because the backend forwarder discovers the head's port by executing
|
|
85
|
+
* a command the language server answers, and the language server only
|
|
86
|
+
* launches once there is a workspace to launch it for. Asking earlier polls
|
|
87
|
+
* a command nobody has registered.
|
|
88
|
+
*
|
|
89
|
+
* Rejects once the port is disposed: the consumer reconnects when the
|
|
90
|
+
* dispose fires {@link onDispose}, and a channel opened then is closed by
|
|
91
|
+
* nothing.
|
|
92
|
+
*/
|
|
93
|
+
connect() {
|
|
94
|
+
if (this.disposed) {
|
|
95
|
+
return Promise.reject(new Error(`${this.constructor.name}: the port is disposed`));
|
|
96
|
+
}
|
|
97
|
+
// Read per call rather than cached: `current` is repointed at a fresh
|
|
98
|
+
// promise every time the channel is re-opened, so reading through the
|
|
99
|
+
// handle is what makes a later generation reach the live server.
|
|
100
|
+
if (!this.handle) {
|
|
101
|
+
this.handle = (0, channel_connection_1.openChannelConnection)(this.connectionProvider, this.servicePath, {
|
|
102
|
+
whenReady: (0, workspace_gate_1.whenWorkspaceOpen)(this.workspaceService),
|
|
103
|
+
logger: this.logger,
|
|
104
|
+
reconnect: this.reconnectOnConnectionLoss
|
|
105
|
+
});
|
|
106
|
+
// A relaunched server binds new ephemeral ports; the handle re-opens
|
|
107
|
+
// and the forwarder rediscovers, but `DataConnection` caches its
|
|
108
|
+
// generation and would go on addressing the dead one. Its signal to
|
|
109
|
+
// drop that generation is this event.
|
|
110
|
+
this.handle.onDidLoseConnection(() => this.disposeEmitter.fire(undefined));
|
|
111
|
+
}
|
|
112
|
+
return this.handle.current;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Surface a transport or write failure as a Theia notification.
|
|
116
|
+
*
|
|
117
|
+
* Swallowing it is the failure this exists to prevent: a dead connection and
|
|
118
|
+
* an empty document are indistinguishable in a widget.
|
|
119
|
+
*
|
|
120
|
+
* `reported` is already a complete sentence with the detail interpolated, so
|
|
121
|
+
* wrapping it in a sentence of the host's own would nest one owner's clause
|
|
122
|
+
* inside another's and leave no translator in control of the whole.
|
|
123
|
+
*/
|
|
124
|
+
reportError(_error, reported) {
|
|
125
|
+
const connectionFailure = reported.code === protocol_1.DATA_SERVER_CONNECT_FAILED.code || reported.code === protocol_1.DATA_SERVER_NOT_READY.code;
|
|
126
|
+
const message = (0, protocol_1.renderFrameworkMessage)(reported, core_1.nls.localization?.translations);
|
|
127
|
+
if (connectionFailure && this.reportsConnections) {
|
|
128
|
+
// The reporter shows the failure without its detail, so it is kept here.
|
|
129
|
+
this.logger.warn(message);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
this.messageService.error(message);
|
|
133
|
+
}
|
|
134
|
+
/** End the current attempt through `settle`, or cancel it. */
|
|
135
|
+
settleAttempt(settle = attempt => attempt.cancelled()) {
|
|
136
|
+
clearTimeout(this.attemptTimer);
|
|
137
|
+
const attempt = this.attempt;
|
|
138
|
+
this.attempt = undefined;
|
|
139
|
+
if (attempt) {
|
|
140
|
+
settle(attempt);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
get connectionTarget() {
|
|
144
|
+
return (this.cachedConnectionTarget ??= {
|
|
145
|
+
connectingMessage: core_1.nls.localize('hydranium/data-client-theia/data-server-connecting', 'Connecting to the data server…'),
|
|
146
|
+
connectedMessage: core_1.nls.localize('hydranium/data-client-theia/data-server-connected', 'Connected to the data server.')
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/** One object per port: the reporter keys what it has shown on it. */
|
|
150
|
+
cachedConnectionTarget;
|
|
151
|
+
unreachableMessage() {
|
|
152
|
+
return core_1.nls.localize('hydranium/data-client-theia/data-server-unreachable', 'Could not connect to the data server.');
|
|
153
|
+
}
|
|
154
|
+
connectTimeoutMessage() {
|
|
155
|
+
return core_1.nls.localize('hydranium/data-client-theia/data-server-timeout', 'The data server did not answer within {0} seconds.', String(Math.round(this.connectFailureNoticeMs / 1000)));
|
|
156
|
+
}
|
|
157
|
+
dispose() {
|
|
158
|
+
this.disposed = true;
|
|
159
|
+
this.settleAttempt();
|
|
160
|
+
this.handle?.dispose();
|
|
161
|
+
this.handle = undefined;
|
|
162
|
+
this.disposeEmitter.fire(undefined);
|
|
163
|
+
this.disposeEmitter.dispose();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
exports.ChannelDataPort = ChannelDataPort;
|
|
167
|
+
__decorate([
|
|
168
|
+
(0, inversify_1.inject)(service_connection_provider_1.RemoteConnectionProvider),
|
|
169
|
+
__metadata("design:type", Function)
|
|
170
|
+
], ChannelDataPort.prototype, "connectionProvider", void 0);
|
|
171
|
+
__decorate([
|
|
172
|
+
(0, inversify_1.inject)(browser_2.WorkspaceService),
|
|
173
|
+
__metadata("design:type", browser_2.WorkspaceService)
|
|
174
|
+
], ChannelDataPort.prototype, "workspaceService", void 0);
|
|
175
|
+
__decorate([
|
|
176
|
+
(0, inversify_1.inject)(core_1.MessageService),
|
|
177
|
+
__metadata("design:type", core_1.MessageService)
|
|
178
|
+
], ChannelDataPort.prototype, "messageService", void 0);
|
|
179
|
+
__decorate([
|
|
180
|
+
(0, inversify_1.inject)(browser_1.ConnectionReporter),
|
|
181
|
+
__metadata("design:type", Object)
|
|
182
|
+
], ChannelDataPort.prototype, "connectionReporter", void 0);
|
|
183
|
+
__decorate([
|
|
184
|
+
(0, inversify_1.inject)(browser_1.ChannelLogger),
|
|
185
|
+
__metadata("design:type", browser_1.ChannelLogger)
|
|
186
|
+
], ChannelDataPort.prototype, "logger", void 0);
|
|
187
|
+
exports.ChannelDataPort = ChannelDataPort = __decorate([
|
|
188
|
+
(0, inversify_1.injectable)()
|
|
189
|
+
], ChannelDataPort);
|
|
190
|
+
//# sourceMappingURL=channel-data-port.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-data-port.js","sourceRoot":"","sources":["../../src/browser/channel-data-port.ts"],"names":[],"mappings":"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"}
|