@hydranium/client-theia 1.0.0-next.10

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.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +113 -0
  3. package/lib/browser/browser-capture.d.ts +21 -0
  4. package/lib/browser/browser-capture.d.ts.map +1 -0
  5. package/lib/browser/browser-capture.js +61 -0
  6. package/lib/browser/browser-capture.js.map +1 -0
  7. package/lib/browser/channel-logger.d.ts +87 -0
  8. package/lib/browser/channel-logger.d.ts.map +1 -0
  9. package/lib/browser/channel-logger.js +149 -0
  10. package/lib/browser/channel-logger.js.map +1 -0
  11. package/lib/browser/index.d.ts +13 -0
  12. package/lib/browser/index.d.ts.map +1 -0
  13. package/lib/browser/index.js +30 -0
  14. package/lib/browser/index.js.map +1 -0
  15. package/lib/browser/log-level-preference.d.ts +82 -0
  16. package/lib/browser/log-level-preference.d.ts.map +1 -0
  17. package/lib/browser/log-level-preference.js +146 -0
  18. package/lib/browser/log-level-preference.js.map +1 -0
  19. package/lib/browser/memory-diagnostics-contribution.d.ts +105 -0
  20. package/lib/browser/memory-diagnostics-contribution.d.ts.map +1 -0
  21. package/lib/browser/memory-diagnostics-contribution.js +229 -0
  22. package/lib/browser/memory-diagnostics-contribution.js.map +1 -0
  23. package/lib/index.d.ts +10 -0
  24. package/lib/index.d.ts.map +1 -0
  25. package/lib/index.js +11 -0
  26. package/lib/index.js.map +1 -0
  27. package/lib/node/abstract-socket-forwarding-connection-handler.d.ts +96 -0
  28. package/lib/node/abstract-socket-forwarding-connection-handler.d.ts.map +1 -0
  29. package/lib/node/abstract-socket-forwarding-connection-handler.js +224 -0
  30. package/lib/node/abstract-socket-forwarding-connection-handler.js.map +1 -0
  31. package/lib/node/index.d.ts +10 -0
  32. package/lib/node/index.d.ts.map +1 -0
  33. package/lib/node/index.js +26 -0
  34. package/lib/node/index.js.map +1 -0
  35. package/lib/testing/index.d.ts +11 -0
  36. package/lib/testing/index.d.ts.map +1 -0
  37. package/lib/testing/index.js +29 -0
  38. package/lib/testing/index.js.map +1 -0
  39. package/lib/testing/stub-inversify-context.d.ts +15 -0
  40. package/lib/testing/stub-inversify-context.d.ts.map +1 -0
  41. package/lib/testing/stub-inversify-context.js +32 -0
  42. package/lib/testing/stub-inversify-context.js.map +1 -0
  43. package/lib/testing/stub-output-channel.d.ts +25 -0
  44. package/lib/testing/stub-output-channel.d.ts.map +1 -0
  45. package/lib/testing/stub-output-channel.js +33 -0
  46. package/lib/testing/stub-output-channel.js.map +1 -0
  47. package/package.json +95 -0
  48. package/src/browser/browser-capture.ts +75 -0
  49. package/src/browser/channel-logger.ts +160 -0
  50. package/src/browser/index.ts +14 -0
  51. package/src/browser/log-level-preference.ts +127 -0
  52. package/src/browser/memory-diagnostics-contribution.ts +248 -0
  53. package/src/index.ts +19 -0
  54. package/src/node/abstract-socket-forwarding-connection-handler.ts +218 -0
  55. package/src/node/index.ts +10 -0
  56. package/src/testing/index.ts +14 -0
  57. package/src/testing/stub-inversify-context.ts +32 -0
  58. package/src/testing/stub-output-channel.ts +47 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CrossBreeze, EclipseSource and others.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # `@hydranium/client-theia`
