import dotenv from 'dotenv'; // Load root .env first dotenv.config({ path: '/Volumes/sms/edtech/.env' }); const { R2_ACCOUNT_ID, R2_BUCKET, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_PUBLIC_URL } = process.env; // ── Fast fail: show config status first ────────────────────────────────────── console.log('\n📋 R2 Config Check:'); console.log(` R2_ACCOUNT_ID: ${R2_ACCOUNT_ID ? '✅ ' + R2_ACCOUNT_ID : '❌ MISSING'}`); console.log(` R2_BUCKET: ${R2_BUCKET ? '✅ ' + R2_BUCKET : '❌ MISSING'}`); console.log(` R2_ACCESS_KEY_ID: ${R2_ACCESS_KEY_ID ? '✅ SET' : '❌ MISSING'}`); console.log(` R2_SECRET_ACCESS_KEY:${R2_SECRET_ACCESS_KEY ? '✅ SET' : '❌ MISSING'}`); console.log(` R2_PUBLIC_URL: ${R2_PUBLIC_URL ? '✅ ' + R2_PUBLIC_URL : '❌ MISSING'}`); if (!R2_ACCOUNT_ID || !R2_BUCKET || !R2_ACCESS_KEY_ID || !R2_SECRET_ACCESS_KEY || !R2_PUBLIC_URL) { console.error('\n❌ Missing R2 credentials. Add these to /Volumes/sms/edtech/.env:'); console.error('\n R2_ACCOUNT_ID='); console.error(' R2_BUCKET='); console.error(' R2_ACCESS_KEY_ID='); console.error(' R2_SECRET_ACCESS_KEY='); console.error(' R2_PUBLIC_URL=https://r2.xamle.sn'); console.error('\n Find them on: dash.cloudflare.com → R2 → Manage R2 API Tokens'); process.exit(1); } import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; import fs from 'fs'; import path from 'path'; const ARTIFACTS_DIR = '/Users/macbookair/.gemini/antigravity/brain/ea618d02-1ee0-47c1-a2b7-aed00a3604bc'; const IMAGE_MAP = [ { src: 'xaml_t1_j1_activity_1772065123770.png', dest: 'images/t1/bes1_activity.png' }, { src: 'xaml_t1_j1_5_remediation_1772065225648.png', dest: 'images/t1/bes1_5_remediation.png' }, { src: 'xaml_t1_j2_customer_1772065290030.png', dest: 'images/t1/bes2_customer.png' }, { src: 'xaml_t1_j3_problem_1772065392345.png', dest: 'images/t1/bes3_problem.png' }, { src: 'xaml_t1_j4_solution_1772065519438.png', dest: 'images/t1/bes4_solution.png' }, { src: 'xaml_t1_j5_differentiation_v2_1772065582075.png', dest: 'images/t1/bes5_differentiation.png' }, { src: 'xaml_t1_j6_pricing_v2_1772065655264.png', dest: 'images/t1/bes6_pricing.png' }, { src: 'xaml_t1_j7_channel_sales_v2_1772065752541.png', dest: 'images/t1/bes7_channel.png' }, { src: 'xaml_t1_j8_trust_1772065782385.png', dest: 'images/t1/bes8_trust.png' }, { src: 'xaml_t1_j9_pitch_1772065807317.png', dest: 'images/t1/bes9_pitch.png' }, { src: 'xaml_t1_j10_objections_1772065830459.png', dest: 'images/t1/bes10_objections.png' }, { src: 'xaml_t1_j11_plan_1772065894417.png', dest: 'images/t1/bes11_plan.png' }, { src: 'xaml_t1_j12_success_1772065982976.png', dest: 'images/t1/bes12_success.png' }, ]; async function main() { const { R2_ACCOUNT_ID, R2_BUCKET, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_PUBLIC_URL } = process.env; console.log('📋 R2 Config Check:'); console.log(' R2_ACCOUNT_ID:', R2_ACCOUNT_ID ? '✅ SET' : '❌ MISSING'); console.log(' R2_BUCKET:', R2_BUCKET ? `✅ ${R2_BUCKET}` : '❌ MISSING'); console.log(' R2_ACCESS_KEY_ID:', R2_ACCESS_KEY_ID ? '✅ SET' : '❌ MISSING'); console.log(' R2_SECRET_ACCESS_KEY:', R2_SECRET_ACCESS_KEY ? '✅ SET' : '❌ MISSING'); console.log(' R2_PUBLIC_URL:', R2_PUBLIC_URL || '❌ MISSING'); if (!R2_ACCOUNT_ID || !R2_BUCKET || !R2_ACCESS_KEY_ID || !R2_SECRET_ACCESS_KEY) { console.error('\n❌ Missing R2 environment variables. Stopping.'); process.exit(1); } const client = new S3Client({ region: 'auto', endpoint: `https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com`, credentials: { accessKeyId: R2_ACCESS_KEY_ID, secretAccessKey: R2_SECRET_ACCESS_KEY }, }); console.log('\n🚀 Uploading 13 T1 images to R2...\n'); let ok = 0, failed = 0; for (const { src, dest } of IMAGE_MAP) { const srcPath = path.join(ARTIFACTS_DIR, src); if (!fs.existsSync(srcPath)) { console.warn(`⚠️ Not found: ${src}`); failed++; continue; } try { const buf = fs.readFileSync(srcPath); await client.send(new PutObjectCommand({ Bucket: R2_BUCKET, Key: dest, Body: buf, ContentType: 'image/png', CacheControl: 'public, max-age=31536000', })); const publicUrl = `${(R2_PUBLIC_URL || '').replace(/\/$/, '')}/${dest}`; console.log(`✅ ${dest}`); console.log(` URL: ${publicUrl}`); ok++; } catch (e: unknown) { console.error(`❌ ${dest}: ${(e instanceof Error ? (e instanceof Error ? e.message : String(e)) : String(e))}`); failed++; } } console.log(`\n── RÉSULTAT ────────────────────`); console.log(`✅ Uploaded: ${ok}/${IMAGE_MAP.length}`); if (failed > 0) { console.log(`❌ Failed: ${failed}`); process.exit(1); } else { console.log(`\n🎉 Toutes les images T1 sont maintenant sur R2 !`); console.log(` Les leçons WhatsApp du module T1 afficheront bien les images.`); } } main().catch(e => { console.error(e); process.exit(1); });