mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
panel_request resolved paths with a check for a leading //, but URL parsing also reads /\host as another host, so it could request other servers. It now resolves the path against the app's address, refuses any other origin, matches refused routes decoded as well, and does not follow redirects. Responses are capped at 64 MiB while reading, with a deadline; held responses make room on arrival and expire by time only, so a response being read keeps its parts. The panel keeps converted images only for its build files, so live camera frames no longer accumulate, and failed build loads are retried. The dev server answers a malformed /panel/ path with 400 instead of crashing.
104 lines
3.3 KiB
JavaScript
104 lines
3.3 KiB
JavaScript
/**
|
|
* The MCP Apps panel build. A panel loads the app through its MCP server,
|
|
* one tool call per file (see src/tools/globePanel.js), so the app must be
|
|
* few files: one app script, one stylesheet, Cesium's own script, and
|
|
* Cesium's workers combined into one script that Cesium runs from memory.
|
|
* The build is served at PANEL_BASE next to the app.
|
|
*/
|
|
|
|
// The panel loads these paths (src/tools/globePanel.js); a test keeps the
|
|
// two in step.
|
|
export const PANEL_BASE = '/panel/';
|
|
/** Cesium's workers as one script, relative to the panel build. */
|
|
export const PANEL_WORKERS_PATH = 'cesium/workers.js';
|
|
export const PANEL_OUT_DIR = 'dist/panel';
|
|
|
|
/** A browser Vite config changed to produce the panel build. */
|
|
export function panelBuildConfig(config) {
|
|
return {
|
|
...config,
|
|
base: PANEL_BASE,
|
|
build: {
|
|
...config.build,
|
|
outDir: PANEL_OUT_DIR,
|
|
emptyOutDir: true,
|
|
modulePreload: false,
|
|
cssCodeSplit: false,
|
|
rollupOptions: {
|
|
...config.build?.rollupOptions,
|
|
output: { inlineDynamicImports: true },
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Source for Cesium's `CESIUM_WORKERS` script: every worker module, each
|
|
* evaluated only when Cesium starts that worker. `workerNames` are the
|
|
* module names in Cesium's Workers directory, without `.js`.
|
|
*/
|
|
export function workersEntrySource(workerNames, workersDir) {
|
|
const entries = workerNames.map(
|
|
(name) =>
|
|
` ${JSON.stringify(name)}: () => import(${JSON.stringify(`${workersDir}/${name}.js`)}),`,
|
|
);
|
|
return `self.CesiumWorkers = {\n${entries.join('\n')}\n};\n`;
|
|
}
|
|
|
|
const CONTENT_TYPES = {
|
|
'.css': 'text/css',
|
|
'.geojsonl': 'application/geo+json-seq',
|
|
'.glb': 'model/gltf-binary',
|
|
'.html': 'text/html',
|
|
'.jpg': 'image/jpeg',
|
|
'.js': 'text/javascript',
|
|
'.json': 'application/json',
|
|
'.png': 'image/png',
|
|
'.svg': 'image/svg+xml',
|
|
'.wasm': 'application/wasm',
|
|
'.woff2': 'font/woff2',
|
|
'.xml': 'application/xml',
|
|
};
|
|
|
|
/**
|
|
* Vite plugin serving the panel build at PANEL_BASE on the dev server, as
|
|
* the preview server and hosted deployments serve it from the build output.
|
|
*/
|
|
export function panelBuildPlugin({ outDir = PANEL_OUT_DIR } = {}) {
|
|
return {
|
|
name: 'panel-build',
|
|
configureServer(server) {
|
|
server.middlewares.use(async (req, res, next) => {
|
|
const { pathname } = new URL(req.url || '/', 'http://localhost');
|
|
if (!pathname.startsWith(PANEL_BASE)) return next();
|
|
const { readFile } = await import('node:fs/promises');
|
|
const { extname, resolve, sep } = await import('node:path');
|
|
const root = resolve(server.config.root, outDir);
|
|
let relative;
|
|
try {
|
|
relative = decodeURIComponent(pathname.slice(PANEL_BASE.length));
|
|
} catch {
|
|
res.statusCode = 400;
|
|
res.end('Bad path');
|
|
return;
|
|
}
|
|
const file = resolve(root, relative || 'index.html');
|
|
if (file !== root && !file.startsWith(root + sep)) return next();
|
|
try {
|
|
const body = await readFile(file);
|
|
res.setHeader(
|
|
'Content-Type',
|
|
CONTENT_TYPES[extname(file)] || 'application/octet-stream',
|
|
);
|
|
res.end(body);
|
|
} catch {
|
|
res.statusCode = 404;
|
|
res.end(
|
|
relative ? 'Not found' : 'No panel build; run npm run build:panel',
|
|
);
|
|
}
|
|
});
|
|
},
|
|
};
|
|
}
|