deploy: current vibn theia state
Some checks failed
Playwright Tests / Playwright Tests (ubuntu-22.04, Node.js 22.x) (push) Has been cancelled
3PP License Check / 3PP License Check (11, 22.x, ubuntu-22.04) (push) Has been cancelled
Publish packages to NPM / Perform Publishing (push) Has been cancelled

Made-with: Cursor
This commit is contained in:
2026-02-27 12:01:08 -08:00
commit 8bb5110148
3782 changed files with 640947 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: [
'../../configs/build.eslintrc.json'
],
parserOptions: {
tsconfigRootDir: __dirname,
project: 'tsconfig.json'
}
};

View File

@@ -0,0 +1,50 @@
<div align='center'>
<br />
<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
<h2>ECLIPSE THEIA - API PROVIDER SAMPLE</h2>
<hr />
</div>
## Description
The `@theia/api-provider-sample` extension is a programming example showing how to define and provide a custom API object for _plugins_ to use.
The purpose of the extension is to:
- provide developers with realistic coding examples of providing custom API objects
- provide easy-to-use and test examples for features when reviewing pull requests
The extension is for reference and test purposes only and is not published on `npm` (`private: true`).
### Greeting of the Day
The sample defines a `gotd` API that plugins can import and use to obtain tailored messages with which to greet the world, for example in their activation function.
The source code is laid out in the `src/` tree as follows:
- `gotd.d.ts` — the TypeScript definition of the `gotd` API object that plugins import to interact with the "Greeting of the Day" service
- `plugin/` — the API initialization script and the implementation of the API objects (`GreetingExt` and similar interfaces).
All code in this directory runs exclusively in the separate plugin-host Node process, isolated from the main Theia process, together with either headless plugins or the backend of VS Code plugins.
The `GreetingExtImpl` and similar classes communicate with the actual API implementation (`GreetingMainImpl` etc.) classes in the main Theia process via RPC
- `node/` — the API classes implementing `GreetingMain` and similar interfaces and the Inversify bindings that register the API provider.
All code in this directory runs in the main Theia Node process
- `common/` — the RPC API Ext/Main interface definitions corresponding to the backend of the `gotd` plugin API
## Additional Information
- [Theia - GitHub](https://github.com/eclipse-theia/theia)
- [Theia - Website](https://theia-ide.org/)
## License
- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
## Trademark
"Theia" is a trademark of the Eclipse Foundation
<https://www.eclipse.org/theia>

View File

@@ -0,0 +1,42 @@
{
"private": true,
"name": "@theia/api-provider-sample",
"version": "1.68.0",
"description": "Theia - Example code to demonstrate Theia API Provider Extensions",
"dependencies": {
"@theia/core": "1.68.0",
"@theia/plugin-ext": "1.68.0",
"@theia/plugin-ext-headless": "1.68.0"
},
"theiaExtensions": [
{
"backend": "lib/node/gotd-backend-module"
}
],
"keywords": [
"theia-extension"
],
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
"repository": {
"type": "git",
"url": "https://github.com/eclipse-theia/theia.git"
},
"bugs": {
"url": "https://github.com/eclipse-theia/theia/issues"
},
"homepage": "https://github.com/eclipse-theia/theia",
"files": [
"lib",
"src"
],
"types": "src/gotd.d.ts",
"scripts": {
"lint": "theiaext lint",
"build": "theiaext build",
"watch": "theiaext watch",
"clean": "theiaext clean"
},
"devDependencies": {
"@theia/ext-scripts": "1.68.0"
}
}

View File

@@ -0,0 +1,70 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { createProxyIdentifier } from '@theia/plugin-ext/lib/common/rpc-protocol';
import type { greeting } from '../gotd';
import { Event } from '@theia/core';
export enum GreetingKind {
DIRECT = 1,
QUIRKY = 2,
SNARKY = 3,
}
export interface GreeterData {
readonly uuid: string;
greetingKinds: greeting.GreetingKind[];
};
export const GreetingMain = Symbol('GreetingMain');
export interface GreetingMain {
$getMessage(greeterId: string): Promise<string>;
$createGreeter(): Promise<GreeterData>;
$destroyGreeter(greeterId: GreeterData['uuid']): Promise<void>;
$updateGreeter(data: GreeterData): void;
}
export const GreetingExt = Symbol('GreetingExt');
export interface GreetingExt {
//
// External protocol
//
registerGreeter(): Promise<string>;
unregisterGreeter(uuid: string): Promise<void>;
getMessage(greeterId: string): Promise<string>;
getGreetingKinds(greeterId: string): readonly greeting.GreetingKind[];
setGreetingKindEnabled(greeterId: string, greetingKind: greeting.GreetingKind, enable: boolean): void;
onGreetingKindsChanged(greeterId: string): Event<readonly greeting.GreetingKind[]>;
//
// Internal protocol
//
$greeterUpdated(data: GreeterData): void;
}
export const PLUGIN_RPC_CONTEXT = {
GREETING_MAIN: createProxyIdentifier<GreetingMain>('GreetingMain'),
};
export const MAIN_RPC_CONTEXT = {
GREETING_EXT: createProxyIdentifier<GreetingExt>('GreetingExt'),
};

View File

@@ -0,0 +1,49 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
// Strictly speaking, the 'greeting' namespace is an unnecessary level of organization
// but it serves to illustrate how API namespaces are implemented in the backend.
export namespace greeting {
export function createGreeter(): Promise<greeting.Greeter>;
export enum GreetingKind {
DIRECT = 1,
QUIRKY = 2,
SNARKY = 3,
}
export interface Greeter extends Disposable {
greetingKinds: readonly GreetingKind[];
getMessage(): Promise<string>;
setGreetingKind(kind: GreetingKind, enable = true): void;
onGreetingKindsChanged: Event<readonly GreetingKind[]>;
}
}
export interface Event<T> {
(listener: (e: T) => unknown, thisArg?: unknown): Disposable;
}
export interface Disposable {
dispose(): void;
}
namespace Disposable {
export function create(func: () => void): Disposable;
}

View File

@@ -0,0 +1,33 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import * as path from 'path';
import { injectable } from '@theia/core/shared/inversify';
import { ExtPluginApi, ExtPluginApiProvider } from '@theia/plugin-ext-headless';
@injectable()
export class ExtPluginGotdApiProvider implements ExtPluginApiProvider {
provideApi(): ExtPluginApi {
// We can support both backend plugins and headless plugins, so we have only one
// entry-point script. Moreover, the application build packages that script in
// the `../backend/` directory from its source `../plugin/` location, alongside
// the scripts for all other plugin API providers.
const universalInitPath = path.join(__dirname, '../backend/gotd-api-init');
return {
backendInitPath: universalInitPath,
headlessInitPath: universalInitPath
};
}
}

View File

@@ -0,0 +1,28 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { ContainerModule } from '@theia/core/shared/inversify';
import { ExtPluginApiProvider } from '@theia/plugin-ext';
import { ExtPluginGotdApiProvider } from './ext-plugin-gotd-api-provider';
import { MainPluginApiProvider } from '@theia/plugin-ext/lib/common/plugin-ext-api-contribution';
import { GotdMainPluginApiProvider } from './gotd-main-plugin-provider';
import { GreetingMain } from '../common/plugin-api-rpc';
import { GreetingMainImpl } from './greeting-main-impl';
export default new ContainerModule(bind => {
bind(Symbol.for(ExtPluginApiProvider)).to(ExtPluginGotdApiProvider).inSingletonScope();
bind(MainPluginApiProvider).to(GotdMainPluginApiProvider).inSingletonScope();
bind(GreetingMain).to(GreetingMainImpl).inSingletonScope();
});

View File

@@ -0,0 +1,29 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { MainPluginApiProvider } from '@theia/plugin-ext/lib/common/plugin-ext-api-contribution';
import { RPCProtocol } from '@theia/plugin-ext/lib/common/rpc-protocol';
import { inject, injectable } from '@theia/core/shared/inversify';
import { GreetingMain, PLUGIN_RPC_CONTEXT } from '../common/plugin-api-rpc';
@injectable()
export class GotdMainPluginApiProvider implements MainPluginApiProvider {
@inject(GreetingMain)
protected readonly greetingMain: GreetingMain;
initialize(rpc: RPCProtocol): void {
rpc.set(PLUGIN_RPC_CONTEXT.GREETING_MAIN, this.greetingMain);
}
}

View File

@@ -0,0 +1,72 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { generateUuid } from '@theia/core/lib/common/uuid';
import { RPCProtocol } from '@theia/plugin-ext/lib/common/rpc-protocol';
import { inject, injectable } from '@theia/core/shared/inversify';
import { GreetingKind, GreeterData, GreetingExt, GreetingMain, MAIN_RPC_CONTEXT } from '../common/plugin-api-rpc';
const GREETINGS = {
[GreetingKind.DIRECT]: ['Hello, world!', "I'm here!", 'Good day!'],
[GreetingKind.QUIRKY]: ['Howdy doody, world?', "What's crack-a-lackin'?", 'Wazzup werld?'],
[GreetingKind.SNARKY]: ["Oh, it's you, world.", 'You again, world?!', 'Whatever.'],
} as const;
@injectable()
export class GreetingMainImpl implements GreetingMain {
protected proxy: GreetingExt;
private greeterData: Record<string, GreeterData> = {};
constructor(@inject(RPCProtocol) rpc: RPCProtocol) {
this.proxy = rpc.getProxy(MAIN_RPC_CONTEXT.GREETING_EXT);
}
async $createGreeter(): Promise<GreeterData> {
const result: GreeterData = {
uuid: generateUuid(),
greetingKinds: [GreetingKind.DIRECT]
};
this.greeterData[result.uuid] = result;
return result;
}
async $destroyGreeter(greeterId: string): Promise<void> {
delete this.greeterData[greeterId];
}
$updateGreeter(data: GreeterData): void {
const myData = this.greeterData[data.uuid];
if (myData) {
myData.greetingKinds = [...data.greetingKinds];
this.proxy.$greeterUpdated({ ...myData });
}
}
async $getMessage(greeterId: string): Promise<string> {
const data = this.greeterData[greeterId];
if (data.greetingKinds.length === 0) {
throw new Error(`No greetings are available for greeter ${greeterId}`);
}
// Get a random one of our supported greeting kinds.
const kind = data.greetingKinds[(Math.floor(Math.random() * data.greetingKinds.length))];
// And a random greeting of that kind
const greetingIdx = Math.floor(Math.random() * GREETINGS[kind].length);
return GREETINGS[kind][greetingIdx];
}
}

View File

@@ -0,0 +1,97 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
import { RPCProtocol } from '@theia/plugin-ext/lib/common/rpc-protocol';
import { Plugin } from '@theia/plugin-ext/lib/common/plugin-api-rpc';
import type * as gotd from '../gotd';
import { GreetingKind, GreetingExt, MAIN_RPC_CONTEXT } from '../common/plugin-api-rpc';
import { GreetingExtImpl } from './greeting-ext-impl';
import { Disposable, DisposableCollection } from '@theia/core';
import { PluginContainerModule } from '@theia/plugin-ext/lib/plugin/node/plugin-container-module';
// This script is responsible for creating and returning the extension's
// custom API object when a plugin's module imports it. Keep in mind that
// all of the code here runs in the plugin-host node process, whether that
// be the backend host dedicated to some frontend connection or the single
// host for headless plugins, which is where the plugin itself is running.
type Gotd = typeof gotd;
const GotdApiFactory = Symbol('GotdApiFactory');
// Retrieved by Theia to configure the Inversify DI container when the plugin is initialized.
// This is called when the plugin-host process is forked.
export const containerModule = PluginContainerModule.create(({ bind, bindApiFactory }) => {
bind(GreetingExt).to(GreetingExtImpl).inSingletonScope();
bindApiFactory('@theia/api-provider-sample', GotdApiFactory, GotdApiFactoryImpl);
});
// Creates the Greeting of the Day API object
@injectable()
class GotdApiFactoryImpl {
@inject(RPCProtocol)
protected readonly rpc: RPCProtocol;
@inject(GreetingExt)
protected readonly greetingExt: GreetingExt;
@postConstruct()
initialize(): void {
this.rpc.set(MAIN_RPC_CONTEXT.GREETING_EXT, this.greetingExt);
}
createApi(plugin: Plugin): Gotd {
const self = this;
async function createGreeter(): Promise<gotd.greeting.Greeter> {
const toDispose = new DisposableCollection();
const uuid = await self.greetingExt.registerGreeter();
toDispose.push(Disposable.create(() => self.greetingExt.unregisterGreeter(uuid)));
const onGreetingKindsChanged = self.greetingExt.onGreetingKindsChanged(uuid);
const result: gotd.greeting.Greeter = {
get greetingKinds(): readonly GreetingKind[] {
return self.greetingExt.getGreetingKinds(uuid);
},
setGreetingKind(greetingKind: GreetingKind, enable = true): void {
self.greetingExt.setGreetingKindEnabled(uuid, greetingKind, enable);
},
getMessage(): Promise<string> {
return self.greetingExt.getMessage(uuid);
},
onGreetingKindsChanged,
dispose: toDispose.dispose.bind(toDispose),
};
return result;
}
const greeting: Gotd['greeting'] = {
createGreeter,
GreetingKind
};
return {
greeting,
Disposable,
};
};
}

View File

@@ -0,0 +1,86 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { inject, injectable } from '@theia/core/shared/inversify';
import { GreetingKind, GreeterData, GreetingExt, GreetingMain, PLUGIN_RPC_CONTEXT } from '../common/plugin-api-rpc';
import { RPCProtocol } from '@theia/plugin-ext/lib/common/rpc-protocol';
import { Event, Emitter } from '@theia/core';
type LocalGreeterData = GreeterData & {
onGreetingKindsChangedEmitter: Emitter<readonly GreetingKind[]>
};
@injectable()
export class GreetingExtImpl implements GreetingExt {
private readonly proxy: GreetingMain;
private greeterData: Record<string, LocalGreeterData> = {};
constructor(@inject(RPCProtocol) rpc: RPCProtocol) {
this.proxy = rpc.getProxy(PLUGIN_RPC_CONTEXT.GREETING_MAIN);
}
async registerGreeter(): Promise<string> {
const newGreeter = await this.proxy.$createGreeter();
this.greeterData[newGreeter.uuid] = {
...newGreeter,
onGreetingKindsChangedEmitter: new Emitter()
};
return newGreeter.uuid;
}
unregisterGreeter(uuid: string): Promise<void> {
delete this.greeterData[uuid];
return this.proxy.$destroyGreeter(uuid);
}
getGreetingKinds(greeterId: string): readonly GreetingKind[] {
const data = this.greeterData[greeterId];
return data ? [...data.greetingKinds] : [];
}
setGreetingKindEnabled(greeterId: string, greetingKind: GreetingKind, enable: boolean): void {
const data = this.greeterData[greeterId];
if (data.greetingKinds.includes(greetingKind) === enable) {
return; // Nothing to change
}
if (enable) {
data.greetingKinds.push(greetingKind);
} else {
const index = data.greetingKinds.indexOf(greetingKind);
data.greetingKinds.splice(index, 1);
}
this.proxy.$updateGreeter({uuid: greeterId, greetingKinds: [...data.greetingKinds] });
}
onGreetingKindsChanged(greeterId: string): Event<readonly GreetingKind[]> {
return this.greeterData[greeterId].onGreetingKindsChangedEmitter.event;
}
getMessage(greeterId: string): Promise<string> {
return this.proxy.$getMessage(greeterId);
}
$greeterUpdated(data: GreeterData): void {
const myData = this.greeterData[data.uuid];
if (myData) {
myData.greetingKinds = [...data.greetingKinds];
myData.onGreetingKindsChangedEmitter.fire([...data.greetingKinds]);
}
}
}

View File

@@ -0,0 +1,22 @@
{
"extends": "../../configs/base.tsconfig",
"compilerOptions": {
"composite": true,
"rootDir": "src",
"outDir": "lib"
},
"include": [
"src"
],
"references": [
{
"path": "../../packages/core"
},
{
"path": "../../packages/plugin-ext"
},
{
"path": "../../packages/plugin-ext-headless"
}
]
}