@rimori/client 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/CRUDModal.d.ts +16 -0
  2. package/dist/CRUDModal.js +31 -0
  3. package/dist/MarkdownEditor.d.ts +8 -0
  4. package/dist/MarkdownEditor.js +46 -0
  5. package/dist/audio/Playbutton.d.ts +14 -0
  6. package/dist/audio/Playbutton.js +73 -0
  7. package/dist/components/CRUDModal.d.ts +17 -0
  8. package/dist/components/CRUDModal.js +25 -0
  9. package/dist/components/MarkdownEditor.d.ts +8 -0
  10. package/dist/components/MarkdownEditor.js +46 -0
  11. package/dist/components/Spinner.d.ts +8 -0
  12. package/dist/components/Spinner.js +5 -0
  13. package/dist/components/audio/Playbutton.d.ts +15 -0
  14. package/dist/components/audio/Playbutton.js +78 -0
  15. package/dist/components/hooks/UseChatHook.d.ts +15 -0
  16. package/dist/components/hooks/UseChatHook.js +21 -0
  17. package/dist/controller/AIController.d.ts +22 -0
  18. package/dist/controller/AIController.js +68 -0
  19. package/dist/controller/ObjectController.d.ts +34 -0
  20. package/dist/controller/ObjectController.js +77 -0
  21. package/dist/controller/SettingsController.d.ts +24 -0
  22. package/dist/controller/SettingsController.js +72 -0
  23. package/dist/controller/SharedContentController.d.ts +22 -0
  24. package/dist/controller/SharedContentController.js +56 -0
  25. package/dist/controller/VoiceController.d.ts +10 -0
  26. package/dist/controller/VoiceController.js +28 -0
  27. package/dist/hooks/UseChatHook.d.ts +9 -0
  28. package/dist/hooks/UseChatHook.js +21 -0
  29. package/dist/index.d.ts +14 -0
  30. package/dist/index.js +14 -0
  31. package/dist/plugin/AIController copy.d.ts +22 -0
  32. package/dist/plugin/AIController copy.js +68 -0
  33. package/dist/plugin/AIController.d.ts +22 -0
  34. package/dist/plugin/AIController.js +68 -0
  35. package/dist/plugin/ObjectController.d.ts +34 -0
  36. package/dist/plugin/ObjectController.js +77 -0
  37. package/dist/plugin/PluginController.d.ts +29 -0
  38. package/dist/plugin/PluginController.js +138 -0
  39. package/dist/plugin/RimoriClient.d.ts +91 -0
  40. package/dist/plugin/RimoriClient.js +163 -0
  41. package/dist/plugin/SettingController.d.ts +13 -0
  42. package/dist/plugin/SettingController.js +55 -0
  43. package/dist/plugin/ThemeSetter.d.ts +1 -0
  44. package/dist/plugin/ThemeSetter.js +13 -0
  45. package/dist/plugin/VoiceController.d.ts +2 -0
  46. package/dist/plugin/VoiceController.js +27 -0
  47. package/dist/providers/EventEmitter.d.ts +11 -0
  48. package/dist/providers/EventEmitter.js +41 -0
  49. package/dist/providers/EventEmitterContext.d.ts +6 -0
  50. package/dist/providers/EventEmitterContext.js +19 -0
  51. package/dist/providers/PluginProvider.d.ts +8 -0
  52. package/dist/providers/PluginProvider.js +52 -0
  53. package/dist/style.css +110 -0
  54. package/dist/style.css.map +1 -0
  55. package/dist/utils/DifficultyConverter.d.ts +3 -0
  56. package/dist/utils/DifficultyConverter.js +7 -0
  57. package/dist/utils/PluginUtils.d.ts +2 -0
  58. package/dist/utils/PluginUtils.js +23 -0
  59. package/dist/utils/constants.d.ts +4 -0
  60. package/dist/utils/constants.js +12 -0
  61. package/dist/utils/difficultyConverter.d.ts +3 -0
  62. package/dist/utils/difficultyConverter.js +7 -0
  63. package/dist/utils/plugin/Client.d.ts +72 -0
  64. package/dist/utils/plugin/Client.js +118 -0
  65. package/dist/utils/plugin/PluginController.d.ts +36 -0
  66. package/dist/utils/plugin/PluginController.js +119 -0
  67. package/dist/utils/plugin/PluginUtils.d.ts +2 -0
  68. package/dist/utils/plugin/PluginUtils.js +23 -0
  69. package/dist/utils/plugin/RimoriClient.d.ts +72 -0
  70. package/dist/utils/plugin/RimoriClient.js +118 -0
  71. package/dist/utils/plugin/ThemeSetter.d.ts +1 -0
  72. package/dist/utils/plugin/ThemeSetter.js +13 -0
  73. package/dist/utils/plugin/WhereClauseBuilder.d.ts +24 -0
  74. package/dist/utils/plugin/WhereClauseBuilder.js +79 -0
  75. package/dist/utils/plugin/providers/EventEmitter.d.ts +11 -0
  76. package/dist/utils/plugin/providers/EventEmitter.js +41 -0
  77. package/dist/utils/plugin/providers/EventEmitterContext.d.ts +6 -0
  78. package/dist/utils/plugin/providers/EventEmitterContext.js +19 -0
  79. package/dist/utils/plugin/providers/PluginProvider.d.ts +8 -0
  80. package/dist/utils/plugin/providers/PluginProvider.js +49 -0
  81. package/package.json +30 -0
  82. package/src/components/CRUDModal.tsx +61 -0
  83. package/src/components/MarkdownEditor.tsx +111 -0
  84. package/src/components/Spinner.tsx +24 -0
  85. package/src/components/audio/Playbutton.tsx +119 -0
  86. package/src/controller/AIController.ts +87 -0
  87. package/src/controller/ObjectController.ts +109 -0
  88. package/src/controller/SettingsController.ts +87 -0
  89. package/src/controller/SharedContentController.ts +71 -0
  90. package/src/controller/VoiceController.ts +26 -0
  91. package/src/hooks/UseChatHook.ts +25 -0
  92. package/src/index.ts +14 -0
  93. package/src/plugin/PluginController.ts +158 -0
  94. package/src/plugin/RimoriClient.ts +207 -0
  95. package/src/plugin/ThemeSetter.ts +17 -0
  96. package/src/providers/EventEmitter.ts +48 -0
  97. package/src/providers/EventEmitterContext.tsx +27 -0
  98. package/src/providers/PluginProvider.tsx +68 -0
  99. package/src/style.scss +136 -0
  100. package/src/utils/PluginUtils.ts +26 -0
  101. package/src/utils/constants.ts +18 -0
  102. package/src/utils/difficultyConverter.ts +11 -0
  103. package/tsconfig.json +16 -0
