@rimori/client 2.5.5-next.4 → 2.5.5-next.5

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.
@@ -61,10 +61,12 @@ interface BaseTableStructure {
61
61
  created_by: DbColumnDefinition;
62
62
  }
63
63
  /**
64
- * Complete database table schema definition.
65
- * Defines the structure, constraints, and relationships for a database table.
64
+ * Normal database table schema definition.
65
+ * Defines the structure, constraints, and relationships for a standard database table.
66
66
  */
67
- export interface DbTableDefinition {
67
+ export interface DbNormalTableDefinition {
68
+ /** Type discriminator for normal tables */
69
+ type: 'table';
68
70
  /** Name of the database table */
69
71
  table_name: string;
70
72
  /** Description of the table's purpose and usage */
@@ -83,6 +85,37 @@ export interface DbTableDefinition {
83
85
  [column_name: string]: DbColumnDefinition;
84
86
  };
85
87
  }
88
+ /**
89
+ * Shared content table schema definition.
90
+ * Defines the structure for community-shared content tables with automatic columns and verification.
91
+ * Table naming: {pluginId}_sc_{table_name}
92
+ * Automatic columns: title (text), keywords (text[]), verified (boolean), embedding (vector)
93
+ * Hardcoded permissions: read ALL public+own, insert/update/delete OWN
94
+ */
95
+ export interface DbSharedContentTableDefinition {
96
+ /** Type discriminator for shared content tables */
97
+ type: 'shared_content';
98
+ /** Name of the database table (will become {pluginId}_sc_{table_name}) */
99
+ table_name: string;
100
+ /** Description of the table's purpose and usage */
101
+ description: string;
102
+ /** AI prompt for generating content. Supports placeholders like {{topic}}, {{level}}, etc. */
103
+ instructions: string;
104
+ /** Optional AI prompt to verify content quality before marking as verified */
105
+ verification_prompt: string;
106
+ /** Column definitions for the table (excluding auto-generated columns) */
107
+ columns: {
108
+ [column_name: string]: DbColumnDefinition & {
109
+ /** Whether the column is used for LLM generation. If not set, the column is not used for LLM generation. */
110
+ expose_to_llm?: boolean;
111
+ };
112
+ };
113
+ }
114
+ /**
115
+ * Complete database table schema definition.
116
+ * Can be either a normal table or a shared content table.
117
+ */
118
+ export type DbTableDefinition = DbNormalTableDefinition | DbSharedContentTableDefinition;
86
119
  /**
87
120
  * Permission definition for a database table.
88
121
  * NONE means the action is not allowed.
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export { setupWorker } from './worker/WorkerSetup';
9
9
  export { AudioController } from './controller/AudioController';
10
10
  export { Translator } from './controller/TranslationController';
11
11
  export type { TOptions } from 'i18next';
12
- export type { SharedContent, SharedContentObjectRequest } from './controller/SharedContentController';
12
+ export type { SharedContent, BasicSharedContent } from './plugin/module/SharedContentController';
13
13
  export type { Exercise } from './plugin/module/ExerciseModule';
14
14
  export type { UserInfo, Language, UserRole } from './controller/SettingsController';
15
15
  export type { Message, ToolInvocation } from './controller/AIController';
@@ -1,4 +1,4 @@
1
- import { SharedContent, SharedContentFilter, SharedContentObjectRequest } from '../controller/SharedContentController';
1
+ import { SharedContentController } from './module/SharedContentController';
2
2
  import { PluginModule } from './module/PluginModule';
3
3
  import { DbModule } from './module/DbModule';
4
4
  import { EventModule } from './module/EventModule';
@@ -6,8 +6,7 @@ import { AIModule } from './module/AIModule';
6
6
  import { ExerciseModule } from './module/ExerciseModule';
7
7
  export declare class RimoriClient {
8
8
  private static instance;
9
- private pluginController;
10
- private sharedContentController;
9
+ sharedContent: SharedContentController;
11
10
  db: DbModule;
12
11
  event: EventModule;
13
12
  plugin: PluginModule;
@@ -15,97 +14,11 @@ export declare class RimoriClient {
15
14
  exercise: ExerciseModule;
16
15
  private rimoriInfo;
17
16
  private constructor();
17
+ static getInstance(pluginId?: string): Promise<RimoriClient>;
18
18
  navigation: {
19
19
  toDashboard: () => void;
20
20
  };
21
- /**
22
- * Get a query parameter value that was passed via MessageChannel
23
- * @param key The query parameter key
24
- * @deprecated Use the plugin.applicationMode and plugin.theme properties instead
25
- * @returns The query parameter value or null if not found
26
- */
27
- getQueryParam(key: string): string | null;
28
- static getInstance(pluginId?: string): Promise<RimoriClient>;
29
21
  runtime: {
30
22
  fetchBackend: (url: string, options: RequestInit) => Promise<Response>;
31
23
  };
32
- community: {
33
- /**
34
- * Shared content is a way to share completable content with other users using this plugin.
35
- * Typical examples are assignments, exercises, stories, etc.
36
- * Users generate new shared content items and others can complete the content too.
37
- */
38
- sharedContent: {
39
- /**
40
- * Get one dedicated shared content item by id. It does not matter if it is completed or not.
41
- * @param contentType The type of shared content to get. E.g. assignments, exercises, etc.
42
- * @param id The id of the shared content item.
43
- * @returns The shared content item.
44
- */
45
- get: <T = any>(contentType: string, id: string) => Promise<SharedContent<T>>;
46
- /**
47
- * Get a list of shared content items.
48
- * @param contentType The type of shared content to get. E.g. assignments, exercises, etc.
49
- * @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.
50
- * @param limit The optional limit for the number of results.
51
- * @returns The list of shared content items.
52
- */
53
- getList: <T = any>(contentType: string, filter?: SharedContentFilter, limit?: number) => Promise<SharedContent<T>[]>;
54
- /**
55
- * Get new shared content.
56
- * @param contentType The type of shared content to fetch. E.g. assignments, exercises, etc.
57
- * @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.
58
- * @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.
59
- * @param options An optional object with options for the new shared content.
60
- * @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.
61
- * @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.
62
- * @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.
63
- * @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.
64
- * @returns The new shared content.
65
- */
66
- getNew: <T = any>(contentType: string, generatorInstructions: SharedContentObjectRequest, filter?: SharedContentFilter, options?: {
67
- privateTopic?: boolean;
68
- skipDbSave?: boolean;
69
- alwaysGenerateNew?: boolean;
70
- excludeIds?: string[];
71
- }) => Promise<SharedContent<T>>;
72
- /**
73
- * Create a new shared content item.
74
- * @param content The content to create.
75
- * @returns The new shared content item.
76
- */
77
- create: <T = any>(content: Omit<SharedContent<T>, "id">) => Promise<SharedContent<T>>;
78
- /**
79
- * Update a shared content item.
80
- * @param id The id of the shared content item to update.
81
- * @param content The content to update.
82
- * @returns The updated shared content item.
83
- */
84
- update: <T = any>(id: string, content: Partial<SharedContent<T>>) => Promise<SharedContent<T>>;
85
- /**
86
- * Complete a shared content item.
87
- * @param contentType The type of shared content to complete. E.g. assignments, exercises, etc.
88
- * @param assignmentId The id of the shared content item to complete.
89
- */
90
- complete: (contentType: string, assignmentId: string) => Promise<void>;
91
- /**
92
- /**
93
- * Update the state of a shared content item for a specific user.
94
- * Useful for marking content as completed, ongoing, hidden, liked, disliked, or bookmarked.
95
- */
96
- updateState: (params: {
97
- contentType: string;
98
- id: string;
99
- state?: "completed" | "ongoing" | "hidden";
100
- reaction?: "liked" | "disliked" | null;
101
- bookmarked?: boolean;
102
- }) => Promise<void>;
103
- /**
104
- * Remove a shared content item.
105
- * @param id The id of the shared content item to remove.
106
- * @returns The removed shared content item.
107
- */
108
- remove: (id: string) => Promise<SharedContent<any>>;
109
- };
110
- };
111
24
  }
