Merge current main into S2 GhostMaps and preserve updated import and voice behavior

This commit is contained in:
Mazeyar Moeini Feizabadi committed 2026-10-26 16:25:49 +01:00
commit 4da002bd42
515 files changed
+17681 -2202

No files matched your search

+27 -23
View File
@@ -98,7 +98,7 @@ test('standalone composition mounts every extracted provider exactly once withou
assert.equal(plugins.filter((p) => p.name === factory().name).length, 1);
});
test('terrain middleware chunks missing points and reconstructs repeated/reordered requests from cache', async (t) => {
test('terrain middleware bounds missing points and reconstructs repeated/reordered requests from cache', async (t) => {
isolate(t);
let calls = 0;
const sizes = [];
@@ -116,25 +116,23 @@ test('terrain middleware chunks missing points and reconstructs repeated/reorder
});
});
const request = install(terrainHeightsProxy());
const points = Array.from({ length: 257 }, (_, i) => `${i / 100},1`);
const points = Array.from({ length: 64 }, (_, i) => `${i / 100},1`);
const res = await request('/?points=' + points.join(';'));
assert.equal(res.status, 200);
// Tracks UPSTREAM_CHUNK in server/providers/terrain.js (64): 257 points
// split into four full chunks and a remainder.
assert.deepEqual(sizes, [64, 64, 64, 64, 1]);
const reordered = await request('/?points=2.56,1;0,1;2.56,1');
assert.deepEqual(sizes, [64]);
const reordered = await request('/?points=0.63,1;0,1;0.63,1');
assert.deepEqual(json(reordered), {
results: [{ ellipsoid: 102.56 }, { ellipsoid: 100 }, { ellipsoid: 102.56 }],
results: [{ ellipsoid: 100.63 }, { ellipsoid: 100 }, { ellipsoid: 100.63 }],
});
// Five chunks for the first batch; the reordered request is fully cached.
assert.equal(calls, 5);
// One bounded batch; the reordered request is fully cached.
assert.equal(calls, 1);
assert.equal((await request('/?points=invalid')).status, 400);
assert.equal(
(await request('/?points=' + Array(2001).fill('0,1').join(';'))).status,
500,
413,
);
// Rejected requests add no upstream calls: still the five from the first batch.
assert.equal(calls, 5);
// Rejected requests add no upstream calls.
assert.equal(calls, 1);
});
test('terrain middleware migrates valid legacy disk points without fabricating omitted heights', async (t) => {
@@ -160,6 +158,7 @@ test('terrain middleware migrates valid legacy disk points without fabricating o
test('traffic middleware preserves keyless mode, caching, stale budget fallback and UTC rollover', async (t) => {
isolate(t, { TOMTOM_API_KEY: '', TOMTOM_DAILY_TILE_BUDGET: '1' });
let now = Date.UTC(2026, 8, 12, 12);
const fetchedAt = String(now);
t.mock.method(Date, 'now', () => now);
let calls = 0;
t.mock.method(globalThis, 'fetch', async (raw) => {
@@ -184,10 +183,10 @@ test('traffic middleware preserves keyless mode, caching, stale budget fallback
assert.equal(json(await request('/status')).dailyCount, 1);
assert.equal(calls, 1);
now += 120001;
assert.equal(
(await request('/flow/8/1/1.pbf')).headers['x-tomtom-cache'],
'STALE-BUDGET',
);
const staleTile = await request('/flow/8/1/1.pbf');
assert.equal(staleTile.headers['x-tomtom-cache'], 'STALE-BUDGET');
// The stale copy still says when TomTom produced it.
assert.equal(staleTile.headers['x-tomtom-fetched-at'], fetchedAt);
assert.equal((await request('/flow/8/2/1.pbf')).status, 429);
assert.equal(calls, 1);
now += 86400000;
@@ -388,21 +387,26 @@ test('terrain middleware retains successful chunks around a failure and retries
});
const request = install(terrainHeightsProxy());
const points = Array.from({ length: 130 }, (_, i) => `${i / 100},1`);
const url = '/?points=' + points.join(';');
assert.equal((await request(url)).status, 502);
const urls = [0, 64, 128].map(
(start) => '/?points=' + points.slice(start, start + 64).join(';'),
);
assert.deepEqual(
requests.map((p) => p.length),
[64, 64, 2],
await Promise.all(urls.map(async (url) => (await request(url)).status)),
[200, 502, 200],
);
assert.deepEqual(
requests.map((p) => p.length).sort((a, b) => a - b),
[2, 64, 64],
);
fail = false;
const recovered = await request(url);
assert.equal(recovered.status, 200);
const recovered = await Promise.all(urls.map((url) => request(url)));
assert.ok(recovered.every((response) => response.status === 200));
assert.deepEqual(
requests[3],
Array.from({ length: 64 }, (_, i) => [(i + 64) / 100, 1]),
);
assert.deepEqual(
json(recovered).results,
recovered.flatMap((response) => json(response).results),
Array.from({ length: 130 }, (_, i) => ({ ellipsoid: i / 100 + 100 })),
);
assert.equal(requests.length, 4);
@@ -0,0 +1,94 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { createServer } from 'node:http';
import { once } from 'node:events';
import { createGoogleTokenSource } from '../maps/googleTokens.js';
import { googleTokenUnavailablePlugin } from '../../server/standalone/google-token-unavailable.js';
async function withServer({ beforeFallback } = {}, check) {
const middlewares = [];
const app = {
middlewares: {
use: (handler) => middlewares.push(handler),
},
};
if (beforeFallback) app.middlewares.use(beforeFallback);
googleTokenUnavailablePlugin().configureServer(app);
app.middlewares.use((_req, res) => {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Unknown API route' }));
});
const server = createServer((req, res) => {
let index = 0;
const next = () => middlewares[index++]?.(req, res, next);
next();
});
server.listen(0, '127.0.0.1');
await once(server, 'listening');
const address = server.address();
const url = 'http://127.0.0.1:' + address.port;
try {
await check(url);
} finally {
server.close();
await once(server, 'close');
}
}
test('keyless GET and HEAD return uncached 204 instead of 404', async () => {
await withServer({}, async (url) => {
for (const method of ['GET', 'HEAD']) {
const response = await fetch(url + '/api/google/tiles-token?probe=1', {
method,
});
assert.equal(response.status, 204);
assert.equal(response.headers.get('cache-control'), 'no-store');
assert.equal(await response.text(), '');
}
});
});
test('the existing client treats unavailable tokens as null', async () => {
await withServer({}, async (url) => {
const source = createGoogleTokenSource({
fetchImpl: (path, options) => fetch(new URL(path, url), options),
});
assert.equal(await source.token(), null);
});
});
test('unrelated API paths and unsupported methods remain 404', async () => {
await withServer({}, async (url) => {
for (const [path, method] of [
['/api/google/tiles-token/extra', 'GET'],
['/api/not-a-token', 'GET'],
['/api/google/tiles-token', 'POST'],
]) {
const response = await fetch(new URL(path, url), { method });
assert.equal(response.status, 404);
}
});
});
test('a real token provider registered first still wins', async () => {
await withServer(
{
beforeFallback: (req, res, next) => {
if (req.url !== '/api/google/tiles-token') return next();
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(
JSON.stringify({
accessToken: 'server-token',
expiresAt: 10000000000000,
}),
);
},
},
async (url) => {
const response = await fetch(url + '/api/google/tiles-token');
assert.equal(response.status, 200);
assert.equal((await response.json()).accessToken, 'server-token');
},
);
});
+7 -2
View File
@@ -156,13 +156,18 @@ test('self package imports cannot evade portable ownership', (t) => {
assert.throws(() => checkImportDirections(root), /Source imports rendering/);
});
test('compatibility exceptions are limited to the two existing composition entries', (t) => {
test('the compatibility exception is limited to the existing composition entry', (t) => {
const { root, write } = fixture(t);
write('src/ui.js', "import './standalone/catalog.js';");
write('src/standalone/catalog.js');
write('server/providers/local.js', "import '../standalone/key-setup.js';");
write('server/standalone/key-setup.js');
assert.doesNotThrow(() => checkImportDirections(root));
write('src/ui.js', "import './standalone/catalog.js';");
assert.throws(
() => checkImportDirections(root),
/Reusable module imports standalone/,
);
write('src/ui.js');
write('src/ui/new.js', "import '../standalone/catalog.js';");
assert.throws(
() => checkImportDirections(root),
+202
View File
@@ -583,3 +583,205 @@ test('track backfill proxy returns 502 on an oversized upstream body and caches
assert.equal(res2.statusCode, 502);
assert.equal(callCount, 1);
});
test('OpenSky Basic mode no longer sends username and password: it asks anonymously and warns once', async (t) => {
environment(t, {
OPENSKY_CLIENT_ID: undefined,
OPENSKY_CLIENT_SECRET: undefined,
OPENSKY_CREDENTIALS_FILE: undefined,
OPENSKY_AUTH_MODE: 'basic',
OPENSKY_USERNAME: 'fixture-user',
OPENSKY_PASSWORD: 'fixture-password',
});
const warnings = [];
t.mock.method(console, 'warn', (message) => warnings.push(message));
const authorizations = [];
t.mock.method(globalThis, 'fetch', async (url, options) => {
if (url.includes('/states/')) {
authorizations.push(options.headers.Authorization);
return Response.json({ time: Math.floor(Date.now() / 1000), states: [] });
}
throw Error(`Unexpected URL: ${url}`);
});
const fresh = await import(
`../../server/providers/aircraft/opensky.js?basic=${Math.random()}`
);
const flights = install(fresh.openSkyProxy());
const first = await flights('/api/flights');
assert.equal(first.statusCode, 200);
assert.equal(first.headers['x-opensky-auth'], 'anon');
assert.equal(first.headers['x-opensky-auth-reason'], 'basic_retired');
assert.deepEqual(authorizations, [undefined]);
assert.equal(warnings.length, 1);
assert.match(warnings[0], /retired username\/password sign-in/);
assert.ok(!warnings[0].includes('fixture-password'));
});
test('OpenSky auto mode never falls back to Basic, even when OAuth is rejected', async (t) => {
environment(t, {
OPENSKY_CLIENT_ID: 'fixture-client',
OPENSKY_CLIENT_SECRET: 'fixture-secret',
OPENSKY_CREDENTIALS_FILE: undefined,
OPENSKY_AUTH_MODE: 'auto',
OPENSKY_USERNAME: 'fixture-user',
OPENSKY_PASSWORD: 'fixture-password',
});
t.mock.method(console, 'warn', () => {});
t.mock.method(console, 'log', () => {});
t.mock.method(console, 'error', () => {});
const authorizations = [];
t.mock.method(globalThis, 'fetch', async (url, options) => {
if (url.includes('/token'))
return Response.json({ access_token: 'fixture-token', expires_in: 1800 });
if (url.includes('/states/')) {
authorizations.push(options.headers.Authorization);
return new Response('', { status: 401 });
}
if (url.includes('/lat/')) return regionalFallback();
throw Error(`Unexpected URL: ${url}`);
});
const fresh = await import(
`../../server/providers/aircraft/opensky.js?auto=${Math.random()}`
);
await install(fresh.openSkyProxy())('/api/flights', '?lat=30&lon=-97');
assert.deepEqual(authorizations, ['Bearer fixture-token']);
});
test('retired military history refuses without upstream I/O while validating identifiers', async (t) => {
t.mock.method(globalThis, 'fetch', async () => {
assert.fail('retired history must not contact the upstream');
});
const route = install(providers.trackBackfillProxies());
for (const hex of ['abc123', 'abc456']) {
const response = await route('/api/military/track', '?hex=' + hex);
assert.equal(response.statusCode, 503);
assert.equal(JSON.parse(response.body).code, 'history_unavailable');
assert.equal(response.headers['retry-after'], '1800');
assert.equal(response.headers['cache-control'], 'no-store');
}
assert.equal(
(await route('/api/military/track', '?hex=invalid')).statusCode,
400,
);
});
test('global aircraft snapshots coalesce cold and expired callers and clear rejected flights', async (t) => {
environment(t, { OPENSKY_AUTH_MODE: 'anon' });
t.mock.method(console, 'warn', () => {});
t.mock.method(console, 'error', () => {});
let now = Date.now();
t.mock.method(Date, 'now', () => now);
for (const kind of ['opensky', 'military']) {
const module =
kind === 'opensky'
? await import(
`../../server/providers/aircraft/opensky.js?coalesce=${Math.random()}`
)
: await import('../../server/providers/aircraft/adsb-lol.js');
const request = install(
kind === 'opensky' ? module.openSkyProxy() : module.adsbLolProxy(),
);
const route = kind === 'opensky' ? '/api/flights' : '/api/military';
let calls = 0;
let release;
let blocked;
let fail = false;
t.mock.method(globalThis, 'fetch', async () => {
calls++;
await blocked;
if (fail) throw new Error('fixture connection failed');
return Response.json(
{ time: now / 1000, states: [], ac: [] },
{ headers: { 'x-rate-limit-remaining': '5000' } },
);
});
for (const phase of ['cold', 'expired', 'failed', 'recovered']) {
now += 13000;
fail = phase === 'failed';
blocked = new Promise((resolve) => {
release = resolve;
});
const before = calls;
const pending = Array.from({ length: 5 }, () => request(route));
await new Promise(setImmediate);
assert.equal(calls - before, 1, `${kind} ${phase}: one refresh starts`);
release();
const responses = await Promise.all(pending);
assert.equal(calls - before, fail && kind === 'opensky' ? 2 : 1);
assert.ok(responses.every((res) => res.statusCode === 200));
assert.ok(responses.every((res) => res.body === responses[0].body));
}
}
});
test('OpenSky 5xx retains dated last-good data, cancels error bodies and cools down before recovery', async (t) => {
environment(t, { OPENSKY_AUTH_MODE: 'anon' });
let now = Date.now();
t.mock.method(Date, 'now', () => now);
for (const status of [502, 503, 504]) {
const module = await import(
`../../server/providers/aircraft/opensky.js?server-error=${status}`
);
const request = install(module.openSkyProxy());
let fail = false;
let calls = 0;
let cancelled = false;
t.mock.method(globalThis, 'fetch', async () => {
calls++;
if (fail)
return new Response(
new ReadableStream({
cancel() {
cancelled = true;
},
}),
{ status },
);
return Response.json(
{ time: now / 1000, states: [] },
{ headers: { 'x-rate-limit-remaining': '5000' } },
);
});
const good = await request('/api/flights');
now += 10000;
fail = true;
const stale = await request('/api/flights');
assert.equal(stale.statusCode, 200);
assert.equal(stale.body, good.body);
assert.equal(stale.headers['x-opensky-cache'], 'STALE');
assert.equal(
stale.headers['x-opensky-auth-reason'],
`upstream_http_${status}_serving_stale`,
);
assert.equal(stale.headers['x-opensky-stale-seconds'], '10');
assert.equal(cancelled, true);
const cooling = await request('/api/flights');
assert.equal(cooling.body, good.body);
assert.equal(
cooling.headers['x-opensky-auth-reason'],
`upstream_http_${status}_serving_stale`,
);
assert.equal(calls, 2);
now += 16000;
fail = false;
assert.equal(
(await request('/api/flights')).headers['x-opensky-cache'],
'MISS',
);
assert.equal(calls, 3);
}
const coldModule =
await import('../../server/providers/aircraft/opensky.js?cold-server-error');
let calls = 0;
t.mock.method(globalThis, 'fetch', async () => {
calls++;
return new Response('<html>failure</html>', { status: 503 });
});
const cold = install(coldModule.openSkyProxy());
for (let i = 0; i < 2; i++) {
const response = await cold('/api/flights');
assert.equal(response.statusCode, 503);
assert.match(JSON.parse(response.body).error, /OpenSky/);
}
assert.equal(calls, 1);
});
+18
View File
@@ -81,6 +81,24 @@ test('nearby labels rank landmarks, deduplicate names/addresses and bound the pr
assert.deepEqual(projectNearbyPlaces({}, 0, 0), []);
});
test('nearby place distances take the short way round 180°', () => {
const at = (name, longitude) => ({
id: name,
displayName: { text: name },
location: { latitude: -16.8, longitude },
types: ['point_of_interest'],
});
// From Taveuni at 179.98: 2 km east across 180°, 4 km west on this side.
const result = projectNearbyPlaces(
{ places: [at('West', 179.942), at('East', -179.999)] },
-16.8,
179.98,
);
const byName = Object.fromEntries(result.map((p) => [p.name, p.distanceM]));
assert.ok(byName.East > 1500 && byName.East < 2500, String(byName.East));
assert.ok(byName.West > 3500 && byName.West < 4500, String(byName.West));
});
test('text search preserves bounds, rejects malformed bounds and tolerates absent locations', () => {
const viewport = {
low: { latitude: 1, longitude: 2 },
+205 -3
View File
@@ -12,6 +12,7 @@ import {
launchLibraryRecentUrl,
} from 'gods-eye-view/sources/space';
import * as compatibility from '../../server/providers/local.js';
import { createLaunchSource } from 'gods-eye-view/layers/launches/source';
function install(plugin, preview = false) {
const routes = new Map();
@@ -22,17 +23,23 @@ function install(plugin, preview = false) {
},
},
});
return async (route, url = '/', method = 'GET') => {
return async (route, url = '/', method = 'GET', headers = {}) => {
const res = {
headersSent: false,
headers: {},
writeHead(status, headers) {
Object.assign(this, { status, headers, headersSent: true });
},
// The same-site gates answer 403 through statusCode + setHeader.
setHeader(name, value) {
this.headers[name] = value;
},
end(body) {
this.body = body;
this.status ??= this.statusCode;
},
};
await routes.get(route)({ url, method }, res);
await routes.get(route)({ url, method, headers, socket: {} }, res);
return res;
};
}
@@ -161,7 +168,11 @@ test('CelesTrak answers 502 to an oversized TLE body without caching it', async
assert.ok(bodies[0].pulled <= 17, 'reading stops at the 16 MiB cap');
assert.equal(fsp.writeFile.mock.callCount(), 0);
assert.equal((await request('/api/celestrak', '/stations')).status, 502);
assert.equal(bodies.length, 2, 'nothing was cached in memory');
assert.equal(
bodies.length,
1,
'failed bodies are not cached but a cooldown bounds retry work',
);
});
for (const preview of [false, true])
@@ -190,3 +201,194 @@ for (const preview of [false, true])
assert.equal(hit.body, first.body);
assert.equal(calls, 1);
});
test('space providers honor Retry-After, gate groups, preserve stale dates and recover', async (t) => {
isolateDisk(t);
t.mock.method(console, 'warn', () => {});
let now = Date.now();
t.mock.method(Date, 'now', () => now);
for (const kind of ['tle', 'launches']) {
for (const retryAfter of ['90', new Date(now + 90000).toUTCString()]) {
let calls = 0;
let fail = false;
let cancelled = false;
t.mock.method(globalThis, 'fetch', async () => {
calls++;
if (fail)
return new Response(
new ReadableStream({
cancel() {
cancelled = true;
},
}),
{
status: kind === 'tle' ? 403 : 429,
headers: { 'Retry-After': retryAfter },
},
);
return new Response(
kind === 'tle'
? 'ISS\n1 25544U fixture\n2 25544 fixture\n'
: '{"results":[]}',
);
});
const request = install(
kind === 'tle' ? celestrakProxy() : rocketLaunchesProxy(),
);
const route = kind === 'tle' ? '/api/celestrak' : '/api/launches';
const url = kind === 'tle' ? '/stations' : '/';
if (kind === 'tle') {
assert.equal(
(await request(route, '/not-a-supported-group')).status,
400,
);
assert.equal(calls, 0);
}
const first = await request(route, url);
now += 7 * 3600000;
// Recompute the HTTP-date relative to the clock at the failed refresh.
const originalFetch = globalThis.fetch;
t.mock.method(globalThis, 'fetch', async (...args) => {
const response = await originalFetch(...args);
if (fail && !/^\d+$/.test(retryAfter))
response.headers.set(
'Retry-After',
new Date(now + 90000).toUTCString(),
);
return response;
});
fail = true;
const stale = await request(route, url);
assert.equal(stale.status, 200);
assert.equal(stale.body, first.body);
assert.equal(stale.headers['Retry-After'], '90');
assert.ok(
stale.headers[kind === 'tle' ? 'X-TLE-Cached-At' : 'X-GEV-Cached-At'],
);
assert.equal(cancelled, true);
await request(route, url);
if (kind === 'tle')
assert.equal((await request(route, '/visual')).status, 502);
assert.equal(calls, 2, 'cooldown applies across TLE groups');
now += 91000;
fail = false;
assert.equal((await request(route, url)).status, 200);
assert.equal(calls, 3);
}
}
});
test('Space Missions reads the active catalog through the real proxy while unknown groups stay rejected', async (t) => {
isolateDisk(t);
const tle = 'ISS\n1 25544U fixture\n2 25544 fixture\n';
const fetched = [];
t.mock.method(globalThis, 'fetch', async (url) => {
fetched.push(new URL(url).searchParams.get('GROUP'));
return new Response(tle);
});
const request = install(celestrakProxy());
// Route the browser source's real request into the middleware.
const source = createLaunchSource({
fetchImpl: async (url) => {
const prefix = '/api/celestrak';
assert.ok(url.startsWith(`${prefix}/`));
const res = await request(prefix, url.slice(prefix.length));
return new Response(res.body, { status: res.status });
},
});
assert.equal(await source.getActiveTle(), tle);
assert.deepEqual(fetched, ['active']);
for (const group of ['/not-a-group', '/active-extra', '/../active'])
assert.equal((await request('/api/celestrak', group)).status, 400);
assert.deepEqual(fetched, ['active'], 'rejected groups never reach upstream');
});
test('CelesTrak admits a same-origin request behind the documented reverse proxy and refuses foreign origins', async (t) => {
isolateDisk(t);
let calls = 0;
t.mock.method(globalThis, 'fetch', async () => {
calls++;
return new Response('ISS\n1 25544U fixture\n2 25544 fixture\n');
});
const request = install(celestrakProxy());
const proxied = {
host: 'gev.example.test',
'x-forwarded-for': '203.0.113.7',
'x-forwarded-host': 'gev.example.test',
'x-forwarded-proto': 'https',
via: '1.1 proxy',
};
const app = await request('/api/celestrak', '/stations', 'GET', {
...proxied,
origin: 'https://gev.example.test',
'sec-fetch-site': 'same-origin',
});
assert.equal(app.status, 200);
assert.equal(app.headers['x-tle-cache'], 'MISS');
assert.equal(calls, 1);
for (const headers of [
{ ...proxied, origin: 'https://unrelated.example' },
{ ...proxied, origin: 'null' },
{ ...proxied, 'sec-fetch-site': 'cross-site' },
]) {
const refused = await request('/api/celestrak', '/visual', 'GET', headers);
assert.equal(refused.status, 403);
}
assert.equal(calls, 1, 'refused requests do no provider or cache work');
});
for (const longFirst of [true, false])
test(`CelesTrak keeps the longest cooldown when concurrent failures finish ${longFirst ? 'long then short' : 'short then long'}`, async (t) => {
isolateDisk(t);
t.mock.method(console, 'warn', () => {});
let now = Date.now();
t.mock.method(Date, 'now', () => now);
const pending = new Map();
let calls = 0;
t.mock.method(globalThis, 'fetch', async (url) => {
calls++;
const group = new URL(url).searchParams.get('GROUP');
await new Promise((resolve) => pending.set(group, resolve));
return group === 'stations'
? new Response('slow down', {
status: 429,
headers: { 'Retry-After': '1800' },
})
: new Response('unavailable', { status: 503 });
});
const request = install(celestrakProxy());
const long = request('/api/celestrak', '/stations');
const short = request('/api/celestrak', '/visual');
while (pending.size < 2) await new Promise(setImmediate);
const order = longFirst
? [
['stations', long],
['visual', short],
]
: [
['visual', short],
['stations', long],
];
for (const [group, response] of order) {
pending.get(group)();
assert.equal((await response).status, 502);
}
assert.equal(calls, 2);
const cooling = await request('/api/celestrak', '/geo');
assert.equal(cooling.status, 502);
assert.equal(cooling.headers['Retry-After'], '1800');
now += 61_000;
assert.equal((await request('/api/celestrak', '/geo')).status, 502);
assert.equal(
calls,
2,
'the 60 s fallback did not replace the 30 min deadline',
);
now += 1800_000;
t.mock.method(
globalThis,
'fetch',
async () => new Response('ISS\n1 25544U fixture\n2 25544 fixture\n'),
);
assert.equal((await request('/api/celestrak', '/geo')).status, 200);
});
+170
View File
@@ -0,0 +1,170 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import {
trafficFixtureResponse,
trafficFixtureTile,
} from '../../scripts/traffic-fixtures.mjs';
import { decodeOpenFreeMapTile } from '../sources/openFreeMap.js';
import { isDrivableFlowSegment } from '../layers/traffic/roadModes.js';
import { decodeFlowTile } from '../layers/traffic/flowDecode.js';
test('traffic fixtures provide aligned current road tiles and partial flow coverage', () => {
for (const z of [12, 14]) {
const roads = decodeOpenFreeMapTile(
trafficFixtureTile(z),
z,
935,
1686,
).roads;
const flow = decodeFlowTile(trafficFixtureTile(z, true), z, 935, 1686);
assert.ok(roads.length > flow.length && flow.length > 0);
for (const segment of flow) {
assert.equal(segment.trafficLevel, 0.6);
assert.equal(isDrivableFlowSegment(segment), true);
assert.ok(
roads.some(
(road) =>
JSON.stringify(road.coordinates) === JSON.stringify(segment.coords),
),
);
}
}
});
test('fixture TileJSON and every road/flow request stay on intercepted sources', () => {
const request = (url) => trafficFixtureResponse({ url: () => url });
const tileJson = request('https://tiles.openfreemap.org/planet');
assert.equal(tileJson.headers['access-control-allow-origin'], '*');
const metadata = JSON.parse(tileJson.body);
const tileUrl = metadata.tiles[0]
.replace('{z}', '14')
.replace('{x}', '935')
.replace('{y}', '1686');
assert.ok(
decodeOpenFreeMapTile(request(tileUrl).body, 14, 935, 1686).roads.length,
);
assert.ok(
decodeFlowTile(
request('http://localhost/api/tomtom/flow/12/935/1686.pbf').body,
12,
935,
1686,
).length,
);
assert.throws(
() => request('https://tiles.openfreemap.org/unexpected'),
/Unrecognized/,
);
assert.equal(request('http://localhost/api/unrelated'), null);
});
test('flat terrain fixture decodes through Cesium and advertises no network children', async () => {
const { createServer } = await import('node:http');
const { CesiumTerrainProvider } = await import('cesium');
const server = createServer((req, res) => {
const response = trafficFixtureResponse({
url: () => `https://terrain.reearth.land${req.url}`,
});
res.writeHead(response.status, { 'content-type': response.contentType });
res.end(response.body);
});
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
try {
const provider = await CesiumTerrainProvider.fromUrl(
`http://127.0.0.1:${server.address().port}`,
);
for (const x of [0, 1]) {
const data = await provider.requestTileGeometry(x, 0, 0);
const rect = provider.tilingScheme.tileXYToRectangle(x, 0, 0);
assert.equal(
data.interpolateHeight(rect, (rect.west + rect.east) / 2, 0),
0,
);
for (const dx of [0, 1])
for (const dy of [0, 1]) {
assert.equal(data.isChildAvailable(x, 0, x * 2 + dx, dy), false);
}
}
} finally {
server.closeAllConnections();
await new Promise((resolve) => server.close(resolve));
}
});
test('fixture interception targets provider URLs and leaves app workers alone', async () => {
const { installTrafficRoutes } =
await import('../../scripts/traffic-fixtures.mjs');
const sent = [];
let paused;
const session = {
on: (_, handler) => {
paused = handler;
},
send: async (name, args) => {
sent.push({ name, args });
},
};
await installTrafficRoutes(
{ createCDPSession: async () => session, isClosed: () => false },
{ origin: 'http://localhost:4173', fixtures: true },
);
const patterns = sent[0].args.patterns.map((p) => p.urlPattern);
assert.deepEqual(patterns, [
'http://localhost:4173/api/tomtom/status*',
'http://localhost:4173/api/tomtom/flow/*',
'https://tiles.openfreemap.org/*',
'https://terrain.reearth.land/*',
]);
await paused({
requestId: 'terrain',
request: { url: 'https://terrain.reearth.land/layer.json' },
});
const reply = sent.at(-1);
assert.equal(reply.name, 'Fetch.fulfillRequest');
assert.equal(
JSON.parse(Buffer.from(reply.args.body, 'base64')).format,
'heightmap-1.0',
);
assert.ok(
reply.args.responseHeaders.some(
(h) => h.name === 'access-control-allow-origin' && h.value === '*',
),
);
});
test('keyless interception refuses and records unexpected flow requests', async () => {
const { installTrafficRoutes } =
await import('../../scripts/traffic-fixtures.mjs');
const sent = [],
flows = [];
let paused;
const session = {
on: (_, handler) => {
paused = handler;
},
send: async (name, args) => {
sent.push({ name, args });
},
};
await installTrafficRoutes(
{ createCDPSession: async () => session, isClosed: () => false },
{
origin: 'http://localhost:4173',
keyless: true,
onFlow: (url) => flows.push(url),
},
);
await paused({
requestId: 'status',
request: { url: 'http://localhost:4173/api/tomtom/status' },
});
assert.deepEqual(JSON.parse(Buffer.from(sent.at(-1).args.body, 'base64')), {
hasKey: false,
});
await paused({
requestId: 'flow',
request: { url: 'http://localhost:4173/api/tomtom/flow/12/1/1.pbf' },
});
assert.equal(sent.at(-1).args.responseCode, 503);
assert.equal(flows.length, 1);
});
+13
View File
@@ -1,6 +1,7 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { getTransitFeed } from '../data/transitFeeds.js';
import {
chooseLiveCities,
selectStyle,
@@ -101,6 +102,18 @@ test('live visual cities follow local operating hours in summer and winter', ()
const cities = chooseLiveCities(now);
assert.ok(cities.length >= 1);
for (const city of cities) {
const feed = getTransitFeed(city.feedId);
assert.ok(feed, `${city.id} has a registered feed`);
const distanceKm =
111.32 *
Math.hypot(
feed.center.lat - city.lat,
(feed.center.lon - city.lon) * Math.cos((city.lat * Math.PI) / 180),
);
assert.ok(
distanceKm < feed.loadRadiusKm,
`${city.id} is inside its feed's admission region`,
);
const local = Number(
new Intl.DateTimeFormat('en', {
timeZone: city.zone,
+25 -5
View File
@@ -1,3 +1,4 @@
import { fileURLToPath } from 'node:url';
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
@@ -5,7 +6,11 @@ import { rm, writeFile } from 'node:fs/promises';
import { request } from 'node:http';
import path from 'node:path';
import { build, createServer, preview } from 'vite';
import { BROWSER_CSP, createBrowserViteConfig } from '../../build/vite.js';
import {
BROWSER_CSP,
createBrowserViteConfig,
escapeFsDenyPath,
} from '../../build/vite.js';
import standaloneConfig, * as compatibility from '../../vite.config.js';
import * as providers from '../../server/providers/local.js';
import { apiNotFoundPlugin } from '../../server/standalone/api-not-found.js';
@@ -30,6 +35,20 @@ test('explicit build inputs preserve browser-only defines, plugin order and loop
assert.deepEqual(config.server.allowedHosts, ['localhost', '127.0.0.1']);
assert.ok(config.server.fs.deny.includes('**/ENVIRONMENT'));
assert.ok(config.server.fs.deny.includes('.env.*'));
assert.ok(config.server.fs.deny.includes('**/.gev-logs/**'));
assert.ok(config.server.fs.deny.includes('**/.gev-cache/**'));
const root = fileURLToPath(new URL('../../', import.meta.url))
.replace(/\\/g, '/')
.replace(/\/$/, '');
assert.deepEqual(
config.server.fs.deny.filter((pattern) => pattern.endsWith('/dist/**')),
[`${escapeFsDenyPath(root)}/dist/**`],
'only project build output is denied, not dependency dist directories',
);
assert.equal(
escapeFsDenyPath('C:/Users/a/project (1) [test]{copy}'),
'C:/Users/a/project \\(1\\) \\[test\\]\\{copy\\}',
);
assert.equal(config.server.headers['X-Frame-Options'], 'DENY');
assert.equal(config.server.headers['X-Content-Type-Options'], 'nosniff');
const csp = config.server.headers['Content-Security-Policy'];
@@ -98,7 +117,7 @@ test('root config retains existing named exports and standalone provider order',
assert.equal(compatibility[name], value, name);
const config = standaloneConfig({ mode: 'test' });
const standaloneProviders = config.plugins
.slice(4, -5)
.slice(4, -6)
.map((plugin) => plugin.name);
assert.equal(
standaloneProviders.filter((name) => name === 'gemini-live-proxy').length,
@@ -112,9 +131,10 @@ test('root config retains existing named exports and standalone provider order',
standaloneProviders.filter((name) => name !== 'gemini-live-proxy'),
providers.localProviderPlugins().map((plugin) => plugin.name),
);
assert.equal(config.plugins.at(-6).name, 'gev-key-setup');
// The local MCP route follows every provider and precedes the API fallback.
assert.equal(config.plugins.at(-5).name, 'local-mcp');
assert.equal(config.plugins.at(-7).name, 'gev-key-setup');
// Token fallback follows real providers and local MCP before the API 404.
assert.equal(config.plugins.at(-6).name, 'local-mcp');
assert.equal(config.plugins.at(-5).name, 'google-token-unavailable');
assert.equal(config.plugins.at(-4).name, 'api-not-found');
// Config-only, so it sits after the provider slice rather than in it.
assert.equal(config.plugins.at(-3).name, 'gev-unwatched-runtime-dirs');
+13
View File
@@ -234,6 +234,19 @@ test('typed argument checks feed full-call accuracy without changing the legacy
const inMeters = gradeCore(altitude, [{ name: 'analyst_query', args: { layers: ['flights'], filters: [{ field: 'altitudeM', op: 'gt', value: 12192 }] } }]);
assert.equal(inMeters.fullCallOk, true);
assert.equal(where('set_hud', (a) => a.visible === 'off')({ name: 'set_hud', args: { visible: 'off' } }), true);
const globe = byPhrase('Keep spinning the Earth slowly to the left');
const globeArgs = { motion: 'rotate_globe', direction: 'left', speed: 'slow' };
for (const mode of [undefined, 'continuous', 'once', null]) {
assert.equal(gradeCore(globe, [{ name: 'move_camera', args: { ...globeArgs, mode } }]).fullCallOk, mode === undefined || mode === 'continuous');
}
assert.equal(gradeCore(globe, [{ name: 'move_camera', args: { ...globeArgs, direction: 'right' } }]).fullCallOk, false);
assert.equal(gradeCore(globe, [{ name: 'move_camera', args: { ...globeArgs, speed: 'normal' } }]).fullCallOk, false);
const right = byPhrase('Rotate the globe to the right');
assert.equal(gradeCore(right, [{ name: 'move_camera', args: { motion: 'rotate_globe' } }]).fullCallOk, true);
for (const direction of ['right', 'left', null]) {
assert.equal(gradeCore(right, [{ name: 'move_camera', args: { motion: 'rotate_globe', direction } }]).fullCallOk, direction === 'right');
}
assert.equal(gradeCore(right, [{ name: 'move_camera', args: { motion: 'rotate', direction: 'right' } }]).fullCallOk, false);
});
test('gradeDialogue scores turn 2 in the context of turn 1', () => {