@rimori/client 1.0.5 → 1.1.1

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 (101) hide show
  1. package/README.md +955 -28
  2. package/dist/components/MarkdownEditor.js +6 -4
  3. package/dist/components/PluginController.d.ts +21 -0
  4. package/dist/components/PluginController.js +116 -0
  5. package/dist/components/ai/Assistant.js +1 -1
  6. package/dist/components/ai/Avatar.d.ts +6 -4
  7. package/dist/components/ai/Avatar.js +14 -6
  8. package/dist/components/ai/EmbeddedAssistent/AudioInputField.js +1 -1
  9. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.d.ts +2 -1
  10. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +36 -15
  11. package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.d.ts +1 -0
  12. package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.js +3 -0
  13. package/dist/components/ai/EmbeddedAssistent/TTS/Player.d.ts +2 -0
  14. package/dist/components/ai/EmbeddedAssistent/TTS/Player.js +5 -0
  15. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.d.ts +3 -0
  16. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +41 -5
  17. package/dist/components/ai/utils.d.ts +1 -1
  18. package/dist/components.d.ts +1 -0
  19. package/dist/components.js +1 -0
  20. package/dist/controller/AIController.js +2 -1
  21. package/dist/controller/SettingsController.d.ts +15 -15
  22. package/dist/controller/SettingsController.js +15 -16
  23. package/dist/controller/SharedContentController.d.ts +58 -11
  24. package/dist/controller/SharedContentController.js +161 -26
  25. package/dist/controller/SidePluginController.d.ts +1 -12
  26. package/dist/controller/SidePluginController.js +2 -1
  27. package/dist/core/components/ContextMenu.d.ts +10 -0
  28. package/dist/core/components/ContextMenu.js +93 -0
  29. package/dist/core.d.ts +1 -4
  30. package/dist/core.js +1 -4
  31. package/dist/hooks/UseChatHook.d.ts +1 -1
  32. package/dist/index.d.ts +0 -8
  33. package/dist/index.js +0 -8
  34. package/dist/plugin/AccomplishmentHandler.d.ts +38 -0
  35. package/dist/plugin/AccomplishmentHandler.js +108 -0
  36. package/dist/plugin/ContextMenu.d.ts +17 -0
  37. package/dist/plugin/ContextMenu.js +45 -0
  38. package/dist/plugin/PluginController.js +6 -3
  39. package/dist/plugin/RimoriClient.d.ts +92 -65
  40. package/dist/plugin/RimoriClient.js +105 -75
  41. package/dist/plugin/ThemeSetter.js +2 -2
  42. package/dist/plugin/fromRimori/EventBus.d.ts +6 -3
  43. package/dist/plugin/fromRimori/EventBus.js +15 -9
  44. package/dist/plugin/fromRimori/PluginTypes.d.ts +48 -0
  45. package/dist/plugin/fromRimori/PluginTypes.js +1 -0
  46. package/dist/providers/PluginController.d.ts +21 -0
  47. package/dist/providers/PluginController.js +116 -0
  48. package/dist/providers/PluginProvider.js +26 -73
  49. package/dist/types/Actions.d.ts +4 -0
  50. package/dist/types/Actions.js +1 -0
  51. package/dist/utils/Language.d.ts +66 -0
  52. package/dist/utils/Language.js +67 -0
  53. package/dist/utils/difficultyConverter.d.ts +1 -0
  54. package/dist/utils/difficultyConverter.js +3 -0
  55. package/dist/worker/WorkerSetup.js +4 -4
  56. package/package.json +2 -3
  57. package/src/components/MarkdownEditor.tsx +78 -76
  58. package/src/components/ai/Assistant.tsx +1 -1
  59. package/src/components/ai/Avatar.tsx +66 -49
  60. package/src/components/ai/EmbeddedAssistent/AudioInputField.tsx +1 -1
  61. package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +82 -59
  62. package/src/components/ai/EmbeddedAssistent/TTS/MessageSender.ts +4 -0
  63. package/src/components/ai/EmbeddedAssistent/TTS/Player.ts +6 -0
  64. package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +51 -8
  65. package/src/components/ai/utils.ts +1 -1
  66. package/src/components.ts +2 -1
  67. package/src/controller/AIController.ts +2 -1
  68. package/src/controller/SettingsController.ts +83 -84
  69. package/src/controller/SharedContentController.ts +214 -53
  70. package/src/controller/SidePluginController.ts +3 -14
  71. package/src/core/components/ContextMenu.tsx +123 -0
  72. package/src/core.ts +1 -4
  73. package/src/hooks/UseChatHook.ts +17 -17
  74. package/src/index.ts +0 -8
  75. package/src/plugin/AccomplishmentHandler.ts +165 -0
  76. package/src/plugin/PluginController.ts +105 -103
  77. package/src/plugin/RimoriClient.ts +267 -250
  78. package/src/plugin/ThemeSetter.ts +2 -2
  79. package/src/plugin/fromRimori/EventBus.ts +23 -12
  80. package/src/plugin/fromRimori/PluginTypes.ts +64 -0
  81. package/src/providers/PluginProvider.tsx +63 -110
  82. package/src/types/Actions.ts +6 -0
  83. package/src/utils/Language.ts +70 -0
  84. package/src/utils/difficultyConverter.ts +4 -0
  85. package/src/worker/WorkerSetup.ts +4 -4
  86. package/dist/components/avatar/Assistant.d.ts +0 -9
  87. package/dist/components/avatar/Assistant.js +0 -59
  88. package/dist/components/avatar/Avatar.d.ts +0 -12
  89. package/dist/components/avatar/Avatar.js +0 -42
  90. package/dist/components/avatar/EmbeddedAssistent/AudioInputField.d.ts +0 -7
  91. package/dist/components/avatar/EmbeddedAssistent/AudioInputField.js +0 -38
  92. package/dist/components/avatar/EmbeddedAssistent/CircleAudioAvatar.d.ts +0 -7
  93. package/dist/components/avatar/EmbeddedAssistent/CircleAudioAvatar.js +0 -59
  94. package/dist/components/avatar/EmbeddedAssistent/TTS/MessageSender.d.ts +0 -19
  95. package/dist/components/avatar/EmbeddedAssistent/TTS/MessageSender.js +0 -84
  96. package/dist/components/avatar/EmbeddedAssistent/TTS/Player.d.ts +0 -25
  97. package/dist/components/avatar/EmbeddedAssistent/TTS/Player.js +0 -180
  98. package/dist/components/avatar/EmbeddedAssistent/VoiceRecoder.d.ts +0 -7
  99. package/dist/components/avatar/EmbeddedAssistent/VoiceRecoder.js +0 -45
  100. package/dist/components/avatar/utils.d.ts +0 -6
  101. package/dist/components/avatar/utils.js +0 -14
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ interface Props {
3
+ iframeRef: React.RefObject<HTMLIFrameElement | null>;
4
+ }
5
+ export interface ContextMenuInfo {
6
+ x: number;
7
+ y: number;
8
+ text: string;
9
+ open: boolean;
10
+ }
11
+ export interface ContextMenuAction {
12
+ text: string;
13
+ pluginId: string;
14
+ actionKey: string;
15
+ }
16
+ declare const ContextMenu: ({ iframeRef }: Props) => import("react/jsx-runtime").JSX.Element | null;
17
+ export default ContextMenu;
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { EventBus } from "@/lib/handler/EventBus";
3
+ import { useState, useEffect } from "react";
4
+ import { SupabaseClient } from "@/integrations/supabase/client";
5
+ const ContextMenu = ({ iframeRef }) => {
6
+ const [showMenu, setMenuVisibility] = useState(false);
7
+ const [constextActions, setContextMenuActions] = useState([]);
8
+ const [contextMenu, setContextMenu] = useState({ x: 0, y: 0, open: false, text: "" });
9
+ useEffect(() => {
10
+ SupabaseClient.getPlugins().then(plugins => {
11
+ setContextMenuActions(plugins.flatMap(p => p.context_menu_actions));
12
+ });
13
+ }, []);
14
+ useEffect(() => {
15
+ // Hide the menu on click outside
16
+ const handleClick = () => setMenuVisibility(false);
17
+ document.addEventListener("click", handleClick);
18
+ return () => document.removeEventListener("click", handleClick);
19
+ }, []);
20
+ useEffect(() => {
21
+ EventBus.on("global.contextMenu.createActions", ({ data }) => {
22
+ console.log("addContextMenuActions", data.actions);
23
+ setContextMenuActions([...data.actions, ...constextActions]);
24
+ });
25
+ EventBus.on("global.contextMenu.trigger", ({ data }) => {
26
+ if (!iframeRef.current)
27
+ return;
28
+ const { x, y, open, text } = data;
29
+ const rect = iframeRef.current.getBoundingClientRect();
30
+ setContextMenu({ x: x + rect.left, y: y + rect.top, open, text });
31
+ setMenuVisibility(open);
32
+ });
33
+ }, []);
34
+ if (!showMenu) {
35
+ return null;
36
+ }
37
+ return (_jsx("div", { className: "fixed bg-gray-400 dark:bg-gray-700 shadow-lg border border-gray-400 rounded-md overflow-hidden dark:text-white", style: { top: contextMenu.y, left: contextMenu.x }, children: constextActions.map((action, index) => (_jsx(MenuEntryItem, { icon: action.icon, text: action.text, onClick: () => {
38
+ setMenuVisibility(false);
39
+ EventBus.emit("global.contextMenu", "global.sidebar.triggerAction", Object.assign(Object.assign({}, action), { text: contextMenu.text }));
40
+ } }, index))) }));
41
+ };
42
+ function MenuEntryItem(props) {
43
+ return _jsxs("button", { onClick: props.onClick, className: "px-4 py-2 text-left hover:bg-gray-500 dark:hover:bg-gray-600 w-full flex flex-row", children: [_jsx("span", { className: "flex-grow", children: props.icon }), _jsx("span", { className: "flex-grow", children: props.text })] });
44
+ }
45
+ export default ContextMenu;
@@ -93,7 +93,7 @@ export class PluginController {
93
93
  return this.supabaseInfo.url;
94
94
  }
