UNPKG

fleetbo-cli

Version:

Creates a new Fleetbo project.

223 lines (188 loc) 9.42 kB
#!/usr/bin/env node // --- IMPORTS (Anciens + Nouveaux) --- const { execSync, spawn } = require('child_process'); // 'spawn' est ajouté const fs = require('fs'); const path = require('path'); const https = require('https'); const axios = require('axios'); // 'axios' est ajouté (plus propre que https) const inquirer = require('inquirer'); // 'inquirer' est ajouté const dotenv = require('dotenv'); // 'dotenv' est ajouté // --- URLs de vos Cloud Functions --- const BOOTSTRAP_URL = 'https://us-central1-myapp-259bf.cloudfunctions.net/bootstrapProject'; // Mettez à jour avec vos vraies URLs de déploiement const CHECK_ACCESS_URL = 'https://us-central1-myapp-259bf.cloudfunctions.net/checkDeveloperAccess'; const UPDATE_NETWORK_URL = 'https://us-central1-myapp-259bf.cloudfunctions.net/updateDeveloperNetwork'; // --- LE ROUTEUR --- // Il décide quelle fonction lancer const args = process.argv.slice(2); const command = args[0]; // ex: 'start' ou 'mon-projet' if (command === 'start') { runGuardian(); // Lancer le "gardien" } else { // Si ce n'est pas 'start', on suppose que c'est une installation. // L'ancienne logique 'setupProject' sera appelée. setupProject(args); } // ========================================================== // FONCTION 1: LE "GARDIEN" (Nouveau code pour `fleetbo start`) // ========================================================== async function runGuardian() { console.log('[Fleetbo] Lancement du serveur de développement...'); // 1. Charger le fichier .env du PROJET UTILISATEUR const envPath = path.join(process.cwd(), '.env'); if (!fs.existsSync(envPath)) { console.error('Erreur: Fichier .env introuvable.'); console.error('Veuillez lancer "fleetbo start" à la racine de votre projet Fleetbo.'); process.exit(1); } dotenv.config({ path: envPath }); // Charge les variables de .env const enterpriseId = process.env.REACT_APP_ENTERPRISE_ID; if (!enterpriseId) { console.error('Erreur: REACT_APP_ENTERPRISE_ID est manquant dans votre .env.'); process.exit(1); } // 2. Demander l'e-mail const answers = await inquirer.prompt([ { type: 'input', name: 'email', message: 'Veuillez entrer votre e-mail (admin/testeur) :' } ]); const email = answers.email.trim(); // 3. Vérifier l'accès via la Cloud Function (SÉCURISÉ) try { console.log(`Vérification de l'accès pour ${email}...`); // APPEL SÉCURISÉ await axios.post(CHECK_ACCESS_URL, { email: email, enterpriseId: enterpriseId }); console.log('Accès autorisé. Démarrage du serveur...'); } catch (error) { console.error('\nAccès refusé.'); if (error.response && error.response.data) { console.error(`Raison: ${error.response.data.error}`); } else { console.error(error.message); } process.exit(1); } // 4. Lancer "npm start" (du package.json local de l'utilisateur) // Le template 'dev.fleetbo.io' doit avoir "start": "react-scripts start" const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'; const child = spawn(npmCmd, ['start'], { stdio: ['inherit', 'pipe', 'inherit'] }); // 5. Capturer l'URL du réseau child.stdout.on('data', (data) => { const output = data.toString(); process.stdout.write(output); // Relayer la sortie pour que l'utilisateur la voie const regex = /On Your Network:\s+(http:\/\/[^\s]+)/; const match = output.match(regex); if (match && match[1]) { const networkUrl = match[1]; console.log(`\n[Fleetbo] URL réseau capturée : ${networkUrl}`); // 6. Mettre à jour Firestore via Cloud Function (en "fire-and-forget") axios.post(UPDATE_NETWORK_URL, { enterpriseId: enterpriseId, networkUrl: networkUrl }).catch(err => { // Pas critique si ça échoue, on affiche juste un avertissement console.warn('[Fleetbo] Avertissement: Impossible de mettre à jour l\'URL réseau.', err.message); }); } }); } // ================================================================= // FONCTION 2: L'"INSTALLATEUR" (Votre code existant, adapté) // ================================================================= // On passe 'args' à la fonction async function setupProject(installerArgs) { // --- Configuration de l'Installateur (Votre code) --- const repoOwner = 'FleetFleetbo'; const repoName = 'dev.fleetbo.io'; const branchName = 'master'; const repoGitUrl = `https://github.com/${repoOwner}/${repoName}.git`; // bootstrapUrl est déjà défini en haut // --- Analyse des Arguments (Adapté) --- // On utilise 'installerArgs' au lieu de 'process.argv.slice(2)' const projectNameArg = installerArgs.find(arg => !arg.startsWith('--')); const tokenArg = installerArgs.find(arg => arg.startsWith('--token=')); // Le reste de vos vérifications est parfait if (!projectNameArg) { console.error('\n Error : Please specify a name for your project.'); console.log(' Usage: npx fleetbo <nom-du-projet> --token=<votre-token>'); // 'create-fleetbo-project' devient 'fleetbo' process.exit(1); } const bootstrapToken = tokenArg ? tokenArg.split('=')[1] : null; if (!bootstrapToken) { console.error('\n Error : "The bootstrap token is missing.'); console.log(' Usage: npx fleetbo <nom-du-projet> --token=<votre-token>'); process.exit(1); } const projectName = projectNameArg; // --- Fonction Principale (Votre code, inchangé) --- console.log(`\nCreating your Fleetbo project "${projectName}"...`); const projectDir = path.join(process.cwd(), projectName); try { // Étape 1 : Télécharger console.log(' [1/5] Initializing project structure...'); execSync(`git clone --depth 1 --branch ${branchName} ${repoGitUrl} "${projectName}" 2> /dev/null`); // Étape 2 : Nettoyer console.log(' [2/5] Project structure initialized. Configuring...'); process.chdir(projectDir); fs.rmSync(path.join(projectDir, '.git'), { recursive: true, force: true }); // Étape 3 : Récupération des clés (utilise 'fetchProjectKeys' ci-dessous) console.log(' [3/5] Fetching project keys...'); const keys = await fetchProjectKeys(bootstrapToken); if (!keys.enterpriseId || !keys.fleetboDBKey) { throw new Error("Received keys from the server are invalid."); } // Étape 4 : Configuration du .env console.log(' [4/5] .env file configured successfully.'); const envContent = `REACT_APP_FLEETBO_DB_KEY=${keys.fleetboDBKey}\nREACT_APP_ENTERPRISE_ID=${keys.enterpriseId}\n`; // J'ai remis la variable enterpriseId fs.writeFileSync(path.join(projectDir, '.env'), envContent, 'utf8'); // Étape 5 : Installation console.log(' [5/5] Installing dependencies...'); execSync('npm install', { stdio: 'inherit' }); // Personnalisation const packageJsonPath = path.join(projectDir, 'package.json'); const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); packageJson.name = projectName; fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8'); console.log('\n🚀 Your Fleetbo project is ready !'); console.log(`\nTo get started, run the following commands :`); console.log(` cd ${projectName}`); console.log(` npx fleetbo start`); // <-- CHANGEMENT IMPORTANT ! } catch (error) { console.error('\n An error occurred while creating the project :', error.message); if (fs.existsSync(projectDir)) { fs.rmSync(projectDir, { recursive: true, force: true }); } } } // --- Fonctions Utilitaires (Votre code, inchangé) --- function fetchProjectKeys(token) { return new Promise((resolve, reject) => { const postData = JSON.stringify({ token }); const options = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) } }; // 'bootstrapUrl' est défini en haut const req = https.request(BOOTSTRAP_URL, options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { if (res.statusCode >= 200 && res.statusCode < 300) { try { // On log les clés pour le debug const parsedData = JSON.parse(data); console.log('Keys received:', parsedData); resolve(parsedData); } catch (e) { reject(new Error('Invalid response from the key server.')); } } else { const errorMsg = JSON.parse(data).error || `Server error (code: ${res.statusCode})`; reject(new Error(errorMsg)); } }); }); req.on('error', (e) => reject(e)); req.write(postData); req.end(); }); }