@@ -0,0 +1,52 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect, useState } from 'react';
3
+ import { PluginController } from '../plugin/PluginController';
4
+ const PluginContext = createContext(null);
5
+ export const PluginProvider = ({ children }) => {
6
+ const [plugin, setPlugin] = useState(null);
7
+ //route change
8
+ useEffect(() => {
9
+ let lastHash = window.location.hash;
10
+ setInterval(() => {
11
+ if (lastHash !== window.location.hash) {
12
+ lastHash = window.location.hash;
13
+ console.log('url changed:', lastHash);
14
+ plugin === null || plugin === void 0 ? void 0 : plugin.emit('urlChange', window.location.hash);
15
+ }
16
+ }, 100);
17
+ PluginController.getInstance().then(setPlugin);
18
+ }, []);
19
+ //context menu
20
+ useEffect(() => {
21
+ let isOpen = false;
22
+ const handleContextMenu = (e) => {
23
+ var _a;
24
+ const selection = (_a = window.getSelection()) === null || _a === void 0 ? void 0 : _a.toString().trim();
25
+ if (selection) {
26
+ e.preventDefault();
27
+ // console.log('context menu', selection);
28
+ plugin === null || plugin === void 0 ? void 0 : plugin.emit('contextMenu', { text: selection, x: e.clientX, y: e.clientY, open: true });
29
+ isOpen = true;
30
+ }
31
+ };
32
+ // Hide the menu on click outside
33
+ const handleClick = () => isOpen && (plugin === null || plugin === void 0 ? void 0 : plugin.emit('contextMenu', { text: '', x: 0, y: 0, open: false }));
34
+ document.addEventListener("click", handleClick);
35
+ document.addEventListener('contextmenu', handleContextMenu);
36
+ return () => {
37
+ document.removeEventListener("click", handleClick);
38
+ document.removeEventListener('contextmenu', handleContextMenu);
39
+ };
40
+ }, [plugin]);
41
+ if (!plugin) {
42
+ return "";
43
+ }
44
+ return (_jsx(PluginContext.Provider, { value: plugin, children: children }));
45
+ };
46
+ export const usePlugin = () => {
47
+ const context = useContext(PluginContext);
48
+ if (context === null) {
49
+ throw new Error('usePlugin must be used within an PluginProvider');
50
+ }
51
+ return context;
52
+ };
package/dist/style.css ADDED
@@ -0,0 +1,110 @@
1
+ dialog::backdrop {
2
+ backdrop-filter: blur(2px);
3
+ }
4
+
5
+ .dark * dialog::backdrop {
6
+ background: transparent;
7
+ }
8
+
9
+ .tiptap {
10
+ padding-top: 5px;
11
+ padding-left: 7px;
12
+ /* min-height: 300px; */
13
+ }
14
+ .tiptap:focus-visible {
15
+ outline: none;
16
+ }
17
+ .tiptap h1,
18
+ .tiptap h2,
19
+ .tiptap h3,
20
+ .tiptap h4,
21
+ .tiptap h5,
22
+ .tiptap h6 {
23
+ @apply font-bold;
24
+ margin-bottom: 1rem;
25
+ }
26
+ .tiptap h1 {
27
+ @apply text-4xl;
28
+ }
29
+ .tiptap h2 {
30
+ @apply text-3xl;
31
+ }
32
+ .tiptap h3 {
33
+ @apply text-2xl;
34
+ }
35
+ .tiptap h4 {
36
+ @apply text-xl;
37
+ }
38
+ .tiptap h5 {
39
+ @apply text-lg;
40
+ }
41
+ .tiptap h6 {
42
+ @apply text-base;
43
+ }
44
+ .tiptap p {
45
+ @apply mb-4;
46
+ }
47
+ .tiptap a {
48
+ @apply text-blue-600 hover:text-blue-800;
49
+ text-decoration: none;
50
+ }
51
+ .tiptap a:hover {
52
+ @apply underline;
53
+ }
54
+ .tiptap ul {
55
+ @apply list-disc pl-8;
56
+ }
57
+ .tiptap ul li > p {
58
+ @apply mb-1;
59
+ }
60
+ .tiptap ol {
61
+ @apply list-decimal pl-7;
62
+ }
63
+ .tiptap ol li > p {
64
+ @apply mb-1;
65
+ }
66
+ .tiptap blockquote {
67
+ @apply border-l-4 pl-4 italic text-gray-600 my-4;
68
+ border-color: #ccc;
69
+ }
70
+ .tiptap code {
71
+ font-family: monospace;
72
+ }
73
+ .tiptap pre {
74
+ @apply bg-gray-800 text-gray-500 p-4 rounded-lg overflow-x-auto;
75
+ font-family: monospace;
76
+ white-space: pre-wrap;
77
+ word-wrap: break-word;
78
+ }
79
+ .tiptap img {
80
+ @apply max-w-full h-auto rounded-lg my-4;
81
+ }
82
+ .tiptap table {
83
+ @apply table-auto w-full border-collapse mb-4;
84
+ }
85
+ .tiptap th,
86
+ .tiptap td {
87
+ @apply border px-4 py-2 text-left;
88
+ }
89
+ .tiptap th {
90
+ @apply bg-gray-500 font-semibold;
91
+ }
92
+ .tiptap tr:nth-child(even) {
93
+ @apply bg-gray-400;
94
+ }
95
+ @media (max-width: 768px) {
96
+ .tiptap h1 {
97
+ @apply text-3xl;
98
+ }
99
+ .tiptap h2 {
100
+ @apply text-2xl;
101
+ }
102
+ .tiptap p {
103
+ @apply text-base;
104
+ }
105
+ .tiptap img {
106
+ @apply max-w-full;
107
+ }
108
+ }
109
+
110
+ /*# sourceMappingURL=style.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sourceRoot":"","sources":["../src/style.scss"],"names":[],"mappings":"AAAA;EACE;;;AAIF;EACE;;;AAGF;EACE;EACA;AACA;;AAEA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;AAAA;EAME;EACA;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;EACA;;AAGF;EACE;;AAGF;EACE;;AAEA;EACE;;AAIJ;EACE;;AAEA;EACE;;AAIJ;EACE;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAGF;AAAA;EAEE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE","file":"style.css"}
@@ -0,0 +1,3 @@
1
+ export type LanguageLevel = "Pre-A1" | "A1" | "A2" | "B1" | "B2" | "C1" | "C2" | "Post-C2";
2
+ export declare function getDifficultyLevel(difficulty: LanguageLevel): number;
3
+ export declare function getDifficultyLabel(difficulty: number): LanguageLevel;
@@ -0,0 +1,7 @@
1
+ const codes = ["Pre-A1", "A1", "A2", "B1", "B2", "C1", "C2", "Post-C2"];
2
+ export function getDifficultyLevel(difficulty) {
3
+ return codes.indexOf(difficulty) + 1;
4
+ }
5
+ export function getDifficultyLabel(difficulty) {
6
+ return codes[difficulty];
7
+ }
@@ -0,0 +1,2 @@
1
+ export declare function isFullscreen(): boolean;
2
+ export declare function triggerFullscreen(onStateChange: (isFullscreen: boolean) => void, selector?: string): void;
@@ -0,0 +1,23 @@
1
+ export function isFullscreen() {
2
+ return !!document.fullscreenElement;
3
+ }
4
+ export function triggerFullscreen(onStateChange, selector) {
5
+ document.addEventListener("fullscreenchange", () => {
6
+ onStateChange(isFullscreen());
7
+ });
8
+ try {
9
+ const ref = document.querySelector(selector || "#root");
10
+ if (!isFullscreen()) {
11
+ // @ts-ignore
12
+ ref.requestFullscreen() || ref.webkitRequestFullscreen();
13
+ }
14
+ else {
15
+ // @ts-ignore
16
+ document.exitFullscreen() || document.webkitExitFullscreen();
17
+ }
18
+ }
19
+ catch (error) {
20
+ console.error("Failed to enter fullscreen", error.message);
21
+ }
22
+ onStateChange(isFullscreen());
23
+ }
@@ -0,0 +1,4 @@
1
+ export type Env = typeof env;
2
+ export declare const env: {
3
+ SUPABASE_URL: string;
4
+ };
@@ -0,0 +1,12 @@
1
+ // import { unstable_noStore as noStore } from 'next/cache';
2
+ export const env = {
3
+ // SUPABASE_URL: process?.env?.SUPABASE_URL || "https://pheptqdoqsdnadgoihvr.supabase.co",
4
+ SUPABASE_URL: "https://pheptqdoqsdnadgoihvr.supabase.co",
5
+ // SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY,
6
+ };
7
+ // Validate all environment variables are set
8
+ Object.entries(env).forEach(([key, value]) => {
9
+ if (!value) {
10
+ throw new Error(`${key} is not set`);
11
+ }
12
+ });
@@ -0,0 +1,3 @@
1
+ export type LanguageLevel = "Pre-A1" | "A1" | "A2" | "B1" | "B2" | "C1" | "C2" | "Post-C2";
2
+ export declare function getDifficultyLevel(difficulty: LanguageLevel): number;
3
+ export declare function getDifficultyLabel(difficulty: number): LanguageLevel;
@@ -0,0 +1,7 @@
1
+ const codes = ["Pre-A1", "A1", "A2", "B1", "B2", "C1", "C2", "Post-C2"];
2
+ export function getDifficultyLevel(difficulty) {
3
+ return codes.indexOf(difficulty) + 1;
4
+ }
5
+ export function getDifficultyLabel(difficulty) {
6
+ return codes[difficulty];
7
+ }
@@ -0,0 +1,72 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+ import { GenericSchema } from "@supabase/supabase-js/dist/module/lib/types";
3
+ import { PostgrestQueryBuilder, PostgrestFilterBuilder } from "@supabase/postgrest-js";
4
+ import { PluginController, Tool, ToolInvocation } from "./PluginController";
5
+ import { LanguageLevel } from "../difficultyConverter";
6
+ export declare class RimoriClient {
7
+ private static instance;
8
+ private superbase;
9
+ private plugin;
10
+ functions: SupabaseClient["functions"];
11
+ storage: SupabaseClient["storage"];
12
+ private constructor();
13
+ static getInstance(pluginController: PluginController): Promise<RimoriClient>;
14
+ from<TableName extends string & keyof GenericSchema['Tables'], Table extends GenericSchema['Tables'][TableName]>(relation: TableName): PostgrestQueryBuilder<GenericSchema, Table, GenericSchema, Table extends {
15
+ Relationships: infer R;
16
+ } ? R : unknown>;
17
+ /**
18
+ * Perform a function call.
19
+ *
20
+ * @param fn - The function name to call
21
+ * @param args - The arguments to pass to the function call
22
+ * @param options - Named parameters
23
+ * @param options.head - When set to `true`, `data` will not be returned.
24
+ * Useful if you only need the count.
25
+ * @param options.get - When set to `true`, the function will be called with
26
+ * read-only access mode.
27
+ * @param options.count - Count algorithm to use to count rows returned by the
28
+ * function. Only applicable for [set-returning
29
+ * functions](https://www.postgresql.org/docs/current/functions-srf.html).
30
+ *
31
+ * `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the
32
+ * hood.
33
+ *
34
+ * `"planned"`: Approximated but fast count algorithm. Uses the Postgres
35
+ * statistics under the hood.
36
+ *
37
+ * `"estimated"`: Uses exact count for low numbers and planned count for high
38
+ * numbers.
39
+ */
40
+ rpc<FnName extends string & keyof GenericSchema['Functions'], Fn extends GenericSchema['Functions'][FnName]>(fn: FnName, args?: Fn['Args'], options?: {
41
+ head?: boolean;
42
+ get?: boolean;
43
+ count?: 'exact' | 'planned' | 'estimated';
44
+ }): PostgrestFilterBuilder<GenericSchema, Fn['Returns'] extends any[] ? Fn['Returns'][number] extends Record<string, unknown> ? Fn['Returns'][number] : never : never, Fn['Returns'], FnName, null>;
45
+ subscribe(eventName: string, callback: (_id: number, data: any) => void): void;
46
+ request<T>(eventName: string, data: any): Promise<T>;
47
+ emit(eventName: string, data: any): void;
48
+ /**
49
+ * Get the settings for the plugin. T can be any type of settings, UserSettings or SystemSettings.
50
+ * @param defaultSettings The default settings to use if no settings are found.
51
+ * @param genericSettings The type of settings to get.
52
+ * @returns The settings for the plugin.
53
+ */
54
+ getSettings<T>(defaultSettings: T, genericSettings?: "user" | "system"): Promise<T>;
55
+ setSettings(settings: any, genericSettings?: "user" | "system"): Promise<void>;
56
+ getAIResponse(messages: {
57
+ role: string;
58
+ content: string;
59
+ }[]): Promise<string>;
60
+ getAIResponseStream(messages: {
61
+ role: string;
62
+ content: string;
63
+ }[], onMessage: (id: string, message: string, finished: boolean, toolInvocations?: ToolInvocation[]) => void, tools?: Tool[]): Promise<void>;
64
+ getVoiceResponse(text: string, voice?: string, speed?: number, language?: string): Promise<Blob>;
65
+ getVoiceToTextResponse(file: Blob): Promise<string>;
66
+ }
67
+ export interface UserSettings {
68
+ motherTongue: string;
69
+ languageLevel: LanguageLevel;
70
+ }
71
+ export interface SystemSettings {
72
+ }
@@ -0,0 +1,118 @@
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 RimoriClient {
11
+ constructor(pluginController, superbase) {
12
+ this.superbase = superbase;
13
+ this.plugin = pluginController;
14
+ this.functions = this.superbase.functions;
15
+ this.storage = this.superbase.storage;
16
+ }
17
+ static getInstance(pluginController) {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ if (!RimoriClient.instance) {
20
+ const superbase = yield pluginController.getClient();
21
+ RimoriClient.instance = new RimoriClient(pluginController, superbase);
22
+ }
23
+ return RimoriClient.instance;
24
+ });
25
+ }
26
+ from(relation) {
27
+ return this.superbase.from(relation);
28
+ }
29
+ /**
30
+ * Perform a function call.
31
+ *
32
+ * @param fn - The function name to call
33
+ * @param args - The arguments to pass to the function call
34
+ * @param options - Named parameters
35
+ * @param options.head - When set to `true`, `data` will not be returned.
36
+ * Useful if you only need the count.
37
+ * @param options.get - When set to `true`, the function will be called with
38
+ * read-only access mode.
39
+ * @param options.count - Count algorithm to use to count rows returned by the
40
+ * function. Only applicable for [set-returning
41
+ * functions](https://www.postgresql.org/docs/current/functions-srf.html).
42
+ *
43
+ * `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the
44
+ * hood.
45
+ *
46
+ * `"planned"`: Approximated but fast count algorithm. Uses the Postgres
47
+ * statistics under the hood.
48
+ *
49
+ * `"estimated"`: Uses exact count for low numbers and planned count for high
50
+ * numbers.
51
+ */
52
+ rpc(fn, args = {}, options = {}) {
53
+ return this.superbase.rpc(fn, args, options);
54
+ }
55
+ subscribe(eventName, callback) {
56
+ this.plugin.subscribe(eventName, callback);
57
+ }
58
+ request(eventName, data) {
59
+ return this.plugin.request(eventName, data);
60
+ }
61
+ emit(eventName, data) {
62
+ this.plugin.emit(eventName, data);
63
+ }
64
+ /**
65
+ * Get the settings for the plugin. T can be any type of settings, UserSettings or SystemSettings.
66
+ * @param defaultSettings The default settings to use if no settings are found.
67
+ * @param genericSettings The type of settings to get.
68
+ * @returns The settings for the plugin.
69
+ */
70
+ getSettings(defaultSettings, genericSettings) {
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ const response = yield this.plugin.request("get_settings", { genericSettings });
73
+ if (response === null) {
74
+ this.setSettings(defaultSettings, genericSettings);
75
+ return defaultSettings;
76
+ //if the settings are not the same, merge the settings
77
+ }
78
+ else if (Object.keys(response).length !== Object.keys(defaultSettings).length) {
79
+ const existingKeys = Object.fromEntries(Object.entries(response).filter(([k]) => k in defaultSettings));
80
+ const mergedSettings = Object.assign(Object.assign({}, defaultSettings), existingKeys);
81
+ console.warn("Settings mismatch", { response, defaultSettings, mergedSettings });
82
+ this.setSettings(mergedSettings, genericSettings);
83
+ return mergedSettings;
84
+ }
85
+ return response;
86
+ });
87
+ }
88
+ setSettings(settings, genericSettings) {
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ yield this.plugin.request("set_settings", { settings, genericSettings });
91
+ });
92
+ }
93
+ getAIResponse(messages) {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ return this.plugin.request("getAIResponse", messages);
96
+ });
97
+ }
98
+ getAIResponseStream(messages, onMessage, tools) {
99
+ return __awaiter(this, void 0, void 0, function* () {
100
+ throw new Error("Not implemented");
101
+ // let triggered = false;
102
+ // console.log("getAIResponseStream", messages);
103
+ // const id = Math.random();
104
+ // this.internalEmit("getAIResponseStream", id, { messages, tools: tools || [] });
105
+ // this.subscribe("getAIResponseStream", (_id: number, data: { id: string, response: string, finished: boolean, toolInvocations?: ToolInvocation[] }) => {
106
+ // if (triggered || (_id !== id && _id !== 0)) return;
107
+ // triggered = data.finished;
108
+ // onMessage(data.id, data.response, data.finished, data.toolInvocations);
109
+ // })
110
+ });
111
+ }
112
+ getVoiceResponse(text, voice = "alloy", speed = 1, language) {
113
+ return this.plugin.request("getVoiceResponse", { text, voice, speed, language });
114
+ }
115
+ getVoiceToTextResponse(file) {
116
+ return this.plugin.request("getSTTResponse", file);
117
+ }
118
+ }
@@ -0,0 +1,36 @@
1
+ import { SupabaseClient } from '@supabase/supabase-js';
2
+ import { RimoriClient } from "./RimoriClient";
3
+ export interface Tool {
4
+ name: string;
5
+ description: string;
6
+ parameters: {
7
+ name: string;
8
+ type: "string" | "number" | "boolean";
9
+ description: string;
10
+ }[];
11
+ }
12
+ export interface ToolInvocation {
13
+ toolName: string;
14
+ args: Record<string, string>;
15
+ }
16
+ export declare class PluginController {
17
+ private static instance;
18
+ private static client;
19
+ private plugin;
20
+ private onceListeners;
21
+ private listeners;
22
+ private communicationSecret;
23
+ private initialized;
24
+ private supabase;
25
+ private accessTokenExpiration;
26
+ private constructor();
27
+ static getInstance(): Promise<RimoriClient>;
28
+ init(): Promise<void>;
29
+ private getSecret;
30
+ getClient(): Promise<SupabaseClient<any, "public", any>>;
31
+ emit(eventName: string, data?: any): void;
32
+ private internalEmit;
33
+ subscribe(eventName: string, callback: (_id: number, data: any) => void): void;
34
+ onOnce(eventName: string, callback: (data: any) => void): void;
35
+ request<T>(topic: string, data: any): Promise<T>;
36
+ }
@@ -0,0 +1,119 @@
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
+ import { Child } from "ibridge-flex";
11
+ import { createClient } from '@supabase/supabase-js';
12
+ import { RimoriClient } from "./RimoriClient";
13
+ export class PluginController {
14
+ constructor() {
15
+ // localStorage.debug = "*";
16
+ this.onceListeners = new Map();
17
+ this.listeners = new Map();
18
+ this.communicationSecret = null;
19
+ this.initialized = false;
20
+ this.supabase = null;
21
+ this.accessTokenExpiration = null;
22
+ this.plugin = new Child({
23
+ triggerChild: ({ topic, data, _id }) => {
24
+ var _a, _b;
25
+ // console.log("trigger child with topic:" + topic + " and data: ", data);
26
+ (_a = this.onceListeners.get(topic)) === null || _a === void 0 ? void 0 : _a.forEach((callback) => callback(_id, data));
27
+ this.onceListeners.set(topic, []);
28
+ (_b = this.listeners.get(topic)) === null || _b === void 0 ? void 0 : _b.forEach((callback) => callback(_id, data));
29
+ }
30
+ });
31
+ // this.init();
32
+ this.emit = this.emit.bind(this);
33
+ this.onOnce = this.onOnce.bind(this);
34
+ this.getClient = this.getClient.bind(this);
35
+ this.subscribe = this.subscribe.bind(this);
36
+ this.internalEmit = this.internalEmit.bind(this);
37
+ this.request = this.request.bind(this);
38
+ }
39
+ static getInstance() {
40
+ return __awaiter(this, void 0, void 0, function* () {
41
+ if (!PluginController.instance) {
42
+ PluginController.instance = new PluginController();
43
+ yield PluginController.instance.init();
44
+ PluginController.client = yield RimoriClient.getInstance(PluginController.instance);
45
+ }
46
+ return PluginController.client;
47
+ });
48
+ }
49
+ init() {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ if (this.initialized) {
52
+ return;
53
+ }
54
+ // Wait for the plugin to be ready
55
+ yield this.plugin.handshake().then(() => this.initialized = true).catch((error) => {
56
+ console.error("Failed to initialize the plugin communication:", error);
57
+ });
58
+ });
59
+ }
60
+ getSecret() {
61
+ if (!this.communicationSecret) {
62
+ const secret = new URLSearchParams(window.location.search).get("secret");
63
+ if (!secret) {
64
+ throw new Error("Communication secret not found in URL as query parameter");
65
+ }
66
+ this.communicationSecret = secret;
67
+ }
68
+ return this.communicationSecret;
69
+ }
70
+ getClient() {
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ if (this.supabase && this.accessTokenExpiration && this.accessTokenExpiration > new Date()) {
73
+ return this.supabase;
74
+ }
75
+ const response = yield this.request("getSupabaseAccess", {});
76
+ this.accessTokenExpiration = response.expiration;
77
+ this.supabase = createClient(response.url, response.key, {
78
+ accessToken: () => Promise.resolve(response.token)
79
+ });
80
+ return this.supabase;
81
+ });
82
+ }
83
+ emit(eventName, data) {
84
+ this.internalEmit(eventName, 0, data);
85
+ }
86
+ // the communication needs to have an id to be able to distinguish between different responses
87
+ internalEmit(eventName, id, data) {
88
+ this.init().then(() => this.plugin.emitToParent(eventName, { data, _id: id, secret: this.getSecret() }));
89
+ }
90
+ subscribe(eventName, callback) {
91
+ var _a;
92
+ if (!this.listeners.has(eventName)) {
93
+ this.listeners.set(eventName, []);
94
+ }
95
+ (_a = this.listeners.get(eventName)) === null || _a === void 0 ? void 0 : _a.push(callback);
96
+ }
97
+ onOnce(eventName, callback) {
98
+ var _a;
99
+ if (!this.onceListeners.has(eventName)) {
100
+ this.onceListeners.set(eventName, []);
101
+ }
102
+ (_a = this.onceListeners.get(eventName)) === null || _a === void 0 ? void 0 : _a.push(callback);
103
+ }
104
+ request(topic, data) {
105
+ return __awaiter(this, void 0, void 0, function* () {
106
+ return yield new Promise((resolve) => {
107
+ let triggered = false;
108
+ const id = Math.random();
109
+ this.internalEmit(topic, id, data);
110
+ this.subscribe(topic, (_id, data) => {
111
+ if (triggered || (_id !== id && _id !== 0))
112
+ return;
113
+ triggered = true;
114
+ resolve(data);
115
+ });
116
+ });
117
+ });
118
+ }
119
+ }
@@ -0,0 +1,2 @@
1
+ export declare function isFullscreen(): boolean;
2
+ export declare function triggerFullscreen(onStateChange: (isFullscreen: boolean) => void, selector?: string): void;
@@ -0,0 +1,23 @@
1
+ export function isFullscreen() {
2
+ return !!document.fullscreenElement;
3
+ }
4
+ export function triggerFullscreen(onStateChange, selector) {
5
+ document.addEventListener("fullscreenchange", () => {
6
+ onStateChange(isFullscreen());
7
+ });
8
+ try {
9
+ const ref = document.querySelector(selector || "#root");
10
+ if (!isFullscreen()) {
11
+ // @ts-ignore
12
+ ref.requestFullscreen() || ref.webkitRequestFullscreen();
13
+ }
14
+ else {
15
+ // @ts-ignore
16
+ document.exitFullscreen() || document.webkitExitFullscreen();
17
+ }
18
+ }
19
+ catch (error) {
20
+ console.error("Failed to enter fullscreen", error.message);
21
+ }
22
+ onStateChange(isFullscreen());
23
+ }