95
95
  getGlobalEventTopic(preliminaryTopic) {
96
- var _a, _b, _c;
96
+ var _a, _b;
97
97
  if (preliminaryTopic.startsWith("global.")) {
98
98
  return preliminaryTopic;
99
99
  }
@@ -102,12 +102,15 @@ export class PluginController {
102
102
  }
103
103
  const topicParts = preliminaryTopic.split(".");
104
104
  if (topicParts.length === 3) {
105
- if (![(_a = this.supabaseInfo) === null || _a === void 0 ? void 0 : _a.pluginId, "global"].includes(topicParts[0])) {
105
+ if (!topicParts[0].startsWith("pl") && topicParts[0] !== "global") {
106
106
  throw new Error("The event topic must start with the plugin id or 'global'.");
107
107
  }
108
108
  return preliminaryTopic;
109
109
  }
110
- const topicRoot = (_c = (_b = this.supabaseInfo) === null || _b === void 0 ? void 0 : _b.pluginId) !== null && _c !== void 0 ? _c : "global";
110
+ else if (topicParts.length > 3) {
111
+ throw new Error(`The event topic must consist of 3 parts. <pluginId>.<topic area>.<action>. Received: ${preliminaryTopic}`);
112
+ }
113
+ const topicRoot = (_b = (_a = this.supabaseInfo) === null || _a === void 0 ? void 0 : _a.pluginId) !== null && _b !== void 0 ? _b : "global";
111
114
  return `${topicRoot}.${preliminaryTopic}`;
112
115
  }
113
116
  }
