@rimori/client 1.3.1 → 1.4.3
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/.prettierignore +35 -0
- package/README.md +77 -71
- package/dist/cli/scripts/init/dev-registration.d.ts +1 -1
- package/dist/cli/scripts/init/dev-registration.js +4 -4
- package/dist/cli/scripts/init/main.js +1 -1
- package/dist/cli/scripts/init/package-setup.d.ts +1 -1
- package/dist/cli/scripts/init/package-setup.js +3 -3
- package/dist/cli/scripts/init/router-transformer.js +19 -12
- package/dist/cli/scripts/init/vite-config.d.ts +2 -2
- package/dist/cli/scripts/init/vite-config.js +2 -2
- package/dist/cli/scripts/release/release-config-upload.js +9 -9
- package/dist/cli/scripts/release/release-db-update.d.ts +1 -1
- package/dist/cli/scripts/release/release-db-update.js +9 -9
- package/dist/cli/scripts/release/release-file-upload.js +2 -2
- package/dist/cli/scripts/release/release.js +2 -2
- package/dist/cli/types/DatabaseTypes.d.ts +2 -2
- package/dist/components/CRUDModal.d.ts +1 -1
- package/dist/components/CRUDModal.js +3 -3
- package/dist/components/MarkdownEditor.js +16 -16
- package/dist/components/Spinner.js +2 -2
- package/dist/components/ai/Assistant.js +7 -8
- package/dist/components/ai/Avatar.d.ts +2 -2
- package/dist/components/ai/Avatar.js +14 -7
- package/dist/components/ai/EmbeddedAssistent/AudioInputField.js +5 -6
- package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.d.ts +1 -1
- package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +1 -2
- package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.d.ts +1 -2
- package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.js +4 -2
- package/dist/components/ai/EmbeddedAssistent/TTS/Player.js +1 -1
- package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +2 -3
- package/dist/components/audio/Playbutton.js +10 -7
- package/dist/components/components/ContextMenu.d.ts +1 -1
- package/dist/components/components/ContextMenu.js +19 -16
- package/dist/components.d.ts +10 -10
- package/dist/components.js +10 -10
- package/dist/core/controller/AIController.d.ts +2 -2
- package/dist/core/controller/AIController.js +20 -18
- package/dist/core/controller/ExerciseController.d.ts +52 -0
- package/dist/core/controller/ExerciseController.js +73 -0
- package/dist/core/controller/ObjectController.js +5 -5
- package/dist/core/controller/SettingsController.d.ts +22 -7
- package/dist/core/controller/SettingsController.js +73 -8
- package/dist/core/controller/SharedContentController.d.ts +3 -3
- package/dist/core/controller/SharedContentController.js +38 -20
- package/dist/core/controller/VoiceController.js +6 -4
- package/dist/core/core.d.ts +15 -14
- package/dist/core/core.js +7 -7
- package/dist/fromRimori/EventBus.js +23 -23
- package/dist/fromRimori/PluginTypes.d.ts +4 -4
- package/dist/hooks/UseChatHook.d.ts +3 -3
- package/dist/hooks/UseChatHook.js +9 -3
- package/dist/index.d.ts +10 -10
- package/dist/index.js +9 -9
- package/dist/plugin/AccomplishmentHandler.d.ts +5 -5
- package/dist/plugin/AccomplishmentHandler.js +31 -27
- package/dist/plugin/AudioController.d.ts +1 -1
- package/dist/plugin/AudioController.js +6 -6
- package/dist/plugin/Logger.d.ts +5 -0
- package/dist/plugin/Logger.js +65 -13
- package/dist/plugin/PluginController.d.ts +7 -1
- package/dist/plugin/PluginController.js +32 -27
- package/dist/plugin/RimoriClient.d.ts +39 -14
- package/dist/plugin/RimoriClient.js +60 -31
- package/dist/plugin/StandaloneClient.d.ts +1 -1
- package/dist/plugin/StandaloneClient.js +35 -16
- package/dist/plugin/ThemeSetter.js +4 -4
- package/dist/providers/PluginProvider.js +44 -14
- package/dist/utils/Language.js +57 -57
- package/dist/utils/PluginUtils.js +3 -3
- package/dist/utils/difficultyConverter.d.ts +1 -1
- package/dist/utils/difficultyConverter.js +1 -1
- package/dist/utils/endpoint.js +2 -2
- package/dist/worker/WorkerSetup.d.ts +1 -1
- package/dist/worker/WorkerSetup.js +6 -6
- package/eslint.config.js +53 -0
- package/example/docs/devdocs.md +50 -40
- package/example/docs/overview.md +1 -1
- package/example/docs/userdocs.md +4 -1
- package/example/rimori.config.ts +51 -49
- package/example/worker/vite.config.ts +3 -3
- package/example/worker/worker.ts +2 -2
- package/package.json +17 -4
- package/prettier.config.js +8 -0
- package/src/cli/scripts/init/dev-registration.ts +5 -8
- package/src/cli/scripts/init/env-setup.ts +1 -1
- package/src/cli/scripts/init/file-operations.ts +1 -1
- package/src/cli/scripts/init/html-cleaner.ts +2 -5
- package/src/cli/scripts/init/main.ts +16 -13
- package/src/cli/scripts/init/package-setup.ts +11 -15
- package/src/cli/scripts/init/router-transformer.ts +40 -37
- package/src/cli/scripts/init/tailwind-config.ts +17 -26
- package/src/cli/scripts/init/vite-config.ts +3 -3
- package/src/cli/scripts/release/release-config-upload.ts +11 -11
- package/src/cli/scripts/release/release-db-update.ts +12 -12
- package/src/cli/scripts/release/release-file-upload.ts +3 -3
- package/src/cli/scripts/release/release.ts +4 -4
- package/src/cli/types/DatabaseTypes.ts +7 -8
- package/src/components/CRUDModal.tsx +64 -48
- package/src/components/MarkdownEditor.tsx +58 -27
- package/src/components/Spinner.tsx +24 -17
- package/src/components/ai/Assistant.tsx +70 -70
- package/src/components/ai/Avatar.tsx +20 -16
- package/src/components/ai/EmbeddedAssistent/AudioInputField.tsx +63 -54
- package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +14 -5
- package/src/components/ai/EmbeddedAssistent/TTS/MessageSender.ts +75 -74
- package/src/components/ai/EmbeddedAssistent/TTS/Player.ts +177 -178
- package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +109 -94
- package/src/components/ai/utils.ts +4 -4
- package/src/components/audio/Playbutton.tsx +101 -93
- package/src/components/components/ContextMenu.tsx +47 -35
- package/src/components.ts +10 -10
- package/src/core/controller/AIController.ts +62 -50
- package/src/core/controller/ExerciseController.ts +98 -0
- package/src/core/controller/ObjectController.ts +15 -10
- package/src/core/controller/SettingsController.ts +89 -16
- package/src/core/controller/SharedContentController.ts +80 -44
- package/src/core/controller/VoiceController.ts +10 -8
- package/src/core/core.ts +15 -15
- package/src/fromRimori/EventBus.ts +76 -47
- package/src/fromRimori/PluginTypes.ts +26 -17
- package/src/fromRimori/readme.md +2 -2
- package/src/hooks/UseChatHook.ts +25 -15
- package/src/index.ts +10 -10
- package/src/plugin/AccomplishmentHandler.ts +53 -35
- package/src/plugin/AudioController.ts +18 -12
- package/src/plugin/Logger.ts +77 -19
- package/src/plugin/PluginController.ts +60 -44
- package/src/plugin/RimoriClient.ts +133 -69
- package/src/plugin/StandaloneClient.ts +51 -24
- package/src/plugin/ThemeSetter.ts +5 -5
- package/src/providers/PluginProvider.tsx +90 -36
- package/src/style.scss +3 -3
- package/src/utils/Language.ts +58 -58
- package/src/utils/PluginUtils.ts +16 -20
- package/src/utils/difficultyConverter.ts +2 -2
- package/src/utils/endpoint.ts +3 -2
- package/src/worker/WorkerSetup.ts +8 -9
- package/tsconfig.json +2 -4
- package/dist/components/LoggerExample.d.ts +0 -6
- package/dist/components/LoggerExample.js +0 -79
- package/dist/core/controller/AudioController.d.ts +0 -0
- package/dist/core/controller/AudioController.js +0 -1
- package/dist/hooks/UseLogger.d.ts +0 -30
- package/dist/hooks/UseLogger.js +0 -122
- package/dist/plugin/LoggerExample.d.ts +0 -16
- package/dist/plugin/LoggerExample.js +0 -140
- package/dist/utils/audioFormats.d.ts +0 -26
- package/dist/utils/audioFormats.js +0 -67
|
@@ -2,7 +2,7 @@ import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
|
|
2
2
|
import { UserInfo } from '../core/controller/SettingsController';
|
|
3
3
|
import { EventBus, EventBusMessage } from '../fromRimori/EventBus';
|
|
4
4
|
import { ActivePlugin, Plugin } from '../fromRimori/PluginTypes';
|
|
5
|
-
import { RimoriClient } from
|
|
5
|
+
import { RimoriClient } from './RimoriClient';
|
|
6
6
|
import { StandaloneClient } from './StandaloneClient';
|
|
7
7
|
import { setTheme } from './ThemeSetter';
|
|
8
8
|
import { Logger } from './Logger';
|
|
@@ -10,18 +10,25 @@ import { Logger } from './Logger';
|
|
|
10
10
|
// Add declaration for WorkerGlobalScope
|
|
11
11
|
declare const WorkerGlobalScope: any;
|
|
12
12
|
|
|
13
|
+
export interface Guild {
|
|
14
|
+
id: string;
|
|
15
|
+
longTermGoalOverride: string;
|
|
16
|
+
allowUserPluginSettings: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
13
19
|
export interface RimoriInfo {
|
|
14
|
-
url: string
|
|
15
|
-
key: string
|
|
16
|
-
backendUrl: string
|
|
17
|
-
token: string
|
|
18
|
-
expiration: Date
|
|
19
|
-
tablePrefix: string
|
|
20
|
-
pluginId: string
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
url: string;
|
|
21
|
+
key: string;
|
|
22
|
+
backendUrl: string;
|
|
23
|
+
token: string;
|
|
24
|
+
expiration: Date;
|
|
25
|
+
tablePrefix: string;
|
|
26
|
+
pluginId: string;
|
|
27
|
+
guild: Guild;
|
|
28
|
+
installedPlugins: Plugin[];
|
|
29
|
+
profile: UserInfo;
|
|
30
|
+
mainPanelPlugin?: ActivePlugin;
|
|
31
|
+
sidePanelPlugin?: ActivePlugin;
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
export class PluginController {
|
|
@@ -54,12 +61,16 @@ export class PluginController {
|
|
|
54
61
|
|
|
55
62
|
private initMessageChannel(worker: boolean = false) {
|
|
56
63
|
const listener = (event: MessageEvent) => {
|
|
57
|
-
console.log(
|
|
64
|
+
console.log('[PluginController] window message', { origin: event.origin, data: event.data });
|
|
58
65
|
const { type, pluginId, queryParams, rimoriInfo } = event.data || {};
|
|
59
66
|
const [transferredPort] = event.ports || [];
|
|
60
67
|
|
|
61
|
-
if (type !==
|
|
62
|
-
console.log(
|
|
68
|
+
if (type !== 'rimori:init' || !transferredPort || pluginId !== this.pluginId) {
|
|
69
|
+
console.log('[PluginController] message ignored (not init or wrong plugin)', {
|
|
70
|
+
type,
|
|
71
|
+
pluginId,
|
|
72
|
+
hasPort: !!transferredPort,
|
|
73
|
+
});
|
|
63
74
|
return;
|
|
64
75
|
}
|
|
65
76
|
|
|
@@ -70,7 +81,7 @@ export class PluginController {
|
|
|
70
81
|
if (rimoriInfo) {
|
|
71
82
|
this.rimoriInfo = rimoriInfo;
|
|
72
83
|
this.supabase = createClient(rimoriInfo.url, rimoriInfo.key, {
|
|
73
|
-
accessToken: () => Promise.resolve(rimoriInfo.token)
|
|
84
|
+
accessToken: () => Promise.resolve(rimoriInfo.token),
|
|
74
85
|
});
|
|
75
86
|
}
|
|
76
87
|
|
|
@@ -98,8 +109,8 @@ export class PluginController {
|
|
|
98
109
|
}
|
|
99
110
|
|
|
100
111
|
// Forward plugin events to parent (only after MessageChannel is ready)
|
|
101
|
-
EventBus.on(
|
|
102
|
-
if (ev.sender === this.pluginId && !ev.topic.startsWith(
|
|
112
|
+
EventBus.on('*', (ev) => {
|
|
113
|
+
if (ev.sender === this.pluginId && !ev.topic.startsWith('self.')) {
|
|
103
114
|
this.port?.postMessage({ event: ev });
|
|
104
115
|
}
|
|
105
116
|
});
|
|
@@ -108,27 +119,27 @@ export class PluginController {
|
|
|
108
119
|
this.isMessageChannelReady = true;
|
|
109
120
|
|
|
110
121
|
// Process any pending requests
|
|
111
|
-
this.pendingRequests.forEach(request => request());
|
|
122
|
+
this.pendingRequests.forEach((request) => request());
|
|
112
123
|
this.pendingRequests = [];
|
|
113
124
|
};
|
|
114
125
|
if (worker) {
|
|
115
126
|
self.onmessage = listener;
|
|
116
127
|
} else {
|
|
117
|
-
window.addEventListener(
|
|
128
|
+
window.addEventListener('message', listener);
|
|
118
129
|
}
|
|
119
130
|
this.sendHello(worker);
|
|
120
131
|
}
|
|
121
132
|
|
|
122
133
|
private sendHello(isWorker: boolean = false) {
|
|
123
134
|
try {
|
|
124
|
-
const payload = { type:
|
|
135
|
+
const payload = { type: 'rimori:hello', pluginId: this.pluginId };
|
|
125
136
|
if (isWorker) {
|
|
126
137
|
self.postMessage(payload);
|
|
127
138
|
} else {
|
|
128
|
-
window.parent.postMessage(payload,
|
|
139
|
+
window.parent.postMessage(payload, '*');
|
|
129
140
|
}
|
|
130
141
|
} catch (e) {
|
|
131
|
-
console.error(
|
|
142
|
+
console.error('[PluginController] Error sending hello:', e);
|
|
132
143
|
}
|
|
133
144
|
}
|
|
134
145
|
|
|
@@ -141,7 +152,7 @@ export class PluginController {
|
|
|
141
152
|
PluginController.client = await RimoriClient.getInstance(PluginController.instance);
|
|
142
153
|
|
|
143
154
|
//only init logger in workers and on main plugin pages
|
|
144
|
-
if (PluginController.instance.getQueryParam(
|
|
155
|
+
if (PluginController.instance.getQueryParam('applicationMode') !== 'sidebar') {
|
|
145
156
|
Logger.getInstance(PluginController.client);
|
|
146
157
|
}
|
|
147
158
|
}
|
|
@@ -152,7 +163,7 @@ export class PluginController {
|
|
|
152
163
|
return this.queryParams[key] || null;
|
|
153
164
|
}
|
|
154
165
|
|
|
155
|
-
public async getClient(): Promise<{ supabase: SupabaseClient
|
|
166
|
+
public async getClient(): Promise<{ supabase: SupabaseClient; info: RimoriInfo }> {
|
|
156
167
|
// Return cached client if valid
|
|
157
168
|
if (this.supabase && this.rimoriInfo && this.rimoriInfo.expiration > new Date()) {
|
|
158
169
|
return { supabase: this.supabase, info: this.rimoriInfo };
|
|
@@ -160,7 +171,7 @@ export class PluginController {
|
|
|
160
171
|
|
|
161
172
|
// If MessageChannel is not ready yet, queue the request
|
|
162
173
|
if (!this.isMessageChannelReady) {
|
|
163
|
-
return new Promise<{ supabase: SupabaseClient
|
|
174
|
+
return new Promise<{ supabase: SupabaseClient; info: RimoriInfo }>((resolve) => {
|
|
164
175
|
this.pendingRequests.push(async () => {
|
|
165
176
|
const result = await this.getClient();
|
|
166
177
|
resolve(result);
|
|
@@ -185,18 +196,18 @@ export class PluginController {
|
|
|
185
196
|
sender: this.pluginId,
|
|
186
197
|
topic: 'global.supabase.requestAccess',
|
|
187
198
|
data: {},
|
|
188
|
-
debug: false
|
|
189
|
-
}
|
|
199
|
+
debug: false,
|
|
200
|
+
},
|
|
190
201
|
};
|
|
191
202
|
|
|
192
|
-
return new Promise<{ supabase: SupabaseClient
|
|
203
|
+
return new Promise<{ supabase: SupabaseClient; info: RimoriInfo }>((resolve) => {
|
|
193
204
|
// Listen for the response
|
|
194
205
|
const originalOnMessage = self.onmessage;
|
|
195
206
|
self.onmessage = (event) => {
|
|
196
207
|
if (event.data?.topic === 'global.supabase.requestAccess' && event.data?.eventId === eventId) {
|
|
197
208
|
this.rimoriInfo = event.data.data;
|
|
198
209
|
this.supabase = createClient(this.rimoriInfo!.url, this.rimoriInfo!.key, {
|
|
199
|
-
accessToken: () => Promise.resolve(this.getToken())
|
|
210
|
+
accessToken: () => Promise.resolve(this.getToken()),
|
|
200
211
|
});
|
|
201
212
|
self.onmessage = originalOnMessage; // Restore original handler
|
|
202
213
|
resolve({ supabase: this.supabase, info: this.rimoriInfo! });
|
|
@@ -210,10 +221,11 @@ export class PluginController {
|
|
|
210
221
|
});
|
|
211
222
|
} else {
|
|
212
223
|
// In main thread context, use EventBus
|
|
213
|
-
const { data } = await EventBus.request<RimoriInfo>(this.pluginId,
|
|
224
|
+
const { data } = await EventBus.request<RimoriInfo>(this.pluginId, 'global.supabase.requestAccess');
|
|
225
|
+
console.log({ data });
|
|
214
226
|
this.rimoriInfo = data;
|
|
215
227
|
this.supabase = createClient(this.rimoriInfo.url, this.rimoriInfo.key, {
|
|
216
|
-
accessToken: () => Promise.resolve(this.getToken())
|
|
228
|
+
accessToken: () => Promise.resolve(this.getToken()),
|
|
217
229
|
});
|
|
218
230
|
}
|
|
219
231
|
}
|
|
@@ -228,13 +240,16 @@ export class PluginController {
|
|
|
228
240
|
|
|
229
241
|
// If we don't have rimoriInfo, request it
|
|
230
242
|
if (!this.rimoriInfo) {
|
|
231
|
-
const { data } = await EventBus.request<RimoriInfo>(this.pluginId,
|
|
243
|
+
const { data } = await EventBus.request<RimoriInfo>(this.pluginId, 'global.supabase.requestAccess');
|
|
232
244
|
this.rimoriInfo = data;
|
|
233
245
|
return this.rimoriInfo.token;
|
|
234
246
|
}
|
|
235
247
|
|
|
236
248
|
// If token is expired, request fresh access
|
|
237
|
-
const { data } = await EventBus.request<{ token: string
|
|
249
|
+
const { data } = await EventBus.request<{ token: string; expiration: Date }>(
|
|
250
|
+
this.pluginId,
|
|
251
|
+
'global.supabase.requestAccess',
|
|
252
|
+
);
|
|
238
253
|
this.rimoriInfo.token = data.token;
|
|
239
254
|
this.rimoriInfo.expiration = data.expiration;
|
|
240
255
|
|
|
@@ -248,7 +263,7 @@ export class PluginController {
|
|
|
248
263
|
*/
|
|
249
264
|
public getSupabaseUrl() {
|
|
250
265
|
if (!this.rimoriInfo) {
|
|
251
|
-
throw new Error(
|
|
266
|
+
throw new Error('Supabase info not found');
|
|
252
267
|
}
|
|
253
268
|
|
|
254
269
|
return this.rimoriInfo.url;
|
|
@@ -256,30 +271,31 @@ export class PluginController {
|
|
|
256
271
|
|
|
257
272
|
public getBackendUrl() {
|
|
258
273
|
if (!this.rimoriInfo) {
|
|
259
|
-
throw new Error(
|
|
274
|
+
throw new Error('Rimori info not found');
|
|
260
275
|
}
|
|
261
276
|
return this.rimoriInfo.backendUrl;
|
|
262
277
|
}
|
|
263
278
|
|
|
264
279
|
public getGlobalEventTopic(preliminaryTopic: string) {
|
|
265
|
-
if (preliminaryTopic.startsWith(
|
|
280
|
+
if (preliminaryTopic.startsWith('global.')) {
|
|
266
281
|
return preliminaryTopic;
|
|
267
282
|
}
|
|
268
|
-
if (preliminaryTopic.startsWith(
|
|
283
|
+
if (preliminaryTopic.startsWith('self.')) {
|
|
269
284
|
return preliminaryTopic;
|
|
270
285
|
}
|
|
271
|
-
const topicParts = preliminaryTopic.split(
|
|
286
|
+
const topicParts = preliminaryTopic.split('.');
|
|
272
287
|
if (topicParts.length === 3) {
|
|
273
|
-
if (!topicParts[0].startsWith(
|
|
288
|
+
if (!topicParts[0].startsWith('pl') && topicParts[0] !== 'global') {
|
|
274
289
|
throw new Error("The event topic must start with the plugin id or 'global'.");
|
|
275
290
|
}
|
|
276
291
|
return preliminaryTopic;
|
|
277
292
|
} else if (topicParts.length > 3) {
|
|
278
|
-
throw new Error(
|
|
293
|
+
throw new Error(
|
|
294
|
+
`The event topic must consist of 3 parts. <pluginId>.<topic area>.<action>. Received: ${preliminaryTopic}`,
|
|
295
|
+
);
|
|
279
296
|
}
|
|
280
297
|
|
|
281
|
-
const topicRoot = this.rimoriInfo?.pluginId ??
|
|
298
|
+
const topicRoot = this.rimoriInfo?.pluginId ?? 'global';
|
|
282
299
|
return `${topicRoot}.${preliminaryTopic}`;
|
|
283
300
|
}
|
|
284
|
-
|
|
285
|
-
}
|
|
301
|
+
}
|
|
@@ -1,21 +1,30 @@
|
|
|
1
|
-
import { PostgrestQueryBuilder } from
|
|
2
|
-
import { SupabaseClient } from
|
|
3
|
-
import { GenericSchema } from
|
|
4
|
-
import { generateText, Message, OnLLMResponse, streamChatGPT } from
|
|
5
|
-
import { generateObject, ObjectRequest } from
|
|
6
|
-
import { SettingsController, UserInfo } from
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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 '../core/controller/AIController';
|
|
5
|
+
import { generateObject, ObjectRequest } from '../core/controller/ObjectController';
|
|
6
|
+
import { SettingsController, UserInfo } from '../core/controller/SettingsController';
|
|
7
|
+
import {
|
|
8
|
+
SharedContent,
|
|
9
|
+
SharedContentController,
|
|
10
|
+
SharedContentFilter,
|
|
11
|
+
SharedContentObjectRequest,
|
|
12
|
+
} from '../core/controller/SharedContentController';
|
|
13
|
+
import { getSTTResponse, getTTSResponse } from '../core/controller/VoiceController';
|
|
14
|
+
import { ExerciseController, CreateExerciseParams } from '../core/controller/ExerciseController';
|
|
15
|
+
import { EventBus, EventBusMessage, EventHandler, EventPayload } from '../fromRimori/EventBus';
|
|
16
|
+
import { ActivePlugin, MainPanelAction, Plugin, Tool } from '../fromRimori/PluginTypes';
|
|
17
|
+
import { AccomplishmentHandler, AccomplishmentPayload } from './AccomplishmentHandler';
|
|
18
|
+
import { PluginController, RimoriInfo } from './PluginController';
|
|
14
19
|
|
|
15
20
|
interface Db {
|
|
16
21
|
from: {
|
|
17
|
-
<TableName extends string & keyof GenericSchema['Tables'], Table extends GenericSchema['Tables'][TableName]>(
|
|
18
|
-
|
|
22
|
+
<TableName extends string & keyof GenericSchema['Tables'], Table extends GenericSchema['Tables'][TableName]>(
|
|
23
|
+
relation: TableName,
|
|
24
|
+
): PostgrestQueryBuilder<GenericSchema, Table, TableName>;
|
|
25
|
+
<ViewName extends string & keyof GenericSchema['Views'], View extends GenericSchema['Views'][ViewName]>(
|
|
26
|
+
relation: ViewName,
|
|
27
|
+
): PostgrestQueryBuilder<GenericSchema, View, ViewName>;
|
|
19
28
|
};
|
|
20
29
|
// storage: SupabaseClient["storage"];
|
|
21
30
|
|
|
@@ -40,7 +49,7 @@ interface PluginInterface {
|
|
|
40
49
|
* Get the settings for the plugin. T can be any type of settings, UserSettings or SystemSettings.
|
|
41
50
|
* @param defaultSettings The default settings to use if no settings are found.
|
|
42
51
|
* @param genericSettings The type of settings to get.
|
|
43
|
-
* @returns The settings for the plugin.
|
|
52
|
+
* @returns The settings for the plugin.
|
|
44
53
|
*/
|
|
45
54
|
getSettings: <T extends object>(defaultSettings: T) => Promise<T>;
|
|
46
55
|
/**
|
|
@@ -53,15 +62,15 @@ interface PluginInterface {
|
|
|
53
62
|
/**
|
|
54
63
|
* All installed plugins.
|
|
55
64
|
*/
|
|
56
|
-
installedPlugins: Plugin[]
|
|
65
|
+
installedPlugins: Plugin[];
|
|
57
66
|
/**
|
|
58
67
|
* The plugin that is loaded in the main panel.
|
|
59
68
|
*/
|
|
60
|
-
mainPanelPlugin?: ActivePlugin
|
|
69
|
+
mainPanelPlugin?: ActivePlugin;
|
|
61
70
|
/**
|
|
62
71
|
* The plugin that is loaded in the side panel.
|
|
63
72
|
*/
|
|
64
|
-
sidePanelPlugin?: ActivePlugin
|
|
73
|
+
sidePanelPlugin?: ActivePlugin;
|
|
65
74
|
};
|
|
66
75
|
getUserInfo: () => UserInfo;
|
|
67
76
|
}
|
|
@@ -72,6 +81,7 @@ export class RimoriClient {
|
|
|
72
81
|
private pluginController: PluginController;
|
|
73
82
|
private settingsController: SettingsController;
|
|
74
83
|
private sharedContentController: SharedContentController;
|
|
84
|
+
private exerciseController: ExerciseController;
|
|
75
85
|
private accomplishmentHandler: AccomplishmentHandler;
|
|
76
86
|
private rimoriInfo: RimoriInfo;
|
|
77
87
|
public plugin: PluginInterface;
|
|
@@ -81,19 +91,21 @@ export class RimoriClient {
|
|
|
81
91
|
this.rimoriInfo = info;
|
|
82
92
|
this.superbase = supabase;
|
|
83
93
|
this.pluginController = pluginController;
|
|
84
|
-
this.settingsController = new SettingsController(supabase, info.pluginId);
|
|
94
|
+
this.settingsController = new SettingsController(supabase, info.pluginId, info.guild);
|
|
85
95
|
this.sharedContentController = new SharedContentController(this.superbase, this);
|
|
96
|
+
this.exerciseController = new ExerciseController(supabase, pluginController);
|
|
86
97
|
this.accomplishmentHandler = new AccomplishmentHandler(info.pluginId);
|
|
87
98
|
|
|
88
99
|
this.from = this.from.bind(this);
|
|
100
|
+
this.getTableName = this.getTableName.bind(this);
|
|
89
101
|
|
|
90
102
|
this.db = {
|
|
91
103
|
from: this.from,
|
|
92
104
|
// storage: this.superbase.storage,
|
|
93
105
|
// functions: this.superbase.functions,
|
|
94
106
|
tablePrefix: info.tablePrefix,
|
|
95
|
-
getTableName: this.getTableName
|
|
96
|
-
}
|
|
107
|
+
getTableName: this.getTableName,
|
|
108
|
+
};
|
|
97
109
|
this.plugin = {
|
|
98
110
|
pluginId: info.pluginId,
|
|
99
111
|
setSettings: async (settings: any) => {
|
|
@@ -110,14 +122,14 @@ export class RimoriClient {
|
|
|
110
122
|
installedPlugins: this.rimoriInfo.installedPlugins,
|
|
111
123
|
mainPanelPlugin: this.rimoriInfo.mainPanelPlugin,
|
|
112
124
|
sidePanelPlugin: this.rimoriInfo.sidePanelPlugin,
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
};
|
|
116
128
|
}
|
|
117
129
|
|
|
118
130
|
public event = {
|
|
119
131
|
/**
|
|
120
|
-
* Emit an event to Rimori or a plugin.
|
|
132
|
+
* Emit an event to Rimori or a plugin.
|
|
121
133
|
* The topic schema is:
|
|
122
134
|
* {pluginId}.{eventId}
|
|
123
135
|
* Check out the event bus documentation for more information.
|
|
@@ -148,7 +160,10 @@ export class RimoriClient {
|
|
|
148
160
|
*/
|
|
149
161
|
on: <T = EventPayload>(topic: string | string[], callback: EventHandler<T>) => {
|
|
150
162
|
const topics = Array.isArray(topic) ? topic : [topic];
|
|
151
|
-
return EventBus.on<T>(
|
|
163
|
+
return EventBus.on<T>(
|
|
164
|
+
topics.map((t) => this.pluginController.getGlobalEventTopic(t)),
|
|
165
|
+
callback,
|
|
166
|
+
);
|
|
152
167
|
},
|
|
153
168
|
/**
|
|
154
169
|
* Subscribe to an event once.
|
|
@@ -163,9 +178,16 @@ export class RimoriClient {
|
|
|
163
178
|
* @param topic The topic to respond to.
|
|
164
179
|
* @param data The data to respond with.
|
|
165
180
|
*/
|
|
166
|
-
respond: <T = EventPayload>(
|
|
181
|
+
respond: <T = EventPayload>(
|
|
182
|
+
topic: string | string[],
|
|
183
|
+
data: EventPayload | ((data: EventBusMessage<T>) => EventPayload | Promise<EventPayload>),
|
|
184
|
+
) => {
|
|
167
185
|
const topics = Array.isArray(topic) ? topic : [topic];
|
|
168
|
-
EventBus.respond(
|
|
186
|
+
EventBus.respond(
|
|
187
|
+
this.plugin.pluginId,
|
|
188
|
+
topics.map((t) => this.pluginController.getGlobalEventTopic(t)),
|
|
189
|
+
data,
|
|
190
|
+
);
|
|
169
191
|
},
|
|
170
192
|
/**
|
|
171
193
|
* Emit an accomplishment.
|
|
@@ -179,7 +201,10 @@ export class RimoriClient {
|
|
|
179
201
|
* @param accomplishmentTopic The topic to subscribe to.
|
|
180
202
|
* @param callback The callback to call when the accomplishment is emitted.
|
|
181
203
|
*/
|
|
182
|
-
onAccomplishment: (
|
|
204
|
+
onAccomplishment: (
|
|
205
|
+
accomplishmentTopic: string,
|
|
206
|
+
callback: (payload: EventBusMessage<AccomplishmentPayload>) => void,
|
|
207
|
+
) => {
|
|
183
208
|
this.accomplishmentHandler.subscribe(accomplishmentTopic, callback);
|
|
184
209
|
},
|
|
185
210
|
/**
|
|
@@ -189,21 +214,21 @@ export class RimoriClient {
|
|
|
189
214
|
* @param text Optional text to be used for the action like for example text that the translator would look up.
|
|
190
215
|
*/
|
|
191
216
|
emitSidebarAction: (pluginId: string, actionKey: string, text?: string) => {
|
|
192
|
-
this.event.emit(
|
|
217
|
+
this.event.emit('global.sidebar.triggerAction', { plugin_id: pluginId, action_key: actionKey, text });
|
|
193
218
|
},
|
|
194
219
|
|
|
195
220
|
onMainPanelAction: (callback: (data: MainPanelAction) => void) => {
|
|
196
221
|
// this needs to be a emit and on because the main panel action is triggered by the user and not by the plugin
|
|
197
|
-
this.event.emit(
|
|
198
|
-
this.event.on<MainPanelAction>(
|
|
199
|
-
}
|
|
200
|
-
}
|
|
222
|
+
this.event.emit('action.requestMain');
|
|
223
|
+
this.event.on<MainPanelAction>('action.requestMain', ({ data }) => callback(data));
|
|
224
|
+
},
|
|
225
|
+
};
|
|
201
226
|
|
|
202
227
|
public navigation = {
|
|
203
228
|
toDashboard: () => {
|
|
204
|
-
this.event.emit(
|
|
205
|
-
}
|
|
206
|
-
}
|
|
229
|
+
this.event.emit('global.navigation.triggerToDashboard');
|
|
230
|
+
},
|
|
231
|
+
};
|
|
207
232
|
|
|
208
233
|
/**
|
|
209
234
|
* Get a query parameter value that was passed via MessageChannel
|
|
@@ -224,36 +249,37 @@ export class RimoriClient {
|
|
|
224
249
|
|
|
225
250
|
private from<
|
|
226
251
|
TableName extends string & keyof GenericSchema['Tables'],
|
|
227
|
-
Table extends GenericSchema['Tables'][TableName]
|
|
228
|
-
>(relation: TableName): PostgrestQueryBuilder<GenericSchema, Table, TableName
|
|
229
|
-
private from<
|
|
230
|
-
ViewName
|
|
231
|
-
|
|
232
|
-
>(relation: ViewName): PostgrestQueryBuilder<GenericSchema, View, ViewName>
|
|
252
|
+
Table extends GenericSchema['Tables'][TableName],
|
|
253
|
+
>(relation: TableName): PostgrestQueryBuilder<GenericSchema, Table, TableName>;
|
|
254
|
+
private from<ViewName extends string & keyof GenericSchema['Views'], View extends GenericSchema['Views'][ViewName]>(
|
|
255
|
+
relation: ViewName,
|
|
256
|
+
): PostgrestQueryBuilder<GenericSchema, View, ViewName>;
|
|
233
257
|
private from(relation: string): PostgrestQueryBuilder<GenericSchema, any, any> {
|
|
234
258
|
return this.superbase.from(this.getTableName(relation));
|
|
235
259
|
}
|
|
236
260
|
|
|
237
261
|
private getTableName(table: string) {
|
|
238
262
|
if (/[A-Z]/.test(table)) {
|
|
239
|
-
throw new Error(
|
|
263
|
+
throw new Error('Table name cannot include uppercase letters. Please use snake_case for table names.');
|
|
240
264
|
}
|
|
241
|
-
if (table.startsWith(
|
|
242
|
-
return table.replace(
|
|
265
|
+
if (table.startsWith('global_')) {
|
|
266
|
+
return table.replace('global_', '');
|
|
243
267
|
}
|
|
244
|
-
return this.db.tablePrefix +
|
|
268
|
+
return this.db.tablePrefix + '_' + table;
|
|
245
269
|
}
|
|
246
270
|
|
|
247
271
|
public ai = {
|
|
248
272
|
getText: async (messages: Message[], tools?: Tool[]): Promise<string> => {
|
|
249
273
|
const token = await this.pluginController.getToken();
|
|
250
|
-
return generateText(this.pluginController.getBackendUrl(), messages, tools || [], token).then(
|
|
274
|
+
return generateText(this.pluginController.getBackendUrl(), messages, tools || [], token).then(
|
|
275
|
+
({ messages }) => messages[0].content[0].text,
|
|
276
|
+
);
|
|
251
277
|
},
|
|
252
278
|
getSteamedText: async (messages: Message[], onMessage: OnLLMResponse, tools?: Tool[]) => {
|
|
253
279
|
const token = await this.pluginController.getToken();
|
|
254
280
|
streamChatGPT(this.pluginController.getBackendUrl(), messages, tools || [], onMessage, token);
|
|
255
281
|
},
|
|
256
|
-
getVoice: async (text: string, voice =
|
|
282
|
+
getVoice: async (text: string, voice = 'alloy', speed = 1, language?: string): Promise<Blob> => {
|
|
257
283
|
const token = await this.pluginController.getToken();
|
|
258
284
|
return getTTSResponse(this.pluginController.getBackendUrl(), { input: text, voice, speed, language }, token);
|
|
259
285
|
},
|
|
@@ -266,7 +292,7 @@ export class RimoriClient {
|
|
|
266
292
|
return generateObject(this.pluginController.getBackendUrl(), request, token);
|
|
267
293
|
},
|
|
268
294
|
// getSteamedObject: this.generateObjectStream,
|
|
269
|
-
}
|
|
295
|
+
};
|
|
270
296
|
|
|
271
297
|
public runtime = {
|
|
272
298
|
fetchBackend: async (url: string, options: RequestInit) => {
|
|
@@ -275,11 +301,11 @@ export class RimoriClient {
|
|
|
275
301
|
...options,
|
|
276
302
|
headers: {
|
|
277
303
|
...options.headers,
|
|
278
|
-
|
|
279
|
-
}
|
|
304
|
+
Authorization: `Bearer ${token}`,
|
|
305
|
+
},
|
|
280
306
|
});
|
|
281
|
-
}
|
|
282
|
-
}
|
|
307
|
+
},
|
|
308
|
+
};
|
|
283
309
|
|
|
284
310
|
public community = {
|
|
285
311
|
/**
|
|
@@ -304,7 +330,11 @@ export class RimoriClient {
|
|
|
304
330
|
* @param limit The optional limit for the number of results.
|
|
305
331
|
* @returns The list of shared content items.
|
|
306
332
|
*/
|
|
307
|
-
getList: async <T = any>(
|
|
333
|
+
getList: async <T = any>(
|
|
334
|
+
contentType: string,
|
|
335
|
+
filter?: SharedContentFilter,
|
|
336
|
+
limit?: number,
|
|
337
|
+
): Promise<SharedContent<T>[]> => {
|
|
308
338
|
return await this.sharedContentController.getSharedContentList(contentType, filter, limit);
|
|
309
339
|
},
|
|
310
340
|
/**
|
|
@@ -325,7 +355,12 @@ export class RimoriClient {
|
|
|
325
355
|
filter?: SharedContentFilter,
|
|
326
356
|
options?: { privateTopic?: boolean; skipDbSave?: boolean; alwaysGenerateNew?: boolean; excludeIds?: string[] },
|
|
327
357
|
): Promise<SharedContent<T>> => {
|
|
328
|
-
return await this.sharedContentController.getNewSharedContent(
|
|
358
|
+
return await this.sharedContentController.getNewSharedContent(
|
|
359
|
+
contentType,
|
|
360
|
+
generatorInstructions,
|
|
361
|
+
filter,
|
|
362
|
+
options,
|
|
363
|
+
);
|
|
329
364
|
},
|
|
330
365
|
/**
|
|
331
366
|
* Create a new shared content item.
|
|
@@ -345,10 +380,10 @@ export class RimoriClient {
|
|
|
345
380
|
return await this.sharedContentController.updateSharedContent(id, content);
|
|
346
381
|
},
|
|
347
382
|
/**
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
383
|
+
* Complete a shared content item.
|
|
384
|
+
* @param contentType The type of shared content to complete. E.g. assignments, exercises, etc.
|
|
385
|
+
* @param assignmentId The id of the shared content item to complete.
|
|
386
|
+
*/
|
|
352
387
|
complete: async (contentType: string, assignmentId: string) => {
|
|
353
388
|
return await this.sharedContentController.completeSharedContent(contentType, assignmentId);
|
|
354
389
|
},
|
|
@@ -358,11 +393,11 @@ export class RimoriClient {
|
|
|
358
393
|
* Useful for marking content as completed, ongoing, hidden, liked, disliked, or bookmarked.
|
|
359
394
|
*/
|
|
360
395
|
updateState: async (params: {
|
|
361
|
-
contentType: string
|
|
362
|
-
id: string
|
|
363
|
-
state?: 'completed' | 'ongoing' | 'hidden'
|
|
364
|
-
reaction?: 'liked' | 'disliked' | null
|
|
365
|
-
bookmarked?: boolean
|
|
396
|
+
contentType: string;
|
|
397
|
+
id: string;
|
|
398
|
+
state?: 'completed' | 'ongoing' | 'hidden';
|
|
399
|
+
reaction?: 'liked' | 'disliked' | null;
|
|
400
|
+
bookmarked?: boolean;
|
|
366
401
|
}): Promise<void> => {
|
|
367
402
|
return await this.sharedContentController.updateSharedContentState(params);
|
|
368
403
|
},
|
|
@@ -373,7 +408,36 @@ export class RimoriClient {
|
|
|
373
408
|
*/
|
|
374
409
|
remove: async (id: string): Promise<SharedContent<any>> => {
|
|
375
410
|
return await this.sharedContentController.removeSharedContent(id);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
public exercise = {
|
|
416
|
+
/**
|
|
417
|
+
* Fetches weekly exercises from the weekly_exercises view.
|
|
418
|
+
* Shows exercises for the current week that haven't expired.
|
|
419
|
+
* @returns Array of exercise objects.
|
|
420
|
+
*/
|
|
421
|
+
view: async () => {
|
|
422
|
+
return this.exerciseController.viewWeeklyExercises();
|
|
423
|
+
},
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Creates a new exercise via the backend API.
|
|
427
|
+
* @param params Exercise creation parameters.
|
|
428
|
+
* @returns Created exercise object.
|
|
429
|
+
*/
|
|
430
|
+
add: async (params: CreateExerciseParams) => {
|
|
431
|
+
return this.exerciseController.addExercise(params);
|
|
432
|
+
},
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Deletes an exercise via the backend API.
|
|
436
|
+
* @param id The exercise ID to delete.
|
|
437
|
+
* @returns Success status.
|
|
438
|
+
*/
|
|
439
|
+
delete: async (id: string) => {
|
|
440
|
+
return this.exerciseController.deleteExercise(id);
|
|
441
|
+
},
|
|
442
|
+
};
|
|
379
443
|
}
|