Monorepo for Aesthetic.Computer aesthetic.computer
at main 144 lines 4.5 kB view raw
1#!/usr/bin/env node 2// Batch mint keeps from keep-queue.txt 3// Reads the AC auth from vault and mints each code sequentially 4 5import fs from 'fs'; 6import path from 'path'; 7import os from 'os'; 8import { fileURLToPath } from 'url'; 9 10const __dirname = path.dirname(fileURLToPath(import.meta.url)); 11 12// Load auth from ~/.ac-token (same as artery-tui.mjs) 13const authPath = path.join(os.homedir(), '.ac-token'); 14 15if (!fs.existsSync(authPath)) { 16 console.error('❌ Auth not found at:', authPath); 17 console.error(' Run: node artery/artery-tui.mjs and login first (press "a" then "l")'); 18 process.exit(1); 19} 20 21const auth = JSON.parse(fs.readFileSync(authPath, 'utf8')); 22console.log(`🔑 Loaded auth for: ${auth.email || auth.user?.email || 'unknown'}`); 23 24// Load queue 25const queuePath = path.join(__dirname, 'keep-queue.txt'); 26const codes = fs.readFileSync(queuePath, 'utf8') 27 .split('\n') 28 .map(c => c.trim()) 29 .filter(c => c.length > 0); 30 31console.log(`📋 ${codes.length} codes to mint\n`); 32 33// Disable SSL verification for localhost 34process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; 35 36const API_URL = 'https://localhost:8888/api/keep-mint'; 37 38async function mintCode(code, index) { 39 console.log(`\n[${index + 1}/${codes.length}] 🎨 Minting $${code}...`); 40 41 try { 42 const response = await fetch(API_URL, { 43 method: 'POST', 44 headers: { 45 'Authorization': `Bearer ${auth.access_token}`, 46 'Content-Type': 'application/json', 47 'Accept': 'text/event-stream', 48 }, 49 body: JSON.stringify({ piece: code, mode: 'mint' }), 50 }); 51 52 if (!response.ok) { 53 const text = await response.text(); 54 console.log(` ❌ Error (${response.status}): ${text.slice(0, 200)}`); 55 return { code, success: false, error: text }; 56 } 57 58 // Parse SSE stream 59 const reader = response.body.getReader(); 60 const decoder = new TextDecoder(); 61 let buffer = ''; 62 let tokenId = null; 63 let currentEvent = 'progress'; 64 65 while (true) { 66 const { done, value } = await reader.read(); 67 if (done) break; 68 69 buffer += decoder.decode(value, { stream: true }); 70 const lines = buffer.split('\n'); 71 buffer = lines.pop() || ''; 72 73 for (const line of lines) { 74 if (line.startsWith('event: ')) { 75 currentEvent = line.slice(7).trim(); 76 continue; 77 } 78 79 if (line.startsWith('data: ')) { 80 try { 81 const data = JSON.parse(line.slice(6)); 82 83 if (currentEvent === 'error' || data.error) { 84 console.log(` ⚠️ ${data.error}${data.minter ? ` by ${data.minter}` : ''}`); 85 if (data.tokenId) { 86 console.log(` Already kept as token #${data.tokenId}`); 87 } 88 return { code, success: false, error: data.error, tokenId: data.tokenId }; 89 } 90 91 if (currentEvent === 'progress') { 92 process.stdout.write(` ${data.step || data.message || '...'}\r`); 93 } 94 95 if (currentEvent === 'complete' && data.success) { 96 tokenId = data.tokenId; 97 console.log(` ✅ Kept as token #${tokenId}`); 98 console.log(` ${data.objktUrl || ''}`); 99 return { code, success: true, tokenId }; 100 } 101 } catch (e) { 102 // Ignore JSON parse errors for partial data 103 } 104 } 105 } 106 } 107 108 return { code, success: !!tokenId, tokenId }; 109 } catch (e) { 110 console.log(` ❌ Fetch error: ${e.message}`); 111 return { code, success: false, error: e.message }; 112 } 113} 114 115// Main 116async function main() { 117 const results = { success: 0, failed: 0, skipped: 0 }; 118 const startTime = Date.now(); 119 120 for (let i = 0; i < codes.length; i++) { 121 const result = await mintCode(codes[i], i); 122 if (result.success) { 123 results.success++; 124 } else if (result.tokenId) { 125 results.skipped++; // Already minted 126 } else { 127 results.failed++; 128 } 129 130 // Small delay between mints to avoid overwhelming 131 if (i < codes.length - 1) { 132 await new Promise(r => setTimeout(r, 500)); 133 } 134 } 135 136 const elapsed = ((Date.now() - startTime) / 1000 / 60).toFixed(1); 137 console.log(`\n${'='.repeat(50)}`); 138 console.log(`✅ Complete in ${elapsed} minutes`); 139 console.log(` Success: ${results.success}`); 140 console.log(` Skipped (already minted): ${results.skipped}`); 141 console.log(` Failed: ${results.failed}`); 142} 143 144main().catch(console.error);