feature: core plugin support events & preferences modules (#365)
This commit is contained in:
parent
85e14c2942
commit
abeb6b3bc4
@ -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.
|
||||
|
||||
@ -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
71
plugin-core/events.ts
Normal 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,
|
||||
};
|
||||
@ -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";
|
||||
|
||||
20
plugin-core/package-lock.json
generated
20
plugin-core/package-lock.json
generated
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
82
plugin-core/preferences.ts
Normal file
82
plugin-core/preferences.ts
Normal 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,
|
||||
};
|
||||
1
plugin-core/types/index.d.ts
vendored
1
plugin-core/types/index.d.ts
vendored
@ -3,6 +3,7 @@ export {};
|
||||
declare global {
|
||||
interface CorePlugin {
|
||||
store?: any | undefined;
|
||||
events?: any | undefined;
|
||||
}
|
||||
interface Window {
|
||||
corePlugin?: CorePlugin;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user