@rimori/client 1.0.3 → 1.0.4

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 (133) hide show
  1. package/README.md +51 -0
  2. package/dist/components/CRUDModal.js +0 -1
  3. package/dist/components/ai/Assistant.d.ts +9 -0
  4. package/dist/components/ai/Assistant.js +59 -0
  5. package/dist/components/ai/Avatar.d.ts +11 -0
  6. package/dist/components/ai/Avatar.js +39 -0
  7. package/dist/components/ai/EmbeddedAssistent/AudioInputField.d.ts +7 -0
  8. package/dist/components/ai/EmbeddedAssistent/AudioInputField.js +38 -0
  9. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.d.ts +7 -0
  10. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +59 -0
  11. package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.d.ts +19 -0
  12. package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.js +86 -0
  13. package/dist/components/ai/EmbeddedAssistent/TTS/Player.d.ts +25 -0
  14. package/dist/components/ai/EmbeddedAssistent/TTS/Player.js +180 -0
  15. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.d.ts +7 -0
  16. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +45 -0
  17. package/dist/components/ai/utils.d.ts +6 -0
  18. package/dist/components/ai/utils.js +14 -0
  19. package/dist/components/audio/Playbutton.js +4 -5
  20. package/dist/components/avatar/Assistant.d.ts +9 -0
  21. package/dist/components/avatar/Assistant.js +59 -0
  22. package/dist/components/avatar/Avatar.d.ts +12 -0
  23. package/dist/components/avatar/Avatar.js +42 -0
  24. package/dist/components/avatar/EmbeddedAssistent/AudioInputField.d.ts +7 -0
  25. package/dist/components/avatar/EmbeddedAssistent/AudioInputField.js +38 -0
  26. package/dist/components/avatar/EmbeddedAssistent/CircleAudioAvatar.d.ts +7 -0
  27. package/dist/components/avatar/EmbeddedAssistent/CircleAudioAvatar.js +59 -0
  28. package/dist/components/avatar/EmbeddedAssistent/TTS/MessageSender.d.ts +19 -0
  29. package/dist/components/avatar/EmbeddedAssistent/TTS/MessageSender.js +84 -0
  30. package/dist/components/avatar/EmbeddedAssistent/TTS/Player.d.ts +25 -0
  31. package/dist/components/avatar/EmbeddedAssistent/TTS/Player.js +180 -0
  32. package/dist/components/avatar/EmbeddedAssistent/VoiceRecoder.d.ts +7 -0
  33. package/dist/components/avatar/EmbeddedAssistent/VoiceRecoder.js +45 -0
  34. package/dist/components/avatar/utils.d.ts +6 -0
  35. package/dist/components/avatar/utils.js +14 -0
  36. package/dist/components.d.ts +9 -0
  37. package/dist/components.js +10 -0
  38. package/dist/controller/AIController.d.ts +4 -3
  39. package/dist/controller/AIController.js +32 -8
  40. package/dist/controller/ObjectController.d.ts +2 -2
  41. package/dist/controller/ObjectController.js +4 -5
  42. package/dist/controller/SettingsController.d.ts +2 -1
  43. package/dist/controller/SettingsController.js +9 -0
  44. package/dist/controller/SharedContentController.js +6 -6
  45. package/dist/core.d.ts +9 -0
  46. package/dist/core.js +10 -0
  47. package/dist/hooks/UseChatHook.js +2 -2
  48. package/dist/index.d.ts +3 -2
  49. package/dist/index.js +4 -2
  50. package/dist/plugin/PluginController.d.ts +4 -12
  51. package/dist/plugin/PluginController.js +43 -70
  52. package/dist/plugin/RimoriClient.d.ts +85 -32
  53. package/dist/plugin/RimoriClient.js +98 -77
  54. package/dist/plugin/fromRimori/EventBus.d.ts +98 -0
  55. package/dist/plugin/fromRimori/EventBus.js +240 -0
  56. package/dist/providers/PluginProvider.d.ts +1 -0
  57. package/dist/providers/PluginProvider.js +10 -12
  58. package/dist/worker/WorkerSetup.d.ts +6 -0
  59. package/dist/worker/WorkerSetup.js +79 -0
  60. package/package.json +16 -3
  61. package/src/components/CRUDModal.tsx +1 -3
  62. package/src/components/ai/Assistant.tsx +96 -0
  63. package/src/components/ai/Avatar.tsx +61 -0
  64. package/src/components/ai/EmbeddedAssistent/AudioInputField.tsx +64 -0
  65. package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +75 -0
  66. package/src/components/ai/EmbeddedAssistent/TTS/MessageSender.ts +91 -0
  67. package/src/components/ai/EmbeddedAssistent/TTS/Player.ts +192 -0
  68. package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +56 -0
  69. package/src/components/ai/utils.ts +23 -0
  70. package/src/components/audio/Playbutton.tsx +4 -5
  71. package/src/components.ts +10 -0
  72. package/src/controller/AIController.ts +84 -60
  73. package/src/controller/ObjectController.ts +4 -6
  74. package/src/controller/SettingsController.ts +9 -1
  75. package/src/controller/SharedContentController.ts +6 -6
  76. package/src/core.ts +10 -0
  77. package/src/hooks/UseChatHook.ts +2 -2
  78. package/src/index.ts +4 -2
  79. package/src/plugin/PluginController.ts +46 -76
  80. package/src/plugin/RimoriClient.ts +147 -85
  81. package/src/plugin/fromRimori/EventBus.ts +301 -0
  82. package/src/plugin/fromRimori/readme.md +2 -0
  83. package/src/providers/PluginProvider.tsx +12 -14
  84. package/src/worker/WorkerSetup.ts +80 -0
  85. package/dist/CRUDModal.d.ts +0 -16
  86. package/dist/CRUDModal.js +0 -31
  87. package/dist/MarkdownEditor.d.ts +0 -8
  88. package/dist/MarkdownEditor.js +0 -46
  89. package/dist/audio/Playbutton.d.ts +0 -14
  90. package/dist/audio/Playbutton.js +0 -73
  91. package/dist/components/hooks/UseChatHook.d.ts +0 -15
  92. package/dist/components/hooks/UseChatHook.js +0 -21
  93. package/dist/controller/PluginController.d.ts +0 -14
  94. package/dist/controller/PluginController.js +0 -30
  95. package/dist/plugin/AIController copy.d.ts +0 -22
  96. package/dist/plugin/AIController copy.js +0 -68
  97. package/dist/plugin/AIController.d.ts +0 -22
  98. package/dist/plugin/AIController.js +0 -68
  99. package/dist/plugin/ObjectController.d.ts +0 -34
  100. package/dist/plugin/ObjectController.js +0 -77
  101. package/dist/plugin/SettingController.d.ts +0 -13
  102. package/dist/plugin/SettingController.js +0 -55
  103. package/dist/plugin/VoiceController.d.ts +0 -2
  104. package/dist/plugin/VoiceController.js +0 -27
  105. package/dist/providers/EventEmitter.d.ts +0 -11
  106. package/dist/providers/EventEmitter.js +0 -41
  107. package/dist/providers/EventEmitterContext.d.ts +0 -6
  108. package/dist/providers/EventEmitterContext.js +0 -19
  109. package/dist/utils/DifficultyConverter.d.ts +0 -3
  110. package/dist/utils/DifficultyConverter.js +0 -7
  111. package/dist/utils/constants.d.ts +0 -4
  112. package/dist/utils/constants.js +0 -12
  113. package/dist/utils/plugin/Client.d.ts +0 -72
  114. package/dist/utils/plugin/Client.js +0 -118
  115. package/dist/utils/plugin/PluginController.d.ts +0 -36
  116. package/dist/utils/plugin/PluginController.js +0 -119
  117. package/dist/utils/plugin/PluginUtils.d.ts +0 -2
  118. package/dist/utils/plugin/PluginUtils.js +0 -23
  119. package/dist/utils/plugin/RimoriClient.d.ts +0 -72
  120. package/dist/utils/plugin/RimoriClient.js +0 -118
  121. package/dist/utils/plugin/ThemeSetter.d.ts +0 -1
  122. package/dist/utils/plugin/ThemeSetter.js +0 -13
  123. package/dist/utils/plugin/WhereClauseBuilder.d.ts +0 -24
  124. package/dist/utils/plugin/WhereClauseBuilder.js +0 -79
  125. package/dist/utils/plugin/providers/EventEmitter.d.ts +0 -11
  126. package/dist/utils/plugin/providers/EventEmitter.js +0 -41
  127. package/dist/utils/plugin/providers/EventEmitterContext.d.ts +0 -6
  128. package/dist/utils/plugin/providers/EventEmitterContext.js +0 -19
  129. package/dist/utils/plugin/providers/PluginProvider.d.ts +0 -8
  130. package/dist/utils/plugin/providers/PluginProvider.js +0 -49
  131. package/src/providers/EventEmitter.ts +0 -48
  132. package/src/providers/EventEmitterContext.tsx +0 -27
  133. package/src/utils/constants.ts +0 -18