2
+
3
+ Cross-head Theia client primitives for the
4
+ [Hydranium](https://github.com/eclipse-emfcloud/hydranium) framework.
5
+
6
+ This is the host-coupled layer every hydranium head shares when it runs inside a
7
+ Theia application: the Output-channel logger, the log-threshold preference
8
+ binding, the memory-diagnostics command set, and the backend base class that
9
+ bridges a Theia frontend channel to a server socket. It carries no head-specific
10
+ dependency — `@hydranium/data-client-theia` and `@hydranium/glsp-client-theia`
11
+ both build on it. Install it if you are assembling a Theia extension around a
12
+ hydranium server; a non-Theia host does not need it.
13
+
14
+ ## What it gives you
15
+
16
+ - **`ChannelLogger`** with `bindChannelLogger` — writes frontend log lines into a
17
+ Theia Output channel, formatted to interleave with the server's own log so both
18
+ sides of the conversation read as one transcript. The same call also binds
19
+ `ChannelTracer`, the `Tracer` token frontend services inject when they time
20
+ something.
21
+ - **`LogLevelPreferenceContribution`** with `bindLogLevelPreference` — applies the
22
+ framework log threshold from a Theia preference once per application, and keeps
23
+ it in sync on change. It is a `FrontendApplicationContribution` on purpose: the
24
+ threshold is process-global, so applying it from a per-diagram container would
25
+ leak one preference listener per container.
26
+ - **`MemoryDiagnosticsContribution`** with `bindMemoryDiagnostics` — the whole
27
+ diagnostics command set, parameterised by three branding strings
28
+ (`MemoryDiagnosticsOptions`: `commandIdPrefix`, `category`, `channelName`):
29
+ Dump Server State, Dump Pod Memory, Dump Frontend State, Write Heap Snapshot
30
+ (Server), Start / Stop Profiling (Server), Record Performance Profile, and Dump
31
+ RPC/LSP Latency. Two more — Dump Backend State and Write Heap Snapshot
32
+ (Backend) — register only when the optional `HostMemoryDiagnosticsService` is
33
+ bound. You bind `MemoryDiagnosticsService` to your own connected data-server
34
+ frontend; the framework cannot, because that class is yours.
35
+ - **`captureBrowserRuntime` / `formatBrowserRuntime`** — the renderer's own memory
36
+ reading as a `BrowserRuntimeReport`, preferring the standardized
37
+ `performance.measureUserAgentSpecificMemory()` and falling back to Chromium's
38
+ coarse `performance.memory`.
39
+ - **`AbstractSocketForwardingConnectionHandler`** (Node side) — the abstract base for the
40
+ Theia _backend_ half of a head's transport. It discovers the server's listening
41
+ port by executing a registered command, opens a `net.Socket`, and relays bytes
42
+ between the frontend channel and it. The one abstract hook is which byte
43
+ forwarder bridges the two; port discovery, connect orchestration, and the
44
+ buffer-and-replay fix for frontend writes that arrive before the forwarder is
45
+ wired all live here.
46
+ - **`./testing`** — `makeStubOutputChannelManager` and `makeStubInversifyContext`,
47
+ the doubles that let the pieces above be unit-tested without a Theia
48
+ application.
49
+
50
+ ## Install
51
+
52
+ ```bash
53
+ npm install @hydranium/client-theia
54
+ ```
55
+
56
+ You must already have a Theia application (or a Theia extension inside one). The
57
+ declared peer dependencies are:
58
+
59
+ | Peer | Range |
60
+ | --------------------- | ------------- |
61
+ | `@hydranium/protocol` | `^1.0.0-next` |
62
+ | `@theia/core` | `^1.71.0` |
63
+ | `@theia/output` | `^1.71.0` |
64
+ | `inversify` | `^6.0.0` |
65
+
66
+ `@theia/output` is easy to miss: the memory-diagnostics commands and the channel
67
+ logger both write to an Output channel, so a host that does not already depend on
68
+ it has to add it.
69
+
70
+ ## Wiring
71
+
72
+ This package is a **library, not a Theia extension** — it declares no
73
+ `theiaExtensions`, so dropping it into an application wires nothing on its own.
74
+ Your own extension package declares the `theiaExtensions` entries and imports
75
+ from here:
76
+
77
+ - a **frontend** module (a `ContainerModule` in the extension's `browser/` tier)
78
+ calls the `bind*` helpers — `bindChannelLogger`, `bindLogLevelPreference`,
79
+ `bindMemoryDiagnostics` — and binds `MemoryDiagnosticsService` to your
80
+ data-server frontend;
81
+ - a **backend** module (the extension's `node/` tier) registers a
82
+ `AbstractSocketForwardingConnectionHandler` subclass as a Theia `ConnectionHandler`. In
83
+ practice you subclass one of the head-specific subclasses shipped by
84
+ `@hydranium/data-client-theia` or `@hydranium/glsp-client-theia` rather than
85
+ this base directly.
86
+
87
+ ## Entry points
88
+
89
+ | Subpath | Holds | Environment |
90
+ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
91
+ | `.` | Nothing. Deliberately empty, so an environment-specific import cannot reach the wrong bundle through a barrel. | browser-neutral (gated) |
92
+ | `./browser` | `ChannelLogger`, `ChannelTracer`, `LogLevelPreferenceContribution`, `MemoryDiagnosticsContribution`, the `bind*` helpers, `captureBrowserRuntime` | browser / Theia frontend (gated) |
93
+ | `./node` | `AbstractSocketForwardingConnectionHandler` and its options — imports `node:net` | Node / Theia backend |
94
+ | `./testing` | `makeStubOutputChannelManager`, `makeStubInversifyContext` | browser-neutral (gated) |
95
+
96
+ Every subpath also has a `./lib/<name>` twin, so a consumer on
97
+ `moduleResolution: "Node"` can reach it. "Gated" means the entry is enforced
98
+ browser-neutral by the repository's neutral-bundle check: it must bundle for the
99
+ browser with no `node:*` import, including transitive ones — and [what "gated neutral" does and does not promise](../../docs/concepts/browser-hosting.md#a-note-on-what-gated-neutral-does-and-does-not-promise).
100
+ `./node` is deliberately not gated — that tier is where Node-only code belongs.
101
+
102
+ ## Status
103
+
104
+ Alpha — pre-v0, not yet published. The API is not stable and may change without a
105
+ deprecation cycle. See [`docs/concepts/architecture.md`](../../docs/concepts/architecture.md) for
106
+ how the Theia client tier relates to the heads, and the
107
+ [repository README](../../README.md) for current status and known limitations.
108
+
109
+ ## License
110
+
111
+ `MIT` — see this package's [`LICENSE`](./LICENSE). Third-party notices for the
112
+ runtime dependency closure are collected in the repository
113
+ [`NOTICE.md`](../../NOTICE.md).
@@ -0,0 +1,21 @@
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
+ import type { BrowserRuntimeReport } from '@hydranium/protocol';
10
+ /**
11
+ * Capture the renderer runtime as a single-point {@link BrowserRuntimeReport}
12
+ * (`after`-only — the live gauge read). Prefers the standardized
13
+ * `performance.measureUserAgentSpecificMemory()` (precise, by type + container, but
14
+ * requires cross-origin isolation and is rate-limited), falling back to Chrome's
15
+ * coarse `performance.memory` (JS-heap gauge), then to `unavailable`. The two-point
16
+ * CDP source (`nodes`/`jsEventListeners`/… + delta) is the e2e bridge's job.
17
+ */
18
+ export declare function captureBrowserRuntime(): Promise<BrowserRuntimeReport>;
19
+ /** Render a {@link BrowserRuntimeReport} as a one-line summary for a channel / toast. */
20
+ export declare function formatBrowserRuntime(report: BrowserRuntimeReport): string;
21
+ //# sourceMappingURL=browser-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-capture.d.ts","sourceRoot":"","sources":["../../src/browser/browser-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAYlF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAOhE;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAqB3E;AAMD,yFAAyF;AACzF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAYzE"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ /********************************************************************************
3
+ * Copyright (c) 2026 CrossBreeze, 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
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.captureBrowserRuntime = captureBrowserRuntime;
12
+ exports.formatBrowserRuntime = formatBrowserRuntime;
13
+ /**
14
+ * Capture the renderer runtime as a single-point {@link BrowserRuntimeReport}
15
+ * (`after`-only — the live gauge read). Prefers the standardized
16
+ * `performance.measureUserAgentSpecificMemory()` (precise, by type + container, but
17
+ * requires cross-origin isolation and is rate-limited), falling back to Chrome's
18
+ * coarse `performance.memory` (JS-heap gauge), then to `unavailable`. The two-point
19
+ * CDP source (`nodes`/`jsEventListeners`/… + delta) is the e2e bridge's job.
20
+ */
21
+ async function captureBrowserRuntime() {
22
+ const perf = globalThis.performance;
23
+ if (perf?.measureUserAgentSpecificMemory) {
24
+ try {
25
+ const result = await perf.measureUserAgentSpecificMemory();
26
+ return { source: 'measureUserAgentSpecificMemory', after: { totalBytes: result.bytes, breakdown: result.breakdown } };
27
+ }
28
+ catch {
29
+ // COI missing or rate-limited — fall through to the coarse fallback.
30
+ }
31
+ }
32
+ if (perf?.memory) {
33
+ return {
34
+ source: 'performance.memory',
35
+ after: {
36
+ jsHeapUsedBytes: perf.memory.usedJSHeapSize,
37
+ jsHeapTotalBytes: perf.memory.totalJSHeapSize,
38
+ jsHeapLimitBytes: perf.memory.jsHeapSizeLimit
39
+ }
40
+ };
41
+ }
42
+ return { source: 'unavailable', after: {} };
43
+ }
44
+ function mb(bytes) {
45
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
46
+ }
47
+ /** Render a {@link BrowserRuntimeReport} as a one-line summary for a channel / toast. */
48
+ function formatBrowserRuntime(report) {
49
+ const { after } = report;
50
+ if (report.source === 'measureUserAgentSpecificMemory' && after.totalBytes !== undefined) {
51
+ return `Browser renderer memory (precise): ${mb(after.totalBytes)} total across JS/DOM/workers.`;
52
+ }
53
+ if (report.source === 'performance.memory' && after.jsHeapUsedBytes !== undefined) {
54
+ const used = after.jsHeapUsedBytes;
55
+ const total = after.jsHeapTotalBytes ?? 0;
56
+ const limit = after.jsHeapLimitBytes ?? 0;
57
+ return `Browser JS heap: ${mb(used)} used / ${mb(total)} total / ${mb(limit)} limit (JS heap only, not the full renderer).`;
58
+ }
59
+ return 'Browser memory info unavailable (non-Chromium, or performance.memory disabled / cross-origin isolation off).';
60
+ }
61
+ //# sourceMappingURL=browser-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-capture.js","sourceRoot":"","sources":["../../src/browser/browser-capture.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;AA2BlF,sDAqBC;AAOD,oDAYC;AAhDD;;;;;;;GAOG;AACI,KAAK,UAAU,qBAAqB;IACxC,MAAM,IAAI,GAAG,UAAU,CAAC,WAAmE,CAAC;IAC5F,IAAI,IAAI,EAAE,8BAA8B,EAAE,CAAC;QACxC,IAAI,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,8BAA8B,EAAE,CAAC;YAC3D,OAAO,EAAE,MAAM,EAAE,gCAAgC,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;QACzH,CAAC;QAAC,MAAM,CAAC;YACN,qEAAqE;QACxE,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;QAChB,OAAO;YACJ,MAAM,EAAE,oBAAoB;YAC5B,KAAK,EAAE;gBACJ,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc;gBAC3C,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe;gBAC7C,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe;aAC/C;SACH,CAAC;IACL,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,EAAE,CAAC,KAAa;IACtB,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACrD,CAAC;AAED,yFAAyF;AACzF,SAAgB,oBAAoB,CAAC,MAA4B;IAC9D,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IACzB,IAAI,MAAM,CAAC,MAAM,KAAK,gCAAgC,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACxF,OAAO,sCAAsC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,+BAA+B,CAAC;IACpG,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,oBAAoB,IAAI,KAAK,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;QACjF,MAAM,IAAI,GAAG,KAAK,CAAC,eAAe,CAAC;QACnC,MAAM,KAAK,GAAG,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;QAC1C,OAAO,oBAAoB,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,+CAA+C,CAAC;IAC/H,CAAC;IACD,OAAO,8GAA8G,CAAC;AACzH,CAAC"}
@@ -0,0 +1,87 @@
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
+ import { AbstractLogger, type LogLevel } from '@hydranium/protocol';
10
+ import { type interfaces } from '@theia/core/shared/inversify';
11
+ import { type OutputChannel, OutputChannelManager } from '@theia/output/lib/browser/output-channel';
12
+ /**
13
+ * Configuration for a {@link ChannelLogger}, supplied once at bind time via
14
+ * {@link bindChannelLogger} (the framework's `(deps, options)` constructor
15
+ * shape — the only piece an adopter must provide is the channel name).
16
+ *
17
+ * Note there is no log-threshold option here: the threshold is not a per-logger
18
+ * concern. See {@link ChannelLogger} for why, and
19
+ * `LogLevelPreferenceContribution` for the owner.
20
+ */
21
+ export interface ChannelLoggerOptions {
22
+ /** Name of the Theia Output channel lines are written to. */
23
+ readonly channelName: string;
24
+ /** Initial logger component prefix (see `Logger.for`). */
25
+ readonly component?: string;
26
+ }
27
+ /** Inversify token for the {@link ChannelLoggerOptions} constant (merged with the
28
+ * interface name — the standard Theia "type + token under one identifier" idiom). */
29
+ export declare const ChannelLoggerOptions: unique symbol;
30
+ /**
31
+ * Writes client-side lines to a Theia Output channel, formatted to align with
32
+ * the server-side `LspLogger` so both sides of the conversation interleave
33
+ * cleanly under the same Output panel entry. Cross-head: the data, LSP, and
34
+ * GLSP Theia integrations can all reuse it — nothing here is GLSP-specific.
35
+ *
36
+ * Concrete and options-configured: adopters wire it with
37
+ * {@link bindChannelLogger}, supplying {@link ChannelLoggerOptions}, rather
38
+ * than subclassing to pin a channel name.
39
+ *
40
+ * It deliberately owns **no** threshold logic. The threshold is a process-global
41
+ * shared by every `AbstractLogger`, whereas this class's singleton scope is
42
+ * whichever container bound it (for a GLSP head, one per diagram) — so applying a
43
+ * global from here would subscribe a preference listener per container and never
44
+ * dispose one. `LogLevelPreferenceContribution` owns it instead, at application
45
+ * scope. This class only formats and appends.
46
+ */
47
+ export declare class ChannelLogger extends AbstractLogger {
48
+ protected readonly outputChannels: OutputChannelManager;
49
+ protected readonly options: ChannelLoggerOptions;
50
+ protected _channel?: OutputChannel;
51
+ constructor(outputChannels: OutputChannelManager, options: ChannelLoggerOptions, component?: string | undefined);
52
+ protected get channel(): OutputChannel;
53
+ protected emit(_level: LogLevel, label: string, message: string, args: readonly unknown[]): void;
54
+ /**
55
+ * Allocates a free instance bypassing Inversify, so a derived logger inherits
56
+ * the same OutputChannelManager + options without going through the container
57
+ * singleton. Subclasses with additional constructor dependencies must
58
+ * override and pass the extra args along.
59
+ */
60
+ protected derive(component: string): this;
61
+ }
62
+ /**
63
+ * Inversify token for the browser `Tracer` — a {@link DefaultTracer} over
64
+ * the {@link ChannelLogger} (emit sink) + a {@link SystemClock} + a browser
65
+ * heap reader. The browser head has no Langium `services.Tracer` slot, so this
66
+ * is how frontend services that time obtain a tracer: `@inject(ChannelTracer)`.
67
+ * Bound by {@link bindChannelLogger}.
68
+ */
69
+ export declare const ChannelTracer: unique symbol;
70
+ /** Reads the requesting class's name from an Inversify context, by walking the
71
+ * current request up to its parent binding. */
72
+ export declare function getRequestParentName(context: interfaces.Context): string | undefined;
73
+ /**
74
+ * Bind the {@link ChannelLogger} for an adopter's Theia frontend:
75
+ *
76
+ * - `bind(ChannelLoggerOptions).toConstantValue(options)` — the config
77
+ * - the un-tagged singleton base (private token), constructed by Inversify
78
+ * - `bind(ChannelLogger).toDynamicValue(...)` — class-scoped per request, so
79
+ * every `@inject(ChannelLogger)` site gets a logger pre-tagged with the
80
+ * requesting class name
81
+ *
82
+ * Adopters that compose their own module (bypassing a head's module helper)
83
+ * call this directly; head module helpers (`createGlspClientTheiaModule`)
84
+ * forward to it.
85
+ */
86
+ export declare function bindChannelLogger(bind: interfaces.Bind, options: ChannelLoggerOptions): void;
87
+ //# sourceMappingURL=channel-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-logger.d.ts","sourceRoot":"","sources":["../../src/browser/channel-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,cAAc,EAAiB,KAAK,QAAQ,EAAkC,MAAM,qBAAqB,CAAC;AACnH,OAAO,EAAc,KAAK,UAAU,EAAqB,MAAM,8BAA8B,CAAC;AAC9F,OAAO,EAAE,KAAK,aAAa,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAEpG;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB;IAClC,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;sFACsF;AACtF,eAAO,MAAM,oBAAoB,eAAiC,CAAC;AAEnE;;;;;;;;;;;;;;;;GAgBG;AACH,qBACa,aAAc,SAAQ,cAAc;IAIb,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,oBAAoB;IACvD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,oBAAoB;IAJjF,SAAS,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC;gBAGiB,cAAc,EAAE,oBAAoB,EACpC,OAAO,EAAE,oBAAoB,EACjE,SAAS,GAAE,MAAM,GAAG,SAA6B;IAKjE,SAAS,KAAK,OAAO,IAAI,aAAa,CAErC;IAED,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI;IAOhG;;;;;OAKG;IACH,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAQ3C;AAOD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,eAA0B,CAAC;AAErD;gDACgD;AAChD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,GAAG,MAAM,GAAG,SAAS,CAOpF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAW5F"}
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ /********************************************************************************
3
+ * Copyright (c) 2026 CrossBreeze, 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
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
20
+ return function (target, key) { decorator(target, key, paramIndex); }
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.ChannelTracer = exports.ChannelLogger = exports.ChannelLoggerOptions = void 0;
24
+ exports.getRequestParentName = getRequestParentName;
25
+ exports.bindChannelLogger = bindChannelLogger;
26
+ const protocol_1 = require("@hydranium/protocol");
27
+ const inversify_1 = require("@theia/core/shared/inversify");
28
+ const output_channel_1 = require("@theia/output/lib/browser/output-channel");
29
+ /** Inversify token for the {@link ChannelLoggerOptions} constant (merged with the
30
+ * interface name — the standard Theia "type + token under one identifier" idiom). */
31
+ exports.ChannelLoggerOptions = Symbol('ChannelLoggerOptions');
32
+ /**
33
+ * Writes client-side lines to a Theia Output channel, formatted to align with
34
+ * the server-side `LspLogger` so both sides of the conversation interleave
35
+ * cleanly under the same Output panel entry. Cross-head: the data, LSP, and
36
+ * GLSP Theia integrations can all reuse it — nothing here is GLSP-specific.
37
+ *
38
+ * Concrete and options-configured: adopters wire it with
39
+ * {@link bindChannelLogger}, supplying {@link ChannelLoggerOptions}, rather
40
+ * than subclassing to pin a channel name.
41
+ *
42
+ * It deliberately owns **no** threshold logic. The threshold is a process-global
43
+ * shared by every `AbstractLogger`, whereas this class's singleton scope is
44
+ * whichever container bound it (for a GLSP head, one per diagram) — so applying a
45
+ * global from here would subscribe a preference listener per container and never
46
+ * dispose one. `LogLevelPreferenceContribution` owns it instead, at application
47
+ * scope. This class only formats and appends.
48
+ */
49
+ let ChannelLogger = class ChannelLogger extends protocol_1.AbstractLogger {
50
+ outputChannels;
51
+ options;
52
+ _channel;
53
+ constructor(outputChannels, options, component = options.component) {
54
+ super(component);
55
+ this.outputChannels = outputChannels;
56
+ this.options = options;
57
+ }
58
+ get channel() {
59
+ return (this._channel ??= this.outputChannels.getChannel(this.options.channelName));
60
+ }
61
+ emit(_level, label, message, args) {
62
+ const componentSegment = this.component ? ` [${this.component}]` : '';
63
+ const formattedArgs = args.length > 0 ? ' ' + args.map(stringifyArg).join(' ') : '';
64
+ // Pad to match the server's 5-char label width so timestamps align across sources.
65
+ this.channel.appendLine(`[${label.padEnd(5)} - ${this.timestamp()}]${componentSegment} ${message}${formattedArgs}`);
66
+ }
67
+ /**
68
+ * Allocates a free instance bypassing Inversify, so a derived logger inherits
69
+ * the same OutputChannelManager + options without going through the container
70
+ * singleton. Subclasses with additional constructor dependencies must
71
+ * override and pass the extra args along.
72
+ */
73
+ derive(component) {
74
+ const Ctor = this.constructor;
75
+ return new Ctor(this.outputChannels, this.options, component);
76
+ }
77
+ };
78
+ exports.ChannelLogger = ChannelLogger;
79
+ exports.ChannelLogger = ChannelLogger = __decorate([
80
+ (0, inversify_1.injectable)(),
81
+ __param(0, (0, inversify_1.inject)(output_channel_1.OutputChannelManager)),
82
+ __param(1, (0, inversify_1.inject)(exports.ChannelLoggerOptions)),
83
+ __param(2, (0, inversify_1.unmanaged)()),
84
+ __metadata("design:paramtypes", [output_channel_1.OutputChannelManager, Object, Object])
85
+ ], ChannelLogger);
86
+ /** Private token for the un-tagged singleton base that the per-class dynamic
87
+ * binding derives from. Kept module-internal so the only public token is the
88
+ * {@link ChannelLogger} class itself. */
89
+ const ChannelLoggerBase = Symbol('ChannelLoggerBase');
90
+ /**
91
+ * Inversify token for the browser `Tracer` — a {@link DefaultTracer} over
92
+ * the {@link ChannelLogger} (emit sink) + a {@link SystemClock} + a browser
93
+ * heap reader. The browser head has no Langium `services.Tracer` slot, so this
94
+ * is how frontend services that time obtain a tracer: `@inject(ChannelTracer)`.
95
+ * Bound by {@link bindChannelLogger}.
96
+ */
97
+ exports.ChannelTracer = Symbol('ChannelTracer');
98
+ /** Reads the requesting class's name from an Inversify context, by walking the
99
+ * current request up to its parent binding. */
100
+ function getRequestParentName(context) {
101
+ const parent = context.currentRequest.parentRequest;
102
+ if (!parent || parent.bindings.length === 0) {
103
+ return undefined;
104
+ }
105
+ const binding = parent.bindings[0];
106
+ return binding.implementationType?.name;
107
+ }
108
+ /**
109
+ * Bind the {@link ChannelLogger} for an adopter's Theia frontend:
110
+ *
111
+ * - `bind(ChannelLoggerOptions).toConstantValue(options)` — the config
112
+ * - the un-tagged singleton base (private token), constructed by Inversify
113
+ * - `bind(ChannelLogger).toDynamicValue(...)` — class-scoped per request, so
114
+ * every `@inject(ChannelLogger)` site gets a logger pre-tagged with the
115
+ * requesting class name
116
+ *
117
+ * Adopters that compose their own module (bypassing a head's module helper)
118
+ * call this directly; head module helpers (`createGlspClientTheiaModule`)
119
+ * forward to it.
120
+ */
121
+ function bindChannelLogger(bind, options) {
122
+ bind(exports.ChannelLoggerOptions).toConstantValue(options);
123
+ bind(ChannelLoggerBase).to(ChannelLogger).inSingletonScope();
124
+ bind(ChannelLogger).toDynamicValue(ctx => {
125
+ const base = ctx.container.get(ChannelLoggerBase);
126
+ const parentName = getRequestParentName(ctx);
127
+ return parentName ? base.for(parentName) : base;
128
+ });
129
+ bind(exports.ChannelTracer)
130
+ .toDynamicValue(ctx => new protocol_1.DefaultTracer(ctx.container.get(ChannelLoggerBase), new protocol_1.SystemClock(), readBrowserMemory))
131
+ .inSingletonScope();
132
+ }
133
+ /** Browser heap reader for {@link ChannelTracer}, backed by Chromium's non-standard `performance.memory`. */
134
+ const readBrowserMemory = () => {
135
+ const mem = performance.memory;
136
+ return mem ? { usedBytes: mem.usedJSHeapSize, totalBytes: mem.totalJSHeapSize } : undefined;
137
+ };
138
+ function stringifyArg(arg) {
139
+ if (typeof arg === 'string') {
140
+ return arg;
141
+ }
142
+ try {
143
+ return JSON.stringify(arg);
144
+ }
145
+ catch {
146
+ return String(arg);
147
+ }
148
+ }
149
+ //# sourceMappingURL=channel-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-logger.js","sourceRoot":"","sources":["../../src/browser/channel-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
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
+ export * from './channel-logger';
10
+ export * from './log-level-preference';
11
+ export * from './browser-capture';
12
+ export * from './memory-diagnostics-contribution';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAGlF,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mCAAmC,CAAC"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ /********************************************************************************
3
+ * Copyright (c) 2026 CrossBreeze, 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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
22
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ // Browser-side cross-head Theia client primitives shared by the protocol heads.
26
+ __exportStar(require("./channel-logger"), exports);
27
+ __exportStar(require("./log-level-preference"), exports);
28
+ __exportStar(require("./browser-capture"), exports);
29
+ __exportStar(require("./memory-diagnostics-contribution"), exports);
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,gFAAgF;AAChF,mDAAiC;AACjC,yDAAuC;AACvC,oDAAkC;AAClC,oEAAkD"}
@@ -0,0 +1,82 @@
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
+ import { DisposableCollection } from '@hydranium/protocol';
10
+ import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application-contribution';
11
+ import { ILogger } from '@theia/core/lib/common/logger';
12
+ import { PreferenceService } from '@theia/core/lib/common/preferences/preference-service';
13
+ import { type interfaces } from '@theia/core/shared/inversify';
14
+ /** Inversify token for the preference id {@link LogLevelPreferenceContribution} watches. */
15
+ export declare const LogLevelPreference: unique symbol;
16
+ /**
17
+ * Applies the framework log threshold from a Theia preference, once per
18
+ * application.
19
+ *
20
+ * **Why this is a `FrontendApplicationContribution` and not a logger concern.**
21
+ * The threshold is a process-global (`Logger.setLevel`, read by every
22
+ * `AbstractLogger` at emit time), so applying it is an *application* lifecycle
23
+ * event. Applying it from a logger's `@postConstruct` instead puts a global side
24
+ * effect on the construction of an object whose singleton scope is the
25
+ * per-diagram container, which costs two things:
26
+ *
27
+ * - the `onPreferenceChanged` subscription is never disposed AND is re-created
28
+ * for every diagram container, so opening N diagrams leaves N live listeners
29
+ * holding N loggers;
30
+ * - with no diagram open the preference is never applied at all, so anything
31
+ * logging before the first diagram runs at the default threshold.
32
+ *
33
+ * Bound by {@link bindLogLevelPreference} in the **frontend** container — a
34
+ * diagram container is a child and cannot contribute to the parent's
35
+ * multi-binding.
36
+ */
37
+ export declare class LogLevelPreferenceContribution implements FrontendApplicationContribution {
38
+ protected readonly preferenceName: string;
39
+ protected readonly preferences: PreferenceService;
40
+ protected readonly logger: ILogger;
41
+ /** Holds the single preference subscription. `DisposableCollection` disposes a
42
+ * push-after-dispose immediately, so a subscription that lands after
43
+ * {@link onStop} cannot outlive the application either. */
44
+ protected readonly toDispose: DisposableCollection;
45
+ /** Guards against a second subscription if `onStart` is ever invoked twice —
46
+ * a duplicated listener is exactly the failure this contribution exists to
47
+ * prevent. */
48
+ protected subscribed: boolean;
49
+ /**
50
+ * Returns `void` rather than the promise, so `FrontendApplication.start` does
51
+ * NOT await it.
52
+ *
53
+ * This is load-bearing: `PreferenceService.ready` resolves only once the
54
+ * preference providers are initialised, which happens as part of the same
55
+ * startup sequence that runs the contributions, so awaiting it here deadlocks
56
+ * the frontend on its preload splash. The threshold is therefore applied as
57
+ * soon as preferences are ready, which is early but not synchronously before
58
+ * the first possible log line.
59
+ */
60
+ onStart(): void;
61
+ /** The awaited body of {@link onStart}, separated so it can be driven directly
62
+ * in tests without going through the non-awaited lifecycle hook. */
63
+ protected applyWhenReady(): Promise<void>;
64
+ onStop(): void;
65
+ /**
66
+ * Read the preference and apply it. An unparseable or unset value leaves the
67
+ * current threshold alone rather than resetting it to a default — the value may
68
+ * legitimately have been set by another source (an env baseline, a test).
69
+ *
70
+ * Override for a custom preference→level mapping.
71
+ */
72
+ protected applyLevel(): void;
73
+ }
74
+ /**
75
+ * Bind {@link LogLevelPreferenceContribution} for `preferenceName`.
76
+ *
77
+ * Call from a **frontend** container module. Adopters using
78
+ * `AbstractHydraniumGlspTheiaFrontendModule` set its `logLevelPreference` field
79
+ * instead and the base calls this for them.
80
+ */
81
+ export declare function bindLogLevelPreference(bind: interfaces.Bind, preferenceName: string): void;
82
+ //# sourceMappingURL=log-level-preference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-level-preference.d.ts","sourceRoot":"","sources":["../../src/browser/log-level-preference.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,oBAAoB,EAAyB,MAAM,qBAAqB,CAAC;AAIlF,OAAO,EAAE,+BAA+B,EAAE,MAAM,2DAA2D,CAAC;AAC5G,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uDAAuD,CAAC;AAC1F,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAEnF,4FAA4F;AAC5F,eAAO,MAAM,kBAAkB,eAA+B,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBACa,8BAA+B,YAAW,+BAA+B;IACvD,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAG,MAAM,CAAC;IAC5C,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAG,iBAAiB,CAAC;IAC7D,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAG,OAAO,CAAC;IAErD;;gEAE4D;IAC5D,SAAS,CAAC,QAAQ,CAAC,SAAS,uBAA8B;IAC1D;;mBAEe;IACf,SAAS,CAAC,UAAU,UAAS;IAE7B;;;;;;;;;;OAUG;IACH,OAAO,IAAI,IAAI;IAIf;yEACqE;cACrD,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB/C,MAAM,IAAI,IAAI;IAId;;;;;;OAMG;IACH,SAAS,CAAC,UAAU,IAAI,IAAI;CAM9B;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAI1F"}