@rimori/client 2.5.17 → 2.5.18-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/dist/cli/types/DatabaseTypes.d.ts +8 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/plugin/RimoriClient.d.ts +3 -0
- package/dist/plugin/RimoriClient.js +2 -0
- package/dist/plugin/module/AIModule.d.ts +7 -2
- package/dist/plugin/module/AIModule.js +30 -1
- package/dist/plugin/module/ExerciseModule.d.ts +3 -2
- package/dist/plugin/module/ExerciseModule.js +17 -18
- package/dist/plugin/module/StorageModule.d.ts +34 -0
- package/dist/plugin/module/StorageModule.js +57 -0
- package/package.json +1 -1
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Supported database column data types for table schema definitions.
|
|
3
3
|
*/
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* 'markdown' is stored as `text` in the database.
|
|
6
|
+
* Marking a column as 'markdown' causes the migration system to:
|
|
7
|
+
* 1. Add an `updated_at` timestamp + trigger to the table.
|
|
8
|
+
* 2. Add an `updated_at` trigger so the image-sync cron can detect recently
|
|
9
|
+
* modified entries. The cron derives which columns to scan from release.db_schema.
|
|
10
|
+
*/
|
|
11
|
+
type DbColumnType = 'decimal' | 'integer' | 'text' | 'boolean' | 'json' | 'timestamp' | 'uuid' | 'markdown';
|
|
5
12
|
/**
|
|
6
13
|
* Foreign key relationship configuration with cascade delete support.
|
|
7
14
|
* Defines a relationship where the source record is deleted when the destination record is deleted.
|
package/dist/index.d.ts
CHANGED
|
@@ -18,3 +18,4 @@ export type { Theme, ApplicationMode } from './plugin/module/PluginModule';
|
|
|
18
18
|
export type { UserInfo, Language, UserRole, ExplicitUndefined } from './plugin/module/PluginModule';
|
|
19
19
|
export type { SharedContent, BasicSharedContent, ContentStatus } from './plugin/module/SharedContentController';
|
|
20
20
|
export type { MacroAccomplishmentPayload, MicroAccomplishmentPayload } from './controller/AccomplishmentController';
|
|
21
|
+
export { StorageModule } from './plugin/module/StorageModule';
|
package/dist/index.js
CHANGED
|
@@ -10,3 +10,4 @@ export * from './plugin/CommunicationHandler';
|
|
|
10
10
|
export { setupWorker } from './worker/WorkerSetup';
|
|
11
11
|
export { AudioController } from './controller/AudioController';
|
|
12
12
|
export { Translator } from './controller/TranslationController';
|
|
13
|
+
export { StorageModule } from './plugin/module/StorageModule';
|
|
@@ -4,6 +4,7 @@ import { DbModule } from './module/DbModule';
|
|
|
4
4
|
import { EventModule } from './module/EventModule';
|
|
5
5
|
import { AIModule } from './module/AIModule';
|
|
6
6
|
import { ExerciseModule } from './module/ExerciseModule';
|
|
7
|
+
import { StorageModule } from './module/StorageModule';
|
|
7
8
|
export declare class RimoriClient {
|
|
8
9
|
private static instance;
|
|
9
10
|
sharedContent: SharedContentController;
|
|
@@ -12,6 +13,8 @@ export declare class RimoriClient {
|
|
|
12
13
|
plugin: PluginModule;
|
|
13
14
|
ai: AIModule;
|
|
14
15
|
exercise: ExerciseModule;
|
|
16
|
+
/** Upload and manage images stored in Supabase via the backend. */
|
|
17
|
+
storage: StorageModule;
|
|
15
18
|
private rimoriInfo;
|
|
16
19
|
private constructor();
|
|
17
20
|
static getInstance(pluginId?: string): Promise<RimoriClient>;
|
|
@@ -15,6 +15,7 @@ import { DbModule } from './module/DbModule';
|
|
|
15
15
|
import { EventModule } from './module/EventModule';
|
|
16
16
|
import { AIModule } from './module/AIModule';
|
|
17
17
|
import { ExerciseModule } from './module/ExerciseModule';
|
|
18
|
+
import { StorageModule } from './module/StorageModule';
|
|
18
19
|
import { EventBus } from '../fromRimori/EventBus';
|
|
19
20
|
export class RimoriClient {
|
|
20
21
|
constructor(controller, supabase, info) {
|
|
@@ -38,6 +39,7 @@ export class RimoriClient {
|
|
|
38
39
|
this.db = new DbModule(supabase, controller, info);
|
|
39
40
|
this.plugin = new PluginModule(supabase, controller, info, this.ai);
|
|
40
41
|
this.exercise = new ExerciseModule(supabase, controller, info, this.event);
|
|
42
|
+
this.storage = new StorageModule(info.backendUrl, () => this.rimoriInfo.token);
|
|
41
43
|
controller.onUpdate((updatedInfo) => {
|
|
42
44
|
this.rimoriInfo = updatedInfo;
|
|
43
45
|
});
|
|
@@ -67,6 +67,11 @@ export declare class AIModule {
|
|
|
67
67
|
setSessionToken(id: string): void;
|
|
68
68
|
/** Clears the stored session token (called after macro accomplishment). */
|
|
69
69
|
clearSessionToken(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Ensures a session token exists, requesting one from the backend if needed.
|
|
72
|
+
* Mirrors the lazy-issuance pattern used by the AI/LLM endpoint.
|
|
73
|
+
*/
|
|
74
|
+
private ensureSessionToken;
|
|
70
75
|
/** Registers a callback invoked whenever a 429 rate-limit response is received. */
|
|
71
76
|
setOnRateLimited(cb: (exercisesRemaining: number) => void): void;
|
|
72
77
|
/**
|
|
@@ -86,7 +91,7 @@ export declare class AIModule {
|
|
|
86
91
|
* @param cache Whether to cache the result (default: false).
|
|
87
92
|
* @param model The model to use for generation.
|
|
88
93
|
*/
|
|
89
|
-
getSteamedText(messages: Message[], onMessage: OnLLMResponse, tools?: Tool[], cache?: boolean, model?: string, knowledgeId?: string): Promise<
|
|
94
|
+
getSteamedText(messages: Message[], onMessage: OnLLMResponse, tools?: Tool[], cache?: boolean, model?: string, knowledgeId?: string): Promise<string>;
|
|
90
95
|
/**
|
|
91
96
|
* Generate voice audio from text using AI.
|
|
92
97
|
* @param text The text to convert to voice.
|
|
@@ -146,7 +151,7 @@ export declare class AIModule {
|
|
|
146
151
|
tools?: Tool[];
|
|
147
152
|
model?: string;
|
|
148
153
|
knowledgeId?: string;
|
|
149
|
-
}): Promise<
|
|
154
|
+
}): Promise<T>;
|
|
150
155
|
private streamObject;
|
|
151
156
|
private sendToolResult;
|
|
152
157
|
}
|
|
@@ -29,6 +29,32 @@ export class AIModule {
|
|
|
29
29
|
clearSessionToken() {
|
|
30
30
|
this.sessionTokenId = null;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Ensures a session token exists, requesting one from the backend if needed.
|
|
34
|
+
* Mirrors the lazy-issuance pattern used by the AI/LLM endpoint.
|
|
35
|
+
*/
|
|
36
|
+
ensureSessionToken() {
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
var _a, _b, _c;
|
|
39
|
+
if (this.sessionTokenId)
|
|
40
|
+
return;
|
|
41
|
+
const response = yield fetch(`${this.backendUrl}/ai/session`, {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: { Authorization: `Bearer ${this.getToken()}` },
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
if (response.status === 429) {
|
|
47
|
+
const body = yield response.json().catch(() => ({}));
|
|
48
|
+
const remaining = (_a = body.exercises_remaining) !== null && _a !== void 0 ? _a : 0;
|
|
49
|
+
(_b = this.onRateLimitedCb) === null || _b === void 0 ? void 0 : _b.call(this, remaining);
|
|
50
|
+
throw new Error(`Rate limit exceeded: ${(_c = body.error) !== null && _c !== void 0 ? _c : 'Daily exercise limit reached'}. exercises_remaining: ${remaining}`);
|
|
51
|
+
}
|
|
52
|
+
throw new Error(`Failed to create session: ${response.status} ${response.statusText}`);
|
|
53
|
+
}
|
|
54
|
+
const { session_token_id } = yield response.json();
|
|
55
|
+
this.sessionTokenId = session_token_id;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
32
58
|
/** Registers a callback invoked whenever a 429 rate-limit response is received. */
|
|
33
59
|
setOnRateLimited(cb) {
|
|
34
60
|
this.onRateLimitedCb = cb;
|
|
@@ -82,6 +108,7 @@ export class AIModule {
|
|
|
82
108
|
onResult: ({ result }) => onMessage(messageId, result, false),
|
|
83
109
|
});
|
|
84
110
|
onMessage(messageId, result, true);
|
|
111
|
+
return result;
|
|
85
112
|
});
|
|
86
113
|
}
|
|
87
114
|
/**
|
|
@@ -96,6 +123,7 @@ export class AIModule {
|
|
|
96
123
|
getVoice(text_1) {
|
|
97
124
|
return __awaiter(this, arguments, void 0, function* (text, voice = 'alloy', speed = 1, language, cache = false) {
|
|
98
125
|
var _a;
|
|
126
|
+
yield this.ensureSessionToken();
|
|
99
127
|
return yield fetch(`${this.backendUrl}/voice/tts`, {
|
|
100
128
|
method: 'POST',
|
|
101
129
|
headers: {
|
|
@@ -114,6 +142,7 @@ export class AIModule {
|
|
|
114
142
|
*/
|
|
115
143
|
getTextFromVoice(file, language) {
|
|
116
144
|
return __awaiter(this, void 0, void 0, function* () {
|
|
145
|
+
yield this.ensureSessionToken();
|
|
117
146
|
const formData = new FormData();
|
|
118
147
|
formData.append('file', file);
|
|
119
148
|
if (language) {
|
|
@@ -180,7 +209,7 @@ export class AIModule {
|
|
|
180
209
|
getStreamedObject(params) {
|
|
181
210
|
return __awaiter(this, void 0, void 0, function* () {
|
|
182
211
|
const { systemPrompt, responseSchema, userPrompt, onResult, cache = false, tools = [], model = undefined, knowledgeId, } = params;
|
|
183
|
-
yield this.streamObject({
|
|
212
|
+
return yield this.streamObject({
|
|
184
213
|
responseSchema,
|
|
185
214
|
messages: this.getChatMessage(systemPrompt, userPrompt),
|
|
186
215
|
onResult,
|
|
@@ -45,8 +45,9 @@ export declare class ExerciseModule {
|
|
|
45
45
|
*/
|
|
46
46
|
view(): Promise<Exercise[]>;
|
|
47
47
|
/**
|
|
48
|
-
* Creates
|
|
49
|
-
*
|
|
48
|
+
* Creates one or more exercises via the backend API.
|
|
49
|
+
* Multiple exercises are sent in a single bulk request to ensure atomicity —
|
|
50
|
+
* either all succeed or none are inserted.
|
|
50
51
|
* @param params Exercise creation parameters (single or array).
|
|
51
52
|
* @returns Created exercise objects.
|
|
52
53
|
*/
|
|
@@ -37,31 +37,30 @@ export class ExerciseModule {
|
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
|
-
* Creates
|
|
41
|
-
*
|
|
40
|
+
* Creates one or more exercises via the backend API.
|
|
41
|
+
* Multiple exercises are sent in a single bulk request to ensure atomicity —
|
|
42
|
+
* either all succeed or none are inserted.
|
|
42
43
|
* @param params Exercise creation parameters (single or array).
|
|
43
44
|
* @returns Created exercise objects.
|
|
44
45
|
*/
|
|
45
46
|
add(params) {
|
|
46
47
|
return __awaiter(this, void 0, void 0, function* () {
|
|
47
48
|
const exercises = Array.isArray(params) ? params : [params];
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return yield response.json();
|
|
62
|
-
})));
|
|
49
|
+
const response = yield fetch(`${this.backendUrl}/exercises`, {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: {
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
Authorization: `Bearer ${this.token}`,
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({ exercises }),
|
|
56
|
+
});
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
const errorText = yield response.text();
|
|
59
|
+
throw new Error(`Failed to create exercises: ${errorText}`);
|
|
60
|
+
}
|
|
61
|
+
const data = yield response.json();
|
|
63
62
|
this.eventModule.emit('global.exercises.triggerChange');
|
|
64
|
-
return
|
|
63
|
+
return data;
|
|
65
64
|
});
|
|
66
65
|
}
|
|
67
66
|
/**
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage module for plugin image operations.
|
|
3
|
+
*
|
|
4
|
+
* Handles uploading images to Supabase storage via the backend.
|
|
5
|
+
*
|
|
6
|
+
* Images are tracked automatically: the backend cron scans markdown columns
|
|
7
|
+
* (declared via `type: 'markdown'` in db.config.ts) every 30 minutes,
|
|
8
|
+
* confirms images found in content, and deletes orphaned ones. No plugin-side
|
|
9
|
+
* confirm or delete calls are needed.
|
|
10
|
+
*/
|
|
11
|
+
export declare class StorageModule {
|
|
12
|
+
private readonly backendUrl;
|
|
13
|
+
private readonly getToken;
|
|
14
|
+
constructor(backendUrl: string, getToken: () => string);
|
|
15
|
+
/**
|
|
16
|
+
* Upload a PNG image blob to Supabase storage via the backend.
|
|
17
|
+
*
|
|
18
|
+
* The image is initially "unconfirmed". The background cron will link it to
|
|
19
|
+
* the entry automatically when it scans the markdown column after the entry
|
|
20
|
+
* is saved (within ~30 minutes).
|
|
21
|
+
*
|
|
22
|
+
* @returns `{ data: { url, path } }` on success, `{ error }` on failure.
|
|
23
|
+
*/
|
|
24
|
+
uploadImage(pngBlob: Blob): Promise<{
|
|
25
|
+
data: {
|
|
26
|
+
url: string;
|
|
27
|
+
path: string;
|
|
28
|
+
};
|
|
29
|
+
error?: undefined;
|
|
30
|
+
} | {
|
|
31
|
+
data?: undefined;
|
|
32
|
+
error: Error;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
/**
|
|
11
|
+
* Storage module for plugin image operations.
|
|
12
|
+
*
|
|
13
|
+
* Handles uploading images to Supabase storage via the backend.
|
|
14
|
+
*
|
|
15
|
+
* Images are tracked automatically: the backend cron scans markdown columns
|
|
16
|
+
* (declared via `type: 'markdown'` in db.config.ts) every 30 minutes,
|
|
17
|
+
* confirms images found in content, and deletes orphaned ones. No plugin-side
|
|
18
|
+
* confirm or delete calls are needed.
|
|
19
|
+
*/
|
|
20
|
+
export class StorageModule {
|
|
21
|
+
constructor(backendUrl, getToken) {
|
|
22
|
+
this.backendUrl = backendUrl;
|
|
23
|
+
this.getToken = getToken;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Upload a PNG image blob to Supabase storage via the backend.
|
|
27
|
+
*
|
|
28
|
+
* The image is initially "unconfirmed". The background cron will link it to
|
|
29
|
+
* the entry automatically when it scans the markdown column after the entry
|
|
30
|
+
* is saved (within ~30 minutes).
|
|
31
|
+
*
|
|
32
|
+
* @returns `{ data: { url, path } }` on success, `{ error }` on failure.
|
|
33
|
+
*/
|
|
34
|
+
uploadImage(pngBlob) {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
var _a;
|
|
37
|
+
const formData = new FormData();
|
|
38
|
+
formData.append('file', pngBlob, 'image.png');
|
|
39
|
+
try {
|
|
40
|
+
const response = yield fetch(`${this.backendUrl}/plugin-images/upload`, {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
headers: { Authorization: `Bearer ${this.getToken()}` },
|
|
43
|
+
body: formData,
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
const body = (yield response.json().catch(() => ({})));
|
|
47
|
+
return { error: new Error((_a = body.message) !== null && _a !== void 0 ? _a : `Upload failed (${response.status})`) };
|
|
48
|
+
}
|
|
49
|
+
const result = (yield response.json());
|
|
50
|
+
return { data: result };
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return { error: err instanceof Error ? err : new Error(String(err)) };
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|