← back to Secrets Manager

update-viewer/server.mjs

32 lines

#!/usr/bin/env node
// Credentials & Tokens Update Tracker — local web viewer. Zero deps.
//   node server.mjs   → http://localhost:9778
// Reads update-items.json; lets Steve toggle status (persisted). No secret VALUES.
import http from 'node:http';
import fs from 'node:fs';
import path from 'node:path';

const DIR = path.dirname(new URL(import.meta.url).pathname);
const DATA = path.join(DIR, 'update-items.json');
const PORT = process.env.PORT || 9778;
const send = (res, code, type, body) => { res.writeHead(code, { 'Content-Type': type, 'Cache-Control': 'no-store' }); res.end(body); };

http.createServer((req, res) => {
  const u = new URL(req.url, 'http://localhost');
  if (u.pathname === '/') return send(res, 200, 'text/html; charset=utf-8', fs.readFileSync(path.join(DIR, 'index.html')));
  if (u.pathname === '/api/items') return send(res, 200, 'application/json', fs.readFileSync(DATA));
  if (u.pathname === '/api/toggle' && req.method === 'POST') {
    let b = ''; req.on('data', c => b += c); req.on('end', () => {
      try {
        const { id, status } = JSON.parse(b);
        const d = JSON.parse(fs.readFileSync(DATA, 'utf8'));
        const it = d.items.find(x => x.id === id);
        if (it) { it.status = status; fs.writeFileSync(DATA, JSON.stringify(d, null, 2) + '\n'); }
        send(res, 200, 'application/json', JSON.stringify({ ok: !!it }));
      } catch (e) { send(res, 400, 'application/json', JSON.stringify({ ok: false, error: e.message })); }
    });
    return;
  }
  send(res, 404, 'text/plain', 'not found');
}).listen(PORT, () => console.log(`Credentials Update Tracker → http://localhost:${PORT}`));