create-fleetbo-project 1.2.10 → 1.2.11
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/install-react-template.js +118 -94
- package/package.json +1 -1
|
@@ -4,41 +4,118 @@ const { execSync } = require('child_process');
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const https = require('https');
|
|
7
|
-
// const os = require('os'); // Pas strictement nécessaire ici
|
|
8
7
|
|
|
9
8
|
// --- Configuration ---
|
|
10
9
|
const repoOwner = 'FleetFleetbo';
|
|
11
10
|
const repoName = 'dev.fleetbo.io';
|
|
12
11
|
const branchName = 'master';
|
|
13
|
-
|
|
14
|
-
// URL de téléchargement direct de l'archive
|
|
15
12
|
const archiveUrl = `https://github.com/${repoOwner}/${repoName}/archive/refs/heads/${branchName}.tar.gz`;
|
|
16
13
|
const bootstrapUrl = 'https://us-central1-myapp-259bf.cloudfunctions.net/bootstrapProject';
|
|
17
14
|
|
|
15
|
+
// --- LE CONTENU DU GARDIEN (Injecté dynamiquement) ---
|
|
16
|
+
const CLI_SCRIPT_CONTENT = `#!/usr/bin/env node
|
|
17
|
+
|
|
18
|
+
const { spawn } = require('child_process');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
const axios = require('axios');
|
|
22
|
+
const dotenv = require('dotenv');
|
|
23
|
+
const ngrok = require('ngrok');
|
|
24
|
+
const os = require('os');
|
|
25
|
+
|
|
26
|
+
const UPDATE_NETWORK_URL = 'https://us-central1-myapp-259bf.cloudfunctions.net/updateDeveloperNetwork';
|
|
27
|
+
const PORT = 3000;
|
|
28
|
+
|
|
29
|
+
async function cleanupAndExit(code = 0) {
|
|
30
|
+
console.log('\\n[Fleetbo] 🛑 Shutting down services...');
|
|
31
|
+
try { await ngrok.kill(); } catch (e) {}
|
|
32
|
+
process.exit(code);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
process.on('SIGINT', () => cleanupAndExit(0));
|
|
36
|
+
process.on('SIGTERM', () => cleanupAndExit(0));
|
|
37
|
+
|
|
38
|
+
async function syncFirebase(keyApp, networkUrl) {
|
|
39
|
+
try {
|
|
40
|
+
await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl });
|
|
41
|
+
console.log('\\n[Fleetbo] ---------------------------------------------------');
|
|
42
|
+
console.log(\`[Fleetbo] ✅ Tunnel Active: \${networkUrl}\`);
|
|
43
|
+
console.log(\`[Fleetbo] 🚀 Simulator: https://fleetbo.io/studio/view/\${keyApp}\`);
|
|
44
|
+
console.log('[Fleetbo] ---------------------------------------------------\\n');
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.error(\`[Fleetbo] ⚠️ Sync Error: \${err.message}\`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function runGuardian() {
|
|
51
|
+
console.log(\`[Fleetbo] 🛡️ Starting Fleetbo Guardian on \${os.platform()}...\`);
|
|
52
|
+
|
|
53
|
+
const envPath = path.join(process.cwd(), '.env');
|
|
54
|
+
if (!fs.existsSync(envPath)) {
|
|
55
|
+
console.error('Error: .env file not found.');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
dotenv.config({ path: envPath });
|
|
59
|
+
|
|
60
|
+
const keyApp = process.env.REACT_KEY_APP;
|
|
61
|
+
|
|
62
|
+
console.log(\`[Fleetbo] 📦 Booting React Server...\`);
|
|
63
|
+
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
64
|
+
|
|
65
|
+
const devServer = spawn(npmCmd, ['start'], {
|
|
66
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
67
|
+
env: { ...process.env, BROWSER: 'none' }
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
devServer.stdout.pipe(process.stdout);
|
|
71
|
+
devServer.stderr.pipe(process.stderr);
|
|
72
|
+
|
|
73
|
+
let tunnelStarted = false;
|
|
74
|
+
|
|
75
|
+
devServer.stdout.on('data', async (data) => {
|
|
76
|
+
const output = data.toString();
|
|
77
|
+
if (!tunnelStarted && (output.includes('Local:') || output.includes('Compiled successfully'))) {
|
|
78
|
+
tunnelStarted = true;
|
|
79
|
+
console.log(\`\\n[Fleetbo] 🔗 React is ready. Opening secure tunnel...\`);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const url = await ngrok.connect({ addr: PORT });
|
|
83
|
+
await syncFirebase(keyApp, url);
|
|
84
|
+
} catch (err) {
|
|
85
|
+
console.error('\\n[Fleetbo] ❌ NGROK CONNECTION FAILED');
|
|
86
|
+
if (err.message.includes('ERR_NGROK_4018') || err.message.includes('limited') || err.message.includes('authtoken')) {
|
|
87
|
+
console.error('-------------------------------------------------------');
|
|
88
|
+
console.error('⚠️ MISSING OR INVALID AUTH TOKEN');
|
|
89
|
+
console.error(' Run this command once:');
|
|
90
|
+
console.error(' npx ngrok config add-authtoken <YOUR_TOKEN>');
|
|
91
|
+
console.error('-------------------------------------------------------');
|
|
92
|
+
}
|
|
93
|
+
cleanupAndExit(1);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
runGuardian();
|
|
100
|
+
`;
|
|
101
|
+
|
|
18
102
|
// --- Analyse des Arguments ---
|
|
19
103
|
const args = process.argv.slice(2);
|
|
20
104
|
const projectNameArg = args.find(arg => !arg.startsWith('--'));
|
|
21
105
|
const tokenArg = args.find(arg => arg.startsWith('--token='));
|
|
22
106
|
|
|
23
|
-
if (!projectNameArg) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const bootstrapToken = tokenArg ? tokenArg.split('=')[1] : null;
|
|
30
|
-
|
|
31
|
-
if (!bootstrapToken) {
|
|
32
|
-
console.error('\n ❌ Error : The bootstrap token is missing.');
|
|
33
|
-
console.log(' Usage: npx create-fleetbo-project <project-name> --token=<your-token>');
|
|
34
|
-
process.exit(1);
|
|
107
|
+
if (!projectNameArg || !bootstrapToken(tokenArg)) {
|
|
108
|
+
console.error('\n ❌ Usage: npx create-fleetbo-project <project-name> --token=<your-token>');
|
|
109
|
+
process.exit(1);
|
|
35
110
|
}
|
|
36
111
|
|
|
112
|
+
function bootstrapToken(arg) { return arg ? arg.split('=')[1] : null; }
|
|
37
113
|
const projectName = projectNameArg;
|
|
38
114
|
const projectDir = path.join(process.cwd(), projectName);
|
|
115
|
+
const bToken = bootstrapToken(tokenArg);
|
|
39
116
|
|
|
40
|
-
// --- Fonctions Utilitaires ---
|
|
41
117
|
|
|
118
|
+
// --- Fonctions Utilitaires ---
|
|
42
119
|
function fetchProjectKeys(token) {
|
|
43
120
|
return new Promise((resolve, reject) => {
|
|
44
121
|
const postData = JSON.stringify({ token });
|
|
@@ -48,16 +125,8 @@ function fetchProjectKeys(token) {
|
|
|
48
125
|
res.on('data', (chunk) => { data += chunk; });
|
|
49
126
|
res.on('end', () => {
|
|
50
127
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
51
|
-
try {
|
|
52
|
-
|
|
53
|
-
} catch (e) {
|
|
54
|
-
reject(new Error('Invalid response from the key server.'));
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
let errorMsg = `Server error (code: ${res.statusCode})`;
|
|
58
|
-
try { errorMsg = JSON.parse(data).error || errorMsg; } catch(e){}
|
|
59
|
-
reject(new Error(errorMsg));
|
|
60
|
-
}
|
|
128
|
+
try { resolve(JSON.parse(data)); } catch (e) { reject(new Error('Invalid response')); }
|
|
129
|
+
} else { reject(new Error(`Server error ${res.statusCode}`)); }
|
|
61
130
|
});
|
|
62
131
|
});
|
|
63
132
|
req.on('error', (e) => reject(e));
|
|
@@ -66,123 +135,78 @@ function fetchProjectKeys(token) {
|
|
|
66
135
|
});
|
|
67
136
|
}
|
|
68
137
|
|
|
69
|
-
// --- CORRECTION ICI : Gestion des redirections (301/302) ---
|
|
70
138
|
function downloadEngine(url, dest) {
|
|
71
139
|
return new Promise((resolve, reject) => {
|
|
72
140
|
const request = https.get(url, (response) => {
|
|
73
|
-
// 1. Gérer la redirection (GitHub renvoie souvent 302 Found)
|
|
74
141
|
if (response.statusCode === 301 || response.statusCode === 302) {
|
|
75
|
-
|
|
76
|
-
if (!newUrl) {
|
|
77
|
-
reject(new Error("Redirect status found but no location header."));
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
// Appel récursif avec la nouvelle URL
|
|
81
|
-
downloadEngine(newUrl, dest)
|
|
82
|
-
.then(resolve)
|
|
83
|
-
.catch(reject);
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// 2. Vérifier le succès (200 OK)
|
|
88
|
-
if (response.statusCode !== 200) {
|
|
89
|
-
reject(new Error(`Failed to download engine (Status: ${response.statusCode})`));
|
|
142
|
+
downloadEngine(response.headers.location, dest).then(resolve).catch(reject);
|
|
90
143
|
return;
|
|
91
144
|
}
|
|
92
|
-
|
|
93
|
-
// 3. Écriture du fichier
|
|
145
|
+
if (response.statusCode !== 200) { reject(new Error(`Status: ${response.statusCode}`)); return; }
|
|
94
146
|
const file = fs.createWriteStream(dest);
|
|
95
147
|
response.pipe(file);
|
|
96
|
-
|
|
97
|
-
file.on('
|
|
98
|
-
file.close(resolve);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
file.on('error', (err) => {
|
|
102
|
-
fs.unlink(dest, () => {}); // Supprimer fichier incomplet
|
|
103
|
-
reject(err);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
request.on('error', (err) => {
|
|
108
|
-
fs.unlink(dest, () => {});
|
|
109
|
-
reject(err);
|
|
148
|
+
file.on('finish', () => file.close(resolve));
|
|
149
|
+
file.on('error', (err) => { fs.unlink(dest, () => {}); reject(err); });
|
|
110
150
|
});
|
|
151
|
+
request.on('error', (err) => reject(err));
|
|
111
152
|
});
|
|
112
153
|
}
|
|
113
154
|
|
|
114
155
|
// --- Fonction Principale ---
|
|
115
|
-
|
|
116
156
|
async function setupProject() {
|
|
117
157
|
console.log(`\n⚡ Initializing Fleetbo Framework for "${projectName}"...`);
|
|
118
158
|
|
|
119
159
|
try {
|
|
120
|
-
if (fs.existsSync(projectDir)) {
|
|
121
|
-
throw new Error(`Directory "${projectName}" already exists.`);
|
|
122
|
-
}
|
|
160
|
+
if (fs.existsSync(projectDir)) throw new Error(`Directory "${projectName}" already exists.`);
|
|
123
161
|
fs.mkdirSync(projectDir);
|
|
124
162
|
|
|
125
|
-
//
|
|
163
|
+
// 1. Download
|
|
126
164
|
console.log(' [1/6] 📥 Downloading Fleetbo Core Engine...');
|
|
127
165
|
const archivePath = path.join(projectDir, 'engine.tar.gz');
|
|
128
|
-
|
|
129
|
-
// Cette fonction gère maintenant la redirection GitHub
|
|
130
166
|
await downloadEngine(archiveUrl, archivePath);
|
|
131
167
|
|
|
132
|
-
//
|
|
168
|
+
// 2. Extract
|
|
133
169
|
console.log(' [2/6] 📦 Scaffolding project structure...');
|
|
134
170
|
try {
|
|
135
|
-
// On ignore les erreurs de tar si c'est juste des warnings, mais on catch les erreurs fatales
|
|
136
171
|
execSync(`tar -xf "${archivePath}" -C "${projectDir}" --strip-components=1`, { stdio: 'ignore' });
|
|
137
172
|
fs.unlinkSync(archivePath);
|
|
138
|
-
} catch (e) {
|
|
139
|
-
// Fallback pour Windows si 'tar' n'est pas dans le path (rare sur Win10/11 mais possible)
|
|
140
|
-
throw new Error("Failed to extract engine. Make sure 'tar' command is available.");
|
|
141
|
-
}
|
|
173
|
+
} catch (e) { throw new Error("Failed to extract engine. Ensure 'tar' is available."); }
|
|
142
174
|
|
|
143
175
|
process.chdir(projectDir);
|
|
144
176
|
|
|
145
|
-
//
|
|
177
|
+
// 3. Auth
|
|
146
178
|
console.log(' [3/6] 🔑 Authenticating with Fleetbo Cloud...');
|
|
147
|
-
const keys = await fetchProjectKeys(
|
|
148
|
-
if (!keys.enterpriseId
|
|
149
|
-
throw new Error("Received keys from the server are invalid.");
|
|
150
|
-
}
|
|
179
|
+
const keys = await fetchProjectKeys(bToken);
|
|
180
|
+
if (!keys.enterpriseId) throw new Error("Invalid keys.");
|
|
151
181
|
|
|
152
|
-
//
|
|
153
|
-
console.log(' [4/6] ⚙️ Configuring environment...');
|
|
182
|
+
// 4. Environment & CLI Generation
|
|
183
|
+
console.log(' [4/6] ⚙️ Configuring environment & CLI...');
|
|
154
184
|
const envContent = `REACT_APP_FLEETBO_DB_KEY=${keys.fleetboDBKey}\nREACT_APP_ENTERPRISE_ID=${keys.enterpriseId}\nREACT_KEY_APP=${projectName}\nDANGEROUSLY_DISABLE_HOST_CHECK=true\n`;
|
|
155
185
|
fs.writeFileSync(path.join(projectDir, '.env'), envContent, 'utf8');
|
|
156
186
|
|
|
157
|
-
//
|
|
187
|
+
// --- ICI ON CRÉE LE FICHIER CLI.JS ---
|
|
188
|
+
fs.writeFileSync(path.join(projectDir, 'cli.js'), CLI_SCRIPT_CONTENT, 'utf8');
|
|
189
|
+
// -------------------------------------
|
|
190
|
+
|
|
191
|
+
// 5. Deps
|
|
158
192
|
console.log(' [5/6] 📚 Installing dependencies...');
|
|
159
|
-
// On installe les deps du projet + ngrok en dev
|
|
160
193
|
execSync('npm install', { stdio: 'inherit' });
|
|
161
194
|
execSync('npm install ngrok dotenv --save-dev', { stdio: 'ignore' });
|
|
162
195
|
|
|
163
|
-
//
|
|
196
|
+
// 6. Finalize
|
|
164
197
|
console.log(' [6/6] ✨ Finalizing setup...');
|
|
165
198
|
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
166
199
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
167
200
|
packageJson.name = projectName;
|
|
168
|
-
|
|
169
|
-
packageJson.scripts = {
|
|
170
|
-
...packageJson.scripts,
|
|
171
|
-
"fleetbo": "node cli.js",
|
|
172
|
-
"dev": "node cli.js"
|
|
173
|
-
};
|
|
201
|
+
packageJson.scripts = { ...packageJson.scripts, "fleetbo": "node cli.js", "dev": "node cli.js" };
|
|
174
202
|
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
|
|
175
203
|
|
|
176
204
|
console.log('\n✅ Project successfully created!');
|
|
177
|
-
console.log(`\n👉
|
|
178
|
-
console.log(` cd ${projectName}`);
|
|
179
|
-
console.log(` npm run fleetbo`);
|
|
205
|
+
console.log(`\n👉 Run: cd ${projectName} && npm run fleetbo`);
|
|
180
206
|
|
|
181
207
|
} catch (error) {
|
|
182
208
|
console.error('\n❌ Setup failed:', error.message);
|
|
183
|
-
if (fs.existsSync(projectDir)) {
|
|
184
|
-
try { fs.rmSync(projectDir, { recursive: true, force: true }); } catch(e){}
|
|
185
|
-
}
|
|
209
|
+
if (fs.existsSync(projectDir)) try { fs.rmSync(projectDir, { recursive: true, force: true }); } catch(e){}
|
|
186
210
|
process.exit(1);
|
|
187
211
|
}
|
|
188
212
|
}
|