@hydranium/data-client-theia 1.0.0-next.216 → 1.0.0-next.217

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 CHANGED
@@ -45,9 +45,10 @@ text edits.
45
45
  would hang in port discovery; pass this as `whenReady`.
46
46
  - **`DataSessionStopContribution`** — ends a frontend's data sessions with its
47
47
  page, so the server ends them as closed rather than waiting for the connection
48
- to go, and holds the page while one of them is saving. Bind it as a
49
- `FrontendApplicationContribution` and call its `track(connection)` once, where
50
- the connection is bound.
48
+ to go, and holds the page while one of them is saving.
49
+ `bindDataConnection(bind, isBound, ConnectionClass)` binds a connection with
50
+ its sessions tracked, and binds this contribution and the
51
+ `ConnectionReporter` the connection's port injects unless they are bound.
51
52
  - **Backend (`./node`)** — `DataServerConnectionHandler` (the socket bridge,
52
53
  over `@hydranium/client-theia`'s `SocketChannelForwarder`),
53
54
  `createDataServerConnectionContainerModule(...handlers)` for the
@@ -80,11 +81,15 @@ This package declares no `theiaExtensions` — it is a library your own Theia
80
81
  extension builds on. That extension's `package.json` declares the entries, and
81
82
  each entry names one frontend/backend module pair:
82
83
 
83
- - the **frontend** module binds your `ChannelDataPort` subclass and the
84
- connection over it, both in singleton scope, and calls
85
- `bindConnectionReporter` and `bindChannelLogger` from `@hydranium/client-theia`
86
- (the port logs the connection failures it leaves to the reporter there), and,
87
- for the diagnostics commands, `bindHostDiagnostics`;
84
+ - the **frontend** module:
85
+ - binds your `ChannelDataPort` subclass in singleton scope;
86
+ - calls `bindDataConnection(bind, isBound, MyConnection)` for the connection
87
+ over it;
88
+ - calls `bindChannelLogger` from `@hydranium/client-theia`, where the port
89
+ logs the connection failures it leaves to the reporter;
90
+ - calls `bindEditorDiskSync` from `@hydranium/client-theia`, since a data
91
+ server save writes a file an editor can have open;
92
+ - calls `bindHostDiagnostics` for the diagnostics commands;
88
93
  - the **backend** module is typically a one-liner:
89
94
  `export default createDataServerConnectionContainerModule(MyHandler)`, where
90
95
  `MyHandler` extends `DataServerConnectionHandler`.
@@ -107,7 +112,7 @@ its loading state indefinitely with nothing in the server log to say why.
107
112
  | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
108
113
  | `.` | Nothing — the surface is split by environment, so the root barrel stays empty. | browser-neutral (gated) |
109
114
  | `./common` | `EmitterDataClient` — a module lands here only when values, types and relative imports are all neutral or Theia COMMON tier. No error-reconstruction bridge, and that is a property of the transport: the direct `vscode-jsonrpc` connection carries a typed error across the relay natively. | browser-neutral (gated) |
110
- | `./browser` | `openChannelConnection`, `createChannelConnection`, the three `Abstract*DataServiceFrontend` bases, `bindHostDiagnostics`, `whenWorkspaceOpen`, `DataSessionStopContribution` | browser / Theia frontend (gated) |
115
+ | `./browser` | `openChannelConnection`, `createChannelConnection`, the three `Abstract*DataServiceFrontend` bases, `bindHostDiagnostics`, `whenWorkspaceOpen`, `DataSessionStopContribution`, `bindDataConnection` | browser / Theia frontend (gated) |
111
116
  | `./node` | `DataServerConnectionHandler`, `createDataServerConnectionContainerModule`, `HostDiagnosticsServer`, `createHostDiagnosticsBackendModule` | Node / Theia backend |
112
117
 
113
118
  Resolve the subpaths with [a resolver that reads
@@ -7,12 +7,12 @@
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
9
  import type { DataConnection, DataServerProtocol, DataSession, DiagnosticOf, TransferElement } from '@hydranium/protocol';
10
- import type { FrontendApplicationContribution, OnWillStopAction } from '@theia/core/lib/browser';
10
+ import { FrontendApplicationContribution, type OnWillStopAction } from '@theia/core/lib/browser/frontend-application-contribution';
11
+ import { type interfaces } from '@theia/core/shared/inversify';
11
12
  /**
12
13
  * Ends a Theia frontend's data sessions with its page, and holds the page
13
- * while one of them is still saving. Bind it as a
14
- * `FrontendApplicationContribution` in singleton scope and {@link track} each
15
- * data connection the frontend binds, once.
14
+ * while one of them is still saving. {@link bindDataConnection} binds it and
15
+ * has it {@link track} each data connection bound through it.
16
16
  *
17
17
  * **Stop.** {@link onStop} disposes every tracked session, which sends its
18
18
  * `closeSession`, so the server ends it as closed: each document it was the
@@ -61,4 +61,16 @@ export declare class DataSessionStopContribution implements FrontendApplicationC
61
61
  protected savingSessions(): DataSession<TransferElement>[];
62
62
  onStop(): void;
63
63
  }
64
+ /**
65
+ * Bind `connectionClass` in singleton scope, its sessions tracked by the
66
+ * {@link DataSessionStopContribution}, and bind that contribution and the
67
+ * `ConnectionReporter` the connection's port injects unless they are bound
68
+ * already. The binding's `onActivation` is taken; a frontend's own hook on the
69
+ * connection goes on the container's `onActivation`, which runs after it. A
70
+ * subclass of the contribution is rebound after this call: one bound before it
71
+ * is never registered as a frontend contribution, so its stop never runs.
72
+ * Call it once per connection class: a second call makes the class's lookup
73
+ * ambiguous.
74
+ */
75
+ export declare function bindDataConnection<TTransfer extends TransferElement, TServer extends DataServerProtocol<TTransfer, DiagnosticOf<TServer>>, TClient extends object>(bind: interfaces.Bind, isBound: interfaces.IsBound, connectionClass: interfaces.Newable<DataConnection<TTransfer, TServer, TClient>>): void;
64
76
  //# sourceMappingURL=data-session-stop-contribution.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-session-stop-contribution.d.ts","sourceRoot":"","sources":["../../src/browser/data-session-stop-contribution.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG1H,OAAO,KAAK,EAAE,+BAA+B,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGjG;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBACa,2BAA4B,YAAW,+BAA+B;IAChF,wEAAwE;IACxE,SAAS,CAAC,QAAQ,CAAC,QAAQ,kKAA2C;IACtE;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAK;IAE/C;;;;OAIG;IACH,KAAK,CAAC,SAAS,SAAS,eAAe,EAAE,OAAO,SAAS,kBAAkB,CAAC,SAAS,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,SAAS,MAAM,EAClI,UAAU,EAAE,cAAc,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,GACvD,IAAI,CAGN;IAED;;;;OAIG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,GAAG,IAAI,CAYlE;IAED,UAAU,IAAI,gBAAgB,GAAG,SAAS,CAoBzC;IAED,kDAAkD;IAClD,SAAS,CAAC,cAAc,IAAI,WAAW,CAAC,eAAe,CAAC,EAAE,CAEzD;IAED,MAAM,IAAI,IAAI,CAIb;CACH"}
1
+ {"version":3,"file":"data-session-stop-contribution.d.ts","sourceRoot":"","sources":["../../src/browser/data-session-stop-contribution.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAGlF,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG1H,OAAO,EAAE,+BAA+B,EAAE,KAAK,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AACnI,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBACa,2BAA4B,YAAW,+BAA+B;IAChF,wEAAwE;IACxE,SAAS,CAAC,QAAQ,CAAC,QAAQ,kKAA2C;IACtE;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAK;IAE/C;;;;OAIG;IACH,KAAK,CAAC,SAAS,SAAS,eAAe,EAAE,OAAO,SAAS,kBAAkB,CAAC,SAAS,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,SAAS,MAAM,EAClI,UAAU,EAAE,cAAc,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,GACvD,IAAI,CAGN;IAED;;;;OAIG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,GAAG,IAAI,CAYlE;IAED,UAAU,IAAI,gBAAgB,GAAG,SAAS,CAoBzC;IAED,kDAAkD;IAClD,SAAS,CAAC,cAAc,IAAI,WAAW,CAAC,eAAe,CAAC,EAAE,CAEzD;IAED,MAAM,IAAI,IAAI,CAIb;CACH;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAC/B,SAAS,SAAS,eAAe,EACjC,OAAO,SAAS,kBAAkB,CAAC,SAAS,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,EACpE,OAAO,SAAS,MAAM,EAEtB,IAAI,EAAE,UAAU,CAAC,IAAI,EACrB,OAAO,EAAE,UAAU,CAAC,OAAO,EAC3B,eAAe,EAAE,UAAU,CAAC,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,GAChF,IAAI,CAaN"}
@@ -15,12 +15,16 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.DataSessionStopContribution = void 0;
18
+ exports.bindDataConnection = bindDataConnection;
19
+ const browser_1 = require("@hydranium/client-theia/browser");
20
+ // Not the `@theia/core/lib/browser` barrel: it touches DOM globals at module
21
+ // load, which the node-environment unit tests cannot provide.
22
+ const frontend_application_contribution_1 = require("@theia/core/lib/browser/frontend-application-contribution");
18
23
  const inversify_1 = require("@theia/core/shared/inversify");
19
24
  /**
20
25
  * Ends a Theia frontend's data sessions with its page, and holds the page
21
- * while one of them is still saving. Bind it as a
22
- * `FrontendApplicationContribution` in singleton scope and {@link track} each
23
- * data connection the frontend binds, once.
26
+ * while one of them is still saving. {@link bindDataConnection} binds it and
27
+ * has it {@link track} each data connection bound through it.
24
28
  *
25
29
  * **Stop.** {@link onStop} disposes every tracked session, which sends its
26
30
  * `closeSession`, so the server ends it as closed: each document it was the
@@ -114,4 +118,29 @@ exports.DataSessionStopContribution = DataSessionStopContribution;
114
118
  exports.DataSessionStopContribution = DataSessionStopContribution = __decorate([
115
119
  (0, inversify_1.injectable)()
116
120
  ], DataSessionStopContribution);
121
+ /**
122
+ * Bind `connectionClass` in singleton scope, its sessions tracked by the
123
+ * {@link DataSessionStopContribution}, and bind that contribution and the
124
+ * `ConnectionReporter` the connection's port injects unless they are bound
125
+ * already. The binding's `onActivation` is taken; a frontend's own hook on the
126
+ * connection goes on the container's `onActivation`, which runs after it. A
127
+ * subclass of the contribution is rebound after this call: one bound before it
128
+ * is never registered as a frontend contribution, so its stop never runs.
129
+ * Call it once per connection class: a second call makes the class's lookup
130
+ * ambiguous.
131
+ */
132
+ function bindDataConnection(bind, isBound, connectionClass) {
133
+ bind(connectionClass)
134
+ .toSelf()
135
+ .inSingletonScope()
136
+ .onActivation((context, connection) => {
137
+ context.container.get(DataSessionStopContribution).track(connection);
138
+ return connection;
139
+ });
140
+ if (!isBound(DataSessionStopContribution)) {
141
+ bind(DataSessionStopContribution).toSelf().inSingletonScope();
142
+ bind(frontend_application_contribution_1.FrontendApplicationContribution).toService(DataSessionStopContribution);
143
+ }
144
+ (0, browser_1.bindConnectionReporter)(bind, isBound);
145
+ }
117
146
  //# sourceMappingURL=data-session-stop-contribution.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-session-stop-contribution.js","sourceRoot":"","sources":["../../src/browser/data-session-stop-contribution.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;AAMlF,4DAA0D;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEI,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IACrC,wEAAwE;IACrD,QAAQ,GAAG,IAAI,GAAG,EAAgC,CAAC;IACtE;;;;OAIG;IACgB,eAAe,GAAW,CAAC,CAAC;IAE/C;;;;OAIG;IACH,KAAK,CACF,UAAuD;QAEvD,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;QACvE,UAAU,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IACxE,CAAC;IAED;;;;OAIG;IACO,YAAY,CAAC,OAAqC;QACzD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3B,uEAAuE;QACvE,qBAAqB;QACrB,MAAM,OAAO,GAAG,GAAS,EAAE,CACxB,KAAK,OAAO,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACtH,0EAA0E;QAC1E,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACtB,OAAO,EAAE,CAAC;QACb,CAAC;aAAM,CAAC;YACL,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;IACJ,CAAC;IAED,UAAU;QACP,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtC,OAAO,SAAS,CAAC;QACpB,CAAC;QACD,OAAO;YACJ,uEAAuE;YACvE,MAAM,EAAE,0BAA0B;YAClC,MAAM,EAAE,KAAK,IAAI,EAAE;gBAChB,+DAA+D;gBAC/D,qEAAqE;gBACrE,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,CAAC;oBACtD,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;oBACrC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACvB,MAAM;oBACT,CAAC;oBACD,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC;gBACxE,CAAC;gBACD,OAAO,IAAI,CAAC;YACf,CAAC;SACH,CAAC;IACL,CAAC;IAED,kDAAkD;IACxC,cAAc;QACrB,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACzE,CAAC;IAED,MAAM;QACH,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC;IACJ,CAAC;CACH,CAAA;;sCAzEY,2BAA2B;IADvC,IAAA,sBAAU,GAAE;GACA,2BAA2B,CAyEvC"}
1
+ {"version":3,"file":"data-session-stop-contribution.js","sourceRoot":"","sources":["../../src/browser/data-session-stop-contribution.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydranium/data-client-theia",
3
- "version": "1.0.0-next.216",
3
+ "version": "1.0.0-next.217",
4
4
  "description": "Theia-coupled client primitives for the hydranium data-server protocol head; companion of @hydranium/data-server. Bridges framework typed errors (e.g. ConflictError) across Theia's RPC boundary so their code + data survive the wire.",
5
5
  "keywords": [
6
6
  "hydranium",
@@ -61,8 +61,8 @@
61
61
  "watch": "tsc -b -w --preserveWatchOutput"
62
62
  },
63
63
  "devDependencies": {
64
- "@hydranium/client-theia": "1.0.0-next.216",
65
- "@hydranium/protocol": "1.0.0-next.216",
64
+ "@hydranium/client-theia": "1.0.0-next.217",
65
+ "@hydranium/protocol": "1.0.0-next.217",
66
66
  "@theia/core": "^1.70.0",
67
67
  "@theia/workspace": "^1.70.0",
68
68
  "@types/node": "^22.0.0",
@@ -73,8 +73,8 @@
73
73
  "vscode-jsonrpc": "9.0.0"
74
74
  },
75
75
  "peerDependencies": {
76
- "@hydranium/client-theia": "1.0.0-next.216",
77
- "@hydranium/protocol": "1.0.0-next.216",
76
+ "@hydranium/client-theia": "1.0.0-next.217",
77
+ "@hydranium/protocol": "1.0.0-next.217",
78
78
  "@theia/core": "^1.70.0",
79
79
  "@theia/workspace": "^1.70.0",
80
80
  "inversify": "^6.0.0",
@@ -7,17 +7,17 @@
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
9
 
10
+ import { bindConnectionReporter } from '@hydranium/client-theia/browser';
10
11
  import type { DataConnection, DataServerProtocol, DataSession, DiagnosticOf, TransferElement } from '@hydranium/protocol';
11
- // Type-only: the `@theia/core/lib/browser` barrel touches DOM globals at module
12
+ // Not the `@theia/core/lib/browser` barrel: it touches DOM globals at module
12
13
  // load, which the node-environment unit tests cannot provide.
13
- import type { FrontendApplicationContribution, OnWillStopAction } from '@theia/core/lib/browser';
14
- import { injectable } from '@theia/core/shared/inversify';
14
+ import { FrontendApplicationContribution, type OnWillStopAction } from '@theia/core/lib/browser/frontend-application-contribution';
15
+ import { injectable, type interfaces } from '@theia/core/shared/inversify';
15
16
 
16
17
  /**
17
18
  * Ends a Theia frontend's data sessions with its page, and holds the page
18
- * while one of them is still saving. Bind it as a
19
- * `FrontendApplicationContribution` in singleton scope and {@link track} each
20
- * data connection the frontend binds, once.
19
+ * while one of them is still saving. {@link bindDataConnection} binds it and
20
+ * has it {@link track} each data connection bound through it.
21
21
  *
22
22
  * **Stop.** {@link onStop} disposes every tracked session, which sends its
23
23
  * `closeSession`, so the server ends it as closed: each document it was the
@@ -115,3 +115,37 @@ export class DataSessionStopContribution implements FrontendApplicationContribut
115
115
  }
116
116
  }
117
117
  }
118
+
119
+ /**
120
+ * Bind `connectionClass` in singleton scope, its sessions tracked by the
121
+ * {@link DataSessionStopContribution}, and bind that contribution and the
122
+ * `ConnectionReporter` the connection's port injects unless they are bound
123
+ * already. The binding's `onActivation` is taken; a frontend's own hook on the
124
+ * connection goes on the container's `onActivation`, which runs after it. A
125
+ * subclass of the contribution is rebound after this call: one bound before it
126
+ * is never registered as a frontend contribution, so its stop never runs.
127
+ * Call it once per connection class: a second call makes the class's lookup
128
+ * ambiguous.
129
+ */
130
+ export function bindDataConnection<
131
+ TTransfer extends TransferElement,
132
+ TServer extends DataServerProtocol<TTransfer, DiagnosticOf<TServer>>,
133
+ TClient extends object
134
+ >(
135
+ bind: interfaces.Bind,
136
+ isBound: interfaces.IsBound,
137
+ connectionClass: interfaces.Newable<DataConnection<TTransfer, TServer, TClient>>
138
+ ): void {
139
+ bind(connectionClass)
140
+ .toSelf()
141
+ .inSingletonScope()
142
+ .onActivation((context, connection) => {
143
+ context.container.get(DataSessionStopContribution).track(connection);
144
+ return connection;
145
+ });
146
+ if (!isBound(DataSessionStopContribution)) {
147
+ bind(DataSessionStopContribution).toSelf().inSingletonScope();
148
+ bind(FrontendApplicationContribution).toService(DataSessionStopContribution);
149
+ }
150
+ bindConnectionReporter(bind, isBound);
151
+ }