@@ -0,0 +1,301 @@
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 class EventBusHandler {
35
+ private listeners: Map<string, Set<Listeners<EventPayload>>> = new Map();
36
+ private responseResolvers: Map<number, (value: EventBusMessage<unknown>) => void> = new Map();
37
+ private static instance: EventBusHandler | null = null;
38
+ private debugEnabled: boolean = false;
39
+ private evName: string = "";
40
+
41
+ private constructor() {
42
+ //private constructor
43
+ }
44
+
45
+ static getInstance(name?: string) {
46
+ if (!EventBusHandler.instance) {
47
+ EventBusHandler.instance = new EventBusHandler();
48
+
49
+ EventBusHandler.instance.on("global.system.requestDebug", () => {
50
+ EventBusHandler.instance!.debugEnabled = true;
51
+ console.log(`[${EventBusHandler.instance!.evName}] Debug mode enabled. Make sure debugging messages are enabled in the browser console.`);
52
+ });
53
+ }
54
+ if (name && EventBusHandler.instance.evName === "") {
55
+ EventBusHandler.instance.evName = name;
56
+ }
57
+ return EventBusHandler.instance;
58
+ }
59
+
60
+ private createEvent(sender: string, topic: string, data: EventPayload, eventId?: number): EventBusMessage {
61
+ const generatedEventId = eventId || Math.floor(Math.random() * 10000000000);
62
+
63
+ return {
64
+ eventId: generatedEventId,
65
+ timestamp: new Date().toISOString(),
66
+ sender,
67
+ topic,
68
+ data,
69
+ debug: this.debugEnabled,
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Emits an event to the event bus. Can be a new event or a response to a request.
75
+ * @param sender - The sender of the event.
76
+ * @param topic - The topic of the event.
77
+ * @param data - The data of the event.
78
+ * @param eventId - The event id of the event.
79
+ *
80
+ * The topic format is: **pluginId.area.action**
81
+ *
82
+ * Example topics:
83
+ * - pl1234.card.requestHard
84
+ * - pl1234.card.requestNew
85
+ * - pl1234.card.requestAll
86
+ * - pl1234.card.create
87
+ * - pl1234.card.update
88
+ * - pl1234.card.delete
89
+ * - pl1234.card.triggerBackup
90
+ */
91
+ public emit<T = EventPayload>(sender: string, topic: string, data?: T, eventId?: number): void {
92
+ this.emitInternal(sender, topic, data || {}, eventId);
93
+ }
94
+
95
+ private emitInternal(sender: string, topic: string, data: EventPayload, eventId?: number, skipResponseTrigger = false): void {
96
+ if (!this.validateTopic(topic)) {
97
+ this.logAndThrowError(false, `Invalid topic: ` + topic);
98
+ return;
99
+ }
100
+
101
+ const event = this.createEvent(sender, topic, data, eventId);
102
+
103
+ const handlers = this.getMatchingHandlers(event.topic);
104
+ handlers.forEach(handler => {
105
+ if (handler.ignoreSender && handler.ignoreSender.includes(sender)) {
106
+ // console.log("ignore event as its in the ignoreSender list", { event, ignoreList: handler.ignoreSender });
107
+ return;
108
+ }
109
+ handler.handler(event);
110
+ });
111
+ this.logIfDebug(`Emitting event to ` + topic, event);
112
+ if (handlers.size === 0) {
113
+ this.logAndThrowError(false, `No handlers found for topic: ` + topic);
114
+ }
115
+
116
+ // If it's a response to a request
117
+ if (eventId && this.responseResolvers.has(eventId) && !skipResponseTrigger) {
118
+ // console.log("[Rimori] Resolving response to request: " + eventId, event.data);
119
+ this.responseResolvers.get(eventId)!(event);
120
+ this.responseResolvers.delete(eventId);
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Subscribes to an event on the event bus.
126
+ * @param topics - The topic of the event.
127
+ * @param handler - The handler to be called when the event is emitted.
128
+ * @param ignoreSender - The senders to ignore.
129
+ * @returns The ids of the listeners.
130
+ */
131
+ public on<T = EventPayload>(topics: string | string[], handler: EventHandler<T>, ignoreSender: string[] = []): string[] {
132
+ return this.toArray(topics).map(topic => {
133
+ if (!this.validateTopic(topic)) {
134
+ this.logAndThrowError(true, `Invalid topic: ` + topic);
135
+ }
136
+
137
+ if (!this.listeners.has(topic)) {
138
+ this.listeners.set(topic, new Set());
139
+ }
140
+ const id = Math.floor(Math.random() * 10000000000);
141
+
142
+ // Type assertion to handle the generic type mismatch
143
+ const eventHandler = handler as unknown as EventHandler<EventPayload>;
144
+ this.listeners.get(topic)!.add({ id, handler: eventHandler, ignoreSender });
145
+
146
+ this.logIfDebug(`Subscribed to ` + topic, { listenerId: id, ignoreSender });
147
+
148
+ return btoa(JSON.stringify({ topic, id }));
149
+ });
150
+ }
151
+
152
+ /**
153
+ * Subscribes to an event, processes the data and emits a response on the event bus.
154
+ * @param sender - The sender of the event.
155
+ * @param topic - The topic of the event.
156
+ * @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.
157
+ * @returns The ids of the listeners.
158
+ */
159
+ public respond(sender: string, topic: string, handler: EventPayload | ((data: EventBusMessage) => EventPayload | Promise<EventPayload>)): string[] {
160
+ const ids = this.on(topic, async (data: EventBusMessage) => {
161
+ const response = typeof handler === "function" ? await handler(data) : handler;
162
+ this.emit(sender, topic, response, data.eventId);
163
+ }, [sender]);
164
+
165
+ this.logIfDebug(`Added respond listener ` + sender + " to topic " + topic, { listenerIds: ids, sender });
166
+ return ids;
167
+ }
168
+
169
+ /**
170
+ * Subscribes to an event on the event bus. The handler will be called once and then removed.
171
+ * @param topic - The topic of the event.
172
+ * @param handler - The handler to be called when the event is emitted.
173
+ */
174
+ public once<T = EventPayload>(topic: string, handler: EventHandler<T>): void {
175
+ if (!this.validateTopic(topic)) {
176
+ this.logAndThrowError(false, `Invalid topic: ` + topic);
177
+ return;
178
+ }
179
+
180
+ let ids: string[] = [];
181
+ const wrapper = (event: EventBusMessage<T>) => {
182
+ handler(event);
183
+ this.off(ids);
184
+ };
185
+ ids = this.on(topic, wrapper);
186
+
187
+ this.logIfDebug(`Added once listener ` + topic, { listenerIds: ids, topic });
188
+ }
189
+
190
+ /**
191
+ * Unsubscribes from an event on the event bus.
192
+ * @param listenerIds - The ids of the listeners to unsubscribe from.
193
+ */
194
+ public off(listenerIds: string | string[]): void {
195
+ this.toArray(listenerIds).forEach(fullId => {
196
+ const { topic, id } = JSON.parse(atob(fullId));
197
+
198
+ const listeners = this.listeners.get(topic) || new Set();
199
+
200
+ listeners.forEach(listener => {
201
+ if (listener.id === Number(id)) {
202
+ listeners.delete(listener);
203
+ this.logIfDebug(`Removed listener ` + fullId, { topic, listenerId: id });
204
+ }
205
+ });
206
+ });
207
+ }
208
+
209
+ private toArray(item: string | string[]): string[] {
210
+ return Array.isArray(item) ? item : [item];
211
+ }
212
+
213
+ /**
214
+ * Requests data from the event bus.
215
+ * @param sender - The sender of the event.
216
+ * @param topic - The topic of the event.
217
+ * @param data - The data of the event.
218
+ * @returns A promise that resolves to the event.
219
+ */
220
+ public async request<T = EventPayload>(sender: string, topic: string, data?: EventPayload): Promise<EventBusMessage<T>> {
221
+ if (!this.validateTopic(topic)) {
222
+ this.logAndThrowError(true, `Invalid topic: ` + topic);
223
+ }
224
+
225
+ const event = this.createEvent(sender, topic, data || {});
226
+
227
+ this.logIfDebug(`Requesting data from ` + topic, { event });
228
+
229
+ return new Promise<EventBusMessage<T>>(resolve => {
230
+ this.responseResolvers.set(event.eventId, (value: EventBusMessage<unknown>) => resolve(value as EventBusMessage<T>));
231
+ this.emitInternal(sender, topic, data || {}, event.eventId, true);
232
+ });
233
+ }
234
+
235
+ /**
236
+ * Gets the matching handlers for an event.
237
+ * @param topic - The topic of the event.
238
+ * @returns A set of handlers that match the event type.
239
+ */
240
+ private getMatchingHandlers(topic: string): Set<Listeners<EventPayload>> {
241
+ const exact = this.listeners.get(topic) || new Set();
242
+
243
+ // Find wildcard matches
244
+ const wildcard = [...this.listeners.entries()]
245
+ .filter(([key]) => key.endsWith("*") && topic.startsWith(key.slice(0, -1)))
246
+ .flatMap(([_, handlers]) => [...handlers]);
247
+ return new Set([...exact, ...wildcard]);
248
+ }
249
+
250
+ /**
251
+ * Validates the topic of an event.
252
+ * @param topic - The topic of the event.
253
+ * @returns True if the topic is valid, false otherwise.
254
+ */
255
+ private validateTopic(topic: string): boolean {
256
+ // Split event type into parts
257
+ const parts = topic.split(".");
258
+ const [plugin, area, action] = parts;
259
+
260
+ if (parts.length !== 3) {
261
+ if (parts.length === 1 && plugin === "*") {
262
+ return true;
263
+ }
264
+ if (parts.length === 2 && plugin !== "*" && area === "*") {
265
+ return true;
266
+ }
267
+ this.logAndThrowError(false, `Event type must have 3 parts separated by dots. Received: ` + topic);
268
+ return false;
269
+ }
270
+
271
+ if (action === "*") {
272
+ return true;
273
+ }
274
+
275
+ // Validate action part
276
+ const validActions = ["request", "create", "update", "delete", "trigger"];
277
+
278
+ if (validActions.some(a => action.startsWith(a))) {
279
+ return true;
280
+ }
281
+
282
+ this.logAndThrowError(false, `Invalid event topic name. The action: ` + action + ". Must be or start with one of: " + validActions.join(", "));
283
+ return false;
284
+ }
285
+
286
+ private logIfDebug(...args: (string | EventPayload)[]) {
287
+ if (this.debugEnabled) {
288
+ console.debug(`[${this.evName}] ` + args[0], ...args.slice(1));
289
+ }
290
+ }
291
+
292
+ private logAndThrowError(throwError: boolean, ...args: (string | EventPayload)[]) {
293
+ const message = `[${this.evName}] ` + args[0];
294
+ console.error(message, ...args.slice(1));
295
+ if (throwError) {
296
+ throw new Error(message);
297
+ }
298
+ }
299
+ }
300
+
301
+ export const EventBus = EventBusHandler.getInstance();
@@ -0,0 +1,2 @@
1
+ Files inside this folder are copied from Rimori and should not be changed.
2
+ If change is needed adapt it in Rimori and copy the file then over.
@@ -1,16 +1,18 @@
1
1
  import React, { createContext, useContext, ReactNode, useEffect, useState } from 'react';
2
2
  import { PluginController } from '../plugin/PluginController';
3
3
  import { RimoriClient } from '../plugin/RimoriClient';
4
- import { UserSettings } from '../controller/SettingsController';
4
+ import { EventBusHandler } from '../plugin/fromRimori/EventBus';
5
5
 
6
6
  interface PluginProviderProps {
7
7
  children: ReactNode;
8
+ pluginId: string;
8
9
  }
9
10
 
10
- const PluginContext = createContext<RimoriClient | null>(null);
11
+ EventBusHandler.getInstance("Plugin EventBus");
11
12
 
13
+ const PluginContext = createContext<RimoriClient | null>(null);
12
14
 
13
- export const PluginProvider: React.FC<PluginProviderProps> = ({ children }) => {
15
+ export const PluginProvider: React.FC<PluginProviderProps> = ({ children, pluginId }) => {
14
16
  const [plugin, setPlugin] = useState<RimoriClient | null>(null);
15
17
  const [contextMenuOnSelect, setContextMenuOnTextSelection] = useState(false);
16
18
 
@@ -22,21 +24,17 @@ export const PluginProvider: React.FC<PluginProviderProps> = ({ children }) => {
22
24
  if (lastHash !== window.location.hash) {
23
25
  lastHash = window.location.hash;
24
26
  console.log('url changed:', lastHash);
25
- plugin?.emit('urlChange', window.location.hash);
27
+ plugin?.event.emit('session.triggerUrlChange', window.location.hash);
26
28
  }
27
29
  }, 100);
28
- PluginController.getInstance().then(setPlugin);
30
+ PluginController.getInstance(pluginId).then(setPlugin);
29
31
  }, []);
30
32
 
31
33
  //check if context menu opens on text selection
32
34
  useEffect(() => {
33
35
  if (!plugin) return;
34
- plugin.getSettings<UserSettings>({
35
- languageLevel: "A1",
36
- motherTongue: "English",
37
- contextMenuOnSelect: false,
38
- }, "user").then((settings) => {
39
- setContextMenuOnTextSelection(settings.contextMenuOnSelect);
36
+ plugin.plugin.getUserInfo().then((userInfo) => {
37
+ setContextMenuOnTextSelection(userInfo.contextMenuOnSelect);
40
38
  }).catch(error => {
41
39
  console.error('Error fetching settings:', error);
42
40
  });
@@ -45,7 +43,7 @@ export const PluginProvider: React.FC<PluginProviderProps> = ({ children }) => {
45
43
  //detect page height change
46
44
  useEffect(() => {
47
45
  const body = document.body;
48
- const handleResize = () => plugin?.emit('heightAdjustment', body.clientHeight);
46
+ const handleResize = () => plugin?.event.emit('session.triggerHeightChange', body.clientHeight);
49
47
  body.addEventListener('resize', handleResize);
50
48
  handleResize();
51
49
  return () => body.removeEventListener('resize', handleResize);
@@ -68,7 +66,7 @@ export const PluginProvider: React.FC<PluginProviderProps> = ({ children }) => {
68
66
  if (selection) {
69
67
  e.preventDefault();
70
68
  // console.log('context menu handled', selection);
71
- plugin?.emit('contextMenu', { text: selection, x: e.clientX, y: e.clientY, open: true });
69
+ plugin?.event.emit('global.contextMenu.trigger', { text: selection, x: e.clientX, y: e.clientY, open: true });
72
70
  }
73
71
  };
74
72
 
@@ -77,7 +75,7 @@ export const PluginProvider: React.FC<PluginProviderProps> = ({ children }) => {
77
75
  const selection = window.getSelection()?.toString().trim();
78
76
  const open = !!selection && isSelecting;
79
77
  // console.log('Selection change, contextMenuOnSelect:', contextMenuOnSelect);
80
- plugin?.emit('contextMenu', { text: selection, x: lastMouseX, y: lastMouseY, open });
78
+ plugin?.event.emit('global.contextMenu.trigger', { text: selection, x: lastMouseX, y: lastMouseY, open });
81
79
  // }
82
80
  };
83
81
  const handleMouseUpDown = (e: MouseEvent) => {
@@ -0,0 +1,80 @@
1
+ import { RimoriClient } from "../plugin/RimoriClient";
2
+ import { PluginController } from "../plugin/PluginController";
3
+ import { EventBus, EventBusHandler, EventBusMessage } from "../plugin/fromRimori/EventBus";
4
+
5
+ let controller: RimoriClient | null = null;
6
+ const listeners: ((event: { data: { event: EventBusMessage, secret: string } }) => void)[] = [];
7
+ let debugEnabled = false;
8
+
9
+ /**
10
+ * Sets up the web worker for the plugin to be able receive and send messages to Rimori.
11
+ * @param init - The function containing the subscription logic.
12
+ */
13
+ export function setupWorker(init: (controller: RimoriClient) => void | Promise<void>) {
14
+ // Mock of the window object for the worker context to be able to use the PluginController.
15
+ const mockWindow = {
16
+ location: { search: '?secret=123' },
17
+ parent: {
18
+ postMessage: (message: { event: EventBusMessage }) => {
19
+ message.event.sender = "worker." + message.event.sender;
20
+ checkDebugMode(message.event);
21
+ logIfDebug('[Worker] sending event to Rimori', message.event);
22
+ self.postMessage(message)
23
+ }
24
+ },
25
+ addEventListener: (_: string, listener: any) => {
26
+ listeners.push(listener);
27
+ },
28
+ APP_CONFIG: {
29
+ SUPABASE_URL: 'NOT_SET',
30
+ SUPABASE_ANON_KEY: 'NOT_SET',
31
+ },
32
+ };
33
+
34
+ // Assign the mock to globalThis.
35
+ Object.assign(globalThis, { window: mockWindow });
36
+
37
+ EventBusHandler.getInstance("Worker EventBus");
38
+
39
+ // Handle init message from Rimori.
40
+ self.onmessage = async (response: MessageEvent) => {
41
+ checkDebugMode(response.data);
42
+ logIfDebug('[Worker] message received', response.data);
43
+
44
+ const event = response.data as EventBusMessage;
45
+
46
+ if (event.topic === 'global.worker.requestInit') {
47
+ if (!controller) {
48
+ mockWindow.APP_CONFIG.SUPABASE_URL = event.data.supabaseUrl;
49
+ mockWindow.APP_CONFIG.SUPABASE_ANON_KEY = event.data.supabaseAnonKey;
50
+ controller = await PluginController.getInstance(event.data.pluginId);
51
+ logIfDebug('[Worker] Worker initialized.');
52
+ await init(controller);
53
+ logIfDebug('[Worker] Plugin listeners initialized.');
54
+ }
55
+ const initEvent: EventBusMessage = {
56
+ timestamp: new Date().toISOString(),
57
+ eventId: event.eventId,
58
+ sender: "worker." + event.sender,
59
+ topic: 'global.worker.requestInit',
60
+ data: { success: true },
61
+ debug: debugEnabled
62
+ };
63
+ return self.postMessage({ secret: "123", event: initEvent });
64
+ }
65
+ listeners.forEach(listener => listener({ data: { event: response.data, secret: "123" } }));
66
+ };
67
+ }
68
+
69
+ function checkDebugMode(event: EventBusMessage) {
70
+ if (event.topic === 'global.system.requestDebug' || event.debug) {
71
+ debugEnabled = true;
72
+ EventBus.emit("worker", "global.system.requestDebug");
73
+ }
74
+ }
75
+
76
+ function logIfDebug(...args: any[]) {
77
+ if (debugEnabled) {
78
+ console.debug('[Worker] ' + args[0], ...args.slice(1));
79
+ }
80
+ }
@@ -1,16 +0,0 @@
1
- interface Props {
2
- title: string;
3
- show?: boolean;
4
- className?: string;
5
- closeAble?: boolean;
6
- children: React.ReactNode;
7
- actionbuttons: ActionButton[];
8
- buttonText?: string | React.ReactNode;
9
- }
10
- interface ActionButton {
11
- text: string;
12
- onClick: () => void;
13
- closeModal?: boolean;
14
- }
15
- export declare function CRUDModal({ actionbuttons, children, title, buttonText, className, closeAble, show }: Props): import("react/jsx-runtime").JSX.Element;
16
- export {};
package/dist/CRUDModal.js DELETED
@@ -1,31 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useEffect, useState, useRef } from "react";
4
- export function CRUDModal({ actionbuttons, children, title, buttonText, className, closeAble = true, show = false }) {
5
- const [openModal, setOpenModal] = useState(show);
6
- const dialogRef = useRef(null);
7
- useEffect(() => {
8
- var _a, _b;
9
- if (show) {
10
- (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.showModal();
11
- }
12
- else {
13
- (_b = dialogRef.current) === null || _b === void 0 ? void 0 : _b.close();
14
- }
15
- setOpenModal(show);
16
- }, [show]);
17
- const handleClose = () => {
18
- var _a;
19
- setOpenModal(false);
20
- (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.close();
21
- };
22
- return (_jsxs(_Fragment, { children: [!!buttonText && _jsx("button", { className: className, onClick: () => {
23
- var _a;
24
- setOpenModal(true);
25
- (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.showModal();
26
- }, children: buttonText }), _jsxs("dialog", { ref: dialogRef, className: "bg-gray-400 rounded-lg font-normal", onClose: handleClose, children: [_jsxs("div", { className: "bg-gray-500 text-xl flex flex-row justify-between p-3 items-start font-bold", children: [_jsx("h2", { children: title }), closeAble && _jsx("button", { onClick: handleClose, children: "\u00D7" })] }), _jsx("div", { className: "modal-body p-2", children: children }), _jsx("div", { className: "modal-footer px-2 py-2 flex flex-row gap-2 border-t-2", children: actionbuttons.map(({ onClick, text, closeModal = true }, index) => (_jsx("button", { className: " bg-blue-500 hover:bg-blue-600 dark:border-gray-900 rounded-md py-2 px-4 dark:text-white font-bold", onClick: () => {
27
- if (closeModal)
28
- handleClose();
29
- onClick();
30
- }, children: text }, index))) })] })] }));
31
- }
@@ -1,8 +0,0 @@
1
- interface Props {
2
- content?: string;
3
- editable: boolean;
4
- className?: string;
5
- onUpdate?: (content: string) => void;
6
- }
7
- export declare const MarkdownEditor: (props: Props) => import("react/jsx-runtime").JSX.Element;
8
- export {};
@@ -1,46 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Markdown } from 'tiptap-markdown';
3
- import StarterKit from "@tiptap/starter-kit";
4
- import { PiCodeBlock } from "react-icons/pi";
5
- import { TbBlockquote } from "react-icons/tb";
6
- import { GoListOrdered } from "react-icons/go";
7
- import { AiOutlineUnorderedList } from "react-icons/ai";
8
- import { EditorProvider, useCurrentEditor } from "@tiptap/react";
9
- import { LuHeading1, LuHeading2, LuHeading3 } from "react-icons/lu";
10
- import { FaBold, FaCode, FaItalic, FaParagraph, FaStrikethrough } from "react-icons/fa";
11
- const EditorButton = ({ action, isActive, label, disabled }) => {
12
- const { editor } = useCurrentEditor();
13
- if (!editor) {
14
- return null;
15
- }
16
- if (action.includes("heading")) {
17
- const level = parseInt(action[action.length - 1]);
18
- return (_jsx("button", { onClick: () => editor.chain().focus().toggleHeading({ level: level }).run(), className: `pl-2 ${isActive ? "is-active" : ""}`, children: label }));
19
- }
20
- return (_jsx("button", { onClick: () => editor.chain().focus()[action]().run(), disabled: disabled ? !editor.can().chain().focus()[action]().run() : false, className: `pl-2 ${isActive ? "is-active" : ""}`, children: label }));
21
- };
22
- const MenuBar = () => {
23
- const { editor } = useCurrentEditor();
24
- if (!editor) {
25
- return null;
26
- }
27
- return (_jsxs("div", { className: "bg-gray-400 dark:bg-gray-800 dark:text-white text-lg flex flex-row flex-wrap items-center p-1", children: [_jsx(EditorButton, { action: "toggleBold", isActive: editor.isActive("bold"), label: _jsx(FaBold, {}), disabled: true }), _jsx(EditorButton, { action: "toggleItalic", isActive: editor.isActive("italic"), label: _jsx(FaItalic, {}), disabled: true }), _jsx(EditorButton, { action: "toggleStrike", isActive: editor.isActive("strike"), label: _jsx(FaStrikethrough, {}), disabled: true }), _jsx(EditorButton, { action: "toggleCode", isActive: editor.isActive("code"), label: _jsx(FaCode, {}), disabled: true }), _jsx(EditorButton, { action: "setParagraph", isActive: editor.isActive("paragraph"), label: _jsx(FaParagraph, {}) }), _jsx(EditorButton, { action: 'setHeading1', isActive: editor.isActive("heading", { level: 1 }), label: _jsx(LuHeading1, { size: "24px" }) }), _jsx(EditorButton, { action: 'setHeading2', isActive: editor.isActive("heading", { level: 2 }), label: _jsx(LuHeading2, { size: "24px" }) }), _jsx(EditorButton, { action: 'setHeading3', isActive: editor.isActive("heading", { level: 3 }), label: _jsx(LuHeading3, { size: "24px" }) }), _jsx(EditorButton, { action: "toggleBulletList", isActive: editor.isActive("bulletList"), label: _jsx(AiOutlineUnorderedList, { size: "24px" }) }), _jsx(EditorButton, { action: "toggleOrderedList", isActive: editor.isActive("orderedList"), label: _jsx(GoListOrdered, { size: "24px" }) }), _jsx(EditorButton, { action: "toggleCodeBlock", isActive: editor.isActive("codeBlock"), label: _jsx(PiCodeBlock, { size: "24px" }) }), _jsx(EditorButton, { action: "toggleBlockquote", isActive: editor.isActive("blockquote"), label: _jsx(TbBlockquote, { size: "24px" }) })] }));
28
- };
29
- const extensions = [
30
- StarterKit.configure({
31
- bulletList: {
32
- keepMarks: true,
33
- keepAttributes: false,
34
- },
35
- orderedList: {
36
- keepMarks: true,
37
- keepAttributes: false,
38
- },
39
- }),
40
- Markdown,
41
- ];
42
- export const MarkdownEditor = (props) => {
43
- return (_jsx("div", { className: "text-md border border-gray-800 overflow-hidden " + props.className, style: { borderWidth: props.editable ? 1 : 0 }, children: _jsx(EditorProvider, { slotBefore: props.editable ? _jsx(MenuBar, {}) : null, extensions: extensions, content: props.content, editable: props.editable, onUpdate: (e) => {
44
- props.onUpdate && props.onUpdate(e.editor.storage.markdown.getMarkdown());
45
- } }, (props.editable ? "editable" : "readonly") + props.content) }));
46
- };
@@ -1,14 +0,0 @@
1
- import React from 'react';
2
- type AudioPlayerProps = {
3
- text: string;
4
- voice?: string;
5
- language?: string;
6
- playOnMount?: boolean;
7
- initialSpeed?: number;
8
- enableSpeedAdjustment?: boolean;
9
- playListenerEvent?: string;
10
- };
11
- export declare const AudioPlayOptions: number[];
12
- export type AudioPlayOptionType = 0.8 | 0.9 | 1.0 | 1.1 | 1.2 | 1.5;
13
- export declare const AudioPlayer: React.FC<AudioPlayerProps>;
14
- export {};
@@ -1,73 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
- import { useState, useEffect } from 'react';
12
- import { FaPlayCircle, FaStopCircle } from "react-icons/fa";
13
- import { usePlugin } from "../utils/plugin/providers/PluginProvider";
14
- import Spinner from '../components/Spinner';
15
- import { EmitterSingleton } from '../utils/plugin/providers/EventEmitter';
16
- export const AudioPlayOptions = [0.8, 0.9, 1.0, 1.1, 1.2, 1.5];
17
- let isFetchingAudio = false;
18
- export const AudioPlayer = ({ text, voice, language, playListenerEvent, initialSpeed = 1.0, playOnMount = false, enableSpeedAdjustment = false, }) => {
19
- const [audioUrl, setAudioUrl] = useState(null);
20
- const [speed, setSpeed] = useState(initialSpeed);
21
- const [isPlaying, setIsPlaying] = useState(false);
22
- const [isLoading, setIsLoading] = useState(false);
23
- const { getVoiceResponse, } = usePlugin();
24
- const emitter = EmitterSingleton;
25
- useEffect(() => {
26
- if (!playListenerEvent)
27
- return;
28
- emitter.on(playListenerEvent, () => togglePlayback());
29
- }, [playListenerEvent]);
30
- // Function to generate audio from text using API
31
- const generateAudio = () => __awaiter(void 0, void 0, void 0, function* () {
32
- setIsLoading(true);
33
- const blob = yield getVoiceResponse(text, voice || (language ? "aws_default" : "openai_alloy"), 1, language);
34
- setAudioUrl(URL.createObjectURL(blob));
35
- setIsLoading(false);
36
- });
37
- // Effect to play audio when audioUrl changes and play state is true
38
- useEffect(() => {
39
- if (!audioUrl || !isPlaying)
40
- return;
41
- const audio = new Audio(audioUrl);
42
- audio.playbackRate = speed;
43
- audio.play().then(() => {
44
- audio.onended = () => {
45
- setIsPlaying(false);
46
- isFetchingAudio = false;
47
- };
48
- }).catch(e => {
49
- console.warn("Error playing audio:", e);
50
- setIsPlaying(false);
51
- });
52
- return () => {
53
- audio.pause();
54
- URL.revokeObjectURL(audioUrl);
55
- };
56
- }, [audioUrl, isPlaying, speed]);
57
- const togglePlayback = () => {
58
- if (!isPlaying && !audioUrl) {
59
- generateAudio().then(() => setIsPlaying(true));
60
- }
61
- else {
62
- setIsPlaying((prev) => !prev);
63
- }
64
- };
65
- useEffect(() => {
66
- if (!playOnMount || isFetchingAudio)
67
- return;
68
- isFetchingAudio = true;
69
- // console.log("playOnMount", playOnMount);
70
- togglePlayback();
71
- }, [playOnMount]);
72
- return (_jsx("div", { className: "group relative", children: _jsxs("div", { className: 'flex flex-row items-end', children: [_jsx("button", { className: "text-gray-500", onClick: togglePlayback, disabled: isLoading, children: isLoading ? _jsx(Spinner, {}) : isPlaying ? _jsx(FaStopCircle, { size: "25px" }) : _jsx(FaPlayCircle, { size: "25px" }) }), enableSpeedAdjustment && (_jsxs("div", { className: "ml-1 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-row text-sm text-gray-500", children: [_jsx("span", { className: 'pr-1', children: "Speed: " }), _jsx("select", { value: speed, className: 'appearance-none cursor-pointer pr-0 p-0 rounded shadow leading-tight focus:outline-none focus:bg-gray-800 focus:ring bg-transparent border-0', onChange: (e) => setSpeed(parseFloat(e.target.value)), disabled: isLoading, children: AudioPlayOptions.map((s) => (_jsx("option", { value: s, children: s }, s))) })] }))] }) }));
73
- };
@@ -1,15 +0,0 @@
1
- import React from "react";
2
- import { ToolInvocation, Tool } from "../../utils/plugin/PluginController";
3
- export interface Message {
4
- role: string;
5
- content: string;
6
- id: string | number;
7
- toolInvocations?: ToolInvocation[];
8
- }
9
- export declare function useChat(tools?: Tool[]): {
10
- messages: Message[];
11
- append: (appendMessages: Message[]) => void;
12
- isLoading: boolean;
13
- setMessages: React.Dispatch<React.SetStateAction<Message[]>>;
14
- lastMessage: Message | undefined;
15
- };