@theia/plugin-ext 1.76.0-next.7 → 1.77.0-next.0
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/lib/common/paths-util.d.ts.map +1 -1
- package/lib/common/paths-util.js +9 -2
- package/lib/common/paths-util.js.map +1 -1
- package/lib/common/paths-util.spec.d.ts +2 -0
- package/lib/common/paths-util.spec.d.ts.map +1 -0
- package/lib/common/paths-util.spec.js +42 -0
- package/lib/common/paths-util.spec.js.map +1 -0
- package/lib/common/plugin-api-rpc.d.ts +14 -0
- package/lib/common/plugin-api-rpc.d.ts.map +1 -1
- package/lib/common/plugin-api-rpc.js +1 -1
- package/lib/common/plugin-api-rpc.js.map +1 -1
- package/lib/common/plugin-protocol.d.ts +2 -2
- package/lib/common/plugin-protocol.d.ts.map +1 -1
- package/lib/common/plugin-protocol.js +2 -1
- package/lib/common/plugin-protocol.js.map +1 -1
- package/lib/hosted/browser/hosted-plugin.d.ts +2 -0
- package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
- package/lib/hosted/browser/hosted-plugin.js +9 -3
- package/lib/hosted/browser/hosted-plugin.js.map +1 -1
- package/lib/hosted/browser/worker/worker-main.js +22 -12
- package/lib/hosted/browser/worker/worker-main.js.map +1 -1
- package/lib/hosted/browser/worker/worker-plugin-module.d.ts.map +1 -1
- package/lib/hosted/browser/worker/worker-plugin-module.js +2 -0
- package/lib/hosted/browser/worker/worker-plugin-module.js.map +1 -1
- package/lib/hosted/browser-only/browser-only-hosted-plugin-server.d.ts +37 -0
- package/lib/hosted/browser-only/browser-only-hosted-plugin-server.d.ts.map +1 -0
- package/lib/hosted/browser-only/browser-only-hosted-plugin-server.js +107 -0
- package/lib/hosted/browser-only/browser-only-hosted-plugin-server.js.map +1 -0
- package/lib/hosted/browser-only/browser-only-hosted-plugin-server.spec.d.ts +2 -0
- package/lib/hosted/browser-only/browser-only-hosted-plugin-server.spec.d.ts.map +1 -0
- package/lib/hosted/browser-only/browser-only-hosted-plugin-server.spec.js +106 -0
- package/lib/hosted/browser-only/browser-only-hosted-plugin-server.spec.js.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-file-system-provider.d.ts +38 -0
- package/lib/hosted/browser-only/browser-only-plugin-file-system-provider.d.ts.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-file-system-provider.js +124 -0
- package/lib/hosted/browser-only/browser-only-plugin-file-system-provider.js.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-file-system-provider.spec.d.ts +2 -0
- package/lib/hosted/browser-only/browser-only-plugin-file-system-provider.spec.d.ts.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-file-system-provider.spec.js +137 -0
- package/lib/hosted/browser-only/browser-only-plugin-file-system-provider.spec.js.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-paths-service.d.ts +43 -0
- package/lib/hosted/browser-only/browser-only-plugin-paths-service.d.ts.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-paths-service.js +145 -0
- package/lib/hosted/browser-only/browser-only-plugin-paths-service.js.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-paths-service.spec.d.ts +2 -0
- package/lib/hosted/browser-only/browser-only-plugin-paths-service.spec.d.ts.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-paths-service.spec.js +165 -0
- package/lib/hosted/browser-only/browser-only-plugin-paths-service.spec.js.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-server.d.ts +54 -0
- package/lib/hosted/browser-only/browser-only-plugin-server.d.ts.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-server.js +155 -0
- package/lib/hosted/browser-only/browser-only-plugin-server.js.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-server.spec.d.ts +2 -0
- package/lib/hosted/browser-only/browser-only-plugin-server.spec.d.ts.map +1 -0
- package/lib/hosted/browser-only/browser-only-plugin-server.spec.js +190 -0
- package/lib/hosted/browser-only/browser-only-plugin-server.spec.js.map +1 -0
- package/lib/hosted/browser-only/test/navigator-locks-test-util.d.ts +24 -0
- package/lib/hosted/browser-only/test/navigator-locks-test-util.d.ts.map +1 -0
- package/lib/hosted/browser-only/test/navigator-locks-test-util.js +46 -0
- package/lib/hosted/browser-only/test/navigator-locks-test-util.js.map +1 -0
- package/lib/hosted/common/hosted-plugin.d.ts +2 -2
- package/lib/hosted/common/hosted-plugin.d.ts.map +1 -1
- package/lib/hosted/common/hosted-plugin.js +2 -2
- package/lib/hosted/common/hosted-plugin.js.map +1 -1
- package/lib/hosted/node/plugin-host-module.d.ts.map +1 -1
- package/lib/hosted/node/plugin-host-module.js +2 -0
- package/lib/hosted/node/plugin-host-module.js.map +1 -1
- package/lib/hosted/node/plugin-host-rpc.d.ts +3 -0
- package/lib/hosted/node/plugin-host-rpc.d.ts.map +1 -1
- package/lib/hosted/node/plugin-host-rpc.js +9 -3
- package/lib/hosted/node/plugin-host-rpc.js.map +1 -1
- package/lib/main/browser/editors-and-documents-main.d.ts +7 -0
- package/lib/main/browser/editors-and-documents-main.d.ts.map +1 -1
- package/lib/main/browser/editors-and-documents-main.js +19 -9
- package/lib/main/browser/editors-and-documents-main.js.map +1 -1
- package/lib/main/browser/editors-and-documents-main.spec.d.ts +2 -0
- package/lib/main/browser/editors-and-documents-main.spec.d.ts.map +1 -0
- package/lib/main/browser/editors-and-documents-main.spec.js +117 -0
- package/lib/main/browser/editors-and-documents-main.spec.js.map +1 -0
- package/lib/main/browser/languages-main.d.ts +7 -0
- package/lib/main/browser/languages-main.d.ts.map +1 -1
- package/lib/main/browser/languages-main.js +31 -9
- package/lib/main/browser/languages-main.js.map +1 -1
- package/lib/main/browser/languages-main.spec.d.ts +2 -0
- package/lib/main/browser/languages-main.spec.d.ts.map +1 -0
- package/lib/main/browser/languages-main.spec.js +82 -0
- package/lib/main/browser/languages-main.spec.js.map +1 -0
- package/lib/main/browser/main-context.d.ts.map +1 -1
- package/lib/main/browser/main-context.js +3 -0
- package/lib/main/browser/main-context.js.map +1 -1
- package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts +5 -0
- package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts.map +1 -1
- package/lib/main/browser/menus/vscode-theia-menu-mappings.js +5 -0
- package/lib/main/browser/menus/vscode-theia-menu-mappings.js.map +1 -1
- package/lib/main/browser/plugin-ext-frontend-module.d.ts.map +1 -1
- package/lib/main/browser/plugin-ext-frontend-module.js +1 -0
- package/lib/main/browser/plugin-ext-frontend-module.js.map +1 -1
- package/lib/main/browser/plugin-icon-service.d.ts +6 -0
- package/lib/main/browser/plugin-icon-service.d.ts.map +1 -1
- package/lib/main/browser/plugin-icon-service.js +14 -2
- package/lib/main/browser/plugin-icon-service.js.map +1 -1
- package/lib/main/browser/plugin-icon-service.spec.d.ts +2 -0
- package/lib/main/browser/plugin-icon-service.spec.d.ts.map +1 -0
- package/lib/main/browser/plugin-icon-service.spec.js +83 -0
- package/lib/main/browser/plugin-icon-service.spec.js.map +1 -0
- package/lib/main/browser/plugin-icon-theme-service.d.ts.map +1 -1
- package/lib/main/browser/plugin-icon-theme-service.js +2 -1
- package/lib/main/browser/plugin-icon-theme-service.js.map +1 -1
- package/lib/main/browser/plugin-icon-theme-service.spec.d.ts +2 -0
- package/lib/main/browser/plugin-icon-theme-service.spec.d.ts.map +1 -0
- package/lib/main/browser/plugin-icon-theme-service.spec.js +91 -0
- package/lib/main/browser/plugin-icon-theme-service.spec.js.map +1 -0
- package/lib/main/browser/telemetry-main.d.ts +20 -0
- package/lib/main/browser/telemetry-main.d.ts.map +1 -0
- package/lib/main/browser/telemetry-main.js +43 -0
- package/lib/main/browser/telemetry-main.js.map +1 -0
- package/lib/main/browser/telemetry-main.spec.d.ts +2 -0
- package/lib/main/browser/telemetry-main.spec.d.ts.map +1 -0
- package/lib/main/browser/telemetry-main.spec.js +66 -0
- package/lib/main/browser/telemetry-main.spec.js.map +1 -0
- package/lib/main/browser/webview/webview-context-keys.d.ts +3 -2
- package/lib/main/browser/webview/webview-context-keys.d.ts.map +1 -1
- package/lib/main/browser/webview/webview-context-keys.js +16 -2
- package/lib/main/browser/webview/webview-context-keys.js.map +1 -1
- package/lib/main/browser/webview/webview-environment.d.ts.map +1 -1
- package/lib/main/browser/webview/webview-environment.js +2 -1
- package/lib/main/browser/webview/webview-environment.js.map +1 -1
- package/lib/main/common/paths/const.d.ts +13 -0
- package/lib/main/common/paths/const.d.ts.map +1 -0
- package/lib/main/common/paths/const.js +32 -0
- package/lib/main/common/paths/const.js.map +1 -0
- package/lib/main/node/paths/const.d.ts +5 -5
- package/lib/main/node/paths/const.d.ts.map +1 -1
- package/lib/main/node/paths/const.js +6 -6
- package/lib/main/node/paths/const.js.map +1 -1
- package/lib/main/node/paths/plugin-paths-service.js +1 -1
- package/lib/main/node/paths/plugin-paths-service.js.map +1 -1
- package/lib/main/node/plugin-cli-contribution.d.ts +2 -2
- package/lib/main/node/plugin-cli-contribution.d.ts.map +1 -1
- package/lib/main/node/plugin-cli-contribution.js +4 -3
- package/lib/main/node/plugin-cli-contribution.js.map +1 -1
- package/lib/main/node/plugins-key-value-storage.js +1 -1
- package/lib/main/node/plugins-key-value-storage.js.map +1 -1
- package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.d.ts +5 -0
- package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.d.ts.map +1 -1
- package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.js +12 -1
- package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.js.map +1 -1
- package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.spec.d.ts +2 -0
- package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.spec.d.ts.map +1 -0
- package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.spec.js +54 -0
- package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.spec.js.map +1 -0
- package/lib/plugin/plugin-context.d.ts +2 -1
- package/lib/plugin/plugin-context.d.ts.map +1 -1
- package/lib/plugin/plugin-context.js +2 -3
- package/lib/plugin/plugin-context.js.map +1 -1
- package/lib/plugin/plugin-manager.d.ts +2 -0
- package/lib/plugin/plugin-manager.d.ts.map +1 -1
- package/lib/plugin/plugin-manager.js +12 -1
- package/lib/plugin/plugin-manager.js.map +1 -1
- package/lib/plugin/relative-pattern.spec.d.ts +2 -0
- package/lib/plugin/relative-pattern.spec.d.ts.map +1 -0
- package/lib/plugin/relative-pattern.spec.js +51 -0
- package/lib/plugin/relative-pattern.spec.js.map +1 -0
- package/lib/plugin/telemetry-ext.d.ts +23 -7
- package/lib/plugin/telemetry-ext.d.ts.map +1 -1
- package/lib/plugin/telemetry-ext.js +60 -33
- package/lib/plugin/telemetry-ext.js.map +1 -1
- package/lib/plugin/telemetry-ext.spec.js +121 -16
- package/lib/plugin/telemetry-ext.spec.js.map +1 -1
- package/lib/plugin-ext-frontend-only-module.d.ts +4 -0
- package/lib/plugin-ext-frontend-only-module.d.ts.map +1 -0
- package/lib/plugin-ext-frontend-only-module.js +34 -0
- package/lib/plugin-ext-frontend-only-module.js.map +1 -0
- package/package.json +36 -32
- package/src/common/paths-util.spec.ts +47 -0
- package/src/common/paths-util.ts +11 -2
- package/src/common/plugin-api-rpc.ts +15 -1
- package/src/common/plugin-protocol.ts +2 -0
- package/src/hosted/browser/hosted-plugin.ts +9 -4
- package/src/hosted/browser/worker/worker-main.ts +23 -12
- package/src/hosted/browser/worker/worker-plugin-module.ts +2 -0
- package/src/hosted/browser-only/browser-only-hosted-plugin-server.spec.ts +133 -0
- package/src/hosted/browser-only/browser-only-hosted-plugin-server.ts +122 -0
- package/src/hosted/browser-only/browser-only-plugin-file-system-provider.spec.ts +178 -0
- package/src/hosted/browser-only/browser-only-plugin-file-system-provider.ts +129 -0
- package/src/hosted/browser-only/browser-only-plugin-paths-service.spec.ts +199 -0
- package/src/hosted/browser-only/browser-only-plugin-paths-service.ts +145 -0
- package/src/hosted/browser-only/browser-only-plugin-server.spec.ts +228 -0
- package/src/hosted/browser-only/browser-only-plugin-server.ts +165 -0
- package/src/hosted/browser-only/test/navigator-locks-test-util.ts +54 -0
- package/src/hosted/common/hosted-plugin.ts +4 -4
- package/src/hosted/node/plugin-host-module.ts +2 -0
- package/src/hosted/node/plugin-host-rpc.ts +10 -4
- package/src/main/browser/editors-and-documents-main.spec.ts +140 -0
- package/src/main/browser/editors-and-documents-main.ts +19 -7
- package/src/main/browser/languages-main.spec.ts +101 -0
- package/src/main/browser/languages-main.ts +31 -9
- package/src/main/browser/main-context.ts +4 -0
- package/src/main/browser/menus/vscode-theia-menu-mappings.ts +5 -0
- package/src/main/browser/plugin-ext-frontend-module.ts +2 -1
- package/src/main/browser/plugin-icon-service.spec.ts +101 -0
- package/src/main/browser/plugin-icon-service.ts +16 -3
- package/src/main/browser/plugin-icon-theme-service.spec.ts +103 -0
- package/src/main/browser/plugin-icon-theme-service.ts +2 -1
- package/src/main/browser/telemetry-main.spec.ts +77 -0
- package/src/main/browser/telemetry-main.ts +46 -0
- package/src/main/browser/webview/webview-context-keys.ts +20 -4
- package/src/main/browser/webview/webview-environment.ts +2 -1
- package/src/main/common/paths/const.ts +28 -0
- package/src/main/node/paths/const.ts +5 -5
- package/src/main/node/paths/plugin-paths-service.ts +1 -1
- package/src/main/node/plugin-cli-contribution.ts +4 -3
- package/src/main/node/plugins-key-value-storage.ts +1 -1
- package/src/main/node/resolvers/local-directory-plugin-deployer-resolver.spec.ts +61 -0
- package/src/main/node/resolvers/local-directory-plugin-deployer-resolver.ts +14 -1
- package/src/plugin/plugin-context.ts +3 -2
- package/src/plugin/plugin-manager.ts +11 -1
- package/src/plugin/relative-pattern.spec.ts +55 -0
- package/src/plugin/telemetry-ext.spec.ts +158 -17
- package/src/plugin/telemetry-ext.ts +63 -33
- package/src/plugin-ext-frontend-only-module.ts +34 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 Robert Jandow
|
|
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 { expect } from 'chai';
|
|
18
|
+
import { ILogger } from '@theia/core';
|
|
19
|
+
import { MockLogger } from '@theia/core/lib/common/test/mock-logger';
|
|
20
|
+
import { Container } from '@theia/core/shared/inversify';
|
|
21
|
+
import { LocalStorageService, StorageService } from '@theia/core/lib/browser/storage-service';
|
|
22
|
+
import { PluginPathsService } from '../../main/common/plugin-paths-protocol';
|
|
23
|
+
import { BrowserOnlyPluginServer } from './browser-only-plugin-server';
|
|
24
|
+
import { installFakeLockManager as installNavigatorLocks } from './test/navigator-locks-test-util';
|
|
25
|
+
|
|
26
|
+
class InMemoryStorageService implements StorageService {
|
|
27
|
+
readonly data = new Map<string, string>();
|
|
28
|
+
|
|
29
|
+
async setData<T>(key: string, data: T): Promise<void> {
|
|
30
|
+
this.data.set(key, JSON.stringify(data));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async getData<T>(key: string, defaultValue?: T): Promise<T | undefined> {
|
|
34
|
+
const stored = this.data.get(key);
|
|
35
|
+
return stored === undefined ? defaultValue : JSON.parse(stored);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Stands for `@theia/workspace`'s `WorkspaceStorageService`, to which `@theia/workspace` rebinds
|
|
41
|
+
* the plain `StorageService` symbol, prefixing every key with the current workspace.
|
|
42
|
+
*/
|
|
43
|
+
class PrefixingStorageService implements StorageService {
|
|
44
|
+
|
|
45
|
+
constructor(private readonly delegate: InMemoryStorageService, private readonly prefix: string) { }
|
|
46
|
+
|
|
47
|
+
setData<T>(key: string, data: T): Promise<void> {
|
|
48
|
+
return this.delegate.setData(`${this.prefix}:${key}`, data);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getData<T>(key: string, defaultValue?: T): Promise<T | undefined> {
|
|
52
|
+
return this.delegate.getData(`${this.prefix}:${key}`, defaultValue);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const pluginPathsService: PluginPathsService = {
|
|
57
|
+
getHostLogPath: async () => '/logs/host',
|
|
58
|
+
getHostStoragePath: async workspaceUri => workspaceUri && `/workspace-storage/${workspaceUri}`
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Stand-in for the browser's `LockManager`. Like the real one, it runs requests for the same
|
|
63
|
+
* lock name one after another.
|
|
64
|
+
*/
|
|
65
|
+
class FakeLockManager {
|
|
66
|
+
private readonly queues = new Map<string, Promise<unknown>>();
|
|
67
|
+
|
|
68
|
+
request<T>(name: string, callback: () => T | PromiseLike<T>): Promise<T> {
|
|
69
|
+
const previous = this.queues.get(name) ?? Promise.resolve();
|
|
70
|
+
const run = (async () => {
|
|
71
|
+
await previous.catch(() => undefined);
|
|
72
|
+
return callback();
|
|
73
|
+
})();
|
|
74
|
+
this.queues.set(name, run.catch(() => undefined));
|
|
75
|
+
return run;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Installs a {@link FakeLockManager} as `navigator.locks`; see {@link installNavigatorLocks}. */
|
|
80
|
+
function installFakeLockManager(): () => void {
|
|
81
|
+
return installNavigatorLocks(new FakeLockManager());
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
describe('BrowserOnlyPluginServer', () => {
|
|
85
|
+
|
|
86
|
+
let storageService: InMemoryStorageService;
|
|
87
|
+
|
|
88
|
+
function createServer(): BrowserOnlyPluginServer {
|
|
89
|
+
const container = new Container();
|
|
90
|
+
container.bind(BrowserOnlyPluginServer).toSelf().inSingletonScope();
|
|
91
|
+
container.bind(ILogger).to(MockLogger);
|
|
92
|
+
container.bind<StorageService>(LocalStorageService).toConstantValue(storageService);
|
|
93
|
+
container.bind(PluginPathsService).toConstantValue(pluginPathsService);
|
|
94
|
+
return container.get(BrowserOnlyPluginServer);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
beforeEach(() => {
|
|
98
|
+
storageService = new InMemoryStorageService();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('keeps global state across sessions', async () => {
|
|
102
|
+
expect(await createServer().setStorageValue('my.plugin', { count: 1 }, undefined)).to.be.true;
|
|
103
|
+
|
|
104
|
+
// a fresh server stands for the next session, reading from the same browser storage
|
|
105
|
+
expect(await createServer().getStorageValue('my.plugin', undefined)).to.deep.equal({ count: 1 });
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('keeps global state independent of a workspace-scoped StorageService binding', async () => {
|
|
109
|
+
const container = new Container();
|
|
110
|
+
container.bind(BrowserOnlyPluginServer).toSelf().inSingletonScope();
|
|
111
|
+
container.bind(ILogger).to(MockLogger);
|
|
112
|
+
container.bind<StorageService>(LocalStorageService).toConstantValue(storageService);
|
|
113
|
+
// simulates `@theia/workspace` rebinding the plain `StorageService` symbol; `BrowserOnlyPluginServer`
|
|
114
|
+
// must ignore it and inject `LocalStorageService` directly, or global state would end up
|
|
115
|
+
// scoped per workspace too
|
|
116
|
+
container.bind(StorageService).toConstantValue(new PrefixingStorageService(storageService, 'file:///a'));
|
|
117
|
+
container.bind(PluginPathsService).toConstantValue(pluginPathsService);
|
|
118
|
+
const server = container.get(BrowserOnlyPluginServer);
|
|
119
|
+
|
|
120
|
+
await server.setStorageValue('my.plugin', { count: 1 }, undefined);
|
|
121
|
+
|
|
122
|
+
expect(storageService.data.has('plugin-storage:global')).to.be.true;
|
|
123
|
+
expect(storageService.data.has('file:///a:plugin-storage:global')).to.be.false;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('keeps workspace state per workspace', async () => {
|
|
127
|
+
const server = createServer();
|
|
128
|
+
await server.setStorageValue('my.plugin', { count: 1 }, { workspace: 'file:///a', roots: [] });
|
|
129
|
+
await server.setStorageValue('my.plugin', { count: 2 }, { workspace: 'file:///b', roots: [] });
|
|
130
|
+
|
|
131
|
+
expect(await server.getStorageValue('my.plugin', { workspace: 'file:///a', roots: [] })).to.deep.equal({ count: 1 });
|
|
132
|
+
expect(await server.getStorageValue('my.plugin', { workspace: 'file:///b', roots: [] })).to.deep.equal({ count: 2 });
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('keeps global and workspace state apart', async () => {
|
|
136
|
+
const server = createServer();
|
|
137
|
+
await server.setStorageValue('my.plugin', { scope: 'global' }, undefined);
|
|
138
|
+
await server.setStorageValue('my.plugin', { scope: 'workspace' }, { workspace: 'file:///a', roots: [] });
|
|
139
|
+
|
|
140
|
+
expect(await server.getStorageValue('my.plugin', undefined)).to.deep.equal({ scope: 'global' });
|
|
141
|
+
expect(await server.getAllStorageValues({ workspace: 'file:///a', roots: [] })).to.deep.equal({ 'my.plugin': { scope: 'workspace' } });
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('cannot keep workspace state while no workspace is open', async () => {
|
|
145
|
+
const server = createServer();
|
|
146
|
+
|
|
147
|
+
expect(await server.setStorageValue('my.plugin', { count: 1 }, { workspace: undefined, roots: [] })).to.be.false;
|
|
148
|
+
expect(await server.getAllStorageValues({ workspace: undefined, roots: [] })).to.deep.equal({});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('does not drop what another host stored in the meantime', async () => {
|
|
152
|
+
const one = createServer();
|
|
153
|
+
// stands for another tab of the application, running its own plugin host over the same browser storage
|
|
154
|
+
const other = createServer();
|
|
155
|
+
await one.setStorageValue('plugin.one', { count: 1 }, undefined);
|
|
156
|
+
// as the plugin host does on start up, before the other tab writes
|
|
157
|
+
await one.getAllStorageValues(undefined);
|
|
158
|
+
|
|
159
|
+
await other.setStorageValue('plugin.other', { count: 2 }, undefined);
|
|
160
|
+
await one.setStorageValue('plugin.one', { count: 3 }, undefined);
|
|
161
|
+
|
|
162
|
+
expect(await createServer().getAllStorageValues(undefined)).to.deep.equal({
|
|
163
|
+
'plugin.one': { count: 3 },
|
|
164
|
+
'plugin.other': { count: 2 }
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe('concurrent writes', () => {
|
|
169
|
+
|
|
170
|
+
async function assertNeitherUpdateIsLost(one: BrowserOnlyPluginServer, other: BrowserOnlyPluginServer): Promise<void> {
|
|
171
|
+
// start both writes before awaiting either, so they actually overlap
|
|
172
|
+
await Promise.all([
|
|
173
|
+
one.setStorageValue('plugin.one', { count: 1 }, undefined),
|
|
174
|
+
other.setStorageValue('plugin.other', { count: 2 }, undefined)
|
|
175
|
+
]);
|
|
176
|
+
|
|
177
|
+
expect(await createServer().getAllStorageValues(undefined)).to.deep.equal({
|
|
178
|
+
'plugin.one': { count: 1 },
|
|
179
|
+
'plugin.other': { count: 2 }
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
it('does not lose either update from two tabs, serialized via the Web Locks API', async () => {
|
|
184
|
+
const restore = installFakeLockManager();
|
|
185
|
+
try {
|
|
186
|
+
// one server per tab, sharing the same browser storage
|
|
187
|
+
await assertNeitherUpdateIsLost(createServer(), createServer());
|
|
188
|
+
} finally {
|
|
189
|
+
restore();
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('does not lose either update within one tab when the Web Locks API is unavailable', async () => {
|
|
194
|
+
const server = createServer();
|
|
195
|
+
await assertNeitherUpdateIsLost(server, server);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('drops a value that is set to nothing', async () => {
|
|
200
|
+
const server = createServer();
|
|
201
|
+
await server.setStorageValue('my.plugin', { count: 1 }, undefined);
|
|
202
|
+
|
|
203
|
+
await server.setStorageValue('my.plugin', {}, undefined);
|
|
204
|
+
|
|
205
|
+
expect(await createServer().getAllStorageValues(undefined)).to.deep.equal({});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('answers with an empty value for an unknown key', async () => {
|
|
209
|
+
expect(await createServer().getStorageValue('my.plugin', undefined)).to.deep.equal({});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('rejects changing the deployed plugins', async () => {
|
|
213
|
+
const server = createServer();
|
|
214
|
+
|
|
215
|
+
await server.install('my.plugin').then(
|
|
216
|
+
() => expect.fail('should have rejected'),
|
|
217
|
+
error => expect(error.message).to.contain('browser-only'));
|
|
218
|
+
await server.uninstall('theia.a@1.0.0').then(
|
|
219
|
+
() => expect.fail('should have rejected'),
|
|
220
|
+
error => expect(error.message).to.contain('browser-only'));
|
|
221
|
+
await server.enablePlugin('theia.a').then(
|
|
222
|
+
() => expect.fail('should have rejected'),
|
|
223
|
+
error => expect(error.message).to.contain('browser-only'));
|
|
224
|
+
await server.disablePlugin('theia.a').then(
|
|
225
|
+
() => expect.fail('should have rejected'),
|
|
226
|
+
error => expect(error.message).to.contain('browser-only'));
|
|
227
|
+
});
|
|
228
|
+
});
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 Robert Jandow
|
|
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 { inject, injectable, named } from '@theia/core/shared/inversify';
|
|
18
|
+
import { Mutex } from 'async-mutex';
|
|
19
|
+
import { ILogger, nls } from '@theia/core';
|
|
20
|
+
import { LocalStorageService, StorageService } from '@theia/core/lib/browser/storage-service';
|
|
21
|
+
import { PluginDeployOptions, PluginIdentifiers, PluginServer, PluginStorageKind, PluginType } from '../../common';
|
|
22
|
+
import { KeysToAnyValues, KeysToKeysToAnyValue } from '../../common/types';
|
|
23
|
+
import { PluginPathsService } from '../../main/common/plugin-paths-protocol';
|
|
24
|
+
|
|
25
|
+
const GLOBAL_STORAGE_KEY = 'plugin-storage:global';
|
|
26
|
+
const WORKSPACE_STORAGE_KEY_PREFIX = 'plugin-storage:workspace:';
|
|
27
|
+
const LOCK_NAME_PREFIX = 'theia:plugin-storage:';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Plugins of a browser-only application are deployed at build time, so they can't be installed,
|
|
31
|
+
* uninstalled, enabled or disabled at runtime. The queries just report an empty result instead
|
|
32
|
+
* of failing, so callers like the plugin view still have something to render.
|
|
33
|
+
*
|
|
34
|
+
* The plugin key-value storage backing `ExtensionContext.globalState` and
|
|
35
|
+
* `ExtensionContext.workspaceState` lives in the browser's local storage.
|
|
36
|
+
*/
|
|
37
|
+
@injectable()
|
|
38
|
+
export class BrowserOnlyPluginServer implements PluginServer {
|
|
39
|
+
|
|
40
|
+
@inject(ILogger) @named('plugin-ext:BrowserOnlyPluginServer')
|
|
41
|
+
protected readonly logger: ILogger;
|
|
42
|
+
|
|
43
|
+
// `@theia/workspace` rebinds `StorageService` to `WorkspaceStorageService`, which prefixes every
|
|
44
|
+
// key with the current workspace URI. That would scope `GLOBAL_STORAGE_KEY` per workspace too,
|
|
45
|
+
// so `LocalStorageService` is injected directly instead - the workspace store key already
|
|
46
|
+
// encodes the workspace via `PluginPathsService.getHostStoragePath`.
|
|
47
|
+
@inject(LocalStorageService)
|
|
48
|
+
protected readonly storageService: StorageService;
|
|
49
|
+
|
|
50
|
+
@inject(PluginPathsService)
|
|
51
|
+
protected readonly pluginPathsService: PluginPathsService;
|
|
52
|
+
|
|
53
|
+
/** Fallback for {@link withStoreLock} when the Web Locks API is unavailable. */
|
|
54
|
+
protected readonly localLock = new Mutex();
|
|
55
|
+
protected missingLocksWarned = false;
|
|
56
|
+
|
|
57
|
+
async install(pluginEntry: string, type?: PluginType, options?: PluginDeployOptions): Promise<void> {
|
|
58
|
+
throw new Error(nls.localize('theia/plugin-ext/browserOnlyInstallUnsupported', 'Installing plugins is not supported in a browser-only application.'));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async uninstall(pluginId: PluginIdentifiers.VersionedId): Promise<void> {
|
|
62
|
+
throw new Error(nls.localize('theia/plugin-ext/browserOnlyUninstallUnsupported', 'Uninstalling plugins is not supported in a browser-only application.'));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async enablePlugin(pluginId: PluginIdentifiers.UnversionedId): Promise<boolean> {
|
|
66
|
+
throw new Error(nls.localize('theia/plugin-ext/browserOnlyEnableUnsupported', 'Enabling plugins is not supported in a browser-only application.'));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async disablePlugin(pluginId: PluginIdentifiers.UnversionedId): Promise<boolean> {
|
|
70
|
+
throw new Error(nls.localize('theia/plugin-ext/browserOnlyDisableUnsupported', 'Disabling plugins is not supported in a browser-only application.'));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async getInstalledPlugins(): Promise<readonly PluginIdentifiers.VersionedId[]> {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async getUninstalledPlugins(): Promise<readonly PluginIdentifiers.VersionedId[]> {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async getDisabledPlugins(): Promise<readonly PluginIdentifiers.UnversionedId[]> {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async setStorageValue(key: string, value: KeysToAnyValues, kind: PluginStorageKind): Promise<boolean> {
|
|
86
|
+
const storeKey = await this.getStoreKey(kind);
|
|
87
|
+
if (!storeKey) {
|
|
88
|
+
this.logger.warn('Cannot save plugin data: no opened workspace.');
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
// the browser storage is shared with this application's other tabs, each running its own
|
|
92
|
+
// plugin host, so the read and write below need to be atomic - otherwise a concurrent
|
|
93
|
+
// update from another tab could land in between and get overwritten by this one
|
|
94
|
+
await this.withStoreLock(storeKey, async () => {
|
|
95
|
+
const store = await this.getStore(storeKey);
|
|
96
|
+
if (value === undefined || Object.keys(value).length === 0) {
|
|
97
|
+
delete store[key];
|
|
98
|
+
} else {
|
|
99
|
+
store[key] = value;
|
|
100
|
+
}
|
|
101
|
+
await this.storageService.setData(storeKey, store);
|
|
102
|
+
});
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async getStorageValue(key: string, kind: PluginStorageKind): Promise<KeysToAnyValues> {
|
|
107
|
+
return (await this.getAllStorageValues(kind))[key] ?? {};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async getAllStorageValues(kind: PluginStorageKind): Promise<KeysToKeysToAnyValue> {
|
|
111
|
+
const storeKey = await this.getStoreKey(kind);
|
|
112
|
+
return storeKey ? this.getStore(storeKey) : {};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
protected getStore(storeKey: string): Promise<KeysToKeysToAnyValue> {
|
|
116
|
+
return this.storageService.getData<KeysToKeysToAnyValue>(storeKey, {});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Runs `task` while holding the cross-tab lock for `storeKey`, via the Web Locks API, so a
|
|
121
|
+
* concurrent {@link setStorageValue} on this or another tab can't interleave with it.
|
|
122
|
+
*/
|
|
123
|
+
protected withStoreLock<T>(storeKey: string, task: () => Promise<T>): Promise<T> {
|
|
124
|
+
const locks = this.getWebLocks();
|
|
125
|
+
if (locks) {
|
|
126
|
+
return this.requestLock(locks, `${LOCK_NAME_PREFIX}${storeKey}`, task);
|
|
127
|
+
}
|
|
128
|
+
// no Web Locks API (insecure context, older browser): fall back to serializing writes
|
|
129
|
+
// within this tab. A write from another tab can still race and get lost.
|
|
130
|
+
if (!this.missingLocksWarned) {
|
|
131
|
+
this.missingLocksWarned = true;
|
|
132
|
+
this.logger.warn('Web Locks API unavailable: plugin storage updates from different tabs may race.');
|
|
133
|
+
}
|
|
134
|
+
return this.localLock.runExclusive(task);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** The Web Locks API of this browsing context, or `undefined` in an insecure context or an older browser. */
|
|
138
|
+
protected getWebLocks(): LockManager | undefined {
|
|
139
|
+
return typeof navigator === 'object' ? navigator.locks : undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Requests `name` from `locks` and runs `callback` once granted, same as `LockManager.request()`.
|
|
144
|
+
*
|
|
145
|
+
* `LockGrantedCallback` is typed as `(lock: Lock | null) => T`, which doesn't account for an
|
|
146
|
+
* async or never-settling callback even though the API itself supports and awaits one, hence
|
|
147
|
+
* the cast. Kept as its own method so a subclass or test can swap the lock implementation.
|
|
148
|
+
*/
|
|
149
|
+
protected requestLock<T>(locks: LockManager, name: string, callback: () => T | PromiseLike<T>): Promise<T> {
|
|
150
|
+
return locks.request<T>(name, callback as unknown as LockGrantedCallback<T>);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* The browser storage key holding the given kind of values, or `undefined` if there's
|
|
155
|
+
* nowhere to keep them - e.g. workspace state while no workspace is open.
|
|
156
|
+
*/
|
|
157
|
+
protected async getStoreKey(kind: PluginStorageKind): Promise<string | undefined> {
|
|
158
|
+
if (!kind) {
|
|
159
|
+
return GLOBAL_STORAGE_KEY;
|
|
160
|
+
}
|
|
161
|
+
// derived from the storage path so workspace state follows `ExtensionContext.storageUri`
|
|
162
|
+
const storagePath = await this.pluginPathsService.getHostStoragePath(kind.workspace, kind.roots);
|
|
163
|
+
return storagePath && `${WORKSPACE_STORAGE_KEY_PREFIX}${storagePath}`;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 Robert Jandow
|
|
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
|
+
/**
|
|
18
|
+
* The subset of `LockManager` that the fakes in these tests actually implement. The real
|
|
19
|
+
* `LockManager.request()` is overloaded with an optional `options` parameter that none of our
|
|
20
|
+
* fakes need, so typing {@link installFakeLockManager} directly against the DOM `LockManager`
|
|
21
|
+
* interface would reject every fake as an incompatible overload - we cast to the real type just
|
|
22
|
+
* once instead, at the point where the fake gets installed as `navigator.locks`.
|
|
23
|
+
*/
|
|
24
|
+
export interface FakeLockManager {
|
|
25
|
+
request<T>(name: string, callback: () => T | PromiseLike<T>): Promise<T>;
|
|
26
|
+
query?(): Promise<{ held?: Array<{ name?: string }> }>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Installs `manager` as `navigator.locks` and returns a function that restores whatever was
|
|
31
|
+
* there before. Doesn't assume `navigator` is even defined: `enableJSDOM()`/`disableJSDOM()`
|
|
32
|
+
* (see `packages/core/src/browser/test/jsdom.ts`) deletes the global `navigator` that Node
|
|
33
|
+
* normally provides as a side effect of disabling jsdom, and depending on which spec files ran
|
|
34
|
+
* earlier in this mocha process, it may already be gone by the time a test runs.
|
|
35
|
+
*/
|
|
36
|
+
export function installFakeLockManager(manager: FakeLockManager): () => void {
|
|
37
|
+
const target = globalThis as { navigator?: { locks?: unknown } };
|
|
38
|
+
const hadNavigator = typeof navigator !== 'undefined';
|
|
39
|
+
if (!hadNavigator) {
|
|
40
|
+
Object.defineProperty(target, 'navigator', { value: {}, configurable: true });
|
|
41
|
+
}
|
|
42
|
+
const originalLocks = Object.getOwnPropertyDescriptor(navigator, 'locks');
|
|
43
|
+
Object.defineProperty(navigator, 'locks', { value: manager as unknown as LockManager, configurable: true });
|
|
44
|
+
|
|
45
|
+
return () => {
|
|
46
|
+
if (!hadNavigator) {
|
|
47
|
+
delete target.navigator;
|
|
48
|
+
} else if (originalLocks) {
|
|
49
|
+
Object.defineProperty(navigator, 'locks', originalLocks);
|
|
50
|
+
} else {
|
|
51
|
+
delete (navigator as { locks?: unknown }).locks;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
import debounce = require('@theia/core/shared/lodash.debounce');
|
|
25
25
|
import { injectable, inject, interfaces, named, postConstruct, unmanaged } from '@theia/core/shared/inversify';
|
|
26
|
-
import { PluginMetadata, HostedPluginServer, DeployedPlugin, PluginServer, PluginIdentifiers } from '../../common/plugin-protocol';
|
|
26
|
+
import { PluginMetadata, HostedPluginServer, DeployedPlugin, PluginServer, PluginIdentifiers, PLUGIN_HOST_FRONTEND } from '../../common/plugin-protocol';
|
|
27
27
|
import { AbstractPluginManagerExt, ConfigStorage } from '../../common/plugin-api-rpc';
|
|
28
28
|
import {
|
|
29
29
|
Disposable, DisposableCollection, Emitter,
|
|
@@ -37,7 +37,7 @@ import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
|
|
37
37
|
import { environment } from '@theia/core/shared/@theia/application-package/lib/environment';
|
|
38
38
|
import { Measurement, Stopwatch } from '@theia/core/lib/common';
|
|
39
39
|
|
|
40
|
-
export type PluginHost =
|
|
40
|
+
export type PluginHost = typeof PLUGIN_HOST_FRONTEND | string;
|
|
41
41
|
|
|
42
42
|
export const ALL_ACTIVATION_EVENT = '*';
|
|
43
43
|
|
|
@@ -336,7 +336,7 @@ export abstract class AbstractHostedPluginSupport<PM extends AbstractPluginManag
|
|
|
336
336
|
|
|
337
337
|
if (contributions.state === PluginContributions.State.LOADED) {
|
|
338
338
|
contributions.state = PluginContributions.State.STARTING;
|
|
339
|
-
const host = plugin.model.entryPoint.frontend ?
|
|
339
|
+
const host = plugin.model.entryPoint.frontend ? PLUGIN_HOST_FRONTEND : plugin.host;
|
|
340
340
|
const dynamicContributions = hostContributions.get(host) || [];
|
|
341
341
|
dynamicContributions.push(contributions);
|
|
342
342
|
hostContributions.set(host, dynamicContributions);
|
|
@@ -381,7 +381,7 @@ export abstract class AbstractHostedPluginSupport<PM extends AbstractPluginManag
|
|
|
381
381
|
|
|
382
382
|
for (const [host, hostContributions] of contributionsByHost) {
|
|
383
383
|
// do not start plugins for electron browser
|
|
384
|
-
if (host ===
|
|
384
|
+
if (host === PLUGIN_HOST_FRONTEND && environment.electron.is()) {
|
|
385
385
|
continue;
|
|
386
386
|
}
|
|
387
387
|
|
|
@@ -39,6 +39,7 @@ import { setupPluginHostLogger } from './plugin-host-logger';
|
|
|
39
39
|
import { LmExtImpl } from '../../plugin/lm-ext';
|
|
40
40
|
import { LanguageModelToolsExtImpl } from '../../plugin/lm-tool-ext';
|
|
41
41
|
import { EncodingService } from '@theia/core/lib/common/encoding-service';
|
|
42
|
+
import { TelemetryExtImpl } from '../../plugin/telemetry-ext';
|
|
42
43
|
|
|
43
44
|
export default new ContainerModule(bind => {
|
|
44
45
|
const channel = new IPCChannel();
|
|
@@ -76,4 +77,5 @@ export default new ContainerModule(bind => {
|
|
|
76
77
|
bind(WebviewsExtImpl).toSelf().inSingletonScope();
|
|
77
78
|
bind(MinimalTerminalServiceExt).toService(TerminalServiceExtImpl);
|
|
78
79
|
bind(TerminalServiceExtImpl).toSelf().inSingletonScope();
|
|
80
|
+
bind(TelemetryExtImpl).toSelf().inSingletonScope();
|
|
79
81
|
});
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
import { PluginMetadata, PluginModel, PluginPackage } from '../../common/plugin-protocol';
|
|
32
32
|
import { createAPIFactory } from '../../plugin/plugin-context';
|
|
33
33
|
import { EnvExtImpl } from '../../plugin/env';
|
|
34
|
+
import { TelemetryExtImpl } from '../../plugin/telemetry-ext';
|
|
34
35
|
import { PreferenceRegistryExtImpl } from '../../plugin/preference-registry';
|
|
35
36
|
import { ExtPluginApi, ExtPluginApiBackendInitializationFn } from '../../common/plugin-ext-api-contribution';
|
|
36
37
|
import { DebugExtImpl } from '../../plugin/debug/debug-ext';
|
|
@@ -64,7 +65,8 @@ export interface ExtInterfaces {
|
|
|
64
65
|
webviewExt: WebviewsExtImpl,
|
|
65
66
|
terminalServiceExt: TerminalServiceExtImpl,
|
|
66
67
|
secretsExt: SecretsExtImpl,
|
|
67
|
-
localizationExt: LocalizationExtImpl
|
|
68
|
+
localizationExt: LocalizationExtImpl,
|
|
69
|
+
telemetryExt: TelemetryExtImpl
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
/**
|
|
@@ -352,6 +354,9 @@ export class PluginHostRPC extends AbstractPluginHostRPC<PluginManagerExtImpl, P
|
|
|
352
354
|
@inject(SecretsExtImpl)
|
|
353
355
|
protected readonly secretsExt: SecretsExtImpl;
|
|
354
356
|
|
|
357
|
+
@inject(TelemetryExtImpl)
|
|
358
|
+
protected readonly telemetryExt: TelemetryExtImpl;
|
|
359
|
+
|
|
355
360
|
constructor() {
|
|
356
361
|
super('PLUGIN_HOST', '/scanners/backend-init-theia.js',
|
|
357
362
|
{
|
|
@@ -380,18 +385,19 @@ export class PluginHostRPC extends AbstractPluginHostRPC<PluginManagerExtImpl, P
|
|
|
380
385
|
webviewExt: this.webviewExt,
|
|
381
386
|
terminalServiceExt: this.terminalServiceExt,
|
|
382
387
|
secretsExt: this.secretsExt,
|
|
383
|
-
localizationExt: this.localizationExt
|
|
388
|
+
localizationExt: this.localizationExt,
|
|
389
|
+
telemetryExt: this.telemetryExt
|
|
384
390
|
};
|
|
385
391
|
}
|
|
386
392
|
|
|
387
393
|
protected createAPIFactory(extInterfaces: ExtInterfaces): PluginAPIFactory {
|
|
388
394
|
const {
|
|
389
395
|
envExt, debugExt, preferenceRegistryExt, editorsAndDocumentsExt, workspaceExt,
|
|
390
|
-
messageRegistryExt, clipboardExt, webviewExt, localizationExt
|
|
396
|
+
messageRegistryExt, clipboardExt, webviewExt, localizationExt, telemetryExt
|
|
391
397
|
} = extInterfaces;
|
|
392
398
|
return createAPIFactory(this.rpc, this.pluginManager, envExt, debugExt, preferenceRegistryExt,
|
|
393
399
|
editorsAndDocumentsExt, workspaceExt, messageRegistryExt, clipboardExt, webviewExt,
|
|
394
|
-
localizationExt);
|
|
400
|
+
localizationExt, telemetryExt);
|
|
395
401
|
}
|
|
396
402
|
|
|
397
403
|
protected initExtApi(extApi: ExtPluginApi): void {
|