@rimori/client 1.1.10 → 1.3.0

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 (171) hide show
  1. package/README.md +189 -63
  2. package/dist/cli/scripts/init/dev-registration.d.ts +35 -0
  3. package/dist/cli/scripts/init/dev-registration.js +174 -0
  4. package/dist/cli/scripts/init/env-setup.d.ts +9 -0
  5. package/dist/cli/scripts/init/env-setup.js +43 -0
  6. package/dist/cli/scripts/init/file-operations.d.ts +4 -0
  7. package/dist/cli/scripts/init/file-operations.js +51 -0
  8. package/dist/cli/scripts/init/html-cleaner.d.ts +4 -0
  9. package/dist/cli/scripts/init/html-cleaner.js +38 -0
  10. package/dist/cli/scripts/init/main.d.ts +2 -0
  11. package/dist/cli/scripts/init/main.js +160 -0
  12. package/dist/cli/scripts/init/package-setup.d.ts +32 -0
  13. package/dist/cli/scripts/init/package-setup.js +75 -0
  14. package/dist/cli/scripts/init/router-transformer.d.ts +6 -0
  15. package/dist/cli/scripts/init/router-transformer.js +254 -0
  16. package/dist/cli/scripts/init/tailwind-config.d.ts +4 -0
  17. package/dist/cli/scripts/init/tailwind-config.js +56 -0
  18. package/dist/cli/scripts/init/vite-config.d.ts +20 -0
  19. package/dist/cli/scripts/init/vite-config.js +54 -0
  20. package/dist/cli/scripts/release/release-config-upload.d.ts +7 -0
  21. package/dist/cli/scripts/release/release-config-upload.js +116 -0
  22. package/dist/cli/scripts/release/release-db-update.d.ts +6 -0
  23. package/dist/cli/scripts/release/release-db-update.js +100 -0
  24. package/dist/cli/scripts/release/release-file-upload.d.ts +6 -0
  25. package/dist/cli/scripts/release/release-file-upload.js +136 -0
  26. package/dist/cli/scripts/release/release.d.ts +23 -0
  27. package/dist/cli/scripts/release/release.js +70 -0
  28. package/dist/cli/types/DatabaseTypes.d.ts +103 -0
  29. package/dist/cli/types/DatabaseTypes.js +2 -0
  30. package/dist/components/LoggerExample.d.ts +6 -0
  31. package/dist/components/LoggerExample.js +79 -0
  32. package/dist/components/ai/Assistant.js +5 -5
  33. package/dist/components/ai/Avatar.d.ts +3 -2
  34. package/dist/components/ai/Avatar.js +11 -6
  35. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +1 -1
  36. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.d.ts +1 -0
  37. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +48 -33
  38. package/dist/components/ai/utils.js +0 -1
  39. package/dist/components/audio/Playbutton.js +4 -4
  40. package/dist/{core → components}/components/ContextMenu.js +50 -11
  41. package/dist/components.d.ts +5 -5
  42. package/dist/components.js +5 -5
  43. package/dist/core/controller/AIController.d.ts +15 -0
  44. package/dist/core/controller/AIController.js +253 -0
  45. package/dist/core/controller/AudioController.d.ts +0 -0
  46. package/dist/core/controller/AudioController.js +1 -0
  47. package/dist/{controller → core/controller}/ObjectController.d.ts +10 -2
  48. package/dist/{controller → core/controller}/ObjectController.js +8 -8
  49. package/dist/{controller → core/controller}/SettingsController.d.ts +28 -4
  50. package/dist/{controller → core/controller}/SettingsController.js +0 -25
  51. package/dist/{controller → core/controller}/SharedContentController.d.ts +31 -3
  52. package/dist/{controller → core/controller}/SharedContentController.js +77 -26
  53. package/dist/core/controller/VoiceController.d.ts +9 -0
  54. package/dist/{controller → core/controller}/VoiceController.js +11 -4
  55. package/dist/core/core.d.ts +14 -0
  56. package/dist/core/core.js +8 -0
  57. package/dist/{plugin/fromRimori → fromRimori}/EventBus.d.ts +3 -3
  58. package/dist/{plugin/fromRimori → fromRimori}/EventBus.js +26 -9
  59. package/dist/fromRimori/PluginTypes.d.ts +174 -0
  60. package/dist/hooks/UseChatHook.d.ts +2 -1
  61. package/dist/hooks/UseChatHook.js +6 -4
  62. package/dist/hooks/UseLogger.d.ts +30 -0
  63. package/dist/hooks/UseLogger.js +122 -0
  64. package/dist/index.d.ts +6 -3
  65. package/dist/index.js +5 -3
  66. package/dist/plugin/AccomplishmentHandler.d.ts +1 -1
  67. package/dist/plugin/AccomplishmentHandler.js +1 -1
  68. package/dist/plugin/AudioController.d.ts +37 -0
  69. package/dist/plugin/AudioController.js +68 -0
  70. package/dist/plugin/Logger.d.ts +68 -0
  71. package/dist/plugin/Logger.js +256 -0
  72. package/dist/plugin/LoggerExample.d.ts +16 -0
  73. package/dist/plugin/LoggerExample.js +140 -0
  74. package/dist/plugin/PluginController.d.ts +30 -5
  75. package/dist/plugin/PluginController.js +182 -53
  76. package/dist/plugin/RimoriClient.d.ts +68 -21
  77. package/dist/plugin/RimoriClient.js +88 -41
  78. package/dist/plugin/StandaloneClient.d.ts +1 -0
  79. package/dist/plugin/StandaloneClient.js +24 -10
  80. package/dist/plugin/ThemeSetter.d.ts +2 -1
  81. package/dist/plugin/ThemeSetter.js +13 -7
  82. package/dist/providers/PluginProvider.d.ts +4 -1
  83. package/dist/providers/PluginProvider.js +39 -13
  84. package/dist/utils/Language.d.ts +2 -1
  85. package/dist/utils/Language.js +4 -2
  86. package/dist/utils/audioFormats.d.ts +26 -0
  87. package/dist/utils/audioFormats.js +67 -0
  88. package/dist/utils/difficultyConverter.js +1 -1
  89. package/dist/utils/endpoint.d.ts +2 -0
  90. package/dist/utils/endpoint.js +2 -0
  91. package/dist/worker/WorkerSetup.d.ts +3 -2
  92. package/dist/worker/WorkerSetup.js +22 -65
  93. package/example/docs/devdocs.md +231 -0
  94. package/example/docs/overview.md +29 -0
  95. package/example/docs/userdocs.md +123 -0
  96. package/example/rimori.config.ts +89 -0
  97. package/example/worker/vite.config.ts +23 -0
  98. package/example/worker/worker.ts +11 -0
  99. package/package.json +16 -9
  100. package/src/cli/scripts/init/dev-registration.ts +192 -0
  101. package/src/cli/scripts/init/env-setup.ts +44 -0
  102. package/src/cli/scripts/init/file-operations.ts +58 -0
  103. package/src/cli/scripts/init/html-cleaner.ts +48 -0
  104. package/src/cli/scripts/init/main.ts +172 -0
  105. package/src/cli/scripts/init/package-setup.ts +117 -0
  106. package/src/cli/scripts/init/router-transformer.ts +329 -0
  107. package/src/cli/scripts/init/tailwind-config.ts +75 -0
  108. package/src/cli/scripts/init/vite-config.ts +73 -0
  109. package/src/cli/scripts/release/release-config-upload.ts +114 -0
  110. package/src/cli/scripts/release/release-db-update.ts +97 -0
  111. package/src/cli/scripts/release/release-file-upload.ts +138 -0
  112. package/src/cli/scripts/release/release.ts +69 -0
  113. package/src/cli/types/DatabaseTypes.ts +117 -0
  114. package/src/components/ai/Assistant.tsx +5 -5
  115. package/src/components/ai/Avatar.tsx +25 -8
  116. package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +1 -1
  117. package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +50 -35
  118. package/src/components/ai/utils.ts +0 -2
  119. package/src/components/audio/Playbutton.tsx +4 -4
  120. package/src/{core → components}/components/ContextMenu.tsx +56 -12
  121. package/src/components.ts +6 -6
  122. package/src/core/controller/AIController.ts +283 -0
  123. package/src/core/controller/ObjectController.ts +115 -0
  124. package/src/{controller → core/controller}/SettingsController.ts +29 -29
  125. package/src/{controller → core/controller}/SharedContentController.ts +91 -29
  126. package/src/core/controller/VoiceController.ts +31 -0
  127. package/src/core/core.ts +16 -0
  128. package/src/{plugin/fromRimori → fromRimori}/EventBus.ts +29 -11
  129. package/src/fromRimori/PluginTypes.ts +205 -0
  130. package/src/hooks/UseChatHook.ts +8 -5
  131. package/src/index.ts +6 -3
  132. package/src/plugin/AccomplishmentHandler.ts +1 -1
  133. package/src/plugin/AudioController.ts +58 -0
  134. package/src/plugin/Logger.ts +324 -0
  135. package/src/plugin/PluginController.ts +203 -63
  136. package/src/plugin/RimoriClient.ts +127 -55
  137. package/src/plugin/StandaloneClient.ts +30 -11
  138. package/src/plugin/ThemeSetter.ts +16 -9
  139. package/src/providers/PluginProvider.tsx +46 -13
  140. package/src/utils/Language.ts +4 -2
  141. package/src/utils/difficultyConverter.ts +3 -3
  142. package/src/utils/endpoint.ts +2 -0
  143. package/src/worker/WorkerSetup.ts +13 -60
  144. package/dist/components/PluginController.d.ts +0 -21
  145. package/dist/components/PluginController.js +0 -116
  146. package/dist/controller/AIController.d.ts +0 -23
  147. package/dist/controller/AIController.js +0 -93
  148. package/dist/controller/SidePluginController.d.ts +0 -3
  149. package/dist/controller/SidePluginController.js +0 -31
  150. package/dist/controller/VoiceController.d.ts +0 -10
  151. package/dist/core.d.ts +0 -7
  152. package/dist/core.js +0 -7
  153. package/dist/plugin/ContextMenu.d.ts +0 -17
  154. package/dist/plugin/ContextMenu.js +0 -45
  155. package/dist/plugin/fromRimori/PluginTypes.d.ts +0 -48
  156. package/dist/plugin/fromRimori/SupabaseHandler.d.ts +0 -13
  157. package/dist/plugin/fromRimori/SupabaseHandler.js +0 -55
  158. package/dist/providers/PluginController.d.ts +0 -21
  159. package/dist/providers/PluginController.js +0 -116
  160. package/dist/types/Actions.d.ts +0 -4
  161. package/dist/types/Actions.js +0 -1
  162. package/src/controller/AIController.ts +0 -112
  163. package/src/controller/ObjectController.ts +0 -107
  164. package/src/controller/SidePluginController.ts +0 -25
  165. package/src/controller/VoiceController.ts +0 -26
  166. package/src/core.ts +0 -8
  167. package/src/plugin/fromRimori/PluginTypes.ts +0 -64
  168. package/src/types/Actions.ts +0 -6
  169. /package/dist/{core → components}/components/ContextMenu.d.ts +0 -0
  170. /package/dist/{plugin/fromRimori → fromRimori}/PluginTypes.js +0 -0
  171. /package/src/{plugin/fromRimori → fromRimori}/readme.md +0 -0
