@rimori/client 1.1.9 → 1.2.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.
- package/README.md +128 -45
- package/dist/cli/scripts/init/dev-registration.d.ts +35 -0
- package/dist/cli/scripts/init/dev-registration.js +175 -0
- package/dist/cli/scripts/init/env-setup.d.ts +9 -0
- package/dist/cli/scripts/init/env-setup.js +43 -0
- package/dist/cli/scripts/init/file-operations.d.ts +4 -0
- package/dist/cli/scripts/init/file-operations.js +51 -0
- package/dist/cli/scripts/init/html-cleaner.d.ts +4 -0
- package/dist/cli/scripts/init/html-cleaner.js +38 -0
- package/dist/cli/scripts/init/main.d.ts +2 -0
- package/dist/cli/scripts/init/main.js +159 -0
- package/dist/cli/scripts/init/package-setup.d.ts +32 -0
- package/dist/cli/scripts/init/package-setup.js +75 -0
- package/dist/cli/scripts/init/router-transformer.d.ts +6 -0
- package/dist/cli/scripts/init/router-transformer.js +254 -0
- package/dist/cli/scripts/init/tailwind-config.d.ts +4 -0
- package/dist/cli/scripts/init/tailwind-config.js +56 -0
- package/dist/cli/scripts/init/vite-config.d.ts +20 -0
- package/dist/cli/scripts/init/vite-config.js +54 -0
- package/dist/cli/scripts/release/release-config-upload.d.ts +7 -0
- package/dist/cli/scripts/release/release-config-upload.js +116 -0
- package/dist/cli/scripts/release/release-db-update.d.ts +6 -0
- package/dist/cli/scripts/release/release-db-update.js +100 -0
- package/dist/cli/scripts/release/release-file-upload.d.ts +6 -0
- package/dist/cli/scripts/release/release-file-upload.js +136 -0
- package/dist/cli/scripts/release/release.d.ts +23 -0
- package/dist/cli/scripts/release/release.js +70 -0
- package/dist/cli/types/DatabaseTypes.d.ts +103 -0
- package/dist/cli/types/DatabaseTypes.js +2 -0
- package/dist/components/ai/Assistant.js +4 -4
- package/dist/components/ai/Avatar.d.ts +3 -2
- package/dist/components/ai/Avatar.js +10 -5
- package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +1 -1
- package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.d.ts +1 -0
- package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +12 -6
- package/dist/components/ai/utils.js +0 -1
- package/dist/components/audio/Playbutton.js +3 -3
- package/dist/{core → components}/components/ContextMenu.js +2 -2
- package/dist/components.d.ts +5 -5
- package/dist/components.js +5 -5
- package/dist/core/controller/AIController.d.ts +15 -0
- package/dist/core/controller/AIController.js +120 -0
- package/dist/{controller → core/controller}/ObjectController.d.ts +8 -0
- package/dist/{controller → core/controller}/SettingsController.d.ts +12 -4
- package/dist/{controller → core/controller}/SettingsController.js +0 -25
- package/dist/{controller → core/controller}/SharedContentController.d.ts +10 -19
- package/dist/{controller → core/controller}/SharedContentController.js +11 -11
- package/dist/core/core.d.ts +13 -0
- package/dist/core/core.js +8 -0
- package/dist/{plugin/fromRimori → fromRimori}/EventBus.d.ts +3 -3
- package/dist/{plugin/fromRimori → fromRimori}/EventBus.js +25 -8
- package/dist/fromRimori/PluginTypes.d.ts +171 -0
- package/dist/hooks/UseChatHook.d.ts +2 -1
- package/dist/hooks/UseChatHook.js +3 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +4 -3
- package/dist/plugin/AccomplishmentHandler.d.ts +1 -1
- package/dist/plugin/AccomplishmentHandler.js +1 -1
- package/dist/plugin/PluginController.d.ts +16 -3
- package/dist/plugin/PluginController.js +24 -18
- package/dist/plugin/RimoriClient.d.ts +22 -17
- package/dist/plugin/RimoriClient.js +35 -25
- package/dist/plugin/StandaloneClient.js +11 -8
- package/dist/plugin/ThemeSetter.d.ts +1 -0
- package/dist/plugin/ThemeSetter.js +9 -6
- package/dist/providers/PluginProvider.d.ts +3 -0
- package/dist/providers/PluginProvider.js +4 -4
- package/dist/utils/Language.d.ts +2 -1
- package/dist/utils/Language.js +4 -2
- package/dist/utils/difficultyConverter.js +1 -1
- package/dist/utils/endpoint.d.ts +2 -0
- package/dist/utils/endpoint.js +2 -0
- package/dist/worker/WorkerSetup.js +3 -1
- package/example/docs/devdocs.md +231 -0
- package/example/docs/overview.md +29 -0
- package/example/docs/userdocs.md +123 -0
- package/example/rimori.config.ts +89 -0
- package/example/worker/vite.config.ts +23 -0
- package/example/worker/worker.ts +11 -0
- package/package.json +15 -9
- package/src/cli/scripts/init/dev-registration.ts +193 -0
- package/src/cli/scripts/init/env-setup.ts +44 -0
- package/src/cli/scripts/init/file-operations.ts +58 -0
- package/src/cli/scripts/init/html-cleaner.ts +48 -0
- package/src/cli/scripts/init/main.ts +171 -0
- package/src/cli/scripts/init/package-setup.ts +117 -0
- package/src/cli/scripts/init/router-transformer.ts +329 -0
- package/src/cli/scripts/init/tailwind-config.ts +75 -0
- package/src/cli/scripts/init/vite-config.ts +73 -0
- package/src/cli/scripts/release/release-config-upload.ts +114 -0
- package/src/cli/scripts/release/release-db-update.ts +97 -0
- package/src/cli/scripts/release/release-file-upload.ts +138 -0
- package/src/cli/scripts/release/release.ts +69 -0
- package/src/cli/types/DatabaseTypes.ts +117 -0
- package/src/components/ai/Assistant.tsx +4 -4
- package/src/components/ai/Avatar.tsx +24 -7
- package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +1 -1
- package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +16 -8
- package/src/components/ai/utils.ts +0 -2
- package/src/components/audio/Playbutton.tsx +3 -3
- package/src/{core → components}/components/ContextMenu.tsx +3 -3
- package/src/components.ts +6 -6
- package/src/core/controller/AIController.ts +122 -0
- package/src/core/controller/ObjectController.ts +115 -0
- package/src/{controller → core/controller}/SettingsController.ts +13 -29
- package/src/{controller → core/controller}/SharedContentController.ts +18 -28
- package/src/core/core.ts +15 -0
- package/src/{plugin/fromRimori → fromRimori}/EventBus.ts +28 -10
- package/src/fromRimori/PluginTypes.ts +203 -0
- package/src/hooks/UseChatHook.ts +5 -4
- package/src/index.ts +5 -3
- package/src/plugin/AccomplishmentHandler.ts +1 -1
- package/src/plugin/PluginController.ts +35 -23
- package/src/plugin/RimoriClient.ts +48 -41
- package/src/plugin/StandaloneClient.ts +11 -8
- package/src/plugin/ThemeSetter.ts +12 -8
- package/src/providers/PluginProvider.tsx +7 -4
- package/src/utils/Language.ts +4 -2
- package/src/utils/difficultyConverter.ts +3 -3
- package/src/utils/endpoint.ts +2 -0
- package/src/worker/WorkerSetup.ts +4 -2
- package/dist/components/PluginController.d.ts +0 -21
- package/dist/components/PluginController.js +0 -116
- package/dist/controller/AIController.d.ts +0 -23
- package/dist/controller/AIController.js +0 -93
- package/dist/controller/SidePluginController.d.ts +0 -3
- package/dist/controller/SidePluginController.js +0 -31
- package/dist/core.d.ts +0 -7
- package/dist/core.js +0 -7
- package/dist/plugin/ContextMenu.d.ts +0 -17
- package/dist/plugin/ContextMenu.js +0 -45
- package/dist/plugin/fromRimori/PluginTypes.d.ts +0 -48
- package/dist/plugin/fromRimori/SupabaseHandler.d.ts +0 -13
- package/dist/plugin/fromRimori/SupabaseHandler.js +0 -55
- package/dist/providers/PluginController.d.ts +0 -21
- package/dist/providers/PluginController.js +0 -116
- package/dist/types/Actions.d.ts +0 -4
- package/dist/types/Actions.js +0 -1
- package/src/controller/AIController.ts +0 -112
- package/src/controller/ObjectController.ts +0 -107
- package/src/controller/SidePluginController.ts +0 -25
- package/src/core.ts +0 -8
- package/src/plugin/fromRimori/PluginTypes.ts +0 -64
- package/src/types/Actions.ts +0 -6
- /package/dist/{core → components}/components/ContextMenu.d.ts +0 -0
- /package/dist/{controller → core/controller}/ObjectController.js +0 -0
- /package/dist/{controller → core/controller}/VoiceController.d.ts +0 -0
- /package/dist/{controller → core/controller}/VoiceController.js +0 -0
- /package/dist/{plugin/fromRimori → fromRimori}/PluginTypes.js +0 -0
- /package/src/{controller → core/controller}/VoiceController.ts +0 -0
- /package/src/{plugin/fromRimori → fromRimori}/readme.md +0 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Interface representing a detected route component
|
|
6
|
+
*/
|
|
7
|
+
interface RouteComponent {
|
|
8
|
+
/** Component name as used in JSX */
|
|
9
|
+
componentName: string;
|
|
10
|
+
/** Original import statement */
|
|
11
|
+
importStatement: string;
|
|
12
|
+
/** Import path */
|
|
13
|
+
importPath: string;
|
|
14
|
+
/** Whether it's a default import */
|
|
15
|
+
isDefaultImport: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Transform App.tsx to use PluginProvider with HashRouter instead of BrowserRouter.
|
|
20
|
+
* Also converts route components to lazy loading with Suspense.
|
|
21
|
+
* @param pluginId - The plugin ID to use in PluginProvider
|
|
22
|
+
*/
|
|
23
|
+
export function transformAppRouter(pluginId: string): void {
|
|
24
|
+
const appTsxPath = path.resolve('./src/App.tsx');
|
|
25
|
+
|
|
26
|
+
if (!fs.existsSync(appTsxPath)) {
|
|
27
|
+
console.warn('Warning: App.tsx not found, skipping router transformation');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let content = fs.readFileSync(appTsxPath, 'utf8');
|
|
32
|
+
|
|
33
|
+
// Check if PluginProvider is already applied
|
|
34
|
+
if (content.includes('PluginProvider')) {
|
|
35
|
+
console.log('✅ PluginProvider already applied, skipping router transformation');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check if BrowserRouter exists
|
|
40
|
+
if (!content.includes('BrowserRouter')) {
|
|
41
|
+
console.log('✅ BrowserRouter not found, skipping router transformation');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log('🔄 Transforming App.tsx to use PluginProvider with HashRouter...');
|
|
46
|
+
|
|
47
|
+
// Step 1: Detect and extract route components
|
|
48
|
+
const routeComponents = detectRouteComponents(content);
|
|
49
|
+
|
|
50
|
+
if (routeComponents.length > 0) {
|
|
51
|
+
console.log(`🔄 Found ${routeComponents.length} route components, converting to lazy loading...`);
|
|
52
|
+
|
|
53
|
+
// Step 2: Transform imports to lazy loading
|
|
54
|
+
content = transformToLazyImports(content, routeComponents);
|
|
55
|
+
|
|
56
|
+
// Step 3: Add Suspense wrapper around Routes
|
|
57
|
+
content = addSuspenseWrapper(content);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Step 4: Transform router imports and JSX (existing functionality)
|
|
61
|
+
content = transformImports(content);
|
|
62
|
+
content = transformJSX(content, pluginId);
|
|
63
|
+
|
|
64
|
+
// Write the transformed content back
|
|
65
|
+
fs.writeFileSync(appTsxPath, content, 'utf8');
|
|
66
|
+
console.log('✅ App.tsx transformed successfully with lazy loading');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Detects route components in the JSX by parsing Route elements.
|
|
71
|
+
* Looks for patterns like: <Route path="/" element={<ComponentName />} />
|
|
72
|
+
* @param content - The file content to analyze
|
|
73
|
+
* @returns Array of detected route components with their import information
|
|
74
|
+
*/
|
|
75
|
+
function detectRouteComponents(content: string): RouteComponent[] {
|
|
76
|
+
const routeComponents: RouteComponent[] = [];
|
|
77
|
+
|
|
78
|
+
// Regex to match Route elements with component references
|
|
79
|
+
// Matches: <Route ... element={<ComponentName .../>} ... />
|
|
80
|
+
const routeRegex = /<Route[^>]*element=\{\s*<(\w+)[^}]*\}[^>]*\/?>/g;
|
|
81
|
+
|
|
82
|
+
let match;
|
|
83
|
+
const componentNames = new Set<string>();
|
|
84
|
+
|
|
85
|
+
// Extract all unique component names from routes
|
|
86
|
+
while ((match = routeRegex.exec(content)) !== null) {
|
|
87
|
+
const componentName = match[1];
|
|
88
|
+
componentNames.add(componentName);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// For each component, find its corresponding import statement
|
|
92
|
+
componentNames.forEach(componentName => {
|
|
93
|
+
const importInfo = findImportForComponent(content, componentName);
|
|
94
|
+
if (importInfo) {
|
|
95
|
+
routeComponents.push({
|
|
96
|
+
componentName,
|
|
97
|
+
importStatement: importInfo.importStatement,
|
|
98
|
+
importPath: importInfo.importPath,
|
|
99
|
+
isDefaultImport: importInfo.isDefaultImport
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return routeComponents;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Finds the import statement for a given component name.
|
|
109
|
+
* Handles both default imports and named imports.
|
|
110
|
+
* @param content - The file content to search
|
|
111
|
+
* @param componentName - The component name to find import for
|
|
112
|
+
* @returns Import information or null if not found
|
|
113
|
+
*/
|
|
114
|
+
function findImportForComponent(content: string, componentName: string): {
|
|
115
|
+
importStatement: string;
|
|
116
|
+
importPath: string;
|
|
117
|
+
isDefaultImport: boolean;
|
|
118
|
+
} | null {
|
|
119
|
+
// Check for default import: import ComponentName from "path"
|
|
120
|
+
const defaultImportRegex = new RegExp(`import\\s+${componentName}\\s+from\\s+["']([^"']+)["'];?`, 'g');
|
|
121
|
+
const defaultMatch = defaultImportRegex.exec(content);
|
|
122
|
+
|
|
123
|
+
if (defaultMatch) {
|
|
124
|
+
return {
|
|
125
|
+
importStatement: defaultMatch[0],
|
|
126
|
+
importPath: defaultMatch[1],
|
|
127
|
+
isDefaultImport: true
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Check for named import: import { ComponentName } from "path"
|
|
132
|
+
const namedImportRegex = /import\s*\{\s*([^}]*)\s*\}\s*from\s*["']([^"']+)["'];?/g;
|
|
133
|
+
let namedMatch;
|
|
134
|
+
|
|
135
|
+
while ((namedMatch = namedImportRegex.exec(content)) !== null) {
|
|
136
|
+
const imports = namedMatch[1].split(',').map(imp => imp.trim());
|
|
137
|
+
if (imports.includes(componentName)) {
|
|
138
|
+
return {
|
|
139
|
+
importStatement: namedMatch[0],
|
|
140
|
+
importPath: namedMatch[2],
|
|
141
|
+
isDefaultImport: false
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Transforms regular component imports to lazy imports.
|
|
151
|
+
* Converts: import ComponentName from "./path"
|
|
152
|
+
* To: const ComponentName = lazy(() => import("./path"))
|
|
153
|
+
* @param content - The file content to transform
|
|
154
|
+
* @param routeComponents - Array of route components to transform
|
|
155
|
+
* @returns Transformed content with lazy imports
|
|
156
|
+
*/
|
|
157
|
+
function transformToLazyImports(content: string, routeComponents: RouteComponent[]): string {
|
|
158
|
+
let transformedContent = content;
|
|
159
|
+
|
|
160
|
+
// Add lazy import if not already present
|
|
161
|
+
if (!content.includes('lazy')) {
|
|
162
|
+
transformedContent = addLazyImport(transformedContent);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Transform each route component import
|
|
166
|
+
routeComponents.forEach((component, index) => {
|
|
167
|
+
const { componentName, importStatement, importPath, isDefaultImport } = component;
|
|
168
|
+
|
|
169
|
+
// Create lazy import statement
|
|
170
|
+
const lazyImport = isDefaultImport
|
|
171
|
+
? `const ${componentName} = lazy(() => import("${importPath}"));`
|
|
172
|
+
: `const ${componentName} = lazy(() => import("${importPath}").then(module => ({ default: module.${componentName} })));`;
|
|
173
|
+
|
|
174
|
+
// Replace the original import with lazy import
|
|
175
|
+
transformedContent = transformedContent.replace(importStatement, (index === 0 ? '\n' : '') + lazyImport);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
return transformedContent;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Adds lazy import from React if not already present.
|
|
183
|
+
* @param content - The file content to modify
|
|
184
|
+
* @returns Content with lazy import added
|
|
185
|
+
*/
|
|
186
|
+
function addLazyImport(content: string): string {
|
|
187
|
+
// Check if React import exists and update it
|
|
188
|
+
const reactImportRegex = /import\s+(?:\*\s+as\s+)?React(?:\s*,\s*\{\s*([^}]*)\s*\})?\s+from\s+["']react["'];?/;
|
|
189
|
+
const reactImportMatch = content.match(reactImportRegex);
|
|
190
|
+
|
|
191
|
+
if (reactImportMatch) {
|
|
192
|
+
// React import exists, add lazy to it
|
|
193
|
+
const existingImports = reactImportMatch[1] || '';
|
|
194
|
+
const importList = existingImports.split(',').map(imp => imp.trim()).filter(Boolean);
|
|
195
|
+
|
|
196
|
+
if (!importList.includes('lazy')) {
|
|
197
|
+
importList.push('lazy');
|
|
198
|
+
}
|
|
199
|
+
if (!importList.includes('Suspense')) {
|
|
200
|
+
importList.push('Suspense');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const newImport = importList.length > 0
|
|
204
|
+
? `import React, { ${importList.join(', ')} } from "react";`
|
|
205
|
+
: `import React from "react";`;
|
|
206
|
+
|
|
207
|
+
return content.replace(reactImportMatch[0], newImport);
|
|
208
|
+
} else {
|
|
209
|
+
// No React import found, add it
|
|
210
|
+
const firstImportMatch = content.match(/^import.*$/m);
|
|
211
|
+
if (firstImportMatch) {
|
|
212
|
+
return content.replace(firstImportMatch[0], `import React, { lazy, Suspense } from "react";\n${firstImportMatch[0]}`);
|
|
213
|
+
} else {
|
|
214
|
+
// No imports found, add at the beginning
|
|
215
|
+
return `import React, { lazy, Suspense } from "react";\n${content}`;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Wraps the Routes component with Suspense for lazy loading fallback.
|
|
222
|
+
* Converts: <Routes>...</Routes>
|
|
223
|
+
* To: <Suspense fallback={<div>Loading...</div>}><Routes>...</Routes></Suspense>
|
|
224
|
+
* @param content - The file content to modify
|
|
225
|
+
* @returns Content with Suspense wrapper added
|
|
226
|
+
*/
|
|
227
|
+
function addSuspenseWrapper(content: string): string {
|
|
228
|
+
// Check if Suspense is already wrapping Routes
|
|
229
|
+
if (content.includes('<Suspense') && content.match(/<Suspense[^>]*>[\s\S]*<Routes/)) {
|
|
230
|
+
console.log('✅ Suspense wrapper already present');
|
|
231
|
+
return content;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Find Routes component and wrap with Suspense
|
|
235
|
+
// Handle both self-closing and regular Routes tags
|
|
236
|
+
const routesRegex = /(<Routes(?:[^>]*)>)([\s\S]*?)(<\/Routes>)/;
|
|
237
|
+
const selfClosingRoutesRegex = /(<Routes[^>]*\/>)/;
|
|
238
|
+
|
|
239
|
+
const routesMatch = content.match(routesRegex);
|
|
240
|
+
const selfClosingMatch = content.match(selfClosingRoutesRegex);
|
|
241
|
+
|
|
242
|
+
if (routesMatch) {
|
|
243
|
+
// Regular Routes with children
|
|
244
|
+
const [fullMatch, openTag, children, closeTag] = routesMatch;
|
|
245
|
+
const suspenseWrapper = `<Suspense fallback={<div className="flex items-center justify-center min-h-screen"><div className="text-lg">Loading...</div></div>}>\n ${openTag}${children}${closeTag}\n </Suspense>`;
|
|
246
|
+
return content.replace(fullMatch, suspenseWrapper);
|
|
247
|
+
} else if (selfClosingMatch) {
|
|
248
|
+
// Self-closing Routes
|
|
249
|
+
const suspenseWrapper = `<Suspense fallback={<div className="flex items-center justify-center min-h-screen"><div className="text-lg">Loading...</div></div>}>\n ${selfClosingMatch[1]}\n </Suspense>`;
|
|
250
|
+
return content.replace(selfClosingMatch[1], suspenseWrapper);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
console.log('✅ Routes component not found, skipping Suspense wrapper');
|
|
254
|
+
return content;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Transform the import statements to include PluginProvider and change BrowserRouter to HashRouter.
|
|
259
|
+
* This is the original functionality for router transformation.
|
|
260
|
+
* @param content - The file content to transform
|
|
261
|
+
* @returns Transformed content with updated imports
|
|
262
|
+
*/
|
|
263
|
+
function transformImports(content: string): string {
|
|
264
|
+
// Add PluginProvider import
|
|
265
|
+
if (!content.includes('import') || !content.includes('@rimori/client')) {
|
|
266
|
+
// Add new import line for PluginProvider
|
|
267
|
+
const importMatch = content.match(/^(import.*from\s+["']react["'];?\s*\n)/m);
|
|
268
|
+
if (importMatch) {
|
|
269
|
+
content = content.replace(
|
|
270
|
+
importMatch[0],
|
|
271
|
+
`${importMatch[0]}import { PluginProvider } from "@rimori/client";\n`
|
|
272
|
+
);
|
|
273
|
+
} else {
|
|
274
|
+
// If no React import found, add at the beginning
|
|
275
|
+
content = `import { PluginProvider } from "@rimori/client";\n${content}`;
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
// Update existing @rimori/client import to include PluginProvider
|
|
279
|
+
content = content.replace(
|
|
280
|
+
/import\s*{\s*([^}]*)\s*}\s*from\s*["']@rimori\/client["'];?/,
|
|
281
|
+
(match, imports) => {
|
|
282
|
+
const importList = imports.split(',').map((imp: string) => imp.trim()).filter(Boolean);
|
|
283
|
+
if (!importList.includes('PluginProvider')) {
|
|
284
|
+
importList.push('PluginProvider');
|
|
285
|
+
}
|
|
286
|
+
return `import { ${importList.join(', ')} } from "@rimori/client";`;
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Transform react-router-dom import: replace BrowserRouter with HashRouter
|
|
292
|
+
content = content.replace(
|
|
293
|
+
/import\s*{\s*([^}]*)\s*}\s*from\s*["']react-router-dom["'];?/,
|
|
294
|
+
(match, imports) => {
|
|
295
|
+
const importList = imports.split(',').map((imp: string) => imp.trim()).filter(Boolean);
|
|
296
|
+
const updatedImports = importList.map((imp: string) =>
|
|
297
|
+
imp === 'BrowserRouter' ? 'HashRouter' : imp
|
|
298
|
+
);
|
|
299
|
+
return `import { ${updatedImports.join(', ')} } from "react-router-dom";`;
|
|
300
|
+
}
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
return content;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Transform the JSX to wrap with PluginProvider and change BrowserRouter to HashRouter.
|
|
308
|
+
* This is the original functionality for router transformation.
|
|
309
|
+
* @param content - The file content to transform
|
|
310
|
+
* @param pluginId - The plugin ID to use in PluginProvider
|
|
311
|
+
* @returns Transformed content with updated JSX
|
|
312
|
+
*/
|
|
313
|
+
function transformJSX(content: string, pluginId: string): string {
|
|
314
|
+
// Replace opening BrowserRouter tag
|
|
315
|
+
content = content.replace(
|
|
316
|
+
/<BrowserRouter(\s[^>]*)?>/,
|
|
317
|
+
`<PluginProvider pluginId="${pluginId}">
|
|
318
|
+
<HashRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>`
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
// Replace closing BrowserRouter tag
|
|
322
|
+
content = content.replace(
|
|
323
|
+
/<\/BrowserRouter>/,
|
|
324
|
+
`</HashRouter>
|
|
325
|
+
</PluginProvider>`
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
return content;
|
|
329
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Updates the tailwind.config.ts file to set darkMode to "class" and add the Rimori client package to content.
|
|
6
|
+
*/
|
|
7
|
+
export function updateTailwindConfig(): void {
|
|
8
|
+
console.log('Updating Tailwind CSS configuration...');
|
|
9
|
+
|
|
10
|
+
const tailwindConfigPath = path.resolve('./tailwind.config.ts');
|
|
11
|
+
|
|
12
|
+
if (!fs.existsSync(tailwindConfigPath)) {
|
|
13
|
+
console.log('Warning: tailwind.config.ts not found, skipping Tailwind CSS update');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const configContent = fs.readFileSync(tailwindConfigPath, 'utf8');
|
|
19
|
+
|
|
20
|
+
let updatedContent = configContent;
|
|
21
|
+
|
|
22
|
+
// Set darkMode to "class" if it exists, otherwise add it
|
|
23
|
+
if (updatedContent.includes('darkMode:')) {
|
|
24
|
+
updatedContent = updatedContent.replace(
|
|
25
|
+
/darkMode:\s*\[?"[^"]*"?\]?,?/g,
|
|
26
|
+
'darkMode: ["class"],'
|
|
27
|
+
);
|
|
28
|
+
} else {
|
|
29
|
+
// Add darkMode after the opening brace
|
|
30
|
+
updatedContent = updatedContent.replace(
|
|
31
|
+
/export default \{/,
|
|
32
|
+
'export default {\n darkMode: ["class"],'
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Add Rimori client package to content array if not already present
|
|
37
|
+
if (!updatedContent.includes('node_modules/@rimori/client')) {
|
|
38
|
+
// Find the content array and add the Rimori client path
|
|
39
|
+
if (updatedContent.includes('content:')) {
|
|
40
|
+
// More precise regex to handle the content array properly
|
|
41
|
+
updatedContent = updatedContent.replace(
|
|
42
|
+
/(content:\s*\[)([\s\S]*?)(\])/,
|
|
43
|
+
(match, start, content, end) => {
|
|
44
|
+
// Clean up any existing double commas first
|
|
45
|
+
let cleanContent = content.replace(/,\s*,/g, ',');
|
|
46
|
+
|
|
47
|
+
// Remove trailing comma and whitespace
|
|
48
|
+
cleanContent = cleanContent.replace(/,\s*$/, '');
|
|
49
|
+
|
|
50
|
+
// Add the new path with proper formatting
|
|
51
|
+
const newPath = '"node_modules/@rimori/client/dist/components/**/*.{js,jsx}"';
|
|
52
|
+
|
|
53
|
+
// If content is not empty, add comma before new entry
|
|
54
|
+
if (cleanContent.trim()) {
|
|
55
|
+
return `${start}${cleanContent},\n ${newPath}\n ${end}`;
|
|
56
|
+
} else {
|
|
57
|
+
return `${start}\n ${newPath}\n ${end}`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
} else {
|
|
62
|
+
// Add content array if it doesn't exist
|
|
63
|
+
updatedContent = updatedContent.replace(
|
|
64
|
+
/darkMode: \["class"\],/,
|
|
65
|
+
'darkMode: ["class"],\n content: [\n "./src/**/*.{js,jsx,ts,tsx}",\n "node_modules/@rimori/client/dist/components/**/*.{js,jsx}"\n ],'
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fs.writeFileSync(tailwindConfigPath, updatedContent, 'utf8');
|
|
71
|
+
console.log('✅ Tailwind CSS configuration updated');
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.warn(`Warning: Could not update tailwind.config.ts: ${error instanceof Error ? error.message : error}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Updates the vite.config.ts file to set the base property.
|
|
6
|
+
* @param param
|
|
7
|
+
* @param param.basePath - The base path to set in vite config (defaults to './')
|
|
8
|
+
* @param param.configPath - Path to the vite.config.ts file (defaults to './vite.config.ts')
|
|
9
|
+
* @throws {Error} if vite.config.ts file is not found or cannot be modified.
|
|
10
|
+
*/
|
|
11
|
+
export function updateViteConfigBase({
|
|
12
|
+
basePath = './',
|
|
13
|
+
configPath = './vite.config.ts'
|
|
14
|
+
}: {
|
|
15
|
+
basePath?: string;
|
|
16
|
+
configPath?: string;
|
|
17
|
+
} = {}): void {
|
|
18
|
+
const viteConfigPath = path.resolve(configPath);
|
|
19
|
+
|
|
20
|
+
if (!fs.existsSync(viteConfigPath)) {
|
|
21
|
+
throw new Error(`vite.config.ts not found at ${viteConfigPath}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let configContent = fs.readFileSync(viteConfigPath, 'utf8');
|
|
25
|
+
|
|
26
|
+
// Check if base property already exists
|
|
27
|
+
const baseRegex = /base:\s*['"][^'"]*['"],?\s*/;
|
|
28
|
+
const hasBase = baseRegex.test(configContent);
|
|
29
|
+
|
|
30
|
+
if (hasBase) {
|
|
31
|
+
// Update existing base property
|
|
32
|
+
configContent = configContent.replace(baseRegex, `base: '${basePath}',`);
|
|
33
|
+
console.log(`Updated existing base property in vite.config.ts to '${basePath}'`);
|
|
34
|
+
} else {
|
|
35
|
+
// Add base property before server config
|
|
36
|
+
const serverRegex = /(\s*)(server:\s*\{)/;
|
|
37
|
+
const serverMatch = configContent.match(serverRegex);
|
|
38
|
+
|
|
39
|
+
if (serverMatch) {
|
|
40
|
+
const indentation = serverMatch[1] || ' '; // Use existing indentation or default to 2 spaces
|
|
41
|
+
const replacement = `${indentation}base: '${basePath}',${indentation}${serverMatch[2]}`;
|
|
42
|
+
configContent = configContent.replace(serverRegex, replacement);
|
|
43
|
+
console.log(`Added base property to vite.config.ts with value '${basePath}'`);
|
|
44
|
+
} else {
|
|
45
|
+
throw new Error('Could not find server config in vite.config.ts to add base property before it');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fs.writeFileSync(viteConfigPath, configContent, 'utf8');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Reads the current base value from vite.config.ts.
|
|
54
|
+
* @param param
|
|
55
|
+
* @param param.configPath - Path to the vite.config.ts file (defaults to './vite.config.ts')
|
|
56
|
+
* @returns The current base value or null if not found.
|
|
57
|
+
*/
|
|
58
|
+
export function getCurrentViteBase({
|
|
59
|
+
configPath = './vite.config.ts'
|
|
60
|
+
}: {
|
|
61
|
+
configPath?: string;
|
|
62
|
+
} = {}): string | null {
|
|
63
|
+
const viteConfigPath = path.resolve(configPath);
|
|
64
|
+
|
|
65
|
+
if (!fs.existsSync(viteConfigPath)) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const configContent = fs.readFileSync(viteConfigPath, 'utf8');
|
|
70
|
+
const baseMatch = configContent.match(/base:\s*['"]([^'"]*)['"]/);
|
|
71
|
+
|
|
72
|
+
return baseMatch ? baseMatch[1] : null;
|
|
73
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import ts from 'typescript';
|
|
4
|
+
import { Config } from './release.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Read and send the rimori configuration to the release endpoint
|
|
8
|
+
* @param config - Configuration object
|
|
9
|
+
*/
|
|
10
|
+
export async function sendConfiguration(config: Config): Promise<string> {
|
|
11
|
+
const configPath = path.resolve('./rimori/rimori.config.ts');
|
|
12
|
+
|
|
13
|
+
// Check if config file exists
|
|
14
|
+
try {
|
|
15
|
+
await fs.promises.access(configPath);
|
|
16
|
+
} catch (e) {
|
|
17
|
+
throw new Error('Could not find rimori.config.ts in ./rimori/ directory');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
let configObject;
|
|
22
|
+
|
|
23
|
+
// Use TypeScript compiler to transpile and load
|
|
24
|
+
const configContent = await fs.promises.readFile(configPath, 'utf8');
|
|
25
|
+
|
|
26
|
+
// Transpile TypeScript to JavaScript
|
|
27
|
+
const result = ts.transpile(configContent, {
|
|
28
|
+
target: ts.ScriptTarget.ES2020,
|
|
29
|
+
module: ts.ModuleKind.ES2020
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Create a temporary file to import the transpiled code
|
|
33
|
+
const tempFile = path.join(process.cwd(), 'temp_config.js');
|
|
34
|
+
await fs.promises.writeFile(tempFile, result);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
// Use dynamic import to load the config
|
|
38
|
+
const config = await import(`file://${tempFile}`);
|
|
39
|
+
configObject = config.default || config;
|
|
40
|
+
|
|
41
|
+
// Clean up temp file
|
|
42
|
+
await fs.promises.unlink(tempFile);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
// Clean up temp file even on error
|
|
45
|
+
try {
|
|
46
|
+
await fs.promises.unlink(tempFile);
|
|
47
|
+
} catch (e) { }
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!configObject) {
|
|
52
|
+
throw new Error('Configuration object is empty or undefined');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log(`🚀 Sending configuration...`);
|
|
56
|
+
|
|
57
|
+
const requestBody = {
|
|
58
|
+
config: configObject,
|
|
59
|
+
version: config.version,
|
|
60
|
+
plugin_id: config.plugin_id,
|
|
61
|
+
release_channel: config.release_channel,
|
|
62
|
+
rimori_client_version: config.rimori_client_version,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const response = await fetch(`${config.domain}/release`, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: {
|
|
69
|
+
'Content-Type': 'application/json',
|
|
70
|
+
'Authorization': `Bearer ${config.token}`
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify(requestBody),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const responseText = await response.text();
|
|
76
|
+
console.log('Configuration response status:', response.status);
|
|
77
|
+
console.log('Configuration response text:', responseText);
|
|
78
|
+
|
|
79
|
+
const responseData = JSON.parse(responseText);
|
|
80
|
+
if (response.ok) {
|
|
81
|
+
console.log('✅ Configuration deployed successfully!');
|
|
82
|
+
return responseData.release_id;
|
|
83
|
+
} else {
|
|
84
|
+
console.log('❌ Configuration failed!');
|
|
85
|
+
console.log('Error:', responseData.error || 'Unknown error');
|
|
86
|
+
console.log('Response data:', JSON.stringify(responseData, null, 2));
|
|
87
|
+
throw new Error('Configuration upload failed');
|
|
88
|
+
}
|
|
89
|
+
} catch (e) {
|
|
90
|
+
console.log("error", e);
|
|
91
|
+
throw new Error("Error sending configuration");
|
|
92
|
+
}
|
|
93
|
+
} catch (error: any) {
|
|
94
|
+
console.error('❌ Error sending configuration:', error.message);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function releasePlugin(config: Config, release_id: string): Promise<void> {
|
|
100
|
+
const response = await fetch(`${config.domain}/release/${release_id}/release`, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers: {
|
|
103
|
+
'Content-Type': 'application/json',
|
|
104
|
+
'Authorization': `Bearer ${config.token}`
|
|
105
|
+
},
|
|
106
|
+
body: JSON.stringify({ plugin_id: config.plugin_id })
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
console.log("Response:", await response.text());
|
|
111
|
+
throw new Error("Failed to release plugin");
|
|
112
|
+
}
|
|
113
|
+
console.log("✅ Plugin released successfully");
|
|
114
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import ts from 'typescript';
|
|
4
|
+
import { Config } from "./release";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Read and send the database configuration to the release endpoint
|
|
8
|
+
* @param config - Configuration object
|
|
9
|
+
*/
|
|
10
|
+
export default async function dbUpdate(config: Config, release_id: string): Promise<void> {
|
|
11
|
+
const dbConfigPath = path.resolve('./rimori/db.config.ts');
|
|
12
|
+
|
|
13
|
+
// Check if db config file exists
|
|
14
|
+
try {
|
|
15
|
+
await fs.promises.access(dbConfigPath);
|
|
16
|
+
} catch (e) {
|
|
17
|
+
console.warn('Could not find db.config.ts in ./rimori/ directory. Skipping database configuration upload.');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
let dbConfigObject;
|
|
23
|
+
|
|
24
|
+
// Use TypeScript compiler to transpile and load
|
|
25
|
+
const dbConfigContent = await fs.promises.readFile(dbConfigPath, 'utf8');
|
|
26
|
+
|
|
27
|
+
// Transpile TypeScript to JavaScript
|
|
28
|
+
const result = ts.transpile(dbConfigContent, {
|
|
29
|
+
target: ts.ScriptTarget.ES2020,
|
|
30
|
+
module: ts.ModuleKind.ES2020
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Create a temporary file to import the transpiled code
|
|
34
|
+
const tempFile = path.join(process.cwd(), 'temp_db_config.js');
|
|
35
|
+
await fs.promises.writeFile(tempFile, result);
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
// Use dynamic import to load the db config
|
|
39
|
+
const dbConfig = await import(`file://${tempFile}`);
|
|
40
|
+
dbConfigObject = Object.values(dbConfig);
|
|
41
|
+
|
|
42
|
+
// Clean up temp file
|
|
43
|
+
await fs.promises.unlink(tempFile);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
// Clean up temp file even on error
|
|
46
|
+
try {
|
|
47
|
+
await fs.promises.unlink(tempFile);
|
|
48
|
+
} catch (e) { }
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!dbConfigObject) {
|
|
53
|
+
throw new Error('Database configuration object is empty or undefined');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log(`🗄️ Sending database configuration...`);
|
|
57
|
+
|
|
58
|
+
const requestBody = {
|
|
59
|
+
db_config: dbConfigObject,
|
|
60
|
+
version: config.version,
|
|
61
|
+
release_channel: config.release_channel,
|
|
62
|
+
plugin_id: config.plugin_id,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const response = await fetch(`${config.domain}/release/${release_id}/db`, {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
headers: {
|
|
68
|
+
'Content-Type': 'application/json',
|
|
69
|
+
'Authorization': `Bearer ${config.token}`
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify(requestBody),
|
|
72
|
+
}).catch((e) => {
|
|
73
|
+
console.log("error", e);
|
|
74
|
+
throw new Error("Error sending database configuration");
|
|
75
|
+
});
|
|
76
|
+
try {
|
|
77
|
+
const responseText = await response.text().catch((e) => {
|
|
78
|
+
console.log("error", e);
|
|
79
|
+
throw new Error("Error sending database configuration");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const responseData = JSON.parse(responseText);
|
|
83
|
+
if (response.ok) {
|
|
84
|
+
console.log('✅ Database configuration deployed successfully!');
|
|
85
|
+
} else {
|
|
86
|
+
console.log("responseData", responseData);
|
|
87
|
+
throw new Error(responseData.message);
|
|
88
|
+
}
|
|
89
|
+
} catch (e) {
|
|
90
|
+
console.log("error", e);
|
|
91
|
+
throw new Error("Error sending database configuration");
|
|
92
|
+
}
|
|
93
|
+
} catch (error: any) {
|
|
94
|
+
console.error('❌ Error sending database configuration:', error.message);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|