create-fleetbo-project 1.2.13 → 1.2.17

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.
@@ -9,14 +9,13 @@ const https = require('https');
9
9
  const repoOwner = 'FleetFleetbo';
10
10
  const repoName = 'dev.fleetbo.io';
11
11
  const branchName = 'master';
12
- // URL de l'archive (On cible 'codeload' implicitement via GitHub)
13
12
  const archiveUrl = `https://github.com/${repoOwner}/${repoName}/archive/refs/heads/${branchName}.tar.gz`;
14
13
  const bootstrapUrl = 'https://us-central1-myapp-259bf.cloudfunctions.net/bootstrapProject';
15
14
 
16
- // --- LE CONTENU DU GARDIEN (CLI.JS) ---
15
+ // --- LE CONTENU DU GARDIEN (CLI.JS) - VERSION BYPASS WARNING ---
17
16
  const CLI_SCRIPT_CONTENT = `#!/usr/bin/env node
18
17
 
19
- const { spawn } = require('child_process');
18
+ const { spawn, exec, execSync } = require('child_process');
20
19
  const fs = require('fs');
21
20
  const path = require('path');
22
21
  const axios = require('axios');
@@ -25,11 +24,36 @@ const ngrok = require('ngrok');
25
24
  const os = require('os');
26
25
 
27
26
  const UPDATE_NETWORK_URL = 'https://us-central1-myapp-259bf.cloudfunctions.net/updateDeveloperNetwork';
28
- const PORT = 3000;
27
+ const PORT = 3000;
28
+ const NGROK_PORT = 4040;
29
+
30
+ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
31
+
32
+ // Tueur de processus générique par port
33
+ function killProcessOnPort(port) {
34
+ try {
35
+ if (process.platform !== 'win32') {
36
+ const pid = execSync(\`lsof -ti:\${port} 2>/dev/null\`).toString().trim();
37
+ if (pid) {
38
+ const pids = pid.split('\\n').join(' ');
39
+ console.log(\`[Fleetbo] 🔫 Freeing port \${port} (PIDs: \${pids})...\`);
40
+ execSync(\`kill -9 \${pids}\`);
41
+ }
42
+ }
43
+ } catch (e) {}
44
+ }
45
+
46
+ async function forceKillNgrok() {
47
+ return new Promise((resolve) => {
48
+ const cmd = process.platform === 'win32' ? 'taskkill /IM ngrok.exe /F' : 'pkill ngrok';
49
+ exec(cmd, () => resolve());
50
+ });
51
+ }
29
52
 
30
53
  async function cleanupAndExit(code = 0) {
31
- console.log('\\n[Fleetbo] 🛑 Shutting down services...');
32
- try { await ngrok.kill(); } catch (e) {}
54
+ console.log('\\n[Fleetbo] 🛑 Stopping services...');
55
+ try { await ngrok.kill(); } catch(e){}
56
+ killProcessOnPort(PORT);
33
57
  process.exit(code);
34
58
  }
35
59
 
@@ -38,10 +62,13 @@ process.on('SIGTERM', () => cleanupAndExit(0));
38
62
 
39
63
  async function syncFirebase(keyApp, networkUrl) {
40
64
  try {
65
+ // Si on utilise l'auth basique, l'URL inclut user:pass@... pour faciliter l'accès si besoin
66
+ // Mais pour le simulateur, mieux vaut envoyer l'URL standard et laisser le navigateur demander.
41
67
  await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl });
42
68
  console.log('\\n[Fleetbo] ---------------------------------------------------');
43
69
  console.log(\`[Fleetbo] ✅ Tunnel Active: \${networkUrl}\`);
44
70
  console.log(\`[Fleetbo] 🚀 Simulator: https://fleetbo.io/studio/view/\${keyApp}\`);
71
+ console.log(\`[Fleetbo] 🔑 Credentials: User="fleetbo", Pass="admin"\`); // RAPPEL POUR LE DEV
45
72
  console.log('[Fleetbo] ---------------------------------------------------\\n');
46
73
  } catch (err) {
47
74
  console.error(\`[Fleetbo] ⚠️ Sync Error: \${err.message}\`);
@@ -51,6 +78,12 @@ async function syncFirebase(keyApp, networkUrl) {
51
78
  async function runGuardian() {
52
79
  console.log(\`[Fleetbo] 🛡️ Starting Fleetbo Guardian on \${os.platform()}...\`);
53
80
 
81
+ console.log(\`[Fleetbo] 🧹 Preparing environment...\`);
82
+ await forceKillNgrok();
83
+ killProcessOnPort(NGROK_PORT);
84
+ killProcessOnPort(PORT);
85
+ await sleep(1000);
86
+
54
87
  const envPath = path.join(process.cwd(), '.env');
55
88
  if (!fs.existsSync(envPath)) {
56
89
  console.error('Error: .env file not found.');
@@ -59,13 +92,21 @@ async function runGuardian() {
59
92
  dotenv.config({ path: envPath });
60
93
 
61
94
  const keyApp = process.env.REACT_KEY_APP;
95
+ const authToken = process.env.NGROK_AUTHTOKEN;
62
96
 
63
- console.log(\`[Fleetbo] 📦 Booting React Server...\`);
97
+ if (authToken) {
98
+ try {
99
+ await ngrok.authtoken(authToken);
100
+ await sleep(500);
101
+ } catch (e) {}
102
+ }
103
+
104
+ console.log(\`[Fleetbo] 📦 Booting React Server on port \${PORT}...\`);
64
105
  const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
65
106
 
66
107
  const devServer = spawn(npmCmd, ['start'], {
67
108
  stdio: ['ignore', 'pipe', 'pipe'],
68
- env: { ...process.env, BROWSER: 'none' }
109
+ env: { ...process.env, BROWSER: 'none', PORT: PORT.toString() }
69
110
  });
70
111
 
71
112
  devServer.stdout.pipe(process.stdout);
@@ -75,23 +116,34 @@ async function runGuardian() {
75
116
 
76
117
  devServer.stdout.on('data', async (data) => {
77
118
  const output = data.toString();
119
+
78
120
  if (!tunnelStarted && (output.includes('Local:') || output.includes('Compiled successfully'))) {
79
121
  tunnelStarted = true;
80
- console.log(\`\\n[Fleetbo] 🔗 React is ready. Opening secure tunnel...\`);
122
+ console.log(\`\\n[Fleetbo] 🔗 React is ready. Initiating Tunnel...\`);
81
123
 
82
124
  try {
83
- const url = await ngrok.connect({ addr: PORT });
125
+ const url = await ngrok.connect({
126
+ addr: PORT,
127
+ name: \`fleetbo_\${Date.now()}\`,
128
+ auth: "fleetbo:admin" // <--- C'EST ICI QUE C'EST DÉFINI
129
+ });
84
130
  await syncFirebase(keyApp, url);
85
- } catch (err) {
86
- console.error('\\n[Fleetbo] ❌ NGROK CONNECTION FAILED');
87
- if (err.message.includes('ERR_NGROK_4018') || err.message.includes('limited') || err.message.includes('authtoken')) {
88
- console.error('-------------------------------------------------------');
89
- console.error('⚠️ MISSING OR INVALID AUTH TOKEN');
90
- console.error(' Run this command once:');
91
- console.error(' npx ngrok config add-authtoken <YOUR_TOKEN>');
92
- console.error('-------------------------------------------------------');
131
+ } catch (firstErr) {
132
+ try {
133
+ await sleep(2000);
134
+ const urlRetry = await ngrok.connect({
135
+ addr: PORT,
136
+ name: \`fleetbo_retry_\${Date.now()}\`,
137
+ auth: "fleetbo:admin" // Retry avec Auth aussi
138
+ });
139
+ await syncFirebase(keyApp, urlRetry);
140
+ } catch (finalErr) {
141
+ console.error('\\n[Fleetbo] ❌ NGROK ERROR');
142
+ console.error("Message:", finalErr.message);
143
+ if (finalErr.message.includes('ERR_NGROK_4018')) {
144
+ console.error("👉 Add NGROK_AUTHTOKEN=... to your .env file OR run 'npx ngrok config add-authtoken <TOKEN>'");
145
+ }
93
146
  }
94
- cleanupAndExit(1);
95
147
  }
96
148
  }
97
149
  });
@@ -105,29 +157,25 @@ const args = process.argv.slice(2);
105
157
  const projectNameArg = args.find(arg => !arg.startsWith('--'));
106
158
  const tokenArg = args.find(arg => arg.startsWith('--token='));
107
159
  const bootstrapTokenArg = tokenArg ? tokenArg.split('=')[1] : null;
160
+ const ngrokArg = args.find(arg => arg.startsWith('--ngrok='));
161
+ const ngrokTokenArg = ngrokArg ? ngrokArg.split('=')[1] : null;
108
162
 
109
163
  if (!projectNameArg || !bootstrapTokenArg) {
110
- console.error('\n ❌ Usage: npx create-fleetbo-project <project-name> --token=<your-token>');
164
+ console.error('\n ❌ Usage: npx create-fleetbo-project <name> --token=<fleetbo-token> [--ngrok=<ngrok-token>]');
111
165
  process.exit(1);
112
166
  }
113
167
 
114
168
  const projectName = projectNameArg;
115
169
  const projectDir = path.join(process.cwd(), projectName);
116
170
 
117
-
118
171
  // --- Fonctions Utilitaires ---
119
172
  function fetchProjectKeys(token) {
120
173
  return new Promise((resolve, reject) => {
121
174
  const postData = JSON.stringify({ token });
122
175
  const uri = new URL(bootstrapUrl);
123
176
  const options = {
124
- hostname: uri.hostname,
125
- path: uri.pathname,
126
- method: 'POST',
127
- headers: {
128
- 'Content-Type': 'application/json',
129
- 'Content-Length': Buffer.byteLength(postData)
130
- }
177
+ hostname: uri.hostname, path: uri.pathname, method: 'POST',
178
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) }
131
179
  };
132
180
  const req = https.request(options, (res) => {
133
181
  let data = '';
@@ -144,57 +192,29 @@ function fetchProjectKeys(token) {
144
192
  });
145
193
  }
146
194
 
147
- // --- CORRECTION MAJEURE : Ajout du User-Agent pour éviter l'erreur 503 ---
148
195
  function downloadEngine(url, dest) {
149
196
  return new Promise((resolve, reject) => {
150
- // On parse l'URL pour pouvoir ajouter des headers
151
197
  const uri = new URL(url);
152
198
  const options = {
153
- hostname: uri.hostname,
154
- path: uri.pathname + uri.search,
155
- method: 'GET',
156
- headers: {
157
- 'User-Agent': 'Fleetbo-CLI-Installer', // CRITIQUE POUR GITHUB
158
- 'Accept': '*/*'
159
- }
199
+ hostname: uri.hostname, path: uri.pathname + uri.search, method: 'GET',
200
+ headers: { 'User-Agent': 'Fleetbo-CLI-Installer', 'Accept': '*/*' }
160
201
  };
161
-
162
202
  const request = https.get(options, (response) => {
163
- // Gestion Redirection (301/302)
164
203
  if (response.statusCode === 301 || response.statusCode === 302) {
165
204
  if (!response.headers.location) {
166
205
  reject(new Error("Redirect found but no location header"));
167
206
  return;
168
207
  }
169
- // Appel récursif avec la nouvelle URL
170
208
  downloadEngine(response.headers.location, dest).then(resolve).catch(reject);
171
209
  return;
172
210
  }
173
-
174
- // Vérification du statut
175
- if (response.statusCode !== 200) {
176
- reject(new Error(`Failed to download (Status: ${response.statusCode})`));
177
- return;
178
- }
179
-
180
- // Écriture du fichier
211
+ if (response.statusCode !== 200) { reject(new Error(`Status: ${response.statusCode}`)); return; }
181
212
  const file = fs.createWriteStream(dest);
182
213
  response.pipe(file);
183
-
184
- file.on('finish', () => {
185
- file.close(resolve);
186
- });
187
-
188
- file.on('error', (err) => {
189
- fs.unlink(dest, () => {}); // Supprimer le fichier incomplet
190
- reject(err);
191
- });
192
- });
193
-
194
- request.on('error', (err) => {
195
- fs.unlink(dest, () => {});
196
- reject(err);
214
+ file.on('finish', () => file.close(resolve));
215
+ file.on('error', (err) => { fs.unlink(dest, () => {}); reject(err); });
197
216
  });
217
+ request.on('error', (err) => reject(err));
198
218
  });
199
219
  }
200
220
 
@@ -206,12 +226,10 @@ async function setupProject() {
206
226
  if (fs.existsSync(projectDir)) throw new Error(`Directory "${projectName}" already exists.`);
207
227
  fs.mkdirSync(projectDir);
208
228
 
209
- // 1. Download
210
229
  console.log(' [1/6] 📥 Downloading Fleetbo Core Engine...');
211
230
  const archivePath = path.join(projectDir, 'engine.tar.gz');
212
231
  await downloadEngine(archiveUrl, archivePath);
213
232
 
214
- // 2. Extract
215
233
  console.log(' [2/6] 📦 Scaffolding project structure...');
216
234
  try {
217
235
  execSync(`tar -xf "${archivePath}" -C "${projectDir}" --strip-components=1`, { stdio: 'ignore' });
@@ -220,23 +238,25 @@ async function setupProject() {
220
238
 
221
239
  process.chdir(projectDir);
222
240
 
223
- // 3. Auth
224
241
  console.log(' [3/6] 🔑 Authenticating with Fleetbo Cloud...');
225
242
  const keys = await fetchProjectKeys(bootstrapTokenArg);
226
243
  if (!keys.enterpriseId) throw new Error("Invalid keys.");
227
244
 
228
- // 4. Environment & CLI Generation
229
245
  console.log(' [4/6] ⚙️ Configuring environment & CLI...');
230
- 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`;
246
+ let envContent = `REACT_APP_FLEETBO_DB_KEY=${keys.fleetboDBKey}\nREACT_APP_ENTERPRISE_ID=${keys.enterpriseId}\nREACT_KEY_APP=${projectName}\nDANGEROUSLY_DISABLE_HOST_CHECK=true\n`;
247
+ if (ngrokTokenArg) {
248
+ console.log(' ✅ Ngrok token injected into .env');
249
+ envContent += `NGROK_AUTHTOKEN=${ngrokTokenArg}\n`;
250
+ } else {
251
+ console.log(' ℹ️ No Ngrok token provided. Assuming global config.');
252
+ }
231
253
  fs.writeFileSync(path.join(projectDir, '.env'), envContent, 'utf8');
