← back to Re Flyers
server.js
53 lines
#!/usr/bin/env node
// TK-10708 re-flyers — normalized cross-source flyer index viewer/API.
// Serves data/flyers.json (built by scripts/build-seed.mjs from the existing
// re-flyer-aggregator outputs). Zero deps. Basic-auth admin/DW2024! (DW viewer standard).
//
// GATED-tier note: rows with rights_basis containing GATED are served WITH their flag so
// the viewer can visually mark/hide them. This surface NEVER downloads or re-hosts a file.
import http from 'node:http';
import { readFileSync, existsSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const ROOT = dirname(fileURLToPath(import.meta.url));
const PORT = process.env.PORT || 0; // 0 = OS-assigned free port (no permanent port)
const USER = process.env.BASIC_USER || 'admin';
const PASS = process.env.BASIC_PASS || 'DW2024!';
const DATA = join(ROOT, 'data', 'flyers.json');
function loadFlyers() {
if (!existsSync(DATA)) return { count: 0, flyers: [] };
return JSON.parse(readFileSync(DATA, 'utf8'));
}
const server = http.createServer((req, res) => {
const hdr = req.headers.authorization || '';
const [, b64] = hdr.split(' ');
const [u, p] = Buffer.from(b64 || '', 'base64').toString().split(':');
if (u !== USER || p !== PASS) {
res.writeHead(401, { 'WWW-Authenticate': 'Basic realm="re-flyers"' });
return res.end('Auth required');
}
try {
if (req.url.startsWith('/api/flyers')) {
const data = loadFlyers();
res.writeHead(200, { 'content-type': 'application/json' });
return res.end(JSON.stringify(data));
}
if (req.url === '/health') { res.writeHead(200); return res.end('ok'); }
const idx = join(ROOT, 'public', 'index.html');
res.writeHead(200, { 'content-type': 'text/html' });
return res.end(existsSync(idx) ? readFileSync(idx) : '<h1>re-flyers</h1>');
} catch (e) {
res.writeHead(500, { 'content-type': 'text/plain' });
res.end('err: ' + e.message);
}
});
server.listen(PORT, () => {
const a = server.address();
console.log(`re-flyers viewer on :${a.port} (basic-auth ${USER}) — GET /api/flyers`);
});