const STATUSES = { running: { label: "running", dot: "ok", sym: "●" }, idle: { label: "idle", dot: "info", sym: "○" }, booting: { label: "booting", dot: "warn", sym: "◐" }, stopped: { label: "stopped", dot: "mute", sym: "○" }, error: { label: "error", dot: "bad", sym: "✕" }, }; const TASKS_BY_STATUS = { running: ["scraping", "ad-create", "checkout", "monitoring", "captcha-solve", "session-keep"], booting: ["warming-up"], idle: ["queued"], stopped: ["—"], error: ["halted"], }; const CODE_PALETTE = [ { name:'orange', dot:'#FF5F1F', text:'#FF8A55', bg:'rgba(255,95,31,.13)', border:'rgba(255,95,31,.32)' }, { name:'red', dot:'#FF6B6B', text:'#FF9393', bg:'rgba(255,107,107,.12)', border:'rgba(255,107,107,.3)' }, { name:'yellow', dot:'#D7B074', text:'#E8CC9A', bg:'rgba(215,176,116,.12)', border:'rgba(215,176,116,.3)' }, { name:'amber', dot:'#FF9A2E', text:'#FFBB70', bg:'rgba(255,154,46,.12)', border:'rgba(255,154,46,.3)' }, { name:'lime', dot:'#A8D060', text:'#C4E48A', bg:'rgba(168,208,96,.10)', border:'rgba(168,208,96,.28)' }, { name:'green', dot:'#5EE083', text:'#90EDAC', bg:'rgba(94,224,131,.10)', border:'rgba(94,224,131,.28)' }, { name:'cyan', dot:'#5BCFCF', text:'#8DDFDF', bg:'rgba(91,207,207,.10)', border:'rgba(91,207,207,.28)' }, { name:'blue', dot:'#77B1D8', text:'#A3CCEC', bg:'rgba(119,177,216,.10)', border:'rgba(119,177,216,.28)' }, { name:'violet', dot:'#9B7FE0', text:'#BBA8EC', bg:'rgba(155,127,224,.10)', border:'rgba(155,127,224,.28)' }, { name:'rose', dot:'#E07899', text:'#EDAABF', bg:'rgba(224,120,153,.10)', border:'rgba(224,120,153,.28)' }, ]; const initialCodes = ["US-EAST-1", "EU-WEST-1", "AP-SOUTHEAST-1"]; function makeColorLookup(codes) { const idx = new Map(codes.map((c, i) => [c, i])); return (code) => { const i = idx.get(code); if (i == null) return CODE_PALETTE[CODE_PALETTE.length - 1]; return CODE_PALETTE[i % CODE_PALETTE.length]; }; } const ACCOUNT_PREFIXES = { "US-EAST-1": ["fb.us", "tt.us", "mp.us", "ads.us"], "EU-WEST-1": ["fb.eu", "tt.eu", "mp.eu", "ads.eu"], "AP-SOUTHEAST-1": ["fb.apac","tt.apac","mp.apac","ads.apac"], }; function makeInstances(codes) { const out = []; const dist = [10, 8, 6]; const statuses = ["running","running","running","running","running","idle","idle","booting","stopped","error"]; let n = 0; codes.forEach((code, ci) => { const count = dist[ci] != null ? dist[ci] : 4; const prefixes = ACCOUNT_PREFIXES[code] || ["acc"]; for (let i = 0; i < count; i++) { n++; const id = "i" + String(n).padStart(4, "0"); const name = "node-" + Math.random().toString(36).slice(2,6) + "-" + Math.random().toString(36).slice(2,5); const status = statuses[(n * 7) % statuses.length]; const uptime = status === "running" ? `${Math.floor(Math.random()*48)}h ${Math.floor(Math.random()*60)}m` : "—"; const account = prefixes[i % prefixes.length] + "." + String(i+1).padStart(3, "0"); const taskPool = TASKS_BY_STATUS[status] || ["—"]; const task = taskPool[n % taskPool.length]; out.push({ id, name, status, code, account, uptime, task }); } }); return out; } const LOG_TEMPLATES = [ ["INFO", "instance booting…"], ["INFO", "loaded shard {sid}"], ["INFO", "attached to map {code}"], ["INFO", "tcp connection established to upstream"], ["DEBUG", "heartbeat ok ↑{up}ms ↓{dn}ms"], ["INFO", "session token rotated"], ["WARN", "upstream latency {lat}ms (threshold 250ms)"], ["INFO", "task queue drained ({n} jobs)"], ["DEBUG", "snapshot captured ({sz}KB)"], ["INFO", "checkpoint persisted to s3://veil-snap/{id}.bin"], ["WARN", "rate limit headroom <20%, backing off"], ["INFO", "tap → tap.veil.cloud:8443 (latency {lat}ms)"], ["ERROR", "upstream reset by peer ECONNRESET — retrying"], ["INFO", "account {acc} session established"], ]; function genLogs(instance, count = 60) { const out = []; let m = 12, s = 22, ms = 1; for (let i = 0; i < count; i++) { ms += 20 + Math.floor(Math.random()*900); if (ms >= 1000) { s += Math.floor(ms/1000); ms = ms % 1000; } if (s >= 60) { m += Math.floor(s/60); s = s % 60; } if (m >= 60) m = m % 60; const tpl = LOG_TEMPLATES[(i * 13 + instance.name.length) % LOG_TEMPLATES.length]; let msg = tpl[1] .replace("{sid}", instance.id.slice(1)) .replace("{code}", instance.code || "—") .replace("{up}", 20 + Math.floor(Math.random()*60)) .replace("{dn}", 20 + Math.floor(Math.random()*60)) .replace("{lat}", 180 + Math.floor(Math.random()*220)) .replace("{n}", 1 + Math.floor(Math.random()*40)) .replace("{sz}", 8 + Math.floor(Math.random()*128)) .replace("{id}", instance.id) .replace("{acc}", instance.account || "?"); out.push({ ts: `${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}.${String(ms).padStart(3,'0')}`, level: tpl[0], msg, }); } return out; } const CODE_NAME_RE = /^[A-Z][A-Z0-9-]{1,23}$/; Object.assign(window, { STATUSES, CODE_PALETTE, initialCodes, makeColorLookup, makeInstances, genLogs, CODE_NAME_RE, TASKS_BY_STATUS });