@@ -1,30 +1,34 @@
1
- import { PluginController } from "./PluginController";
1
+ import { PostgrestQueryBuilder } from "@supabase/postgrest-js";
2
2
  import { SupabaseClient } from "@supabase/supabase-js";
3
- import { EventBusMessage, EventPayload } from "./fromRimori/EventBus";
4
3
  import { GenericSchema } from "@supabase/supabase-js/dist/module/lib/types";
5
- import { PostgrestQueryBuilder, PostgrestFilterBuilder } from "@supabase/postgrest-js";
6
- import { BasicAssignment } from "../controller/SharedContentController";
7
- import { Message, Tool, OnLLMResponse } from "../controller/AIController";
4
+ import { Message, OnLLMResponse, Tool } from "../controller/AIController";
8
5
  import { ObjectRequest } from "../controller/ObjectController";
9
- import { Plugin } from "../controller/SidePluginController";
10
6
  import { UserInfo } from "../controller/SettingsController";
11
- import { EventHandler } from "./fromRimori/EventBus";
7
+ import { BasicAssignment, SharedContent, SharedContentFilter, SharedContentObjectRequest } from "../controller/SharedContentController";
8
+ import { AccomplishmentPayload } from "./AccomplishmentHandler";
9
+ import { EventBusMessage, EventHandler, EventPayload } from "./fromRimori/EventBus";
10
+ import { Plugin } from "./fromRimori/PluginTypes";
11
+ import { PluginController } from "./PluginController";
12
12
  interface Db {
13
13
  from: {
14
14
  <TableName extends string & keyof GenericSchema['Tables'], Table extends GenericSchema['Tables'][TableName]>(relation: TableName): PostgrestQueryBuilder<GenericSchema, Table, TableName>;
15
15
  <ViewName extends string & keyof GenericSchema['Views'], View extends GenericSchema['Views'][ViewName]>(relation: ViewName): PostgrestQueryBuilder<GenericSchema, View, ViewName>;
16
16
  };
17
- rpc: <Fn extends GenericSchema['Functions'][string], FnName extends string & keyof GenericSchema['Functions']>(functionName: FnName, args?: Fn["Args"], options?: {
18
- head?: boolean;
19
- get?: boolean;
20
- count?: "exact" | "planned" | "estimated";
21
- }) => PostgrestFilterBuilder<GenericSchema, Fn["Returns"] extends any[] ? Fn["Returns"][number] extends Record<string, unknown> ? Fn["Returns"][number] : never : never, Fn["Returns"], string, null>;
22
- functions: SupabaseClient["functions"];
23
17
  storage: SupabaseClient["storage"];
18
+ /**
19
+ * The table prefix for of database tables of the plugin.
20
+ */
21
+ tablePrefix: string;
22
+ /**
23
+ * Get the table name for a given plugin table.
24
+ * Internally all tables are prefixed with the plugin id. This function is used to get the correct table name for a given public table.
25
+ * @param table The plugin table name to get the full table name for.
26
+ * @returns The full table name.
27
+ */
28
+ getTableName: (table: string) => string;
24
29
  }
