create-fleetbo-project 1.2.17 → 1.2.19
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 +47 -81
- package/package.json +1 -1
|
@@ -12,47 +12,40 @@ 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
|
|
15
|
+
// --- LE GARDIEN CLOUDFLARE (Version Production Silencieuse) ---
|
|
16
16
|
const CLI_SCRIPT_CONTENT = `#!/usr/bin/env node
|
|
17
17
|
|
|
18
|
-
const { spawn,
|
|
18
|
+
const { spawn, execSync } = require('child_process');
|
|
19
19
|
const fs = require('fs');
|
|
20
20
|
const path = require('path');
|
|
21
21
|
const axios = require('axios');
|
|
22
22
|
const dotenv = require('dotenv');
|
|
23
|
-
const ngrok = require('ngrok');
|
|
24
23
|
const os = require('os');
|
|
25
24
|
|
|
26
25
|
const UPDATE_NETWORK_URL = 'https://us-central1-myapp-259bf.cloudfunctions.net/updateDeveloperNetwork';
|
|
27
|
-
const PORT = 3000;
|
|
28
|
-
const NGROK_PORT = 4040;
|
|
26
|
+
const PORT = 3000;
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// Tueur de processus générique par port
|
|
28
|
+
// Nettoyage des ports (Mac/Linux)
|
|
33
29
|
function killProcessOnPort(port) {
|
|
34
30
|
try {
|
|
35
31
|
if (process.platform !== 'win32') {
|
|
36
32
|
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
|
-
}
|
|
33
|
+
if (pid) execSync(\`kill -9 \${pid.split('\\n').join(' ')} 2>/dev/null\`);
|
|
42
34
|
}
|
|
43
35
|
} catch (e) {}
|
|
44
36
|
}
|
|
45
37
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
// Nettoyage spécifique Cloudflare
|
|
39
|
+
function killCloudflared() {
|
|
40
|
+
try {
|
|
41
|
+
const cmd = process.platform === 'win32' ? 'taskkill /IM cloudflared.exe /F' : 'pkill cloudflared';
|
|
42
|
+
execSync(cmd + ' 2>/dev/null');
|
|
43
|
+
} catch (e) {}
|
|
51
44
|
}
|
|
52
45
|
|
|
53
46
|
async function cleanupAndExit(code = 0) {
|
|
54
47
|
console.log('\\n[Fleetbo] 🛑 Stopping services...');
|
|
55
|
-
|
|
48
|
+
killCloudflared();
|
|
56
49
|
killProcessOnPort(PORT);
|
|
57
50
|
process.exit(code);
|
|
58
51
|
}
|
|
@@ -62,13 +55,10 @@ process.on('SIGTERM', () => cleanupAndExit(0));
|
|
|
62
55
|
|
|
63
56
|
async function syncFirebase(keyApp, networkUrl) {
|
|
64
57
|
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.
|
|
67
58
|
await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl });
|
|
68
59
|
console.log('\\n[Fleetbo] ---------------------------------------------------');
|
|
69
60
|
console.log(\`[Fleetbo] ✅ Tunnel Active: \${networkUrl}\`);
|
|
70
|
-
console.log(\`[Fleetbo] 🚀
|
|
71
|
-
console.log(\`[Fleetbo] 🔑 Credentials: User="fleetbo", Pass="admin"\`); // RAPPEL POUR LE DEV
|
|
61
|
+
console.log(\`[Fleetbo] 🚀 Emulator: https://fleetbo.io/studio/view/\${keyApp}\`);
|
|
72
62
|
console.log('[Fleetbo] ---------------------------------------------------\\n');
|
|
73
63
|
} catch (err) {
|
|
74
64
|
console.error(\`[Fleetbo] ⚠️ Sync Error: \${err.message}\`);
|
|
@@ -78,11 +68,9 @@ async function syncFirebase(keyApp, networkUrl) {
|
|
|
78
68
|
async function runGuardian() {
|
|
79
69
|
console.log(\`[Fleetbo] 🛡️ Starting Fleetbo Guardian on \${os.platform()}...\`);
|
|
80
70
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
killProcessOnPort(NGROK_PORT);
|
|
71
|
+
// 1. NETTOYAGE PRÉVENTIF
|
|
72
|
+
killCloudflared();
|
|
84
73
|
killProcessOnPort(PORT);
|
|
85
|
-
await sleep(1000);
|
|
86
74
|
|
|
87
75
|
const envPath = path.join(process.cwd(), '.env');
|
|
88
76
|
if (!fs.existsSync(envPath)) {
|
|
@@ -90,18 +78,10 @@ async function runGuardian() {
|
|
|
90
78
|
process.exit(1);
|
|
91
79
|
}
|
|
92
80
|
dotenv.config({ path: envPath });
|
|
93
|
-
|
|
94
81
|
const keyApp = process.env.REACT_KEY_APP;
|
|
95
|
-
const authToken = process.env.NGROK_AUTHTOKEN;
|
|
96
|
-
|
|
97
|
-
if (authToken) {
|
|
98
|
-
try {
|
|
99
|
-
await ngrok.authtoken(authToken);
|
|
100
|
-
await sleep(500);
|
|
101
|
-
} catch (e) {}
|
|
102
|
-
}
|
|
103
82
|
|
|
104
|
-
|
|
83
|
+
// 2. DÉMARRAGE REACT
|
|
84
|
+
console.log(\`[Fleetbo] 📦 Booting React Server...\`);
|
|
105
85
|
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
106
86
|
|
|
107
87
|
const devServer = spawn(npmCmd, ['start'], {
|
|
@@ -114,37 +94,33 @@ async function runGuardian() {
|
|
|
114
94
|
|
|
115
95
|
let tunnelStarted = false;
|
|
116
96
|
|
|
117
|
-
devServer.stdout.on('data',
|
|
97
|
+
devServer.stdout.on('data', (data) => {
|
|
118
98
|
const output = data.toString();
|
|
119
99
|
|
|
120
100
|
if (!tunnelStarted && (output.includes('Local:') || output.includes('Compiled successfully'))) {
|
|
121
101
|
tunnelStarted = true;
|
|
122
|
-
console.log(\`\\n[Fleetbo] 🔗 React is ready.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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>'");
|
|
102
|
+
console.log(\`\\n[Fleetbo] 🔗 React is ready. Establishing secure tunnel...\`);
|
|
103
|
+
|
|
104
|
+
// 3. DÉMARRAGE TUNNEL CLOUDFLARE (via npm exec pour la compatibilité)
|
|
105
|
+
const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
106
|
+
const tunnel = spawn(npxCmd, ['cloudflared', 'tunnel', '--url', \`http://localhost:\${PORT}\`]);
|
|
107
|
+
|
|
108
|
+
// Capture de l'URL dans les logs
|
|
109
|
+
tunnel.stderr.on('data', (chunk) => {
|
|
110
|
+
const log = chunk.toString();
|
|
111
|
+
const match = log.match(/https:\/\/[a-zA-Z0-9-]+\.trycloudflare\.com/);
|
|
112
|
+
if (match) {
|
|
113
|
+
const url = match[0];
|
|
114
|
+
if (global.currentUrl !== url) {
|
|
115
|
+
global.currentUrl = url;
|
|
116
|
+
syncFirebase(keyApp, url);
|
|
145
117
|
}
|
|
146
118
|
}
|
|
147
|
-
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
tunnel.on('error', (err) => {
|
|
122
|
+
console.error("[Fleetbo] ❌ Tunnel Error. Ensure 'cloudflared' is installed.");
|
|
123
|
+
});
|
|
148
124
|
}
|
|
149
125
|
});
|
|
150
126
|
}
|
|
@@ -157,11 +133,9 @@ const args = process.argv.slice(2);
|
|
|
157
133
|
const projectNameArg = args.find(arg => !arg.startsWith('--'));
|
|
158
134
|
const tokenArg = args.find(arg => arg.startsWith('--token='));
|
|
159
135
|
const bootstrapTokenArg = tokenArg ? tokenArg.split('=')[1] : null;
|
|
160
|
-
const ngrokArg = args.find(arg => arg.startsWith('--ngrok='));
|
|
161
|
-
const ngrokTokenArg = ngrokArg ? ngrokArg.split('=')[1] : null;
|
|
162
136
|
|
|
163
137
|
if (!projectNameArg || !bootstrapTokenArg) {
|
|
164
|
-
console.error('\n ❌ Usage: npx create-fleetbo-project <name> --token=<
|
|
138
|
+
console.error('\n ❌ Usage: npx create-fleetbo-project <name> --token=<token>');
|
|
165
139
|
process.exit(1);
|
|
166
140
|
}
|
|
167
141
|
|
|
@@ -201,10 +175,7 @@ function downloadEngine(url, dest) {
|
|
|
201
175
|
};
|
|
202
176
|
const request = https.get(options, (response) => {
|
|
203
177
|
if (response.statusCode === 301 || response.statusCode === 302) {
|
|
204
|
-
if (!response.headers.location) {
|
|
205
|
-
reject(new Error("Redirect found but no location header"));
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
178
|
+
if (!response.headers.location) { reject(new Error("Redirect error")); return; }
|
|
208
179
|
downloadEngine(response.headers.location, dest).then(resolve).catch(reject);
|
|
209
180
|
return;
|
|
210
181
|
}
|
|
@@ -234,7 +205,7 @@ async function setupProject() {
|
|
|
234
205
|
try {
|
|
235
206
|
execSync(`tar -xf "${archivePath}" -C "${projectDir}" --strip-components=1`, { stdio: 'ignore' });
|
|
236
207
|
fs.unlinkSync(archivePath);
|
|
237
|
-
} catch (e) { throw new Error("
|
|
208
|
+
} catch (e) { throw new Error("Extract failed."); }
|
|
238
209
|
|
|
239
210
|
process.chdir(projectDir);
|
|
240
211
|
|
|
@@ -243,19 +214,17 @@ async function setupProject() {
|
|
|
243
214
|
if (!keys.enterpriseId) throw new Error("Invalid keys.");
|
|
244
215
|
|
|
245
216
|
console.log(' [4/6] ⚙️ Configuring environment & CLI...');
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
envContent += `NGROK_AUTHTOKEN=${ngrokTokenArg}\n`;
|
|
250
|
-
} else {
|
|
251
|
-
console.log(' ℹ️ No Ngrok token provided. Assuming global config.');
|
|
252
|
-
}
|
|
217
|
+
// On force le host check pour la compatibilité tunnel
|
|
218
|
+
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`;
|
|
219
|
+
|
|
253
220
|
fs.writeFileSync(path.join(projectDir, '.env'), envContent, 'utf8');
|
|
254
221
|
fs.writeFileSync(path.join(projectDir, 'cli.js'), CLI_SCRIPT_CONTENT, 'utf8');
|
|
255
222
|
|
|
256
223
|
console.log(' [5/6] 📚 Installing dependencies...');
|
|
257
224
|
execSync('npm install', { stdio: 'inherit' });
|
|
258
|
-
|
|
225
|
+
|
|
226
|
+
// Installation de cloudflared
|
|
227
|
+
execSync('npm install cloudflared dotenv axios --save-dev', { stdio: 'ignore' });
|
|
259
228
|
|
|
260
229
|
console.log(' [6/6] ✨ Finalizing setup...');
|
|
261
230
|
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
@@ -277,9 +246,6 @@ async function setupProject() {
|
|
|
277
246
|
setupProject();
|
|
278
247
|
|
|
279
248
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
249
|
{/*
|
|
284
250
|
|
|
285
251
|
const { execSync } = require('child_process');
|