@theia/plugin-ext-headless 1.46.0-next.106
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 +32 -0
- package/lib/common/headless-plugin-container.d.ts +8 -0
- package/lib/common/headless-plugin-container.d.ts.map +1 -0
- package/lib/common/headless-plugin-container.js +26 -0
- package/lib/common/headless-plugin-container.js.map +1 -0
- package/lib/common/headless-plugin-protocol.d.ts +21 -0
- package/lib/common/headless-plugin-protocol.d.ts.map +1 -0
- package/lib/common/headless-plugin-protocol.js +26 -0
- package/lib/common/headless-plugin-protocol.js.map +1 -0
- package/lib/common/headless-plugin-rpc.d.ts +23 -0
- package/lib/common/headless-plugin-rpc.d.ts.map +1 -0
- package/lib/common/headless-plugin-rpc.js +31 -0
- package/lib/common/headless-plugin-rpc.js.map +1 -0
- package/lib/common/index.d.ts +5 -0
- package/lib/common/index.d.ts.map +1 -0
- package/lib/common/index.js +26 -0
- package/lib/common/index.js.map +1 -0
- package/lib/common/plugin-ext-headless-api-contribution.d.ts +38 -0
- package/lib/common/plugin-ext-headless-api-contribution.d.ts.map +1 -0
- package/lib/common/plugin-ext-headless-api-contribution.js +20 -0
- package/lib/common/plugin-ext-headless-api-contribution.js.map +1 -0
- package/lib/hosted/node/headless-hosted-plugin.d.ts +30 -0
- package/lib/hosted/node/headless-hosted-plugin.d.ts.map +1 -0
- package/lib/hosted/node/headless-hosted-plugin.js +184 -0
- package/lib/hosted/node/headless-hosted-plugin.js.map +1 -0
- package/lib/hosted/node/plugin-ext-headless-hosted-module.d.ts +4 -0
- package/lib/hosted/node/plugin-ext-headless-hosted-module.d.ts.map +1 -0
- package/lib/hosted/node/plugin-ext-headless-hosted-module.js +69 -0
- package/lib/hosted/node/plugin-ext-headless-hosted-module.js.map +1 -0
- package/lib/hosted/node/plugin-host-headless-module.d.ts +5 -0
- package/lib/hosted/node/plugin-host-headless-module.d.ts.map +1 -0
- package/lib/hosted/node/plugin-host-headless-module.js +73 -0
- package/lib/hosted/node/plugin-host-headless-module.js.map +1 -0
- package/lib/hosted/node/plugin-host-headless-rpc.d.ts +21 -0
- package/lib/hosted/node/plugin-host-headless-rpc.d.ts.map +1 -0
- package/lib/hosted/node/plugin-host-headless-rpc.js +74 -0
- package/lib/hosted/node/plugin-host-headless-rpc.js.map +1 -0
- package/lib/hosted/node/plugin-host-headless.d.ts +2 -0
- package/lib/hosted/node/plugin-host-headless.d.ts.map +1 -0
- package/lib/hosted/node/plugin-host-headless.js +104 -0
- package/lib/hosted/node/plugin-host-headless.js.map +1 -0
- package/lib/hosted/node/scanners/scanner-theia-headless.d.ts +26 -0
- package/lib/hosted/node/scanners/scanner-theia-headless.d.ts.map +1 -0
- package/lib/hosted/node/scanners/scanner-theia-headless.js +83 -0
- package/lib/hosted/node/scanners/scanner-theia-headless.js.map +1 -0
- package/lib/hosted/node-electron/plugin-ext-headless-hosted-electron-module.d.ts +3 -0
- package/lib/hosted/node-electron/plugin-ext-headless-hosted-electron-module.d.ts.map +1 -0
- package/lib/hosted/node-electron/plugin-ext-headless-hosted-electron-module.js +24 -0
- package/lib/hosted/node-electron/plugin-ext-headless-hosted-electron-module.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +20 -0
- package/lib/index.js.map +1 -0
- package/lib/main/node/handlers/plugin-theia-headless-directory-handler.d.ts +7 -0
- package/lib/main/node/handlers/plugin-theia-headless-directory-handler.d.ts.map +1 -0
- package/lib/main/node/handlers/plugin-theia-headless-directory-handler.js +38 -0
- package/lib/main/node/handlers/plugin-theia-headless-directory-handler.js.map +1 -0
- package/lib/main/node/headless-progress-client.d.ts +10 -0
- package/lib/main/node/headless-progress-client.d.ts.map +1 -0
- package/lib/main/node/headless-progress-client.js +47 -0
- package/lib/main/node/headless-progress-client.js.map +1 -0
- package/lib/main/node/main-context.d.ts +4 -0
- package/lib/main/node/main-context.d.ts.map +1 -0
- package/lib/main/node/main-context.js +19 -0
- package/lib/main/node/main-context.js.map +1 -0
- package/lib/main/node/plugin-ext-headless-main-module.d.ts +4 -0
- package/lib/main/node/plugin-ext-headless-main-module.d.ts.map +1 -0
- package/lib/main/node/plugin-ext-headless-main-module.js +38 -0
- package/lib/main/node/plugin-ext-headless-main-module.js.map +1 -0
- package/lib/package.spec.d.ts +1 -0
- package/lib/package.spec.d.ts.map +1 -0
- package/lib/package.spec.js +24 -0
- package/lib/package.spec.js.map +1 -0
- package/lib/plugin/headless-plugin-manager.d.ts +10 -0
- package/lib/plugin/headless-plugin-manager.d.ts.map +1 -0
- package/lib/plugin/headless-plugin-manager.js +51 -0
- package/lib/plugin/headless-plugin-manager.js.map +1 -0
- package/lib/plugin-ext-headless-electron-module.d.ts +4 -0
- package/lib/plugin-ext-headless-electron-module.d.ts.map +1 -0
- package/lib/plugin-ext-headless-electron-module.js +32 -0
- package/lib/plugin-ext-headless-electron-module.js.map +1 -0
- package/lib/plugin-ext-headless-module.d.ts +4 -0
- package/lib/plugin-ext-headless-module.d.ts.map +1 -0
- package/lib/plugin-ext-headless-module.js +31 -0
- package/lib/plugin-ext-headless-module.js.map +1 -0
- package/package.json +57 -0
- package/src/common/headless-plugin-container.ts +23 -0
- package/src/common/headless-plugin-protocol.ts +38 -0
- package/src/common/headless-plugin-rpc.ts +46 -0
- package/src/common/index.ts +23 -0
- package/src/common/plugin-ext-headless-api-contribution.ts +60 -0
- package/src/hosted/node/headless-hosted-plugin.ts +199 -0
- package/src/hosted/node/plugin-ext-headless-hosted-module.ts +75 -0
- package/src/hosted/node/plugin-host-headless-module.ts +76 -0
- package/src/hosted/node/plugin-host-headless-rpc.ts +80 -0
- package/src/hosted/node/plugin-host-headless.ts +111 -0
- package/src/hosted/node/scanners/scanner-theia-headless.ts +85 -0
- package/src/hosted/node-electron/plugin-ext-headless-hosted-electron-module.ts +22 -0
- package/src/index.ts +17 -0
- package/src/main/node/handlers/plugin-theia-headless-directory-handler.ts +35 -0
- package/src/main/node/headless-progress-client.ts +44 -0
- package/src/main/node/main-context.ts +35 -0
- package/src/main/node/plugin-ext-headless-main-module.ts +42 -0
- package/src/package.spec.ts +25 -0
- package/src/plugin/headless-plugin-manager.ts +50 -0
- package/src/plugin-ext-headless-electron-module.ts +32 -0
- package/src/plugin-ext-headless-module.ts +31 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 EclipseSource and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
/*---------------------------------------------------------------------------------------------
|
|
17
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
18
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
19
|
+
*--------------------------------------------------------------------------------------------*/
|
|
20
|
+
// some code copied and modified from https://github.com/microsoft/vscode/blob/da5fb7d5b865aa522abc7e82c10b746834b98639/src/vs/workbench/api/node/extHostExtensionService.ts
|
|
21
|
+
|
|
22
|
+
import { generateUuid } from '@theia/core/lib/common/uuid';
|
|
23
|
+
import { injectable, inject, named } from '@theia/core/shared/inversify';
|
|
24
|
+
import { getPluginId, DeployedPlugin, HostedPluginServer, PluginDeployer } from '@theia/plugin-ext/lib/common/plugin-protocol';
|
|
25
|
+
import { setUpPluginApi } from '../../main/node/main-context';
|
|
26
|
+
import { RPCProtocol, RPCProtocolImpl } from '@theia/plugin-ext/lib/common/rpc-protocol';
|
|
27
|
+
import { ContributionProvider, Disposable, DisposableCollection, nls } from '@theia/core';
|
|
28
|
+
import { environment } from '@theia/core/shared/@theia/application-package/lib/environment';
|
|
29
|
+
import { IPCChannel } from '@theia/core/lib/node';
|
|
30
|
+
import { BackendApplicationConfigProvider } from '@theia/core/lib/node/backend-application-config-provider';
|
|
31
|
+
import { HostedPluginProcess } from '@theia/plugin-ext/lib/hosted/node/hosted-plugin-process';
|
|
32
|
+
import { IShellTerminalServer } from '@theia/terminal/lib/common/shell-terminal-protocol';
|
|
33
|
+
import { HeadlessPluginManagerExt, HEADLESSMAIN_RPC_CONTEXT } from '../../common/headless-plugin-rpc';
|
|
34
|
+
import { AbstractHostedPluginSupport, PluginContributions } from '@theia/plugin-ext/lib/hosted/common/hosted-plugin';
|
|
35
|
+
import { TheiaHeadlessPluginScanner } from './scanners/scanner-theia-headless';
|
|
36
|
+
import { SupportedHeadlessActivationEvents } from '../../common/headless-plugin-protocol';
|
|
37
|
+
import { PluginDeployerImpl } from '@theia/plugin-ext/lib/main/node/plugin-deployer-impl';
|
|
38
|
+
|
|
39
|
+
import URI from '@theia/core/lib/common/uri';
|
|
40
|
+
import * as fs from 'fs';
|
|
41
|
+
import * as asyncFs from 'fs/promises';
|
|
42
|
+
|
|
43
|
+
export type HeadlessPluginHost = string;
|
|
44
|
+
|
|
45
|
+
export function isHeadlessPlugin(plugin: DeployedPlugin): boolean {
|
|
46
|
+
return !!plugin.metadata.model.entryPoint.headless;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@injectable()
|
|
50
|
+
export class HeadlessHostedPluginSupport extends AbstractHostedPluginSupport<HeadlessPluginManagerExt, HostedPluginServer> {
|
|
51
|
+
|
|
52
|
+
@inject(HostedPluginProcess)
|
|
53
|
+
protected readonly pluginProcess: HostedPluginProcess;
|
|
54
|
+
|
|
55
|
+
@inject(IShellTerminalServer)
|
|
56
|
+
protected readonly shellTerminalServer: IShellTerminalServer;
|
|
57
|
+
|
|
58
|
+
@inject(TheiaHeadlessPluginScanner)
|
|
59
|
+
protected readonly scanner: TheiaHeadlessPluginScanner;
|
|
60
|
+
|
|
61
|
+
@inject(PluginDeployer)
|
|
62
|
+
protected readonly pluginDeployer: PluginDeployerImpl;
|
|
63
|
+
|
|
64
|
+
@inject(ContributionProvider)
|
|
65
|
+
@named(SupportedHeadlessActivationEvents)
|
|
66
|
+
protected readonly supportedActivationEventsContributions: ContributionProvider<string[]>;
|
|
67
|
+
|
|
68
|
+
constructor() {
|
|
69
|
+
super(generateUuid());
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
shutDown(): void {
|
|
73
|
+
this.pluginProcess.terminatePluginServer();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
protected createTheiaReadyPromise(): Promise<unknown> {
|
|
77
|
+
return Promise.all([this.envServer.getVariables()]);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Only load headless plugins
|
|
81
|
+
protected acceptPlugin(plugin: DeployedPlugin): boolean | DeployedPlugin {
|
|
82
|
+
if (!isHeadlessPlugin(plugin)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (plugin.metadata.model.engine.type === this.scanner.apiType) {
|
|
87
|
+
// Easy case: take it as it is
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Adapt it for headless
|
|
92
|
+
return this.scanner.adaptForHeadless(plugin);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
protected handleContributions(_plugin: DeployedPlugin): Disposable {
|
|
96
|
+
// We have no contribution points, yet, for headless plugins
|
|
97
|
+
return Disposable.NULL;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
protected override async beforeSyncPlugins(toDisconnect: DisposableCollection): Promise<void> {
|
|
101
|
+
await super.beforeSyncPlugins(toDisconnect);
|
|
102
|
+
|
|
103
|
+
// Plugin deployment is asynchronous, so wait until that's finished.
|
|
104
|
+
return new Promise<void>((resolve, reject) => {
|
|
105
|
+
this.pluginDeployer.onDidDeploy(resolve);
|
|
106
|
+
toDisconnect.push(Disposable.create(reject));
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
protected async obtainManager(host: string, hostContributions: PluginContributions[], toDisconnect: DisposableCollection): Promise<HeadlessPluginManagerExt | undefined> {
|
|
111
|
+
let manager = this.managers.get(host);
|
|
112
|
+
if (!manager) {
|
|
113
|
+
const pluginId = getPluginId(hostContributions[0].plugin.metadata.model);
|
|
114
|
+
const rpc = this.initRpc(host, pluginId);
|
|
115
|
+
toDisconnect.push(rpc);
|
|
116
|
+
|
|
117
|
+
manager = rpc.getProxy(HEADLESSMAIN_RPC_CONTEXT.HOSTED_PLUGIN_MANAGER_EXT);
|
|
118
|
+
this.managers.set(host, manager);
|
|
119
|
+
toDisconnect.push(Disposable.create(() => this.managers.delete(host)));
|
|
120
|
+
|
|
121
|
+
const [extApi, globalState] = await Promise.all([
|
|
122
|
+
this.server.getExtPluginAPI(),
|
|
123
|
+
this.pluginServer.getAllStorageValues(undefined)
|
|
124
|
+
]);
|
|
125
|
+
if (toDisconnect.disposed) {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const activationEvents = this.supportedActivationEventsContributions.getContributions().flatMap(array => array);
|
|
130
|
+
const shell = await this.shellTerminalServer.getDefaultShell();
|
|
131
|
+
const isElectron = environment.electron.is();
|
|
132
|
+
|
|
133
|
+
await manager.$init({
|
|
134
|
+
activationEvents,
|
|
135
|
+
globalState,
|
|
136
|
+
env: {
|
|
137
|
+
language: nls.locale || nls.defaultLocale,
|
|
138
|
+
shell,
|
|
139
|
+
appName: BackendApplicationConfigProvider.get().applicationName,
|
|
140
|
+
appHost: isElectron ? 'desktop' : 'web' // TODO: 'web' could be the embedder's name, e.g. 'github.dev'
|
|
141
|
+
},
|
|
142
|
+
extApi
|
|
143
|
+
});
|
|
144
|
+
if (toDisconnect.disposed) {
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return manager;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
protected initRpc(host: HeadlessPluginHost, pluginId: string): RPCProtocol {
|
|
152
|
+
const rpc = this.createServerRpc(host);
|
|
153
|
+
this.container.bind(RPCProtocol).toConstantValue(rpc);
|
|
154
|
+
setUpPluginApi(rpc, this.container);
|
|
155
|
+
this.mainPluginApiProviders.getContributions().forEach(p => p.initialize(rpc, this.container));
|
|
156
|
+
return rpc;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
protected createServerRpc(pluginHostId: string): RPCProtocol {
|
|
160
|
+
const channel = new IPCChannel(this.pluginProcess['childProcess']);
|
|
161
|
+
|
|
162
|
+
return new RPCProtocolImpl(channel);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
protected async getStoragePath(): Promise<string | undefined> {
|
|
166
|
+
// Headless plugins are associated with the main Node process, so
|
|
167
|
+
// their storage is the global storage.
|
|
168
|
+
return this.getHostGlobalStoragePath();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
protected async getHostGlobalStoragePath(): Promise<string> {
|
|
172
|
+
const configDirUri = await this.envServer.getConfigDirUri();
|
|
173
|
+
const globalStorageFolderUri = new URI(configDirUri).resolve('globalStorage');
|
|
174
|
+
const globalStorageFolderUrl = new URL(globalStorageFolderUri.toString());
|
|
175
|
+
|
|
176
|
+
let stat: fs.Stats | undefined;
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
stat = await asyncFs.stat(globalStorageFolderUrl);
|
|
180
|
+
} catch (_) {
|
|
181
|
+
// OK, no such directory
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (stat && !stat.isDirectory()) {
|
|
185
|
+
throw new Error(`Global storage folder is not a directory: ${globalStorageFolderUri}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Make sure that folder by the path exists
|
|
189
|
+
if (!stat) {
|
|
190
|
+
await asyncFs.mkdir(globalStorageFolderUrl, { recursive: true });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const globalStorageFolderFsPath = await asyncFs.realpath(globalStorageFolderUrl);
|
|
194
|
+
if (!globalStorageFolderFsPath) {
|
|
195
|
+
throw new Error(`Could not resolve the FS path for URI: ${globalStorageFolderUri}`);
|
|
196
|
+
}
|
|
197
|
+
return globalStorageFolderFsPath;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 EclipseSource and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import * as path from 'path';
|
|
18
|
+
import { bindContributionProvider } from '@theia/core/lib/common/contribution-provider';
|
|
19
|
+
import { BackendApplicationContribution } from '@theia/core/lib/node';
|
|
20
|
+
import { ContainerModule, interfaces } from '@theia/core/shared/inversify';
|
|
21
|
+
import { ExtPluginApiProvider, HostedPluginServer, PluginHostEnvironmentVariable, PluginScanner } from '@theia/plugin-ext';
|
|
22
|
+
import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/node/hosted-plugin';
|
|
23
|
+
import { HostedPluginProcess, HostedPluginProcessConfiguration } from '@theia/plugin-ext/lib/hosted/node/hosted-plugin-process';
|
|
24
|
+
import { BackendPluginHostableFilter, HostedPluginServerImpl } from '@theia/plugin-ext/lib/hosted/node/plugin-service';
|
|
25
|
+
import { MaybePromise } from '@theia/core';
|
|
26
|
+
import { HeadlessPluginContainerModule } from '../../common/headless-plugin-container';
|
|
27
|
+
import { HeadlessHostedPluginSupport, isHeadlessPlugin } from './headless-hosted-plugin';
|
|
28
|
+
import { TheiaHeadlessPluginScanner } from './scanners/scanner-theia-headless';
|
|
29
|
+
import { SupportedHeadlessActivationEvents } from '../../common/headless-plugin-protocol';
|
|
30
|
+
|
|
31
|
+
export function bindCommonHostedBackend(bind: interfaces.Bind): void {
|
|
32
|
+
bind(HostedPluginProcess).toSelf().inSingletonScope();
|
|
33
|
+
bind(HostedPluginSupport).toSelf().inSingletonScope();
|
|
34
|
+
|
|
35
|
+
bindContributionProvider(bind, Symbol.for(ExtPluginApiProvider));
|
|
36
|
+
bindContributionProvider(bind, PluginHostEnvironmentVariable);
|
|
37
|
+
bindContributionProvider(bind, SupportedHeadlessActivationEvents);
|
|
38
|
+
|
|
39
|
+
bind(HostedPluginServerImpl).toSelf().inSingletonScope();
|
|
40
|
+
bind(HostedPluginServer).toService(HostedPluginServerImpl);
|
|
41
|
+
bind(HeadlessHostedPluginSupport).toSelf().inSingletonScope();
|
|
42
|
+
bind(BackendPluginHostableFilter).toConstantValue(isHeadlessPlugin);
|
|
43
|
+
|
|
44
|
+
bind(HostedPluginProcessConfiguration).toConstantValue({
|
|
45
|
+
path: path.join(__dirname, 'plugin-host-headless'),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function bindHeadlessHosted(bind: interfaces.Bind): void {
|
|
50
|
+
bind(TheiaHeadlessPluginScanner).toSelf().inSingletonScope();
|
|
51
|
+
bind(PluginScanner).toService(TheiaHeadlessPluginScanner);
|
|
52
|
+
bind(SupportedHeadlessActivationEvents).toConstantValue(['*', 'onStartupFinished']);
|
|
53
|
+
|
|
54
|
+
bind(BackendApplicationContribution).toDynamicValue(({container}) => {
|
|
55
|
+
let hostedPluginSupport: HeadlessHostedPluginSupport | undefined;
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
onStart(): MaybePromise<void> {
|
|
59
|
+
// Create a child container to isolate the Headless Plugin hosting stack
|
|
60
|
+
// from all connection-scoped frontend/backend plugin hosts and
|
|
61
|
+
// also to avoid leaking it into the global container scope
|
|
62
|
+
const headlessPluginsContainer = container.createChild();
|
|
63
|
+
const modules = container.getAll<ContainerModule>(HeadlessPluginContainerModule);
|
|
64
|
+
headlessPluginsContainer.load(...modules);
|
|
65
|
+
|
|
66
|
+
hostedPluginSupport = headlessPluginsContainer.get(HeadlessHostedPluginSupport);
|
|
67
|
+
hostedPluginSupport.onStart(headlessPluginsContainer);
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
onStop(): void {
|
|
71
|
+
hostedPluginSupport?.shutDown();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 EclipseSource and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
import '@theia/core/shared/reflect-metadata';
|
|
17
|
+
import { ContainerModule } from '@theia/core/shared/inversify';
|
|
18
|
+
import { RPCProtocol, RPCProtocolImpl } from '@theia/plugin-ext/lib/common/rpc-protocol';
|
|
19
|
+
import { AbstractPluginHostRPC, PluginContainerModuleLoader } from '@theia/plugin-ext/lib/hosted/node/plugin-host-rpc';
|
|
20
|
+
import { AbstractPluginManagerExtImpl, MinimalTerminalServiceExt } from '@theia/plugin-ext/lib/plugin/plugin-manager';
|
|
21
|
+
import { HeadlessPluginHostRPC } from './plugin-host-headless-rpc';
|
|
22
|
+
import { HeadlessPluginManagerExtImpl } from '../../plugin/headless-plugin-manager';
|
|
23
|
+
import { IPCChannel } from '@theia/core/lib/node';
|
|
24
|
+
import { InternalPluginContainerModule } from '@theia/plugin-ext/lib/plugin/node/plugin-container-module';
|
|
25
|
+
|
|
26
|
+
import { EnvExtImpl } from '@theia/plugin-ext/lib/plugin/env';
|
|
27
|
+
import { EnvNodeExtImpl } from '@theia/plugin-ext/lib/plugin/node/env-node-ext';
|
|
28
|
+
import { LocalizationExt } from '@theia/plugin-ext';
|
|
29
|
+
import { LocalizationExtImpl } from '@theia/plugin-ext/lib/plugin/localization-ext';
|
|
30
|
+
import { InternalStorageExt } from '@theia/plugin-ext/lib/plugin/plugin-storage';
|
|
31
|
+
import { InternalSecretsExt } from '@theia/plugin-ext/lib/plugin/secrets-ext';
|
|
32
|
+
import { EnvironmentVariableCollectionImpl } from '@theia/plugin-ext/lib/plugin/terminal-ext';
|
|
33
|
+
import { Disposable } from '@theia/core';
|
|
34
|
+
|
|
35
|
+
export default new ContainerModule(bind => {
|
|
36
|
+
const channel = new IPCChannel();
|
|
37
|
+
bind(RPCProtocol).toConstantValue(new RPCProtocolImpl(channel));
|
|
38
|
+
|
|
39
|
+
bind(PluginContainerModuleLoader).toDynamicValue(({ container }) =>
|
|
40
|
+
(module: ContainerModule) => {
|
|
41
|
+
container.load(module);
|
|
42
|
+
const internalModule = module as InternalPluginContainerModule;
|
|
43
|
+
const pluginApiCache = internalModule.initializeApi?.(container);
|
|
44
|
+
return pluginApiCache;
|
|
45
|
+
}).inSingletonScope();
|
|
46
|
+
|
|
47
|
+
bind(AbstractPluginHostRPC).toService(HeadlessPluginHostRPC);
|
|
48
|
+
bind(HeadlessPluginHostRPC).toSelf().inSingletonScope();
|
|
49
|
+
bind(AbstractPluginManagerExtImpl).toService(HeadlessPluginManagerExtImpl);
|
|
50
|
+
bind(HeadlessPluginManagerExtImpl).toSelf().inSingletonScope();
|
|
51
|
+
bind(EnvExtImpl).to(EnvNodeExtImpl).inSingletonScope();
|
|
52
|
+
bind(LocalizationExt).to(LocalizationExtImpl).inSingletonScope();
|
|
53
|
+
|
|
54
|
+
const dummySecrets: InternalSecretsExt = {
|
|
55
|
+
get: () => Promise.resolve(undefined),
|
|
56
|
+
store: () => Promise.resolve(undefined),
|
|
57
|
+
delete: () => Promise.resolve(undefined),
|
|
58
|
+
$onDidChangePassword: () => Promise.resolve(),
|
|
59
|
+
onDidChangePassword: () => Disposable.NULL,
|
|
60
|
+
};
|
|
61
|
+
const dummyStorage: InternalStorageExt = {
|
|
62
|
+
init: () => undefined,
|
|
63
|
+
setPerPluginData: () => Promise.resolve(false),
|
|
64
|
+
getPerPluginData: () => ({}),
|
|
65
|
+
storageDataChangedEvent: () => Disposable.NULL,
|
|
66
|
+
$updatePluginsWorkspaceData: () => undefined
|
|
67
|
+
};
|
|
68
|
+
const dummyTerminalService: MinimalTerminalServiceExt = {
|
|
69
|
+
$initEnvironmentVariableCollections: () => undefined,
|
|
70
|
+
$setShell: () => undefined,
|
|
71
|
+
getEnvironmentVariableCollection: () => new EnvironmentVariableCollectionImpl(false),
|
|
72
|
+
};
|
|
73
|
+
bind(InternalSecretsExt).toConstantValue(dummySecrets);
|
|
74
|
+
bind(InternalStorageExt).toConstantValue(dummyStorage);
|
|
75
|
+
bind(MinimalTerminalServiceExt).toConstantValue(dummyTerminalService);
|
|
76
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 EclipseSource and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { dynamicRequire } from '@theia/core/lib/node/dynamic-require';
|
|
18
|
+
import { ContainerModule, injectable, inject } from '@theia/core/shared/inversify';
|
|
19
|
+
import { EnvExtImpl } from '@theia/plugin-ext/lib/plugin/env';
|
|
20
|
+
import { LocalizationExt } from '@theia/plugin-ext';
|
|
21
|
+
import { LocalizationExtImpl } from '@theia/plugin-ext/lib/plugin/localization-ext';
|
|
22
|
+
import { HEADLESSMAIN_RPC_CONTEXT } from '../../common/headless-plugin-rpc';
|
|
23
|
+
import { HeadlessPluginManagerExtImpl } from '../../plugin/headless-plugin-manager';
|
|
24
|
+
import { AbstractPluginHostRPC, ExtInterfaces } from '@theia/plugin-ext/lib/hosted/node/plugin-host-rpc';
|
|
25
|
+
import { PluginModel } from '@theia/plugin-ext/lib/common/plugin-protocol';
|
|
26
|
+
import { ExtPluginApi, ExtPluginApiHeadlessInitializationFn } from '../../common/plugin-ext-headless-api-contribution';
|
|
27
|
+
|
|
28
|
+
type HeadlessExtInterfaces = Pick<ExtInterfaces, 'envExt'|'localizationExt'>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The RPC handler for headless plugins.
|
|
32
|
+
*/
|
|
33
|
+
@injectable()
|
|
34
|
+
export class HeadlessPluginHostRPC extends AbstractPluginHostRPC<HeadlessPluginManagerExtImpl, null, HeadlessExtInterfaces> {
|
|
35
|
+
@inject(EnvExtImpl)
|
|
36
|
+
protected readonly envExt: EnvExtImpl;
|
|
37
|
+
|
|
38
|
+
@inject(LocalizationExt)
|
|
39
|
+
protected readonly localizationExt: LocalizationExtImpl;
|
|
40
|
+
|
|
41
|
+
constructor() {
|
|
42
|
+
super('HEADLESS_PLUGIN_HOST', undefined,
|
|
43
|
+
{
|
|
44
|
+
$pluginManager: HEADLESSMAIN_RPC_CONTEXT.HOSTED_PLUGIN_MANAGER_EXT,
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
protected createExtInterfaces(): HeadlessExtInterfaces {
|
|
50
|
+
return {
|
|
51
|
+
envExt: this.envExt,
|
|
52
|
+
localizationExt: this.localizationExt
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
protected createAPIFactory(_extInterfaces: HeadlessExtInterfaces): null {
|
|
57
|
+
// As yet there is no default API namespace for backend plugins to access the Theia framework
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
protected override getBackendPluginPath(pluginModel: PluginModel): string | undefined {
|
|
62
|
+
return pluginModel.entryPoint.headless;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
protected initExtApi(extApi: ExtPluginApi): void {
|
|
66
|
+
interface PluginExports {
|
|
67
|
+
containerModule?: ContainerModule;
|
|
68
|
+
provideApi?: ExtPluginApiHeadlessInitializationFn;
|
|
69
|
+
}
|
|
70
|
+
if (extApi.headlessInitPath) {
|
|
71
|
+
const { containerModule, provideApi } = dynamicRequire<PluginExports>(extApi.headlessInitPath);
|
|
72
|
+
if (containerModule) {
|
|
73
|
+
this.loadContainerModule(containerModule);
|
|
74
|
+
}
|
|
75
|
+
if (provideApi) {
|
|
76
|
+
provideApi(this.rpc, this.pluginManager);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2018 Red Hat, Inc. and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
import '@theia/core/shared/reflect-metadata';
|
|
17
|
+
import { Container } from '@theia/core/shared/inversify';
|
|
18
|
+
import { ConnectionClosedError, RPCProtocol } from '@theia/plugin-ext/lib/common/rpc-protocol';
|
|
19
|
+
import { ProcessTerminatedMessage, ProcessTerminateMessage } from '@theia/plugin-ext/lib/hosted/node/hosted-plugin-protocol';
|
|
20
|
+
import { HeadlessPluginHostRPC } from './plugin-host-headless-rpc';
|
|
21
|
+
import pluginHostModule from './plugin-host-headless-module';
|
|
22
|
+
|
|
23
|
+
const banner = `HEADLESS_PLUGIN_HOST(${process.pid}):`;
|
|
24
|
+
console.log(banner, 'Starting instance');
|
|
25
|
+
|
|
26
|
+
// override exit() function, to do not allow plugin kill this node
|
|
27
|
+
process.exit = function (code?: number): void {
|
|
28
|
+
const err = new Error('A plugin called process.exit() but it was blocked.');
|
|
29
|
+
console.warn(banner, err.stack);
|
|
30
|
+
} as (code?: number) => never;
|
|
31
|
+
|
|
32
|
+
// same for 'crash'(works only in electron)
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
const proc = process as any;
|
|
35
|
+
if (proc.crash) {
|
|
36
|
+
proc.crash = function (): void {
|
|
37
|
+
const err = new Error('A plugin called process.crash() but it was blocked.');
|
|
38
|
+
console.warn(banner, err.stack);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
process.on('uncaughtException', (err: Error) => {
|
|
43
|
+
console.error(banner, err);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
47
|
+
const unhandledPromises: Promise<any>[] = [];
|
|
48
|
+
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
+
process.on('unhandledRejection', (reason: any, promise: Promise<any>) => {
|
|
51
|
+
unhandledPromises.push(promise);
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
const index = unhandledPromises.indexOf(promise);
|
|
54
|
+
if (index >= 0) {
|
|
55
|
+
promise.catch(err => {
|
|
56
|
+
unhandledPromises.splice(index, 1);
|
|
57
|
+
if (terminating && (ConnectionClosedError.is(err) || ConnectionClosedError.is(reason))) {
|
|
58
|
+
// during termination it is expected that pending rpc request are rejected
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
console.error(banner, `Promise rejection not handled in one second: ${err} , reason: ${reason}`);
|
|
62
|
+
if (err && err.stack) {
|
|
63
|
+
console.error(banner, `With stack trace: ${err.stack}`);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}, 1000);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
|
+
process.on('rejectionHandled', (promise: Promise<any>) => {
|
|
72
|
+
const index = unhandledPromises.indexOf(promise);
|
|
73
|
+
if (index >= 0) {
|
|
74
|
+
unhandledPromises.splice(index, 1);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
let terminating = false;
|
|
79
|
+
|
|
80
|
+
const container = new Container();
|
|
81
|
+
container.load(pluginHostModule);
|
|
82
|
+
|
|
83
|
+
const rpc: RPCProtocol = container.get(RPCProtocol);
|
|
84
|
+
const pluginHostRPC = container.get(HeadlessPluginHostRPC);
|
|
85
|
+
|
|
86
|
+
process.on('message', async (message: string) => {
|
|
87
|
+
if (terminating) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const msg = JSON.parse(message);
|
|
92
|
+
if (ProcessTerminateMessage.is(msg)) {
|
|
93
|
+
terminating = true;
|
|
94
|
+
if (msg.stopTimeout) {
|
|
95
|
+
await Promise.race([
|
|
96
|
+
pluginHostRPC.terminate(),
|
|
97
|
+
new Promise(resolve => setTimeout(resolve, msg.stopTimeout))
|
|
98
|
+
]);
|
|
99
|
+
} else {
|
|
100
|
+
await pluginHostRPC.terminate();
|
|
101
|
+
}
|
|
102
|
+
rpc.dispose();
|
|
103
|
+
if (process.send) {
|
|
104
|
+
process.send(JSON.stringify({ type: ProcessTerminatedMessage.TYPE }));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
} catch (e) {
|
|
109
|
+
console.error(banner, e);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 EclipseSource and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
/* eslint-disable @theia/localization-check */
|
|
18
|
+
|
|
19
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
20
|
+
import { DeployedPlugin, PluginPackage, PluginEntryPoint } from '@theia/plugin-ext';
|
|
21
|
+
import { AbstractPluginScanner } from '@theia/plugin-ext/lib/hosted/node/scanners/scanner-theia';
|
|
22
|
+
import { deepClone } from '@theia/core/lib/common/objects';
|
|
23
|
+
|
|
24
|
+
@injectable()
|
|
25
|
+
export class TheiaHeadlessPluginScanner extends AbstractPluginScanner {
|
|
26
|
+
|
|
27
|
+
constructor() {
|
|
28
|
+
super('theiaHeadlessPlugin');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
protected getEntryPoint(plugin: PluginPackage): PluginEntryPoint {
|
|
32
|
+
if (plugin?.theiaPlugin?.headless) {
|
|
33
|
+
return {
|
|
34
|
+
headless: plugin.theiaPlugin.headless
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
headless: plugin.main
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Adapt the given `plugin`'s metadata for headless deployment, where it does not
|
|
45
|
+
* already natively specify its headless deployment, such as is the case for plugins
|
|
46
|
+
* declaring the `"vscode"` or `"theiaPlugin"` engine. This consists of cloning the
|
|
47
|
+
* relevant properties of its deployment metadata and modifying them as required,
|
|
48
|
+
* including but not limited to:
|
|
49
|
+
*
|
|
50
|
+
* - renaming the `lifecycle` start and stop functions as 'activate' and 'deactivate'
|
|
51
|
+
* following the VS Code naming convention (in case the `plugin` is a Theia-style
|
|
52
|
+
* plugin that uses 'start' and 'stop')
|
|
53
|
+
* - deleting inapplicable information such as frontend and backend init script paths
|
|
54
|
+
* - filtering/rewriting contributions and/or activation events
|
|
55
|
+
*
|
|
56
|
+
* The cloning is necessary to retain the original information for the non-headless
|
|
57
|
+
* deployments that the plugin also supports.
|
|
58
|
+
*/
|
|
59
|
+
adaptForHeadless(plugin: DeployedPlugin): DeployedPlugin {
|
|
60
|
+
return {
|
|
61
|
+
type: plugin.type,
|
|
62
|
+
metadata: this.adaptMetadataForHeadless(plugin),
|
|
63
|
+
contributes: this.adaptContributesForHeadless(plugin)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
protected adaptMetadataForHeadless(plugin: DeployedPlugin): DeployedPlugin['metadata'] {
|
|
68
|
+
const result = deepClone(plugin.metadata);
|
|
69
|
+
|
|
70
|
+
const lifecycle = result.lifecycle;
|
|
71
|
+
delete lifecycle.frontendInitPath;
|
|
72
|
+
delete lifecycle.backendInitPath;
|
|
73
|
+
|
|
74
|
+
// Same as in VS Code
|
|
75
|
+
lifecycle.startMethod = 'activate';
|
|
76
|
+
lifecycle.stopMethod = 'deactivate';
|
|
77
|
+
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
protected adaptContributesForHeadless(plugin: DeployedPlugin): DeployedPlugin['contributes'] {
|
|
82
|
+
// We don't yet support and contribution points in headless plugins
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 EclipseSource and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { interfaces } from '@theia/core/shared/inversify';
|
|
18
|
+
import { bindCommonHostedBackend } from '../node/plugin-ext-headless-hosted-module';
|
|
19
|
+
|
|
20
|
+
export function bindElectronBackend(bind: interfaces.Bind): void {
|
|
21
|
+
bindCommonHostedBackend(bind);
|
|
22
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 EclipseSource and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
export * from './common';
|