@@ -7,16 +7,15 @@ 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";
12
- import { SettingsController } from "../controller/SettingsController";
13
- import { SharedContentController } from "../controller/SharedContentController";
14
- import { getPlugins } from "../controller/SidePluginController";
15
- import { getSTTResponse, getTTSResponse } from "../controller/VoiceController";
10
+ import { generateText, streamChatGPT } from "../core/controller/AIController";
11
+ import { generateObject } from "../core/controller/ObjectController";
12
+ import { SettingsController } from "../core/controller/SettingsController";
13
+ import { SharedContentController } from "../core/controller/SharedContentController";
14
+ import { getSTTResponse, getTTSResponse } from "../core/controller/VoiceController";
15
+ import { EventBus } from "../fromRimori/EventBus";
16
16
  import { AccomplishmentHandler } from "./AccomplishmentHandler";
17
- import { EventBus } from "./fromRimori/EventBus";
18
17
  export class RimoriClient {
19
- constructor(options) {
18
+ constructor(supabase, info, pluginController) {
20
19
  this.event = {
21
20
  /**
22
21
  * Emit an event to Rimori or a plugin.
@@ -46,11 +45,11 @@ export class RimoriClient {
46
45
  * Subscribe to an event.
47
46
  * @param topic The topic to subscribe to.
48
47
  * @param callback The callback to call when the event is emitted.
49
- * @returns The unsubscribe ids.
48
+ * @returns An EventListener object containing an off() method to unsubscribe the listeners.
50
49
  */
51
50
  on: (topic, callback) => {
52
51
  const topics = Array.isArray(topic) ? topic : [topic];
53
- return topics.map(topic => EventBus.on(this.pluginController.getGlobalEventTopic(topic), callback));
52
+ return EventBus.on(topics.map(t => this.pluginController.getGlobalEventTopic(t)), callback);
54
53
  },
55
54
  /**
56
55
  * Subscribe to an event once.
@@ -66,7 +65,8 @@ export class RimoriClient {
66
65
  * @param data The data to respond with.
67
66
  */
68
67
  respond: (topic, data) => {
69
- EventBus.respond(this.plugin.pluginId, this.pluginController.getGlobalEventTopic(topic), data);
68
+ const topics = Array.isArray(topic) ? topic : [topic];
69
+ EventBus.respond(this.plugin.pluginId, topics.map(t => this.pluginController.getGlobalEventTopic(t)), data);
70
70
  },
71
71
  /**
72
72
  * Emit an accomplishment.
@@ -90,31 +90,48 @@ export class RimoriClient {
90
90
  * @param text Optional text to be used for the action like for example text that the translator would look up.
91
91
  */
92
92
  emitSidebarAction: (pluginId, actionKey, text) => {
93
- this.event.emit("global.sidebar.triggerAction", { pluginId, actionKey, text });
93
+ this.event.emit("global.sidebar.triggerAction", { plugin_id: pluginId, action_key: actionKey, text });
94
+ },
95
+ onMainPanelAction: (callback) => {
96
+ // this needs to be a emit and on because the main panel action is triggered by the user and not by the plugin
97
+ this.event.emit("action.requestMain");
98
+ this.event.on("action.requestMain", ({ data }) => callback(data));
94
99
  }
95
100
  };
96
- this.llm = {
101
+ this.navigation = {
102
+ toDashboard: () => {
103
+ this.event.emit("global.navigation.triggerToDashboard");
104
+ }
105
+ };
106
+ this.ai = {
97
107
  getText: (messages, tools) => __awaiter(this, void 0, void 0, function* () {
98
108
  const token = yield this.pluginController.getToken();
99
- return generateText(this.supabaseUrl, messages, tools || [], token).then(({ messages }) => messages[0].content[0].text);
109
+ return generateText(this.pluginController.getBackendUrl(), messages, tools || [], token).then(({ messages }) => messages[0].content[0].text);
100
110
  }),
101
111
  getSteamedText: (messages, onMessage, tools) => __awaiter(this, void 0, void 0, function* () {
102
112
  const token = yield this.pluginController.getToken();
103
- streamChatGPT(this.supabaseUrl, messages, tools || [], onMessage, token);
113
+ streamChatGPT(this.pluginController.getBackendUrl(), messages, tools || [], onMessage, token);
104
114
  }),
105
115
  getVoice: (text_1, ...args_1) => __awaiter(this, [text_1, ...args_1], void 0, function* (text, voice = "alloy", speed = 1, language) {
106
116
  const token = yield this.pluginController.getToken();
107
- return getTTSResponse(this.supabaseUrl, { input: text, voice, speed, language }, token);
117
+ return getTTSResponse(this.pluginController.getBackendUrl(), { input: text, voice, speed, language }, token);
118
+ }),
119
+ getTextFromVoice: (file) => __awaiter(this, void 0, void 0, function* () {
120
+ const token = yield this.pluginController.getToken();
121
+ return getSTTResponse(this.pluginController.getBackendUrl(), file, token);
108
122
  }),
109
- getTextFromVoice: (file) => {
110
- return getSTTResponse(this.superbase, file);
111
- },
112
123
  getObject: (request) => __awaiter(this, void 0, void 0, function* () {
113
124
  const token = yield this.pluginController.getToken();
114
- return generateObjectFunction(this.supabaseUrl, request, token);
125
+ return generateObject(this.pluginController.getBackendUrl(), request, token);
115
126
  }),
116
127
  // getSteamedObject: this.generateObjectStream,
117
128
  };
129
+ this.runtime = {
130
+ fetchBackend: (url, options) => __awaiter(this, void 0, void 0, function* () {
131
+ const token = yield this.pluginController.getToken();
132
+ return fetch(this.pluginController.getBackendUrl() + url, Object.assign(Object.assign({}, options), { headers: Object.assign(Object.assign({}, options.headers), { 'Authorization': `Bearer ${token}` }) }));
133
+ })
134
+ };
118
135
  this.community = {
119
136
  /**
120
137
  * Shared content is a way to share completable content with other users using this plugin.
@@ -146,11 +163,15 @@ export class RimoriClient {
146
163
  * @param contentType The type of shared content to fetch. E.g. assignments, exercises, etc.
147
164
  * @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
165
  * @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.
166
+ * @param options An optional object with options for the new shared content.
167
+ * @param options.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.
168
+ * @param options.skipDbSave An optional flag to indicate if the new shared content should not be saved to the database. This is useful if the new shared content is not meant to be saved to the database.
169
+ * @param options.alwaysGenerateNew An optional flag to indicate if the new shared content should always be generated even if there is already a content with the same filter. This is useful if the new shared content is not meant to be saved to the database.
170
+ * @param options.excludeIds An optional list of ids to exclude from the selection. This is useful if the new shared content is not meant to be saved to the database.
150
171
  * @returns The new shared content.
151
172
  */
152
- getNew: (contentType, generatorInstructions, filter, privateTopic) => __awaiter(this, void 0, void 0, function* () {
153
- return yield this.sharedContentController.getNewSharedContent(contentType, generatorInstructions, filter, privateTopic);
173
+ getNew: (contentType, generatorInstructions, filter, options) => __awaiter(this, void 0, void 0, function* () {
174
+ return yield this.sharedContentController.getNewSharedContent(contentType, generatorInstructions, filter, options);
154
175
  }),
155
176
  /**
156
177
  * Create a new shared content item.
@@ -177,6 +198,14 @@ export class RimoriClient {
177
198
  complete: (contentType, assignmentId) => __awaiter(this, void 0, void 0, function* () {
178
199
  return yield this.sharedContentController.completeSharedContent(contentType, assignmentId);
179
200
  }),
201
+ /**
202
+ /**
203
+ * Update the state of a shared content item for a specific user.
204
+ * Useful for marking content as completed, ongoing, hidden, liked, disliked, or bookmarked.
205
+ */
206
+ updateState: (params) => __awaiter(this, void 0, void 0, function* () {
207
+ return yield this.sharedContentController.updateSharedContentState(params);
208
+ }),
180
209
  /**
181
210
  * Remove a shared content item.
182
211
  * @param id The id of the shared content item to remove.
@@ -187,41 +216,53 @@ export class RimoriClient {
187
216
  })
188
217
  }
189
218
  };
190
- this.superbase = options.supabase;
191
- this.pluginController = options.pluginController;
192
- this.settingsController = new SettingsController(options.supabase, options.pluginId);
219
+ this.rimoriInfo = info;
220
+ this.superbase = supabase;
221
+ this.pluginController = pluginController;
222
+ this.settingsController = new SettingsController(supabase, info.pluginId);
193
223
  this.sharedContentController = new SharedContentController(this.superbase, this);
194
- this.supabaseUrl = this.pluginController.getSupabaseUrl();
195
- this.accomplishmentHandler = new AccomplishmentHandler(options.pluginId);
224
+ this.accomplishmentHandler = new AccomplishmentHandler(info.pluginId);
196
225
  this.from = this.from.bind(this);
197
226
  this.db = {
198
227
  from: this.from,
199
- storage: this.superbase.storage,
228
+ // storage: this.superbase.storage,
200
229
  // functions: this.superbase.functions,
201
- tablePrefix: options.tablePrefix,
230
+ tablePrefix: info.tablePrefix,
202
231
  getTableName: this.getTableName.bind(this),
203
232
  };
204
233
  this.plugin = {
205
- pluginId: options.pluginId,
234
+ pluginId: info.pluginId,
206
235
  setSettings: (settings) => __awaiter(this, void 0, void 0, function* () {
207
236
  yield this.settingsController.setSettings(settings);
208
237
  }),
209
238
  getSettings: (defaultSettings) => __awaiter(this, void 0, void 0, function* () {
210
239
  return yield this.settingsController.getSettings(defaultSettings);
211
240
  }),
212
- getInstalled: () => __awaiter(this, void 0, void 0, function* () {
213
- return getPlugins(this.superbase);
214
- }),
215
- getUserInfo: () => __awaiter(this, void 0, void 0, function* () {
216
- return this.settingsController.getUserInfo();
217
- })
241
+ getUserInfo: () => {
242
+ return this.rimoriInfo.profile;
243
+ },
244
+ getPluginInfo: () => {
245
+ return {
246
+ installedPlugins: this.rimoriInfo.installedPlugins,
247
+ mainPanelPlugin: this.rimoriInfo.mainPanelPlugin,
248
+ sidePanelPlugin: this.rimoriInfo.sidePanelPlugin,
249
+ };
250
+ }
218
251
  };
219
252
  }
253
+ /**
254
+ * Get a query parameter value that was passed via MessageChannel
255
+ * @param key The query parameter key
256
+ * @returns The query parameter value or null if not found
257
+ */
258
+ getQueryParam(key) {
259
+ return this.pluginController.getQueryParam(key);
260
+ }
220
261
  static getInstance(pluginController) {
221
262
  return __awaiter(this, void 0, void 0, function* () {
222
263
  if (!RimoriClient.instance) {
223
- const { supabase, tablePrefix, pluginId } = yield pluginController.getClient();
224
- RimoriClient.instance = new RimoriClient({ pluginController, supabase, tablePrefix, pluginId });
264
+ const client = yield pluginController.getClient();
265
+ RimoriClient.instance = new RimoriClient(client.supabase, client.info, pluginController);
225
266
  }
226
267
  return RimoriClient.instance;
227
268
  });
@@ -229,7 +270,13 @@ export class RimoriClient {
229
270
  from(relation) {
230
271
  return this.superbase.from(this.getTableName(relation));
231
272
  }
232
- getTableName(type) {
233
- return this.db.tablePrefix + "_" + type;
273
+ getTableName(table) {
274
+ if (/[A-Z]/.test(table)) {
275
+ throw new Error("Table name cannot include uppercase letters. Please use snake_case for table names.");
276
+ }
277
+ if (table.startsWith("global_")) {
278
+ return table.replace("global_", "");
279
+ }
280
+ return this.db.tablePrefix + "_" + table;
234
281
  }
235
282
  }
@@ -2,6 +2,7 @@ import { SupabaseClient } from "@supabase/supabase-js";
2
2
  export interface StandaloneConfig {
3
3
  url: string;
4
4
  key: string;
5
+ backendUrl?: string;
5
6
  }
6
7
  export declare class StandaloneClient {
7
8
  private static instance;
@@ -7,8 +7,9 @@ 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 { EventBus } from "./fromRimori/EventBus";
11
10
  import { createClient } from "@supabase/supabase-js";
11
+ import { EventBus } from "../fromRimori/EventBus";
12
+ import { DEFAULT_ANON_KEY, DEFAULT_ENDPOINT } from "../utils/endpoint";
12
13
  export class StandaloneClient {
13
14
  constructor(config) {
14
15
  this.supabase = createClient(config.url, config.key);
@@ -17,14 +18,14 @@ export class StandaloneClient {
17
18
  static getInstance() {
18
19
  return __awaiter(this, void 0, void 0, function* () {
19
20
  if (!StandaloneClient.instance) {
20
- const config = yield fetch("http://localhost:3000/config.json").then(res => res.json()).catch(err => {
21
+ const config = yield fetch("https://app.rimori.se/config.json").then(res => res.json()).catch(err => {
21
22
  console.warn("Error fetching config.json, using default values", err);
22
- return {
23
- SUPABASE_URL: "https://pheptqdoqsdnadgoihvr.supabase.co",
24
- SUPABASE_ANON_KEY: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBoZXB0cWRvcXNkbmFkZ29paHZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzE2OTY2ODcsImV4cCI6MjA0NzI3MjY4N30.4GPFAXTF8685FaXISdAPNCIM-H3RGLo8GbyhQpu1mP0",
25
- };
26
23
  });
27
- StandaloneClient.instance = new StandaloneClient({ url: config.SUPABASE_URL, key: config.SUPABASE_ANON_KEY });
24
+ StandaloneClient.instance = new StandaloneClient({
25
+ url: (config === null || config === void 0 ? void 0 : config.SUPABASE_URL) || DEFAULT_ENDPOINT,
26
+ key: (config === null || config === void 0 ? void 0 : config.SUPABASE_ANON_KEY) || DEFAULT_ANON_KEY,
27
+ backendUrl: (config === null || config === void 0 ? void 0 : config.BACKEND_URL) || 'https://api.rimori.se',
28
+ });
28
29
  }
29
30
  return StandaloneClient.instance;
30
31
  });
@@ -61,15 +62,28 @@ export class StandaloneClient {
61
62
  var _a;
62
63
  const session = yield supabase.auth.getSession();
63
64
  console.log("session", session);
64
- const { data, error } = yield supabase.functions.invoke("plugin-token", { headers: { authorization: `Bearer ${(_a = session.data.session) === null || _a === void 0 ? void 0 : _a.access_token}` } });
65
- if (error) {
66
- throw new Error("Failed to get plugin token. " + error.message);
65
+ // Call the NestJS backend endpoint instead of the Supabase edge function
66
+ const response = yield fetch(`${config.backendUrl}/plugin/token`, {
67
+ method: 'POST',
68
+ headers: {
69
+ 'Content-Type': 'application/json',
70
+ 'Authorization': `Bearer ${(_a = session.data.session) === null || _a === void 0 ? void 0 : _a.access_token}`
71
+ },
72
+ body: JSON.stringify({
73
+ pluginId: pluginId
74
+ })
75
+ });
76
+ if (!response.ok) {
77
+ const errorText = yield response.text();
78
+ throw new Error(`Failed to get plugin token. ${response.status}: ${errorText}`);
67
79
  }
80
+ const data = yield response.json();
68
81
  return {
69
82
  token: data.token,
70
83
  pluginId: pluginId,
71
84
  url: config.url,
72
85
  key: config.key,
86
+ backendUrl: config.backendUrl,
73
87
  tablePrefix: pluginId,
74
88
  expiration: new Date(Date.now() + 1000 * 60 * 60 * 1.5), // 1.5 hours
75
89
  };
@@ -1 +1,2 @@
1
- export declare function setTheme(): void;
1
+ export declare function setTheme(theme?: string | null): void;
2
+ export declare function isDarkTheme(theme?: string | null): boolean;
@@ -1,13 +1,19 @@
1
- export function setTheme() {
2
- const urlParams = new URLSearchParams(window.location.search);
3
- let theme = urlParams.get('theme');
4
- if (!theme || theme === 'system') {
5
- theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
6
- }
1
+ export function setTheme(theme) {
7
2
  document.documentElement.classList.add("dark:text-gray-200");
8
- if (theme === 'dark') {
3
+ if (isDarkTheme(theme)) {
9
4
  document.documentElement.setAttribute("data-theme", "dark");
10
5
  document.documentElement.classList.add('dark', "dark:bg-gray-950");
11
6
  document.documentElement.style.background = "hsl(var(--background))";
12
7
  }
13
8
  }
9
+ export function isDarkTheme(theme) {
10
+ // If no theme provided, try to get from URL as fallback (for standalone mode)
11
+ if (!theme) {
12
+ const urlParams = new URLSearchParams(window.location.search);
13
+ theme = urlParams.get('theme');
14
+ }
15
+ if (!theme || theme === 'system') {
16
+ return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
17
+ }
18
+ return theme === 'dark';
19
+ }
@@ -3,7 +3,10 @@ import { RimoriClient } from '../plugin/RimoriClient';
3
3
  interface PluginProviderProps {
4
4
  children: ReactNode;
5
5
  pluginId: string;
6
+ settings?: {
7
+ disableContextMenu?: boolean;
8
+ };
6
9
  }
7
10
  export declare const PluginProvider: React.FC<PluginProviderProps>;
8
- export declare const usePlugin: () => RimoriClient;
11
+ export declare const useRimori: () => RimoriClient;
9
12
  export {};
@@ -10,34 +10,47 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  import { createContext, useContext, useEffect, useState } from 'react';
12
12
  import { PluginController } from '../plugin/PluginController';
13
- import { EventBusHandler } from '../plugin/fromRimori/EventBus';
14
- import ContextMenu from '../core/components/ContextMenu';
13
+ import { EventBusHandler } from '../fromRimori/EventBus';
14
+ import ContextMenu from '../components/components/ContextMenu';
15
15
  import { StandaloneClient } from '../plugin/StandaloneClient';
16
16
  const PluginContext = createContext(null);
17
- export const PluginProvider = ({ children, pluginId }) => {
17
+ export const PluginProvider = ({ children, pluginId, settings }) => {
18
18
  const [plugin, setPlugin] = useState(null);
19
19
  const [standaloneClient, setStandaloneClient] = useState(false);
20
+ const [applicationMode, setApplicationMode] = useState(null);
21
+ const [theme, setTheme] = useState(null);
22
+ const isSidebar = applicationMode === "sidebar";
23
+ const isSettings = applicationMode === "settings";
20
24
  useEffect(() => {
21
25
  initEventBus(pluginId);
22
- const standaloneDetected = new URLSearchParams(window.location.search).get("secret") === null;
26
+ // Check if we're in an iframe context - if not, we're standalone
27
+ const standaloneDetected = window === window.parent;
23
28
  if (standaloneDetected && !standaloneClient) {
24
29
  StandaloneClient.getInstance().then(client => {
25
30
  client.needsLogin().then((needLogin) => setStandaloneClient(needLogin ? client : true));
26
31
  });
27
32
  }
28
33
  if ((!standaloneDetected && !plugin) || (standaloneDetected && standaloneClient === true)) {
29
- PluginController.getInstance(pluginId, standaloneDetected).then(setPlugin);
34
+ PluginController.getInstance(pluginId, standaloneDetected).then(client => {
35
+ setPlugin(client);
36
+ // Get applicationMode and theme from MessageChannel query params
37
+ if (!standaloneDetected) {
38
+ const mode = client.getQueryParam("applicationMode");
39
+ const themeParam = client.getQueryParam("rm_theme");
40
+ setApplicationMode(mode);
41
+ setTheme(themeParam);
42
+ }
43
+ });
30
44
  }
31
45
  }, [pluginId, standaloneClient]);
32
46
  //route change
33
47
  useEffect(() => {
34
48
  if (!plugin)
35
49
  return;
36
- const url = new URL(window.location.href);
37
50
  //sidebar pages should not report url changes
38
- if (url.searchParams.get("applicationMode") === "sidebar")
51
+ if (isSidebar)
39
52
  return;
40
- let lastHash = url.hash;
53
+ let lastHash = window.location.hash;
41
54
  const emitUrlChange = (url) => plugin.event.emit('session.triggerUrlChange', { url });
42
55
  const interval = setInterval(() => {
43
56
  if (lastHash === window.location.hash)
@@ -66,18 +79,31 @@ export const PluginProvider = ({ children, pluginId }) => {
66
79
  if (!plugin) {
67
80
  return "";
68
81
  }
69
- return (_jsxs(PluginContext.Provider, { value: plugin, children: [_jsx(ContextMenu, { client: plugin }), children] }));
82
+ return (_jsxs(PluginContext.Provider, { value: plugin, children: [!(settings === null || settings === void 0 ? void 0 : settings.disableContextMenu) && !isSidebar && !isSettings && _jsx(ContextMenu, { client: plugin }), children] }));
70
83
  };
71
- export const usePlugin = () => {
84
+ export const useRimori = () => {
72
85
  const context = useContext(PluginContext);
73
86
  if (context === null) {
74
- throw new Error('usePlugin must be used within an PluginProvider');
87
+ throw new Error('useRimori must be used within an PluginProvider');
75
88
  }
76
89
  return context;
77
90
  };
78
- function initEventBus(pluginId) {
91
+ function getUrlParam(name) {
92
+ // First try to get from URL hash query params (for compatibility)
93
+ const hashParts = window.location.hash.split('?');
94
+ if (hashParts.length > 1) {
95
+ const hashParams = new URLSearchParams(hashParts[1]);
96
+ const hashValue = hashParams.get(name);
97
+ if (hashValue)
98
+ return hashValue;
99
+ }
100
+ // Fallback to regular URL search params
79
101
  const url = new URL(window.location.href);
80
- const isSidebar = url.searchParams.get("applicationMode") === "sidebar";
102
+ return url.searchParams.get(name);
103
+ }
104
+ function initEventBus(pluginId) {
105
+ // For now, use URL fallback for EventBus naming - this will be updated once MessageChannel is ready
106
+ const isSidebar = getUrlParam("applicationMode") === "sidebar";
81
107
  EventBusHandler.getInstance("Plugin EventBus " + pluginId + " " + (isSidebar ? "sidebar" : "main"));
82
108
  }
83
109
  function StandaloneAuth({ onLogin }) {
@@ -61,6 +61,7 @@ export type Language = keyof typeof languageKeys;
61
61
  /**
62
62
  * Get the language name from the language code
63
63
  * @param languageCode The code of the language
64
+ * @param capitalize Whether to capitalize the first letter of the language name
64
65
  * @returns The language name
65
66
  */
66
- export declare function getLanguageName(languageCode: Language): string;
67
+ export declare function getLanguageName(languageCode: Language, capitalize?: boolean): string;
@@ -60,8 +60,10 @@ export const languageKeys = {
60
60
  /**
61
61
  * Get the language name from the language code
62
62
  * @param languageCode The code of the language
63
+ * @param capitalize Whether to capitalize the first letter of the language name
63
64
  * @returns The language name
64
65
  */
65
- export function getLanguageName(languageCode) {
66
- return languageKeys[languageCode];
66
+ export function getLanguageName(languageCode, capitalize = false) {
67
+ const lang = languageKeys[languageCode];
68
+ return capitalize ? lang.charAt(0).toUpperCase() + lang.slice(1) : lang;
67
69
  }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Maps audio MIME types to their corresponding file extensions
3
+ * OpenAI supports: mp3, mp4, mpeg, mpga, m4a, wav, webm
4
+ */
5
+ export declare const AUDIO_MIME_TO_EXTENSION: Record<string, string>;
6
+ /**
7
+ * OpenAI supported audio formats for STT API
8
+ */
9
+ export declare const OPENAI_SUPPORTED_FORMATS: string[];
10
+ /**
11
+ * Determines the appropriate file extension for an audio MIME type
12
+ * @param mimeType - The MIME type of the audio
13
+ * @returns The file extension (without dot) or null if unsupported
14
+ */
15
+ export declare function getAudioFormatFromMimeType(mimeType: string): string | null;
16
+ /**
17
+ * Checks if an audio MIME type is supported by OpenAI
18
+ * @param mimeType - The MIME type to check
19
+ * @returns True if supported, false otherwise
20
+ */
21
+ export declare function isAudioFormatSupported(mimeType: string): boolean;
22
+ /**
23
+ * Gets a human-readable list of supported audio formats
24
+ * @returns Formatted string of supported formats
25
+ */
26
+ export declare function getSupportedFormatsList(): string;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Maps audio MIME types to their corresponding file extensions
3
+ * OpenAI supports: mp3, mp4, mpeg, mpga, m4a, wav, webm
4
+ */
5
+ export const AUDIO_MIME_TO_EXTENSION = {
6
+ 'audio/mpeg': 'mp3',
7
+ 'audio/mp3': 'mp3',
8
+ 'audio/mp4': 'mp4',
9
+ 'audio/m4a': 'm4a',
10
+ 'audio/wav': 'wav',
11
+ 'audio/wave': 'wav',
12
+ 'audio/x-wav': 'wav',
13
+ 'audio/webm': 'webm',
14
+ 'audio/ogg': 'webm', // Convert ogg to webm for OpenAI compatibility
15
+ 'audio/aac': 'm4a', // Convert aac to m4a for OpenAI compatibility
16
+ 'audio/x-aac': 'm4a',
17
+ 'audio/3gpp': 'mp4', // Convert 3gpp to mp4
18
+ 'audio/3gpp2': 'mp4',
19
+ 'audio/amr': 'mp4', // Convert amr to mp4
20
+ 'audio/amr-wb': 'mp4',
21
+ 'audio/flac': 'wav', // Convert flac to wav
22
+ 'audio/x-flac': 'wav',
23
+ 'audio/opus': 'webm', // Convert opus to webm
24
+ 'audio/x-opus': 'webm',
25
+ };
26
+ /**
27
+ * OpenAI supported audio formats for STT API
28
+ */
29
+ export const OPENAI_SUPPORTED_FORMATS = ['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm'];
30
+ /**
31
+ * Determines the appropriate file extension for an audio MIME type
32
+ * @param mimeType - The MIME type of the audio
33
+ * @returns The file extension (without dot) or null if unsupported
34
+ */
35
+ export function getAudioFormatFromMimeType(mimeType) {
36
+ const normalizedMimeType = mimeType.toLowerCase();
37
+ // Try to get format from MIME type mapping first
38
+ let format = AUDIO_MIME_TO_EXTENSION[normalizedMimeType];
39
+ // If no mapping found, try to extract from MIME type
40
+ if (!format && normalizedMimeType.includes('audio/')) {
41
+ format = normalizedMimeType.replace('audio/', '');
42
+ }
43
+ // Handle special cases
44
+ if (format === 'mpeg') {
45
+ format = 'mp3'; // OpenAI expects mp3, not mpeg
46
+ }
47
+ // Validate the format
48
+ if (!format || !OPENAI_SUPPORTED_FORMATS.includes(format)) {
49
+ return null;
50
+ }
51
+ return format;
52
+ }
53
+ /**
54
+ * Checks if an audio MIME type is supported by OpenAI
55
+ * @param mimeType - The MIME type to check
56
+ * @returns True if supported, false otherwise
57
+ */
58
+ export function isAudioFormatSupported(mimeType) {
59
+ return getAudioFormatFromMimeType(mimeType) !== null;
60
+ }
61
+ /**
62
+ * Gets a human-readable list of supported audio formats
63
+ * @returns Formatted string of supported formats
64
+ */
65
+ export function getSupportedFormatsList() {
66
+ return OPENAI_SUPPORTED_FORMATS.join(', ');
67
+ }
@@ -6,5 +6,5 @@ export function getDifficultyLabel(difficulty) {
6
6
  return codes[difficulty];
7
7
  }
8
8
  export function getNeighborDifficultyLevel(difficulty, difficultyAdjustment) {
9
- return getDifficultyLabel(getDifficultyLevel(difficulty) + difficultyAdjustment);
9
+ return getDifficultyLabel(getDifficultyLevel(difficulty) + difficultyAdjustment - 1);
10
10
  }
@@ -0,0 +1,2 @@
1
+ export declare const DEFAULT_ENDPOINT = "https://pheptqdoqsdnadgoihvr.supabase.co";
2
+ export declare const DEFAULT_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBoZXB0cWRvcXNkbmFkZ29paHZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzE2OTY2ODcsImV4cCI6MjA0NzI3MjY4N30.4GPFAXTF8685FaXISdAPNCIM-H3RGLo8GbyhQpu1mP0";
@@ -0,0 +1,2 @@
1
+ export const DEFAULT_ENDPOINT = "https://pheptqdoqsdnadgoihvr.supabase.co";
2
+ export const DEFAULT_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBoZXB0cWRvcXNkbmFkZ29paHZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzE2OTY2ODcsImV4cCI6MjA0NzI3MjY4N30.4GPFAXTF8685FaXISdAPNCIM-H3RGLo8GbyhQpu1mP0";
@@ -1,6 +1,7 @@
1
1
  import { RimoriClient } from "../plugin/RimoriClient";
2
2
  /**
3
3
  * Sets up the web worker for the plugin to be able receive and send messages to Rimori.
4
- * @param init - The function containing the subscription logic.
4
+ * @param pluginId - The id of the plugin to setup the worker for.
5
+ * @param init - The function containing the initialization logic.
5
6
  */
6
- export declare function setupWorker(init: (controller: RimoriClient) => void | Promise<void>): void;
7
+ export declare function setupWorker(pluginId: string, init: (client: RimoriClient) => void | Promise<void>): Promise<void>;