create-fleetbo-project 1.2.12 → 1.2.14

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.
@@ -12,10 +12,10 @@ const branchName = 'master';
12
12
  const archiveUrl = `https://github.com/${repoOwner}/${repoName}/archive/refs/heads/${branchName}.tar.gz`;
13
13
  const bootstrapUrl = 'https://us-central1-myapp-259bf.cloudfunctions.net/bootstrapProject';
14
14
 
15
- // --- LE CONTENU DU GARDIEN (Injecté dynamiquement) ---
15
+ // --- LE CONTENU DU GARDIEN (CLI.JS) - VERSION BLINDÉE ---
16
16
  const CLI_SCRIPT_CONTENT = `#!/usr/bin/env node
17
17
 
18
- const { spawn } = require('child_process');
18
+ const { spawn, exec } = require('child_process');
19
19
  const fs = require('fs');
20
20
  const path = require('path');
21
21
  const axios = require('axios');
@@ -26,9 +26,19 @@ const os = require('os');
26
26
  const UPDATE_NETWORK_URL = 'https://us-central1-myapp-259bf.cloudfunctions.net/updateDeveloperNetwork';
27
27
  const PORT = 3000;
28
28
 
29
+ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
30
+
31
+ // 1. NETTOYAGE VIOLENT (Anti-Zombie)
32
+ async function forceKillNgrok() {
33
+ return new Promise((resolve) => {
34
+ const cmd = process.platform === 'win32' ? 'taskkill /IM ngrok.exe /F' : 'pkill ngrok';
35
+ exec(cmd, () => resolve());
36
+ });
37
+ }
38
+
29
39
  async function cleanupAndExit(code = 0) {
30
- console.log('\\n[Fleetbo] 🛑 Shutting down services...');
31
- try { await ngrok.kill(); } catch (e) {}
40
+ console.log('\\n[Fleetbo] 🛑 Stopping React...');
41
+ try { await ngrok.kill(); } catch(e){}
32
42
  process.exit(code);
33
43
  }
34
44
 
@@ -50,6 +60,11 @@ async function syncFirebase(keyApp, networkUrl) {
50
60
  async function runGuardian() {
51
61
  console.log(\`[Fleetbo] 🛡️ Starting Fleetbo Guardian on \${os.platform()}...\`);
52
62
 
63
+ // 2. NETTOYAGE AU DÉMARRAGE
64
+ console.log(\`[Fleetbo] 🧹 Cleaning up...\`);
65
+ await forceKillNgrok();
66
+ await sleep(1000);
67
+
53
68
  const envPath = path.join(process.cwd(), '.env');
54
69
  if (!fs.existsSync(envPath)) {
55
70
  console.error('Error: .env file not found.');
@@ -58,6 +73,15 @@ async function runGuardian() {
58
73
  dotenv.config({ path: envPath });
59
74
 
60
75
  const keyApp = process.env.REACT_KEY_APP;
76
+ const authToken = process.env.NGROK_AUTHTOKEN;
77
+
78
+ // 3. AUTHENTIFICATION (Si token présent dans .env, sinon Global)
79
+ if (authToken) {
80
+ try {
81
+ await ngrok.authtoken(authToken);
82
+ await sleep(1000);
83
+ } catch (e) {}
84
+ }
61
85
 
62
86
  console.log(\`[Fleetbo] 📦 Booting React Server...\`);
63
87
  const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
@@ -74,23 +98,34 @@ async function runGuardian() {
74
98
 
75
99
  devServer.stdout.on('data', async (data) => {
76
100
  const output = data.toString();
101
+
77
102
  if (!tunnelStarted && (output.includes('Local:') || output.includes('Compiled successfully'))) {
78
103
  tunnelStarted = true;
79
- console.log(\`\\n[Fleetbo] 🔗 React is ready. Opening secure tunnel...\`);
104
+ console.log(\`\\n[Fleetbo] 🔗 React is ready. Initiating Tunnel...\`);
80
105
 
81
106
  try {
82
- const url = await ngrok.connect({ addr: PORT });
107
+ // 4. CONNEXION AVEC NOM UNIQUE (Évite les collisions)
108
+ const url = await ngrok.connect({
109
+ addr: PORT,
110
+ name: \`fleetbo_\${Date.now()}\` // <--- CRUCIAL
111
+ });
83
112
  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('-------------------------------------------------------');
113
+ } catch (firstErr) {
114
+ // 5. RETRY LOGIC
115
+ try {
116
+ await sleep(2000);
117
+ const urlRetry = await ngrok.connect({
118
+ addr: PORT,
119
+ name: \`fleetbo_retry_\${Date.now()}\`
120
+ });
121
+ await syncFirebase(keyApp, urlRetry);
122
+ } catch (finalErr) {
123
+ console.error('\\n[Fleetbo] ❌ NGROK ERROR');
124
+ console.error("Message:", finalErr.message);
125
+ if (finalErr.message.includes('ERR_NGROK_4018')) {
126
+ console.error("👉 Add NGROK_AUTHTOKEN=... to your .env file OR run 'npx ngrok config add-authtoken <TOKEN>'");
127
+ }
92
128
  }
93
- cleanupAndExit(1);
94
129
  }
95
130
  }
96
131
  });
@@ -102,11 +137,17 @@ runGuardian();
102
137
  // --- Analyse des Arguments ---
103
138
  const args = process.argv.slice(2);
104
139
  const projectNameArg = args.find(arg => !arg.startsWith('--'));
140
+
141
+ // Argument Token Fleetbo
105
142
  const tokenArg = args.find(arg => arg.startsWith('--token='));
106
143
  const bootstrapTokenArg = tokenArg ? tokenArg.split('=')[1] : null;
107
144
 
145
+ // --- NOUVEAU : Argument Token Ngrok (Optionnel) ---
146
+ const ngrokArg = args.find(arg => arg.startsWith('--ngrok='));
147
+ const ngrokTokenArg = ngrokArg ? ngrokArg.split('=')[1] : null;
148
+
108
149
  if (!projectNameArg || !bootstrapTokenArg) {
109
- console.error('\n ❌ Usage: npx create-fleetbo-project <project-name> --token=<your-token>');
150
+ console.error('\n ❌ Usage: npx create-fleetbo-project <name> --token=<fleetbo-token> [--ngrok=<ngrok-token>]');
110
151
  process.exit(1);
111
152
  }
112
153
 
@@ -118,8 +159,17 @@ const projectDir = path.join(process.cwd(), projectName);
118
159
  function fetchProjectKeys(token) {
119
160
  return new Promise((resolve, reject) => {
120
161
  const postData = JSON.stringify({ token });
121
- const options = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) } };
122
- const req = https.request(bootstrapUrl, options, (res) => {
162
+ const uri = new URL(bootstrapUrl);
163
+ const options = {
164
+ hostname: uri.hostname,
165
+ path: uri.pathname,
166
+ method: 'POST',
167
+ headers: {
168
+ 'Content-Type': 'application/json',
169
+ 'Content-Length': Buffer.byteLength(postData)
170
+ }
171
+ };
172
+ const req = https.request(options, (res) => {
123
173
  let data = '';
124
174
  res.on('data', (chunk) => { data += chunk; });
125
175
  res.on('end', () => {
@@ -136,18 +186,49 @@ function fetchProjectKeys(token) {
136
186
 
137
187
  function downloadEngine(url, dest) {
138
188
  return new Promise((resolve, reject) => {
139
- const request = https.get(url, (response) => {
189
+ const uri = new URL(url);
190
+ const options = {
191
+ hostname: uri.hostname,
192
+ path: uri.pathname + uri.search,
193
+ method: 'GET',
194
+ headers: {
195
+ 'User-Agent': 'Fleetbo-CLI-Installer',
196
+ 'Accept': '*/*'
197
+ }
198
+ };
199
+
200
+ const request = https.get(options, (response) => {
140
201
  if (response.statusCode === 301 || response.statusCode === 302) {
202
+ if (!response.headers.location) {
203
+ reject(new Error("Redirect found but no location header"));
204
+ return;
205
+ }
141
206
  downloadEngine(response.headers.location, dest).then(resolve).catch(reject);
142
207
  return;
143
208
  }
144
- if (response.statusCode !== 200) { reject(new Error(`Status: ${response.statusCode}`)); return; }
209
+
210
+ if (response.statusCode !== 200) {
211
+ reject(new Error(`Failed to download (Status: ${response.statusCode})`));
212
+ return;
213
+ }
214
+
145
215
  const file = fs.createWriteStream(dest);
146
216
  response.pipe(file);
147
- file.on('finish', () => file.close(resolve));
148
- file.on('error', (err) => { fs.unlink(dest, () => {}); reject(err); });
217
+
218
+ file.on('finish', () => {
219
+ file.close(resolve);
220
+ });
221
+
222
+ file.on('error', (err) => {
223
+ fs.unlink(dest, () => {});
224
+ reject(err);
225
+ });
226
+ });
227
+
228
+ request.on('error', (err) => {
229
+ fs.unlink(dest, () => {});
230
+ reject(err);
149
231
  });
150
- request.on('error', (err) => reject(err));
151
232
  });
152
233
  }
153
234
 
@@ -180,14 +261,27 @@ async function setupProject() {
180
261
 
181
262
  // 4. Environment & CLI Generation
182
263
  console.log(' [4/6] ⚙️ Configuring environment & CLI...');
183
- 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`;
264
+
265
+ // --- CRÉATION DU .ENV ---
266
+ let envContent = `REACT_APP_FLEETBO_DB_KEY=${keys.fleetboDBKey}\n`;
267
+ envContent += `REACT_APP_ENTERPRISE_ID=${keys.enterpriseId}\n`;
268
+ envContent += `REACT_KEY_APP=${projectName}\n`;
269
+ envContent += `DANGEROUSLY_DISABLE_HOST_CHECK=true\n`;
270
+
271
+ // Ajout conditionnel du token Ngrok
272
+ if (ngrokTokenArg) {
273
+ console.log(' ✅ Ngrok token injected into .env');
274
+ envContent += `NGROK_AUTHTOKEN=${ngrokTokenArg}\n`;
275
+ } else {
276
+ console.log(' ℹ️ No Ngrok token provided. Assuming global config.');
277
+ }
278
+
184
279
  fs.writeFileSync(path.join(projectDir, '.env'), envContent, 'utf8');
185
280
  fs.writeFileSync(path.join(projectDir, 'cli.js'), CLI_SCRIPT_CONTENT, 'utf8');
186
281
 
187
282
  // 5. Deps
188
283
  console.log(' [5/6] 📚 Installing dependencies...');
189
284
  execSync('npm install', { stdio: 'inherit' });
190
- // AJOUT DE AXIOS ICI
191
285
  execSync('npm install ngrok dotenv axios --save-dev', { stdio: 'ignore' });
192
286
 
193
287
  // 6. Finalize
@@ -198,7 +292,7 @@ async function setupProject() {
198
292
  packageJson.scripts = { ...packageJson.scripts, "fleetbo": "node cli.js", "dev": "node cli.js" };
199
293
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
200
294
 
201
- console.log('\n✅ Project successfully created!');
295
+ console.log('\n [Fleetbo] ✅ Project successfully created!');
202
296
  console.log(`\n👉 Run: cd ${projectName} && npm run fleetbo`);
203
297
 
204
298
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fleetbo-project",
3
- "version": "1.2.12",
3
+ "version": "1.2.14",
4
4
  "description": "Creates a new Fleetbo project.",
5
5
  "main": "install-react-template.js",
6
6
  "bin": {