@rimori/client 1.2.0 → 1.3.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 (75) hide show
  1. package/README.md +61 -18
  2. package/dist/cli/scripts/init/dev-registration.js +0 -1
  3. package/dist/cli/scripts/init/main.d.ts +1 -1
  4. package/dist/cli/scripts/init/main.js +1 -0
  5. package/dist/components/LoggerExample.d.ts +6 -0
  6. package/dist/components/LoggerExample.js +79 -0
  7. package/dist/components/ai/Assistant.js +2 -2
  8. package/dist/components/ai/Avatar.js +2 -2
  9. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +41 -32
  10. package/dist/components/audio/Playbutton.js +2 -2
  11. package/dist/components/components/ContextMenu.js +48 -9
  12. package/dist/core/controller/AIController.js +202 -69
  13. package/dist/core/controller/AudioController.d.ts +0 -0
  14. package/dist/core/controller/AudioController.js +1 -0
  15. package/dist/core/controller/ObjectController.d.ts +2 -2
  16. package/dist/core/controller/ObjectController.js +8 -8
  17. package/dist/core/controller/SettingsController.d.ts +16 -0
  18. package/dist/core/controller/SharedContentController.d.ts +30 -2
  19. package/dist/core/controller/SharedContentController.js +74 -23
  20. package/dist/core/controller/VoiceController.d.ts +2 -3
  21. package/dist/core/controller/VoiceController.js +11 -4
  22. package/dist/core/core.d.ts +1 -0
  23. package/dist/fromRimori/EventBus.js +1 -1
  24. package/dist/fromRimori/PluginTypes.d.ts +7 -4
  25. package/dist/hooks/UseChatHook.js +6 -4
  26. package/dist/hooks/UseLogger.d.ts +30 -0
  27. package/dist/hooks/UseLogger.js +122 -0
  28. package/dist/index.d.ts +1 -0
  29. package/dist/index.js +1 -0
  30. package/dist/plugin/AudioController.d.ts +37 -0
  31. package/dist/plugin/AudioController.js +68 -0
  32. package/dist/plugin/Logger.d.ts +68 -0
  33. package/dist/plugin/Logger.js +256 -0
  34. package/dist/plugin/LoggerExample.d.ts +16 -0
  35. package/dist/plugin/LoggerExample.js +140 -0
  36. package/dist/plugin/PluginController.d.ts +15 -3
  37. package/dist/plugin/PluginController.js +162 -39
  38. package/dist/plugin/RimoriClient.d.ts +55 -13
  39. package/dist/plugin/RimoriClient.js +60 -23
  40. package/dist/plugin/StandaloneClient.d.ts +1 -0
  41. package/dist/plugin/StandaloneClient.js +16 -5
  42. package/dist/plugin/ThemeSetter.d.ts +2 -2
  43. package/dist/plugin/ThemeSetter.js +8 -5
  44. package/dist/providers/PluginProvider.d.ts +1 -1
  45. package/dist/providers/PluginProvider.js +36 -10
  46. package/dist/utils/audioFormats.d.ts +26 -0
  47. package/dist/utils/audioFormats.js +67 -0
  48. package/dist/worker/WorkerSetup.d.ts +3 -2
  49. package/dist/worker/WorkerSetup.js +22 -67
  50. package/package.json +7 -6
  51. package/src/cli/scripts/init/dev-registration.ts +0 -1
  52. package/src/cli/scripts/init/main.ts +1 -0
  53. package/src/components/ai/Assistant.tsx +2 -2
  54. package/src/components/ai/Avatar.tsx +2 -2
  55. package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +39 -32
  56. package/src/components/audio/Playbutton.tsx +2 -2
  57. package/src/components/components/ContextMenu.tsx +53 -9
  58. package/src/core/controller/AIController.ts +236 -75
  59. package/src/core/controller/ObjectController.ts +8 -8
  60. package/src/core/controller/SettingsController.ts +16 -0
  61. package/src/core/controller/SharedContentController.ts +87 -25
  62. package/src/core/controller/VoiceController.ts +24 -19
  63. package/src/core/core.ts +1 -0
  64. package/src/fromRimori/EventBus.ts +1 -1
  65. package/src/fromRimori/PluginTypes.ts +6 -4
  66. package/src/hooks/UseChatHook.ts +6 -4
  67. package/src/index.ts +1 -0
  68. package/src/plugin/AudioController.ts +58 -0
  69. package/src/plugin/Logger.ts +324 -0
  70. package/src/plugin/PluginController.ts +171 -43
  71. package/src/plugin/RimoriClient.ts +95 -30
  72. package/src/plugin/StandaloneClient.ts +22 -6
  73. package/src/plugin/ThemeSetter.ts +8 -5
  74. package/src/providers/PluginProvider.tsx +40 -10
  75. package/src/worker/WorkerSetup.ts +14 -63
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Example of how to integrate the Logger into a plugin's main entry point.
3
+ * This shows the complete setup process.
4
+ */
5
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
7
+ return new (P || (P = Promise))(function (resolve, reject) {
8
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
9
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
10
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
11
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
12
+ });
13
+ };
14
+ import { Logger } from './Logger';
15
+ // Example plugin initialization with Logger integration
16
+ export function initializePluginWithLogger() {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ // 1. Initialize the Logger singleton (call this as early as possible)
19
+ const logger = Logger.getInstance(process.env.NODE_ENV === 'production');
20
+ console.log('Logger initialized, console methods are now overridden globally');
21
+ try {
22
+ // 2. Initialize your plugin's core functionality
23
+ console.info('Starting plugin initialization...');
24
+ // 3. Get the Rimori client (this would be your actual client initialization)
25
+ const rimoriClient = yield getRimoriClient(); // Your actual client setup
26
+ // 4. Set the Rimori client in the Logger
27
+ logger.setRimoriClient(rimoriClient);
28
+ console.info('Plugin initialized successfully', {
29
+ version: '1.0.0',
30
+ environment: process.env.NODE_ENV,
31
+ timestamp: new Date().toISOString()
32
+ });
33
+ // 5. Set up periodic log transmission (optional)
34
+ setInterval(() => __awaiter(this, void 0, void 0, function* () {
35
+ yield logger.sendRecentLogs(10); // Send last 10 logs every 5 minutes
36
+ }), 5 * 60 * 1000);
37
+ // 6. Set up error boundary for unhandled errors
38
+ window.addEventListener('error', (event) => {
39
+ console.error('Unhandled error caught by Logger', {
40
+ message: event.message,
41
+ filename: event.filename,
42
+ lineno: event.lineno,
43
+ colno: event.colno
44
+ });
45
+ });
46
+ window.addEventListener('unhandledrejection', (event) => {
47
+ console.error('Unhandled promise rejection caught by Logger', {
48
+ reason: event.reason
49
+ });
50
+ });
51
+ }
52
+ catch (error) {
53
+ // This console.error will be automatically captured with screenshot + mouse position
54
+ console.error('Failed to initialize plugin', {
55
+ error: error.message,
56
+ stack: error.stack
57
+ });
58
+ // Send error logs immediately
59
+ yield logger.sendLogsByLevel('error');
60
+ }
61
+ });
62
+ }
63
+ // Example of how to use console methods in your components
64
+ export function exampleComponentUsage() {
65
+ const handleUserAction = () => {
66
+ // These console calls are automatically captured by the Logger
67
+ console.log('User performed action', {
68
+ action: 'button_click',
69
+ timestamp: Date.now(),
70
+ userId: 'user123'
71
+ });
72
+ };
73
+ const handleApiError = (error) => {
74
+ // This console.error will include screenshot + mouse position
75
+ console.error('API request failed', {
76
+ endpoint: '/api/users',
77
+ error: error.message,
78
+ statusCode: 500
79
+ });
80
+ };
81
+ const handleDeprecatedFeature = () => {
82
+ // This console.warn will include screenshot + mouse position
83
+ console.warn('Deprecated feature used', {
84
+ feature: 'old-api-endpoint',
85
+ suggestedAlternative: 'new-api-endpoint'
86
+ });
87
+ };
88
+ return {
89
+ handleUserAction,
90
+ handleApiError,
91
+ handleDeprecatedFeature
92
+ };
93
+ }
94
+ // Example of log management utilities
95
+ export function exampleLogManagement() {
96
+ const logger = Logger.getInstance(process.env.NODE_ENV === 'production');
97
+ const sendLogsToRimori = () => __awaiter(this, void 0, void 0, function* () {
98
+ yield logger.sendAllLogs();
99
+ console.log('All logs sent to Rimori');
100
+ });
101
+ const getLogStatistics = () => {
102
+ const stats = logger.getStats();
103
+ console.log('Log statistics:', stats);
104
+ return stats;
105
+ };
106
+ const exportLogsForDebugging = () => {
107
+ const exportedLogs = logger.exportLogs();
108
+ const blob = new Blob([exportedLogs], { type: 'application/json' });
109
+ const url = URL.createObjectURL(blob);
110
+ const a = document.createElement('a');
111
+ a.href = url;
112
+ a.download = `rimori-logs-${new Date().toISOString()}.json`;
113
+ a.click();
114
+ URL.revokeObjectURL(url);
115
+ };
116
+ const clearOldLogs = () => {
117
+ logger.clearLogs();
118
+ console.log('All logs cleared');
119
+ };
120
+ return {
121
+ sendLogsToRimori,
122
+ getLogStatistics,
123
+ exportLogsForDebugging,
124
+ clearOldLogs
125
+ };
126
+ }
127
+ // Mock function for demonstration
128
+ function getRimoriClient() {
129
+ return __awaiter(this, void 0, void 0, function* () {
130
+ // This would be your actual Rimori client initialization
131
+ return {
132
+ plugin: { pluginId: 'example-plugin' },
133
+ event: {
134
+ emit: (topic, data) => __awaiter(this, void 0, void 0, function* () {
135
+ console.log('Sending to Rimori:', topic, data);
136
+ })
137
+ }
138
+ };
139
+ });
140
+ }
@@ -1,6 +1,6 @@
1
1
  import { SupabaseClient } from '@supabase/supabase-js';