232
254
  fs.writeFileSync(path.join(projectDir, 'cli.js'), CLI_SCRIPT_CONTENT, 'utf8');
233
255
 
234
- // 5. Deps
235
256
  console.log(' [5/6] 📚 Installing dependencies...');
236
257
  execSync('npm install', { stdio: 'inherit' });
237
258
  execSync('npm install ngrok dotenv axios --save-dev', { stdio: 'ignore' });
238
259
 
239
- // 6. Finalize
240
260
  console.log(' [6/6] ✨ Finalizing setup...');
241
261
  const packageJsonPath = path.join(projectDir, 'package.json');
242
262
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
@@ -244,7 +264,7 @@ async function setupProject() {
244
264
  packageJson.scripts = { ...packageJson.scripts, "fleetbo": "node cli.js", "dev": "node cli.js" };
245
265
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
246
266
 
247
- console.log('\n [Fleetbo] Project successfully created!');
267
+ console.log('\n [Fleetbo] Project successfully created!');
248
268
  console.log(`\n👉 Run: cd ${projectName} && npm run fleetbo`);
249
269
 
250
270
  } catch (error) {
@@ -258,6 +278,8 @@ setupProject();
258
278
 
259
279
 
260
280
 
281
+
282
+
261
283
  {/*
262
284
 
263
285
  const { execSync } = require('child_process');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fleetbo-project",
3
- "version": "1.2.13",
3
+ "version": "1.2.17",
4
4
  "description": "Creates a new Fleetbo project.",
5
5
  "main": "install-react-template.js",
6
6
  "bin": {