25
30
  interface PluginInterface {
26
31
  pluginId: string;
27
- tablePrefix: string;
28
32
  setSettings: (settings: any) => Promise<void>;
29
33
  /**
30
34
  * Get the settings for the plugin. T can be any type of settings, UserSettings or SystemSettings.
@@ -46,6 +50,7 @@ export declare class RimoriClient {
46
50
  private pluginController;
47
51
  private settingsController;
48
52
  private sharedContentController;
53
+ private accomplishmentHandler;
49
54
  private supabaseUrl;
50
55
  db: Db;
51
56
  plugin: PluginInterface;
@@ -61,7 +66,7 @@ export declare class RimoriClient {
61
66
  * @param data The data to emit.
62
67
  * @param eventId The event id.
63
68
  */
64
- emit: (topic: string, data: any, eventId?: number) => void;
69
+ emit: (topic: string, data?: any, eventId?: number) => void;
65
70
  /**
66
71
  * Request an event.
67
72
  * @param topic The topic to request the event on.
@@ -73,8 +78,9 @@ export declare class RimoriClient {
73
78
  * Subscribe to an event.
74
79
  * @param topic The topic to subscribe to.
75
80
  * @param callback The callback to call when the event is emitted.
81
+ * @returns The unsubscribe ids.
76
82
  */
77
- on: <T = EventPayload>(topic: string, callback: EventHandler<T>) => void;
83
+ on: <T = EventPayload>(topic: string | string[], callback: EventHandler<T>) => import("./fromRimori/EventBus").EventListener[];
78
84
  /**
79
85
  * Subscribe to an event once.
80
86
  * @param topic The topic to subscribe to.
@@ -87,33 +93,27 @@ export declare class RimoriClient {
87
93
  * @param data The data to respond with.
88
94
  */
89
95
  respond: <T = EventPayload>(topic: string, data: EventPayload | ((data: EventBusMessage<T>) => EventPayload | Promise<EventPayload>)) => void;
96
+ /**
97
+ * Emit an accomplishment.
98
+ * @param payload The payload to emit.
99
+ */
100
+ emitAccomplishment: (payload: AccomplishmentPayload) => void;
101
+ /**
102
+ * Subscribe to an accomplishment.
103
+ * @param accomplishmentTopic The topic to subscribe to.
104
+ * @param callback The callback to call when the accomplishment is emitted.
105
+ */
106
+ onAccomplishment: (accomplishmentTopic: string, callback: (payload: EventBusMessage<AccomplishmentPayload>) => void) => void;
107
+ /**
108
+ * Trigger an action that opens the sidebar and triggers an action in the designated plugin.
109
+ * @param pluginId The id of the plugin to trigger the action for.
110
+ * @param actionKey The key of the action to trigger.
111
+ * @param text Optional text to be used for the action like for example text that the translator would look up.
112
+ */
113
+ emitSidebarAction: (pluginId: string, actionKey: string, text?: string) => void;
90
114
  };
91
115
  static getInstance(pluginController: PluginController): Promise<RimoriClient>;
92
116
  private from;
93
- /**
94
- * Perform a function call.
95
- *
96
- * @param functionName - The function name to call
97
- * @param args - The arguments to pass to the function call
98
- * @param options - Named parameters
99
- * @param options.head - When set to `true`, `data` will not be returned.
100
- * Useful if you only need the count.
101
- * @param options.get - When set to `true`, the function will be called with
102
- * read-only access mode.
103
- * @param options.count - Count algorithm to use to count rows returned by the
104
- * function. Only applicable for [set-returning
105
- * functions](https://www.postgresql.org/docs/current/functions-srf.html).
106
- *
107
- * `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the
108
- * hood.
109
- *
110
- * `"planned"`: Approximated but fast count algorithm. Uses the Postgres
111
- * statistics under the hood.
112
- *
113
- * `"estimated"`: Uses exact count for low numbers and planned count for high
114
- * numbers.
115
- */
116
- private rpc;
117
117
  private getTableName;
