@rimori/client 2.1.8 → 2.2.0-next.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.
- package/.github/workflows/pre-release.yml +105 -0
- package/dist/cli/scripts/init/main.js +0 -0
- package/dist/cli/scripts/release/release.js +0 -0
- package/dist/cli/types/DatabaseTypes.d.ts +12 -4
- package/dist/controller/AccomplishmentController.js +6 -2
- package/dist/controller/SettingsController.d.ts +6 -2
- package/dist/controller/SharedContentController.js +28 -25
- package/dist/controller/TranslationController.d.ts +2 -1
- package/dist/controller/TranslationController.js +37 -16
- package/dist/fromRimori/EventBus.js +45 -18
- package/dist/index.d.ts +2 -1
- package/dist/plugin/CommunicationHandler.d.ts +1 -0
- package/dist/plugin/CommunicationHandler.js +9 -7
- package/dist/plugin/Logger.d.ts +1 -0
- package/dist/plugin/Logger.js +15 -3
- package/dist/plugin/RimoriClient.js +18 -8
- package/package.json +15 -1
- package/src/cli/types/DatabaseTypes.ts +17 -16
- package/src/controller/AccomplishmentController.ts +7 -3
- package/src/controller/SettingsController.ts +7 -2
- package/src/controller/SharedContentController.ts +34 -32
- package/src/controller/TranslationController.ts +47 -20
- package/src/fromRimori/EventBus.ts +146 -49
- package/src/index.ts +2 -1
- package/src/plugin/CommunicationHandler.ts +10 -7
- package/src/plugin/Logger.ts +15 -3
- package/src/plugin/RimoriClient.ts +19 -8
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
name: Pre-Release Rimori Client
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [dev]
|
|
6
|
+
paths:
|
|
7
|
+
- '**'
|
|
8
|
+
- '!.github/workflows/**'
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
pre-release:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
permissions:
|
|
14
|
+
contents: write
|
|
15
|
+
id-token: write
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout repository
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
|
|
24
|
+
- name: Setup Node.js
|
|
25
|
+
uses: actions/setup-node@v4
|
|
26
|
+
with:
|
|
27
|
+
node-version: '20'
|
|
28
|
+
registry-url: 'https://registry.npmjs.org'
|
|
29
|
+
cache: 'yarn'
|
|
30
|
+
cache-dependency-path: yarn.lock
|
|
31
|
+
|
|
32
|
+
- name: Update npm
|
|
33
|
+
run: npm install -g npm@latest
|
|
34
|
+
|
|
35
|
+
- name: Install dependencies
|
|
36
|
+
run: yarn install --frozen-lockfile
|
|
37
|
+
|
|
38
|
+
- name: Build rimori-client (TypeScript verification)
|
|
39
|
+
run: yarn build
|
|
40
|
+
|
|
41
|
+
- name: Calculate next pre-release version
|
|
42
|
+
id: version
|
|
43
|
+
run: |
|
|
44
|
+
# Read current version from package.json (may be base or pre-release)
|
|
45
|
+
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
46
|
+
|
|
47
|
+
# Extract base version (strip any pre-release suffix)
|
|
48
|
+
# Examples: "2.2.0" -> "2.2.0", "2.2.0-next.5" -> "2.2.0"
|
|
49
|
+
if [[ "$CURRENT_VERSION" =~ ^([0-9]+\.[0-9]+\.[0-9]+) ]]; then
|
|
50
|
+
BASE_VERSION="${BASH_REMATCH[1]}"
|
|
51
|
+
else
|
|
52
|
+
BASE_VERSION="$CURRENT_VERSION"
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Try to get latest next version from npm
|
|
56
|
+
LATEST_NEXT=$(npm view @rimori/client@next version 2>/dev/null || echo "none")
|
|
57
|
+
|
|
58
|
+
if [ "$LATEST_NEXT" != "none" ]; then
|
|
59
|
+
# Extract base version and pre-release number from latest next version
|
|
60
|
+
# Example: "2.2.0-next.5" -> extract "2.2.0" and "5"
|
|
61
|
+
if [[ "$LATEST_NEXT" =~ ^([0-9]+\.[0-9]+\.[0-9]+)-next\.([0-9]+)$ ]]; then
|
|
62
|
+
LATEST_BASE="${BASH_REMATCH[1]}"
|
|
63
|
+
PRERELEASE_NUM="${BASH_REMATCH[2]}"
|
|
64
|
+
|
|
65
|
+
# If base version changed, reset to 1, otherwise increment
|
|
66
|
+
if [ "$LATEST_BASE" != "$BASE_VERSION" ]; then
|
|
67
|
+
NEW_NUM=1
|
|
68
|
+
else
|
|
69
|
+
NEW_NUM=$((PRERELEASE_NUM + 1))
|
|
70
|
+
fi
|
|
71
|
+
else
|
|
72
|
+
# Fallback: if format doesn't match, start at 1
|
|
73
|
+
NEW_NUM=1
|
|
74
|
+
fi
|
|
75
|
+
else
|
|
76
|
+
# First pre-release
|
|
77
|
+
NEW_NUM=1
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
NEW_VERSION="${BASE_VERSION}-next.${NEW_NUM}"
|
|
81
|
+
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
|
82
|
+
echo "Base version: $BASE_VERSION"
|
|
83
|
+
echo "Calculated next version: $NEW_VERSION"
|
|
84
|
+
|
|
85
|
+
- name: Update package.json version
|
|
86
|
+
run: |
|
|
87
|
+
# Use node to update version directly (yarn version creates git tags)
|
|
88
|
+
node -e "const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync('package.json')); pkg.version = '${{ steps.version.outputs.new_version }}'; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');"
|
|
89
|
+
|
|
90
|
+
- name: Publish to npm
|
|
91
|
+
run: npm publish --tag next --access public
|
|
92
|
+
# Uses OIDC token automatically (no NODE_AUTH_TOKEN needed)
|
|
93
|
+
# Requires npm 11.5.1+ and id-token: write permission (already set)
|
|
94
|
+
|
|
95
|
+
- name: Commit version bump
|
|
96
|
+
run: |
|
|
97
|
+
git config --local user.email "action@github.com"
|
|
98
|
+
git config --local user.name "GitHub Action"
|
|
99
|
+
git add package.json
|
|
100
|
+
git commit -m "chore: bump @rimori/client to ${{ steps.version.outputs.new_version }} [skip ci]"
|
|
101
|
+
git push
|
|
102
|
+
|
|
103
|
+
- name: Output published version
|
|
104
|
+
run: |
|
|
105
|
+
echo "✅ Published @rimori/client@${{ steps.version.outputs.new_version }} to npm with @next tag"
|
|
File without changes
|
|
File without changes
|
|
@@ -42,8 +42,10 @@ export interface DbColumnDefinition {
|
|
|
42
42
|
restrict?: {
|
|
43
43
|
/** Restrictions for the user */
|
|
44
44
|
user: Partial<Omit<DbPermissionDefinition, 'delete'>>;
|
|
45
|
-
/** Restrictions for the moderator */
|
|
46
|
-
|
|
45
|
+
/** Restrictions for the guild moderator */
|
|
46
|
+
guild_moderator?: Partial<Omit<DbPermissionDefinition, 'delete'>>;
|
|
47
|
+
/** Restrictions for the language moderator */
|
|
48
|
+
lang_moderator?: Partial<Omit<DbPermissionDefinition, 'delete'>>;
|
|
47
49
|
};
|
|
48
50
|
}
|
|
49
51
|
/**
|
|
@@ -69,8 +71,12 @@ export interface DbTableDefinition {
|
|
|
69
71
|
description: string;
|
|
70
72
|
/** Permissions for the table */
|
|
71
73
|
permissions: {
|
|
74
|
+
/** Permissions for the user */
|
|
72
75
|
user: DbPermissionDefinition;
|
|
73
|
-
moderator
|
|
76
|
+
/** Permissions for the guild moderator */
|
|
77
|
+
guild_moderator?: DbPermissionDefinition;
|
|
78
|
+
/** Permissions for the language moderator */
|
|
79
|
+
lang_moderator?: DbPermissionDefinition;
|
|
74
80
|
};
|
|
75
81
|
/** Column definitions for the table */
|
|
76
82
|
columns: {
|
|
@@ -81,11 +87,13 @@ export interface DbTableDefinition {
|
|
|
81
87
|
* Permission definition for a database table.
|
|
82
88
|
* NONE means the action is not allowed.
|
|
83
89
|
* OWN means only do the action on your own records.
|
|
90
|
+
* GUILD means do the action on all records in the guild.
|
|
91
|
+
* LANG means do the action on all records in the language.
|
|
84
92
|
* ALL means do the action on all records.
|
|
85
93
|
*
|
|
86
94
|
* Defines the permissions for a database table.
|
|
87
95
|
*/
|
|
88
|
-
export type DbPermission = 'NONE' | 'OWN' | 'ALL';
|
|
96
|
+
export type DbPermission = 'NONE' | 'OWN' | 'GUILD' | 'LANG' | 'ALL';
|
|
89
97
|
/**
|
|
90
98
|
* Permission definition for a database table.
|
|
91
99
|
* Defines the permissions for a database table.
|
|
@@ -6,7 +6,9 @@ export class AccomplishmentController {
|
|
|
6
6
|
}
|
|
7
7
|
emitAccomplishment(payload) {
|
|
8
8
|
const accomplishmentPayload = Object.assign(Object.assign({}, payload), { type: 'durationMinutes' in payload ? 'macro' : 'micro' });
|
|
9
|
-
this.validateAccomplishment(accomplishmentPayload)
|
|
9
|
+
if (!this.validateAccomplishment(accomplishmentPayload)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
10
12
|
const sanitizedPayload = this.sanitizeAccomplishment(accomplishmentPayload);
|
|
11
13
|
const topic = 'global.accomplishment.trigger' + (accomplishmentPayload.type === 'macro' ? 'Macro' : 'Micro');
|
|
12
14
|
EventBus.emit(this.pluginId, topic, sanitizedPayload);
|
|
@@ -29,7 +31,8 @@ export class AccomplishmentController {
|
|
|
29
31
|
}
|
|
30
32
|
//durationMinutes is required
|
|
31
33
|
if (payload.type === 'macro' && payload.durationMinutes < 4) {
|
|
32
|
-
|
|
34
|
+
console.warn('The duration must be at least 4 minutes');
|
|
35
|
+
return false;
|
|
33
36
|
}
|
|
34
37
|
//errorRatio is required
|
|
35
38
|
if (payload.type === 'macro' && (payload.errorRatio < 0 || payload.errorRatio > 1)) {
|
|
@@ -43,6 +46,7 @@ export class AccomplishmentController {
|
|
|
43
46
|
}
|
|
44
47
|
});
|
|
45
48
|
}
|
|
49
|
+
return true;
|
|
46
50
|
}
|
|
47
51
|
sanitizeAccomplishment(payload) {
|
|
48
52
|
var _a;
|
|
@@ -16,6 +16,7 @@ export interface Language {
|
|
|
16
16
|
capitalized: string;
|
|
17
17
|
uppercase: string;
|
|
18
18
|
}
|
|
19
|
+
export type UserRole = 'user' | 'plugin_moderator' | 'lang_moderator' | 'admin';
|
|
19
20
|
export interface UserInfo {
|
|
20
21
|
skill_level_reading: LanguageLevel;
|
|
21
22
|
skill_level_writing: LanguageLevel;
|
|
@@ -29,8 +30,7 @@ export interface UserInfo {
|
|
|
29
30
|
story_genre: string;
|
|
30
31
|
study_duration: number;
|
|
31
32
|
/**
|
|
32
|
-
* The
|
|
33
|
-
* With the function getLanguageName, the language name can be retrieved.
|
|
33
|
+
* The language the user speaks natively.
|
|
34
34
|
*/
|
|
35
35
|
mother_tongue: Language;
|
|
36
36
|
/**
|
|
@@ -49,6 +49,10 @@ export interface UserInfo {
|
|
|
49
49
|
* Optional: nearest big city (>100,000) near user's location
|
|
50
50
|
*/
|
|
51
51
|
target_city?: string;
|
|
52
|
+
/**
|
|
53
|
+
* The user's role: 'user', 'plugin_moderator', 'lang_moderator', or 'admin'
|
|
54
|
+
*/
|
|
55
|
+
user_role: UserRole;
|
|
52
56
|
}
|
|
53
57
|
export declare class SettingsController {
|
|
54
58
|
private pluginId;
|
|
@@ -28,31 +28,34 @@ export class SharedContentController {
|
|
|
28
28
|
//this filter is there if the content should be filtered additionally by a column and value
|
|
29
29
|
filter, options) {
|
|
30
30
|
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
31
|
+
// The db cache of the shared content is temporary disabled until the new shared content implementation is completed
|
|
32
|
+
// if (false) {
|
|
33
|
+
// let query = this.supabase
|
|
34
|
+
// .from('shared_content')
|
|
35
|
+
// .select('*, scc:shared_content_completed(id, state)')
|
|
36
|
+
// .eq('content_type', contentType)
|
|
37
|
+
// .not('scc.state', 'in', '("completed","ongoing","hidden")')
|
|
38
|
+
// .is('deleted_at', null);
|
|
39
|
+
// if (options?.excludeIds?.length ?? 0 > 0) {
|
|
40
|
+
// const excludeIds = options.excludeIds.filter((id) => !id.startsWith('internal-temp-id-'));
|
|
41
|
+
// // Supabase expects raw PostgREST syntax like '("id1","id2")'.
|
|
42
|
+
// const excludeList = `(${excludeIds.map((id) => `"${id}"`).join(',')})`;
|
|
43
|
+
// query = query.not('id', 'in', excludeList);
|
|
44
|
+
// }
|
|
45
|
+
// if (filter) {
|
|
46
|
+
// query.contains('data', filter);
|
|
47
|
+
// }
|
|
48
|
+
// const { data: newAssignments, error } = await query.limit(30);
|
|
49
|
+
// if (error) {
|
|
50
|
+
// console.error('error fetching new assignments:', error);
|
|
51
|
+
// throw new Error('error fetching new assignments');
|
|
52
|
+
// }
|
|
53
|
+
// // console.log('newAssignments:', newAssignments);
|
|
54
|
+
// if (!options?.alwaysGenerateNew && newAssignments.length > 0) {
|
|
55
|
+
// const index = Math.floor(Math.random() * newAssignments.length);
|
|
56
|
+
// return newAssignments[index];
|
|
57
|
+
// }
|
|
58
|
+
// }
|
|
56
59
|
const instructions = yield this.generateNewAssignment(contentType, generatorInstructions, filter);
|
|
57
60
|
console.log('instructions:', instructions);
|
|
58
61
|
//create the shared content object
|
|
@@ -4,7 +4,8 @@ import { ThirdPartyModule, TOptions } from 'i18next';
|
|
|
4
4
|
*/
|
|
5
5
|
export declare class Translator {
|
|
6
6
|
private currentLanguage;
|
|
7
|
-
private
|
|
7
|
+
private initializationState;
|
|
8
|
+
private initializationPromise;
|
|
8
9
|
private i18n;
|
|
9
10
|
constructor(initialLanguage: string);
|
|
10
11
|
/**
|
|
@@ -13,8 +13,9 @@ import { createInstance } from 'i18next';
|
|
|
13
13
|
*/
|
|
14
14
|
export class Translator {
|
|
15
15
|
constructor(initialLanguage) {
|
|
16
|
-
this.isInitialized = false;
|
|
17
16
|
this.currentLanguage = initialLanguage;
|
|
17
|
+
this.initializationState = 'not-inited';
|
|
18
|
+
this.initializationPromise = null;
|
|
18
19
|
}
|
|
19
20
|
/**
|
|
20
21
|
* Initialize translator with user's language
|
|
@@ -22,21 +23,41 @@ export class Translator {
|
|
|
22
23
|
*/
|
|
23
24
|
initialize() {
|
|
24
25
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
|
|
26
|
+
// If already finished, return immediately
|
|
27
|
+
if (this.initializationState === 'finished') {
|
|
26
28
|
return;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
}
|
|
30
|
+
// If currently initializing, wait for the existing initialization to complete
|
|
31
|
+
if (this.initializationState === 'initing' && this.initializationPromise) {
|
|
32
|
+
return this.initializationPromise;
|
|
33
|
+
}
|
|
34
|
+
// Start initialization
|
|
35
|
+
this.initializationState = 'initing';
|
|
36
|
+
// Create a promise that will be resolved when initialization completes
|
|
37
|
+
this.initializationPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
try {
|
|
39
|
+
const translations = yield this.fetchTranslations(this.currentLanguage);
|
|
40
|
+
const instance = createInstance({
|
|
41
|
+
lng: this.currentLanguage,
|
|
42
|
+
resources: {
|
|
43
|
+
[this.currentLanguage]: {
|
|
44
|
+
translation: translations,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
debug: window.location.hostname === 'localhost',
|
|
48
|
+
});
|
|
49
|
+
yield instance.init();
|
|
50
|
+
this.i18n = instance;
|
|
51
|
+
this.initializationState = 'finished';
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
// Reset state on error so it can be retried
|
|
55
|
+
this.initializationState = 'not-inited';
|
|
56
|
+
this.initializationPromise = null;
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}))();
|
|
60
|
+
return this.initializationPromise;
|
|
40
61
|
});
|
|
41
62
|
}
|
|
42
63
|
getTranslationUrl(language) {
|
|
@@ -101,6 +122,6 @@ export class Translator {
|
|
|
101
122
|
* Check if translator is initialized
|
|
102
123
|
*/
|
|
103
124
|
isReady() {
|
|
104
|
-
return this.
|
|
125
|
+
return this.initializationState === 'finished';
|
|
105
126
|
}
|
|
106
127
|
}
|
|
@@ -67,7 +67,7 @@ export class EventBusHandler {
|
|
|
67
67
|
}
|
|
68
68
|
const event = this.createEvent(sender, topic, data, eventId);
|
|
69
69
|
const handlers = this.getMatchingHandlers(event.topic);
|
|
70
|
-
handlers.forEach(handler => {
|
|
70
|
+
handlers.forEach((handler) => {
|
|
71
71
|
if (handler.ignoreSender && handler.ignoreSender.includes(sender)) {
|
|
72
72
|
// console.log("ignore event as its in the ignoreSender list", { event, ignoreList: handler.ignoreSender });
|
|
73
73
|
return;
|
|
@@ -79,7 +79,9 @@ export class EventBusHandler {
|
|
|
79
79
|
this.logAndThrowError(false, `No handlers found for topic: ` + topic);
|
|
80
80
|
}
|
|
81
81
|
// If it's a response to a request
|
|
82
|
-
if (eventId &&
|
|
82
|
+
if (eventId &&
|
|
83
|
+
this.responseResolvers.has(eventId) &&
|
|
84
|
+
!skipResponseTrigger) {
|
|
83
85
|
// console.log("[Rimori] Resolving response to request: " + eventId, event.data);
|
|
84
86
|
this.responseResolvers.get(eventId)(event);
|
|
85
87
|
this.responseResolvers.delete(eventId);
|
|
@@ -93,7 +95,7 @@ export class EventBusHandler {
|
|
|
93
95
|
* @returns An EventListener object containing an off() method to unsubscribe the listeners.
|
|
94
96
|
*/
|
|
95
97
|
on(topics, handler, ignoreSender = []) {
|
|
96
|
-
const ids = this.toArray(topics).map(topic => {
|
|
98
|
+
const ids = this.toArray(topics).map((topic) => {
|
|
97
99
|
this.logIfDebug(`Subscribing to ` + topic, { ignoreSender });
|
|
98
100
|
if (!this.validateTopic(topic)) {
|
|
99
101
|
this.logAndThrowError(true, `Invalid topic: ` + topic);
|
|
@@ -102,14 +104,33 @@ export class EventBusHandler {
|
|
|
102
104
|
this.listeners.set(topic, new Set());
|
|
103
105
|
}
|
|
104
106
|
const id = Math.floor(Math.random() * 10000000000);
|
|
105
|
-
//
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
// To prevent infinite loops and processing the same eventId multiple times
|
|
108
|
+
const blackListedEventIds = [];
|
|
109
|
+
const eventHandler = (data) => {
|
|
110
|
+
if (blackListedEventIds.some((item) => item.eventId === data.eventId && item.sender === data.sender)) {
|
|
111
|
+
console.log("BLACKLISTED EVENT ID", data.eventId, data);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
blackListedEventIds.push({
|
|
115
|
+
eventId: data.eventId,
|
|
116
|
+
sender: data.sender,
|
|
117
|
+
});
|
|
118
|
+
if (blackListedEventIds.length > 100) {
|
|
119
|
+
blackListedEventIds.shift();
|
|
120
|
+
}
|
|
121
|
+
return handler(data);
|
|
122
|
+
};
|
|
123
|
+
this.listeners
|
|
124
|
+
.get(topic)
|
|
125
|
+
.add({ id, handler: eventHandler, ignoreSender });
|
|
126
|
+
this.logIfDebug(`Subscribed to ` + topic, {
|
|
127
|
+
listenerId: id,
|
|
128
|
+
ignoreSender,
|
|
129
|
+
});
|
|
109
130
|
return btoa(JSON.stringify({ topic, id }));
|
|
110
131
|
});
|
|
111
132
|
return {
|
|
112
|
-
off: () => this.off(ids)
|
|
133
|
+
off: () => this.off(ids),
|
|
113
134
|
};
|
|
114
135
|
}
|
|
115
136
|
/**
|
|
@@ -121,7 +142,7 @@ export class EventBusHandler {
|
|
|
121
142
|
*/
|
|
122
143
|
respond(sender, topic, handler) {
|
|
123
144
|
const topics = Array.isArray(topic) ? topic : [topic];
|
|
124
|
-
const listeners = topics.map(topic => {
|
|
145
|
+
const listeners = topics.map((topic) => {
|
|
125
146
|
const blackListedEventIds = [];
|
|
126
147
|
//To allow event communication inside the same plugin the sender needs to be ignored but the events still need to be checked for the same event just reaching the subscriber to prevent infinite loops
|
|
127
148
|
const finalIgnoreSender = !topic.startsWith("self.") ? [sender] : [];
|
|
@@ -131,7 +152,7 @@ export class EventBusHandler {
|
|
|
131
152
|
return;
|
|
132
153
|
}
|
|
133
154
|
blackListedEventIds.push(data.eventId);
|
|
134
|
-
if (blackListedEventIds.length >
|
|
155
|
+
if (blackListedEventIds.length > 100) {
|
|
135
156
|
blackListedEventIds.shift();
|
|
136
157
|
}
|
|
137
158
|
const response = typeof handler === "function" ? yield handler(data) : handler;
|
|
@@ -139,11 +160,11 @@ export class EventBusHandler {
|
|
|
139
160
|
}), finalIgnoreSender);
|
|
140
161
|
this.logIfDebug(`Added respond listener ` + sender + " to topic " + topic, { listener, sender });
|
|
141
162
|
return {
|
|
142
|
-
off: () => listener.off()
|
|
163
|
+
off: () => listener.off(),
|
|
143
164
|
};
|
|
144
165
|
});
|
|
145
166
|
return {
|
|
146
|
-
off: () => listeners.forEach(listener => listener.off())
|
|
167
|
+
off: () => listeners.forEach((listener) => listener.off()),
|
|
147
168
|
};
|
|
148
169
|
}
|
|
149
170
|
/**
|
|
@@ -169,13 +190,16 @@ export class EventBusHandler {
|
|
|
169
190
|
* @param listenerIds - The ids of the listeners to unsubscribe from.
|
|
170
191
|
*/
|
|
171
192
|
off(listenerIds) {
|
|
172
|
-
this.toArray(listenerIds).forEach(fullId => {
|
|
193
|
+
this.toArray(listenerIds).forEach((fullId) => {
|
|
173
194
|
const { topic, id } = JSON.parse(atob(fullId));
|
|
174
195
|
const listeners = this.listeners.get(topic) || new Set();
|
|
175
|
-
listeners.forEach(listener => {
|
|
196
|
+
listeners.forEach((listener) => {
|
|
176
197
|
if (listener.id === Number(id)) {
|
|
177
198
|
listeners.delete(listener);
|
|
178
|
-
this.logIfDebug(`Removed listener ` + fullId, {
|
|
199
|
+
this.logIfDebug(`Removed listener ` + fullId, {
|
|
200
|
+
topic,
|
|
201
|
+
listenerId: id,
|
|
202
|
+
});
|
|
179
203
|
}
|
|
180
204
|
});
|
|
181
205
|
});
|
|
@@ -197,7 +221,7 @@ export class EventBusHandler {
|
|
|
197
221
|
}
|
|
198
222
|
const event = this.createEvent(sender, topic, data || {});
|
|
199
223
|
this.logIfDebug(`Requesting data from ` + topic, { event });
|
|
200
|
-
return new Promise(resolve => {
|
|
224
|
+
return new Promise((resolve) => {
|
|
201
225
|
this.responseResolvers.set(event.eventId, (value) => resolve(value));
|
|
202
226
|
this.emitInternal(sender, topic, data || {}, event.eventId, true);
|
|
203
227
|
});
|
|
@@ -240,10 +264,13 @@ export class EventBusHandler {
|
|
|
240
264
|
}
|
|
241
265
|
// Validate action part
|
|
242
266
|
const validActions = ["request", "create", "update", "delete", "trigger"];
|
|
243
|
-
if (validActions.some(a => action.startsWith(a))) {
|
|
267
|
+
if (validActions.some((a) => action.startsWith(a))) {
|
|
244
268
|
return true;
|
|
245
269
|
}
|
|
246
|
-
this.logAndThrowError(false, `Invalid event topic name. The action: ` +
|
|
270
|
+
this.logAndThrowError(false, `Invalid event topic name. The action: ` +
|
|
271
|
+
action +
|
|
272
|
+
". Must be or start with one of: " +
|
|
273
|
+
validActions.join(", "));
|
|
247
274
|
return false;
|
|
248
275
|
}
|
|
249
276
|
logIfDebug(...args) {
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,8 @@ export { Translator } from './controller/TranslationController';
|
|
|
11
11
|
export type { TOptions } from 'i18next';
|
|
12
12
|
export type { SharedContent, SharedContentObjectRequest } from './controller/SharedContentController';
|
|
13
13
|
export type { Exercise } from './controller/ExerciseController';
|
|
14
|
-
export type { UserInfo, Language } from './controller/SettingsController';
|
|
14
|
+
export type { UserInfo, Language, UserRole } from './controller/SettingsController';
|
|
15
15
|
export type { Message, ToolInvocation } from './controller/AIController';
|
|
16
16
|
export type { TriggerAction } from './controller/ExerciseController';
|
|
17
17
|
export type { MacroAccomplishmentPayload, MicroAccomplishmentPayload } from './controller/AccomplishmentController';
|
|
18
|
+
export type { EventBusMessage } from './fromRimori/EventBus';
|
|
@@ -26,15 +26,17 @@ export class RimoriCommunicationHandler {
|
|
|
26
26
|
}
|
|
27
27
|
initMessageChannel(worker = false) {
|
|
28
28
|
const listener = (event) => {
|
|
29
|
-
console.log('[PluginController] window message', { origin: event.origin, data: event.data });
|
|
29
|
+
// console.log('[PluginController] window message', { origin: event.origin, data: event.data });
|
|
30
30
|
const { type, pluginId, queryParams, rimoriInfo } = event.data || {};
|
|
31
31
|
const [transferredPort] = event.ports || [];
|
|
32
32
|
if (type !== 'rimori:init' || !transferredPort || pluginId !== this.pluginId) {
|
|
33
|
-
console.log('[PluginController] message ignored (not init or wrong plugin)', {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
// console.log('[PluginController] message ignored (not init or wrong plugin)', {
|
|
34
|
+
// type,
|
|
35
|
+
// pluginId,
|
|
36
|
+
// currentPluginId: this.pluginId,
|
|
37
|
+
// hasPortProperty: !!transferredPort,
|
|
38
|
+
// event
|
|
39
|
+
// });
|
|
38
40
|
return;
|
|
39
41
|
}
|
|
40
42
|
this.queryParams = queryParams || {};
|
|
@@ -182,7 +184,7 @@ export class RimoriCommunicationHandler {
|
|
|
182
184
|
else {
|
|
183
185
|
// In main thread context, use EventBus
|
|
184
186
|
const { data } = yield EventBus.request(this.pluginId, 'global.supabase.requestAccess');
|
|
185
|
-
console.log({ data });
|
|
187
|
+
// console.log({ data });
|
|
186
188
|
this.rimoriInfo = data;
|
|
187
189
|
this.supabase = createClient(this.rimoriInfo.url, this.rimoriInfo.key, {
|
|
188
190
|
accessToken: () => Promise.resolve(this.getToken()),
|
package/dist/plugin/Logger.d.ts
CHANGED
|
@@ -54,6 +54,7 @@ export declare class Logger {
|
|
|
54
54
|
private getBrowserInfo;
|
|
55
55
|
/**
|
|
56
56
|
* Capture a screenshot of the current page.
|
|
57
|
+
* Dynamically imports html2canvas only in browser environments.
|
|
57
58
|
* @returns Promise resolving to base64 screenshot or null if failed
|
|
58
59
|
*/
|
|
59
60
|
private captureScreenshot;
|
package/dist/plugin/Logger.js
CHANGED
|
@@ -7,7 +7,6 @@ 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 html2canvas from 'html2canvas';
|
|
11
10
|
/**
|
|
12
11
|
* Singleton Logger class for Rimori client plugins.
|
|
13
12
|
* Handles all logging levels, production filtering, and log transmission to Rimori.
|
|
@@ -242,17 +241,30 @@ export class Logger {
|
|
|
242
241
|
}
|
|
243
242
|
/**
|
|
244
243
|
* Capture a screenshot of the current page.
|
|
244
|
+
* Dynamically imports html2canvas only in browser environments.
|
|
245
245
|
* @returns Promise resolving to base64 screenshot or null if failed
|
|
246
246
|
*/
|
|
247
247
|
captureScreenshot() {
|
|
248
248
|
return __awaiter(this, void 0, void 0, function* () {
|
|
249
|
-
|
|
249
|
+
// Only attempt to capture screenshot in browser environments
|
|
250
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
// Dynamically import html2canvas only when window is available
|
|
255
|
+
// This allows tree-shaking for environments without window (e.g., Node.js)
|
|
256
|
+
const html2canvas = (yield import('html2canvas')).default;
|
|
250
257
|
const canvas = yield html2canvas(document.body);
|
|
251
258
|
const screenshot = canvas.toDataURL('image/png');
|
|
252
259
|
// this.originalConsole.log("screenshot captured", screenshot)
|
|
253
260
|
return screenshot;
|
|
254
261
|
}
|
|
255
|
-
|
|
262
|
+
catch (error) {
|
|
263
|
+
// html2canvas may not be available or may fail to load
|
|
264
|
+
// Silently fail to avoid breaking logging functionality
|
|
265
|
+
this.originalConsole.warn('[Rimori Logger] Failed to capture screenshot:', error);
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
256
268
|
});
|
|
257
269
|
}
|
|
258
270
|
/**
|