@rimori/client 2.4.0 → 2.5.0-next.2

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.
Files changed (70) hide show
  1. package/dist/cli/scripts/init/dev-registration.js +4 -2
  2. package/dist/cli/scripts/init/main.js +1 -0
  3. package/dist/cli/scripts/release/release.js +0 -0
  4. package/dist/controller/SettingsController.d.ts +1 -1
  5. package/dist/controller/SharedContentController.d.ts +1 -1
  6. package/dist/fromRimori/EventBus.js +1 -1
  7. package/dist/index.d.ts +2 -2
  8. package/dist/plugin/CommunicationHandler.d.ts +13 -8
  9. package/dist/plugin/CommunicationHandler.js +44 -59
  10. package/dist/plugin/RimoriClient.d.ts +11 -195
  11. package/dist/plugin/RimoriClient.js +17 -298
  12. package/dist/plugin/StandaloneClient.d.ts +1 -1
  13. package/dist/plugin/StandaloneClient.js +3 -2
  14. package/dist/plugin/module/AIModule.d.ts +49 -0
  15. package/dist/plugin/module/AIModule.js +81 -0
  16. package/dist/plugin/module/DbModule.d.ts +30 -0
  17. package/dist/plugin/module/DbModule.js +51 -0
  18. package/dist/plugin/module/EventModule.d.ts +99 -0
  19. package/dist/plugin/module/EventModule.js +162 -0
  20. package/dist/{controller/ExerciseController.d.ts → plugin/module/ExerciseModule.d.ts} +20 -16
  21. package/dist/{controller/ExerciseController.js → plugin/module/ExerciseModule.js} +27 -20
  22. package/dist/plugin/module/PluginModule.d.ts +76 -0
  23. package/dist/plugin/module/PluginModule.js +88 -0
  24. package/package.json +8 -3
  25. package/.github/workflows/pre-release.yml +0 -126
  26. package/.prettierignore +0 -35
  27. package/eslint.config.js +0 -53
  28. package/example/docs/devdocs.md +0 -241
  29. package/example/docs/overview.md +0 -29
  30. package/example/docs/userdocs.md +0 -126
  31. package/example/rimori.config.ts +0 -91
  32. package/example/worker/vite.config.ts +0 -26
  33. package/example/worker/worker.ts +0 -11
  34. package/prettier.config.js +0 -8
  35. package/src/cli/scripts/init/dev-registration.ts +0 -189
  36. package/src/cli/scripts/init/env-setup.ts +0 -44
  37. package/src/cli/scripts/init/file-operations.ts +0 -58
  38. package/src/cli/scripts/init/html-cleaner.ts +0 -45
  39. package/src/cli/scripts/init/main.ts +0 -175
  40. package/src/cli/scripts/init/package-setup.ts +0 -113
  41. package/src/cli/scripts/init/router-transformer.ts +0 -332
  42. package/src/cli/scripts/init/tailwind-config.ts +0 -66
  43. package/src/cli/scripts/init/vite-config.ts +0 -73
  44. package/src/cli/scripts/release/detect-translation-languages.ts +0 -37
  45. package/src/cli/scripts/release/release-config-upload.ts +0 -119
  46. package/src/cli/scripts/release/release-db-update.ts +0 -97
  47. package/src/cli/scripts/release/release-file-upload.ts +0 -138
  48. package/src/cli/scripts/release/release.ts +0 -85
  49. package/src/cli/types/DatabaseTypes.ts +0 -125
  50. package/src/controller/AIController.ts +0 -295
  51. package/src/controller/AccomplishmentController.ts +0 -188
  52. package/src/controller/AudioController.ts +0 -64
  53. package/src/controller/ExerciseController.ts +0 -117
  54. package/src/controller/ObjectController.ts +0 -120
  55. package/src/controller/SettingsController.ts +0 -186
  56. package/src/controller/SharedContentController.ts +0 -365
  57. package/src/controller/TranslationController.ts +0 -136
  58. package/src/controller/VoiceController.ts +0 -33
  59. package/src/fromRimori/EventBus.ts +0 -382
  60. package/src/fromRimori/PluginTypes.ts +0 -214
  61. package/src/fromRimori/readme.md +0 -2
  62. package/src/index.ts +0 -19
  63. package/src/plugin/CommunicationHandler.ts +0 -310
  64. package/src/plugin/Logger.ts +0 -394
  65. package/src/plugin/RimoriClient.ts +0 -530
  66. package/src/plugin/StandaloneClient.ts +0 -125
  67. package/src/utils/difficultyConverter.ts +0 -15
  68. package/src/utils/endpoint.ts +0 -3
  69. package/src/worker/WorkerSetup.ts +0 -35
  70. package/tsconfig.json +0 -17
