#!/usr/bin/env node const N8N_URL = process.env.N8N_URL || 'https://n8n.airtria.pro'; const N8N_API_KEY = process.env.N8N_API_KEY; const WORKFLOW_ID = process.env.WORKFLOW_ID || 'ATswvGfG4KJUls0K'; if (!N8N_API_KEY) { console.error('❌ Erreur: N8N_API_KEY non défini'); console.error(' Exportez la variable: export N8N_API_KEY="votre_token"'); process.exit(1); } const headers = { 'X-N8N-API-KEY': N8N_API_KEY, 'Content-Type': 'application/json' }; async function main() { console.log('=== Test PUT workflow n8n ===\n'); console.log(`URL: ${N8N_URL}/api/v1/workflows/${WORKFLOW_ID}`); console.log(`Workflow ID: ${WORKFLOW_ID}\n`); // 1. Lire le workflow console.log('1️⃣ Lecture du workflow via GET...'); let getResponse; try { getResponse = await fetch(`${N8N_URL}/api/v1/workflows/${WORKFLOW_ID}`, { method: 'GET', headers }); } catch (err) { console.error('❌ Erreur réseau GET:', err.message); process.exit(1); } if (!getResponse.ok) { console.error(`❌ GET échoué: ${getResponse.status} ${getResponse.statusText}`); const text = await getResponse.text(); console.error('Réponse:', text); process.exit(1); } const workflow = await getResponse.json(); console.log(`✅ Workflow lu: "${workflow.name}" (${workflow.nodes?.length || 0} nodes)`); // 2. Sauvegarde locale const backupPath = `./backup-workflow-${WORKFLOW_ID}-${Date.now()}.json`; console.log(`\n2️⃣ Sauvegarde locale: ${backupPath}`); const fs = await import('fs'); fs.writeFileSync(backupPath, JSON.stringify(workflow, null, 2)); console.log('✅ Backup créé'); // 3. Reconstruire body propre (settings minimal) const body = { name: workflow.name, nodes: workflow.nodes, connections: workflow.connections, settings: { executionOrder: workflow.settings?.executionOrder || 'v1', callerPolicy: workflow.settings?.callerPolicy || 'workflowsFromSameOwner' }, staticData: workflow.staticData }; console.log('\n3️⃣ Body reconstruit (champs inclus):'); console.log(' - name:', body.name); console.log(' - nodes:', body.nodes?.length || 0); console.log(' - connections:', body.connections ? 'présent' : 'absent'); console.log(' - settings:', JSON.stringify(body.settings)); console.log(' - staticData:', body.staticData ? 'présent' : 'absent'); // 4. Appliquer les corrections console.log('\n4️⃣ Application des corrections...'); // Trouver le node BATTERY_CLOUD_LOCKS const batteryCloudLocksNode = body.nodes.find(n => n.name === 'BATTERY_CLOUD_LOCKS'); if (!batteryCloudLocksNode) { console.error('❌ Node BATTERY_CLOUD_LOCKS non trouvé'); process.exit(1); } let jsCode = batteryCloudLocksNode.parameters.jsCode; // Fix 1: gridAllowedBySoc - ajouter context.profile === 'night_hc' const fix1Old = 'const gridAllowedBySoc = parsed.soc <= 35 || strategy.forceGridRequested;'; const fix1New = `const gridAllowedBySoc = strategy.forceGridRequested || context.profile === 'night_hc' || parsed.soc <= 35;`; if (jsCode.includes(fix1Old)) { jsCode = jsCode.replace(fix1Old, fix1New); console.log(' ✅ Fix 1 appliqué: gridAllowedBySoc'); } else { console.log(' ⚠️ Fix 1: pattern non trouvé (déjà appliqué?)'); } // Fix 2: nightTakeoverLatched - libérer quand charge terminée (soc >= 50) const fix2Old = `const nightTakeoverLatched = nightSessionActive && nightTakeoverPrev && parsed.soc < NIGHT_TAKEOVER_RELEASE_SOC_PCT;`; const fix2New = `const vehicleChargeCompleted = !parsed.evcsChargingSwitchOn && parsed.soc >= 50; const nightTakeoverLatched = nightSessionActive && nightTakeoverPrev && ( parsed.soc < NIGHT_TAKEOVER_RELEASE_SOC_PCT || vehicleChargeCompleted );`; if (jsCode.includes(fix2Old)) { jsCode = jsCode.replace(fix2Old, fix2New); console.log(' ✅ Fix 2 appliqué: nightTakeoverLatched'); } else { console.log(' ⚠️ Fix 2: pattern non trouvé (déjà appliqué?)'); } batteryCloudLocksNode.parameters.jsCode = jsCode; // 5. Tenter PUT console.log('\n5️⃣ Tentative PUT...'); let putResponse; try { putResponse = await fetch(`${N8N_URL}/api/v1/workflows/${WORKFLOW_ID}`, { method: 'PUT', headers, body: JSON.stringify(body) }); } catch (err) { console.error('❌ Erreur réseau PUT:', err.message); process.exit(1); } const putStatus = putResponse.status; const putStatusText = putResponse.statusText; const putResponseText = await putResponse.text(); console.log(`\n📊 Résultat PUT:`); console.log(` Status: ${putStatus} ${putStatusText}`); if (putResponse.ok) { console.log('✅ PUT réussi!'); const putJson = JSON.parse(putResponseText); console.log(` Workflow mis à jour: "${putJson.name}"`); } else { console.log('❌ PUT REFUSÉ par n8n'); console.log('\n📄 Erreur exacte:'); try { const errorJson = JSON.parse(putResponseText); console.log(JSON.stringify(errorJson, null, 2)); } catch { console.log(putResponseText); } } } main();