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.
@@ -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
- console.error('\n ❌ Error : Please specify a name for your project.');
25
- console.log(' Usage: npx create-fleetbo-project <project-name> --token=<your-token>');
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
- resolve(JSON.parse(data));
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
- const newUrl = response.headers.location;
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('finish', () => {
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
- // Étape 1 : Téléchargement
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
- // Étape 2 : Extraction
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
- // Étape 3 : Authentification
177
+ // 3. Auth
146
178
  console.log(' [3/6] 🔑 Authenticating with Fleetbo Cloud...');
147
- const keys = await fetchProjectKeys(bootstrapToken);
148
- if (!keys.enterpriseId || !keys.fleetboDBKey) {
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
- // Étape 4 : Environnement
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
- // Étape 5 : Dépendances
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
- // Étape 6 : Finalisation
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👉 Get started with:`);
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fleetbo-project",
3
- "version": "1.2.10",
3
+ "version": "1.2.11",
4
4
  "description": "Creates a new Fleetbo project.",
5
5
  "main": "install-react-template.js",
6
6
  "bin": {