feat(outlines): restore voice outlines without public Overpass

use bundled place boundaries and shared OpenFreeMap tiles before a guarded Nominatim fallback

preserve multipart shapes, holes and cancellation,
and keep pending annotations visible while ground sampling finishes across frames

keep non-Latin name distinctions when selecting provider results,
and retain an outline anchor only when it lies in filled geometry
This commit is contained in:
manjunath committed 2026-10-27 13:24:02 +00:00
commit d4434aa6d7
1489 files changed
+196442 -12353

No files matched your search

@@ -0,0 +1,27 @@
/**
* Treat an unavailable Google Maps tile-token endpoint as a supported, silent
* outcome. Install after real token providers and before the unknown-API 404.
*/
export function googleTokenUnavailablePlugin() {
const install = (server) => {
server.middlewares.use((req, res, next) => {
const pathname = String(req.url || '').split('?')[0];
if (
(req.method !== 'GET' && req.method !== 'HEAD') ||
pathname !== '/api/google/tiles-token'
) {
next();
return;
}
res.writeHead(204, { 'Cache-Control': 'no-store' });
res.end();
});
};
return {
name: 'google-token-unavailable',
configureServer: install,
configurePreviewServer: install,
};
}
+29 -7
View File
@@ -134,6 +134,8 @@ function keySetupEndpoint({ sourceRoot = defaultSourceRoot } = {}) {
};
// The gate itself is pure and unit-tested (admitKeySetupRequest in
// src/keySetupCore.mjs) — this just feeds it the request.
// `code`/`params` pick the panel's sentence (src/keySetup.js); `error` is for logs.
const refusal = ({ error, code, params }) => ({ error, code, params });
const admit = (req) =>
admitKeySetupRequest({
method: req.method,
@@ -247,18 +249,24 @@ function keySetupEndpoint({ sourceRoot = defaultSourceRoot } = {}) {
configureServer(server) {
server.middlewares.use('/api/setup/status', (req, res) => {
if (req.method !== 'GET')
return respond(res, 405, { error: 'Method not allowed' });
return respond(res, 405, {
error: 'Method not allowed',
code: 'method',
});
const admission = admit(req);
if (!admission.ok)
return respond(res, admission.status, { error: admission.error });
return respond(res, admission.status, refusal(admission));
respond(res, 200, providerStatus());
});
server.middlewares.use('/api/setup/keys', (req, res) => {
if (req.method !== 'POST')
return respond(res, 405, { error: 'Method not allowed' });
return respond(res, 405, {
error: 'Method not allowed',
code: 'method',
});
const admission = admit(req);
if (!admission.ok)
return respond(res, admission.status, { error: admission.error });
return respond(res, admission.status, refusal(admission));
let body = '';
let overflowed = false;
req.on('data', (chunk) => {
@@ -270,15 +278,21 @@ function keySetupEndpoint({ sourceRoot = defaultSourceRoot } = {}) {
});
req.on('end', () => {
if (overflowed)
return respond(res, 413, { error: 'Request too large' });
return respond(res, 413, {
error: 'Request too large',
code: 'too-large',
});
let parsed;
try {
parsed = JSON.parse(body || '{}');
} catch {
return respond(res, 400, { error: 'Invalid JSON' });
return respond(res, 400, {
error: 'Invalid JSON',
code: 'invalid-json',
});
}
const verdict = validateKeySetupUpdates(parsed);
if (!verdict.ok) return respond(res, 400, { error: verdict.error });
if (!verdict.ok) return respond(res, 400, refusal(verdict));
// Neither a replace NOR a removal may touch an externally-supplied
// credential (shell env, Keychain, another workflow). This backs the
// UI's read-only "configured externally" state with a real contract —
@@ -289,6 +303,8 @@ function keySetupEndpoint({ sourceRoot = defaultSourceRoot } = {}) {
if (isExternallyManaged(name, inStore)) {
return respond(res, 409, {
error: `${name} is configured outside Provider Settings and can only be changed where it was set`,
code: 'external',
params: { name },
});
}
}
@@ -305,10 +321,16 @@ function keySetupEndpoint({ sourceRoot = defaultSourceRoot } = {}) {
) {
return respond(res, 500, {
error: `The key was not saved: ${error.message}`,
code:
error.code === 'GEV_HARDEN_FAILED'
? 'harden-failed'
: 'store-unreadable',
});
}
return respond(res, 500, {
error: `Could not write the ${storeName()} store`,
code: 'write-failed',
params: { store: storeName() },
});
}
// Live for the server-side proxies immediately; the restart below is
+28
View File
@@ -0,0 +1,28 @@
/**
* Directories the app writes to while it runs. None is source, and none
* should reload anything.
*/
const RUNTIME_WRITE_GLOBS = Object.freeze([
'**/.gev-cache/**',
'**/.gev-logs/**',
]);
/**
* Keep the directories the app writes to out of the dev server's file watcher.
*
* Disk-cached providers write a file per response into `.gev-cache`, and the
* voice debug log appends to `.gev-logs`. Left watched, each write costs the
* watcher stat calls on libuv's thread pool, which `getaddrinfo` shares; heavy
* cache writes have been seen to delay upstream DNS lookups.
*
* @returns {import('vite').Plugin} Config-only plugin; no server hooks.
*/
export function unwatchedRuntimeDirsPlugin() {
return {
name: 'gev-unwatched-runtime-dirs',
apply: 'serve',
config: () => ({
server: { watch: { ignored: [...RUNTIME_WRITE_GLOBS] } },
}),
};
}
+18 -3
View File
@@ -5,28 +5,43 @@ import { createBrowserViteConfig } from '../../build/vite.js';
import { localProviderPlugins } from '../providers/local.js';
import { localMcpPlugin } from '../mcp/plugin.js';
import { apiNotFoundPlugin } from './api-not-found.js';
import { googleTokenUnavailablePlugin } from './google-token-unavailable.js';
import { standaloneVoiceTools } from './voiceTools.js';
import { unwatchedRuntimeDirsPlugin } from './unwatched-cache.js';
const root = fileURLToPath(new URL('../../', import.meta.url));
/** Load this checkout's configuration and attach its local provider middleware. */
export default defineConfig(({ command, mode }) => {
export function standaloneConfig(
{ command, mode },
{ nominatimStorageDir } = {},
) {
const loaded = loadEnv(mode, root, '');
for (const [key, value] of Object.entries(loaded)) {
if (process.env[key] === undefined) process.env[key] = value;
}
const tools = standaloneVoiceTools();
return createBrowserViteConfig({
plugins: [
...localProviderPlugins({ realtime: { tools: standaloneVoiceTools() } }),
...localProviderPlugins({
realtime: { tools },
gemini: { tools },
nominatimStorageDir,
}),
localMcpPlugin(),
googleTokenUnavailablePlugin(),
apiNotFoundPlugin(),
unwatchedRuntimeDirsPlugin(),
],
googleApiKey: process.env.GOOGLE_MAPS_API_KEY,
cesiumToken: process.env.CESIUM_ION_TOKEN,
photonUrl: process.env.PHOTON_URL,
mapillaryToken: process.env.MAPILLARY_CLIENT_TOKEN,
host: process.env.HOST,
port: process.env.PORT,
allowedHosts: resolveAllowedHosts(process.env.GEV_ALLOWED_HOSTS),
command,
});
});
}
export default defineConfig(standaloneConfig);