@rimori/client 1.1.10 → 1.2.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 (151) hide show
  1. package/README.md +128 -45
  2. package/dist/cli/scripts/init/dev-registration.d.ts +35 -0
  3. package/dist/cli/scripts/init/dev-registration.js +175 -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 +159 -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/ai/Assistant.js +4 -4
  31. package/dist/components/ai/Avatar.d.ts +3 -2
  32. package/dist/components/ai/Avatar.js +10 -5
  33. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +1 -1
  34. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.d.ts +1 -0
  35. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +12 -6
  36. package/dist/components/ai/utils.js +0 -1
  37. package/dist/components/audio/Playbutton.js +3 -3
  38. package/dist/{core → components}/components/ContextMenu.js +2 -2
  39. package/dist/components.d.ts +5 -5
  40. package/dist/components.js +5 -5
  41. package/dist/core/controller/AIController.d.ts +15 -0
  42. package/dist/core/controller/AIController.js +120 -0
  43. package/dist/{controller → core/controller}/ObjectController.d.ts +8 -0
  44. package/dist/{controller → core/controller}/SettingsController.d.ts +12 -4
  45. package/dist/{controller → core/controller}/SettingsController.js +0 -25
  46. package/dist/{controller → core/controller}/SharedContentController.d.ts +1 -1
  47. package/dist/{controller → core/controller}/SharedContentController.js +4 -4
  48. package/dist/core/core.d.ts +13 -0
  49. package/dist/core/core.js +8 -0
  50. package/dist/{plugin/fromRimori → fromRimori}/EventBus.d.ts +3 -3
  51. package/dist/{plugin/fromRimori → fromRimori}/EventBus.js +25 -8
  52. package/dist/fromRimori/PluginTypes.d.ts +171 -0
  53. package/dist/hooks/UseChatHook.d.ts +2 -1
  54. package/dist/hooks/UseChatHook.js +3 -3
  55. package/dist/index.d.ts +5 -3
  56. package/dist/index.js +4 -3
  57. package/dist/plugin/AccomplishmentHandler.d.ts +1 -1
  58. package/dist/plugin/AccomplishmentHandler.js +1 -1
  59. package/dist/plugin/PluginController.d.ts +16 -3
  60. package/dist/plugin/PluginController.js +24 -18
  61. package/dist/plugin/RimoriClient.d.ts +16 -11
  62. package/dist/plugin/RimoriClient.js +35 -25
  63. package/dist/plugin/StandaloneClient.js +11 -8
  64. package/dist/plugin/ThemeSetter.d.ts +1 -0
  65. package/dist/plugin/ThemeSetter.js +9 -6
  66. package/dist/providers/PluginProvider.d.ts +3 -0
  67. package/dist/providers/PluginProvider.js +4 -4
  68. package/dist/utils/Language.d.ts +2 -1
  69. package/dist/utils/Language.js +4 -2
  70. package/dist/utils/difficultyConverter.js +1 -1
  71. package/dist/utils/endpoint.d.ts +2 -0
  72. package/dist/utils/endpoint.js +2 -0
  73. package/dist/worker/WorkerSetup.js +3 -1
  74. package/example/docs/devdocs.md +231 -0
  75. package/example/docs/overview.md +29 -0
  76. package/example/docs/userdocs.md +123 -0
  77. package/example/rimori.config.ts +89 -0
  78. package/example/worker/vite.config.ts +23 -0
  79. package/example/worker/worker.ts +11 -0
  80. package/package.json +15 -9
  81. package/src/cli/scripts/init/dev-registration.ts +193 -0
  82. package/src/cli/scripts/init/env-setup.ts +44 -0
  83. package/src/cli/scripts/init/file-operations.ts +58 -0
  84. package/src/cli/scripts/init/html-cleaner.ts +48 -0
  85. package/src/cli/scripts/init/main.ts +171 -0
  86. package/src/cli/scripts/init/package-setup.ts +117 -0
  87. package/src/cli/scripts/init/router-transformer.ts +329 -0
  88. package/src/cli/scripts/init/tailwind-config.ts +75 -0
  89. package/src/cli/scripts/init/vite-config.ts +73 -0
  90. package/src/cli/scripts/release/release-config-upload.ts +114 -0
  91. package/src/cli/scripts/release/release-db-update.ts +97 -0
  92. package/src/cli/scripts/release/release-file-upload.ts +138 -0
  93. package/src/cli/scripts/release/release.ts +69 -0
  94. package/src/cli/types/DatabaseTypes.ts +117 -0
  95. package/src/components/ai/Assistant.tsx +4 -4
  96. package/src/components/ai/Avatar.tsx +24 -7
  97. package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +1 -1
  98. package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +16 -8
  99. package/src/components/ai/utils.ts +0 -2
  100. package/src/components/audio/Playbutton.tsx +3 -3
  101. package/src/{core → components}/components/ContextMenu.tsx +3 -3
  102. package/src/components.ts +6 -6
  103. package/src/core/controller/AIController.ts +122 -0
  104. package/src/core/controller/ObjectController.ts +115 -0
  105. package/src/{controller → core/controller}/SettingsController.ts +13 -29
  106. package/src/{controller → core/controller}/SharedContentController.ts +5 -5
  107. package/src/core/core.ts +15 -0
  108. package/src/{plugin/fromRimori → fromRimori}/EventBus.ts +28 -10
  109. package/src/fromRimori/PluginTypes.ts +203 -0
  110. package/src/hooks/UseChatHook.ts +5 -4
  111. package/src/index.ts +5 -3
  112. package/src/plugin/AccomplishmentHandler.ts +1 -1
  113. package/src/plugin/PluginController.ts +35 -23
  114. package/src/plugin/RimoriClient.ts +42 -35
  115. package/src/plugin/StandaloneClient.ts +11 -8
  116. package/src/plugin/ThemeSetter.ts +12 -8
  117. package/src/providers/PluginProvider.tsx +7 -4
  118. package/src/utils/Language.ts +4 -2
  119. package/src/utils/difficultyConverter.ts +3 -3
  120. package/src/utils/endpoint.ts +2 -0
  121. package/src/worker/WorkerSetup.ts +4 -2
  122. package/dist/components/PluginController.d.ts +0 -21
  123. package/dist/components/PluginController.js +0 -116
  124. package/dist/controller/AIController.d.ts +0 -23
  125. package/dist/controller/AIController.js +0 -93
  126. package/dist/controller/SidePluginController.d.ts +0 -3
  127. package/dist/controller/SidePluginController.js +0 -31
  128. package/dist/core.d.ts +0 -7
  129. package/dist/core.js +0 -7
  130. package/dist/plugin/ContextMenu.d.ts +0 -17
  131. package/dist/plugin/ContextMenu.js +0 -45
  132. package/dist/plugin/fromRimori/PluginTypes.d.ts +0 -48
  133. package/dist/plugin/fromRimori/SupabaseHandler.d.ts +0 -13
  134. package/dist/plugin/fromRimori/SupabaseHandler.js +0 -55
  135. package/dist/providers/PluginController.d.ts +0 -21
  136. package/dist/providers/PluginController.js +0 -116
  137. package/dist/types/Actions.d.ts +0 -4
  138. package/dist/types/Actions.js +0 -1
  139. package/src/controller/AIController.ts +0 -112
  140. package/src/controller/ObjectController.ts +0 -107
  141. package/src/controller/SidePluginController.ts +0 -25
  142. package/src/core.ts +0 -8
  143. package/src/plugin/fromRimori/PluginTypes.ts +0 -64
  144. package/src/types/Actions.ts +0 -6
  145. /package/dist/{core → components}/components/ContextMenu.d.ts +0 -0
  146. /package/dist/{controller → core/controller}/ObjectController.js +0 -0
  147. /package/dist/{controller → core/controller}/VoiceController.d.ts +0 -0
  148. /package/dist/{controller → core/controller}/VoiceController.js +0 -0
  149. /package/dist/{plugin/fromRimori → fromRimori}/PluginTypes.js +0 -0
  150. /package/src/{controller → core/controller}/VoiceController.ts +0 -0
  151. /package/src/{plugin/fromRimori → fromRimori}/readme.md +0 -0
