@rimori/client 1.3.1 → 1.4.3
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.
- package/.prettierignore +35 -0
- package/README.md +77 -71
- package/dist/cli/scripts/init/dev-registration.d.ts +1 -1
- package/dist/cli/scripts/init/dev-registration.js +4 -4
- package/dist/cli/scripts/init/main.js +1 -1
- package/dist/cli/scripts/init/package-setup.d.ts +1 -1
- package/dist/cli/scripts/init/package-setup.js +3 -3
- package/dist/cli/scripts/init/router-transformer.js +19 -12
- package/dist/cli/scripts/init/vite-config.d.ts +2 -2
- package/dist/cli/scripts/init/vite-config.js +2 -2
- package/dist/cli/scripts/release/release-config-upload.js +9 -9
- package/dist/cli/scripts/release/release-db-update.d.ts +1 -1
- package/dist/cli/scripts/release/release-db-update.js +9 -9
- package/dist/cli/scripts/release/release-file-upload.js +2 -2
- package/dist/cli/scripts/release/release.js +2 -2
- package/dist/cli/types/DatabaseTypes.d.ts +2 -2
- package/dist/components/CRUDModal.d.ts +1 -1
- package/dist/components/CRUDModal.js +3 -3
- package/dist/components/MarkdownEditor.js +16 -16
- package/dist/components/Spinner.js +2 -2
- package/dist/components/ai/Assistant.js +7 -8
- package/dist/components/ai/Avatar.d.ts +2 -2
- package/dist/components/ai/Avatar.js +14 -7
- package/dist/components/ai/EmbeddedAssistent/AudioInputField.js +5 -6
- package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.d.ts +1 -1
- package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +1 -2
- package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.d.ts +1 -2
- package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.js +4 -2
- package/dist/components/ai/EmbeddedAssistent/TTS/Player.js +1 -1
- package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +2 -3
- package/dist/components/audio/Playbutton.js +10 -7
- package/dist/components/components/ContextMenu.d.ts +1 -1
- package/dist/components/components/ContextMenu.js +19 -16
- package/dist/components.d.ts +10 -10
- package/dist/components.js +10 -10
- package/dist/core/controller/AIController.d.ts +2 -2
- package/dist/core/controller/AIController.js +20 -18
- package/dist/core/controller/ExerciseController.d.ts +52 -0
- package/dist/core/controller/ExerciseController.js +73 -0
- package/dist/core/controller/ObjectController.js +5 -5
- package/dist/core/controller/SettingsController.d.ts +22 -7
- package/dist/core/controller/SettingsController.js +73 -8
- package/dist/core/controller/SharedContentController.d.ts +3 -3
- package/dist/core/controller/SharedContentController.js +38 -20
- package/dist/core/controller/VoiceController.js +6 -4
- package/dist/core/core.d.ts +15 -14
- package/dist/core/core.js +7 -7
- package/dist/fromRimori/EventBus.js +23 -23
- package/dist/fromRimori/PluginTypes.d.ts +4 -4
- package/dist/hooks/UseChatHook.d.ts +3 -3
- package/dist/hooks/UseChatHook.js +9 -3
- package/dist/index.d.ts +10 -10
- package/dist/index.js +9 -9
- package/dist/plugin/AccomplishmentHandler.d.ts +5 -5
- package/dist/plugin/AccomplishmentHandler.js +31 -27
- package/dist/plugin/AudioController.d.ts +1 -1
- package/dist/plugin/AudioController.js +6 -6
- package/dist/plugin/Logger.d.ts +5 -0
- package/dist/plugin/Logger.js +65 -13
- package/dist/plugin/PluginController.d.ts +7 -1
- package/dist/plugin/PluginController.js +32 -27
- package/dist/plugin/RimoriClient.d.ts +39 -14
- package/dist/plugin/RimoriClient.js +60 -31
- package/dist/plugin/StandaloneClient.d.ts +1 -1
- package/dist/plugin/StandaloneClient.js +35 -16
- package/dist/plugin/ThemeSetter.js +4 -4
- package/dist/providers/PluginProvider.js +44 -14
- package/dist/utils/Language.js +57 -57
- package/dist/utils/PluginUtils.js +3 -3
- package/dist/utils/difficultyConverter.d.ts +1 -1
- package/dist/utils/difficultyConverter.js +1 -1
- package/dist/utils/endpoint.js +2 -2
- package/dist/worker/WorkerSetup.d.ts +1 -1
- package/dist/worker/WorkerSetup.js +6 -6
- package/eslint.config.js +53 -0
- package/example/docs/devdocs.md +50 -40
- package/example/docs/overview.md +1 -1
- package/example/docs/userdocs.md +4 -1
- package/example/rimori.config.ts +51 -49
- package/example/worker/vite.config.ts +3 -3
- package/example/worker/worker.ts +2 -2
- package/package.json +17 -4
- package/prettier.config.js +8 -0
- package/src/cli/scripts/init/dev-registration.ts +5 -8
- package/src/cli/scripts/init/env-setup.ts +1 -1
- package/src/cli/scripts/init/file-operations.ts +1 -1
- package/src/cli/scripts/init/html-cleaner.ts +2 -5
- package/src/cli/scripts/init/main.ts +16 -13
- package/src/cli/scripts/init/package-setup.ts +11 -15
- package/src/cli/scripts/init/router-transformer.ts +40 -37
- package/src/cli/scripts/init/tailwind-config.ts +17 -26
- package/src/cli/scripts/init/vite-config.ts +3 -3
- package/src/cli/scripts/release/release-config-upload.ts +11 -11
- package/src/cli/scripts/release/release-db-update.ts +12 -12
- package/src/cli/scripts/release/release-file-upload.ts +3 -3
- package/src/cli/scripts/release/release.ts +4 -4
- package/src/cli/types/DatabaseTypes.ts +7 -8
- package/src/components/CRUDModal.tsx +64 -48
- package/src/components/MarkdownEditor.tsx +58 -27
- package/src/components/Spinner.tsx +24 -17
- package/src/components/ai/Assistant.tsx +70 -70
- package/src/components/ai/Avatar.tsx +20 -16
- package/src/components/ai/EmbeddedAssistent/AudioInputField.tsx +63 -54
- package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +14 -5
- package/src/components/ai/EmbeddedAssistent/TTS/MessageSender.ts +75 -74
- package/src/components/ai/EmbeddedAssistent/TTS/Player.ts +177 -178
- package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +109 -94
- package/src/components/ai/utils.ts +4 -4
- package/src/components/audio/Playbutton.tsx +101 -93
- package/src/components/components/ContextMenu.tsx +47 -35
- package/src/components.ts +10 -10
- package/src/core/controller/AIController.ts +62 -50
- package/src/core/controller/ExerciseController.ts +98 -0
- package/src/core/controller/ObjectController.ts +15 -10
- package/src/core/controller/SettingsController.ts +89 -16
- package/src/core/controller/SharedContentController.ts +80 -44
- package/src/core/controller/VoiceController.ts +10 -8
- package/src/core/core.ts +15 -15
- package/src/fromRimori/EventBus.ts +76 -47
- package/src/fromRimori/PluginTypes.ts +26 -17
- package/src/fromRimori/readme.md +2 -2
- package/src/hooks/UseChatHook.ts +25 -15
- package/src/index.ts +10 -10
- package/src/plugin/AccomplishmentHandler.ts +53 -35
- package/src/plugin/AudioController.ts +18 -12
- package/src/plugin/Logger.ts +77 -19
- package/src/plugin/PluginController.ts +60 -44
- package/src/plugin/RimoriClient.ts +133 -69
- package/src/plugin/StandaloneClient.ts +51 -24
- package/src/plugin/ThemeSetter.ts +5 -5
- package/src/providers/PluginProvider.tsx +90 -36
- package/src/style.scss +3 -3
- package/src/utils/Language.ts +58 -58
- package/src/utils/PluginUtils.ts +16 -20
- package/src/utils/difficultyConverter.ts +2 -2
- package/src/utils/endpoint.ts +3 -2
- package/src/worker/WorkerSetup.ts +8 -9
- package/tsconfig.json +2 -4
- package/dist/components/LoggerExample.d.ts +0 -6
- package/dist/components/LoggerExample.js +0 -79
- package/dist/core/controller/AudioController.d.ts +0 -0
- package/dist/core/controller/AudioController.js +0 -1
- package/dist/hooks/UseLogger.d.ts +0 -30
- package/dist/hooks/UseLogger.js +0 -122
- package/dist/plugin/LoggerExample.d.ts +0 -16
- package/dist/plugin/LoggerExample.js +0 -140
- package/dist/utils/audioFormats.d.ts +0 -26
- package/dist/utils/audioFormats.js +0 -67
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { EventBus } from
|
|
2
|
-
export const skillCategories = [
|
|
1
|
+
import { EventBus } from '../fromRimori/EventBus';
|
|
2
|
+
export const skillCategories = ['reading', 'listening', 'speaking', 'writing', 'learning', 'community'];
|
|
3
3
|
export class AccomplishmentHandler {
|
|
4
4
|
constructor(pluginId) {
|
|
5
5
|
this.pluginId = pluginId;
|
|
6
6
|
}
|
|
7
7
|
emitAccomplishment(payload) {
|
|
8
|
-
const accomplishmentPayload = Object.assign(Object.assign({}, payload), { type:
|
|
8
|
+
const accomplishmentPayload = Object.assign(Object.assign({}, payload), { type: 'durationMinutes' in payload ? 'macro' : 'micro' });
|
|
9
9
|
this.validateAccomplishment(accomplishmentPayload);
|
|
10
10
|
const sanitizedPayload = this.sanitizeAccomplishment(accomplishmentPayload);
|
|
11
|
-
const topic =
|
|
11
|
+
const topic = 'global.accomplishment.trigger' + (accomplishmentPayload.type === 'macro' ? 'Macro' : 'Micro');
|
|
12
12
|
EventBus.emit(this.pluginId, topic, sanitizedPayload);
|
|
13
13
|
}
|
|
14
14
|
validateAccomplishment(payload) {
|
|
@@ -21,68 +21,72 @@ export class AccomplishmentHandler {
|
|
|
21
21
|
}
|
|
22
22
|
//description is required
|
|
23
23
|
if (payload.description.length < 10) {
|
|
24
|
-
throw new Error(
|
|
24
|
+
throw new Error('Description is too short');
|
|
25
25
|
}
|
|
26
26
|
//check that the type is valid
|
|
27
|
-
if (![
|
|
28
|
-
throw new Error(
|
|
27
|
+
if (!['micro', 'macro'].includes(payload.type)) {
|
|
28
|
+
throw new Error('Invalid accomplishment type ' + payload.type);
|
|
29
29
|
}
|
|
30
30
|
//durationMinutes is required
|
|
31
|
-
if (payload.type ===
|
|
32
|
-
throw new Error(
|
|
31
|
+
if (payload.type === 'macro' && payload.durationMinutes < 4) {
|
|
32
|
+
throw new Error('The duration must be at least 4 minutes');
|
|
33
33
|
}
|
|
34
34
|
//errorRatio is required
|
|
35
|
-
if (payload.type ===
|
|
36
|
-
throw new Error(
|
|
35
|
+
if (payload.type === 'macro' && (payload.errorRatio < 0 || payload.errorRatio > 1)) {
|
|
36
|
+
throw new Error('The error ratio must be between 0 and 1');
|
|
37
37
|
}
|
|
38
38
|
//regex check meta data key
|
|
39
39
|
if (payload.meta) {
|
|
40
|
-
payload.meta.forEach(meta => {
|
|
40
|
+
payload.meta.forEach((meta) => {
|
|
41
41
|
if (!/^[a-z_]+$/.test(meta.key)) {
|
|
42
|
-
throw new Error(
|
|
42
|
+
throw new Error('Invalid meta data key ' + meta.key + ', only lowercase letters and underscores are allowed');
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
sanitizeAccomplishment(payload) {
|
|
48
48
|
var _a;
|
|
49
|
-
payload.description = payload.description.replace(/[^\x20-\x7E]/g,
|
|
49
|
+
payload.description = payload.description.replace(/[^\x20-\x7E]/g, '');
|
|
50
50
|
(_a = payload.meta) === null || _a === void 0 ? void 0 : _a.forEach((meta) => {
|
|
51
|
-
meta.description = meta.description.replace(/[^\x20-\x7E]/g,
|
|
51
|
+
meta.description = meta.description.replace(/[^\x20-\x7E]/g, '');
|
|
52
52
|
});
|
|
53
53
|
return payload;
|
|
54
54
|
}
|
|
55
55
|
getDecoupledTopic(topic) {
|
|
56
|
-
const [plugin, skillCategory, accomplishmentKeyword] = topic.split(
|
|
57
|
-
return {
|
|
56
|
+
const [plugin, skillCategory, accomplishmentKeyword] = topic.split('.');
|
|
57
|
+
return {
|
|
58
|
+
plugin: plugin || '*',
|
|
59
|
+
skillCategory: skillCategory || '*',
|
|
60
|
+
accomplishmentKeyword: accomplishmentKeyword || '*',
|
|
61
|
+
};
|
|
58
62
|
}
|
|
59
63
|
/**
|
|
60
64
|
* Subscribe to accomplishment events
|
|
61
65
|
* @param accomplishmentTopic - The topic of the accomplishment event. The pattern can be any pattern of plugin.skillCategory.accomplishmentKeyword or an * as wildcard for any plugin, skill category or accomplishment keyword
|
|
62
66
|
* @param callback - The callback function to be called when the accomplishment event is triggered
|
|
63
67
|
*/
|
|
64
|
-
subscribe(accomplishmentTopics =
|
|
65
|
-
if (typeof accomplishmentTopics ===
|
|
68
|
+
subscribe(accomplishmentTopics = '*', callback) {
|
|
69
|
+
if (typeof accomplishmentTopics === 'string') {
|
|
66
70
|
accomplishmentTopics = [accomplishmentTopics];
|
|
67
71
|
}
|
|
68
72
|
accomplishmentTopics.forEach((accomplishmentTopic) => {
|
|
69
|
-
const topicLength = accomplishmentTopic.split(
|
|
73
|
+
const topicLength = accomplishmentTopic.split('.').length;
|
|
70
74
|
if (topicLength === 1) {
|
|
71
|
-
accomplishmentTopic +=
|
|
75
|
+
accomplishmentTopic += '.*.*';
|
|
72
76
|
}
|
|
73
77
|
else if (topicLength === 2) {
|
|
74
|
-
accomplishmentTopic +=
|
|
78
|
+
accomplishmentTopic += '.*';
|
|
75
79
|
}
|
|
76
80
|
else if (topicLength !== 3) {
|
|
77
|
-
throw new Error(
|
|
81
|
+
throw new Error('Invalid accomplishment topic pattern. The pattern must be plugin.skillCategory.accomplishmentKeyword or an * as wildcard for any plugin, skill category or accomplishment keyword');
|
|
78
82
|
}
|
|
79
|
-
EventBus.on([
|
|
83
|
+
EventBus.on(['global.accomplishment.triggerMicro', 'global.accomplishment.triggerMacro'], (event) => {
|
|
80
84
|
const { plugin, skillCategory, accomplishmentKeyword } = this.getDecoupledTopic(accomplishmentTopic);
|
|
81
|
-
if (plugin !==
|
|
85
|
+
if (plugin !== '*' && event.sender !== plugin)
|
|
82
86
|
return;
|
|
83
|
-
if (skillCategory !==
|
|
87
|
+
if (skillCategory !== '*' && event.data.skillCategory !== skillCategory)
|
|
84
88
|
return;
|
|
85
|
-
if (accomplishmentKeyword !==
|
|
89
|
+
if (accomplishmentKeyword !== '*' && event.data.accomplishmentKeyword !== accomplishmentKeyword)
|
|
86
90
|
return;
|
|
87
91
|
callback(event);
|
|
88
92
|
}, [this.pluginId]);
|
|
@@ -7,7 +7,7 @@ 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
|
|
10
|
+
import { EventBus } from '../fromRimori/EventBus';
|
|
11
11
|
/**
|
|
12
12
|
* AudioController is a class that provides methods to record audio. It is a wrapper around the Capacitor Voice Recorder plugin. For more information, see https://github.com/tchvu3/capacitor-voice-recorder.
|
|
13
13
|
*
|
|
@@ -29,7 +29,7 @@ export class AudioController {
|
|
|
29
29
|
*/
|
|
30
30
|
startRecording() {
|
|
31
31
|
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
-
EventBus.emit(this.pluginId,
|
|
32
|
+
EventBus.emit(this.pluginId, 'global.microphone.triggerStartRecording');
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
@@ -43,25 +43,25 @@ export class AudioController {
|
|
|
43
43
|
*/
|
|
44
44
|
stopRecording() {
|
|
45
45
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
-
const result = yield EventBus.request(this.pluginId,
|
|
46
|
+
const result = yield EventBus.request(this.pluginId, 'global.microphone.triggerStopRecording');
|
|
47
47
|
return result.data;
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
pauseRecording() {
|
|
51
51
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
-
const result = yield EventBus.request(this.pluginId,
|
|
52
|
+
const result = yield EventBus.request(this.pluginId, 'global.microphone.triggerPauseRecording');
|
|
53
53
|
return result.data;
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
resumeRecording() {
|
|
57
57
|
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
-
const result = yield EventBus.request(this.pluginId,
|
|
58
|
+
const result = yield EventBus.request(this.pluginId, 'global.microphone.triggerResumeRecording');
|
|
59
59
|
return result.data;
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
getCurrentStatus() {
|
|
63
63
|
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
-
const result = yield EventBus.request(this.pluginId,
|
|
64
|
+
const result = yield EventBus.request(this.pluginId, 'global.microphone.triggerGetCurrentStatus');
|
|
65
65
|
return result.data;
|
|
66
66
|
});
|
|
67
67
|
}
|
package/dist/plugin/Logger.d.ts
CHANGED
|
@@ -32,6 +32,11 @@ export declare class Logger {
|
|
|
32
32
|
* Override console methods globally to capture all console calls.
|
|
33
33
|
*/
|
|
34
34
|
private overrideConsoleMethods;
|
|
35
|
+
/**
|
|
36
|
+
* Get caller information from stack trace.
|
|
37
|
+
* @returns Object with location string and CSS style, or empty values for production
|
|
38
|
+
*/
|
|
39
|
+
private getCallerLocation;
|
|
35
40
|
/**
|
|
36
41
|
* Track mouse position for screenshot context.
|
|
37
42
|
*/
|
package/dist/plugin/Logger.js
CHANGED
|
@@ -25,7 +25,7 @@ export class Logger {
|
|
|
25
25
|
info: console.info,
|
|
26
26
|
warn: console.warn,
|
|
27
27
|
error: console.error,
|
|
28
|
-
debug: console.debug
|
|
28
|
+
debug: console.debug,
|
|
29
29
|
};
|
|
30
30
|
// Override console methods globally
|
|
31
31
|
this.overrideConsoleMethods();
|
|
@@ -40,7 +40,7 @@ export class Logger {
|
|
|
40
40
|
const logs = {
|
|
41
41
|
logs: this.logs,
|
|
42
42
|
pluginId: rimori.plugin.pluginId,
|
|
43
|
-
timestamp: new Date().toISOString()
|
|
43
|
+
timestamp: new Date().toISOString(),
|
|
44
44
|
};
|
|
45
45
|
this.logs = [];
|
|
46
46
|
this.logIdCounter = 0;
|
|
@@ -84,7 +84,7 @@ export class Logger {
|
|
|
84
84
|
if (typeof window === 'undefined' || typeof history === 'undefined')
|
|
85
85
|
return;
|
|
86
86
|
// Clear logs on browser back/forward
|
|
87
|
-
window.addEventListener('popstate', () => this.logs = []);
|
|
87
|
+
window.addEventListener('popstate', () => (this.logs = []));
|
|
88
88
|
// Override history methods to clear logs on programmatic navigation
|
|
89
89
|
const originalPushState = history.pushState;
|
|
90
90
|
const originalReplaceState = history.replaceState;
|
|
@@ -107,7 +107,7 @@ export class Logger {
|
|
|
107
107
|
// Check for URL changes periodically
|
|
108
108
|
setInterval(checkUrlChange, 100);
|
|
109
109
|
// Also listen for hash changes (for hash-based routing)
|
|
110
|
-
window.addEventListener('hashchange', () => this.logs = []);
|
|
110
|
+
window.addEventListener('hashchange', () => (this.logs = []));
|
|
111
111
|
}
|
|
112
112
|
/**
|
|
113
113
|
* Override console methods globally to capture all console calls.
|
|
@@ -115,30 +115,71 @@ export class Logger {
|
|
|
115
115
|
overrideConsoleMethods() {
|
|
116
116
|
// Override console.log
|
|
117
117
|
console.log = (...args) => {
|
|
118
|
-
this.
|
|
118
|
+
const { location, style } = this.getCallerLocation();
|
|
119
|
+
this.originalConsole.log(location, style, ...args);
|
|
119
120
|
this.handleConsoleCall('info', args);
|
|
120
121
|
};
|
|
121
122
|
// Override console.info
|
|
122
123
|
console.info = (...args) => {
|
|
123
|
-
this.
|
|
124
|
+
const { location, style } = this.getCallerLocation();
|
|
125
|
+
this.originalConsole.info(location, style, ...args);
|
|
124
126
|
this.handleConsoleCall('info', args);
|
|
125
127
|
};
|
|
126
128
|
// Override console.warn
|
|
127
129
|
console.warn = (...args) => {
|
|
128
|
-
this.
|
|
130
|
+
const { location, style } = this.getCallerLocation();
|
|
131
|
+
this.originalConsole.warn(location, style, ...args);
|
|
129
132
|
this.handleConsoleCall('warn', args);
|
|
130
133
|
};
|
|
131
134
|
// Override console.error
|
|
132
135
|
console.error = (...args) => {
|
|
133
|
-
this.
|
|
136
|
+
const { location, style } = this.getCallerLocation();
|
|
137
|
+
this.originalConsole.error(location, style, ...args);
|
|
134
138
|
this.handleConsoleCall('error', args);
|
|
135
139
|
};
|
|
136
140
|
// Override console.debug
|
|
137
141
|
console.debug = (...args) => {
|
|
138
|
-
this.
|
|
142
|
+
const { location, style } = this.getCallerLocation();
|
|
143
|
+
this.originalConsole.debug(location, style, ...args);
|
|
139
144
|
this.handleConsoleCall('debug', args);
|
|
140
145
|
};
|
|
141
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Get caller information from stack trace.
|
|
149
|
+
* @returns Object with location string and CSS style, or empty values for production
|
|
150
|
+
*/
|
|
151
|
+
getCallerLocation() {
|
|
152
|
+
const emptyResult = { location: '', style: '' };
|
|
153
|
+
const style = 'color: #0063A2; font-weight: bold;';
|
|
154
|
+
if (this.isProduction)
|
|
155
|
+
return emptyResult;
|
|
156
|
+
try {
|
|
157
|
+
const stack = new Error().stack;
|
|
158
|
+
if (!stack)
|
|
159
|
+
return emptyResult;
|
|
160
|
+
const stackLines = stack.split('\n');
|
|
161
|
+
// Skip the first 3 lines: Error, getCallerLocation, overrideConsoleMethods wrapper
|
|
162
|
+
const callerLine = stackLines[3];
|
|
163
|
+
if (!callerLine)
|
|
164
|
+
return emptyResult;
|
|
165
|
+
// Extract file name and line number from stack trace
|
|
166
|
+
// Format: "at functionName (file:line:column)" or "at file:line:column"
|
|
167
|
+
const match = callerLine.match(/(?:at\s+.*?\s+\()?([^/\\(]+\.(?:ts|tsx|js|jsx)):(\d+):(\d+)\)?/);
|
|
168
|
+
if (match) {
|
|
169
|
+
const [, fileName, lineNumber] = match;
|
|
170
|
+
return { style, location: `%c[${fileName}:${lineNumber}]` };
|
|
171
|
+
}
|
|
172
|
+
// Fallback: try to extract just the file name
|
|
173
|
+
const simpleMatch = callerLine.match(/([^/\\]+\.(?:ts|tsx|js|jsx))/);
|
|
174
|
+
if (simpleMatch) {
|
|
175
|
+
return { style, location: `%c[${simpleMatch[1]}]` };
|
|
176
|
+
}
|
|
177
|
+
return emptyResult;
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
return emptyResult;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
142
183
|
/**
|
|
143
184
|
* Track mouse position for screenshot context.
|
|
144
185
|
*/
|
|
@@ -148,7 +189,7 @@ export class Logger {
|
|
|
148
189
|
this.mousePosition = {
|
|
149
190
|
x: event.clientX,
|
|
150
191
|
y: event.clientY,
|
|
151
|
-
timestamp: new Date().toISOString()
|
|
192
|
+
timestamp: new Date().toISOString(),
|
|
152
193
|
};
|
|
153
194
|
};
|
|
154
195
|
window.addEventListener('mousemove', updateMousePosition);
|
|
@@ -167,7 +208,18 @@ export class Logger {
|
|
|
167
208
|
return;
|
|
168
209
|
}
|
|
169
210
|
// Convert console arguments to message and data
|
|
170
|
-
const message = args
|
|
211
|
+
const message = args
|
|
212
|
+
.map((arg) => {
|
|
213
|
+
if (typeof arg !== 'object')
|
|
214
|
+
return arg;
|
|
215
|
+
try {
|
|
216
|
+
return JSON.stringify(arg);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
return 'Error adding object to log: ' + error.message + ' ' + String(arg);
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
.join(' ');
|
|
171
223
|
const data = args.length > 1 ? args.slice(1) : undefined;
|
|
172
224
|
const entry = yield this.createLogEntry(level, message, data);
|
|
173
225
|
this.addLogEntry(entry);
|
|
@@ -185,7 +237,7 @@ export class Logger {
|
|
|
185
237
|
onLine: navigator.onLine,
|
|
186
238
|
screenResolution: `${screen.width}x${screen.height}`,
|
|
187
239
|
windowSize: `${window.innerWidth}x${window.innerHeight}`,
|
|
188
|
-
timestamp: new Date().toISOString()
|
|
240
|
+
timestamp: new Date().toISOString(),
|
|
189
241
|
};
|
|
190
242
|
}
|
|
191
243
|
/**
|
|
@@ -238,7 +290,7 @@ export class Logger {
|
|
|
238
290
|
level,
|
|
239
291
|
message,
|
|
240
292
|
data,
|
|
241
|
-
context: context
|
|
293
|
+
context: context,
|
|
242
294
|
};
|
|
243
295
|
});
|
|
244
296
|
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
2
|
import { UserInfo } from '../core/controller/SettingsController';
|
|
3
3
|
import { ActivePlugin, Plugin } from '../fromRimori/PluginTypes';
|
|
4
|
-
import { RimoriClient } from
|
|
4
|
+
import { RimoriClient } from './RimoriClient';
|
|
5
|
+
export interface Guild {
|
|
6
|
+
id: string;
|
|
7
|
+
longTermGoalOverride: string;
|
|
8
|
+
allowUserPluginSettings: boolean;
|
|
9
|
+
}
|
|
5
10
|
export interface RimoriInfo {
|
|
6
11
|
url: string;
|
|
7
12
|
key: string;
|
|
@@ -10,6 +15,7 @@ export interface RimoriInfo {
|
|
|
10
15
|
expiration: Date;
|
|
11
16
|
tablePrefix: string;
|
|
12
17
|
pluginId: string;
|
|
18
|
+
guild: Guild;
|
|
13
19
|
installedPlugins: Plugin[];
|
|
14
20
|
profile: UserInfo;
|
|
15
21
|
mainPanelPlugin?: ActivePlugin;
|
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { createClient } from '@supabase/supabase-js';
|
|
11
11
|
import { EventBus } from '../fromRimori/EventBus';
|
|
12
|
-
import { RimoriClient } from
|
|
12
|
+
import { RimoriClient } from './RimoriClient';
|
|
13
13
|
import { StandaloneClient } from './StandaloneClient';
|
|
14
14
|
import { setTheme } from './ThemeSetter';
|
|
15
15
|
import { Logger } from './Logger';
|
|
@@ -36,11 +36,15 @@ export class PluginController {
|
|
|
36
36
|
}
|
|
37
37
|
initMessageChannel(worker = false) {
|
|
38
38
|
const listener = (event) => {
|
|
39
|
-
console.log(
|
|
39
|
+
console.log('[PluginController] window message', { origin: event.origin, data: event.data });
|
|
40
40
|
const { type, pluginId, queryParams, rimoriInfo } = event.data || {};
|
|
41
41
|
const [transferredPort] = event.ports || [];
|
|
42
|
-
if (type !==
|
|
43
|
-
console.log(
|
|
42
|
+
if (type !== 'rimori:init' || !transferredPort || pluginId !== this.pluginId) {
|
|
43
|
+
console.log('[PluginController] message ignored (not init or wrong plugin)', {
|
|
44
|
+
type,
|
|
45
|
+
pluginId,
|
|
46
|
+
hasPort: !!transferredPort,
|
|
47
|
+
});
|
|
44
48
|
return;
|
|
45
49
|
}
|
|
46
50
|
this.queryParams = queryParams || {};
|
|
@@ -49,7 +53,7 @@ export class PluginController {
|
|
|
49
53
|
if (rimoriInfo) {
|
|
50
54
|
this.rimoriInfo = rimoriInfo;
|
|
51
55
|
this.supabase = createClient(rimoriInfo.url, rimoriInfo.key, {
|
|
52
|
-
accessToken: () => Promise.resolve(rimoriInfo.token)
|
|
56
|
+
accessToken: () => Promise.resolve(rimoriInfo.token),
|
|
53
57
|
});
|
|
54
58
|
}
|
|
55
59
|
// Handle messages from parent
|
|
@@ -75,38 +79,38 @@ export class PluginController {
|
|
|
75
79
|
setTheme(theme);
|
|
76
80
|
}
|
|
77
81
|
// Forward plugin events to parent (only after MessageChannel is ready)
|
|
78
|
-
EventBus.on(
|
|
82
|
+
EventBus.on('*', (ev) => {
|
|
79
83
|
var _a;
|
|
80
|
-
if (ev.sender === this.pluginId && !ev.topic.startsWith(
|
|
84
|
+
if (ev.sender === this.pluginId && !ev.topic.startsWith('self.')) {
|
|
81
85
|
(_a = this.port) === null || _a === void 0 ? void 0 : _a.postMessage({ event: ev });
|
|
82
86
|
}
|
|
83
87
|
});
|
|
84
88
|
// Mark MessageChannel as ready and process pending requests
|
|
85
89
|
this.isMessageChannelReady = true;
|
|
86
90
|
// Process any pending requests
|
|
87
|
-
this.pendingRequests.forEach(request => request());
|
|
91
|
+
this.pendingRequests.forEach((request) => request());
|
|
88
92
|
this.pendingRequests = [];
|
|
89
93
|
};
|
|
90
94
|
if (worker) {
|
|
91
95
|
self.onmessage = listener;
|
|
92
96
|
}
|
|
93
97
|
else {
|
|
94
|
-
window.addEventListener(
|
|
98
|
+
window.addEventListener('message', listener);
|
|
95
99
|
}
|
|
96
100
|
this.sendHello(worker);
|
|
97
101
|
}
|
|
98
102
|
sendHello(isWorker = false) {
|
|
99
103
|
try {
|
|
100
|
-
const payload = { type:
|
|
104
|
+
const payload = { type: 'rimori:hello', pluginId: this.pluginId };
|
|
101
105
|
if (isWorker) {
|
|
102
106
|
self.postMessage(payload);
|
|
103
107
|
}
|
|
104
108
|
else {
|
|
105
|
-
window.parent.postMessage(payload,
|
|
109
|
+
window.parent.postMessage(payload, '*');
|
|
106
110
|
}
|
|
107
111
|
}
|
|
108
112
|
catch (e) {
|
|
109
|
-
console.error(
|
|
113
|
+
console.error('[PluginController] Error sending hello:', e);
|
|
110
114
|
}
|
|
111
115
|
}
|
|
112
116
|
static getInstance(pluginId_1) {
|
|
@@ -118,7 +122,7 @@ export class PluginController {
|
|
|
118
122
|
PluginController.instance = new PluginController(pluginId, standalone);
|
|
119
123
|
PluginController.client = yield RimoriClient.getInstance(PluginController.instance);
|
|
120
124
|
//only init logger in workers and on main plugin pages
|
|
121
|
-
if (PluginController.instance.getQueryParam(
|
|
125
|
+
if (PluginController.instance.getQueryParam('applicationMode') !== 'sidebar') {
|
|
122
126
|
Logger.getInstance(PluginController.client);
|
|
123
127
|
}
|
|
124
128
|
}
|
|
@@ -159,8 +163,8 @@ export class PluginController {
|
|
|
159
163
|
sender: this.pluginId,
|
|
160
164
|
topic: 'global.supabase.requestAccess',
|
|
161
165
|
data: {},
|
|
162
|
-
debug: false
|
|
163
|
-
}
|
|
166
|
+
debug: false,
|
|
167
|
+
},
|
|
164
168
|
};
|
|
165
169
|
return new Promise((resolve) => {
|
|
166
170
|
// Listen for the response
|
|
@@ -170,7 +174,7 @@ export class PluginController {
|
|
|
170
174
|
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
175
|
this.rimoriInfo = event.data.data;
|
|
172
176
|
this.supabase = createClient(this.rimoriInfo.url, this.rimoriInfo.key, {
|
|
173
|
-
accessToken: () => Promise.resolve(this.getToken())
|
|
177
|
+
accessToken: () => Promise.resolve(this.getToken()),
|
|
174
178
|
});
|
|
175
179
|
self.onmessage = originalOnMessage; // Restore original handler
|
|
176
180
|
resolve({ supabase: this.supabase, info: this.rimoriInfo });
|
|
@@ -185,10 +189,11 @@ export class PluginController {
|
|
|
185
189
|
}
|
|
186
190
|
else {
|
|
187
191
|
// In main thread context, use EventBus
|
|
188
|
-
const { data } = yield EventBus.request(this.pluginId,
|
|
192
|
+
const { data } = yield EventBus.request(this.pluginId, 'global.supabase.requestAccess');
|
|
193
|
+
console.log({ data });
|
|
189
194
|
this.rimoriInfo = data;
|
|
190
195
|
this.supabase = createClient(this.rimoriInfo.url, this.rimoriInfo.key, {
|
|
191
|
-
accessToken: () => Promise.resolve(this.getToken())
|
|
196
|
+
accessToken: () => Promise.resolve(this.getToken()),
|
|
192
197
|
});
|
|
193
198
|
}
|
|
194
199
|
}
|
|
@@ -202,12 +207,12 @@ export class PluginController {
|
|
|
202
207
|
}
|
|
203
208
|
// If we don't have rimoriInfo, request it
|
|
204
209
|
if (!this.rimoriInfo) {
|
|
205
|
-
const { data } = yield EventBus.request(this.pluginId,
|
|
210
|
+
const { data } = yield EventBus.request(this.pluginId, 'global.supabase.requestAccess');
|
|
206
211
|
this.rimoriInfo = data;
|
|
207
212
|
return this.rimoriInfo.token;
|
|
208
213
|
}
|
|
209
214
|
// If token is expired, request fresh access
|
|
210
|
-
const { data } = yield EventBus.request(this.pluginId,
|
|
215
|
+
const { data } = yield EventBus.request(this.pluginId, 'global.supabase.requestAccess');
|
|
211
216
|
this.rimoriInfo.token = data.token;
|
|
212
217
|
this.rimoriInfo.expiration = data.expiration;
|
|
213
218
|
return this.rimoriInfo.token;
|
|
@@ -220,27 +225,27 @@ export class PluginController {
|
|
|
220
225
|
*/
|
|
221
226
|
getSupabaseUrl() {
|
|
222
227
|
if (!this.rimoriInfo) {
|
|
223
|
-
throw new Error(
|
|
228
|
+
throw new Error('Supabase info not found');
|
|
224
229
|
}
|
|
225
230
|
return this.rimoriInfo.url;
|
|
226
231
|
}
|
|
227
232
|
getBackendUrl() {
|
|
228
233
|
if (!this.rimoriInfo) {
|
|
229
|
-
throw new Error(
|
|
234
|
+
throw new Error('Rimori info not found');
|
|
230
235
|
}
|
|
231
236
|
return this.rimoriInfo.backendUrl;
|
|
232
237
|
}
|
|
233
238
|
getGlobalEventTopic(preliminaryTopic) {
|
|
234
239
|
var _a, _b;
|
|
235
|
-
if (preliminaryTopic.startsWith(
|
|
240
|
+
if (preliminaryTopic.startsWith('global.')) {
|
|
236
241
|
return preliminaryTopic;
|
|
237
242
|
}
|
|
238
|
-
if (preliminaryTopic.startsWith(
|
|
243
|
+
if (preliminaryTopic.startsWith('self.')) {
|
|
239
244
|
return preliminaryTopic;
|
|
240
245
|
}
|
|
241
|
-
const topicParts = preliminaryTopic.split(
|
|
246
|
+
const topicParts = preliminaryTopic.split('.');
|
|
242
247
|
if (topicParts.length === 3) {
|
|
243
|
-
if (!topicParts[0].startsWith(
|
|
248
|
+
if (!topicParts[0].startsWith('pl') && topicParts[0] !== 'global') {
|
|
244
249
|
throw new Error("The event topic must start with the plugin id or 'global'.");
|
|
245
250
|
}
|
|
246
251
|
return preliminaryTopic;
|
|
@@ -248,7 +253,7 @@ export class PluginController {
|
|
|
248
253
|
else if (topicParts.length > 3) {
|
|
249
254
|
throw new Error(`The event topic must consist of 3 parts. <pluginId>.<topic area>.<action>. Received: ${preliminaryTopic}`);
|
|
250
255
|
}
|
|
251
|
-
const topicRoot = (_b = (_a = this.rimoriInfo) === null || _a === void 0 ? void 0 : _a.pluginId) !== null && _b !== void 0 ? _b :
|
|
256
|
+
const topicRoot = (_b = (_a = this.rimoriInfo) === null || _a === void 0 ? void 0 : _a.pluginId) !== null && _b !== void 0 ? _b : 'global';
|
|
252
257
|
return `${topicRoot}.${preliminaryTopic}`;
|
|
253
258
|
}
|
|
254
259
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { PostgrestQueryBuilder } from
|
|
2
|
-
import { GenericSchema } from
|
|
3
|
-
import { Message, OnLLMResponse } from
|
|
4
|
-
import { ObjectRequest } from
|
|
5
|
-
import { UserInfo } from
|
|
6
|
-
import { SharedContent, SharedContentFilter, SharedContentObjectRequest } from
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
1
|
+
import { PostgrestQueryBuilder } from '@supabase/postgrest-js';
|
|
2
|
+
import { GenericSchema } from '@supabase/supabase-js/dist/module/lib/types';
|
|
3
|
+
import { Message, OnLLMResponse } from '../core/controller/AIController';
|
|
4
|
+
import { ObjectRequest } from '../core/controller/ObjectController';
|
|
5
|
+
import { UserInfo } from '../core/controller/SettingsController';
|
|
6
|
+
import { SharedContent, SharedContentFilter, SharedContentObjectRequest } from '../core/controller/SharedContentController';
|
|
7
|
+
import { CreateExerciseParams } from '../core/controller/ExerciseController';
|
|
8
|
+
import { EventBusMessage, EventHandler, EventPayload } from '../fromRimori/EventBus';
|
|
9
|
+
import { ActivePlugin, MainPanelAction, Plugin, Tool } from '../fromRimori/PluginTypes';
|
|
10
|
+
import { AccomplishmentPayload } from './AccomplishmentHandler';
|
|
11
|
+
import { PluginController } from './PluginController';
|
|
11
12
|
interface Db {
|
|
12
13
|
from: {
|
|
13
14
|
<TableName extends string & keyof GenericSchema['Tables'], Table extends GenericSchema['Tables'][TableName]>(relation: TableName): PostgrestQueryBuilder<GenericSchema, Table, TableName>;
|
|
@@ -63,6 +64,7 @@ export declare class RimoriClient {
|
|
|
63
64
|
private pluginController;
|
|
64
65
|
private settingsController;
|
|
65
66
|
private sharedContentController;
|
|
67
|
+
private exerciseController;
|
|
66
68
|
private accomplishmentHandler;
|
|
67
69
|
private rimoriInfo;
|
|
68
70
|
plugin: PluginInterface;
|
|
@@ -202,10 +204,10 @@ export declare class RimoriClient {
|
|
|
202
204
|
*/
|
|
203
205
|
update: <T = any>(id: string, content: Partial<SharedContent<T>>) => Promise<SharedContent<T>>;
|
|
204
206
|
/**
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
* Complete a shared content item.
|
|
208
|
+
* @param contentType The type of shared content to complete. E.g. assignments, exercises, etc.
|
|
209
|
+
* @param assignmentId The id of the shared content item to complete.
|
|
210
|
+
*/
|
|
209
211
|
complete: (contentType: string, assignmentId: string) => Promise<void>;
|
|
210
212
|
/**
|
|
211
213
|
/**
|
|
@@ -227,5 +229,28 @@ export declare class RimoriClient {
|
|
|
227
229
|
remove: (id: string) => Promise<SharedContent<any>>;
|
|
228
230
|
};
|
|
229
231
|
};
|
|
232
|
+
exercise: {
|
|
233
|
+
/**
|
|
234
|
+
* Fetches weekly exercises from the weekly_exercises view.
|
|
235
|
+
* Shows exercises for the current week that haven't expired.
|
|
236
|
+
* @returns Array of exercise objects.
|
|
237
|
+
*/
|
|
238
|
+
view: () => Promise<import("../core/controller/ExerciseController").Exercise[]>;
|
|
239
|
+
/**
|
|
240
|
+
* Creates a new exercise via the backend API.
|
|
241
|
+
* @param params Exercise creation parameters.
|
|
242
|
+
* @returns Created exercise object.
|
|
243
|
+
*/
|
|
244
|
+
add: (params: CreateExerciseParams) => Promise<import("../core/controller/ExerciseController").Exercise>;
|
|
245
|
+
/**
|
|
246
|
+
* Deletes an exercise via the backend API.
|
|
247
|
+
* @param id The exercise ID to delete.
|
|
248
|
+
* @returns Success status.
|
|
249
|
+
*/
|
|
250
|
+
delete: (id: string) => Promise<{
|
|
251
|
+
success: boolean;
|
|
252
|
+
message: string;
|
|
253
|
+
}>;
|
|
254
|
+
};
|
|
230
255
|
}
|
|
231
256
|
export {};
|