@hydranium/data-client-vscode 0.0.0-stage → 1.0.0-next.315

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -2
  3. package/lib/browser/index.d.ts +10 -0
  4. package/lib/browser/index.d.ts.map +1 -0
  5. package/lib/browser/index.js +26 -0
  6. package/lib/browser/index.js.map +1 -0
  7. package/lib/browser/webview-data-port.d.ts +64 -0
  8. package/lib/browser/webview-data-port.d.ts.map +1 -0
  9. package/lib/browser/webview-data-port.js +97 -0
  10. package/lib/browser/webview-data-port.js.map +1 -0
  11. package/lib/index.d.ts +10 -0
  12. package/lib/index.d.ts.map +1 -0
  13. package/lib/index.js +29 -0
  14. package/lib/index.js.map +1 -0
  15. package/lib/messenger-channel.d.ts +155 -0
  16. package/lib/messenger-channel.d.ts.map +1 -0
  17. package/lib/messenger-channel.js +106 -0
  18. package/lib/messenger-channel.js.map +1 -0
  19. package/lib/node/data-server-connection.d.ts +57 -0
  20. package/lib/node/data-server-connection.d.ts.map +1 -0
  21. package/lib/node/data-server-connection.js +92 -0
  22. package/lib/node/data-server-connection.js.map +1 -0
  23. package/lib/node/index.d.ts +10 -0
  24. package/lib/node/index.d.ts.map +1 -0
  25. package/lib/node/index.js +26 -0
  26. package/lib/node/index.js.map +1 -0
  27. package/lib/testing/index.d.ts +10 -0
  28. package/lib/testing/index.d.ts.map +1 -0
  29. package/lib/testing/index.js +26 -0
  30. package/lib/testing/index.js.map +1 -0
  31. package/lib/testing/messenger-harness.d.ts +48 -0
  32. package/lib/testing/messenger-harness.d.ts.map +1 -0
  33. package/lib/testing/messenger-harness.js +91 -0
  34. package/lib/testing/messenger-harness.js.map +1 -0
  35. package/package.json +99 -4
  36. package/src/browser/index.ts +10 -0
  37. package/src/browser/webview-data-port.ts +115 -0
  38. package/src/index.ts +13 -0
  39. package/src/messenger-channel.ts +224 -0
  40. package/src/node/data-server-connection.ts +85 -0
  41. package/src/node/index.ts +10 -0
  42. package/src/testing/index.ts +10 -0
  43. package/src/testing/messenger-harness.ts +121 -0