118
118
  llm: {
119
119
  getText: (messages: Message[], tools?: Tool[]) => Promise<string>;
@@ -122,30 +122,57 @@ export declare class RimoriClient {
122
122
  getTextFromVoice: (file: Blob) => Promise<string>;
123
123
  getObject: (request: ObjectRequest) => Promise<any>;
124
124
  };
125
- /**
126
- * Fetch new shared content.
127
- * @param type The type of shared content to fetch. E.g. assignments, exercises, etc.
128
- * @param generatorInstructions The instructions for the generator.
129
- * @param filter The filter for the shared content.
130
- * @returns The new shared content.
131
- */
132
- fetchNewSharedContent<T, R = T & BasicAssignment>(type: string, generatorInstructions: (reservedTopics: string[]) => Promise<ObjectRequest> | ObjectRequest, filter?: {
133
- column: string;
134
- value: string | number | boolean;
135
- }): Promise<R[]>;
136
- /**
137
- * Get a shared content item by id.
138
- * @param type The type of shared content to get. E.g. assignments, exercises, etc.
139
- * @param id The id of the shared content item.
140
- * @returns The shared content item.
141
- */
142
- getSharedContent<T extends BasicAssignment>(type: string, id: string): Promise<T>;
143
- /**
144
- * Complete a shared content item.
145
- * @param type The type of shared content to complete. E.g. assignments, exercises, etc.
146
- * @param assignmentId The id of the shared content item to complete.
147
- */
148
- completeSharedContent(type: string, assignmentId: string): Promise<void>;
149
- triggerSidebarAction(pluginId: string, actionKey: string, text?: string): void;
125
+ community: {
126
+ /**
127
+ * Shared content is a way to share completable content with other users using this plugin.
128
+ * Typical examples are assignments, exercises, stories, etc.
129
+ * Users generate new shared content items and others can complete the content too.
130
+ */
131
+ sharedContent: {
132
+ /**
133
+ * Get one dedicated shared content item by id. It does not matter if it is completed or not.
134
+ * @param contentType The type of shared content to get. E.g. assignments, exercises, etc.
135
+ * @param id The id of the shared content item.
136
+ * @returns The shared content item.
137
+ */
138
+ get: <T = any>(contentType: string, id: string) => Promise<BasicAssignment<T>>;
139
+ /**
140
+ * Get a list of shared content items.
141
+ * @param contentType The type of shared content to get. E.g. assignments, exercises, etc.
142
+ * @param filter The optional additional filter for checking new shared content based on a column and value. This is useful if the aditional information stored on the shared content is used to further narrow down the kind of shared content wanted to be received. E.g. only adjective grammar exercises.
143
+ * @param limit The optional limit for the number of results.
144
+ * @returns The list of shared content items.
145
+ */
146
+ getList: <T = any>(contentType: string, filter?: SharedContentFilter, limit?: number) => Promise<BasicAssignment<T>[]>;
147
+ /**
148
+ * Get new shared content.
149
+ * @param contentType The type of shared content to fetch. E.g. assignments, exercises, etc.
150
+ * @param generatorInstructions The instructions for the creation of new shared content. The object will automatically be extended with a tool property with a topic and keywords property to let a new unique topic be generated.
151
+ * @param filter The optional additional filter for checking new shared content based on a column and value. This is useful if the aditional information stored on the shared content is used to further narrow down the kind of shared content wanted to be received. E.g. only adjective grammar exercises.
152
+ * @param privateTopic An optional flag to indicate if the topic should be private and only be visible to the user. This is useful if the topic is not meant to be shared with other users. Like for personal topics or if the content is based on the personal study goal.
153
+ * @returns The new shared content.
154
+ */
155
+ getNew: <T = any>(contentType: string, generatorInstructions: SharedContentObjectRequest, filter?: SharedContentFilter, privateTopic?: boolean) => Promise<BasicAssignment<T>>;
156
+ /**
157
+ * Create a new shared content item.
158
+ * @param content The content to create.
159
+ * @returns The new shared content item.
160
+ */
161
+ create: <T = any>(content: SharedContent<T>) => Promise<BasicAssignment<T>>;
162
+ /**
163
+ * Update a shared content item.
164
+ * @param id The id of the shared content item to update.
165
+ * @param content The content to update.
166
+ * @returns The updated shared content item.
167
+ */
168
+ update: <T = any>(id: string, content: Partial<SharedContent<T>>) => Promise<BasicAssignment<T>>;
169
+ /**
170
+ * Complete a shared content item.
171
+ * @param contentType The type of shared content to complete. E.g. assignments, exercises, etc.
172
+ * @param assignmentId The id of the shared content item to complete.
173
+ */
174
+ complete: (contentType: string, assignmentId: string) => Promise<void>;
175
+ };
176
+ };
150
177
  }
151
178
  export {};
@@ -7,12 +7,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
+ import { generateText, streamChatGPT } from "../controller/AIController";
11
+ import { generateObject as generateObjectFunction } from "../controller/ObjectController";
10
12
  import { SettingsController } from "../controller/SettingsController";
11
- import { getSTTResponse, getTTSResponse } from "../controller/VoiceController";
12
13
  import { SharedContentController } from "../controller/SharedContentController";
13
- import { streamChatGPT, generateText } from "../controller/AIController";
14
- import { generateObject as generateObjectFunction } from "../controller/ObjectController";
15
14
  import { getPlugins } from "../controller/SidePluginController";