@@ -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 { SharedContentController, } from '../controller/SharedContentController';
10
+ import { SharedContentController } from './module/SharedContentController';
11
11
  import { RimoriCommunicationHandler } from './CommunicationHandler';
12
12
  import { Logger } from './Logger';
13
13
  import { PluginModule } from './module/PluginModule';
@@ -27,93 +27,8 @@ export class RimoriClient {
27
27
  return fetch(this.rimoriInfo.backendUrl + url, Object.assign(Object.assign({}, options), { headers: Object.assign(Object.assign({}, options.headers), { Authorization: `Bearer ${this.rimoriInfo.token}` }) }));
28
28
  }),
29
29
  };
30
- this.community = {
31
- /**
32
- * Shared content is a way to share completable content with other users using this plugin.
33
- * Typical examples are assignments, exercises, stories, etc.
34
- * Users generate new shared content items and others can complete the content too.
35
- */
36
- sharedContent: {
37
- /**
38
- * Get one dedicated shared content item by id. It does not matter if it is completed or not.
39
- * @param contentType The type of shared content to get. E.g. assignments, exercises, etc.
40
- * @param id The id of the shared content item.
41
- * @returns The shared content item.
42
- */
43
- get: (contentType, id) => __awaiter(this, void 0, void 0, function* () {
44
- return yield this.sharedContentController.getSharedContent(contentType, id);
45
- }),
46
- /**
47
- * Get a list of shared content items.
48
- * @param contentType The type of shared content to get. E.g. assignments, exercises, etc.
49
- * @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.
50
- * @param limit The optional limit for the number of results.
51
- * @returns The list of shared content items.
52
- */
53
- getList: (contentType, filter, limit) => __awaiter(this, void 0, void 0, function* () {
54
- return yield this.sharedContentController.getSharedContentList(contentType, filter, limit);
55
- }),
56
- /**
57
- * Get new shared content.
58
- * @param contentType The type of shared content to fetch. E.g. assignments, exercises, etc.
59
- * @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.
60
- * @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.
61
- * @param options An optional object with options for the new shared content.
62
- * @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.
63
- * @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.
64
- * @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.
65
- * @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.
66
- * @returns The new shared content.
67
- */
68
- getNew: (contentType, generatorInstructions, filter, options) => __awaiter(this, void 0, void 0, function* () {
69
- return yield this.sharedContentController.getNewSharedContent(contentType, generatorInstructions, filter, options);
70
- }),
71
- /**
72
- * Create a new shared content item.
73
- * @param content The content to create.
74
- * @returns The new shared content item.
75
- */
76
- create: (content) => __awaiter(this, void 0, void 0, function* () {
77
- return yield this.sharedContentController.createSharedContent(content);
78
- }),
79
- /**
80
- * Update a shared content item.
81
- * @param id The id of the shared content item to update.
82
- * @param content The content to update.
83
- * @returns The updated shared content item.
84
- */
85
- update: (id, content) => __awaiter(this, void 0, void 0, function* () {
86
- return yield this.sharedContentController.updateSharedContent(id, content);
87
- }),
88
- /**
89
- * Complete a shared content item.
90
- * @param contentType The type of shared content to complete. E.g. assignments, exercises, etc.
91
- * @param assignmentId The id of the shared content item to complete.
92
- */
93
- complete: (contentType, assignmentId) => __awaiter(this, void 0, void 0, function* () {
94
- return yield this.sharedContentController.completeSharedContent(contentType, assignmentId);
95
- }),
96
- /**
97
- /**
98
- * Update the state of a shared content item for a specific user.
99
- * Useful for marking content as completed, ongoing, hidden, liked, disliked, or bookmarked.
100
- */
101
- updateState: (params) => __awaiter(this, void 0, void 0, function* () {
102
- return yield this.sharedContentController.updateSharedContentState(params);
103
- }),
104
- /**
105
- * Remove a shared content item.
106
- * @param id The id of the shared content item to remove.
107
- * @returns The removed shared content item.
108
- */
109
- remove: (id) => __awaiter(this, void 0, void 0, function* () {
110
- return yield this.sharedContentController.removeSharedContent(id);
111
- }),
112
- },
113
- };
114
30
  this.rimoriInfo = info;
115
- this.pluginController = controller;
116
- this.sharedContentController = new SharedContentController(supabase, this);
31
+ this.sharedContent = new SharedContentController(supabase, this);
117
32
  this.ai = new AIModule(controller, info);
118
33
  this.event = new EventModule(info.pluginId);
119
34
  this.db = new DbModule(supabase, controller, info);
