@rimori/client 2.4.0-next.4 → 2.4.0-next.6
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/dist/cli/scripts/init/dev-registration.js +4 -2
- package/dist/cli/scripts/init/main.js +1 -0
- package/dist/controller/SettingsController.d.ts +1 -1
- package/dist/controller/SharedContentController.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/plugin/CommunicationHandler.d.ts +3 -10
- package/dist/plugin/CommunicationHandler.js +15 -69
- package/dist/plugin/RimoriClient.d.ts +11 -208
- package/dist/plugin/RimoriClient.js +16 -312
- package/dist/plugin/StandaloneClient.d.ts +1 -1
- package/dist/plugin/StandaloneClient.js +3 -2
- package/dist/plugin/module/AIModule.d.ts +49 -0
- package/dist/plugin/module/AIModule.js +81 -0
- package/dist/plugin/module/DbModule.d.ts +30 -0
- package/dist/plugin/module/DbModule.js +51 -0
- package/dist/plugin/module/EventModule.d.ts +99 -0
- package/dist/plugin/module/EventModule.js +162 -0
- package/dist/{controller/ExerciseController.d.ts → plugin/module/ExerciseModule.d.ts} +20 -16
- package/dist/{controller/ExerciseController.js → plugin/module/ExerciseModule.js} +27 -20
- package/dist/plugin/module/PluginModule.d.ts +76 -0
- package/dist/plugin/module/PluginModule.js +88 -0
- package/package.json +4 -3
- package/src/cli/scripts/init/dev-registration.ts +4 -2
- package/src/cli/scripts/init/main.ts +1 -0
- package/src/controller/SettingsController.ts +1 -1
- package/src/controller/SharedContentController.ts +1 -1
- package/src/index.ts +2 -2
- package/src/plugin/CommunicationHandler.ts +17 -79
- package/src/plugin/RimoriClient.ts +25 -368
- package/src/plugin/StandaloneClient.ts +5 -3
- package/src/plugin/module/AIModule.ts +77 -0
- package/src/plugin/module/DbModule.ts +67 -0
- package/src/plugin/module/EventModule.ts +192 -0
- package/src/{controller/ExerciseController.ts → plugin/module/ExerciseModule.ts} +43 -29
- package/src/plugin/module/PluginModule.ts +114 -0
package/src/index.ts
CHANGED
|
@@ -11,9 +11,9 @@ export { AudioController } from './controller/AudioController';
|
|
|
11
11
|
export { Translator } from './controller/TranslationController';
|
|
12
12
|
export type { TOptions } from 'i18next';
|
|
13
13
|
export type { SharedContent, SharedContentObjectRequest } from './controller/SharedContentController';
|
|
14
|
-
export type { Exercise } from './
|
|
14
|
+
export type { Exercise } from './plugin/module/ExerciseModule';
|
|
15
15
|
export type { UserInfo, Language, UserRole } from './controller/SettingsController';
|
|
16
16
|
export type { Message, ToolInvocation } from './controller/AIController';
|
|
17
|
-
export type { TriggerAction } from './
|
|
17
|
+
export type { TriggerAction } from './plugin/module/ExerciseModule';
|
|
18
18
|
export type { MacroAccomplishmentPayload, MicroAccomplishmentPayload } from './controller/AccomplishmentController';
|
|
19
19
|
export type { EventBusMessage } from './fromRimori/EventBus';
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
|
2
1
|
import { UserInfo } from '../controller/SettingsController';
|
|
3
2
|
import { EventBus, EventBusMessage } from '../fromRimori/EventBus';
|
|
4
3
|
import { ActivePlugin, Plugin } from '../fromRimori/PluginTypes';
|
|
4
|
+
import { PostgrestClient } from '@supabase/postgrest-js';
|
|
5
5
|
|
|
6
6
|
// Add declaration for WorkerGlobalScope
|
|
7
7
|
declare const WorkerGlobalScope: any;
|
|
8
8
|
|
|
9
|
+
export type SupabaseClient = PostgrestClient;
|
|
10
|
+
|
|
9
11
|
export interface Guild {
|
|
10
12
|
allowUserPluginSettings: boolean;
|
|
11
13
|
city: string | null;
|
|
@@ -89,9 +91,7 @@ export class RimoriCommunicationHandler {
|
|
|
89
91
|
// Initialize Supabase client immediately with provided info
|
|
90
92
|
if (rimoriInfo) {
|
|
91
93
|
this.rimoriInfo = rimoriInfo;
|
|
92
|
-
this.supabase =
|
|
93
|
-
accessToken: () => Promise.resolve(rimoriInfo.token),
|
|
94
|
-
});
|
|
94
|
+
this.supabase = this.getSupabase(rimoriInfo.url, rimoriInfo.key, rimoriInfo.token);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
// Handle messages from parent
|
|
@@ -180,6 +180,16 @@ export class RimoriCommunicationHandler {
|
|
|
180
180
|
return this.queryParams[key] || null;
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
private getSupabase(url: string, key: string, token: string): SupabaseClient {
|
|
184
|
+
return new PostgrestClient(`${url}/rest/v1`, {
|
|
185
|
+
schema: this.rimoriInfo?.dbSchema,
|
|
186
|
+
headers: {
|
|
187
|
+
apikey: key,
|
|
188
|
+
Authorization: `Bearer ${token}`,
|
|
189
|
+
},
|
|
190
|
+
}) as unknown as SupabaseClient;
|
|
191
|
+
}
|
|
192
|
+
|
|
183
193
|
public async getClient(): Promise<{ supabase: SupabaseClient; info: RimoriInfo }> {
|
|
184
194
|
// Return cached client if valid
|
|
185
195
|
if (this.supabase && this.rimoriInfo && this.rimoriInfo.expiration > new Date()) {
|
|
@@ -223,9 +233,7 @@ export class RimoriCommunicationHandler {
|
|
|
223
233
|
self.onmessage = (event) => {
|
|
224
234
|
if (event.data?.topic === 'global.supabase.requestAccess' && event.data?.eventId === eventId) {
|
|
225
235
|
this.rimoriInfo = event.data.data;
|
|
226
|
-
this.supabase =
|
|
227
|
-
accessToken: () => Promise.resolve(this.getToken()),
|
|
228
|
-
});
|
|
236
|
+
this.supabase = this.getSupabase(this.rimoriInfo!.url, this.rimoriInfo!.key, this.rimoriInfo!.token);
|
|
229
237
|
self.onmessage = originalOnMessage; // Restore original handler
|
|
230
238
|
resolve({ supabase: this.supabase, info: this.rimoriInfo! });
|
|
231
239
|
} else if (originalOnMessage) {
|
|
@@ -241,81 +249,13 @@ export class RimoriCommunicationHandler {
|
|
|
241
249
|
const { data } = await EventBus.request<RimoriInfo>(this.pluginId, 'global.supabase.requestAccess');
|
|
242
250
|
// console.log({ data });
|
|
243
251
|
this.rimoriInfo = data;
|
|
244
|
-
this.supabase =
|
|
245
|
-
accessToken: () => Promise.resolve(this.getToken()),
|
|
246
|
-
});
|
|
252
|
+
this.supabase = this.getSupabase(this.rimoriInfo.url, this.rimoriInfo.key, this.rimoriInfo.token);
|
|
247
253
|
}
|
|
248
254
|
}
|
|
249
255
|
|
|
250
256
|
return { supabase: this.supabase!, info: this.rimoriInfo };
|
|
251
257
|
}
|
|
252
258
|
|
|
253
|
-
public async getToken(): Promise<string> {
|
|
254
|
-
if (this.rimoriInfo && this.rimoriInfo.expiration && this.rimoriInfo.expiration > new Date()) {
|
|
255
|
-
return this.rimoriInfo.token;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// If we don't have rimoriInfo, request it
|
|
259
|
-
if (!this.rimoriInfo) {
|
|
260
|
-
const { data } = await EventBus.request<RimoriInfo>(this.pluginId, 'global.supabase.requestAccess');
|
|
261
|
-
this.rimoriInfo = data;
|
|
262
|
-
return this.rimoriInfo.token;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// If token is expired, request fresh access
|
|
266
|
-
const { data } = await EventBus.request<{ token: string; expiration: Date }>(
|
|
267
|
-
this.pluginId,
|
|
268
|
-
'global.supabase.requestAccess',
|
|
269
|
-
);
|
|
270
|
-
this.rimoriInfo.token = data.token;
|
|
271
|
-
this.rimoriInfo.expiration = data.expiration;
|
|
272
|
-
|
|
273
|
-
return this.rimoriInfo.token;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Gets the Supabase URL.
|
|
278
|
-
* @returns The Supabase URL.
|
|
279
|
-
* @deprecated All endpoints should use the backend URL instead.
|
|
280
|
-
*/
|
|
281
|
-
public getSupabaseUrl(): string {
|
|
282
|
-
if (!this.rimoriInfo) {
|
|
283
|
-
throw new Error('Supabase info not found');
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return this.rimoriInfo.url;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
public getBackendUrl(): string {
|
|
290
|
-
if (!this.rimoriInfo) {
|
|
291
|
-
throw new Error('Rimori info not found');
|
|
292
|
-
}
|
|
293
|
-
return this.rimoriInfo.backendUrl;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
public getGlobalEventTopic(preliminaryTopic: string): string {
|
|
297
|
-
if (preliminaryTopic.startsWith('global.')) {
|
|
298
|
-
return preliminaryTopic;
|
|
299
|
-
}
|
|
300
|
-
if (preliminaryTopic.startsWith('self.')) {
|
|
301
|
-
return preliminaryTopic;
|
|
302
|
-
}
|
|
303
|
-
const topicParts = preliminaryTopic.split('.');
|
|
304
|
-
if (topicParts.length === 3) {
|
|
305
|
-
if (!topicParts[0].startsWith('pl') && topicParts[0] !== 'global') {
|
|
306
|
-
throw new Error("The event topic must start with the plugin id or 'global'.");
|
|
307
|
-
}
|
|
308
|
-
return preliminaryTopic;
|
|
309
|
-
} else if (topicParts.length > 3) {
|
|
310
|
-
throw new Error(
|
|
311
|
-
`The event topic must consist of 3 parts. <pluginId>.<topic area>.<action>. Received: ${preliminaryTopic}`,
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const topicRoot = this.rimoriInfo?.pluginId ?? 'global';
|
|
316
|
-
return `${topicRoot}.${preliminaryTopic}`;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
259
|
/**
|
|
320
260
|
* Handles updates to RimoriInfo from rimori-main.
|
|
321
261
|
* Updates the cached info and Supabase client, then notifies all registered callbacks.
|
|
@@ -325,9 +265,7 @@ export class RimoriCommunicationHandler {
|
|
|
325
265
|
this.rimoriInfo = newInfo;
|
|
326
266
|
|
|
327
267
|
// Update Supabase client with new token
|
|
328
|
-
this.supabase =
|
|
329
|
-
accessToken: () => Promise.resolve(newInfo.token),
|
|
330
|
-
});
|
|
268
|
+
this.supabase = this.getSupabase(newInfo.url, newInfo.key, newInfo.token);
|
|
331
269
|
|
|
332
270
|
// Notify all registered callbacks
|
|
333
271
|
this.updateCallbacks.forEach((callback) => {
|
|
@@ -1,334 +1,52 @@
|
|
|
1
|
-
import { PostgrestQueryBuilder } from '@supabase/postgrest-js';
|
|
2
|
-
import { SupabaseClient } from '@supabase/supabase-js';
|
|
3
|
-
import { GenericSchema } from '@supabase/supabase-js/dist/module/lib/types';
|
|
4
|
-
import { generateText, Message, OnLLMResponse, streamChatGPT } from '../controller/AIController';
|
|
5
|
-
import { generateObject, ObjectRequest } from '../controller/ObjectController';
|
|
6
|
-
import { SettingsController, UserInfo } from '../controller/SettingsController';
|
|
7
1
|
import {
|
|
8
2
|
SharedContent,
|
|
9
3
|
SharedContentController,
|
|
10
4
|
SharedContentFilter,
|
|
11
5
|
SharedContentObjectRequest,
|
|
12
6
|
} from '../controller/SharedContentController';
|
|
13
|
-
import { getSTTResponse, getTTSResponse } from '../controller/VoiceController';
|
|
14
|
-
import { ExerciseController, CreateExerciseParams } from '../controller/ExerciseController';
|
|
15
|
-
import { EventBus, EventBusMessage, EventHandler, EventPayload, EventListener } from '../fromRimori/EventBus';
|
|
16
|
-
import { ActivePlugin, MainPanelAction, Plugin, Tool } from '../fromRimori/PluginTypes';
|
|
17
|
-
import { AccomplishmentController, AccomplishmentPayload } from '../controller/AccomplishmentController';
|
|
18
7
|
import { RimoriCommunicationHandler, RimoriInfo } from './CommunicationHandler';
|
|
19
|
-
import { Translator } from '../controller/TranslationController';
|
|
20
8
|
import { Logger } from './Logger';
|
|
9
|
+
import { PluginModule } from './module/PluginModule';
|
|
10
|
+
import { DbModule } from './module/DbModule';
|
|
11
|
+
import { EventModule } from './module/EventModule';
|
|
12
|
+
import { AIModule } from './module/AIModule';
|
|
13
|
+
import { ExerciseModule } from './module/ExerciseModule';
|
|
14
|
+
import { PostgrestClient } from '@supabase/postgrest-js';
|
|
21
15
|
|
|
22
16
|
// Add declaration for WorkerGlobalScope
|
|
23
17
|
declare const WorkerGlobalScope: any;
|
|
24
18
|
|
|
25
19
|
export class RimoriClient {
|
|
26
20
|
private static instance: RimoriClient;
|
|
27
|
-
private superbase: SupabaseClient;
|
|
28
21
|
private pluginController: RimoriCommunicationHandler;
|
|
29
|
-
private settingsController: SettingsController;
|
|
30
22
|
private sharedContentController: SharedContentController;
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
public db: DbModule;
|
|
24
|
+
public event: EventModule;
|
|
25
|
+
public plugin: PluginModule;
|
|
26
|
+
public ai: AIModule;
|
|
27
|
+
public exercise: ExerciseModule;
|
|
33
28
|
private rimoriInfo: RimoriInfo;
|
|
34
|
-
private translator: Translator;
|
|
35
29
|
|
|
36
|
-
private constructor(controller: RimoriCommunicationHandler, supabase:
|
|
30
|
+
private constructor(controller: RimoriCommunicationHandler, supabase: PostgrestClient, info: RimoriInfo) {
|
|
37
31
|
this.rimoriInfo = info;
|
|
38
|
-
this.superbase = supabase;
|
|
39
32
|
this.pluginController = controller;
|
|
40
|
-
this.exerciseController = new ExerciseController(supabase, this);
|
|
41
|
-
this.accomplishmentHandler = new AccomplishmentController(info.pluginId);
|
|
42
|
-
this.settingsController = new SettingsController(supabase, info.pluginId, info.guild);
|
|
43
33
|
this.sharedContentController = new SharedContentController(supabase, this);
|
|
44
|
-
|
|
45
|
-
this.
|
|
34
|
+
this.ai = new AIModule(controller, info);
|
|
35
|
+
this.event = new EventModule(info.pluginId);
|
|
36
|
+
this.db = new DbModule(supabase, controller, info);
|
|
37
|
+
this.plugin = new PluginModule(supabase, controller, info);
|
|
38
|
+
this.exercise = new ExerciseModule(supabase, controller, info, this.event);
|
|
39
|
+
|
|
40
|
+
controller.onUpdate((updatedInfo) => {
|
|
41
|
+
this.rimoriInfo = updatedInfo;
|
|
42
|
+
});
|
|
46
43
|
|
|
47
44
|
//only init logger in workers and on main plugin pages
|
|
48
|
-
if (this.
|
|
45
|
+
if (this.plugin.applicationMode !== 'sidebar') {
|
|
49
46
|
Logger.getInstance(this);
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
49
|
|
|
53
|
-
public get plugin() {
|
|
54
|
-
return {
|
|
55
|
-
pluginId: this.rimoriInfo.pluginId,
|
|
56
|
-
/**
|
|
57
|
-
* The release channel of this plugin installation.
|
|
58
|
-
* Determines which database schema is used for plugin tables.
|
|
59
|
-
*/
|
|
60
|
-
releaseChannel: this.rimoriInfo.releaseChannel,
|
|
61
|
-
/**
|
|
62
|
-
* Set the settings for the plugin.
|
|
63
|
-
* @param settings The settings to set.
|
|
64
|
-
*/
|
|
65
|
-
setSettings: async (settings: any): Promise<void> => {
|
|
66
|
-
await this.settingsController.setSettings(settings);
|
|
67
|
-
},
|
|
68
|
-
/**
|
|
69
|
-
* Get the settings for the plugin. T can be any type of settings, UserSettings or SystemSettings.
|
|
70
|
-
* @param defaultSettings The default settings to use if no settings are found.
|
|
71
|
-
* @param genericSettings The type of settings to get.
|
|
72
|
-
* @returns The settings for the plugin.
|
|
73
|
-
*/
|
|
74
|
-
getSettings: async <T extends object>(defaultSettings: T): Promise<T> => {
|
|
75
|
-
return await this.settingsController.getSettings<T>(defaultSettings);
|
|
76
|
-
},
|
|
77
|
-
/**
|
|
78
|
-
* Get the current user info.
|
|
79
|
-
* Note: For reactive updates in React components, use the userInfo from useRimori() hook instead.
|
|
80
|
-
* @returns The user info.
|
|
81
|
-
*/
|
|
82
|
-
getUserInfo: (): UserInfo => {
|
|
83
|
-
return this.rimoriInfo.profile;
|
|
84
|
-
},
|
|
85
|
-
/**
|
|
86
|
-
* Register a callback to be notified when RimoriInfo is updated.
|
|
87
|
-
* This is useful for reacting to changes in user info, tokens, or other rimori data.
|
|
88
|
-
* @param callback - Function to call with the new RimoriInfo
|
|
89
|
-
* @returns Cleanup function to unregister the callback
|
|
90
|
-
*/
|
|
91
|
-
onRimoriInfoUpdate: (callback: (info: RimoriInfo) => void): (() => void) => {
|
|
92
|
-
return this.pluginController.onUpdate(callback);
|
|
93
|
-
},
|
|
94
|
-
/**
|
|
95
|
-
* Retrieves information about plugins, including:
|
|
96
|
-
* - All installed plugins
|
|
97
|
-
* - The currently active plugin in the main panel
|
|
98
|
-
* - The currently active plugin in the side panel
|
|
99
|
-
*/
|
|
100
|
-
getPluginInfo: (): {
|
|
101
|
-
/**
|
|
102
|
-
* All installed plugins.
|
|
103
|
-
*/
|
|
104
|
-
installedPlugins: Plugin[];
|
|
105
|
-
/**
|
|
106
|
-
* The plugin that is loaded in the main panel.
|
|
107
|
-
*/
|
|
108
|
-
mainPanelPlugin?: ActivePlugin;
|
|
109
|
-
/**
|
|
110
|
-
* The plugin that is loaded in the side panel.
|
|
111
|
-
*/
|
|
112
|
-
sidePanelPlugin?: ActivePlugin;
|
|
113
|
-
} => {
|
|
114
|
-
return {
|
|
115
|
-
installedPlugins: this.rimoriInfo.installedPlugins,
|
|
116
|
-
mainPanelPlugin: this.rimoriInfo.mainPanelPlugin,
|
|
117
|
-
sidePanelPlugin: this.rimoriInfo.sidePanelPlugin,
|
|
118
|
-
};
|
|
119
|
-
},
|
|
120
|
-
/**
|
|
121
|
-
* Get the translator for the plugin.
|
|
122
|
-
* @returns The translator for the plugin.
|
|
123
|
-
*/
|
|
124
|
-
getTranslator: async (): Promise<Translator> => {
|
|
125
|
-
await this.translator.initialize();
|
|
126
|
-
return this.translator;
|
|
127
|
-
},
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
public get db() {
|
|
132
|
-
return {
|
|
133
|
-
// private from<
|
|
134
|
-
// TableName extends string & keyof GenericSchema['Tables'],
|
|
135
|
-
// Table extends GenericSchema['Tables'][TableName],
|
|
136
|
-
// >(relation: TableName): PostgrestQueryBuilder<GenericSchema, Table, TableName>;
|
|
137
|
-
// private from<ViewName extends string & keyof GenericSchema['Views'], View extends GenericSchema['Views'][ViewName]>(
|
|
138
|
-
// relation: ViewName,
|
|
139
|
-
// ): PostgrestQueryBuilder<GenericSchema, View, ViewName>;
|
|
140
|
-
from: <ViewName extends string & keyof GenericSchema['Views'], View extends GenericSchema['Views'][ViewName]>(
|
|
141
|
-
relation: string,
|
|
142
|
-
): PostgrestQueryBuilder<GenericSchema, View, ViewName> => {
|
|
143
|
-
const tableName = this.db.getTableName(relation);
|
|
144
|
-
// Use the schema determined by rimori-main based on release channel
|
|
145
|
-
// Global tables (starting with 'global_') remain in public schema
|
|
146
|
-
// Plugin tables use the schema provided by rimori-main (plugins or plugins_alpha)
|
|
147
|
-
if (relation.startsWith('global_')) {
|
|
148
|
-
// Global tables stay in public schema
|
|
149
|
-
return this.superbase.from(tableName);
|
|
150
|
-
}
|
|
151
|
-
// Plugin tables go to the schema provided by rimori-main
|
|
152
|
-
return this.superbase.schema(this.rimoriInfo.dbSchema).from(tableName);
|
|
153
|
-
},
|
|
154
|
-
// storage: this.superbase.storage,
|
|
155
|
-
// functions: this.superbase.functions,
|
|
156
|
-
/**
|
|
157
|
-
* The table prefix for of database tables of the plugin.
|
|
158
|
-
*/
|
|
159
|
-
tablePrefix: this.rimoriInfo.tablePrefix,
|
|
160
|
-
/**
|
|
161
|
-
* The database schema used for plugin tables.
|
|
162
|
-
* Determined by rimori-main based on release channel:
|
|
163
|
-
* - 'plugins_alpha' for alpha release channel
|
|
164
|
-
* - 'plugins' for beta and stable release channels
|
|
165
|
-
*/
|
|
166
|
-
schema: this.rimoriInfo.dbSchema,
|
|
167
|
-
/**
|
|
168
|
-
* Get the table name for a given plugin table.
|
|
169
|
-
* Internally all tables are prefixed with the plugin id. This function is used to get the correct table name for a given public table.
|
|
170
|
-
* @param table The plugin table name to get the full table name for.
|
|
171
|
-
* @returns The full table name.
|
|
172
|
-
*/
|
|
173
|
-
getTableName: (table: string): string => {
|
|
174
|
-
if (/[A-Z]/.test(table)) {
|
|
175
|
-
throw new Error('Table name cannot include uppercase letters. Please use snake_case for table names.');
|
|
176
|
-
}
|
|
177
|
-
if (table.startsWith('global_')) {
|
|
178
|
-
return table.replace('global_', '');
|
|
179
|
-
}
|
|
180
|
-
return this.db.tablePrefix + '_' + table;
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
public event = {
|
|
186
|
-
/**
|
|
187
|
-
* Emit an event to Rimori or a plugin.
|
|
188
|
-
* The topic schema is:
|
|
189
|
-
* {pluginId}.{eventId}
|
|
190
|
-
* Check out the event bus documentation for more information.
|
|
191
|
-
* For triggering events from Rimori like context menu actions use the "global" keyword.
|
|
192
|
-
* @param topic The topic to emit the event on.
|
|
193
|
-
* @param data The data to emit.
|
|
194
|
-
* @param eventId The event id.
|
|
195
|
-
*/
|
|
196
|
-
emit: (topic: string, data?: any, eventId?: number) => {
|
|
197
|
-
const globalTopic = this.pluginController.getGlobalEventTopic(topic);
|
|
198
|
-
EventBus.emit(this.plugin.pluginId, globalTopic, data, eventId);
|
|
199
|
-
},
|
|
200
|
-
/**
|
|
201
|
-
* Request an event.
|
|
202
|
-
* @param topic The topic to request the event on.
|
|
203
|
-
* @param data The data to request.
|
|
204
|
-
* @returns The response from the event.
|
|
205
|
-
*/
|
|
206
|
-
request: <T>(topic: string, data?: any): Promise<EventBusMessage<T>> => {
|
|
207
|
-
const globalTopic = this.pluginController.getGlobalEventTopic(topic);
|
|
208
|
-
return EventBus.request<T>(this.plugin.pluginId, globalTopic, data);
|
|
209
|
-
},
|
|
210
|
-
/**
|
|
211
|
-
* Subscribe to an event.
|
|
212
|
-
* @param topic The topic to subscribe to.
|
|
213
|
-
* @param callback The callback to call when the event is emitted.
|
|
214
|
-
* @returns An EventListener object containing an off() method to unsubscribe the listeners.
|
|
215
|
-
*/
|
|
216
|
-
on: <T = EventPayload>(topic: string | string[], callback: EventHandler<T>): EventListener => {
|
|
217
|
-
const topics = Array.isArray(topic) ? topic : [topic];
|
|
218
|
-
return EventBus.on<T>(
|
|
219
|
-
topics.map((t) => this.pluginController.getGlobalEventTopic(t)),
|
|
220
|
-
callback,
|
|
221
|
-
);
|
|
222
|
-
},
|
|
223
|
-
/**
|
|
224
|
-
* Subscribe to an event once.
|
|
225
|
-
* @param topic The topic to subscribe to.
|
|
226
|
-
* @param callback The callback to call when the event is emitted.
|
|
227
|
-
*/
|
|
228
|
-
once: <T = EventPayload>(topic: string, callback: EventHandler<T>) => {
|
|
229
|
-
EventBus.once<T>(this.pluginController.getGlobalEventTopic(topic), callback);
|
|
230
|
-
},
|
|
231
|
-
/**
|
|
232
|
-
* Respond to an event.
|
|
233
|
-
* @param topic The topic to respond to.
|
|
234
|
-
* @param data The data to respond with.
|
|
235
|
-
*/
|
|
236
|
-
respond: <T = EventPayload>(
|
|
237
|
-
topic: string | string[],
|
|
238
|
-
data: EventPayload | ((data: EventBusMessage<T>) => EventPayload | Promise<EventPayload>),
|
|
239
|
-
) => {
|
|
240
|
-
const topics = Array.isArray(topic) ? topic : [topic];
|
|
241
|
-
EventBus.respond(
|
|
242
|
-
this.plugin.pluginId,
|
|
243
|
-
topics.map((t) => this.pluginController.getGlobalEventTopic(t)),
|
|
244
|
-
data,
|
|
245
|
-
);
|
|
246
|
-
},
|
|
247
|
-
/**
|
|
248
|
-
* Emit an accomplishment.
|
|
249
|
-
* @param payload The payload to emit.
|
|
250
|
-
*/
|
|
251
|
-
emitAccomplishment: (payload: AccomplishmentPayload) => {
|
|
252
|
-
this.accomplishmentHandler.emitAccomplishment(payload);
|
|
253
|
-
},
|
|
254
|
-
/**
|
|
255
|
-
* Subscribe to an accomplishment.
|
|
256
|
-
* @param accomplishmentTopic The topic to subscribe to.
|
|
257
|
-
* @param callback The callback to call when the accomplishment is emitted.
|
|
258
|
-
*/
|
|
259
|
-
onAccomplishment: (
|
|
260
|
-
accomplishmentTopic: string,
|
|
261
|
-
callback: (payload: EventBusMessage<AccomplishmentPayload>) => void,
|
|
262
|
-
) => {
|
|
263
|
-
this.accomplishmentHandler.subscribe(accomplishmentTopic, callback);
|
|
264
|
-
},
|
|
265
|
-
/**
|
|
266
|
-
* Trigger an action that opens the sidebar and triggers an action in the designated plugin.
|
|
267
|
-
* @param pluginId The id of the plugin to trigger the action for.
|
|
268
|
-
* @param actionKey The key of the action to trigger.
|
|
269
|
-
* @param text Optional text to be used for the action like for example text that the translator would look up.
|
|
270
|
-
*/
|
|
271
|
-
emitSidebarAction: (pluginId: string, actionKey: string, text?: string) => {
|
|
272
|
-
this.event.emit('global.sidebar.triggerAction', { plugin_id: pluginId, action_key: actionKey, text });
|
|
273
|
-
},
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Subscribe to main panel actions triggered by the user from the dashboard.
|
|
277
|
-
* @param callback Handler function that receives the action data when a matching action is triggered.
|
|
278
|
-
* @param actionsToListen Optional filter to listen only to specific action keys. If empty or not provided, all actions will trigger the callback.
|
|
279
|
-
* @returns An EventListener object with an `off()` method for cleanup.
|
|
280
|
-
*
|
|
281
|
-
* @example
|
|
282
|
-
* ```ts
|
|
283
|
-
* const listener = client.event.onMainPanelAction((data) => {
|
|
284
|
-
* console.log('Action received:', data.action_key);
|
|
285
|
-
* }, ['startSession', 'pauseSession']);
|
|
286
|
-
*
|
|
287
|
-
* // Clean up when component unmounts to prevent events from firing
|
|
288
|
-
* // when navigating away or returning to the page
|
|
289
|
-
* useEffect(() => {
|
|
290
|
-
* return () => listener.off();
|
|
291
|
-
* }, []);
|
|
292
|
-
* ```
|
|
293
|
-
*
|
|
294
|
-
* **Important:** Always call `listener.off()` when your component unmounts or when you no longer need to listen.
|
|
295
|
-
* This prevents the event handler from firing when navigating away from or returning to the page, which could
|
|
296
|
-
* cause unexpected behavior or duplicate event handling.
|
|
297
|
-
*/
|
|
298
|
-
onMainPanelAction: (
|
|
299
|
-
callback: (data: MainPanelAction) => void,
|
|
300
|
-
actionsToListen: string | string[] = [],
|
|
301
|
-
): EventListener => {
|
|
302
|
-
const listeningActions = Array.isArray(actionsToListen) ? actionsToListen : [actionsToListen];
|
|
303
|
-
// this needs to be a emit and on because the main panel action is triggered by the user and not by the plugin
|
|
304
|
-
this.event.emit('action.requestMain');
|
|
305
|
-
return this.event.on<MainPanelAction>('action.requestMain', ({ data }) => {
|
|
306
|
-
// console.log('Received action for main panel ' + data.action_key);
|
|
307
|
-
// console.log('Listening to actions', listeningActions);
|
|
308
|
-
if (listeningActions.length === 0 || listeningActions.includes(data.action_key)) {
|
|
309
|
-
callback(data);
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
},
|
|
313
|
-
|
|
314
|
-
onSidePanelAction: (
|
|
315
|
-
callback: (data: MainPanelAction) => void,
|
|
316
|
-
actionsToListen: string | string[] = [],
|
|
317
|
-
): EventListener => {
|
|
318
|
-
const listeningActions = Array.isArray(actionsToListen) ? actionsToListen : [actionsToListen];
|
|
319
|
-
// this needs to be a emit and on because the main panel action is triggered by the user and not by the plugin
|
|
320
|
-
this.event.emit('action.requestSidebar');
|
|
321
|
-
return this.event.on<MainPanelAction>('action.requestSidebar', ({ data }) => {
|
|
322
|
-
// console.log("eventHandler .onSidePanelAction", data);
|
|
323
|
-
// console.log('Received action for sidebar ' + data.action);
|
|
324
|
-
// console.log('Listening to actions', listeningActions);
|
|
325
|
-
if (listeningActions.length === 0 || listeningActions.includes(data.action)) {
|
|
326
|
-
callback(data);
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
},
|
|
330
|
-
};
|
|
331
|
-
|
|
332
50
|
public navigation = {
|
|
333
51
|
toDashboard: (): void => {
|
|
334
52
|
this.event.emit('global.navigation.triggerToDashboard');
|
|
@@ -338,6 +56,7 @@ export class RimoriClient {
|
|
|
338
56
|
/**
|
|
339
57
|
* Get a query parameter value that was passed via MessageChannel
|
|
340
58
|
* @param key The query parameter key
|
|
59
|
+
* @deprecated Use the plugin.applicationMode and plugin.theme properties instead
|
|
341
60
|
* @returns The query parameter value or null if not found
|
|
342
61
|
*/
|
|
343
62
|
public getQueryParam(key: string): string | null {
|
|
@@ -361,40 +80,13 @@ export class RimoriClient {
|
|
|
361
80
|
return RimoriClient.instance;
|
|
362
81
|
}
|
|
363
82
|
|
|
364
|
-
public ai = {
|
|
365
|
-
getText: async (messages: Message[], tools?: Tool[]): Promise<string> => {
|
|
366
|
-
const token = await this.pluginController.getToken();
|
|
367
|
-
return generateText(this.pluginController.getBackendUrl(), messages, tools || [], token).then(
|
|
368
|
-
({ messages }) => messages[0].content[0].text,
|
|
369
|
-
);
|
|
370
|
-
},
|
|
371
|
-
getSteamedText: async (messages: Message[], onMessage: OnLLMResponse, tools?: Tool[]) => {
|
|
372
|
-
const token = await this.pluginController.getToken();
|
|
373
|
-
streamChatGPT(this.pluginController.getBackendUrl(), messages, tools || [], onMessage, token);
|
|
374
|
-
},
|
|
375
|
-
getVoice: async (text: string, voice = 'alloy', speed = 1, language?: string): Promise<Blob> => {
|
|
376
|
-
const token = await this.pluginController.getToken();
|
|
377
|
-
return getTTSResponse(this.pluginController.getBackendUrl(), { input: text, voice, speed, language }, token);
|
|
378
|
-
},
|
|
379
|
-
getTextFromVoice: async (file: Blob): Promise<string> => {
|
|
380
|
-
const token = await this.pluginController.getToken();
|
|
381
|
-
return getSTTResponse(this.pluginController.getBackendUrl(), file, token);
|
|
382
|
-
},
|
|
383
|
-
getObject: async <T = any>(request: ObjectRequest): Promise<T> => {
|
|
384
|
-
const token = await this.pluginController.getToken();
|
|
385
|
-
return generateObject<T>(this.pluginController.getBackendUrl(), request, token);
|
|
386
|
-
},
|
|
387
|
-
// getSteamedObject: this.generateObjectStream,
|
|
388
|
-
};
|
|
389
|
-
|
|
390
83
|
public runtime = {
|
|
391
84
|
fetchBackend: async (url: string, options: RequestInit) => {
|
|
392
|
-
|
|
393
|
-
return fetch(this.pluginController.getBackendUrl() + url, {
|
|
85
|
+
return fetch(this.rimoriInfo.backendUrl + url, {
|
|
394
86
|
...options,
|
|
395
87
|
headers: {
|
|
396
88
|
...options.headers,
|
|
397
|
-
Authorization: `Bearer ${token}`,
|
|
89
|
+
Authorization: `Bearer ${this.rimoriInfo.token}`,
|
|
398
90
|
},
|
|
399
91
|
});
|
|
400
92
|
},
|
|
@@ -504,39 +196,4 @@ export class RimoriClient {
|
|
|
504
196
|
},
|
|
505
197
|
},
|
|
506
198
|
};
|
|
507
|
-
|
|
508
|
-
public exercise = {
|
|
509
|
-
/**
|
|
510
|
-
* Fetches weekly exercises from the weekly_exercises view.
|
|
511
|
-
* Shows exercises for the current week that haven't expired.
|
|
512
|
-
* @returns Array of exercise objects.
|
|
513
|
-
*/
|
|
514
|
-
view: async () => {
|
|
515
|
-
return this.exerciseController.viewWeeklyExercises();
|
|
516
|
-
},
|
|
517
|
-
|
|
518
|
-
/**
|
|
519
|
-
* Creates a new exercise or multiple exercises via the backend API.
|
|
520
|
-
* When creating multiple exercises, all requests are made in parallel but only one event is emitted.
|
|
521
|
-
* @param params Exercise creation parameters (single or array).
|
|
522
|
-
* @returns Created exercise objects.
|
|
523
|
-
*/
|
|
524
|
-
add: async (params: CreateExerciseParams | CreateExerciseParams[]) => {
|
|
525
|
-
const token = await this.pluginController.getToken();
|
|
526
|
-
const backendUrl = this.pluginController.getBackendUrl();
|
|
527
|
-
const exercises = Array.isArray(params) ? params : [params];
|
|
528
|
-
return this.exerciseController.addExercise(token, backendUrl, exercises);
|
|
529
|
-
},
|
|
530
|
-
|
|
531
|
-
/**
|
|
532
|
-
* Deletes an exercise via the backend API.
|
|
533
|
-
* @param id The exercise ID to delete.
|
|
534
|
-
* @returns Success status.
|
|
535
|
-
*/
|
|
536
|
-
delete: async (id: string) => {
|
|
537
|
-
const token = await this.pluginController.getToken();
|
|
538
|
-
const backendUrl = this.pluginController.getBackendUrl();
|
|
539
|
-
return this.exerciseController.deleteExercise(token, backendUrl, id);
|
|
540
|
-
},
|
|
541
|
-
};
|
|
542
199
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SupabaseClient } from './CommunicationHandler';
|
|
2
2
|
import { EventBus } from '../fromRimori/EventBus';
|
|
3
3
|
import { DEFAULT_ANON_KEY, DEFAULT_ENDPOINT } from '../utils/endpoint';
|
|
4
4
|
|
|
@@ -11,10 +11,12 @@ export interface StandaloneConfig {
|
|
|
11
11
|
export class StandaloneClient {
|
|
12
12
|
private static instance: StandaloneClient;
|
|
13
13
|
private config: StandaloneConfig;
|
|
14
|
-
private supabase: SupabaseClient;
|
|
14
|
+
private supabase: SupabaseClient & { auth: any }; // TODO: remove any
|
|
15
15
|
|
|
16
16
|
private constructor(config: StandaloneConfig) {
|
|
17
|
-
|
|
17
|
+
throw new Error('Authentication is disabled until new developer platform is released.');
|
|
18
|
+
// this.supabase = createClient(config.url, config.key);
|
|
19
|
+
this.supabase = {} as any;
|
|
18
20
|
this.config = config;
|
|
19
21
|
}
|
|
20
22
|
|