@@ -1,136 +0,0 @@
1
- import { createInstance, ThirdPartyModule, TOptions, i18n as i18nType } from 'i18next';
2
-
3
- type InitializationState = 'not-inited' | 'initing' | 'finished';
4
-
5
- /**
6
- * Translator class for handling internationalization
7
- */
8
- export class Translator {
9
- private currentLanguage: string;
10
- private initializationState: InitializationState;
11
- private initializationPromise: Promise<void> | null;
12
- private i18n: i18nType | undefined;
13
- private translationUrl: string;
14
-
15
- constructor(initialLanguage: string, translationUrl: string) {
16
- this.currentLanguage = initialLanguage;
17
- this.initializationState = 'not-inited';
18
- this.initializationPromise = null;
19
- this.translationUrl = translationUrl;
20
- }
21
-
22
- /**
23
- * Initialize translator with user's language
24
- * @param userLanguage - Language code from user info
25
- */
26
- async initialize(): Promise<void> {
27
- // If already finished, return immediately
28
- if (this.initializationState === 'finished') {
29
- return;
30
- }
31
-
32
- // If currently initializing, wait for the existing initialization to complete
33
- if (this.initializationState === 'initing' && this.initializationPromise) {
34
- return this.initializationPromise;
35
- }
36
-
37
- // Start initialization
38
- this.initializationState = 'initing';
39
-
40
- // Create a promise that will be resolved when initialization completes
41
- this.initializationPromise = (async (): Promise<void> => {
42
- try {
43
- const translations = await this.fetchTranslations(this.currentLanguage);
44
-
45
- const instance = createInstance({
46
- lng: this.currentLanguage,
47
- resources: {
48
- [this.currentLanguage]: {
49
- translation: translations,
50
- },
51
- },
52
- debug: window.location.hostname === 'localhost',
53
- });
54
-
55
- await instance.init();
56
- this.i18n = instance;
57
- this.initializationState = 'finished';
58
- } catch (error) {
59
- // Reset state on error so it can be retried
60
- this.initializationState = 'not-inited';
61
- this.initializationPromise = null;
62
- throw error;
63
- }
64
- })();
65
-
66
- return this.initializationPromise;
67
- }
68
-
69
- private getTranslationUrl(language: string): string {
70
- // For localhost development, use local- prefix for non-English languages
71
- if (window.location.hostname === 'localhost') {
72
- const filename = language !== 'en' ? `local-${language}` : language;
73
-
74
- return `${window.location.origin}/locales/${filename}.json`;
75
- }
76
-
77
- return `${this.translationUrl}/locales/${language}.json`;
78
- }
79
-
80
- public usePlugin(plugin: ThirdPartyModule): void {
81
- if (!this.i18n) {
82
- throw new Error('Translator is not initialized');
83
- }
84
- this.i18n.use(plugin);
85
- }
86
- /**
87
- * Fetch translations manually from the current domain
88
- * @param language - Language code to fetch
89
- * @returns Promise with translation data
90
- */
91
- private async fetchTranslations(language: string): Promise<Record<string, string>> {
92
- try {
93
- const response = await fetch(this.getTranslationUrl(language));
94
- if (!response.ok) {
95
- throw new Error(`Failed to fetch translations for ${language}`);
96
- }
97
- return (await response.json()) as Record<string, string>;
98
- } catch (error) {
99
- console.warn(`Failed to fetch translations for ${language}:`, error);
100
- if (language === 'en') return {};
101
-
102
- // Fallback to English
103
- return this.fetchTranslations('en').catch((error) => {
104
- console.error('Failed to fetch fallback translations:', error);
105
- return {};
106
- });
107
- }
108
- }
109
-
110
- /**
111
- * Get translation for a key
112
- * @param key - Translation key
113
- * @param options - Translation options
114
- * @returns Translated string
115
- */
116
- t(key: string, options?: TOptions): string {
117
- if (!this.i18n) {
118
- throw new Error('Translator is not initialized');
119
- }
120
- return this.i18n.t(key, options) as string;
121
- }
122
-
123
- /**
124
- * Get current language
125
- */
126
- getCurrentLanguage(): string {
127
- return this.currentLanguage;
128
- }
129
-
130
- /**
131
- * Check if translator is initialized
132
- */
133
- isReady(): boolean {
134
- return this.initializationState === 'finished';
135
- }
136
- }
@@ -1,33 +0,0 @@
1
- export async function getSTTResponse(backendUrl: string, audio: Blob, token: string): Promise<string> {
2
- const formData = new FormData();
3
- formData.append('file', audio);
4
-
5
- return await fetch(`${backendUrl}/voice/stt`, {
6
- method: 'POST',
7
- headers: { Authorization: `Bearer ${token}` },
8
- body: formData,
9
- })
10
- .then((r) => r.json())
11
- .then((r) => {
12
- // console.log("STT response: ", r);
13
- return r.text;
14
- });
15
- }
16
-
17
- export async function getTTSResponse(backendUrl: string, request: TTSRequest, token: string): Promise<Blob> {
18
- return await fetch(`${backendUrl}/voice/tts`, {
19
- method: 'POST',
20
- headers: {
21
- 'Content-Type': 'application/json',
22
- Authorization: `Bearer ${token}`,
23
- },
24
- body: JSON.stringify(request),
25
- }).then((r) => r.blob());
26
- }
27
-
28
- interface TTSRequest {
29
- input: string;
30
- voice: string;
31
- speed: number;
32
- language?: string;
33
- }
@@ -1,382 +0,0 @@
1
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
- export type EventPayload = Record<string, any>;
3
-
4
- /**
5
- * Interface representing a message sent through the EventBus
6
- *
7
- * Debug capabilities:
8
- * - System-wide debugging: Send an event to "global.system.requestDebug"
9
- * Example: `EventBus.emit("yourPluginId", "global.system.requestDebug");`
10
- */
11
- export interface EventBusMessage<T = EventPayload> {
12
- //timestamp of the event
13
- timestamp: string;
14
- //unique ID of the event
15
- eventId: number;
16
- //plugin id or "global" for global events
17
- sender: string;
18
- //the topic of the event consisting of the plugin id, key area and action e.g. "translator.word.triggerTranslation"
19
- topic: string;
20
- //any type of data to be transmitted
21
- data: T;
22
- //indicated if the debug mode is active
23
- debug: boolean;
24
- }
25
-
26
- export type EventHandler<T = EventPayload> = (event: EventBusMessage<T>) => void | Promise<void>;
27
-
28
- interface Listeners<T = EventPayload> {
29
- id: number;
30
- handler: EventHandler<T>;
31
- ignoreSender?: string[];
32
- }
33
-
34
- export interface EventListener {
35
- off: () => void;
36
- }
37
-
38
- export class EventBusHandler {
39
- private listeners: Map<string, Set<Listeners<EventPayload>>> = new Map();
40
- private responseResolvers: Map<number, (value: EventBusMessage<unknown>) => void> = new Map();
41
- private static instance: EventBusHandler | null = null;
42
- private debugEnabled = false;
43
- private evName = '';
44
-
45
- private constructor() {
46
- //private constructor
47
- }
48
-
49
- static getInstance(name?: string) {
50
- if (!EventBusHandler.instance) {
51
- EventBusHandler.instance = new EventBusHandler();
52
-
53
- EventBusHandler.instance.on('global.system.requestDebug', () => {
54
- EventBusHandler.instance!.debugEnabled = true;
55
- console.log(
56
- `[${
57
- EventBusHandler.instance!.evName
58
- }] Debug mode enabled. Make sure debugging messages are enabled in the browser console.`,
59
- );
60
- });
61
- }
62
- if (name && EventBusHandler.instance.evName === '') {
63
- EventBusHandler.instance.evName = name;
64
- }
65
- return EventBusHandler.instance;
66
- }
67
-
68
- private createEvent(sender: string, topic: string, data: EventPayload, eventId?: number): EventBusMessage {
69
- const generatedEventId = eventId || Math.floor(Math.random() * 10000000000);
70
-
71
- return {
72
- eventId: generatedEventId,
73
- timestamp: new Date().toISOString(),
74
- sender,
75
- topic,
76
- data,
77
- debug: this.debugEnabled,
78
- };
79
- }
80
-
81
- /**
82
- * Emits an event to the event bus. Can be a new event or a response to a request.
83
- * @param sender - The sender of the event.
84
- * @param topic - The topic of the event.
85
- * @param data - The data of the event.
86
- * @param eventId - The event id of the event.
87
- *
88
- * The topic format is: **pluginId.area.action**
89
- *
90
- * Example topics:
91
- * - pl1234.card.requestHard
92
- * - pl1234.card.requestNew
93
- * - pl1234.card.requestAll
94
- * - pl1234.card.create
95
- * - pl1234.card.update
96
- * - pl1234.card.delete
97
- * - pl1234.card.triggerBackup
98
- */
99
- public emit<T = EventPayload>(sender: string, topic: string, data?: T, eventId?: number): void {
100
- this.emitInternal(sender, topic, data || {}, eventId);
101
- }
102
-
103
- private emitInternal(
104
- sender: string,
105
- topic: string,
106
- data: EventPayload,
107
- eventId?: number,
108
- skipResponseTrigger = false,
109
- ): void {
110
- if (!this.validateTopic(topic)) {
111
- this.logAndThrowError(false, `Invalid topic: ` + topic);
112
- return;
113
- }
114
-
115
- const event = this.createEvent(sender, topic, data, eventId);
116
-
117
- const handlers = this.getMatchingHandlers(event.topic);
118
- handlers.forEach((handler) => {
119
- if (handler.ignoreSender && handler.ignoreSender.includes(sender)) {
120
- // console.log("ignore event as its in the ignoreSender list", { event, ignoreList: handler.ignoreSender });
121
- return;
122
- }
123
- handler.handler(event);
124
- });
125
- this.logIfDebug(`Emitting event to ` + topic, event);
126
- if (handlers.size === 0) {
127
- this.logAndThrowError(false, `No handlers found for topic: ` + topic);
128
- }
129
-
130
- // If it's a response to a request
131
- if (eventId && this.responseResolvers.has(eventId) && !skipResponseTrigger) {
132
- // console.log("[Rimori] Resolving response to request: " + eventId, event.data);
133
- this.responseResolvers.get(eventId)!(event);
134
- this.responseResolvers.delete(eventId);
135
- }
136
- }
137
-
138
- /**
139
- * Subscribes to an event on the event bus.
140
- * @param topics - The topic of the event.
141
- * @param handler - The handler to be called when the event is emitted.
142
- * @param ignoreSender - The senders to ignore.
143
- * @returns An EventListener object containing an off() method to unsubscribe the listeners.
144
- */
145
- public on<T = EventPayload>(
146
- topics: string | string[],
147
- handler: EventHandler<T>,
148
- ignoreSender: string[] = [],
149
- ): EventListener {
150
- const ids = this.toArray(topics).map((topic) => {
151
- this.logIfDebug(`Subscribing to ` + topic, { ignoreSender });
152
- if (!this.validateTopic(topic)) {
153
- this.logAndThrowError(true, `Invalid topic: ` + topic);
154
- }
155
-
156
- if (!this.listeners.has(topic)) {
157
- this.listeners.set(topic, new Set());
158
- }
159
- const id = Math.floor(Math.random() * 10000000000);
160
-
161
- // To prevent infinite loops and processing the same eventId multiple times
162
- const blackListedEventIds: { eventId: number; sender: string }[] = [];
163
- const eventHandler = (data: EventBusMessage) => {
164
- if (blackListedEventIds.some((item) => item.eventId === data.eventId && item.sender === data.sender)) {
165
- console.log('BLACKLISTED EVENT ID', data.eventId, data);
166
- return;
167
- }
168
- blackListedEventIds.push({
169
- eventId: data.eventId,
170
- sender: data.sender,
171
- });
172
- if (blackListedEventIds.length > 100) {
173
- blackListedEventIds.shift();
174
- }
175
- return (handler as unknown as EventHandler<EventPayload>)(data);
176
- };
177
-
178
- this.listeners.get(topic)!.add({ id, handler: eventHandler, ignoreSender });
179
-
180
- this.logIfDebug(`Subscribed to ` + topic, {
181
- listenerId: id,
182
- ignoreSender,
183
- });
184
-
185
- return btoa(JSON.stringify({ topic, id }));
186
- });
187
-
188
- return {
189
- off: () => this.off(ids),
190
- };
191
- }
192
-
193
- /**
194
- * Subscribes to an event, processes the data and emits a response on the event bus.
195
- * @param sender - The sender of the event.
196
- * @param topic - The topic of the event.
197
- * @param handler - The handler to be called when the event is received. The handler returns the data to be emitted. Can be a static object or a function.
198
- * @returns An EventListener object containing an off() method to unsubscribe the listeners.
199
- */
200
- public respond(
201
- sender: string,
202
- topic: string | string[],
203
- handler: EventPayload | ((data: EventBusMessage) => EventPayload | Promise<EventPayload>),
204
- ): EventListener {
205
- const topics = Array.isArray(topic) ? topic : [topic];
206
- const listeners = topics.map((topic) => {
207
- const blackListedEventIds: number[] = [];
208
- //To allow event communication inside the same plugin the sender needs to be ignored but the events still need to be checked for the same event just reaching the subscriber to prevent infinite loops
209
- const finalIgnoreSender = !topic.startsWith('self.') ? [sender] : [];
210
-
211
- const listener = this.on(
212
- topic,
213
- async (data: EventBusMessage) => {
214
- if (blackListedEventIds.includes(data.eventId)) {
215
- // console.log("BLACKLISTED EVENT ID", data.eventId);
216
- return;
217
- }
218
- blackListedEventIds.push(data.eventId);
219
- if (blackListedEventIds.length > 100) {
220
- blackListedEventIds.shift();
221
- }
222
- const response = typeof handler === 'function' ? await handler(data) : handler;
223
- this.emit(sender, topic, response, data.eventId);
224
- },
225
- finalIgnoreSender,
226
- );
227
-
228
- this.logIfDebug(`Added respond listener ` + sender + ' to topic ' + topic, { listener, sender });
229
- return {
230
- off: () => listener.off(),
231
- };
232
- });
233
- return {
234
- off: () => listeners.forEach((listener) => listener.off()),
235
- };
236
- }
237
-
238
- /**
239
- * Subscribes to an event on the event bus. The handler will be called once and then removed.
240
- * @param topic - The topic of the event.
241
- * @param handler - The handler to be called when the event is emitted.
242
- */
243
- public once<T = EventPayload>(topic: string, handler: EventHandler<T>): void {
244
- if (!this.validateTopic(topic)) {
245
- this.logAndThrowError(false, `Invalid topic: ` + topic);
246
- return;
247
- }
248
-
249
- let listener: EventListener | undefined = undefined;
250
- const wrapper = (event: EventBusMessage<T>) => {
251
- handler(event);
252
- listener?.off();
253
- };
254
- listener = this.on(topic, wrapper);
255
-
256
- this.logIfDebug(`Added once listener ` + topic, { listener, topic });
257
- }
258
-
259
- /**
260
- * Unsubscribes from an event on the event bus.
261
- * @param listenerIds - The ids of the listeners to unsubscribe from.
262
- */
263
- private off(listenerIds: string | string[]): void {
264
- this.toArray(listenerIds).forEach((fullId) => {
265
- const { topic, id } = JSON.parse(atob(fullId));
266
-
267
- const listeners = this.listeners.get(topic) || new Set();
268
-
269
- listeners.forEach((listener) => {
270
- if (listener.id === Number(id)) {
271
- listeners.delete(listener);
272
- this.logIfDebug(`Removed listener ` + fullId, {
273
- topic,
274
- listenerId: id,
275
- });
276
- }
277
- });
278
- });
279
- }
280
-
281
- private toArray(item: string | string[]): string[] {
282
- return Array.isArray(item) ? item : [item];
283
- }
284
-
285
- /**
286
- * Requests data from the event bus.
287
- * @param sender - The sender of the event.
288
- * @param topic - The topic of the event.
289
- * @param data - The data of the event.
290
- * @returns A promise that resolves to the event.
291
- */
292
- public async request<T = EventPayload>(
293
- sender: string,
294
- topic: string,
295
- data?: EventPayload,
296
- ): Promise<EventBusMessage<T>> {
297
- if (!this.validateTopic(topic)) {
298
- this.logAndThrowError(true, `Invalid topic: ` + topic);
299
- }
300
-
301
- const event = this.createEvent(sender, topic, data || {});
302
-
303
- this.logIfDebug(`Requesting data from ` + topic, { event });
304
-
305
- return new Promise<EventBusMessage<T>>((resolve) => {
306
- this.responseResolvers.set(event.eventId, (value: EventBusMessage<unknown>) =>
307
- resolve(value as EventBusMessage<T>),
308
- );
309
- this.emitInternal(sender, topic, data || {}, event.eventId, true);
310
- });
311
- }
312
-
313
- /**
314
- * Gets the matching handlers for an event.
315
- * @param topic - The topic of the event.
316
- * @returns A set of handlers that match the event type.
317
- */
318
- private getMatchingHandlers(topic: string): Set<Listeners<EventPayload>> {
319
- const exact = this.listeners.get(topic) || new Set();
320
-
321
- // Find wildcard matches
322
- const wildcard = [...this.listeners.entries()]
323
- .filter(([key]) => key.endsWith('*') && topic.startsWith(key.slice(0, -1)))
324
- .flatMap(([_, handlers]) => [...handlers]);
325
- return new Set([...exact, ...wildcard]);
326
- }
327
-
328
- /**
329
- * Validates the topic of an event.
330
- * @param topic - The topic of the event.
331
- * @returns True if the topic is valid, false otherwise.
332
- */
333
- private validateTopic(topic: string): boolean {
334
- // Split event type into parts
335
- const parts = topic.split('.');
336
- const [plugin, area, action] = parts;
337
-
338
- if (parts.length !== 3) {
339
- if (parts.length === 1 && plugin === '*') {
340
- return true;
341
- }
342
- if (parts.length === 2 && plugin !== '*' && area === '*') {
343
- return true;
344
- }
345
- this.logAndThrowError(false, `Event type must have 3 parts separated by dots. Received: ` + topic);
346
- return false;
347
- }
348
-
349
- if (action === '*') {
350
- return true;
351
- }
352
-
353
- // Validate action part
354
- const validActions = ['request', 'create', 'update', 'delete', 'trigger'];
355
-
356
- if (validActions.some((a) => action.startsWith(a))) {
357
- return true;
358
- }
359
-
360
- this.logAndThrowError(
361
- false,
362
- `Invalid event topic name. The action: ` + action + '. Must be or start with one of: ' + validActions.join(', '),
363
- );
364
- return false;
365
- }
366
-
367
- private logIfDebug(...args: (string | EventPayload)[]) {
368
- if (this.debugEnabled) {
369
- console.debug(`[${this.evName}] ` + args[0], ...args.slice(1));
370
- }
371
- }
372
-
373
- private logAndThrowError(throwError: boolean, ...args: (string | EventPayload)[]) {
374
- const message = `[${this.evName}] ` + args[0];
375
- console.error(message, ...args.slice(1));
376
- if (throwError) {
377
- throw new Error(message);
378
- }
379
- }
380
- }
381
-
382
- export const EventBus = EventBusHandler.getInstance();