@@ -127,26 +42,12 @@ export class RimoriClient {
127
42
  Logger.getInstance(this);
128
43
  }
129
44
  }
130
- /**
131
- * Get a query parameter value that was passed via MessageChannel
132
- * @param key The query parameter key
133
- * @deprecated Use the plugin.applicationMode and plugin.theme properties instead
134
- * @returns The query parameter value or null if not found
135
- */
136
- getQueryParam(key) {
137
- return this.pluginController.getQueryParam(key);
138
- }
139
45
  static getInstance(pluginId) {
140
46
  return __awaiter(this, void 0, void 0, function* () {
141
47
  if (!RimoriClient.instance) {
142
48
  if (!pluginId)
143
49
  throw new Error('Plugin ID is required');
144
50
  const controller = new RimoriCommunicationHandler(pluginId, false);
145
- if (typeof WorkerGlobalScope === 'undefined') {
146
- // In standalone mode, use URL fallback. In iframe mode, theme will be set after MessageChannel init
147
- // setTheme();
148
- // await StandaloneClient.initListeners(pluginId);
149
- }
150
51
  const client = yield controller.getClient();
151
52
  RimoriClient.instance = new RimoriClient(controller, client.supabase, client.info);
152
53
  }
@@ -154,5 +55,3 @@ export class RimoriClient {
154
55
  });
155
56
  }
156
57
  }
