feature: core plugin support events & preferences modules (#365)

This commit is contained in:
Louis 2023-10-16 16:15:26 +07:00 committed by GitHub
parent 85e14c2942
commit abeb6b3bc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 312 additions and 31 deletions

View File

@ -34,20 +34,7 @@ export function init({ register }: { register: RegisterExtensionPoint }) {
}
```
### Access Core API
To access the Core API in your plugin, you can follow the code examples and explanations provided below.
##### Import Core API and Store Module
In your main entry code (e.g., `index.ts`), start by importing the necessary modules and functions from the `@janhq/plugin-core` library.
```js
// index.ts
import { store, core } from "@janhq/plugin-core";
```
#### Interact with Local Data Storage
### Interact with Local Data Storage
The Core API allows you to interact with local data storage. Here are a couple of examples of how you can use it:
@ -56,6 +43,8 @@ The Core API allows you to interact with local data storage. Here are a couple o
You can use the store.insertOne function to insert data into a specific collection in the local data store.
```js
import { store } from "@janhq/plugin-core";
function insertData() {
store.insertOne("conversations", { name: "meow" });
// Insert a new document with { name: "meow" } into the "conversations" collection.
@ -70,6 +59,8 @@ store.getOne(collectionName, key) retrieves a single document that matches the p
store.getMany(collectionName, selector, sort) retrieves multiple documents that match the provided selector in the specified collection.
```js
import { store } from "@janhq/plugin-core";
function getData() {
const selector = { name: "meow" };
const data = store.findMany("conversations", selector);
@ -108,6 +99,93 @@ function deleteData() {
}
```
### Events
You can subscribe to NewMessageRequest events by defining a function to handle the event and registering it with the events object:
```js
import { events } from "@janhq/plugin-core";
function handleMessageRequest(message: NewMessageRequest) {
// Your logic here. For example:
// const response = openai.createChatCompletion({...})
}
function registerListener() {
events.on(EventName.OnNewMessageRequest, handleMessageRequest);
}
// Register the listener function with the relevant extension points.
export function init({ register }) {
registerListener();
}
```
In this example, we're defining a function called handleMessageRequest that takes a NewMessageRequest object as its argument. We're also defining a function called registerListener that registers the handleMessageRequest function as a listener for NewMessageRequest events using the on method of the events object.
```js
import { events } from "@janhq/plugin-core";
function handleMessageRequest(data: NewMessageRequest) {
// Your logic here. For example:
const response = openai.createChatCompletion({...})
const message: NewMessageResponse = {
...data,
message: response.data.choices[0].message.content
}
// Now emit event so the app can display in the conversation
events.emit(EventName.OnNewMessageResponse, message)
}
```
### Preferences
To register plugin preferences, you can use the preferences object from the @janhq/plugin-core package. Here's an example of how to register and retrieve plugin preferences:
```js
import { PluginService, preferences } from "@janhq/plugin-core";
const PluginName = "your-first-plugin";
export function init({ register }: { register: RegisterExtensionPoint }) {
// Register preference update handlers. E.g. update plugin instance with new configuration
register(PluginService.OnPreferencesUpdate, PluginName, onPreferencesUpdate);
// Register plugin preferences. E.g. Plugin need apiKey and endpoint to connect to your service
preferences.registerPreferences<string>(register, PluginName, "apiKey", "");
preferences.registerPreferences<string>(register, PluginName, "endpoint", "");
}
```
In this example, we're registering preference update handlers and plugin preferences using the preferences object. We're also defining a PluginName constant to use as the name of the plugin.
To retrieve the values of the registered preferences, we're using the get method of the preferences object and passing in the name of the plugin and the name of the preference.
```js
import { preferences } from "@janhq/plugin-core";
const PluginName = "your-first-plugin";
const setup = async () => {
// Retrieve apiKey
const apiKey: string = (await preferences.get(PluginName, "apiKey")) ?? "";
// Retrieve endpoint
const endpoint: string = (await preferences.get(PluginName, "endpoint")) ?? "";
}
```
### Access Core API
To access the Core API in your plugin, you can follow the code examples and explanations provided below.
##### Import Core API and Store Module
In your main entry code (e.g., `index.ts`), start by importing the necessary modules and functions from the `@janhq/plugin-core` library.
```js
// index.ts
import { core } from "@janhq/plugin-core";
```
#### Perform File Operations
The Core API also provides functions to perform file operations. Here are a couple of examples:
@ -132,7 +210,7 @@ function deleteModel(filePath: string) {
}
```
### Execute plugin module in main process
#### Execute plugin module in main process
To execute a plugin module in the main process of your application, you can follow the steps outlined below.
@ -180,8 +258,8 @@ function getConvMessages(id: number) {
}
module.exports = {
getConvMessages
}
getConvMessages,
};
```
## CoreService API
@ -224,7 +302,6 @@ The `DataService` enum represents methods related to managing conversations and
The `InferenceService` enum exports:
- `InferenceUrl`: The URL for the inference server.
- `InitModel`: Initializes a model for inference.
- `StopModel`: Stops a running inference model.
@ -258,4 +335,11 @@ The `SystemMonitoringService` enum includes methods for monitoring system resour
- `GetResourcesInfo`: Gets information about system resources.
- `GetCurrentLoad`: Gets the current system load.
## PluginService
The `PluginService` enum includes plugin cycle handlers:
- `OnStart`: Handler for starting. E.g. Create a collection.
- `OnPreferencesUpdate`: Handler for preferences update. E.g. Update instances with new configurations.
For more detailed information on each of these components, please refer to the source code.

View File

@ -7,11 +7,7 @@
* @returns Promise<any>
*
*/
const invokePluginFunc: (
plugin: string,
method: string,
...args: any[]
) => Promise<any> = (plugin, method, ...args) =>
const invokePluginFunc: (plugin: string, method: string, ...args: any[]) => Promise<any> = (plugin, method, ...args) =>
window.coreAPI?.invokePluginFunc(plugin, method, ...args) ??
window.electronAPI?.invokePluginFunc(plugin, method, ...args);

71
plugin-core/events.ts Normal file
View File

@ -0,0 +1,71 @@
/**
* The `EventName` enumeration contains the names of all the available events in the Jan platform.
*/
export enum EventName {
OnNewConversation = "onNewConversation",
OnNewMessageRequest = "onNewMessageRequest",
OnNewMessageResponse = "onNewMessageResponse",
OnMessageResponseUpdate = "onMessageResponseUpdate",
}
/**
* The `NewMessageRequest` type defines the shape of a new message request object.
*/
export type NewMessageRequest = {
_id?: string;
conversationId?: string;
user?: string;
avatar?: string;
message?: string;
createdAt?: string;
updatedAt?: string;
};
/**
* The `NewMessageRequest` type defines the shape of a new message request object.
*/
export type NewMessageResponse = {
_id?: string;
conversationId?: string;
user?: string;
avatar?: string;
message?: string;
createdAt?: string;
updatedAt?: string;
};
/**
* Adds an observer for an event.
*
* @param eventName The name of the event to observe.
* @param handler The handler function to call when the event is observed.
*/
const on: (eventName: string, handler: Function) => void = (eventName, handler) => {
window.corePlugin?.events?.on(eventName, handler);
};
/**
* Removes an observer for an event.
*
* @param eventName The name of the event to stop observing.
* @param handler The handler function to call when the event is observed.
*/
const off: (eventName: string, handler: Function) => void = (eventName, handler) => {
window.corePlugin?.events?.off(eventName, handler);
};
/**
* Emits an event.
*
* @param eventName The name of the event to emit.
* @param object The object to pass to the event callback.
*/
const emit: (eventName: string, object: any) => void = (eventName, object) => {
window.corePlugin?.events?.emit(eventName, object);
};
export const events = {
on,
off,
emit,
};

View File

@ -107,11 +107,6 @@ export enum DataService {
* @enum {string}
*/
export enum InferenceService {
/**
* The URL for the inference server.
*/
InferenceUrl = "inferenceUrl",
/**
* Initializes a model for inference.
*/
@ -216,6 +211,32 @@ export enum SystemMonitoringService {
GetCurrentLoad = "getCurrentLoad",
}
/**
* PluginService exports.
* @enum {string}
*/
export enum PluginService {
/**
* The plugin is being started.
*/
OnStart = "pluginOnStart",
/**
* The plugin is being started.
*/
OnPreferencesUpdate = "pluginPreferencesUpdate",
/**
* The plugin is being stopped.
*/
OnStop = "pluginOnStop",
/**
* The plugin is being destroyed.
*/
OnDestroy = "pluginOnDestroy",
}
/**
* Store module exports.
* @module
@ -227,3 +248,15 @@ export { store } from "./store";
* @module
*/
export { core, RegisterExtensionPoint } from "./core";
/**
* Events module exports.
* @module
*/
export { events, EventName, NewMessageRequest, NewMessageResponse } from "./events";
/**
* Preferences module exports.
* @module
*/
export { preferences } from "./preferences";

View File

@ -1,15 +1,16 @@
{
"name": "@janhq/plugin-core",
"version": "0.1.0",
"version": "0.1.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@janhq/plugin-core",
"version": "0.1.0",
"version": "0.1.6",
"license": "MIT",
"devDependencies": {
"@types/node": "^12.0.2"
"@types/node": "^12.0.2",
"typescript": "^5.2.2"
}
},
"node_modules/@types/node": {
@ -17,6 +18,19 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz",
"integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==",
"dev": true
},
"node_modules/typescript": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
}
}
}

View File

@ -0,0 +1,82 @@
import { store } from "./store";
/**
* Returns the value of the specified preference for the specified plugin.
*
* @param pluginName The name of the plugin.
* @param preferenceName The name of the preference.
* @returns A promise that resolves to the value of the preference.
*/
function get(pluginName: string, preferenceName: string): Promise<any> {
return store
.createCollection("preferences", {})
.then(() => store.findOne("preferences", `${pluginName}.${preferenceName}`))
.then((doc) => doc?.value ?? "");
}
/**
* Sets the value of the specified preference for the specified plugin.
*
* @param pluginName The name of the plugin.
* @param preferenceName The name of the preference.
* @param value The value of the preference.
* @returns A promise that resolves when the preference has been set.
*/
function set(pluginName: string, preferenceName: string, value: any): Promise<any> {
return store
.createCollection("preferences", {})
.then(() =>
store
.findOne("preferences", `${pluginName}.${preferenceName}`)
.then((doc) =>
doc
? store.updateOne("preferences", `${pluginName}.${preferenceName}`, { value })
: store.insertOne("preferences", { _id: `${pluginName}.${preferenceName}`, value })
)
);
}
/**
* Clears all preferences for the specified plugin.
*
* @param pluginName The name of the plugin.
* @returns A promise that resolves when the preferences have been cleared.
*/
function clear(pluginName: string): Promise<void> {
return Promise.resolve();
}
/**
* Registers a preference with the specified default value.
*
* @param register The function to use for registering the preference.
* @param pluginName The name of the plugin.
* @param preferenceName The name of the preference.
* @param defaultValue The default value of the preference.
*/
function registerPreferences<T>(
register: Function,
pluginName: string,
preferenceKey: string,
preferenceName: string,
preferenceDescription: string,
defaultValue: T
) {
register("PluginPreferences", `${pluginName}.${preferenceKey}`, () => ({
pluginName,
preferenceKey,
preferenceName,
preferenceDescription,
defaultValue,
}));
}
/**
* An object that provides methods for getting, setting, and clearing preferences.
*/
export const preferences = {
get,
set,
clear,
registerPreferences,
};

View File

@ -3,6 +3,7 @@ export {};
declare global {
interface CorePlugin {
store?: any | undefined;
events?: any | undefined;
}
interface Window {
corePlugin?: CorePlugin;