2
2
  import { UserInfo } from '../core/controller/SettingsController';
3
- import { Plugin } from '../fromRimori/PluginTypes';
3
+ import { ActivePlugin, Plugin } from '../fromRimori/PluginTypes';
4
4
  import { RimoriClient } from "./RimoriClient";
5
5
  export interface RimoriInfo {
6
6
  url: string;
@@ -12,22 +12,34 @@ export interface RimoriInfo {
12
12
  pluginId: string;
13
13
  installedPlugins: Plugin[];
14
14
  profile: UserInfo;
15
+ mainPanelPlugin?: ActivePlugin;
16
+ sidePanelPlugin?: ActivePlugin;
15
17
  }
16
18
  export declare class PluginController {
17
19
  private static client;
18
20
  private static instance;
19
- private communicationSecret;
21
+ private port;
22
+ private queryParams;
20
23
  private supabase;
21
24
  private rimoriInfo;
22
25
  private pluginId;
26
+ private isMessageChannelReady;
27
+ private pendingRequests;
23
28
  private constructor();
29
+ private initMessageChannel;
30
+ private sendHello;
24
31
  static getInstance(pluginId: string, standalone?: boolean): Promise<RimoriClient>;
25
- private getSecret;
32
+ getQueryParam(key: string): string | null;
26
33
  getClient(): Promise<{
27
34
  supabase: SupabaseClient;
28
35
  info: RimoriInfo;
29
36
  }>;
30
37
  getToken(): Promise<string>;
38
+ /**
39
+ * Gets the Supabase URL.
40
+ * @returns The Supabase URL.
41
+ * @deprecated All endpoints should use the backend URL instead.
42
+ */
31
43
  getSupabaseUrl(): string;
32
44
  getBackendUrl(): string;
33
45
  getGlobalEventTopic(preliminaryTopic: string): string;
@@ -12,37 +12,102 @@ import { EventBus } from '../fromRimori/EventBus';
12
12
  import { RimoriClient } from "./RimoriClient";
13
13
  import { StandaloneClient } from './StandaloneClient';
14
14
  import { setTheme } from './ThemeSetter';
15
+ import { Logger } from './Logger';
15
16
  export class PluginController {
16
17
  constructor(pluginId, standalone) {
17
- this.communicationSecret = null;
18
+ this.port = null;
19
+ this.queryParams = {};
18
20
  this.supabase = null;
19
21
  this.rimoriInfo = null;
22
+ this.isMessageChannelReady = false;
23
+ this.pendingRequests = [];
20
24
  this.pluginId = pluginId;
21
25
  this.getClient = this.getClient.bind(this);
22
26
  if (typeof WorkerGlobalScope === 'undefined') {
23
- setTheme();
27
+ // In standalone mode, use URL fallback. In iframe mode, theme will be set after MessageChannel init
28
+ if (standalone) {
29
+ setTheme();
30
+ }
24
31
  }
25
- //no need to forward messages to parent in standalone mode
32
+ //no need to forward messages to parent in standalone mode or worker context
26
33
  if (standalone)
27
34
  return;
28
- window.addEventListener("message", (event) => {
29
- // console.log("client: message received", event);
30
- const { topic, sender, data, eventId } = event.data.event;
31
- // skip forwarding messages from own plugin
32
- if (sender === pluginId)
33
- return;
34
- EventBus.emit(sender, topic, data, eventId);
35
- });
36
- const secret = this.getSecret();
37
- EventBus.on("*", (event) => {
38
- // skip messages which are not from the own plugin
39
- if (event.sender !== this.pluginId)
40
- return;
41
- if (event.topic.startsWith("self."))
35
+ this.initMessageChannel(typeof WorkerGlobalScope !== 'undefined');
36
+ }
37
+ initMessageChannel(worker = false) {
38
+ const listener = (event) => {
39
+ console.log("[PluginController] window message", { origin: event.origin, data: event.data });
40
+ const { type, pluginId, queryParams, rimoriInfo } = event.data || {};
41
+ const [transferredPort] = event.ports || [];
42
+ if (type !== "rimori:init" || !transferredPort || pluginId !== this.pluginId) {
43
+ console.log("[PluginController] message ignored (not init or wrong plugin)", { type, pluginId, hasPort: !!transferredPort });
42
44
  return;
43
- // console.log("sending event to parent", event);
44
- window.parent.postMessage({ event, secret }, "*");
45
- });
45
+ }
46
+ this.queryParams = queryParams || {};
47
+ this.port = transferredPort;
48
+ // Initialize Supabase client immediately with provided info
49
+ if (rimoriInfo) {
50
+ this.rimoriInfo = rimoriInfo;
51
+ this.supabase = createClient(rimoriInfo.url, rimoriInfo.key, {
52
+ accessToken: () => Promise.resolve(rimoriInfo.token)
53
+ });
54
+ }
55
+ // Handle messages from parent
56
+ this.port.onmessage = ({ data }) => {
57
+ const { event, type, eventId, response, error } = data || {};
58
+ // no idea why this is needed but it works for now
59
+ if (type === 'response' && eventId) {
60
+ EventBus.emit(this.pluginId, response.topic, response.data, eventId);
61
+ }
62
+ else if (type === 'error' && eventId) {
63
+ EventBus.emit(this.pluginId, 'error', { error }, eventId);
64
+ }
65
+ else if (event) {
66
+ const { topic, sender, data: eventData, eventId } = event;
67
+ if (sender !== this.pluginId) {
68
+ EventBus.emit(sender, topic, eventData, eventId);
69
+ }
70
+ }
71
+ };
72
+ // Set theme from MessageChannel query params
73
+ if (!worker) {
74
+ const theme = this.queryParams['rm_theme'];
75
+ setTheme(theme);
76
+ }
77
+ // Forward plugin events to parent (only after MessageChannel is ready)
78
+ EventBus.on("*", (ev) => {
79
+ var _a;
80
+ if (ev.sender === this.pluginId && !ev.topic.startsWith("self.")) {
81
+ (_a = this.port) === null || _a === void 0 ? void 0 : _a.postMessage({ event: ev });
82
+ }
83
+ });
84
+ // Mark MessageChannel as ready and process pending requests
85
+ this.isMessageChannelReady = true;
86
+ // Process any pending requests
87
+ this.pendingRequests.forEach(request => request());
88
+ this.pendingRequests = [];
89
+ };
90
+ if (worker) {
91
+ self.onmessage = listener;
92
+ }
93
+ else {
94
+ window.addEventListener("message", listener);
95
+ }
96
+ this.sendHello(worker);
97
+ }
98
+ sendHello(isWorker = false) {
99
+ try {
100
+ const payload = { type: "rimori:hello", pluginId: this.pluginId };
101
+ if (isWorker) {
102
+ self.postMessage(payload);
103
+ }
104
+ else {
105
+ window.parent.postMessage(payload, "*");
106
+ }
107
+ }
108
+ catch (e) {
109
+ console.error("[PluginController] Error sending hello:", e);
110
+ }
46
111
  }
47
112
  static getInstance(pluginId_1) {
48
113
  return __awaiter(this, arguments, void 0, function* (pluginId, standalone = false) {
@@ -52,32 +117,81 @@ export class PluginController {
52
117
  }
53
118
  PluginController.instance = new PluginController(pluginId, standalone);
54
119
  PluginController.client = yield RimoriClient.getInstance(PluginController.instance);
120
+ //only init logger in workers and on main plugin pages
121
+ if (PluginController.instance.getQueryParam("applicationMode") !== "sidebar") {
122
+ Logger.getInstance(PluginController.client);
123
+ }
55
124
  }
56
125
  return PluginController.client;
57
126
  });
58
127
  }
59
- getSecret() {
60
- if (!this.communicationSecret) {
61
- const secret = new URLSearchParams(window.location.search).get("secret");
62
- if (!secret) {
63
- console.info("Communication secret not found in URL as query parameter");
64
- }
65
- this.communicationSecret = secret;
66
- }
67
- return this.communicationSecret;
128
+ getQueryParam(key) {
129
+ return this.queryParams[key] || null;
68
130
  }
69
131
  getClient() {
70
132
  return __awaiter(this, void 0, void 0, function* () {
71
- if (this.supabase &&
72
- this.rimoriInfo &&
73
- this.rimoriInfo.expiration > new Date()) {
133
+ // Return cached client if valid
134
+ if (this.supabase && this.rimoriInfo && this.rimoriInfo.expiration > new Date()) {
74
135
  return { supabase: this.supabase, info: this.rimoriInfo };
75
136
  }
76
- const { data } = yield EventBus.request(this.pluginId, "global.supabase.requestAccess");
77
- this.rimoriInfo = data;
78
- this.supabase = createClient(this.rimoriInfo.url, this.rimoriInfo.key, {
79
- accessToken: () => Promise.resolve(this.getToken())
80
- });
137
+ // If MessageChannel is not ready yet, queue the request
138
+ if (!this.isMessageChannelReady) {
139
+ return new Promise((resolve) => {
140
+ this.pendingRequests.push(() => __awaiter(this, void 0, void 0, function* () {
141
+ const result = yield this.getClient();
142
+ resolve(result);
143
+ }));
144
+ });
145
+ }
146
+ // If we have rimoriInfo from MessageChannel init, use it directly
147
+ if (this.rimoriInfo && this.supabase) {
148
+ return { supabase: this.supabase, info: this.rimoriInfo };
149
+ }
150
+ // Fallback: request from parent
151
+ if (!this.rimoriInfo) {
152
+ if (typeof WorkerGlobalScope !== 'undefined') {
153
+ // In worker context, send request via self.postMessage to WorkerHandler
154
+ const eventId = Math.floor(Math.random() * 1000000000);
155
+ const requestEvent = {
156
+ event: {
157
+ timestamp: new Date().toISOString(),
158
+ eventId,
159
+ sender: this.pluginId,
160
+ topic: 'global.supabase.requestAccess',
161
+ data: {},
162
+ debug: false
163
+ }
164
+ };
165
+ return new Promise((resolve) => {
166
+ // Listen for the response
167
+ const originalOnMessage = self.onmessage;
168
+ self.onmessage = (event) => {
169
+ var _a, _b;
170
+ if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.topic) === 'global.supabase.requestAccess' && ((_b = event.data) === null || _b === void 0 ? void 0 : _b.eventId) === eventId) {
171
+ this.rimoriInfo = event.data.data;
172
+ this.supabase = createClient(this.rimoriInfo.url, this.rimoriInfo.key, {
173
+ accessToken: () => Promise.resolve(this.getToken())
174
+ });
175
+ self.onmessage = originalOnMessage; // Restore original handler
176
+ resolve({ supabase: this.supabase, info: this.rimoriInfo });
177
+ }
178
+ else if (originalOnMessage) {
179
+ originalOnMessage.call(self, event);
180
+ }
181
+ };
182
+ // Send the request
183
+ self.postMessage(requestEvent);
184
+ });
185
+ }
186
+ else {
187
+ // In main thread context, use EventBus
188
+ const { data } = yield EventBus.request(this.pluginId, "global.supabase.requestAccess");
189
+ this.rimoriInfo = data;
190
+ this.supabase = createClient(this.rimoriInfo.url, this.rimoriInfo.key, {
191
+ accessToken: () => Promise.resolve(this.getToken())
192
+ });
193
+ }
194
+ }
81
195
  return { supabase: this.supabase, info: this.rimoriInfo };
82
196
  });
83
197
  }
@@ -86,15 +200,24 @@ export class PluginController {
86
200
  if (this.rimoriInfo && this.rimoriInfo.expiration && this.rimoriInfo.expiration > new Date()) {
87
201
  return this.rimoriInfo.token;
88
202
  }
89
- const { data } = yield EventBus.request(this.pluginId, "global.supabase.requestAccess");
203
+ // If we don't have rimoriInfo, request it
90
204
  if (!this.rimoriInfo) {
91
- throw new Error("Supabase info not found");
205
+ const { data } = yield EventBus.request(this.pluginId, "global.supabase.requestAccess");
206
+ this.rimoriInfo = data;
207
+ return this.rimoriInfo.token;
92
208
  }
209
+ // If token is expired, request fresh access
210
+ const { data } = yield EventBus.request(this.pluginId, "global.supabase.requestAccess");
93
211
  this.rimoriInfo.token = data.token;
94
212
  this.rimoriInfo.expiration = data.expiration;
95
213
  return this.rimoriInfo.token;
96
214
  });
97
215
  }