157
- // test 123456
158
- // console.log('test 1234567890');
@@ -0,0 +1,138 @@
1
+ import { SupabaseClient } from '../CommunicationHandler';
2
+ import { RimoriClient } from '../RimoriClient';
3
+ export type SharedContent<T> = BasicSharedContent & T;
4
+ export interface BasicSharedContent {
5
+ id: string;
6
+ title: string;
7
+ keywords: string[];
8
+ verified: boolean;
9
+ created_by: string;
10
+ created_at: string;
11
+ guild_id: string | null;
12
+ lang_id: string | null;
13
+ }
14
+ export interface SharedContentCompletionState {
15
+ content_id: string;
16
+ state: 'completed' | 'ongoing' | 'hidden';
17
+ reaction?: 'liked' | 'disliked' | null;
18
+ bookmarked: boolean;
19
+ created_at: string;
20
+ updated_at: string;
21
+ }
22
+ export declare class SharedContentController {
23
+ private supabase;
24
+ private rimoriClient;
25
+ constructor(supabase: SupabaseClient, rimoriClient: RimoriClient);
26
+ /**
27
+ * Get new shared content. First searches for existing content matching filters that hasn't been completed,
28
+ * then falls back to AI generation if nothing suitable is found.
29
+ * @param params - Parameters object
30
+ * @param params.table - Name of the shared content table (without plugin prefix)
31
+ * @param params.placeholders - Placeholders for instructions template for AI generation (e.g., {topicAreas: "history"})
32
+ * @param params.filter - Filter to find existing content:
33
+ * - `exact`: Match field value exactly (e.g., {topic_category: {filterType: "exact", value: "history"}})
34
+ * - `exclude`: Exclude specific field value (e.g., {difficulty: {filterType: "exclude", value: "hard"}})
35
+ * - `rag`: Use semantic similarity search (e.g., {topic: {filterType: "rag", value: "japanese culture"}})
36
+ * @param params.customFields - Custom field values for AI-generated content (e.g., {topic_category: "history"})
37
+ * @param params.skipDbSave - If true, don't save generated content to database
38
+ * @param params.isPrivate - If true, content is guild-specific
39
+ * @returns Existing or newly generated shared content item
40
+ */
41
+ getNew<T>(params: {
42
+ table: string;
43
+ placeholders?: Record<string, string>;
44
+ filter?: Record<string, {
45
+ filterType: 'rag' | 'exact' | 'exclude';
46
+ value: string;
47
+ }>;
48
+ customFields?: Record<string, string | number | boolean | null>;
49
+ skipDbSave?: boolean;
50
+ isPrivate?: boolean;
51
+ }): Promise<SharedContent<T>>;
52
+ /**
53
+ * Search for shared content by topic using RAG (semantic similarity).
54
+ * @param tableName - Name of the shared content table
55
+ * @param topic - Topic to search for
56
+ * @param limit - Maximum number of results
57
+ * @returns Array of similar shared content
58
+ */
59
+ searchByTopic<T>(tableName: string, topic: string, limit?: number): Promise<SharedContent<T>[]>;
60
+ /**
61
+ * Get bookmarked shared content.
62
+ * @param tableName - Name of the shared content table
63
+ * @param limit - Maximum number of results
64
+ * @returns Array of bookmarked content
65
+ */
66
+ getBookmarked<T>(tableName: string, limit?: number): Promise<SharedContent<T>[]>;
67
+ /**
68
+ * Get ongoing shared content.
69
+ * @param tableName - Name of the shared content table
70
+ * @param limit - Maximum number of results
71
+ * @returns Array of ongoing content
72
+ */
73
+ getOngoing<T>(tableName: string, limit?: number): Promise<SharedContent<T>[]>;
74
+ /**
75
+ * Get completed shared content.
76
+ * @param tableName - Name of the shared content table
77
+ * @param limit - Maximum number of results
78
+ * @returns Array of completed content
79
+ */
80
+ getCompleted<T>(tableName: string, limit?: number): Promise<SharedContent<T>[]>;
81
+ /**
82
+ * Mark shared content as completed.
83
+ * @param tableName - Name of the shared content table
84
+ * @param contentId - ID of the content to mark as completed
85
+ */
86
+ complete(tableName: string, contentId: string): Promise<void>;
87
+ /**
88
+ * Update the state of shared content.
89
+ * @param tableName - Name of the shared content table
90
+ * @param contentId - ID of the content
91
+ * @param state - New state
92
+ */
93
+ updateState(tableName: string, contentId: string, state: 'completed' | 'ongoing' | 'hidden'): Promise<void>;
94
+ /**
95
+ * Bookmark or unbookmark shared content.
96
+ * @param tableName - Name of the shared content table
97
+ * @param contentId - ID of the content
98
+ * @param bookmarked - Whether to bookmark or unbookmark
99
+ */
100
+ bookmark(tableName: string, contentId: string, bookmarked: boolean): Promise<void>;
101
+ /**
102
+ * React to shared content with like/dislike.
103
+ * @param tableName - Name of the shared content table
104
+ * @param contentId - ID of the content
105
+ * @param reaction - Reaction type or null to remove reaction
106
+ */
107
+ react(tableName: string, contentId: string, reaction: 'liked' | 'disliked' | null): Promise<void>;
108
+ /**
109
+ * Get a specific shared content item by ID.
110
+ * @param tableName - Name of the shared content table
111
+ * @param contentId - ID of the content
112
+ * @returns The shared content item
113
+ */
114
+ get<T = any>(tableName: string, contentId: string): Promise<SharedContent<T>>;
115
+ /**
116
+ * Create new shared content manually.
117
+ * @param tableName - Name of the shared content table
118
+ * @param content - Content to create
119
+ * @returns Created content
120
+ */
121
+ create<T = any>(tableName: string, content: Omit<SharedContent<T>, 'id' | 'created_at' | 'created_by'>): Promise<SharedContent<T>>;
122
+ /**
123
+ * Update existing shared content.
124
+ * @param tableName - Name of the shared content table
125
+ * @param contentId - ID of the content to update
126
+ * @param updates - Updates to apply
127
+ * @returns Updated content
128
+ */
129
+ update<T = any>(tableName: string, contentId: string, updates: Partial<SharedContent<T>>): Promise<SharedContent<T>>;
130
+ /**
131
+ * Delete shared content.
132
+ * @param tableName - Name of the shared content table
133
+ * @param contentId - ID of the content to delete
134
+ */
135
+ remove(tableName: string, contentId: string): Promise<void>;
136
+ private getCompletedTableName;
137
+ private getTableName;
138
+ }
@@ -0,0 +1,307 @@
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
+ export class SharedContentController {
11
+ constructor(supabase, rimoriClient) {
12
+ this.supabase = supabase;
13
+ this.rimoriClient = rimoriClient;
14
+ }
15
+ /**
16
+ * Get new shared content. First searches for existing content matching filters that hasn't been completed,
17
+ * then falls back to AI generation if nothing suitable is found.
18
+ * @param params - Parameters object
19
+ * @param params.table - Name of the shared content table (without plugin prefix)
20
+ * @param params.placeholders - Placeholders for instructions template for AI generation (e.g., {topicAreas: "history"})
21
+ * @param params.filter - Filter to find existing content:
22
+ * - `exact`: Match field value exactly (e.g., {topic_category: {filterType: "exact", value: "history"}})
23
+ * - `exclude`: Exclude specific field value (e.g., {difficulty: {filterType: "exclude", value: "hard"}})
24
+ * - `rag`: Use semantic similarity search (e.g., {topic: {filterType: "rag", value: "japanese culture"}})
25
+ * @param params.customFields - Custom field values for AI-generated content (e.g., {topic_category: "history"})
26
+ * @param params.skipDbSave - If true, don't save generated content to database
27
+ * @param params.isPrivate - If true, content is guild-specific
28
+ * @returns Existing or newly generated shared content item
29
+ */
30
+ getNew(params) {
31
+ return __awaiter(this, void 0, void 0, function* () {
32
+ // Generate new content via backend endpoint
33
+ const response = yield this.rimoriClient.runtime.fetchBackend('/shared-content/generate', {
34
+ method: 'POST',
35
+ headers: { 'Content-Type': 'application/json' },
36
+ body: JSON.stringify({
37
+ tableName: params.table,
38
+ placeholders: params.placeholders,
39
+ filter: params.filter,
40
+ customFields: params.customFields,
41
+ options: {
42
+ skipDbSave: params.skipDbSave,
43
+ isPrivate: params.isPrivate,
44
+ },
45
+ }),
46
+ });
47
+ if (!response.ok) {
48
+ throw new Error(`Failed to generate shared content: ${response.statusText}`);
49
+ }
50
+ return yield response.json();
51
+ });
52
+ }
53
+ /**
54
+ * Search for shared content by topic using RAG (semantic similarity).
55
+ * @param tableName - Name of the shared content table
56
+ * @param topic - Topic to search for
57
+ * @param limit - Maximum number of results
58
+ * @returns Array of similar shared content
59
+ */
60
+ searchByTopic(tableName_1, topic_1) {
61
+ return __awaiter(this, arguments, void 0, function* (tableName, topic, limit = 10) {
62
+ const fullTableName = this.getTableName(tableName);
63
+ const completedTableName = this.getCompletedTableName(tableName);
64
+ // Generate embedding for search topic
65
+ const response = yield this.rimoriClient.runtime.fetchBackend('/ai/embedding', {
66
+ method: 'POST',
67
+ headers: { 'Content-Type': 'application/json' },
68
+ body: JSON.stringify({ text: topic }),
69
+ });
70
+ if (!response.ok) {
71
+ throw new Error(`Failed to generate embedding: ${response.statusText}`);
72
+ }
73
+ const { embedding } = yield response.json();
74
+ // RPC call for vector similarity search with completion filtering
75
+ const { data, error } = yield this.supabase.rpc('search_shared_content', {
76
+ p_table_name: fullTableName,
77
+ p_completed_table_name: completedTableName,
78
+ p_embedding: JSON.stringify(embedding),
79
+ p_limit: limit,
80
+ });
81
+ if (error) {
82
+ console.error('Error searching shared content:', error);
83
+ throw new Error('Error searching shared content');
84
+ }
85
+ return data || [];
86
+ });
87
+ }
88
+ /**
89
+ * Get bookmarked shared content.
90
+ * @param tableName - Name of the shared content table
91
+ * @param limit - Maximum number of results
92
+ * @returns Array of bookmarked content
93
+ */
94
+ getBookmarked(tableName_1) {
95
+ return __awaiter(this, arguments, void 0, function* (tableName, limit = 30) {
96
+ const fullTableName = this.getTableName(tableName);
97
+ const completedTableName = this.getCompletedTableName(tableName);
98
+ const { data, error } = yield this.supabase
99
+ .from(fullTableName)
100
+ .select(`*, completed:${completedTableName}!inner(*)`)
101
+ .eq(`completed.bookmarked`, true)
102
+ .limit(limit);
103
+ if (error) {
104
+ console.error('Error fetching bookmarked content:', error);
105
+ throw new Error('Error fetching bookmarked content');
106
+ }
107
+ return (data || []);
108
+ });
109
+ }
110
+ /**
111
+ * Get ongoing shared content.
112
+ * @param tableName - Name of the shared content table
113
+ * @param limit - Maximum number of results
114
+ * @returns Array of ongoing content
115
+ */
116
+ getOngoing(tableName_1) {
117
+ return __awaiter(this, arguments, void 0, function* (tableName, limit = 30) {
118
+ const fullTableName = this.getTableName(tableName);
119
+ const completedTableName = this.getCompletedTableName(tableName);
120
+ const { data, error } = yield this.supabase
121
+ .from(fullTableName)
122
+ .select(`*, completed:${completedTableName}!inner(*)`)
123
+ .eq(`completed.state`, 'ongoing')
124
+ .limit(limit);
125
+ if (error) {
126
+ console.error('Error fetching ongoing content:', error);
127
+ throw new Error('Error fetching ongoing content');
128
+ }
129
+ return (data || []);
130
+ });
131
+ }
132
+ /**
133
+ * Get completed shared content.
134
+ * @param tableName - Name of the shared content table
135
+ * @param limit - Maximum number of results
136
+ * @returns Array of completed content
137
+ */
138
+ getCompleted(tableName_1) {
139
+ return __awaiter(this, arguments, void 0, function* (tableName, limit = 30) {
140
+ const fullTableName = this.getTableName(tableName);
141
+ const completedTableName = this.getCompletedTableName(tableName);
142
+ const { data, error } = yield this.supabase
143
+ .from(fullTableName)
144
+ .select(`*, completed:${completedTableName}!inner(*)`)
145
+ .eq(`completed.state`, 'completed')
146
+ .limit(limit);
147
+ if (error) {
148
+ console.error('Error fetching completed content:', error);
149
+ throw new Error('Error fetching completed content');
150
+ }
151
+ return (data || []);
152
+ });
153
+ }
154
+ /**
155
+ * Mark shared content as completed.
156
+ * @param tableName - Name of the shared content table
157
+ * @param contentId - ID of the content to mark as completed
158
+ */
159
+ complete(tableName, contentId) {
160
+ return __awaiter(this, void 0, void 0, function* () {
161
+ const completedTableName = this.getCompletedTableName(tableName);
162
+ const { error } = yield this.supabase.from(completedTableName).upsert({
163
+ content_id: contentId,
164
+ state: 'completed',
165
+ }, { onConflict: 'content_id,user_id' });
166
+ if (error) {
167
+ console.error('Error completing shared content:', error);
168
+ throw new Error('Error completing shared content');
169
+ }
170
+ });
171
+ }
172
+ /**
173
+ * Update the state of shared content.
174
+ * @param tableName - Name of the shared content table
175
+ * @param contentId - ID of the content
176
+ * @param state - New state
177
+ */
178
+ updateState(tableName, contentId, state) {
179
+ return __awaiter(this, void 0, void 0, function* () {
180
+ const completedTableName = this.getCompletedTableName(tableName);
181
+ const { error } = yield this.supabase.from(completedTableName).upsert({
182
+ content_id: contentId,
183
+ state,
184
+ }, { onConflict: 'content_id,user_id' });
185
+ if (error) {
186
+ console.error('Error updating content state:', error);
187
+ throw new Error('Error updating content state');
188
+ }
189
+ });
190
+ }
191
+ /**
192
+ * Bookmark or unbookmark shared content.
193
+ * @param tableName - Name of the shared content table
194
+ * @param contentId - ID of the content
195
+ * @param bookmarked - Whether to bookmark or unbookmark
196
+ */
197
+ bookmark(tableName, contentId, bookmarked) {
198
+ return __awaiter(this, void 0, void 0, function* () {
199
+ const completedTableName = this.getCompletedTableName(tableName);
200
+ const { error } = yield this.supabase.from(completedTableName).upsert({
201
+ content_id: contentId,
202
+ bookmarked,
203
+ }, { onConflict: 'content_id,user_id' });
204
+ if (error) {
205
+ console.error('Error bookmarking content:', error);
206
+ throw new Error('Error bookmarking content');
207
+ }
208
+ });
209
+ }
210
+ /**
211
+ * React to shared content with like/dislike.
212
+ * @param tableName - Name of the shared content table
213
+ * @param contentId - ID of the content
214
+ * @param reaction - Reaction type or null to remove reaction
215
+ */
216
+ react(tableName, contentId, reaction) {
217
+ return __awaiter(this, void 0, void 0, function* () {
218
+ const completedTableName = this.getCompletedTableName(tableName);
219
+ const { error } = yield this.supabase.from(completedTableName).upsert({
220
+ content_id: contentId,
221
+ reaction,
222
+ }, { onConflict: 'content_id,user_id' });
223
+ if (error) {
224
+ console.error('Error reacting to content:', error);
225
+ throw new Error('Error reacting to content');
226
+ }
227
+ });
228
+ }
229
+ /**
230
+ * Get a specific shared content item by ID.
231
+ * @param tableName - Name of the shared content table
232
+ * @param contentId - ID of the content
233
+ * @returns The shared content item
234
+ */
235
+ get(tableName, contentId) {
236
+ return __awaiter(this, void 0, void 0, function* () {
237
+ const fullTableName = this.getTableName(tableName);
238
+ const { data, error } = yield this.supabase.from(fullTableName).select('*').eq('id', contentId).single();
239
+ if (error) {
240
+ console.error('Error fetching shared content:', error);
241
+ throw new Error('Error fetching shared content');
242
+ }
243
+ return data;
244
+ });
245
+ }
246
+ /**
247
+ * Create new shared content manually.
248
+ * @param tableName - Name of the shared content table
249
+ * @param content - Content to create
250
+ * @returns Created content
251
+ */
252
+ create(tableName, content) {
253
+ return __awaiter(this, void 0, void 0, function* () {
254
+ const fullTableName = this.getTableName(tableName);
255
+ const { data, error } = yield this.supabase.from(fullTableName).insert(content).select().single();
256
+ if (error) {
257
+ console.error('Error creating shared content:', error);
258
+ throw new Error('Error creating shared content');
259
+ }
260
+ return data;
261
+ });
262
+ }
263
+ /**
264
+ * Update existing shared content.
265
+ * @param tableName - Name of the shared content table
266
+ * @param contentId - ID of the content to update
267
+ * @param updates - Updates to apply
268
+ * @returns Updated content
269
+ */
270
+ update(tableName, contentId, updates) {
271
+ return __awaiter(this, void 0, void 0, function* () {
272
+ const fullTableName = this.getTableName(tableName);
273
+ const { data, error } = yield this.supabase
274
+ .from(fullTableName)
275
+ .update(updates)
276
+ .eq('id', contentId)
277
+ .select()
278
+ .single();
279
+ if (error) {
280
+ console.error('Error updating shared content:', error);
281
+ throw new Error('Error updating shared content');
282
+ }
283
+ return data;
284
+ });
285
+ }
286
+ /**
287
+ * Delete shared content.
288
+ * @param tableName - Name of the shared content table
289
+ * @param contentId - ID of the content to delete
290
+ */
291
+ remove(tableName, contentId) {
292
+ return __awaiter(this, void 0, void 0, function* () {
293
+ const fullTableName = this.getTableName(tableName);
294
+ const { error } = yield this.supabase.from(fullTableName).delete().eq('id', contentId);
295
+ if (error) {
296
+ console.error('Error deleting shared content:', error);
297
+ throw new Error('Error deleting shared content');
298
+ }
299
+ });
300
+ }
301
+ getCompletedTableName(tableName) {
302
+ return this.getTableName(tableName) + '_completed';
303
+ }
304
+ getTableName(tableName) {
305
+ return `${this.rimoriClient.plugin.pluginId}_sc_${tableName}`;
306
+ }
307
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rimori/client",
3
- "version": "2.5.5-next.4",
3
+ "version": "2.5.5-next.5",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "repository": {
@@ -1,106 +0,0 @@
1
- import { SupabaseClient } from '../plugin/CommunicationHandler';
2
- import { RimoriClient } from '../plugin/RimoriClient';
3
- import { ObjectRequest } from './ObjectController';
4
- export interface SharedContentObjectRequest extends ObjectRequest {
5
- fixedProperties?: Record<string, string | number | boolean>;
6
- }
7
- export type SharedContentFilter = Record<string, string | number | boolean>;
8
- export declare class SharedContentController {
9
- private supabase;
10
- private rimoriClient;
11
- constructor(supabase: SupabaseClient, rimoriClient: RimoriClient);
12
- /**
13
- * Fetch new shared content for a given content type.
14
- * @param contentType - The type of content to fetch.
15
- * @param generatorInstructions - The instructions for the generator. The object needs to have a tool property with a topic and keywords property to let a new unique topic be generated.
16
- * @param filter - An optional filter to apply to the query.
17
- * @param options - Optional options.
18
- * @param options.privateTopic - If the topic should be private and only be visible to the user.
19
- * @param options.skipDbSave - If true, do not persist a newly generated content to the DB (default false).
20
- * @param options.alwaysGenerateNew - If true, always generate a new content even if there is already a content with the same filter.
21
- * @param options.excludeIds - Optional list of shared_content ids to exclude from selection.
22
- * @returns The new shared content.
23
- */
24
- getNewSharedContent<T>(contentType: string, generatorInstructions: SharedContentObjectRequest, filter?: SharedContentFilter, options?: {
25
- privateTopic?: boolean;
26
- skipDbSave?: boolean;
27
- alwaysGenerateNew?: boolean;
28
- excludeIds?: string[];
29
- }): Promise<SharedContent<T>>;
30
- private generateNewAssignment;
31
- private getGeneratorInstructions;
32
- private getCompletedTopics;
33
- getSharedContent<T>(contentType: string, id: string): Promise<SharedContent<T>>;
34
- completeSharedContent(contentType: string, assignmentId: string): Promise<void>;
35
- /**
36
- * Update state details for a shared content entry in shared_content_completed.
37
- * Assumes table has columns: state ('completed'|'ongoing'|'hidden'), reaction ('liked'|'disliked'|null), bookmarked boolean.
38
- * Upserts per (id, content_type, user).
39
- * @param param
40
- * @param param.contentType - The content type.
41
- * @param param.id - The shared content id.
42
- * @param param.state - The state to set.
43
- * @param param.reaction - Optional reaction.
44
- * @param param.bookmarked - Optional bookmark flag.
45
- */
46
- updateSharedContentState({ contentType, id, state, reaction, bookmarked, }: {
47
- contentType: string;
48
- id: string;
49
- state?: 'completed' | 'ongoing' | 'hidden';
50
- reaction?: 'liked' | 'disliked' | null;
51
- bookmarked?: boolean;
52
- }): Promise<void>;
53
- /**
54
- * Fetch shared content from the database based on optional filters.
55
- * @param contentType - The type of content to fetch.
56
- * @param filter - Optional filter to apply to the query.
57
- * @param limit - Optional limit for the number of results.
58
- * @returns Array of shared content matching the criteria.
59
- */
60
- getSharedContentList<T>(contentType: string, filter?: SharedContentFilter, limit?: number): Promise<SharedContent<T>[]>;
61
- /**
62
- * Insert new shared content into the database.
63
- * @param param
64
- * @param param.contentType - The type of content to insert.
65
- * @param param.title - The title of the content.
66
- * @param param.keywords - Keywords associated with the content.
67
- * @param param.data - The content data to store.
68
- * @param param.privateTopic - Optional flag to indicate if the topic should be private.
69
- * @returns The inserted shared content.
70
- * @throws {Error} if insertion fails.
71
- */
72
- createSharedContent<T>({ contentType, title, keywords, data, privateTopic, }: Omit<SharedContent<T>, 'id'>): Promise<SharedContent<T>>;
73
- /**
74
- * Update existing shared content in the database.
75
- * @param id - The ID of the content to update.
76
- * @param updates - The updates to apply to the shared content.
77
- * @returns The updated shared content.
78
- * @throws {Error} if update fails.
79
- */
80
- updateSharedContent<T>(id: string, updates: Partial<SharedContent<T>>): Promise<SharedContent<T>>;
81
- /**
82
- * Soft delete shared content by setting the deleted_at timestamp.
83
- * @param id - The ID of the content to delete.
84
- * @returns The deleted shared content record.
85
- * @throws {Error} if deletion fails or content not found.
86
- */
87
- removeSharedContent(id: string): Promise<SharedContent<any>>;
88
- }
89
- /**
90
- * Interface representing shared content in the system.
91
- * @template T The type of data stored in the content
92
- */
93
- export interface SharedContent<T> {
94
- /** The id of the content */
95
- id: string;
96
- /** The type/category of the content (e.g. 'grammar_exercises', 'flashcards', etc.) */
97
- contentType: string;
98
- /** The human readable title of the content */
99
- title: string;
100
- /** Array of keywords/tags associated with the content for search and categorization */
101
- keywords: string[];
102
- /** The actual content data of type T */
103
- data: T;
104
- /** Whether this content should only be visible to the creator. Defaults to false if not specified */
105
- privateTopic?: boolean;
106
- }
@@ -1,300 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- export class SharedContentController {
11
- constructor(supabase, rimoriClient) {
12
- this.supabase = supabase;
13
- this.rimoriClient = rimoriClient;
14
- }
15
- /**
16
- * Fetch new shared content for a given content type.
17
- * @param contentType - The type of content to fetch.
18
- * @param generatorInstructions - The instructions for the generator. The object needs to have a tool property with a topic and keywords property to let a new unique topic be generated.
19
- * @param filter - An optional filter to apply to the query.
20
- * @param options - Optional options.
21
- * @param options.privateTopic - If the topic should be private and only be visible to the user.
22
- * @param options.skipDbSave - If true, do not persist a newly generated content to the DB (default false).
23
- * @param options.alwaysGenerateNew - If true, always generate a new content even if there is already a content with the same filter.
24
- * @param options.excludeIds - Optional list of shared_content ids to exclude from selection.
25
- * @returns The new shared content.
26
- */
27
- getNewSharedContent(contentType, generatorInstructions,
28
- //this filter is there if the content should be filtered additionally by a column and value
29
- filter, options) {
30
- return __awaiter(this, void 0, void 0, function* () {
31
- var _a, _b, _c, _d, _e;
32
- // The db cache of the shared content is temporary disabled until the new shared content implementation is completed
33
- if (true) {
34
- let query = this.supabase
35
- .schema('public')
36
- .from('shared_content')
37
- .select('*, scc:shared_content_completed(id, state)')
38
- .eq('content_type', contentType)
39
- .not('scc.state', 'in', '("completed","ongoing","hidden")')
40
- .is('deleted_at', null);
41
- if ((_b = (_a = options === null || options === void 0 ? void 0 : options.excludeIds) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0 > 0) {
42
- const excludeIds = (_d = (_c = options === null || options === void 0 ? void 0 : options.excludeIds) === null || _c === void 0 ? void 0 : _c.filter((id) => !id.startsWith('internal-temp-id-'))) !== null && _d !== void 0 ? _d : [];
43
- // Supabase expects raw PostgREST syntax like '("id1","id2")'.
44
- const excludeList = `(${(_e = excludeIds === null || excludeIds === void 0 ? void 0 : excludeIds.map((id) => `"${id}"`).join(',')) !== null && _e !== void 0 ? _e : ''})`;
45
- query = query.not('id', 'in', excludeList);
46
- }
47
- if (filter) {
48
- query.contains('data', filter);
49
- }
50
- const { data: newAssignments, error } = yield query.limit(30);
51
- if (error) {
52
- console.error('error fetching new assignments:', error);
53
- throw new Error('error fetching new assignments');
54
- }
55
- // console.log('newAssignments:', newAssignments);
56
- if (!(options === null || options === void 0 ? void 0 : options.alwaysGenerateNew) && newAssignments.length > 0) {
57
- const index = Math.floor(Math.random() * newAssignments.length);
58
- return newAssignments[index];
59
- }
60
- }
61
- const instructions = yield this.generateNewAssignment(contentType, generatorInstructions, filter);
62
- console.log('instructions:', instructions);
63
- //create the shared content object
64
- const data = {
65
- id: 'internal-temp-id-' + Math.random().toString(36).substring(2, 15),
66
- contentType,
67
- title: instructions.title,
68
- keywords: instructions.keywords.map(({ text }) => text),
69
- data: Object.assign(Object.assign(Object.assign({}, instructions), { title: undefined, keywords: undefined }), generatorInstructions.fixedProperties),
70
- privateTopic: options === null || options === void 0 ? void 0 : options.privateTopic,
71
- };
72
- if (options === null || options === void 0 ? void 0 : options.skipDbSave) {
73
- return data;
74
- }
75
- return yield this.createSharedContent(data);
76
- });
77
- }
78
- generateNewAssignment(contentType, generatorInstructions, filter) {
79
- return __awaiter(this, void 0, void 0, function* () {
80
- const fullInstructions = yield this.getGeneratorInstructions(contentType, generatorInstructions, filter);
81
- console.log('fullInstructions:', fullInstructions);
82
- return yield this.rimoriClient.ai.getObject(fullInstructions);
83
- });
84
- }
85
- getGeneratorInstructions(contentType, generatorInstructions, filter) {
86
- return __awaiter(this, void 0, void 0, function* () {
87
- const completedTopics = yield this.getCompletedTopics(contentType, filter);
88
- generatorInstructions.instructions += `
89
- The following topics are already taken: ${completedTopics.join(', ')}`;
90
- generatorInstructions.tool.title = {
91
- type: 'string',
92
- description: 'What the topic is about. Short. ',
93
- };
94
- generatorInstructions.tool.keywords = {
95
- type: [{ text: { type: 'string' } }],
96
- description: 'Keywords around the topic of the assignment.',
97
- };
98
- return generatorInstructions;
99
- });
100
- }
101
- getCompletedTopics(contentType, filter) {
102
- return __awaiter(this, void 0, void 0, function* () {
103
- const query = this.supabase
104
- .schema('public')
105
- .from('shared_content')
106
- .select('title, keywords, scc:shared_content_completed(id)')
107
- .eq('content_type', contentType)
108
- .not('scc.id', 'is', null)
109
- .is('deleted_at', null);
110
- if (filter) {
111
- query.contains('data', filter);
112
- }
113
- const { data: oldAssignments, error } = yield query;
114
- if (error) {
115
- console.error('error fetching old assignments:', error);
116
- return [];
117
- }
118
- return oldAssignments.map(({ title, keywords }) => `${title}(${keywords.join(',')})`);
119
- });
120
- }
121
- getSharedContent(contentType, id) {
122
- return __awaiter(this, void 0, void 0, function* () {
123
- const { data, error } = yield this.supabase
124
- .schema('public')
125
- .from('shared_content')
126
- .select()
127
- .eq('content_type', contentType)
128
- .eq('id', id)
129
- .is('deleted_at', null)
130
- .single();
131
- if (error) {
132
- console.error('error fetching shared content:', error);
133
- throw new Error('error fetching shared content');
134
- }
135
- return data;
136
- });
137
- }
138
- completeSharedContent(contentType, assignmentId) {
139
- return __awaiter(this, void 0, void 0, function* () {
140
- // Idempotent completion: upsert on (id, user_id) so repeated calls don't fail
141
- const { error } = yield this.supabase
142
- .schema('public')
143
- .from('shared_content_completed')
144
- .upsert({ content_type: contentType, id: assignmentId }, { onConflict: 'id' });
145
- if (error) {
146
- console.error('error completing shared content:', error);
147
- throw new Error('error completing shared content');
148
- }
149
- });
150
- }
151
- /**
152
- * Update state details for a shared content entry in shared_content_completed.
153
- * Assumes table has columns: state ('completed'|'ongoing'|'hidden'), reaction ('liked'|'disliked'|null), bookmarked boolean.
154
- * Upserts per (id, content_type, user).
155
- * @param param
156
- * @param param.contentType - The content type.
157
- * @param param.id - The shared content id.
158
- * @param param.state - The state to set.
159
- * @param param.reaction - Optional reaction.
160
- * @param param.bookmarked - Optional bookmark flag.
161
- */
162
- updateSharedContentState(_a) {
163
- return __awaiter(this, arguments, void 0, function* ({ contentType, id, state, reaction, bookmarked, }) {
164
- const payload = { content_type: contentType, id };
165
- if (state !== undefined)
166
- payload.state = state;
167
- if (reaction !== undefined)
168
- payload.reaction = reaction;
169
- if (bookmarked !== undefined)
170
- payload.bookmarked = bookmarked;
171
- // Prefer upsert, fall back to insert/update if upsert not allowed
172
- const { error } = yield this.supabase
173
- .schema('public')
174
- .from('shared_content_completed')
175
- .upsert(payload, { onConflict: 'id' });
176
- if (error) {
177
- console.error('error updating shared content state:', error);
178
- throw new Error('error updating shared content state');
179
- }
180
- });
181
- }
182
- /**
183
- * Fetch shared content from the database based on optional filters.
184
- * @param contentType - The type of content to fetch.
185
- * @param filter - Optional filter to apply to the query.
186
- * @param limit - Optional limit for the number of results.
187
- * @returns Array of shared content matching the criteria.
188
- */
189
- getSharedContentList(contentType, filter, limit) {
190
- return __awaiter(this, void 0, void 0, function* () {
191
- const query = this.supabase
192
- .schema('public')
193
- .from('shared_content')
194
- .select('*')
195
- .eq('content_type', contentType)
196
- .is('deleted_at', null)
197
- .limit(limit !== null && limit !== void 0 ? limit : 30);
198
- if (filter) {
199
- query.contains('data', filter);
200
- }
201
- const { data, error } = yield query;
202
- if (error) {
203
- console.error('error fetching shared content:', error);
204
- throw new Error('error fetching shared content');
205
- }
206
- return data;
207
- });
208
- }
209
- /**
210
- * Insert new shared content into the database.
211
- * @param param
212
- * @param param.contentType - The type of content to insert.
213
- * @param param.title - The title of the content.
214
- * @param param.keywords - Keywords associated with the content.
215
- * @param param.data - The content data to store.
216
- * @param param.privateTopic - Optional flag to indicate if the topic should be private.
217
- * @returns The inserted shared content.
218
- * @throws {Error} if insertion fails.
219
- */
220
- createSharedContent(_a) {
221
- return __awaiter(this, arguments, void 0, function* ({ contentType, title, keywords, data, privateTopic, }) {
222
- const { data: newContent, error } = yield this.supabase
223
- .schema('public')
224
- .from('shared_content')
225
- .insert({
226
- private: privateTopic,
227
- content_type: contentType,
228
- title,
229
- keywords,
230
- data,
231
- })
232
- .select();
233
- if (error) {
234
- console.error('error inserting shared content:', error);
235
- throw new Error('error inserting shared content');
236
- }
237
- return newContent[0];
238
- });
239
- }
240
- /**
241
- * Update existing shared content in the database.
242
- * @param id - The ID of the content to update.
243
- * @param updates - The updates to apply to the shared content.
244
- * @returns The updated shared content.
245
- * @throws {Error} if update fails.
246
- */
247
- updateSharedContent(id, updates) {
248
- return __awaiter(this, void 0, void 0, function* () {
249
- const updateData = {};
250
- if (updates.contentType)
251
- updateData.content_type = updates.contentType;
252
- if (updates.title)
253
- updateData.title = updates.title;
254
- if (updates.keywords)
255
- updateData.keywords = updates.keywords;
256
- if (updates.data)
257
- updateData.data = updates.data;
258
- if (updates.privateTopic !== undefined)
259
- updateData.private = updates.privateTopic;
260
- const { data: updatedContent, error } = yield this.supabase
261
- .schema('public')
262
- .from('shared_content')
263
- .update(updateData)
264
- .eq('id', id)
265
- .select();
266
- if (error) {
267
- console.error('error updating shared content:', error);
268
- throw new Error('error updating shared content');
269
- }
270
- if (!updatedContent || updatedContent.length === 0) {
271
- throw new Error('shared content not found');
272
- }
273
- return updatedContent[0];
274
- });
275
- }
276
- /**
277
- * Soft delete shared content by setting the deleted_at timestamp.
278
- * @param id - The ID of the content to delete.
279
- * @returns The deleted shared content record.
280
- * @throws {Error} if deletion fails or content not found.
281
- */
282
- removeSharedContent(id) {
283
- return __awaiter(this, void 0, void 0, function* () {
284
- const { data: deletedContent, error } = yield this.supabase
285
- .schema('public')
286
- .from('shared_content')
287
- .update({ deleted_at: new Date().toISOString() })
288
- .eq('id', id)
289
- .select();
290
- if (error) {
291
- console.error('error deleting shared content:', error);
292
- throw new Error('error deleting shared content');
293
- }
294
- if (!deletedContent || deletedContent.length === 0) {
295
- throw new Error('shared content not found or already deleted');
296
- }
297
- return deletedContent[0];
298
- });
299
- }
300
- }