@@ -0,0 +1,106 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.DATA_TO_EXTENSION = exports.DATA_TO_WEBVIEW = void 0;
12
+ exports.createMessengerChannel = createMessengerChannel;
13
+ exports.createExtensionSideChannel = createExtensionSideChannel;
14
+ exports.createWebviewSideChannel = createWebviewSideChannel;
15
+ /**
16
+ * The data head's two notification types, one per direction.
17
+ *
18
+ * `vscode-messenger` addresses a notification to its receiver, so one method
19
+ * for both directions would also deliver correctly. Two keep the direction
20
+ * readable on the wire and in a messenger trace, and keep a delivery that
21
+ * routes by method alone, such as `BROADCAST`, from reaching the sender's own
22
+ * handler.
23
+ */
24
+ exports.DATA_TO_WEBVIEW = { method: 'hydranium/data/toWebview' };
25
+ exports.DATA_TO_EXTENSION = { method: 'hydranium/data/toExtension' };
26
+ /**
27
+ * Present a messenger as a {@link PostMessageChannel}, so the data head's
28
+ * transport rides a host's existing notification hop.
29
+ *
30
+ * `createPostMessageTransport` turns the channel into a reader and writer,
31
+ * `relayToPostMessageChannel` pumps the extension host's socket onto it from
32
+ * the other side, and everything above, `createRpcProxy` and `DataSession`
33
+ * included, is host-invariant. Sharing GLSP's `Messenger` rather than opening a
34
+ * second hop gives a diagram and a data webview one lifecycle and one dispose.
35
+ *
36
+ * **`onMessage`'s `Disposable` means "stop delivering", not necessarily
37
+ * "unregister".** The webview-side messenger cannot unregister, so a flag keeps
38
+ * the promise on both sides. Where unregistering is possible,
39
+ * {@link MessengerChannelOptions.releaseRegistration} does it too, or every
40
+ * disposed webview would leave a handler on a shared hop.
41
+ */
42
+ function createMessengerChannel(options) {
43
+ const { messenger, receiver, outbound, inbound, sender, onClose, releaseRegistration } = options;
44
+ return {
45
+ post(message) {
46
+ messenger.sendNotification(outbound, receiver, message);
47
+ },
48
+ onMessage(listener) {
49
+ let delivering = true;
50
+ const registration = messenger.onNotification(inbound, message => {
51
+ if (delivering) {
52
+ listener(message);
53
+ }
54
+ }, sender ? { sender } : undefined);
55
+ return {
56
+ dispose: () => {
57
+ delivering = false;
58
+ releaseRegistration?.(registration);
59
+ }
60
+ };
61
+ },
62
+ ...(onClose ? { onClose } : {})
63
+ };
64
+ }
65
+ /**
66
+ * The extension host's end: posts toward the webview, listens for what the
67
+ * webview sends.
68
+ */
69
+ function createExtensionSideChannel(messenger, webview, onClose) {
70
+ return createMessengerChannel({
71
+ messenger,
72
+ receiver: webview,
73
+ outbound: exports.DATA_TO_WEBVIEW,
74
+ inbound: exports.DATA_TO_EXTENSION,
75
+ // Only this webview's traffic, since the hop is shared.
76
+ sender: webview,
77
+ onClose,
78
+ // This side can unregister, and must: the hop outlives every webview on it.
79
+ releaseRegistration: registration => registration.dispose()
80
+ });
81
+ }
82
+ /**
83
+ * The webview's end: the mirror image, addressed at the extension host.
84
+ *
85
+ * Two preconditions the webview's bootstrap owns, both of which present as "no
86
+ * data ever arrives" when missed:
87
+ *
88
+ * - **Read the channel through `WebviewDataPort`**, or build its connection
89
+ * with `createMessageConnection` from `vscode-jsonrpc/browser`: the package
90
+ * root installs no runtime abstraction layer and throws on the first
91
+ * message.
92
+ * - **Call the messenger's own `start()`**, which attaches the `window`
93
+ * listener.
94
+ *
95
+ * No `sender` filter: a webview has one peer.
96
+ */
97
+ function createWebviewSideChannel(messenger, hostExtension, onClose) {
98
+ return createMessengerChannel({
99
+ messenger,
100
+ receiver: hostExtension,
101
+ outbound: exports.DATA_TO_EXTENSION,
102
+ inbound: exports.DATA_TO_WEBVIEW,
103
+ onClose
104
+ });
105
+ }
106
+ //# sourceMappingURL=messenger-channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messenger-channel.js","sourceRoot":"","sources":["../src/messenger-channel.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;AA+DlF;;;;;;;;GAQG;AACU,QAAA,eAAe,GAAyB,EAAE,MAAM,EAAE,0BAA0B,EAAE,CAAC;AAC/E,QAAA,iBAAiB,GAAyB,EAAE,MAAM,EAAE,4BAA4B,EAAE,CAAC;AAgDhG;;;;;;;;;;;;;;;GAeG;AACH,gCACG,OAA6D;IAE7D,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC;IACjG,OAAO;QACJ,IAAI,CAAC,OAAgB;YAClB,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3D,CAAC;QACD,SAAS,CAAC,QAAoC;YAC3C,IAAI,UAAU,GAAG,IAAI,CAAC;YACtB,MAAM,YAAY,GAAG,SAAS,CAAC,cAAc,CAC1C,OAAO,EACP,OAAO,CAAC,EAAE;gBACP,IAAI,UAAU,EAAE,CAAC;oBACd,QAAQ,CAAC,OAAO,CAAC,CAAC;gBACrB,CAAC;YACJ,CAAC,EACD,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CACjC,CAAC;YACF,OAAO;gBACJ,OAAO,EAAE,GAAG,EAAE;oBACX,UAAU,GAAG,KAAK,CAAC;oBACnB,mBAAmB,EAAE,CAAC,YAAY,CAAC,CAAC;gBACvC,CAAC;aACH,CAAC;QACL,CAAC;QACD,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,oCACG,SAAsC,EACtC,OAAqB,EACrB,OAA8C;IAE9C,OAAO,sBAAsB,CAA2B;QACrD,SAAS;QACT,QAAQ,EAAE,OAAO;QACjB,QAAQ,EAAE,QAAA,eAAe;QACzB,OAAO,EAAE,QAAA,iBAAiB;QAC1B,wDAAwD;QACxD,MAAM,EAAE,OAAO;QACf,OAAO;QACP,4EAA4E;QAC5E,mBAAmB,EAAE,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE;KAC7D,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,kCACG,SAA6C,EAC7C,aAA2B,EAC3B,OAA8C;IAE9C,OAAO,sBAAsB,CAAwB;QAClD,SAAS;QACT,QAAQ,EAAE,aAAa;QACvB,QAAQ,EAAE,QAAA,iBAAiB;QAC3B,OAAO,EAAE,QAAA,eAAe;QACxB,OAAO;KACT,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,57 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ /**
10
+ * The extension host's end of the data head.
11
+ *
12
+ * A webview has no `net`, so the extension host holds the socket to the
13
+ * data-server and moves whole JSON-RPC messages between it and the webview over
14
+ * a `vscode-messenger` hop, typically GLSP's own, so a diagram and a data
15
+ * webview share one lifecycle and one dispose.
16
+ */
17
+ import { type MessageRelay, type RelayTransport, type ResolvedMessage } from '@hydranium/protocol';
18
+ import type { Disposable } from 'vscode-jsonrpc';
19
+ import { type MessengerLike } from '../messenger-channel';
20
+ /** Connect to a head's socket and present it as a relay's framed side. */
21
+ export declare function openSocketTransport(port: number, host?: string): Promise<RelayTransport>;
22
+ /** What {@link connectDataServer} needs from the host. */
23
+ export interface DataServerConnectionOptions<TParticipant> {
24
+ /**
25
+ * The extension-side messenger, typically `GlspVscodeConnector.messenger`.
26
+ * It must be constructed with `ignoreHiddenViews: false`, or a hidden
27
+ * webview misses every message the data-server sends it.
28
+ */
29
+ readonly messenger: MessengerLike<TParticipant>;
30
+ /** The registered webview this connection serves. */
31
+ readonly webview: TParticipant;
32
+ /**
33
+ * Resolve the data-server's listening port. Called once per connection
34
+ * generation, so a restarted server is re-discovered rather than cached —
35
+ * the language server binds a fresh ephemeral port each start.
36
+ */
37
+ readonly findPort: () => Promise<number>;
38
+ /** Observe the webview going away, so the relay releases with it. */
39
+ readonly onWebviewDisposed?: (listener: () => void) => Disposable;
40
+ /**
41
+ * Surface a relay failure. `reported` is a complete sentence plus the
42
+ * identity needed to render it in another language — the extension host holds
43
+ * the locale, so it renders and the relay does not.
44
+ */
45
+ readonly reportError?: (error: unknown, reported: ResolvedMessage) => void;
46
+ }
47
+ /**
48
+ * Wire one webview to the data head.
49
+ *
50
+ * The returned relay's `onClose` is the host's ONLY notice that the framed side
51
+ * died — a `PostMessageChannel` has no `close()`, so a dead data-server is
52
+ * invisible to the webview, whose pending requests would otherwise hang with no
53
+ * rejection. Tell the webview, whose `WebviewDataPort.connectionLost` rejects
54
+ * them, or dispose the webview; doing nothing is the one wrong choice.
55
+ */
56
+ export declare function connectDataServer<TParticipant>(options: DataServerConnectionOptions<TParticipant>): MessageRelay;
57
+ //# sourceMappingURL=data-server-connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-server-connection.d.ts","sourceRoot":"","sources":["../../src/node/data-server-connection.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;;GAOG;AAEH,OAAO,EAA6B,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE9H,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAIjD,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEtF,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,SAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAe7F;AAED,0DAA0D;AAC1D,MAAM,WAAW,2BAA2B,CAAC,YAAY;IACtD;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IAChD,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,qEAAqE;IACrE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,UAAU,CAAC;IAClE;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,KAAK,IAAI,CAAC;CAC7E;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,OAAO,EAAE,2BAA2B,CAAC,YAAY,CAAC,GAAG,YAAY,CAKhH"}
@@ -0,0 +1,92 @@
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 __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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.openSocketTransport = openSocketTransport;
45
+ exports.connectDataServer = connectDataServer;
46
+ /**
47
+ * The extension host's end of the data head.
48
+ *
49
+ * A webview has no `net`, so the extension host holds the socket to the
50
+ * data-server and moves whole JSON-RPC messages between it and the webview over
51
+ * a `vscode-messenger` hop, typically GLSP's own, so a diagram and a data
52
+ * webview share one lifecycle and one dispose.
53
+ */
54
+ const protocol_1 = require("@hydranium/protocol");
55
+ const net = __importStar(require("node:net"));
56
+ // `/node` because the extension host is Node and holds the socket. The webview
57
+ // imports `/browser`; the package root installs no runtime abstraction layer.
58
+ const node_1 = require("vscode-jsonrpc/node");
59
+ const messenger_channel_1 = require("../messenger-channel");
60
+ /** Connect to a head's socket and present it as a relay's framed side. */
61
+ function openSocketTransport(port, host = '127.0.0.1') {
62
+ return new Promise((resolve, reject) => {
63
+ const socket = net.createConnection({ port, host });
64
+ socket.once('error', reject);
65
+ socket.once('connect', () => {
66
+ // Drop the construction-time handler so a later socket error goes to
67
+ // the relay's reader rather than rejecting an already-settled promise.
68
+ socket.removeAllListeners('error');
69
+ resolve({
70
+ reader: new node_1.SocketMessageReader(socket),
71
+ writer: new node_1.SocketMessageWriter(socket),
72
+ dispose: () => socket.destroy()
73
+ });
74
+ });
75
+ });
76
+ }
77
+ /**
78
+ * Wire one webview to the data head.
79
+ *
80
+ * The returned relay's `onClose` is the host's ONLY notice that the framed side
81
+ * died — a `PostMessageChannel` has no `close()`, so a dead data-server is
82
+ * invisible to the webview, whose pending requests would otherwise hang with no
83
+ * rejection. Tell the webview, whose `WebviewDataPort.connectionLost` rejects
84
+ * them, or dispose the webview; doing nothing is the one wrong choice.
85
+ */
86
+ function connectDataServer(options) {
87
+ const channel = (0, messenger_channel_1.createExtensionSideChannel)(options.messenger, options.webview, options.onWebviewDisposed);
88
+ return (0, protocol_1.relayToPostMessageChannel)(channel, async () => openSocketTransport(await options.findPort()), {
89
+ reportError: options.reportError
90
+ });
91
+ }
92
+ //# sourceMappingURL=data-server-connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-server-connection.js","sourceRoot":"","sources":["../../src/node/data-server-connection.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAElF;;;;;;;GAOG;AAEH,kDAA8H;AAC9H,MAAY,GAAG,qCAAiB;AAEhC,+EAA+E;AAC/E,8EAA8E;AAC9E,8CAA+E;AAC/E,4DAAsF;AAEtF,0EAA0E;AAC1E,6BAAoC,IAAY,EAAE,IAAI,GAAG,WAAW;IACjE,OAAO,IAAI,OAAO,CAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACpD,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;YACzB,qEAAqE;YACrE,uEAAuE;YACvE,MAAM,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACnC,OAAO,CAAC;gBACL,MAAM,EAAE,IAAI,0BAAmB,CAAC,MAAM,CAAC;gBACvC,MAAM,EAAE,IAAI,0BAAmB,CAAC,MAAM,CAAC;gBACvC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE;aACjC,CAAC,CAAC;QACN,CAAC,CAAC,CAAC;IACN,CAAC,CAAC,CAAC;AACN,CAAC;AA4BD;;;;;;;;GAQG;AACH,2BAAgD,OAAkD;IAC/F,MAAM,OAAO,GAAG,IAAA,8CAA0B,EAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC1G,OAAO,IAAA,oCAAyB,EAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,mBAAmB,CAAC,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE;QAClG,WAAW,EAAE,OAAO,CAAC,WAAW;KAClC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,10 @@
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
+ export * from './data-server-connection';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,cAAc,0BAA0B,CAAC"}
@@ -0,0 +1,26 @@
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 __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
+ __exportStar(require("./data-server-connection"), exports);
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,2DAAyC"}
@@ -0,0 +1,10 @@
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
+ export * from './messenger-harness';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,26 @@
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 __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
+ __exportStar(require("./messenger-harness"), exports);
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,sDAAoC"}
@@ -0,0 +1,48 @@
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 { Messenger } from 'vscode-messenger';
10
+ import type { WebviewIdMessageParticipant } from 'vscode-messenger-common';
11
+ import { Messenger as WebviewMessenger } from 'vscode-messenger-webview';
12
+ /** One webview on a {@link MessengerHarness}. */
13
+ export interface MessengerHarnessWebview {
14
+ /** How the extension-side messenger addresses this webview. */
15
+ readonly participant: WebviewIdMessageParticipant;
16
+ /** The webview's own messenger, already started. */
17
+ readonly messenger: WebviewMessenger;
18
+ /** Close the webview, as VS Code disposing its panel does: the extension-side messenger forgets it. */
19
+ dispose(): void;
20
+ }
21
+ /** The real `vscode-messenger` classes, joined without VS Code. */
22
+ export interface MessengerHarness {
23
+ /** The extension host's messenger, constructed as `GlspVscodeConnector` constructs its own. */
24
+ readonly extension: Messenger;
25
+ /** Open a webview: a panel registered with {@link extension}, and the webview's messenger behind it. */
26
+ openWebview(): MessengerHarnessWebview;
27
+ /**
28
+ * Restore the global `window` this harness replaced. A webview messenger
29
+ * reads `window.crypto` for every request it sends, so its requests throw
30
+ * once the harness is disposed; notifications still go.
31
+ */
32
+ dispose(): void;
33
+ }
34
+ /**
35
+ * Join the real extension-side and webview-side messengers in a Node test,
36
+ * through a fake webview panel on one end and a fake `window` on the other.
37
+ *
38
+ * Both classes run unchanged, so their routing is the real one: delivery is
39
+ * asynchronous, the webview side keeps one handler per method, and the
40
+ * extension side filters by sender. The webview messenger listens on the
41
+ * global `window`, so the harness installs one for its lifetime and routes each
42
+ * listener to the webview that registered it.
43
+ *
44
+ * One harness at a time: a second replaces the `window` the first routes its
45
+ * webviews through, and disposing them out of order restores the wrong one.
46
+ */
47
+ export declare function makeMessengerHarness(): MessengerHarness;
48
+ //# sourceMappingURL=messenger-harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messenger-harness.d.ts","sourceRoot":"","sources":["../../src/testing/messenger-harness.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAkB,MAAM,0BAA0B,CAAC;AAEzF,iDAAiD;AACjD,MAAM,WAAW,uBAAuB;IACrC,+DAA+D;IAC/D,QAAQ,CAAC,WAAW,EAAE,2BAA2B,CAAC;IAClD,oDAAoD;IACpD,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,uGAAuG;IACvG,OAAO,IAAI,IAAI,CAAC;CAClB;AAED,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC9B,+FAA+F;IAC/F,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,wGAAwG;IACxG,WAAW,IAAI,uBAAuB,CAAC;IACvC;;;;OAIG;IACH,OAAO,IAAI,IAAI,CAAC;CAClB;AAQD;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,IAAI,gBAAgB,CAgEvD"}
@@ -0,0 +1,91 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.makeMessengerHarness = makeMessengerHarness;
12
+ const vscode_messenger_1 = require("vscode-messenger");
13
+ const vscode_messenger_webview_1 = require("vscode-messenger-webview");
14
+ /**
15
+ * Join the real extension-side and webview-side messengers in a Node test,
16
+ * through a fake webview panel on one end and a fake `window` on the other.
17
+ *
18
+ * Both classes run unchanged, so their routing is the real one: delivery is
19
+ * asynchronous, the webview side keeps one handler per method, and the
20
+ * extension side filters by sender. The webview messenger listens on the
21
+ * global `window`, so the harness installs one for its lifetime and routes each
22
+ * listener to the webview that registered it.
23
+ *
24
+ * One harness at a time: a second replaces the `window` the first routes its
25
+ * webviews through, and disposing them out of order restores the wrong one.
26
+ */
27
+ function makeMessengerHarness() {
28
+ const host = globalThis;
29
+ const previousWindow = host.window;
30
+ let starting;
31
+ const harnessWindow = {
32
+ addEventListener: (type, listener) => {
33
+ if (type === 'message') {
34
+ starting?.push(listener);
35
+ }
36
+ },
37
+ crypto: globalThis.crypto
38
+ };
39
+ host.window = harnessWindow;
40
+ const extension = new vscode_messenger_1.Messenger({ ignoreHiddenViews: false });
41
+ return {
42
+ extension,
43
+ openWebview: () => {
44
+ const toWebview = [];
45
+ const toExtension = [];
46
+ const disposeListeners = [];
47
+ const panel = {
48
+ viewType: 'hydranium.messengerHarness',
49
+ visible: true,
50
+ webview: {
51
+ postMessage: async (message) => {
52
+ [...toWebview].forEach(listener => listener({ data: message }));
53
+ return true;
54
+ },
55
+ onDidReceiveMessage: (listener) => {
56
+ toExtension.push(listener);
57
+ return {
58
+ dispose: () => {
59
+ const index = toExtension.indexOf(listener);
60
+ if (index >= 0) {
61
+ toExtension.splice(index, 1);
62
+ }
63
+ }
64
+ };
65
+ }
66
+ },
67
+ onDidDispose: (listener) => {
68
+ disposeListeners.push(listener);
69
+ return { dispose: () => undefined };
70
+ },
71
+ onDidChangeViewState: () => ({ dispose: () => undefined })
72
+ };
73
+ // The members the extension-side messenger reads; the rest of a panel is VS Code's.
74
+ const participant = extension.registerWebviewPanel(panel);
75
+ const vscodeApi = {
76
+ postMessage: message => [...toExtension].forEach(listener => listener(message)),
77
+ getState: () => undefined,
78
+ setState: () => undefined
79
+ };
80
+ const messenger = new vscode_messenger_webview_1.Messenger(vscodeApi);
81
+ starting = toWebview;
82
+ messenger.start();
83
+ starting = undefined;
84
+ return { participant, messenger, dispose: () => disposeListeners.forEach(listener => listener()) };
85
+ },
86
+ dispose: () => {
87
+ host.window = previousWindow;
88
+ }
89
+ };
90
+ }
91
+ //# sourceMappingURL=messenger-harness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messenger-harness.js","sourceRoot":"","sources":["../../src/testing/messenger-harness.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,101 @@
1
1
  {
2
2
  "name": "@hydranium/data-client-vscode",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0-next.315",
4
+ "description": "VS Code client primitives for the hydranium data-server protocol head; companion of @hydranium/data-server. The extension host relays the data-server's socket to a webview over a vscode-messenger hop, and the webview's data port reads it, so DataConnection and DataSession run unchanged in a webview.",
5
+ "keywords": [
6
+ "hydranium",
7
+ "langium",
8
+ "language-server",
9
+ "lsp",
10
+ "vscode",
11
+ "vscode-extension",
12
+ "webview"
13
+ ],
14
+ "homepage": "https://github.com/eclipse-emfcloud/hydranium/tree/main/packages/data-client-vscode",
15
+ "bugs": {
16
+ "url": "https://github.com/eclipse-emfcloud/hydranium/issues"
17
+ },
18
+ "license": "MIT",
19
+ "author": {
20
+ "name": "Hydranium Team"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/eclipse-emfcloud/hydranium.git",
25
+ "directory": "packages/data-client-vscode"
26
+ },
27
+ "files": [
28
+ "lib",
29
+ "src",
30
+ "!lib/**/*.tsbuildinfo"
31
+ ],
32
+ "sideEffects": false,
33
+ "main": "lib/index.js",
34
+ "types": "lib/index.d.ts",
35
+ "exports": {
36
+ ".": {
37
+ "types": "./lib/index.d.ts",
38
+ "default": "./lib/index.js"
39
+ },
40
+ "./browser": {
41
+ "types": "./lib/browser/index.d.ts",
42
+ "default": "./lib/browser/index.js"
43
+ },
44
+ "./node": {
45
+ "types": "./lib/node/index.d.ts",
46
+ "default": "./lib/node/index.js"
47
+ },
48
+ "./testing": {
49
+ "types": "./lib/testing/index.d.ts",
50
+ "default": "./lib/testing/index.js"
51
+ }
52
+ },
53
+ "publishConfig": {
54
+ "access": "public"
55
+ },
56
+ "scripts": {
57
+ "build": "tsc -b",
58
+ "clean": "rimraf lib tsconfig.tsbuildinfo",
59
+ "lint": "oxlint --format stylish --config ../../oxlint.config.cjs src test --max-warnings 0",
60
+ "prepack": "node -e \"const m=require('./package.json'),fs=require('node:fs');const missing=[m.main,...Object.values(m.bin||{})].filter(entry=>entry&&!fs.existsSync(entry));if(missing.length){console.error('prepack '+m.name+': not built ('+missing.join(', ')+' missing). Run the build before packing: a files entry that matches nothing is skipped silently, so the tarball would ship src only.');process.exit(1);}\"",
61
+ "test": "npm run typecheck:test && vitest run",
62
+ "typecheck:test": "tsc --noEmit -p tsconfig.test.json",
63
+ "watch": "tsc -b -w --preserveWatchOutput"
64
+ },
65
+ "devDependencies": {
66
+ "@hydranium/protocol": "1.0.0-next.315",
67
+ "@types/node": "^22.0.0",
68
+ "@types/vscode": "^1.101.0",
69
+ "rimraf": "^5.0.0",
70
+ "typescript": "^7.0.2",
71
+ "vscode-jsonrpc": "9.0.0",
72
+ "vscode-messenger": "^0.4.5",
73
+ "vscode-messenger-common": "^0.4.5",
74
+ "vscode-messenger-webview": "^0.4.5"
75
+ },
76
+ "peerDependencies": {
77
+ "@hydranium/protocol": "1.0.0-next.315",
78
+ "vscode-jsonrpc": "^9.0.0",
79
+ "vscode-messenger": "^0.4.5",
80
+ "vscode-messenger-common": "^0.4.5",
81
+ "vscode-messenger-webview": "^0.4.5"
82
+ },
83
+ "peerDependenciesMeta": {
84
+ "vscode-messenger": {
85
+ "optional": true
86
+ },
87
+ "vscode-messenger-common": {
88
+ "optional": true
89
+ },
90
+ "vscode-messenger-webview": {
91
+ "optional": true
92
+ }
93
+ },
94
+ "engines": {
95
+ "node": ">=22.13",
96
+ "vscode": "^1.101.0"
97
+ },
98
+ "//peerDependencies": "`vscode-jsonrpc` takes a caret, so the framework shares the transport the LSP connection resolves, which an `init` scaffold pins: each `vscode-languageserver-protocol` release pins its transport exactly, so an exact peer would name a copy a fresh install rarely holds. The caret excludes 8.x, so a tree whose top holds GLSP's copy fails the peer with a named ERESOLVE warning, an error under `--strict-peer-deps`, rather than resolving silently. No peer reaches a NESTED copy, such as GLSP's or one the LSP packages nest. The wire compares message types and `ResponseError`s by copy identity, so the framework sends typed messages by method name and recognises errors with `isResponseError` rather than `instanceof`.",
99
+ "//prepack": "The publish guard, a `prepack` rather than a `prepare`: `prepack` runs only when a tarball is made (`npm pack`, `npm publish`) and never on install, so it cannot break the install it has no business touching. What it defends against: `files` lists `lib`, `lib` is gitignored, and a `files` entry matching nothing is skipped SILENTLY — so `npm publish` from an unbuilt tree emits a tarball of `src` and nothing else, with no error.",
100
+ "//vscode-messenger": "The `vscode-messenger` packages are optional peers: the channel restates the two messenger shapes structurally, so the runtime tiers never pin the copy GLSP's VS Code integration brings, and only `./testing`, which joins the real classes, loads them."
101
+ }
@@ -0,0 +1,10 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+
10
+ export * from './webview-data-port';