diff --git a/public/index.html b/public/index.html
index dc6591a0..d7d14422 100644
--- a/public/index.html
+++ b/public/index.html
@@ -81,8 +81,8 @@
-
-
+
+
diff --git a/public/map.js b/public/map.js
index 386783e2..80634f4d 100644
--- a/public/map.js
+++ b/public/map.js
@@ -268,6 +268,9 @@
async function loadNodes() {
try {
+ // Load regions from config + observed IATAs
+ try { REGION_NAMES = await api('/config/regions', { ttl: 3600 }); } catch {}
+
const data = await api(`/nodes?limit=10000&lastHeard=${filters.lastHeard}`, { ttl: CLIENT_TTL.nodeList });
nodes = data.nodes || [];
@@ -308,7 +311,7 @@
}
}
- const REGION_NAMES = { SJC: 'San Jose', SFO: 'San Francisco', OAK: 'Oakland', MTV: 'Mountain View', SCZ: 'Santa Cruz', MRY: 'Monterey', PAO: 'Palo Alto' };
+ let REGION_NAMES = {};
function buildJumpButtons() {
const el = document.getElementById('mcJumps');
diff --git a/public/packets.js b/public/packets.js
index 0a092fc8..c63266d8 100644
--- a/public/packets.js
+++ b/public/packets.js
@@ -1090,11 +1090,10 @@
return '
' + key + '' + val + '
';
}
- // Load regions from config
+ // Load regions from config API
(async () => {
try {
- // We'll use a simple approach - hardcode from config
- regionMap = {"SJC":"San Jose, US","SFO":"San Francisco, US","OAK":"Oakland, US","MRY":"Monterey, US","LAR":"Los Angeles, US"};
+ regionMap = await api('/config/regions', { ttl: 3600 });
} catch {}
})();
diff --git a/server.js b/server.js
index 9b413cd1..76e483a9 100644
--- a/server.js
+++ b/server.js
@@ -188,6 +188,18 @@ app.get('/api/config/cache', (req, res) => {
res.json(config.cacheTTL || {});
});
+app.get('/api/config/regions', (req, res) => {
+ // Merge config regions with any IATA codes seen from observers
+ const regions = { ...(config.regions || {}) };
+ try {
+ const rows = db.db.prepare("SELECT DISTINCT iata FROM observers WHERE iata IS NOT NULL").all();
+ for (const r of rows) {
+ if (r.iata && !regions[r.iata]) regions[r.iata] = r.iata; // fallback to code itself
+ }
+ } catch {}
+ res.json(regions);
+});
+
app.get('/api/perf', (req, res) => {
const summary = {};
for (const [path, ep] of Object.entries(perfStats.endpoints)) {
@@ -1664,7 +1676,7 @@ app.get('/api/observers', (req, res) => {
const observers = db.getObservers();
const oneHourAgo = new Date(Date.now() - 3600000).toISOString();
// Join observer location from nodes table (observers are nodes — same pubkey)
- const nodeLocStmt = db.db.prepare("SELECT lat, lon, role FROM nodes WHERE public_key = ?");
+ const nodeLocStmt = db.db.prepare("SELECT lat, lon, role FROM nodes WHERE public_key = ? COLLATE NOCASE");
const result = observers.map(o => {
const obsPackets = pktStore.byObserver.get(o.id) || [];
const lastHour = { count: obsPackets.filter(p => p.timestamp > oneHourAgo).length };