Something went wrong. Try again.
[PRE-ALPHA] an open source web-based 2D/3D graphing calculator cartesium.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143import { createServer } from 'node:net';import { spawn } from 'node:child_process';import { resolve } from 'node:path';
const appRoot = resolve(import.meta.dirname, '..');const entrypoint = resolve(appRoot, 'build/index.js');const host = '127.0.0.1';const basePath = process.env.CARTESIUM_BASE_PATH ?? '';const routePaths = [`${basePath}/embed`, `${basePath}/embed/v1`];
if (basePath !== '' && (!basePath.startsWith('/') || basePath.endsWith('/'))) { throw new Error('CARTESIUM_BASE_PATH must be empty or a slash-prefixed path without a trailing slash.');}
const port = await findFreePort();const origin = `http://${host}:${port}`;const output = [];
const server = spawn(process.execPath, [entrypoint], { cwd: appRoot, env: { ...process.env, HOST: host, PORT: String(port) }, stdio: ['ignore', 'pipe', 'pipe']});
for (const stream of [server.stdout, server.stderr]) { stream?.on('data', (chunk) => { output.push(chunk.toString());
if (output.length > 40) output.shift(); });}
try { for (const routePath of routePaths) { const response = await waitForResponse(`${origin}${routePath}`, server);
if (response.status !== 200) { throw new Error(`GET ${routePath} returned ${response.status}, expected 200.`); }
const contentSecurityPolicy = response.headers.get('content-security-policy') ?? '';
if (!/(?:^|\s|;)frame-ancestors\s+\*/i.test(contentSecurityPolicy)) { throw new Error( `GET ${routePath} did not return frame-ancestors * (received ${JSON.stringify(contentSecurityPolicy)}).` ); }
if (response.headers.has('x-frame-options')) { throw new Error(`GET ${routePath} returned a conflicting X-Frame-Options header.`); }
process.stdout.write(`adapter-node embed smoke passed: ${response.status} ${routePath}\n`); }
const resolverPath = `${basePath}/api/embed/v1/at`; const resolverResponse = await fetch(`${origin}${resolverPath}`);
if (resolverResponse.status !== 400) { throw new Error(`GET ${resolverPath} returned ${resolverResponse.status}, expected 400.`); }
if (resolverResponse.headers.get('cache-control') !== 'no-store') { throw new Error(`GET ${resolverPath} did not return Cache-Control: no-store.`); }
const resolverError = await resolverResponse.json();
if (resolverError?.error !== 'invalid-at-uri') { throw new Error(`GET ${resolverPath} did not return the structured invalid-at-uri error.`); }
process.stdout.write(`adapter-node resolver smoke passed: ${resolverResponse.status} ${resolverPath}\n`); const removedRoute = await fetch(`${origin}${basePath}/embed/static`);
if (removedRoute.status !== 404) { throw new Error(`GET ${basePath}/embed/static returned ${removedRoute.status}, expected 404.`); }
process.stdout.write(`adapter-node removed-route smoke passed: ${removedRoute.status} ${basePath}/embed/static\n`);} catch (error) { if (output.length > 0) process.stderr.write(`\nadapter-node output:\n${output.join('')}`); throw error;} finally { server.kill('SIGTERM'); await new Promise((resolveExit) => { if (server.exitCode !== null) { resolveExit();
return; }
server.once('exit', resolveExit); setTimeout(() => { if (server.exitCode === null) server.kill('SIGKILL'); resolveExit(); }, 5000).unref(); });}
async function findFreePort() { const probe = createServer(); await new Promise((resolveListen, reject) => { probe.once('error', reject); probe.listen(0, host, resolveListen); }); const address = probe.address();
if (!address || typeof address === 'string') { probe.close(); throw new Error('Unable to determine a free adapter-node port.'); }
const { port } = address; await new Promise((resolveClose, reject) => probe.close((error) => (error ? reject(error) : resolveClose())));
return port;}
async function waitForResponse(url, child) { const deadline = Date.now() + 30_000; let lastError;
while (Date.now() < deadline) { if (child.exitCode !== null) { throw new Error(`adapter-node exited with status ${child.exitCode}.`); }
try { return await fetch(url); } catch (error) { lastError = error; await new Promise((resolveDelay) => setTimeout(resolveDelay, 100)); } }
throw new Error(`Timed out waiting for ${url}: ${lastError instanceof Error ? lastError.message : lastError}`);}