fix: register data providers for local preview

Adapt the preview middleware contribution from PR #324 to the extracted provider modules, including the existing OpenSky route.
This commit is contained in:
Jejugo authored and Sameh Khamis committed 2026-09-12 12:43:54 -07:00
1 parent 276bb84904
commit a0f07b752f
10 files changed
+64 -53

No files matched your search

+6 -4
View File
@@ -13,9 +13,7 @@ export function adsbLolProxy() {
let _cacheAt = 0; let _cacheAt = 0;
/** Response cache TTL (ms). */ /** Response cache TTL (ms). */
const CACHE_MS = 12000; const CACHE_MS = 12000;
return { const installMiddleware = (server) => {
name: 'adsblol-proxy',
configureServer(server) {
server.middlewares.use('/api/adsblol/mil', async (req, res) => { server.middlewares.use('/api/adsblol/mil', async (req, res) => {
try { try {
const now = Date.now(); const now = Date.now();
@@ -56,6 +54,10 @@ export function adsbLolProxy() {
res.end(JSON.stringify({ error: 'ADS-B proxy error' })); res.end(JSON.stringify({ error: 'ADS-B proxy error' }));
} }
}); });
}, };
return {
name: 'adsblol-proxy',
configureServer: installMiddleware,
configurePreviewServer: installMiddleware,
}; };
} }
+8 -12
View File
@@ -107,9 +107,7 @@ export function adsbdbProxy() {
return inflight.get(ik); return inflight.get(ik);
} }
return { const installMiddleware = (server) => {
name: 'adsbdb-proxy',
configureServer(server) {
server.middlewares.use('/api/adsbdb', async (req, res) => { server.middlewares.use('/api/adsbdb', async (req, res) => {
await loadOnce(); await loadOnce();
const send = (status, obj) => { const send = (status, obj) => {
@@ -125,20 +123,14 @@ export function adsbdbProxy() {
if (!/^[A-Z0-9]{2,8}$/.test(cs)) if (!/^[A-Z0-9]{2,8}$/.test(cs))
return send(400, { error: 'invalid callsign' }); return send(400, { error: 'invalid callsign' });
const data = await lookup('route', cs); const data = await lookup('route', cs);
return send( return send(200, data ? { found: true, ...data } : { found: false });
200,
data ? { found: true, ...data } : { found: false },
);
} }
if (kind === 'type') { if (kind === 'type') {
const hex = String(rawKey || '').toLowerCase(); const hex = String(rawKey || '').toLowerCase();
if (!/^[0-9a-f]{6}$/.test(hex)) if (!/^[0-9a-f]{6}$/.test(hex))
return send(400, { error: 'invalid hex' }); return send(400, { error: 'invalid hex' });
const data = await lookup('aircraft', hex); const data = await lookup('aircraft', hex);
return send( return send(200, data ? { found: true, ...data } : { found: false });
200,
data ? { found: true, ...data } : { found: false },
);
} }
return send(404, { error: 'unknown endpoint' }); return send(404, { error: 'unknown endpoint' });
} catch (err) { } catch (err) {
@@ -146,6 +138,10 @@ export function adsbdbProxy() {
return send(500, { error: 'adsbdb proxy error' }); return send(500, { error: 'adsbdb proxy error' });
} }
}); });
}, };
return {
name: 'adsbdb-proxy',
configureServer: installMiddleware,
configurePreviewServer: installMiddleware,
}; };
} }
+6 -4
View File
@@ -348,9 +348,7 @@ function openSkySourceIsStale(sourceEpochMs, now = Date.now()) {
* @returns {import('vite').Plugin} * @returns {import('vite').Plugin}
*/ */
export function openSkyProxy() { export function openSkyProxy() {
return { const installMiddleware = (server) => {
name: 'opensky-proxy',
configureServer(server) {
server.middlewares.use('/api/opensky', async (req, res) => { server.middlewares.use('/api/opensky', async (req, res) => {
try { try {
const requestedMode = normalizeOpenSkyAuthMode( const requestedMode = normalizeOpenSkyAuthMode(
@@ -694,6 +692,10 @@ export function openSkyProxy() {
res.end(JSON.stringify({ error: 'OpenSky proxy error' })); res.end(JSON.stringify({ error: 'OpenSky proxy error' }));
} }
}); });
}, };
return {
name: 'opensky-proxy',
configureServer: installMiddleware,
configurePreviewServer: installMiddleware,
}; };
} }
+8 -9
View File
@@ -119,9 +119,7 @@ export function cctvProxy({ sourceRoot = process.cwd() } = {}) {
} }
}; };
return { const installMiddleware = (server) => {
name: 'cctv-proxy',
configureServer(server) {
server.middlewares.use('/api/cctv', async (req, res) => { server.middlewares.use('/api/cctv', async (req, res) => {
try { try {
const sources = await getCctvSources(); const sources = await getCctvSources();
@@ -297,8 +295,7 @@ export function cctvProxy({ sourceRoot = process.cwd() } = {}) {
decodeURIComponent(url.pathname.replace('/frame/', '').trim()) || decodeURIComponent(url.pathname.replace('/frame/', '').trim()) ||
'camera'; 'camera';
const source = sourceById.get(cameraId); const source = sourceById.get(cameraId);
const label = const label = url.searchParams.get('label') || source?.name || cameraId;
url.searchParams.get('label') || source?.name || cameraId;
const city = url.searchParams.get('city') || source?.city || ''; const city = url.searchParams.get('city') || source?.city || '';
const lat = Number(url.searchParams.get('lat') || source?.lat); const lat = Number(url.searchParams.get('lat') || source?.lat);
const lon = Number(url.searchParams.get('lon') || source?.lon); const lon = Number(url.searchParams.get('lon') || source?.lon);
@@ -306,9 +303,7 @@ export function cctvProxy({ sourceRoot = process.cwd() } = {}) {
url.searchParams.get('heading') || source?.headingDeg, url.searchParams.get('heading') || source?.headingDeg,
); );
const fov = Number(url.searchParams.get('fov') || source?.fovDeg); const fov = Number(url.searchParams.get('fov') || source?.fovDeg);
const pitch = Number( const pitch = Number(url.searchParams.get('pitch') || source?.pitchDeg);
url.searchParams.get('pitch') || source?.pitchDeg,
);
// Only use server-registered upstream URLs — never accept client-supplied URLs // Only use server-registered upstream URLs — never accept client-supplied URLs
// (prevents SSRF via ?upstream= query parameter) // (prevents SSRF via ?upstream= query parameter)
@@ -389,6 +384,10 @@ export function cctvProxy({ sourceRoot = process.cwd() } = {}) {
res.end(JSON.stringify({ error: 'CCTV proxy error' })); res.end(JSON.stringify({ error: 'CCTV proxy error' }));
} }
}); });
}, };
return {
name: 'cctv-proxy',
configureServer: installMiddleware,
configurePreviewServer: installMiddleware,
}; };
} }
+6 -4
View File
@@ -167,9 +167,7 @@ export function firmsProxy() {
return statusInflight; return statusInflight;
} }
return { const installMiddleware = (server) => {
name: 'firms-proxy',
configureServer(server) {
server.middlewares.use('/api/firms', async (req, res) => { server.middlewares.use('/api/firms', async (req, res) => {
const sendJson = (status, obj) => { const sendJson = (status, obj) => {
if (res.headersSent) return; if (res.headersSent) return;
@@ -254,6 +252,10 @@ export function firmsProxy() {
sendJson(500, { error: 'firms proxy error' }); sendJson(500, { error: 'firms proxy error' });
} }
}); });
}, };
return {
name: 'firms-proxy',
configureServer: installMiddleware,
configurePreviewServer: installMiddleware,
}; };
} }
+6 -4
View File
@@ -21,9 +21,7 @@ const GBFS_PROXY_TIMEOUT_MS = 12000;
* @returns {import('vite').Plugin} * @returns {import('vite').Plugin}
*/ */
export function gbfsProxy() { export function gbfsProxy() {
return { const installMiddleware = (server) => {
name: 'gbfs-proxy',
configureServer(server) {
server.middlewares.use('/api/gbfs', async (req, res) => { server.middlewares.use('/api/gbfs', async (req, res) => {
try { try {
if (req.method !== 'GET') { if (req.method !== 'GET') {
@@ -176,6 +174,10 @@ export function gbfsProxy() {
res.end(JSON.stringify({ error: 'GBFS proxy error' })); res.end(JSON.stringify({ error: 'GBFS proxy error' }));
} }
}); });
}, };
return {
name: 'gbfs-proxy',
configureServer: installMiddleware,
configurePreviewServer: installMiddleware,
}; };
} }
+6 -4
View File
@@ -764,9 +764,7 @@ export async function fetchOverpassPayload(body, maxResponseBytes = OVERPASS_MAX
* @returns {import('vite').Plugin} * @returns {import('vite').Plugin}
*/ */
function overpassProxy() { function overpassProxy() {
return { const installMiddleware = (server) => {
name: 'overpass-proxy',
configureServer(server) {
server.middlewares.use('/api/overpass', async (req, res) => { server.middlewares.use('/api/overpass', async (req, res) => {
// Hoisted out of the try so the catch's serve-stale lookup can see it // Hoisted out of the try so the catch's serve-stale lookup can see it
// (a body-read failure would otherwise hit an out-of-scope reference). // (a body-read failure would otherwise hit an out-of-scope reference).
@@ -896,7 +894,11 @@ function overpassProxy() {
}); });
installRouteMiddleware(server.middlewares); installRouteMiddleware(server.middlewares);
}, };
return {
name: 'overpass-proxy',
configureServer: installMiddleware,
configurePreviewServer: installMiddleware,
}; };
} }
+6 -4
View File
@@ -66,9 +66,7 @@ export function celestrakProxy() {
return { at: Date.now(), body }; return { at: Date.now(), body };
} }
return { const installMiddleware = (server) => {
name: 'celestrak-proxy',
configureServer(server) {
server.middlewares.use('/api/celestrak', async (req, res) => { server.middlewares.use('/api/celestrak', async (req, res) => {
const group = String(req.url || '') const group = String(req.url || '')
.replace(/^\//, '') .replace(/^\//, '')
@@ -132,6 +130,10 @@ export function celestrakProxy() {
send(500, 'celestrak proxy error', 'ERROR'); send(500, 'celestrak proxy error', 'ERROR');
} }
}); });
}, };
return {
name: 'celestrak-proxy',
configureServer: installMiddleware,
configurePreviewServer: installMiddleware,
}; };
} }
+6 -4
View File
@@ -131,9 +131,7 @@ export function terrainHeightsProxy() {
return inflight.get(key); return inflight.get(key);
} }
return { const installMiddleware = (server) => {
name: 'terrain-heights-proxy',
configureServer(server) {
server.middlewares.use('/api/terrain/heights', async (req, res) => { server.middlewares.use('/api/terrain/heights', async (req, res) => {
const send = (status, bodyObj) => { const send = (status, bodyObj) => {
if (res.headersSent) return; if (res.headersSent) return;
@@ -178,6 +176,10 @@ export function terrainHeightsProxy() {
send(500, { error: 'terrain heights proxy error' }); send(500, { error: 'terrain heights proxy error' });
} }
}); });
}, };
return {
name: 'terrain-heights-proxy',
configureServer: installMiddleware,
configurePreviewServer: installMiddleware,
}; };
} }
+6 -4
View File
@@ -144,9 +144,7 @@ export function tomtomProxy() {
return buf; return buf;
} }
return { const installMiddleware = (server) => {
name: 'tomtom-proxy',
configureServer(server) {
server.middlewares.use('/api/tomtom', async (req, res) => { server.middlewares.use('/api/tomtom', async (req, res) => {
// Sanitized responses only (proxy/security baseline): no upstream // Sanitized responses only (proxy/security baseline): no upstream
// error details, and never echo the key or the upstream URL. // error details, and never echo the key or the upstream URL.
@@ -259,6 +257,10 @@ export function tomtomProxy() {
sendJson(500, { error: 'proxy' }); sendJson(500, { error: 'proxy' });
} }
}); });
}, };
return {
name: 'tomtom-proxy',
configureServer: installMiddleware,
configurePreviewServer: installMiddleware,
}; };
} }