@rimori/client 2.4.0 → 2.5.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/scripts/init/dev-registration.js +4 -2
- package/dist/cli/scripts/init/main.js +1 -0
- package/dist/cli/scripts/release/release.js +0 -0
- package/dist/controller/SettingsController.d.ts +1 -1
- package/dist/controller/SharedContentController.d.ts +1 -1
- package/dist/fromRimori/EventBus.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/plugin/CommunicationHandler.d.ts +13 -8
- package/dist/plugin/CommunicationHandler.js +44 -59
- package/dist/plugin/RimoriClient.d.ts +11 -195
- package/dist/plugin/RimoriClient.js +16 -298
- package/dist/plugin/StandaloneClient.d.ts +1 -1
- package/dist/plugin/StandaloneClient.js +3 -2
- package/dist/plugin/module/AIModule.d.ts +49 -0
- package/dist/plugin/module/AIModule.js +81 -0
- package/dist/plugin/module/DbModule.d.ts +30 -0
- package/dist/plugin/module/DbModule.js +51 -0
- package/dist/plugin/module/EventModule.d.ts +99 -0
- package/dist/plugin/module/EventModule.js +162 -0
- package/dist/{controller/ExerciseController.d.ts → plugin/module/ExerciseModule.d.ts} +20 -16
- package/dist/{controller/ExerciseController.js → plugin/module/ExerciseModule.js} +27 -20
- package/dist/plugin/module/PluginModule.d.ts +76 -0
- package/dist/plugin/module/PluginModule.js +88 -0
- package/package.json +8 -3
- package/.github/workflows/pre-release.yml +0 -126
- package/.prettierignore +0 -35
- package/eslint.config.js +0 -53
- package/example/docs/devdocs.md +0 -241
- package/example/docs/overview.md +0 -29
- package/example/docs/userdocs.md +0 -126
- package/example/rimori.config.ts +0 -91
- package/example/worker/vite.config.ts +0 -26
- package/example/worker/worker.ts +0 -11
- package/prettier.config.js +0 -8
- package/src/cli/scripts/init/dev-registration.ts +0 -189
- package/src/cli/scripts/init/env-setup.ts +0 -44
- package/src/cli/scripts/init/file-operations.ts +0 -58
- package/src/cli/scripts/init/html-cleaner.ts +0 -45
- package/src/cli/scripts/init/main.ts +0 -175
- package/src/cli/scripts/init/package-setup.ts +0 -113
- package/src/cli/scripts/init/router-transformer.ts +0 -332
- package/src/cli/scripts/init/tailwind-config.ts +0 -66
- package/src/cli/scripts/init/vite-config.ts +0 -73
- package/src/cli/scripts/release/detect-translation-languages.ts +0 -37
- package/src/cli/scripts/release/release-config-upload.ts +0 -119
- package/src/cli/scripts/release/release-db-update.ts +0 -97
- package/src/cli/scripts/release/release-file-upload.ts +0 -138
- package/src/cli/scripts/release/release.ts +0 -85
- package/src/cli/types/DatabaseTypes.ts +0 -125
- package/src/controller/AIController.ts +0 -295
- package/src/controller/AccomplishmentController.ts +0 -188
- package/src/controller/AudioController.ts +0 -64
- package/src/controller/ExerciseController.ts +0 -117
- package/src/controller/ObjectController.ts +0 -120
- package/src/controller/SettingsController.ts +0 -186
- package/src/controller/SharedContentController.ts +0 -365
- package/src/controller/TranslationController.ts +0 -136
- package/src/controller/VoiceController.ts +0 -33
- package/src/fromRimori/EventBus.ts +0 -382
- package/src/fromRimori/PluginTypes.ts +0 -214
- package/src/fromRimori/readme.md +0 -2
- package/src/index.ts +0 -19
- package/src/plugin/CommunicationHandler.ts +0 -310
- package/src/plugin/Logger.ts +0 -394
- package/src/plugin/RimoriClient.ts +0 -530
- package/src/plugin/StandaloneClient.ts +0 -125
- package/src/utils/difficultyConverter.ts +0 -15
- package/src/utils/endpoint.ts +0 -3
- package/src/worker/WorkerSetup.ts +0 -35
- package/tsconfig.json +0 -17
package/example/rimori.config.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { RimoriPluginConfig } from '@rimori/client';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* This is an example of a Rimori plugin configuration file. It is based on the Rimori Flashcards plugin.
|
|
5
|
-
* It is used to configure the plugin and its pages, sidebar, settings, context menu actions, documentation, and worker.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const config: RimoriPluginConfig = {
|
|
9
|
-
id: 'pl1234567890', // This is the plugin id. You can find it in the plugin's package.json file.
|
|
10
|
-
info: {
|
|
11
|
-
title: 'Flashcards',
|
|
12
|
-
description:
|
|
13
|
-
"The Rimori Flashcards Plugin is a powerful tool for learning and memorization using spaced repetition. It helps you efficiently review information, whether you're learning a language, preparing for exams, or mastering new skills. The plugin uses advanced algorithms to schedule your reviews at optimal intervals, maximizing retention while minimizing study time.",
|
|
14
|
-
logo: 'logo.png',
|
|
15
|
-
website: 'https://rimori.se',
|
|
16
|
-
},
|
|
17
|
-
pages: {
|
|
18
|
-
main: [
|
|
19
|
-
{
|
|
20
|
-
id: '1',
|
|
21
|
-
url: '#/',
|
|
22
|
-
show: true,
|
|
23
|
-
name: 'Flashcards',
|
|
24
|
-
root: 'vocabulary',
|
|
25
|
-
description: 'Quickly memorizing info by using flashcards.',
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
// This is a page that is not shown in the navbar. It is used to trigger the flashcards action.
|
|
29
|
-
id: '2',
|
|
30
|
-
url: '#/deck/custom',
|
|
31
|
-
show: false,
|
|
32
|
-
root: 'vocabulary',
|
|
33
|
-
name: 'Latest flashcard deck training',
|
|
34
|
-
description: 'Training the latest flashcards.',
|
|
35
|
-
action: {
|
|
36
|
-
key: 'flashcards',
|
|
37
|
-
parameters: {
|
|
38
|
-
total_amount: {
|
|
39
|
-
type: 'number',
|
|
40
|
-
description: 'Number of flashcards to practice. Default is 70 (10 new + 20 reviewed + 40 forgotten).',
|
|
41
|
-
},
|
|
42
|
-
deck: {
|
|
43
|
-
type: 'string',
|
|
44
|
-
enum: ['latest', 'random', 'oldest', 'mix', 'best_known'],
|
|
45
|
-
description: 'Type of deck to practice from',
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
sidebar: [
|
|
52
|
-
{
|
|
53
|
-
id: 'translate',
|
|
54
|
-
url: '#/sidebar/translate',
|
|
55
|
-
name: 'Translate',
|
|
56
|
-
icon: 'translate.png',
|
|
57
|
-
description: 'Translate words.',
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
id: 'flashcard_quick_add',
|
|
61
|
-
url: '#/sidebar/add',
|
|
62
|
-
name: 'Quick add',
|
|
63
|
-
icon: 'logo.png',
|
|
64
|
-
description: 'Quickly add a word to your flashcards.',
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
settings: '/settings',
|
|
68
|
-
},
|
|
69
|
-
context_menu_actions: [
|
|
70
|
-
{
|
|
71
|
-
text: 'Translate',
|
|
72
|
-
plugin_id: 'pl1234567890',
|
|
73
|
-
action_key: 'translate',
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
text: 'Quick add',
|
|
77
|
-
plugin_id: 'pl1234567890',
|
|
78
|
-
action_key: 'flashcard_quick_add',
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
documentation: {
|
|
82
|
-
overview_path: 'docs/overview.md',
|
|
83
|
-
user_path: 'docs/userdocs.md',
|
|
84
|
-
developer_path: 'docs/devdocs.md',
|
|
85
|
-
},
|
|
86
|
-
worker: {
|
|
87
|
-
url: 'web-worker.js',
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export default config;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vite';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
root: __dirname,
|
|
6
|
-
build: {
|
|
7
|
-
minify: process.env.VITE_MINIFY === 'true',
|
|
8
|
-
lib: {
|
|
9
|
-
entry: 'worker.ts',
|
|
10
|
-
formats: ['iife'],
|
|
11
|
-
name: 'PluginFooWorker',
|
|
12
|
-
fileName: () => 'web-worker.js', // used in rollupOptions.entryFileNames
|
|
13
|
-
},
|
|
14
|
-
outDir: path.resolve(__dirname, '../public'),
|
|
15
|
-
emptyOutDir: false,
|
|
16
|
-
rollupOptions: {
|
|
17
|
-
// Exclude DOM-only libraries that can't run in workers
|
|
18
|
-
// html2canvas is provided by @rimori/react-client for browser contexts
|
|
19
|
-
external: ['html2canvas'],
|
|
20
|
-
output: {
|
|
21
|
-
inlineDynamicImports: true,
|
|
22
|
-
entryFileNames: 'web-worker.js',
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
});
|
package/example/worker/worker.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { setupWorker, RimoriClient } from '@rimori/client/core';
|
|
2
|
-
|
|
3
|
-
setupWorker(async (client: RimoriClient) => {
|
|
4
|
-
console.log('[Worker] initialized');
|
|
5
|
-
|
|
6
|
-
// listening to events for this plugin to create flashcards
|
|
7
|
-
client.event.respond<{ front: string; back: string }>('flashcards.create', ({ data }) => {
|
|
8
|
-
console.log('[Worker] creating flashcards in database', data);
|
|
9
|
-
return { success: true };
|
|
10
|
-
});
|
|
11
|
-
});
|
package/prettier.config.js
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import { createClient } from '@supabase/supabase-js';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import * as readline from 'readline';
|
|
4
|
-
import { DEFAULT_ANON_KEY, DEFAULT_ENDPOINT } from '../../../utils/endpoint.js';
|
|
5
|
-
|
|
6
|
-
export interface UserCredentials {
|
|
7
|
-
email: string;
|
|
8
|
-
password: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface DeveloperRegisterResponse {
|
|
12
|
-
plugin_id: string;
|
|
13
|
-
access_token: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Prompts user for email and password credentials.
|
|
18
|
-
* @returns Promise resolving to user credentials.
|
|
19
|
-
*/
|
|
20
|
-
export async function askForCredentials(): Promise<UserCredentials> {
|
|
21
|
-
const rl = readline.createInterface({
|
|
22
|
-
input: process.stdin,
|
|
23
|
-
output: process.stdout,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
return new Promise((resolve) => {
|
|
27
|
-
rl.question('Enter your email: ', (email) => {
|
|
28
|
-
rl.close();
|
|
29
|
-
|
|
30
|
-
// Create a new interface for password input with muted output
|
|
31
|
-
const passwordRl = readline.createInterface({
|
|
32
|
-
input: process.stdin,
|
|
33
|
-
output: process.stdout,
|
|
34
|
-
terminal: false,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
process.stdout.write('Enter your password: ');
|
|
38
|
-
|
|
39
|
-
// Set up stdin for raw input
|
|
40
|
-
process.stdin.setRawMode(true);
|
|
41
|
-
process.stdin.resume();
|
|
42
|
-
|
|
43
|
-
let password = '';
|
|
44
|
-
|
|
45
|
-
const onData = (buffer: Buffer) => {
|
|
46
|
-
const char = buffer.toString('utf8');
|
|
47
|
-
|
|
48
|
-
if (char === '\r' || char === '\n') {
|
|
49
|
-
// Enter pressed
|
|
50
|
-
process.stdin.setRawMode(false);
|
|
51
|
-
process.stdin.pause();
|
|
52
|
-
process.stdin.removeListener('data', onData);
|
|
53
|
-
process.stdout.write('\n');
|
|
54
|
-
passwordRl.close();
|
|
55
|
-
resolve({ email: email.trim(), password: password.trim() });
|
|
56
|
-
} else if (char === '\u0003') {
|
|
57
|
-
// Ctrl+C
|
|
58
|
-
process.stdin.setRawMode(false);
|
|
59
|
-
process.stdin.pause();
|
|
60
|
-
process.stdin.removeListener('data', onData);
|
|
61
|
-
process.stdout.write('\n');
|
|
62
|
-
process.exit(0);
|
|
63
|
-
} else if (char === '\u007f' || char === '\b') {
|
|
64
|
-
// Backspace
|
|
65
|
-
if (password.length > 0) {
|
|
66
|
-
password = password.slice(0, -1);
|
|
67
|
-
process.stdout.write('\b \b');
|
|
68
|
-
}
|
|
69
|
-
} else if (char.charCodeAt(0) >= 32 && char.charCodeAt(0) <= 126) {
|
|
70
|
-
// Printable characters
|
|
71
|
-
password += char;
|
|
72
|
-
process.stdout.write('*');
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
process.stdin.on('data', onData);
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Prompts user for development port with default value.
|
|
83
|
-
* @returns Promise resolving to the selected port.
|
|
84
|
-
*/
|
|
85
|
-
export async function askForPort(): Promise<number> {
|
|
86
|
-
const rl = readline.createInterface({
|
|
87
|
-
input: process.stdin,
|
|
88
|
-
output: process.stdout,
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
return new Promise((resolve) => {
|
|
92
|
-
rl.question('Enter development port (default: 3000): ', (answer) => {
|
|
93
|
-
rl.close();
|
|
94
|
-
const port = answer.trim() || '3000';
|
|
95
|
-
|
|
96
|
-
// Validate port is a number
|
|
97
|
-
const portNumber = parseInt(port, 10);
|
|
98
|
-
if (isNaN(portNumber) || portNumber < 1 || portNumber > 65535) {
|
|
99
|
-
console.error('Error: Port must be a valid number between 1 and 65535');
|
|
100
|
-
process.exit(1);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
resolve(portNumber);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Authenticates with Supabase using email and password.
|
|
110
|
-
* @param param
|
|
111
|
-
* @param param.email - User email address.
|
|
112
|
-
* @param param.password - User password.
|
|
113
|
-
* @returns Promise resolving to JWT access token.
|
|
114
|
-
* @throws {Error} if authentication fails.
|
|
115
|
-
*/
|
|
116
|
-
export async function authenticateWithSupabase({ email, password }: UserCredentials): Promise<string> {
|
|
117
|
-
console.log('🔐 Authenticating with Supabase...');
|
|
118
|
-
|
|
119
|
-
// Initialize Supabase client (you may need to adjust the URL and key)
|
|
120
|
-
const supabaseUrl = process.env.SUPABASE_URL || DEFAULT_ENDPOINT;
|
|
121
|
-
const supabaseKey = process.env.SUPABASE_ANON_KEY || DEFAULT_ANON_KEY;
|
|
122
|
-
|
|
123
|
-
const supabase = createClient(supabaseUrl, supabaseKey);
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
const { data, error } = await supabase.auth.signInWithPassword({
|
|
127
|
-
email,
|
|
128
|
-
password,
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
if (error) {
|
|
132
|
-
throw new Error(`Authentication failed: ${error.message}`);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (!data.session?.access_token) {
|
|
136
|
-
throw new Error('No access token received from authentication');
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
console.log('✅ Supabase authentication successful!');
|
|
140
|
-
return data.session.access_token;
|
|
141
|
-
} catch (error) {
|
|
142
|
-
throw new Error(`Supabase authentication failed: ${error}`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Registers developer and gets plugin credentials from the backend.
|
|
148
|
-
* @param jwtToken - JWT token from Supabase authentication.
|
|
149
|
-
* @param port - Development port for the plugin.
|
|
150
|
-
* @returns Promise resolving to plugin ID and access token.
|
|
151
|
-
* @throws {Error} if registration request fails.
|
|
152
|
-
*/
|
|
153
|
-
export async function registerDeveloper(jwtToken: string, port: number): Promise<DeveloperRegisterResponse> {
|
|
154
|
-
console.log('🚀 Registering developer and creating plugin...');
|
|
155
|
-
|
|
156
|
-
try {
|
|
157
|
-
const currentFolderName = path.basename(process.cwd());
|
|
158
|
-
const body: any = { port, pluginName: currentFolderName };
|
|
159
|
-
const backendUrl = process.env.RIMORI_BACKEND_URL || 'https://api.rimori.se';
|
|
160
|
-
|
|
161
|
-
const response = await fetch(backendUrl + '/developer/register', {
|
|
162
|
-
method: 'POST',
|
|
163
|
-
headers: {
|
|
164
|
-
'Content-Type': 'application/json',
|
|
165
|
-
Authorization: `Bearer ${jwtToken}`,
|
|
166
|
-
},
|
|
167
|
-
body: JSON.stringify(body),
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
if (!response.ok) {
|
|
171
|
-
console.error(await response.text());
|
|
172
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const data: DeveloperRegisterResponse = await response.json();
|
|
176
|
-
|
|
177
|
-
if (!data.plugin_id || !data.access_token) {
|
|
178
|
-
throw new Error('Invalid response: missing pluginId or access_token');
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
console.log('✅ Plugin registration successful!');
|
|
182
|
-
console.log(`Plugin ID: ${data.plugin_id}`);
|
|
183
|
-
|
|
184
|
-
return data;
|
|
185
|
-
} catch (error) {
|
|
186
|
-
console.error(error);
|
|
187
|
-
throw new Error(`Developer registration failed: ${error}`);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Creates or updates the .env file with the plugin token.
|
|
6
|
-
* @param token - The plugin authentication token.
|
|
7
|
-
*/
|
|
8
|
-
export function setupEnvFile(token: string): void {
|
|
9
|
-
const envPath = path.resolve('.env');
|
|
10
|
-
if (!fs.existsSync(envPath)) {
|
|
11
|
-
const envContent = `RIMORI_TOKEN=${token}\n`;
|
|
12
|
-
fs.writeFileSync(envPath, envContent, 'utf8');
|
|
13
|
-
console.log('Created .env file with RIMORI_TOKEN');
|
|
14
|
-
} else {
|
|
15
|
-
console.log('.env file already exists, skipping creation');
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Updates .gitignore to exclude .env files.
|
|
21
|
-
*/
|
|
22
|
-
export function updateGitignore(): void {
|
|
23
|
-
const gitignorePath = path.resolve('.gitignore');
|
|
24
|
-
let gitignoreContent = '';
|
|
25
|
-
let needsUpdate = false;
|
|
26
|
-
|
|
27
|
-
if (fs.existsSync(gitignorePath)) {
|
|
28
|
-
gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
|
|
29
|
-
// Check if .env is already in .gitignore
|
|
30
|
-
if (!gitignoreContent.includes('.env')) {
|
|
31
|
-
needsUpdate = true;
|
|
32
|
-
}
|
|
33
|
-
} else {
|
|
34
|
-
needsUpdate = true;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (needsUpdate) {
|
|
38
|
-
gitignoreContent += '\n.env\npublic/web-worker.js\n';
|
|
39
|
-
fs.writeFileSync(gitignorePath, gitignoreContent, 'utf8');
|
|
40
|
-
console.log('Added .env to .gitignore');
|
|
41
|
-
} else {
|
|
42
|
-
console.log('.env already in .gitignore, skipping update');
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { dirname } from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
|
|
6
|
-
// ES module equivalent of __dirname
|
|
7
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
-
const __dirname = dirname(__filename);
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Configuration mapping source files to destination files.
|
|
12
|
-
* Key: Source path relative to __dirname
|
|
13
|
-
* Value: Destination path relative to current working directory
|
|
14
|
-
*/
|
|
15
|
-
const FILE_COPY_MAP: Record<string, string> = {
|
|
16
|
-
'../../../../example/rimori.config.ts': './rimori/rimori.config.ts',
|
|
17
|
-
'../../../../README.md': './rimori/readme.md',
|
|
18
|
-
'../../../../example/docs/overview.md': './public/docs/overview.md',
|
|
19
|
-
'../../../../example/docs/devdocs.md': './public/docs/devdocs.md',
|
|
20
|
-
'../../../../example/docs/userdocs.md': './public/docs/userdocs.md',
|
|
21
|
-
'../../../../example/worker/worker.ts': './worker/worker.ts',
|
|
22
|
-
'../../../../example/worker/vite.config.ts': './worker/vite.config.ts',
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Copies necessary files and creates directories for the plugin setup.
|
|
27
|
-
*/
|
|
28
|
-
export function copyPluginFiles(): void {
|
|
29
|
-
console.log('Copying plugin files...');
|
|
30
|
-
|
|
31
|
-
for (const [srcRelativePath, destRelativePath] of Object.entries(FILE_COPY_MAP)) {
|
|
32
|
-
const srcPath = path.resolve(__dirname, srcRelativePath);
|
|
33
|
-
const destPath = path.resolve(destRelativePath);
|
|
34
|
-
const destDir = path.dirname(destPath);
|
|
35
|
-
|
|
36
|
-
// Check if source file exists
|
|
37
|
-
if (!fs.existsSync(srcPath)) {
|
|
38
|
-
console.log(`Warning: Source file not found: ${srcPath}`);
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Create destination directory if it doesn't exist
|
|
43
|
-
if (!fs.existsSync(destDir)) {
|
|
44
|
-
console.log(`Creating directory: ${destDir}`);
|
|
45
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Only copy if destination file doesn't exist
|
|
49
|
-
if (!fs.existsSync(destPath)) {
|
|
50
|
-
fs.copyFileSync(srcPath, destPath);
|
|
51
|
-
console.log(`Copied: ${srcRelativePath} -> ${destRelativePath}`);
|
|
52
|
-
} else {
|
|
53
|
-
console.log(`File already exists, skipping: ${destRelativePath}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
console.log('Plugin file copying completed.');
|
|
58
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Removes all meta tags from HTML content except viewport and charset.
|
|
6
|
-
* @param htmlContent - The HTML content to process.
|
|
7
|
-
* @returns The processed HTML content with unwanted meta tags removed.
|
|
8
|
-
*/
|
|
9
|
-
function removeUnwantedMetaTags(htmlContent: string): string {
|
|
10
|
-
// Remove all meta tags except those with name="viewport" or charset attribute
|
|
11
|
-
let cleanedContent = htmlContent.replace(/<meta\s+(?![^>]*(?:name\s*=\s*["']viewport["']|charset\s*=))[^>]*>/gi, '');
|
|
12
|
-
|
|
13
|
-
// Remove empty lines left behind
|
|
14
|
-
cleanedContent = cleanedContent.replace(/^\s*[\r\n]/gm, '');
|
|
15
|
-
|
|
16
|
-
return cleanedContent;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Processes HTML files to remove unwanted meta tags.
|
|
21
|
-
*/
|
|
22
|
-
export function cleanHtmlMetaTags(): void {
|
|
23
|
-
const filePath = path.resolve('./index.html');
|
|
24
|
-
|
|
25
|
-
if (!filePath.endsWith('.html')) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!fs.existsSync(filePath)) {
|
|
30
|
-
console.log(`Warning: HTML file not found: ${filePath}`);
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
36
|
-
const cleanedContent = removeUnwantedMetaTags(content);
|
|
37
|
-
|
|
38
|
-
if (content !== cleanedContent) {
|
|
39
|
-
fs.writeFileSync(filePath, cleanedContent, 'utf8');
|
|
40
|
-
console.log(`Cleaned meta tags in: ${filePath}`);
|
|
41
|
-
}
|
|
42
|
-
} catch (error) {
|
|
43
|
-
console.error(`Error processing HTML file ${filePath}:`, error);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
import { askForCredentials, askForPort, authenticateWithSupabase, registerDeveloper } from './dev-registration.js';
|
|
6
|
-
import { setupEnvFile, updateGitignore } from './env-setup.js';
|
|
7
|
-
import { copyPluginFiles } from './file-operations.js';
|
|
8
|
-
import { cleanHtmlMetaTags } from './html-cleaner.js';
|
|
9
|
-
import { updatePackageJson, type PackageJson } from './package-setup.js';
|
|
10
|
-
import { transformAppRouter } from './router-transformer.js';
|
|
11
|
-
import { updateTailwindConfig } from './tailwind-config.js';
|
|
12
|
-
import { updateViteConfigBase } from './vite-config.js';
|
|
13
|
-
import 'dotenv/config';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Main function that handles the complete plugin setup flow.
|
|
17
|
-
*/
|
|
18
|
-
async function main(): Promise<void> {
|
|
19
|
-
try {
|
|
20
|
-
// Check for --upgrade flag
|
|
21
|
-
const isUpgrade = process.argv.includes('--upgrade');
|
|
22
|
-
|
|
23
|
-
if (isUpgrade) {
|
|
24
|
-
console.log('🔄 Starting Rimori Plugin Upgrade...');
|
|
25
|
-
} else {
|
|
26
|
-
console.log('🎯 Starting Rimori Plugin Setup...');
|
|
27
|
-
}
|
|
28
|
-
console.log('');
|
|
29
|
-
|
|
30
|
-
// Check if plugin is already initialized (skip for upgrade mode)
|
|
31
|
-
if (!isUpgrade) {
|
|
32
|
-
const packageJsonPath = path.resolve('./package.json');
|
|
33
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
34
|
-
try {
|
|
35
|
-
const packageJson: PackageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
36
|
-
if (packageJson.r_id) {
|
|
37
|
-
console.log('❌ Plugin is already initialized!');
|
|
38
|
-
console.log(`Plugin ID: ${packageJson.r_id}`);
|
|
39
|
-
console.log('');
|
|
40
|
-
console.log(
|
|
41
|
-
'If you want to reinitialize the plugin, please remove the "r_id" field from package.json first.',
|
|
42
|
-
);
|
|
43
|
-
console.log(
|
|
44
|
-
'Or use the --upgrade flag to upgrade the plugin configuration without changing the plugin ID.',
|
|
45
|
-
);
|
|
46
|
-
process.exit(0);
|
|
47
|
-
}
|
|
48
|
-
} catch (error) {
|
|
49
|
-
console.warn('Warning: Could not read package.json, continuing with setup...');
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let pluginId: string = '';
|
|
55
|
-
|
|
56
|
-
if (isUpgrade) {
|
|
57
|
-
// For upgrade mode, only ask for port and setup plugin
|
|
58
|
-
console.log('🔄 Upgrade mode: Skipping authentication and plugin registration...');
|
|
59
|
-
console.log('');
|
|
60
|
-
|
|
61
|
-
// Get plugin ID from existing package.json
|
|
62
|
-
try {
|
|
63
|
-
const packageJsonPath = path.resolve('./package.json');
|
|
64
|
-
const packageJson: PackageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
65
|
-
pluginId = packageJson.r_id || '';
|
|
66
|
-
} catch (error) {
|
|
67
|
-
console.warn('Warning: Could not read plugin ID from package.json');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Ask for development port
|
|
71
|
-
const port = await askForPort();
|
|
72
|
-
console.log('');
|
|
73
|
-
|
|
74
|
-
// Update package.json in upgrade mode
|
|
75
|
-
updatePackageJson({
|
|
76
|
-
port,
|
|
77
|
-
isUpgrade: true,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// Copy files
|
|
81
|
-
copyPluginFiles();
|
|
82
|
-
|
|
83
|
-
// Update gitignore
|
|
84
|
-
updateGitignore();
|
|
85
|
-
} else {
|
|
86
|
-
// Step 1: Get user credentials
|
|
87
|
-
const credentials = await askForCredentials();
|
|
88
|
-
console.log('');
|
|
89
|
-
|
|
90
|
-
// Step 2: Authenticate with Supabase
|
|
91
|
-
const jwtToken = await authenticateWithSupabase(credentials);
|
|
92
|
-
console.log('');
|
|
93
|
-
|
|
94
|
-
// Step 3: Ask for development port
|
|
95
|
-
const port = await askForPort();
|
|
96
|
-
console.log('');
|
|
97
|
-
|
|
98
|
-
// Step 4: Register developer and get plugin credentials
|
|
99
|
-
const { plugin_id, access_token } = await registerDeveloper(jwtToken, port);
|
|
100
|
-
pluginId = plugin_id;
|
|
101
|
-
console.log('');
|
|
102
|
-
|
|
103
|
-
// Step 5: Update package.json
|
|
104
|
-
updatePackageJson({
|
|
105
|
-
pluginId: plugin_id,
|
|
106
|
-
port,
|
|
107
|
-
isUpgrade: false,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// Step 6: Setup environment file
|
|
111
|
-
setupEnvFile(access_token);
|
|
112
|
-
|
|
113
|
-
// Step 7: Copy necessary files
|
|
114
|
-
copyPluginFiles();
|
|
115
|
-
|
|
116
|
-
// Step 8: Update gitignore
|
|
117
|
-
updateGitignore();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Setup vite config base
|
|
121
|
-
try {
|
|
122
|
-
console.log('Updating vite config base...');
|
|
123
|
-
updateViteConfigBase();
|
|
124
|
-
console.log('✅ Vite config base updated');
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.warn(
|
|
127
|
-
`Warning: Could not update vite.config.ts base property: ${error instanceof Error ? error.message : error}`,
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Clean meta tags from index.html after vite adaptation
|
|
132
|
-
cleanHtmlMetaTags();
|
|
133
|
-
console.log('✅ Meta tags cleaned from index.html');
|
|
134
|
-
|
|
135
|
-
// Update Tailwind CSS configuration
|
|
136
|
-
updateTailwindConfig();
|
|
137
|
-
|
|
138
|
-
// Transform App.tsx to use PluginProvider with HashRouter
|
|
139
|
-
if (pluginId) {
|
|
140
|
-
try {
|
|
141
|
-
transformAppRouter(pluginId);
|
|
142
|
-
} catch (error) {
|
|
143
|
-
console.warn(`Warning: Could not transform App.tsx router: ${error instanceof Error ? error.message : error}`);
|
|
144
|
-
}
|
|
145
|
-
} else {
|
|
146
|
-
console.warn('Warning: Plugin ID not available, skipping router transformation');
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
console.log('');
|
|
150
|
-
console.log('✅ Plugin ' + (isUpgrade ? 'upgrade' : 'setup') + ' completed successfully!');
|
|
151
|
-
console.log('');
|
|
152
|
-
console.log('Next steps:');
|
|
153
|
-
console.log('1. Check out ./rimori/readme.md for more information about how to make the most out of the plugin.');
|
|
154
|
-
console.log('2. Adapt the ./rimori/rimori.config.ts file to your needs.');
|
|
155
|
-
console.log(
|
|
156
|
-
'3. Under ./public/docs/ you can find the documentation for an example flashcard plugin to get started easier.',
|
|
157
|
-
);
|
|
158
|
-
console.log('4. Start development with: yarn dev');
|
|
159
|
-
console.log('');
|
|
160
|
-
console.log(`The plugin should now be accessible at: http://localhost:${3000}`);
|
|
161
|
-
console.log('');
|
|
162
|
-
console.log(
|
|
163
|
-
'If you want to release the plugin, simply run: "yarn release:<alpha|beta|stable>" (details are available in ./rimori/readme.md)',
|
|
164
|
-
);
|
|
165
|
-
} catch (error) {
|
|
166
|
-
console.error(`❌ Error: ${error instanceof Error ? error.message : error}`);
|
|
167
|
-
console.error('');
|
|
168
|
-
console.error('Make sure that:');
|
|
169
|
-
console.error('1. Your Supabase credentials are correct');
|
|
170
|
-
console.error('2. You have internet connection for authentication');
|
|
171
|
-
process.exit(1);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
main();
|