15
+ import { getSTTResponse, getTTSResponse } from "../controller/VoiceController";
16
+ import { AccomplishmentHandler } from "./AccomplishmentHandler";
16
17
  import { EventBus } from "./fromRimori/EventBus";
17
18
  export class RimoriClient {
18
19
  constructor(options) {
@@ -45,9 +46,11 @@ export class RimoriClient {
45
46
  * Subscribe to an event.
46
47
  * @param topic The topic to subscribe to.
47
48
  * @param callback The callback to call when the event is emitted.
49
+ * @returns The unsubscribe ids.
48
50
  */
49
51
  on: (topic, callback) => {
50
- EventBus.on(this.pluginController.getGlobalEventTopic(topic), callback);
52
+ const topics = Array.isArray(topic) ? topic : [topic];
53
+ return topics.map(topic => EventBus.on(this.pluginController.getGlobalEventTopic(topic), callback));
51
54
  },
52
55
  /**
53
56
  * Subscribe to an event once.
@@ -64,45 +67,134 @@ export class RimoriClient {
64
67
  */
65
68
  respond: (topic, data) => {
66
69
  EventBus.respond(this.plugin.pluginId, this.pluginController.getGlobalEventTopic(topic), data);
70
+ },
71
+ /**
72
+ * Emit an accomplishment.
73
+ * @param payload The payload to emit.
74
+ */
75
+ emitAccomplishment: (payload) => {
76
+ this.accomplishmentHandler.emitAccomplishment(payload);
77
+ },
78
+ /**
79
+ * Subscribe to an accomplishment.
80
+ * @param accomplishmentTopic The topic to subscribe to.
81
+ * @param callback The callback to call when the accomplishment is emitted.
82
+ */
83
+ onAccomplishment: (accomplishmentTopic, callback) => {
84
+ this.accomplishmentHandler.subscribe(accomplishmentTopic, callback);
85
+ },
86
+ /**
87
+ * Trigger an action that opens the sidebar and triggers an action in the designated plugin.
88
+ * @param pluginId The id of the plugin to trigger the action for.
89
+ * @param actionKey The key of the action to trigger.
90
+ * @param text Optional text to be used for the action like for example text that the translator would look up.
91
+ */
92
+ emitSidebarAction: (pluginId, actionKey, text) => {
93
+ this.event.emit("global.sidebar.triggerAction", { pluginId, actionKey, text });
67
94
  }
68
95
  };
69
96
  this.llm = {
70
97
  getText: (messages, tools) => __awaiter(this, void 0, void 0, function* () {
71
98
  const token = yield this.pluginController.getToken();
72
- return generateText(this.supabaseUrl, messages, tools || [], token).then(response => response.messages[0].content[0].text);
99
+ return generateText(this.supabaseUrl, messages, tools || [], token).then(({ messages }) => messages[0].content[0].text);
73
100
  }),
74
101
  getSteamedText: (messages, onMessage, tools) => __awaiter(this, void 0, void 0, function* () {
75
102
  const token = yield this.pluginController.getToken();
76
103
  streamChatGPT(this.supabaseUrl, messages, tools || [], onMessage, token);
77
104
  }),
78
105
  getVoice: (text_1, ...args_1) => __awaiter(this, [text_1, ...args_1], void 0, function* (text, voice = "alloy", speed = 1, language) {
79
- return getTTSResponse(this.pluginController.getSupabaseUrl(), { input: text, voice, speed, language }, yield this.pluginController.getToken());
106
+ const token = yield this.pluginController.getToken();
107
+ return getTTSResponse(this.supabaseUrl, { input: text, voice, speed, language }, token);
80
108
  }),
81
109
  getTextFromVoice: (file) => {
82
110
  return getSTTResponse(this.superbase, file);
83
111
  },
84
112
  getObject: (request) => __awaiter(this, void 0, void 0, function* () {
85
113
  const token = yield this.pluginController.getToken();
86
- return generateObjectFunction(this.pluginController.getSupabaseUrl(), request, token);
114
+ return generateObjectFunction(this.supabaseUrl, request, token);
87
115
  }),
88
116
  // getSteamedObject: this.generateObjectStream,
89
117
  };
118
+ this.community = {
119
+ /**
120
+ * Shared content is a way to share completable content with other users using this plugin.
121
+ * Typical examples are assignments, exercises, stories, etc.
122
+ * Users generate new shared content items and others can complete the content too.
123
+ */
124
+ sharedContent: {
125
+ /**
126
+ * Get one dedicated shared content item by id. It does not matter if it is completed or not.
127
+ * @param contentType The type of shared content to get. E.g. assignments, exercises, etc.
128
+ * @param id The id of the shared content item.
129
+ * @returns The shared content item.
130
+ */
131
+ get: (contentType, id) => __awaiter(this, void 0, void 0, function* () {
132
+ return yield this.sharedContentController.getSharedContent(contentType, id);
133
+ }),
134
+ /**
135
+ * Get a list of shared content items.
136
+ * @param contentType The type of shared content to get. E.g. assignments, exercises, etc.
137
+ * @param filter The optional additional filter for checking new shared content based on a column and value. This is useful if the aditional information stored on the shared content is used to further narrow down the kind of shared content wanted to be received. E.g. only adjective grammar exercises.
138
+ * @param limit The optional limit for the number of results.
139
+ * @returns The list of shared content items.
140
+ */
141
+ getList: (contentType, filter, limit) => __awaiter(this, void 0, void 0, function* () {
142
+ return yield this.sharedContentController.getSharedContentList(contentType, filter, limit);
143
+ }),
144
+ /**
145
+ * Get new shared content.
146
+ * @param contentType The type of shared content to fetch. E.g. assignments, exercises, etc.
147
+ * @param generatorInstructions The instructions for the creation of new shared content. The object will automatically be extended with a tool property with a topic and keywords property to let a new unique topic be generated.
148
+ * @param filter The optional additional filter for checking new shared content based on a column and value. This is useful if the aditional information stored on the shared content is used to further narrow down the kind of shared content wanted to be received. E.g. only adjective grammar exercises.
149
+ * @param privateTopic An optional flag to indicate if the topic should be private and only be visible to the user. This is useful if the topic is not meant to be shared with other users. Like for personal topics or if the content is based on the personal study goal.
150
+ * @returns The new shared content.
151
+ */
152
+ getNew: (contentType, generatorInstructions, filter, privateTopic) => __awaiter(this, void 0, void 0, function* () {
153
+ return yield this.sharedContentController.getNewSharedContent(contentType, generatorInstructions, filter, privateTopic);
154
+ }),
155
+ /**
156
+ * Create a new shared content item.
157
+ * @param content The content to create.
158
+ * @returns The new shared content item.
159
+ */
160
+ create: (content) => __awaiter(this, void 0, void 0, function* () {
161
+ return yield this.sharedContentController.createSharedContent(content);
162
+ }),
163
+ /**
164
+ * Update a shared content item.
165
+ * @param id The id of the shared content item to update.
166
+ * @param content The content to update.
167
+ * @returns The updated shared content item.
168
+ */
169
+ update: (id, content) => __awaiter(this, void 0, void 0, function* () {
170
+ return yield this.sharedContentController.updateSharedContent(id, content);
171
+ }),
172
+ /**
173
+ * Complete a shared content item.
174
+ * @param contentType The type of shared content to complete. E.g. assignments, exercises, etc.
175
+ * @param assignmentId The id of the shared content item to complete.
176
+ */
177
+ complete: (contentType, assignmentId) => __awaiter(this, void 0, void 0, function* () {
178
+ return yield this.sharedContentController.completeSharedContent(contentType, assignmentId);
179
+ })
180
+ }
181
+ };
90
182
  this.superbase = options.supabase;
91
183
  this.pluginController = options.pluginController;
92
184
  this.settingsController = new SettingsController(options.supabase, options.pluginId);
93
- this.sharedContentController = new SharedContentController(this);
185
+ this.sharedContentController = new SharedContentController(this.superbase, this);
94
186
  this.supabaseUrl = this.pluginController.getSupabaseUrl();
95
- this.rpc = this.rpc.bind(this);
187
+ this.accomplishmentHandler = new AccomplishmentHandler(options.pluginId);
96
188
  this.from = this.from.bind(this);
97
189
  this.db = {
98
- rpc: this.rpc,
99
190
  from: this.from,
100
191
  storage: this.superbase.storage,
101
- functions: this.superbase.functions,
192
+ // functions: this.superbase.functions,
193
+ tablePrefix: options.tablePrefix,
194
+ getTableName: this.getTableName.bind(this),
102
195
  };
103
196
  this.plugin = {
104
197
  pluginId: options.pluginId,
105
- tablePrefix: options.tablePrefix,
106
198
  setSettings: (settings) => __awaiter(this, void 0, void 0, function* () {
107
199
  yield this.settingsController.setSettings(settings);
108
200
  }),
@@ -129,69 +221,7 @@ export class RimoriClient {
129
221
  from(relation) {
130
222
  return this.superbase.from(this.getTableName(relation));
131
223
  }
132
- /**
133
- * Perform a function call.
134
- *
135
- * @param functionName - The function name to call
136
- * @param args - The arguments to pass to the function call
137
- * @param options - Named parameters
138
- * @param options.head - When set to `true`, `data` will not be returned.
139
- * Useful if you only need the count.
140
- * @param options.get - When set to `true`, the function will be called with
141
- * read-only access mode.
142
- * @param options.count - Count algorithm to use to count rows returned by the
143
- * function. Only applicable for [set-returning
144
- * functions](https://www.postgresql.org/docs/current/functions-srf.html).
145
- *
146
- * `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the
147
- * hood.
148
- *
149
- * `"planned"`: Approximated but fast count algorithm. Uses the Postgres
150
- * statistics under the hood.
151
- *
152
- * `"estimated"`: Uses exact count for low numbers and planned count for high
153
- * numbers.
154
- */
155
- rpc(functionName, args = {}, options = {}) {
156
- return this.superbase.rpc(this.getTableName(functionName), args, options);
157
- }
158
224
  getTableName(type) {
159
- return this.plugin.tablePrefix + "_" + type;
160
- }
161
- /**
162
- * Fetch new shared content.
163
- * @param type The type of shared content to fetch. E.g. assignments, exercises, etc.
164
- * @param generatorInstructions The instructions for the generator.
165
- * @param filter The filter for the shared content.
166
- * @returns The new shared content.
167
- */
168
- fetchNewSharedContent(type, generatorInstructions, filter) {
169
- return __awaiter(this, void 0, void 0, function* () {
170
- return this.sharedContentController.fetchNewSharedContent(type, generatorInstructions, filter);
171
- });
172
- }
173
- /**
174
- * Get a shared content item by id.
175
- * @param type The type of shared content to get. E.g. assignments, exercises, etc.
176
- * @param id The id of the shared content item.
177
- * @returns The shared content item.
178
- */
179
- getSharedContent(type, id) {
180
- return __awaiter(this, void 0, void 0, function* () {
181
- return this.sharedContentController.getSharedContent(type, id);
182
- });
183
- }
184
- /**
185
- * Complete a shared content item.
186
- * @param type The type of shared content to complete. E.g. assignments, exercises, etc.
187
- * @param assignmentId The id of the shared content item to complete.
188
- */
189
- completeSharedContent(type, assignmentId) {
190
- return __awaiter(this, void 0, void 0, function* () {
191
- return this.sharedContentController.completeSharedContent(type, assignmentId);
192
- });
193
- }
194
- triggerSidebarAction(pluginId, actionKey, text) {
195
- this.event.emit("global.sidebar.triggerAction", { pluginId, actionKey, text });
225
+ return this.db.tablePrefix + "_" + type;
196
226
  }
197
227
  }
@@ -4,10 +4,10 @@ export function setTheme() {
4
4
  if (!theme || theme === 'system') {
5
5
  theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
6
6
  }
7
- document.documentElement.classList.add("dark:text-gray-200", "bg-white");
7
+ document.documentElement.classList.add("dark:text-gray-200");
8
8
  if (theme === 'dark') {
9
9
  document.documentElement.setAttribute("data-theme", "dark");
10
- document.documentElement.classList.add('dark', "bg-gray-950");
10
+ document.documentElement.classList.add('dark', "dark:bg-gray-950");
11
11
  document.documentElement.style.background = "hsl(var(--background))";
12
12
  }
13
13
  }
@@ -15,6 +15,9 @@ export interface EventBusMessage<T = EventPayload> {
15
15
  debug: boolean;
16
16
  }
17
17
  export type EventHandler<T = EventPayload> = (event: EventBusMessage<T>) => void | Promise<void>;
18
+ export interface EventListener {
19
+ off: () => void;
20
+ }
18
21
  export declare class EventBusHandler {
19
22
  private listeners;
20
23
  private responseResolvers;
@@ -51,7 +54,7 @@ export declare class EventBusHandler {
51
54
  * @param ignoreSender - The senders to ignore.
52
55
  * @returns The ids of the listeners.
53
56
  */
54
- on<T = EventPayload>(topics: string | string[], handler: EventHandler<T>, ignoreSender?: string[]): string[];
57
+ on<T = EventPayload>(topics: string | string[], handler: EventHandler<T>, ignoreSender?: string[]): EventListener;
55
58
  /**
56
59
  * Subscribes to an event, processes the data and emits a response on the event bus.
57
60
  * @param sender - The sender of the event.
@@ -59,7 +62,7 @@ export declare class EventBusHandler {
59
62
  * @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.
60
63
  * @returns The ids of the listeners.
61
64
  */
62
- respond(sender: string, topic: string, handler: EventPayload | ((data: EventBusMessage) => EventPayload | Promise<EventPayload>)): string[];
65
+ respond(sender: string, topic: string, handler: EventPayload | ((data: EventBusMessage) => EventPayload | Promise<EventPayload>)): EventListener;
63
66
  /**
64
67
  * Subscribes to an event on the event bus. The handler will be called once and then removed.
65
68
  * @param topic - The topic of the event.
@@ -70,7 +73,7 @@ export declare class EventBusHandler {
70
73
  * Unsubscribes from an event on the event bus.
71
74
  * @param listenerIds - The ids of the listeners to unsubscribe from.
72
75
  */
73
- off(listenerIds: string | string[]): void;
76
+ private off;
74
77
  private toArray;
75
78
  /**
76
79
  * Requests data from the event bus.