216
+ /**
217
+ * Gets the Supabase URL.
218
+ * @returns The Supabase URL.
219
+ * @deprecated All endpoints should use the backend URL instead.
220
+ */
98
221
  getSupabaseUrl() {
99
222
  if (!this.rimoriInfo) {
100
223
  throw new Error("Supabase info not found");
@@ -1,12 +1,11 @@
1
1
  import { PostgrestQueryBuilder } from "@supabase/postgrest-js";
2
- import { SupabaseClient } from "@supabase/supabase-js";
3
2
  import { GenericSchema } from "@supabase/supabase-js/dist/module/lib/types";
4
3
  import { Message, OnLLMResponse } from "../core/controller/AIController";
5
4
  import { ObjectRequest } from "../core/controller/ObjectController";
6
5
  import { UserInfo } from "../core/controller/SettingsController";
7
6
  import { SharedContent, SharedContentFilter, SharedContentObjectRequest } from "../core/controller/SharedContentController";
8
7
  import { EventBusMessage, EventHandler, EventPayload } from "../fromRimori/EventBus";
9
- import { Plugin, Tool } from "../fromRimori/PluginTypes";
8
+ import { ActivePlugin, MainPanelAction, Plugin, Tool } from "../fromRimori/PluginTypes";
10
9
  import { AccomplishmentPayload } from "./AccomplishmentHandler";
11
10
  import { PluginController } from "./PluginController";
12
11
  interface Db {
@@ -14,7 +13,6 @@ interface Db {
14
13
  <TableName extends string & keyof GenericSchema['Tables'], Table extends GenericSchema['Tables'][TableName]>(relation: TableName): PostgrestQueryBuilder<GenericSchema, Table, TableName>;
15
14
  <ViewName extends string & keyof GenericSchema['Views'], View extends GenericSchema['Views'][ViewName]>(relation: ViewName): PostgrestQueryBuilder<GenericSchema, View, ViewName>;
16
15
  };
17
- storage: SupabaseClient["storage"];
18
16
  /**
19
17
  * The table prefix for of database tables of the plugin.
20
18
  */
@@ -38,11 +36,26 @@ interface PluginInterface {
38
36
  */
39
37
  getSettings: <T extends object>(defaultSettings: T) => Promise<T>;
40
38
  /**
41
- * Fetches all installed plugins.
42
- * @returns A promise that resolves to an array of plugins
43
- */
44
- getInstalled: () => Promise<Plugin[]>;
45
- getUserInfo: () => Promise<UserInfo>;
39
+ * Retrieves information about plugins, including:
40
+ * - All installed plugins
41
+ * - The currently active plugin in the main panel
42
+ * - The currently active plugin in the side panel
43
+ */
44
+ getPluginInfo: () => {
45
+ /**
46
+ * All installed plugins.
47
+ */
48
+ installedPlugins: Plugin[];
49
+ /**
50
+ * The plugin that is loaded in the main panel.
51
+ */
52
+ mainPanelPlugin?: ActivePlugin;
53
+ /**
54
+ * The plugin that is loaded in the side panel.
55
+ */
56
+ sidePanelPlugin?: ActivePlugin;
57
+ };
58
+ getUserInfo: () => UserInfo;
46
59
  }
47
60
  export declare class RimoriClient {
48
61
  private static instance;
@@ -51,9 +64,7 @@ export declare class RimoriClient {
51
64
  private settingsController;
52
65
  private sharedContentController;
53
66
  private accomplishmentHandler;
54
- private supabaseUrl;
55
- private installedPlugins;
56
- private profile;
67
+ private rimoriInfo;
57
68
  plugin: PluginInterface;
58
69
  db: Db;
59
70
  private constructor();
@@ -113,10 +124,17 @@ export declare class RimoriClient {
113
124
  * @param text Optional text to be used for the action like for example text that the translator would look up.
114
125
  */
115
126
  emitSidebarAction: (pluginId: string, actionKey: string, text?: string) => void;
127
+ onMainPanelAction: (callback: (data: MainPanelAction) => void) => void;
116
128
  };
117
129
  navigation: {
118
130
  toDashboard: () => void;
119
131
  };
132
+ /**
133
+ * Get a query parameter value that was passed via MessageChannel
134
+ * @param key The query parameter key
135
+ * @returns The query parameter value or null if not found
136
+ */
137
+ getQueryParam(key: string): string | null;
120
138
  static getInstance(pluginController: PluginController): Promise<RimoriClient>;
121
139
  private from;
122
140
  private getTableName;
@@ -127,6 +145,9 @@ export declare class RimoriClient {
127
145
  getTextFromVoice: (file: Blob) => Promise<string>;
128
146
  getObject: (request: ObjectRequest) => Promise<any>;
129
147
  };
148
+ runtime: {
149
+ fetchBackend: (url: string, options: RequestInit) => Promise<Response>;
150
+ };
130
151
  community: {
131
152
  /**
132
153
  * Shared content is a way to share completable content with other users using this plugin.
@@ -154,10 +175,19 @@ export declare class RimoriClient {
154
175
  * @param contentType The type of shared content to fetch. E.g. assignments, exercises, etc.
155
176
  * @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.
156
177
  * @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.
157
- * @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.
178
+ * @param options An optional object with options for the new shared content.
179
+ * @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.
180
+ * @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.
181
+ * @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.
182
+ * @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.
158
183
  * @returns The new shared content.
159
184
  */
160
- getNew: <T = any>(contentType: string, generatorInstructions: SharedContentObjectRequest, filter?: SharedContentFilter, privateTopic?: boolean) => Promise<SharedContent<T>>;
185
+ getNew: <T = any>(contentType: string, generatorInstructions: SharedContentObjectRequest, filter?: SharedContentFilter, options?: {
186
+ privateTopic?: boolean;
187
+ skipDbSave?: boolean;
188
+ alwaysGenerateNew?: boolean;
189
+ excludeIds?: string[];
190
+ }) => Promise<SharedContent<T>>;
161
191
  /**
162
192
  * Create a new shared content item.
163
193
  * @param content The content to create.
@@ -177,6 +207,18 @@ export declare class RimoriClient {
177
207
  * @param assignmentId The id of the shared content item to complete.
178
208
  */
179
209
  complete: (contentType: string, assignmentId: string) => Promise<void>;
210
+ /**
211
+ /**
212
+ * Update the state of a shared content item for a specific user.
213
+ * Useful for marking content as completed, ongoing, hidden, liked, disliked, or bookmarked.
214
+ */
215
+ updateState: (params: {
216
+ contentType: string;
217
+ id: string;
218
+ state?: "completed" | "ongoing" | "hidden";
219
+ reaction?: "liked" | "disliked" | null;
220
+ bookmarked?: boolean;
221
+ }) => Promise<void>;
180
222
  /**
181
223
  * Remove a shared content item.
182
224
  * @param id The id of the shared content item to remove.