@@ -1,19 +1,24 @@
1
- import { AuthSessionMissingError, createClient, SupabaseClient } from '@supabase/supabase-js';
2
- import { EventBus, EventBusMessage } from './fromRimori/EventBus';
1
+ import { createClient, SupabaseClient } from '@supabase/supabase-js';
2
+ import { UserInfo } from '../core/controller/SettingsController';
3
+ import { EventBus, EventBusMessage } from '../fromRimori/EventBus';
4
+ import { Plugin } from '../fromRimori/PluginTypes';
3
5
  import { RimoriClient } from "./RimoriClient";
4
- import { setTheme } from './ThemeSetter';
5
6
  import { StandaloneClient } from './StandaloneClient';
7
+ import { setTheme } from './ThemeSetter';
6
8
 
7
9
  // Add declaration for WorkerGlobalScope
8
10
  declare const WorkerGlobalScope: any;
9
11
 
10
- interface SupabaseInfo {
12
+ export interface RimoriInfo {
11
13
  url: string,
12
14
  key: string,
15
+ backendUrl: string,
13
16
  token: string,
14
17
  expiration: Date,
15
18
  tablePrefix: string,
16
19
  pluginId: string
20
+ installedPlugins: Plugin[]
21
+ profile: UserInfo
17
22
  }
18
23
 
19
24
  export class PluginController {
@@ -21,7 +26,7 @@ export class PluginController {
21
26
  private static instance: PluginController;
22
27
  private communicationSecret: string | null = null;
23
28
  private supabase: SupabaseClient | null = null;
24
- private supabaseInfo: SupabaseInfo | null = null;
29
+ private rimoriInfo: RimoriInfo | null = null;
25
30
  private pluginId: string;
26
31
 
27
32
  private constructor(pluginId: string, standalone: boolean) {
@@ -34,7 +39,7 @@ export class PluginController {
34
39
 
35
40
  //no need to forward messages to parent in standalone mode
36
41
  if (standalone) return;
37
-
42
+
38
43
  window.addEventListener("message", (event) => {
39
44
  // console.log("client: message received", event);
40
45
  const { topic, sender, data, eventId } = event.data.event as EventBusMessage;
@@ -78,47 +83,54 @@ export class PluginController {
78
83
  return this.communicationSecret;
79
84
  }
80
85
 
81
- public async getClient(): Promise<{ supabase: SupabaseClient, tablePrefix: string, pluginId: string }> {
86
+ public async getClient(): Promise<{ supabase: SupabaseClient, info: RimoriInfo }> {
82
87
  if (
83
88
  this.supabase &&
84
- this.supabaseInfo &&
85
- this.supabaseInfo.expiration > new Date()
89
+ this.rimoriInfo &&
90
+ this.rimoriInfo.expiration > new Date()
86
91
  ) {
87
- return { supabase: this.supabase, tablePrefix: this.supabaseInfo.tablePrefix, pluginId: this.supabaseInfo.pluginId };
92
+ return { supabase: this.supabase, info: this.rimoriInfo };
88
93
  }
89
94
 
90
- const { data } = await EventBus.request<SupabaseInfo>(this.pluginId, "global.supabase.requestAccess");
91
- this.supabaseInfo = data;
92
- this.supabase = createClient(this.supabaseInfo.url, this.supabaseInfo.key, {
95
+ const { data } = await EventBus.request<RimoriInfo>(this.pluginId, "global.supabase.requestAccess");
96
+ this.rimoriInfo = data;
97
+ this.supabase = createClient(this.rimoriInfo.url, this.rimoriInfo.key, {
93
98
  accessToken: () => Promise.resolve(this.getToken())
94
99
  });
95
100
 
96
- return { supabase: this.supabase, tablePrefix: this.supabaseInfo.tablePrefix, pluginId: this.supabaseInfo.pluginId };
101
+ return { supabase: this.supabase, info: this.rimoriInfo };
97
102
  }
98
103
 
99
104
  public async getToken() {
100
- if (this.supabaseInfo && this.supabaseInfo.expiration && this.supabaseInfo.expiration > new Date()) {
101
- return this.supabaseInfo.token;
105
+ if (this.rimoriInfo && this.rimoriInfo.expiration && this.rimoriInfo.expiration > new Date()) {
106
+ return this.rimoriInfo.token;
102
107
  }
103
108
 
104
109
  const { data } = await EventBus.request<{ token: string, expiration: Date }>(this.pluginId, "global.supabase.requestAccess");
105
110
 
106
- if (!this.supabaseInfo) {
111
+ if (!this.rimoriInfo) {
107
112
  throw new Error("Supabase info not found");
108
113
  }
109
114
 
110
- this.supabaseInfo.token = data.token;
111
- this.supabaseInfo.expiration = data.expiration;
115
+ this.rimoriInfo.token = data.token;
116
+ this.rimoriInfo.expiration = data.expiration;
112
117
 
113
- return this.supabaseInfo.token;
118
+ return this.rimoriInfo.token;
114
119
  }
115
120
 
116
121
  public getSupabaseUrl() {
117
- if (!this.supabaseInfo) {
122
+ if (!this.rimoriInfo) {
118
123
  throw new Error("Supabase info not found");
119
124
  }
120
125
 
121
- return this.supabaseInfo.url;
126
+ return this.rimoriInfo.url;
127
+ }
128
+
129
+ public getBackendUrl() {
130
+ if (!this.rimoriInfo) {
131
+ throw new Error("Rimori info not found");
132
+ }
133
+ return this.rimoriInfo.backendUrl;
122
134
  }
123
135
 
124
136
  public getGlobalEventTopic(preliminaryTopic: string) {
@@ -138,7 +150,7 @@ export class PluginController {
138
150
  throw new Error(`The event topic must consist of 3 parts. <pluginId>.<topic area>.<action>. Received: ${preliminaryTopic}`);
139
151
  }
140
152
 
141
- const topicRoot = this.supabaseInfo?.pluginId ?? "global";
153
+ const topicRoot = this.rimoriInfo?.pluginId ?? "global";
142
154
  return `${topicRoot}.${preliminaryTopic}`;
143
155
  }
144
156
 
@@ -1,23 +1,16 @@
1
1
  import { PostgrestQueryBuilder } from "@supabase/postgrest-js";
2
2
  import { SupabaseClient } from "@supabase/supabase-js";
3
3
  import { GenericSchema } from "@supabase/supabase-js/dist/module/lib/types";
4
- import { generateText, Message, OnLLMResponse, streamChatGPT, Tool } from "../controller/AIController";
5
- import { generateObject as generateObjectFunction, ObjectRequest } from "../controller/ObjectController";
6
- import { SettingsController, UserInfo } from "../controller/SettingsController";
7
- import { SharedContent, SharedContentController, SharedContentFilter, SharedContentObjectRequest } from "../controller/SharedContentController";
8
- import { getPlugins } from "../controller/SidePluginController";
9
- import { getSTTResponse, getTTSResponse } from "../controller/VoiceController";
4
+ import { generateText, Message, OnLLMResponse, streamChatGPT } from "../core/controller/AIController";
5
+ import { generateObject as generateObjectFunction, ObjectRequest } from "../core/controller/ObjectController";
6
+ import { SettingsController, UserInfo } from "../core/controller/SettingsController";
7
+ import { SharedContent, SharedContentController, SharedContentFilter, SharedContentObjectRequest } from "../core/controller/SharedContentController";
8
+ import { getSTTResponse, getTTSResponse } from "../core/controller/VoiceController";
9
+ import { EventBus, EventBusMessage, EventHandler, EventPayload } from "../fromRimori/EventBus";
10
+ import { Plugin, Tool } from "../fromRimori/PluginTypes";
10
11
  import { AccomplishmentHandler, AccomplishmentPayload } from "./AccomplishmentHandler";
11
- import { EventBus, EventBusMessage, EventHandler, EventPayload } from "./fromRimori/EventBus";
12
- import { Plugin } from "./fromRimori/PluginTypes";
13
- import { PluginController } from "./PluginController";
12
+ import { PluginController, RimoriInfo } from "./PluginController";
14
13
 
15
- interface RimoriClientOptions {
16
- pluginController: PluginController;
17
- supabase: SupabaseClient;
18
- tablePrefix: string;
19
- pluginId: string;
20
- }
21
14
 
22
15
  interface Db {
23
16
  from: {
@@ -66,16 +59,20 @@ export class RimoriClient {
66
59
  private sharedContentController: SharedContentController;
67
60
  private accomplishmentHandler: AccomplishmentHandler;
68
61
  private supabaseUrl: string;
69
- public db: Db;
62
+ private installedPlugins: Plugin[];
63
+ private profile: UserInfo;
70
64
  public plugin: PluginInterface;
65
+ public db: Db;
71
66
 
72
- private constructor(options: RimoriClientOptions) {
73
- this.superbase = options.supabase;
74
- this.pluginController = options.pluginController;
75
- this.settingsController = new SettingsController(options.supabase, options.pluginId);
67
+ private constructor(supabase: SupabaseClient, info: RimoriInfo, pluginController: PluginController) {
68
+ this.superbase = supabase;
69
+ this.pluginController = pluginController;
70
+ this.settingsController = new SettingsController(supabase, info.pluginId);
76
71
  this.sharedContentController = new SharedContentController(this.superbase, this);
77
72
  this.supabaseUrl = this.pluginController.getSupabaseUrl();
78
- this.accomplishmentHandler = new AccomplishmentHandler(options.pluginId);
73
+ this.accomplishmentHandler = new AccomplishmentHandler(info.pluginId);
74
+ this.installedPlugins = info.installedPlugins;
75
+ this.profile = info.profile;
79
76
 
80
77
  this.from = this.from.bind(this);
81
78
 
@@ -83,11 +80,11 @@ export class RimoriClient {
83
80
  from: this.from,
84
81
  storage: this.superbase.storage,
85
82
  // functions: this.superbase.functions,
86
- tablePrefix: options.tablePrefix,
83
+ tablePrefix: info.tablePrefix,
87
84
  getTableName: this.getTableName.bind(this),
88
85
  }
89
86
  this.plugin = {
90
- pluginId: options.pluginId,
87
+ pluginId: info.pluginId,
91
88
  setSettings: async (settings: any) => {
92
89
  await this.settingsController.setSettings(settings);
93
90
  },
@@ -95,10 +92,10 @@ export class RimoriClient {
95
92
  return await this.settingsController.getSettings<T>(defaultSettings);
96
93
  },
97
94
  getInstalled: async (): Promise<Plugin[]> => {
98
- return getPlugins(this.superbase);
95
+ return this.installedPlugins;
99
96
  },
100
97
  getUserInfo: async (): Promise<UserInfo> => {
101
- return this.settingsController.getUserInfo();
98
+ return this.profile;
102
99
  }
103
100
  }
104
101
  }
@@ -132,11 +129,11 @@ export class RimoriClient {
132
129
  * Subscribe to an event.
133
130
  * @param topic The topic to subscribe to.
134
131
  * @param callback The callback to call when the event is emitted.
135
- * @returns The unsubscribe ids.
132
+ * @returns An EventListener object containing an off() method to unsubscribe the listeners.
136
133
  */
137
134
  on: <T = EventPayload>(topic: string | string[], callback: EventHandler<T>) => {
138
135
  const topics = Array.isArray(topic) ? topic : [topic];
139
- return topics.map(topic => EventBus.on<T>(this.pluginController.getGlobalEventTopic(topic), callback));
136
+ return EventBus.on<T>(topics.map(t => this.pluginController.getGlobalEventTopic(t)), callback);
140
137
  },
141
138
  /**
142
139
  * Subscribe to an event once.
@@ -151,8 +148,9 @@ export class RimoriClient {
151
148
  * @param topic The topic to respond to.
152
149
  * @param data The data to respond with.
153
150
  */
154
- respond: <T = EventPayload>(topic: string, data: EventPayload | ((data: EventBusMessage<T>) => EventPayload | Promise<EventPayload>)) => {
155
- EventBus.respond(this.plugin.pluginId, this.pluginController.getGlobalEventTopic(topic), data);
151
+ respond: <T = EventPayload>(topic: string | string[], data: EventPayload | ((data: EventBusMessage<T>) => EventPayload | Promise<EventPayload>)) => {
152
+ const topics = Array.isArray(topic) ? topic : [topic];
153
+ EventBus.respond(this.plugin.pluginId, topics.map(t => this.pluginController.getGlobalEventTopic(t)), data);
156
154
  },
157
155
  /**
158
156
  * Emit an accomplishment.
@@ -176,14 +174,20 @@ export class RimoriClient {
176
174
  * @param text Optional text to be used for the action like for example text that the translator would look up.
177
175
  */
178
176
  emitSidebarAction: (pluginId: string, actionKey: string, text?: string) => {
179
- this.event.emit("global.sidebar.triggerAction", { pluginId, actionKey, text });
177
+ this.event.emit("global.sidebar.triggerAction", { plugin_id: pluginId, action_key: actionKey, text });
178
+ }
179
+ }
180
+
181
+ public navigation = {
182
+ toDashboard: () => {
183
+ this.event.emit("global.navigation.triggerToDashboard");
180
184
  }
181
185
  }
182
186
 
183
187
  public static async getInstance(pluginController: PluginController): Promise<RimoriClient> {
184
188
  if (!RimoriClient.instance) {
185
- const { supabase, tablePrefix, pluginId } = await pluginController.getClient();
186
- RimoriClient.instance = new RimoriClient({ pluginController, supabase, tablePrefix, pluginId });
189
+ const client = await pluginController.getClient();
190
+ RimoriClient.instance = new RimoriClient(client.supabase, client.info, pluginController);
187
191
  }
188
192
  return RimoriClient.instance;
189
193
  }
@@ -201,17 +205,20 @@ export class RimoriClient {
201
205
  }
202
206
 
203
207
  private getTableName(type: string) {
208
+ if (type.startsWith("global_")) {
209
+ return type.replace("global_", "");
210
+ }
204
211
  return this.db.tablePrefix + "_" + type;
205
212
  }
206
213
 
207
- public llm = {
214
+ public ai = {
208
215
  getText: async (messages: Message[], tools?: Tool[]): Promise<string> => {
209
216
  const token = await this.pluginController.getToken();
210
- return generateText(this.supabaseUrl, messages, tools || [], token).then(({ messages }) => messages[0].content[0].text);
217
+ return generateText(this.pluginController.getBackendUrl(), messages, tools || [], token).then(({ messages }) => messages[0].content[0].text);
211
218
  },
212
219
  getSteamedText: async (messages: Message[], onMessage: OnLLMResponse, tools?: Tool[]) => {
213
220
  const token = await this.pluginController.getToken();
214
- streamChatGPT(this.supabaseUrl, messages, tools || [], onMessage, token);
221
+ streamChatGPT(this.pluginController.getBackendUrl(), messages, tools || [], onMessage, token);
215
222
  },
216
223
  getVoice: async (text: string, voice = "alloy", speed = 1, language?: string): Promise<Blob> => {
217
224
  const token = await this.pluginController.getToken();
@@ -1,5 +1,6 @@
1
- import { EventBus } from "./fromRimori/EventBus";
2
1
  import { createClient, SupabaseClient } from "@supabase/supabase-js";
2
+ import { EventBus } from "../fromRimori/EventBus";
3
+ import { DEFAULT_ANON_KEY, DEFAULT_ENDPOINT } from "../utils/endpoint";
3
4
 
4
5
  export interface StandaloneConfig {
5
6
  url: string,
@@ -18,14 +19,13 @@ export class StandaloneClient {
18
19
 
19
20
  public static async getInstance(): Promise<StandaloneClient> {
20
21
  if (!StandaloneClient.instance) {
21
- const config = await fetch("http://localhost:3000/config.json").then(res => res.json()).catch(err => {
22
+ const config = await fetch("https://app.rimori.se/config.json").then(res => res.json()).catch(err => {
22
23
  console.warn("Error fetching config.json, using default values", err);
23
- return {
24
- SUPABASE_URL: "https://pheptqdoqsdnadgoihvr.supabase.co",
25
- SUPABASE_ANON_KEY: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBoZXB0cWRvcXNkbmFkZ29paHZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzE2OTY2ODcsImV4cCI6MjA0NzI3MjY4N30.4GPFAXTF8685FaXISdAPNCIM-H3RGLo8GbyhQpu1mP0",
26
- }
27
24
  });
28
- StandaloneClient.instance = new StandaloneClient({ url: config.SUPABASE_URL, key: config.SUPABASE_ANON_KEY });
25
+ StandaloneClient.instance = new StandaloneClient({
26
+ url: config?.SUPABASE_URL || DEFAULT_ENDPOINT,
27
+ key: config?.SUPABASE_ANON_KEY || DEFAULT_ANON_KEY,
28
+ });
29
29
  }
30
30
  return StandaloneClient.instance;
31
31
  }
@@ -58,7 +58,10 @@ export class StandaloneClient {
58
58
  EventBus.respond("standalone", "global.supabase.requestAccess", async () => {
59
59
  const session = await supabase.auth.getSession();
60
60
  console.log("session", session);
61
- const { data, error } = await supabase.functions.invoke("plugin-token", { headers: { authorization: `Bearer ${session.data.session?.access_token}` } });
61
+ const { data, error } = await supabase.functions.invoke("plugin-token", {
62
+ body: { pluginId },
63
+ headers: { authorization: `Bearer ${session.data.session?.access_token}` },
64
+ });
62
65
  if (error) {
63
66
  throw new Error("Failed to get plugin token. " + error.message);
64
67
  }
@@ -1,16 +1,20 @@
1
1
  export function setTheme() {
2
- const urlParams = new URLSearchParams(window.location.search);
3
-
4
- let theme = urlParams.get('theme');
5
- if (!theme || theme === 'system') {
6
- theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
7
- }
8
-
9
2
  document.documentElement.classList.add("dark:text-gray-200");
10
3
 
11
- if (theme === 'dark') {
4
+ if (isDarkTheme()) {
12
5
  document.documentElement.setAttribute("data-theme", "dark");
13
6
  document.documentElement.classList.add('dark', "dark:bg-gray-950");
14
7
  document.documentElement.style.background = "hsl(var(--background))";
15
8
  }
9
+ }
10
+
11
+ export function isDarkTheme(): boolean {
12
+ const urlParams = new URLSearchParams(window.location.search);
13
+
14
+ let theme = urlParams.get('theme');
15
+ if (!theme || theme === 'system') {
16
+ return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
17
+ }
18
+
19
+ return theme === 'dark';
16
20
  }
@@ -1,18 +1,21 @@
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 { EventBusHandler } from '../plugin/fromRimori/EventBus';
5
- import ContextMenu from '../core/components/ContextMenu';
4
+ import { EventBusHandler } from '../fromRimori/EventBus';
5
+ import ContextMenu from '../components/components/ContextMenu';
6
6
  import { StandaloneClient } from '../plugin/StandaloneClient';
7
7
 
8
8
  interface PluginProviderProps {
9
9
  children: ReactNode;
10
10
  pluginId: string;
11
+ settings?: {
12
+ disableContextMenu?: boolean;
13
+ }
11
14
  }
12
15
 
13
16
  const PluginContext = createContext<RimoriClient | null>(null);
14
17
 
15
- export const PluginProvider: React.FC<PluginProviderProps> = ({ children, pluginId }) => {
18
+ export const PluginProvider: React.FC<PluginProviderProps> = ({ children, pluginId, settings }) => {
16
19
  const [plugin, setPlugin] = useState<RimoriClient | null>(null);
17
20
  const [standaloneClient, setStandaloneClient] = useState<StandaloneClient | boolean>(false);
18
21
 
@@ -73,7 +76,7 @@ export const PluginProvider: React.FC<PluginProviderProps> = ({ children, plugin
73
76
 
74
77
  return (
75
78
  <PluginContext.Provider value={plugin}>
76
- <ContextMenu client={plugin} />
79
+ {!settings?.disableContextMenu && <ContextMenu client={plugin} />}
77
80
  {children}
78
81
  </PluginContext.Provider>
79
82
  );
@@ -63,8 +63,10 @@ export type Language = keyof typeof languageKeys;
63
63
  /**
64
64
  * Get the language name from the language code
65
65
  * @param languageCode The code of the language
66
+ * @param capitalize Whether to capitalize the first letter of the language name
66
67
  * @returns The language name
67
68
  */
68
- export function getLanguageName(languageCode: Language): string {
69
- return languageKeys[languageCode];
69
+ export function getLanguageName(languageCode: Language, capitalize: boolean = false): string {
70
+ const lang = languageKeys[languageCode];
71
+ return capitalize ? lang.charAt(0).toUpperCase() + lang.slice(1) : lang;
70
72
  }
@@ -3,13 +3,13 @@ const codes = ["Pre-A1", "A1", "A2", "B1", "B2", "C1", "C2", "Post-C2"];
3
3
  export type LanguageLevel = "Pre-A1" | "A1" | "A2" | "B1" | "B2" | "C1" | "C2" | "Post-C2";
4
4
 
5
5
  export function getDifficultyLevel(difficulty: LanguageLevel): number {
6
- return codes.indexOf(difficulty) + 1;
6
+ return codes.indexOf(difficulty) + 1;
7
7
  }
8
8
 
9
9
  export function getDifficultyLabel(difficulty: number): LanguageLevel {
10
- return codes[difficulty] as LanguageLevel;
10
+ return codes[difficulty] as LanguageLevel;
11
11
  }
12
12
 
13
13
  export function getNeighborDifficultyLevel(difficulty: LanguageLevel, difficultyAdjustment: number): LanguageLevel {
14
- return getDifficultyLabel(getDifficultyLevel(difficulty) + difficultyAdjustment);
14
+ return getDifficultyLabel(getDifficultyLevel(difficulty) + difficultyAdjustment - 1);
15
15
  }
@@ -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,6 @@
1
- import { RimoriClient } from "../plugin/RimoriClient";
1
+ import { EventBus, EventBusHandler, EventBusMessage } from "../fromRimori/EventBus";
2
2
  import { PluginController } from "../plugin/PluginController";
3
- import { EventBus, EventBusHandler, EventBusMessage } from "../plugin/fromRimori/EventBus";
3
+ import { RimoriClient } from "../plugin/RimoriClient";
4
4
 
5
5
  let controller: RimoriClient | null = null;
6
6
  const listeners: ((event: { data: { event: EventBusMessage, secret: string } }) => void)[] = [];
@@ -29,6 +29,7 @@ export function setupWorker(init: (controller: RimoriClient) => void | Promise<v
29
29
  APP_CONFIG: {
30
30
  SUPABASE_URL: 'NOT_SET',
31
31
  SUPABASE_ANON_KEY: 'NOT_SET',
32
+ BACKEND_URL: 'NOT_SET',
32
33
  },
33
34
  };
34
35
 
@@ -48,6 +49,7 @@ export function setupWorker(init: (controller: RimoriClient) => void | Promise<v
48
49
  if (!controller) {
49
50
  mockWindow.APP_CONFIG.SUPABASE_URL = event.data.supabaseUrl;
50
51
  mockWindow.APP_CONFIG.SUPABASE_ANON_KEY = event.data.supabaseAnonKey;
52
+ mockWindow.APP_CONFIG.BACKEND_URL = event.data.backendUrl;
51
53
  controller = await PluginController.getInstance(event.data.pluginId);
52
54
  logIfDebug('Worker initialized.');
53
55
  await init(controller);
@@ -1,21 +0,0 @@
1
- import { SupabaseClient } from '@supabase/supabase-js';
2
- import { RimoriClient } from "../plugin/RimoriClient";
3
- export declare class PluginController {
4
- private static client;
5
- private static instance;
6
- private communicationSecret;
7
- private supabase;
8
- private supabaseInfo;
9
- private pluginId;
10
- private constructor();
11
- static getInstance(sender: string): Promise<RimoriClient>;
12
- private getSecret;
13
- getClient(): Promise<{
14
- supabase: SupabaseClient;
15
- tablePrefix: string;
16
- pluginId: string;
17
- }>;
18
- getToken(): Promise<string>;
19
- getSupabaseUrl(): string;
20
- getGlobalEventTopic(preliminaryTopic: string): string;
21
- }
@@ -1,116 +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 { createClient } from '@supabase/supabase-js';
11
- import { EventBus } from '../plugin/fromRimori/EventBus';
12
- import { RimoriClient } from "../plugin/RimoriClient";
13
- import { setTheme } from '../plugin/ThemeSetter';
14
- export class PluginController {
15
- constructor(pluginId) {
16
- this.communicationSecret = null;
17
- this.supabase = null;
18
- this.supabaseInfo = null;
19
- this.pluginId = pluginId;
20
- this.getClient = this.getClient.bind(this);
21
- if (typeof WorkerGlobalScope === 'undefined') {
22
- setTheme();
23
- }
24
- window.addEventListener("message", (event) => {
25
- // console.log("client: message received", event);
26
- const { topic, sender, data, eventId } = event.data.event;
27
- // skip forwarding messages from own plugin
28
- if (sender === pluginId)
29
- return;
30
- EventBus.emit(sender, topic, data, eventId);
31
- });
32
- EventBus.on("*", (event) => {
33
- // skip messages which are not from the own plugin
34
- if (event.sender !== this.pluginId)
35
- return;
36
- if (event.topic.startsWith("self."))
37
- return;
38
- window.parent.postMessage({ event, secret: this.getSecret() }, "*");
39
- });
40
- }
41
- static getInstance(sender) {
42
- return __awaiter(this, void 0, void 0, function* () {
43
- if (!PluginController.instance) {
44
- PluginController.instance = new PluginController(sender);
45
- PluginController.client = yield RimoriClient.getInstance(PluginController.instance);
46
- }
47
- return PluginController.client;
48
- });
49
- }
50
- getSecret() {
51
- if (!this.communicationSecret) {
52
- const secret = new URLSearchParams(window.location.search).get("secret");
53
- if (!secret) {
54
- throw new Error("Communication secret not found in URL as query parameter");
55
- }
56
- this.communicationSecret = secret;
57
- }
58
- return this.communicationSecret;
59
- }
60
- getClient() {
61
- return __awaiter(this, void 0, void 0, function* () {
62
- if (this.supabase &&
63
- this.supabaseInfo &&
64
- this.supabaseInfo.expiration > new Date()) {
65
- return { supabase: this.supabase, tablePrefix: this.supabaseInfo.tablePrefix, pluginId: this.supabaseInfo.pluginId };
66
- }
67
- const { data } = yield EventBus.request(this.pluginId, "global.supabase.requestAccess");
68
- this.supabaseInfo = data;
69
- this.supabase = createClient(this.supabaseInfo.url, this.supabaseInfo.key, {
70
- accessToken: () => Promise.resolve(this.getToken())
71
- });
72
- return { supabase: this.supabase, tablePrefix: this.supabaseInfo.tablePrefix, pluginId: this.supabaseInfo.pluginId };
73
- });
74
- }
75
- getToken() {
76
- return __awaiter(this, void 0, void 0, function* () {
77
- if (this.supabaseInfo && this.supabaseInfo.expiration && this.supabaseInfo.expiration > new Date()) {
78
- return this.supabaseInfo.token;
79
- }
80
- const { data } = yield EventBus.request(this.pluginId, "global.supabase.requestAccess");
81
- if (!this.supabaseInfo) {
82
- throw new Error("Supabase info not found");
83
- }
84
- this.supabaseInfo.token = data.token;
85
- this.supabaseInfo.expiration = data.expiration;
86
- return this.supabaseInfo.token;
87
- });
88
- }
89
- getSupabaseUrl() {
90
- if (!this.supabaseInfo) {
91
- throw new Error("Supabase info not found");
92
- }
93
- return this.supabaseInfo.url;
94
- }
95
- getGlobalEventTopic(preliminaryTopic) {
96
- var _a, _b;
97
- if (preliminaryTopic.startsWith("global.")) {
98
- return preliminaryTopic;
99
- }
100
- if (preliminaryTopic.startsWith("self.")) {
101
- return preliminaryTopic;
102
- }
103
- const topicParts = preliminaryTopic.split(".");
104
- if (topicParts.length === 3) {
105
- if (!topicParts[0].startsWith("pl") && topicParts[0] !== "global") {
106
- throw new Error("The event topic must start with the plugin id or 'global'.");
107
- }
108
- return preliminaryTopic;
109
- }
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";
114
- return `${topicRoot}.${preliminaryTopic}`;
115
- }
116
- }
@@ -1,23 +0,0 @@
1
- export interface ToolInvocation {
2
- toolName: string;
3
- args: Record<string, string>;
4
- }
5
- export interface Tool {
6
- name: string;
7
- description: string;
8
- parameters: {
9
- name: string;
10
- description: string;
11
- type: "string" | "number" | "boolean";
12
- }[];
13
- execute?: <T = Record<string, string | boolean | number>>(args: T) => Promise<any> | void;
14
- }
15
- export interface Message {
16
- id: string;
17
- role: string;
18
- content: string;
19
- toolInvocations?: ToolInvocation[];
20
- }
21
- export declare function generateText(supabaseUrl: string, messages: Message[], tools: Tool[], token: string): Promise<any>;
22
- export type OnLLMResponse = (id: string, response: string, finished: boolean, toolInvocations?: ToolInvocation[]) => void;
23
- export declare function streamChatGPT(supabaseUrl: string, messages: Message[], tools: Tool[], onResponse: OnLLMResponse, token: string): Promise<void>;